From 5fd1142731306a3195e810437ee90e65dc714ce0 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Fri, 5 Mar 2021 15:37:46 +0000 Subject: [PATCH] reimplemented remove/add widget/item in the grid layout to support nested items --- TermTk/TTkLayouts/boxlayout.py | 2 + TermTk/TTkLayouts/gridlayout.py | 86 +++++++++++++++++++-------------- TermTk/TTkLayouts/layout.py | 20 +++++--- tests/showcase/layoutnested.py | 71 +++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 43 deletions(-) create mode 100755 tests/showcase/layoutnested.py diff --git a/TermTk/TTkLayouts/boxlayout.py b/TermTk/TTkLayouts/boxlayout.py index f5a15f9b..f3ad9d8c 100644 --- a/TermTk/TTkLayouts/boxlayout.py +++ b/TermTk/TTkLayouts/boxlayout.py @@ -33,5 +33,7 @@ class TTkHBoxLayout(TTkGridLayout): pass class TTkVBoxLayout(TTkGridLayout): + def addItem(self, item): + TTkGridLayout.addItem(self, item, self.count(), 0) def addWidget(self, widget): TTkGridLayout.addWidget(self, widget, self.count(), 0) \ No newline at end of file diff --git a/TermTk/TTkLayouts/gridlayout.py b/TermTk/TTkLayouts/gridlayout.py index 09d1552b..d8d2d49c 100644 --- a/TermTk/TTkLayouts/gridlayout.py +++ b/TermTk/TTkLayouts/gridlayout.py @@ -30,17 +30,10 @@ from TermTk.TTkCore.constant import TTkK from TermTk.TTkCore.log import TTkLog from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem -class TTkGridWidgetItem(TTkWidgetItem): - __slots__ = ('_row','_col') - def __init__(self, *args, **kwargs): - TTkWidgetItem.__init__(self, args[0]) - self._row = kwargs.get('row') - self._col = kwargs.get('col') - class TTkGridLayout(TTkLayout): __slots__ = ('_gridItems','_columnMinWidth','_columnMinHeight') def __init__(self, *args, **kwargs): - TTkLayout.__init__(self, args, kwargs) + TTkLayout.__init__(self, *args, **kwargs) self._gridItems = [[]] self._columnMinWidth = kwargs.get('columnMinWidth',0) self._columnMinHeight = kwargs.get('columnMinHeight',0) @@ -82,6 +75,14 @@ class TTkGridLayout(TTkLayout): widget = args[0] self.removeWidget(widget) widget._parent = self.parentWidget() + item = TTkWidgetItem(widget=widget) + self.addItem(*[item], **kwargs) + widget.update(updateParent=True) + + def replaceItem(self, item, index): pass + def addItem(self, *args, **kwargs): + item = args[0] + self.removeItem(item) if len(args) == 3: row = args[1] col = args[2] @@ -93,9 +94,9 @@ class TTkGridLayout(TTkLayout): #retrieve the max col/rows to reshape the grid maxrow = row maxcol = col - for item in self.children(): - if maxrow < item._row: maxrow = item._row - if maxcol < item._col: maxcol = item._col + 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 @@ -103,18 +104,29 @@ class TTkGridLayout(TTkLayout): if self._gridItems[row][col] is not None: # TODO: Handle the LayoutItem - self.removeWidget(self._gridItems[row][col]) + self.removeItem(self._gridItems[row][col]) - item = TTkGridWidgetItem(widget, row=row, col=col) + item._row = row + item._col = col self._gridItems[row][col] = item - self.addItem(item) - widget.update(updateParent=True) + TTkLayout.addItem(self, item) + if self.parentWidget(): + self.parentWidget().update() + + def removeItem(self, item): + TTkLayout.removeItem(self, item) + for gridRow in range(len(self._gridItems)): + for gridCol in range(len(self._gridItems[0])): + 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])): if self._gridItems[gridRow][gridCol] is not None and \ + self._gridItems[gridRow][gridCol].layoutItemType == TTkK.WidgetItem and \ self._gridItems[gridRow][gridCol].widget() == widget: self._gridItems[gridRow][gridCol] = None self._reshapeGrid(self._gridUsedsize()) @@ -130,11 +142,12 @@ class TTkGridLayout(TTkLayout): anyItem = False for gridRow in range(len(self._gridItems)): item = self._gridItems[gridRow][gridCol] - if item is not None and item.isVisible(): - anyItem = True - w = item.minimumWidth() - if colw < w: - colw = w + if item is not None and \ + ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): + anyItem = True + w = item.minimumWidth() + if colw < w: + colw = w if not anyItem: return self._columnMinWidth return colw @@ -143,11 +156,12 @@ class TTkGridLayout(TTkLayout): rowh = 0 anyItem = False for item in self._gridItems[gridRow]: - if item is not None and item.isVisible(): - anyItem = True - h = item.minimumHeight() - if rowh < h: - rowh = h + if item is not None and \ + ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): + anyItem = True + h = item.minimumHeight() + if rowh < h: + rowh = h if not anyItem: return self._columnMinHeight return rowh @@ -157,11 +171,12 @@ class TTkGridLayout(TTkLayout): anyItem = False for gridRow in range(len(self._gridItems)): item = self._gridItems[gridRow][gridCol] - if item is not None and item.isVisible(): - anyItem = True - w = item.maximumWidth() - if colw > w: - colw = w + if item is not None and \ + ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): + anyItem = True + w = item.maximumWidth() + if colw > w: + colw = w if not anyItem: return self._columnMinWidth return colw @@ -170,11 +185,12 @@ class TTkGridLayout(TTkLayout): rowh = 0x10000 anyItem = False for item in self._gridItems[gridRow]: - if item is not None and item.isVisible(): - anyItem = True - h = item.maximumHeight() - if rowh > h: - rowh = h + if item is not None and \ + ( item.layoutItemType == TTkK.LayoutItem or item.isVisible() ): + anyItem = True + h = item.maximumHeight() + if rowh > h: + rowh = h if not anyItem: return self._columnMinHeight return rowh diff --git a/TermTk/TTkLayouts/layout.py b/TermTk/TTkLayouts/layout.py index e37763e2..fb5bfc9b 100644 --- a/TermTk/TTkLayouts/layout.py +++ b/TermTk/TTkLayouts/layout.py @@ -30,10 +30,12 @@ from TermTk.TTkCore.log import TTkLog from TermTk.TTkCore.constant import TTkK class TTkLayoutItem: - __slots__ = ('_x', '_y', '_z', '_w', '_h', '_sMax', '_sMaxVal', '_sMin', '_sMinVal', '_layoutItemType') + __slots__ = ('_x', '_y', '_z', '_w', '_h', '_row','_col', '_sMax', '_sMaxVal', '_sMin', '_sMinVal', '_layoutItemType') def __init__(self, *args, **kwargs): self._x, self._y = 0, 0 self._z = kwargs.get('z',0) + self._row = kwargs.get('row', 0) + self._col = kwargs.get('col', 0) self._layoutItemType = kwargs.get('layoutItemType', TTkK.NONE) self._w, self._h = 0, 0 self._sMax, self._sMin = False, False @@ -95,7 +97,7 @@ class TTkLayout(TTkLayoutItem): if isinstance(parent, TTkLayoutItem): self._parent = parent else: - self._parent = TTkWidgetItem(parent) + self._parent = TTkWidgetItem(widget=parent) def parentWidget(self): if self._parent is None: return None @@ -121,15 +123,17 @@ class TTkLayout(TTkLayoutItem): def addWidget(self, widget): if widget.parentWidget() is not None: widget.parentWidget().removeWidget(self) - self.addItem(TTkWidgetItem(widget)) + self.addItem(TTkWidgetItem(widget=widget)) def removeItem(self, item): - self._items.remove(item) + if item in self._items: + self._items.remove(item) self._zSortItems() def removeWidget(self, widget): for item in self._items: - if item.widget() == widget: + if item.layoutItemType == TTkK.WidgetItem and \ + item.widget() == widget: self.removeItem(item) def findBranchWidget(self, widget): @@ -200,9 +204,9 @@ class TTkLayout(TTkLayoutItem): class TTkWidgetItem(TTkLayoutItem): slots = ('_widget') - def __init__(self, widget, z=0): - TTkLayoutItem.__init__(self) - self._widget = widget + def __init__(self, *args, **kwargs): + TTkLayoutItem.__init__(self, *args, **kwargs) + self._widget = kwargs.get('widget', None) self.layoutItemType = TTkK.WidgetItem def widget(self): diff --git a/tests/showcase/layoutnested.py b/tests/showcase/layoutnested.py new file mode 100755 index 00000000..1c75a25b --- /dev/null +++ b/tests/showcase/layoutnested.py @@ -0,0 +1,71 @@ +#!/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 demoLayoutNested(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + mainLayout = ttk.TTkVBoxLayout() + frame.setLayout(mainLayout) + + gridLayout = ttk.TTkGridLayout() + mainLayout.addItem(gridLayout) + + mainLayout.addWidget(ttk.TTkFrame(border=True,title="Frame1")) + mainLayout.addWidget(ttk.TTkFrame(border=True,title="Frame2")) + + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button1"),0,0) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button2"),1,1) + gridLayout.addWidget(ttk.TTkButton(border=True, text="Button3"),2,2) + + gridLayout.addWidget(ttk.TTkFrame(border=True,title="Frame3"),0,1) + gridLayout.addWidget(ttk.TTkFrame(border=True,title="Frame4"),2,3) + + 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()) + demoLayoutNested(rootLayout) + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file