diff --git a/TermTk/TTkLayouts/gridlayout.py b/TermTk/TTkLayouts/gridlayout.py index 809033ed..9c818c1d 100644 --- a/TermTk/TTkLayouts/gridlayout.py +++ b/TermTk/TTkLayouts/gridlayout.py @@ -48,7 +48,7 @@ from TermTk.TTkCore.log import TTkLog from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem class TTkGridLayout(TTkLayout): - __slots__ = ('_gridItems','_columnMinWidth','_columnMinHeight') + __slots__ = ('_gridItems','_columnMinWidth','_columnMinHeight', '_rows', '_cols') def __init__(self, *args, **kwargs): ''' TTkGridLayout constructor @@ -57,26 +57,26 @@ class TTkGridLayout(TTkLayout): columnMinWidth (int, optional, default=0): the minimum width of the column columnMinHeight (int, optional, default=0): the minimum height of the column ''' + self._rows = 0 + self._cols = 0 TTkLayout.__init__(self, *args, **kwargs) self._gridItems = [[]] self._columnMinWidth = kwargs.get('columnMinWidth',0) self._columnMinHeight = kwargs.get('columnMinHeight',0) def _gridUsedsize(self): - rows = 1 + rows = 0 cols = 0 - for gridRow in range(len(self._gridItems)): - if rows < gridRow: - rows = gridRow - for gridCol in range(len(self._gridItems[0])): - if self._gridItems[gridRow][gridCol] is not None: - if cols < gridCol: - cols = gridCol - return (rows+1, cols+1) + for gridRow in range(self._rows): + for gridCol in range(self._cols): + if item:=self._gridItems[gridRow][gridCol]: + rows = max(rows, gridRow+item._rowspan) + cols = max(cols, gridCol+item._colspan) + return (rows, cols) def _reshapeGrid(self, size): - rows = size[0] - cols = size[1] + rows, cols = size + self._rows, self._cols = size # remove extra rows if rows < len(self._gridItems): @@ -94,39 +94,29 @@ class TTkGridLayout(TTkLayout): elif cols > sizeRow: self._gridItems[gridRow] += [None]*(cols-sizeRow) + # addWidget(self, widget, row, col) - def addWidget(self, *args, **kwargs): - widget = args[0] + def addWidget(self, widget, row=None, col=None, rowspan=1, colspan=1): self.removeWidget(widget) item = TTkWidgetItem(widget=widget) - if len(args) == 3: - TTkGridLayout.addItem(self, item, args[1], args[2]) - else: - TTkGridLayout.addItem(self, item) + TTkGridLayout.addItem(self, item, row, col, rowspan, colspan) widget.update() def replaceItem(self, item, index): pass - def addItem(self, *args, **kwargs): - item = args[0] + def addItem(self, item, row=None, col=None, rowspan=1, colspan=1): self.removeItem(item) - if len(args) == 3: - row = args[1] - col = args[2] - else: + if row is None and col is None: # Append The widget at the end row = 0 - col = len(self._gridItems[0]) + col = self._cols #retrieve the max col/rows to reshape the grid - maxrow = row - maxcol = col + maxrow = row + rowspan + maxcol = col + colspan for child in self.children(): - if maxrow < child._row: maxrow = child._row - if maxcol < child._col: maxcol = child._col - # reshape the gridItems - maxrow += 1 - maxcol += 1 + maxrow = max(maxrow, child._row + child._rowspan) + maxcol = max(maxcol, child._col + child._colspan) # TODO: This is RUBBISH!!! self._reshapeGrid(size=(maxrow,maxcol)) @@ -137,21 +127,24 @@ class TTkGridLayout(TTkLayout): item._row = row item._col = col + item._rowspan = rowspan + item._colspan = colspan + self._gridItems[row][col] = item TTkLayout.addItem(self, item) def removeItem(self, item): TTkLayout.removeItem(self, item) - for gridRow in range(len(self._gridItems)): - for gridCol in range(len(self._gridItems[0])): + for gridRow in range(self._rows): + for gridCol in range(self._cols): if self._gridItems[gridRow][gridCol] == item: self._gridItems[gridRow][gridCol] = None self._reshapeGrid(self._gridUsedsize()) def removeWidget(self, widget): TTkLayout.removeWidget(self, widget) - for gridRow in range(len(self._gridItems)): - for gridCol in range(len(self._gridItems[0])): + for gridRow in range(self._rows): + for gridCol in range(self._cols): if self._gridItems[gridRow][gridCol] is not None and \ self._gridItems[gridRow][gridCol].layoutItemType == TTkK.WidgetItem and \ self._gridItems[gridRow][gridCol].widget() == widget: @@ -159,20 +152,26 @@ class TTkGridLayout(TTkLayout): self._reshapeGrid(self._gridUsedsize()) def itemAtPosition(self, row: int, col: int): - if row >= len(self._gridItems) or \ - col >= len(self._gridItems[0]): + if row >= self._rows or \ + col >= self._cols: return None - return self._gridItems[row][col] + if item := self._gridItems[row][col]: + return item + for item in self.children(): + if item._row + item._rowspan > row >= item._row and \ + item._col + item._colspan > col >= item._col : + return item + return None def minimumColWidth(self, gridCol: int) -> int: colw = 0 anyItem = False - for gridRow in range(len(self._gridItems)): - item = self._gridItems[gridRow][gridCol] + for gridRow in range(self._rows): + item = self.itemAtPosition(gridRow,gridCol) if item is not None and \ ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): anyItem = True - w = item.minimumWidth() + w = item.minimumWidthSpan(gridCol) if colw < w: colw = w if not anyItem: @@ -182,11 +181,12 @@ class TTkGridLayout(TTkLayout): def minimumRowHeight(self, gridRow: int): rowh = 0 anyItem = False - for item in self._gridItems[gridRow]: + for gridCol in range(self._cols): + item = self.itemAtPosition(gridRow,gridCol) if item is not None and \ ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): anyItem = True - h = item.minimumHeight() + h = item.minimumHeightSpan(gridRow) if rowh < h: rowh = h if not anyItem: @@ -196,12 +196,12 @@ class TTkGridLayout(TTkLayout): def maximumColWidth(self, gridCol: int) -> int: colw = 0x10000 anyItem = False - for gridRow in range(len(self._gridItems)): - item = self._gridItems[gridRow][gridCol] + for gridRow in range(self._rows): + item = self.itemAtPosition(gridRow,gridCol) if item is not None and \ ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): anyItem = True - w = item.maximumWidth() + w = item.maximumWidthSpan(gridCol) if colw > w: colw = w if not anyItem: @@ -211,11 +211,12 @@ class TTkGridLayout(TTkLayout): def maximumRowHeight(self, gridRow: int): rowh = 0x10000 anyItem = False - for item in self._gridItems[gridRow]: + for gridCol in range(self._cols): + item = self.itemAtPosition(gridRow,gridCol) if item is not None and \ ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): anyItem = True - h = item.maximumHeight() + h = item.maximumHeightSpan(gridRow) if rowh > h: rowh = h if not anyItem: @@ -225,32 +226,32 @@ class TTkGridLayout(TTkLayout): def minimumWidth(self) -> int: ''' process the widgets and get the min size ''' minw = 0 - for gridCol in range(len(self._gridItems[0])): + for gridCol in range(self._cols): minw += self.minimumColWidth(gridCol) return minw def minimumHeight(self) -> int: ''' process the widgets and get the min size ''' minh = 0 - for gridRow in range(len(self._gridItems)): + for gridRow in range(self._rows): minh += self.minimumRowHeight(gridRow) return minh def maximumWidth(self) -> int: ''' process the widgets and get the min size ''' - if not self._gridItems[0]: + if not self._rows: return 0x1000 maxw = 0 - for gridCol in range(len(self._gridItems[0])): + for gridCol in range(self._cols): maxw += self.maximumColWidth(gridCol) return maxw def maximumHeight(self) -> int: ''' process the widgets and get the min size ''' - if not self._gridItems[0]: + if not self._cols: return 0x1000 maxh = 0 - for gridRow in range(len(self._gridItems)): + for gridRow in range(self._rows): maxh += self.maximumRowHeight(gridRow) return maxh @@ -262,8 +263,8 @@ class TTkGridLayout(TTkLayout): # Sorted List of minimum heights # min max val # content IDs 0 1 2 3 - sortedHeights = [ [i, self.minimumRowHeight(i), self.maximumRowHeight(i), -1] for i in range(len(self._gridItems)) ] - sortedWidths = [ [i, self.minimumColWidth(i), self.maximumColWidth(i), -1] for i in range(len(self._gridItems[0])) ] + sortedHeights = [ [i, self.minimumRowHeight(i), self.maximumRowHeight(i), -1] for i in range(self._rows) ] + sortedWidths = [ [i, self.minimumColWidth(i), self.maximumColWidth(i), -1] for i in range(self._cols) ] sortedHeights = sorted(sortedHeights, key=lambda h: h[1]) sortedWidths = sorted(sortedWidths, key=lambda w: w[1]) @@ -275,8 +276,8 @@ class TTkGridLayout(TTkLayout): if h < minHeight: h = minHeight if w < minWidth: w = minWidth - #TTkLog.debug(f"w,h:({w,h}) mh:{minHeight} sh:{sortedHeights}") - #TTkLog.debug(f"w,h:({w,h}) mw:{minWidth} sw:{sortedWidths}") + # TTkLog.debug(f"Height: w,h:({w,h}) mh:{minHeight} sh:{sortedHeights}") + # TTkLog.debug(f"width: w,h:({w,h}) mw:{minWidth} sw:{sortedWidths}") def parseSizes(sizes, space, out): iterate = True @@ -321,15 +322,16 @@ class TTkGridLayout(TTkLayout): i[0] = newy newy += i[1] - #TTkLog.debug(f"h:{horSizes} v:{vertSizes}") + # TTkLog.debug(f"h:{horSizes} v:{vertSizes}") # loop and set the geometry of any item for item in self.children(): col = item._col row = item._row - item.setGeometry( - horSizes[col][0], vertSizes[row][0] , - horSizes[col][1], vertSizes[row][1] ) + x,y = horSizes[col][0], vertSizes[row][0] + w = sum( [ horSizes[col+i][1] for i in range(item._colspan) ] ) + h = sum( [ vertSizes[row+i][1] for i in range(item._rowspan) ] ) + item.setGeometry(x, y, w, h) #TTkLog.debug(f"Children: {item.geometry()}") if item.layoutItemType == TTkK.WidgetItem and not item.isEmpty(): #TTkLog.debug(f"Children name: {item.widget()._name}") diff --git a/TermTk/TTkLayouts/layout.py b/TermTk/TTkLayouts/layout.py index 2053a06b..2ab95dbc 100644 --- a/TermTk/TTkLayouts/layout.py +++ b/TermTk/TTkLayouts/layout.py @@ -34,6 +34,7 @@ class TTkLayoutItem: __slots__ = ( '_x', '_y', '_z', '_w', '_h', '_row','_col', + '_rowspan', '_colspan', '_sMax', '_sMaxVal', '_sMin', '_sMinVal', '_alignment', @@ -43,6 +44,8 @@ class TTkLayoutItem: self._z = kwargs.get('z',0) self._row = kwargs.get('row', 0) self._col = kwargs.get('col', 0) + self._rowspan = kwargs.get('rowspan', 1) + self._colspan = kwargs.get('colspan', 1) self._layoutItemType = kwargs.get('layoutItemType', TTkK.NONE) self._alignment = kwargs.get('alignment', TTkK.NONE) self._w, self._h = 0, 0 @@ -54,12 +57,33 @@ class TTkLayoutItem: def minDimension(self,o)-> int: return 0 def minimumHeight(self) -> int: return 0 def minimumWidth(self) -> int: return 0 + def minimumHeightSpan(self,pos) -> int: return 0 + def minimumWidthSpan(self,pos) -> int: return 0 def maximumSize(self): return self.maximumWidth(), self.maximumHeight() def maxDimension(self,o)-> int: return 0x1000 def maximumHeight(self) -> int: return 0x10000 def maximumWidth(self) -> int: return 0x10000 + def maximumHeightSpan(self,pos) -> int: return 0x10000 + def maximumWidthSpan(self,pos) -> int: return 0x10000 + + @staticmethod + def _calcSpanValue(value, pos, curpos, span): + if pos==curpos: + return value - (value//span) * (span-1) + else: + return value//span + + def minimumHeightSpan(self,pos) -> int: + return TTkLayoutItem._calcSpanValue(self.minimumHeight(),pos,self._row,self._rowspan) + def minimumWidthSpan(self,pos) -> int: + return TTkLayoutItem._calcSpanValue(self.minimumWidth(), pos,self._col,self._colspan) + def maximumHeightSpan(self,pos) -> int: + return TTkLayoutItem._calcSpanValue(self.maximumHeight(),pos,self._row,self._rowspan) + def maximumWidthSpan(self,pos) -> int: + return TTkLayoutItem._calcSpanValue(self.maximumWidth(), pos,self._col,self._colspan) + def geometry(self): return self._x, self._y, self._w, self._h diff --git a/demo/demo.py b/demo/demo.py index c9953de2..34b8074c 100755 --- a/demo/demo.py +++ b/demo/demo.py @@ -28,19 +28,20 @@ import random sys.path.append(os.path.join(sys.path[0],'..')) import TermTk as ttk -from showcase.layout import demoLayout -from showcase.layoutnested import demoLayoutNested -from showcase.table import demoTable -from showcase.tab import demoTab -from showcase.tree import demoTree -from showcase.graph import demoGraph -from showcase.splitter import demoSplitter -from showcase.windows import demoWindows -from showcase.formwidgets import demoFormWidgets -from showcase.scrollarea import demoScrollArea -from showcase.list import demoList -from showcase.menubar import demoMenuBar -from showcase.colorpicker import demoColorPicker +from showcase.layout_basic import demoLayout +from showcase.layout_nested import demoLayoutNested +from showcase.layout_span import demoLayoutSpan +from showcase.table import demoTable +from showcase.tab import demoTab +from showcase.tree import demoTree +from showcase.graph import demoGraph +from showcase.splitter import demoSplitter +from showcase.windows import demoWindows +from showcase.formwidgets import demoFormWidgets +from showcase.scrollarea import demoScrollArea +from showcase.list import demoList +from showcase.menubar import demoMenuBar +from showcase.colorpicker import demoColorPicker words = ["Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit,", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua.", "Ut", "enim", "ad", "minim", "veniam,", "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea", "commodo", "consequat.", "Duis", "aute", "irure", "dolor", "in", "reprehenderit", "in", "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla", "pariatur.", "Excepteur", "sint", "occaecat", "cupidatat", "non", "proident,", "sunt", "in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id", "est", "laborum."] def getWord(): @@ -54,6 +55,7 @@ def demoShowcase(root=None, border=True): tabWidget1.addTab(ttk.TTkTestWidget(border=True, title="Frame1.2"), " Label Test 1.2 ") tabWidget1.addTab(demoLayout(), " Layout Test ") tabWidget1.addTab(demoLayoutNested()," Nested Layout Test ") + tabWidget1.addTab(demoLayoutSpan(), " Layout Span Test ") tabWidget1.addTab(demoMenuBar(), " MenuBar Test ") tabWidget1.addTab(demoFormWidgets(), " Form Test ") tabWidget1.addTab(demoList(), " List Test ") diff --git a/demo/showcase/layout.py b/demo/showcase/layout_basic.py similarity index 100% rename from demo/showcase/layout.py rename to demo/showcase/layout_basic.py diff --git a/demo/showcase/layoutnested.py b/demo/showcase/layout_nested.py similarity index 100% rename from demo/showcase/layoutnested.py rename to demo/showcase/layout_nested.py diff --git a/demo/showcase/layout_span.py b/demo/showcase/layout_span.py new file mode 100755 index 00000000..d03cacd3 --- /dev/null +++ b/demo/showcase/layout_span.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys, os, argparse + +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + + +def demoLayoutSpan(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + + gridLayout = ttk.TTkGridLayout() + frame.setLayout(gridLayout) + + nestedLayout = ttk.TTkGridLayout() + gridLayout.addItem(nestedLayout,1,1) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button1"),0,0,1,2) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button2"),0,2,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button3"),1,0,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button4"),2,1,1,2) + + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B1"),0,0,2,1) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B2"),0,1,1,2) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B3"),1,2,2,1) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B4"),2,0,1,2) + + return frame + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-f', help='Full Screen', action='store_true') + args = parser.parse_args() + + ttk.TTkLog.use_default_file_logging() + + root = ttk.TTk() + if args.f: + rootLayout = root + root.setLayout(ttk.TTkGridLayout()) + else: + rootLayout = ttk.TTkWindow(title="Test Layout", parent=root,pos=(1,1), size=(100,40), border=True, layout=ttk.TTkGridLayout()) + demoLayoutSpan(rootLayout) + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tests/test.ui.003.layout.span.py b/tests/test.ui.003.layout.span.py new file mode 100755 index 00000000..b87f674b --- /dev/null +++ b/tests/test.ui.003.layout.span.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys, os + +sys.path.append(os.path.join(sys.path[0],'..')) +import TermTk as ttk + + +def demoLayoutSpan1(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + + gridLayout = ttk.TTkGridLayout() + frame.setLayout(gridLayout) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button1"),0,0,1,4) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button2"),0,4,4,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button3"),1,0,4,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button4"),4,1,1,4) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="B1"),1,1,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="B2"),1,2,1,2) + gridLayout.addWidget(ttk.TTkButton(border=True, text="B3"),2,3,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="B4"),3,1,1,2) + + return frame + +def demoLayoutSpan2(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + + gridLayout = ttk.TTkGridLayout() + frame.setLayout(gridLayout) + + nestedLayout = ttk.TTkGridLayout() + gridLayout.addItem(nestedLayout,1,1) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button1"),0,0,1,2) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button2"),0,2,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button3"),1,0,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button4"),2,1,1,2) + + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B1", color=ttk.TTkColor.fg("#880000")+ttk.TTkColor.bg("#ffff66")+ttk.TTkColor.BOLD),0,0,2,1) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B2", color=ttk.TTkColor.fg("#880000")+ttk.TTkColor.bg("#ffff66")+ttk.TTkColor.BOLD),0,1,1,2) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B3", color=ttk.TTkColor.fg("#880000")+ttk.TTkColor.bg("#ffff66")+ttk.TTkColor.BOLD),1,2,2,1) + nestedLayout.addWidget(ttk.TTkButton(border=True, text="B4", color=ttk.TTkColor.fg("#880000")+ttk.TTkColor.bg("#ffff66")+ttk.TTkColor.BOLD),2,0,1,2) + + return frame + +def demoLayoutSpan3(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + + gridLayout = ttk.TTkGridLayout() + frame.setLayout(gridLayout) + + nestedLayout = ttk.TTkGridLayout() + gridLayout.addItem(nestedLayout,1,1) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button1"),0,0,1,5) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button2"),0,5,3,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button3"),1,0,4,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button4"),4,1,1,2) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button5"),1,1,3,3) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button6"),1,4,2,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button7"),3,4,2,2) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button8"),4,3) + + return frame + + +def main(): + ttk.TTkLog.use_default_file_logging() + + root = ttk.TTk() + rootLayout1 = ttk.TTkWindow(title="Test Layout", parent=root,pos=(0,0), size=(70,30), border=True, layout=ttk.TTkGridLayout()) + demoLayoutSpan1(rootLayout1) + rootLayout2 = ttk.TTkWindow(title="Test Nested Layout", parent=root,pos=(10,5), size=(70,30), border=True, layout=ttk.TTkGridLayout()) + demoLayoutSpan2(rootLayout2) + rootLayout3 = ttk.TTkWindow(title="Test 2d Span", parent=root,pos=(20,10), size=(70,30), border=True, layout=ttk.TTkGridLayout()) + demoLayoutSpan3(rootLayout3) + rootLayout4 = ttk.TTkWindow(title="Logs", parent=root,pos=(15,7), size=(100,25), border=True, layout=ttk.TTkGridLayout()) + ttk.TTkLogViewer(parent=rootLayout4) + + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file