From 40abf1209bbdbe3d0ed0292e1c8d56adecf36b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parodi=2C=20Eugenio=20=F0=9F=8C=B6?= Date: Sat, 30 Aug 2025 11:17:49 +0200 Subject: [PATCH] chore: reworked the tree icon --- .vscode/launch.json | 28 ++++++++++----- TermTk | 1 - .../TTkWidgets/TTkModelView/filetreewidget.py | 12 ------- .../TTkModelView/filetreewidgetitem.py | 13 +++++++ .../TTkWidgets/TTkModelView/treewidget.py | 35 ++++++++++++++----- .../TTkWidgets/TTkModelView/treewidgetitem.py | 32 +++++++++-------- 6 files changed, 77 insertions(+), 44 deletions(-) delete mode 120000 TermTk diff --git a/.vscode/launch.json b/.vscode/launch.json index e56b17f7..1fc60d27 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -46,7 +46,8 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "TERMTK_GPM": "1" + "TERMTK_GPM": "1", + "PYTHONPATH": "./libs/pyTermTk" }, }, { @@ -59,7 +60,10 @@ "args": [ "-p", "tmp/test.input.001.bin" - ] + ], + "env": { + "PYTHONPATH": "./libs/pyTermTk" + } }, { "name": "py Debug: Module ttkDesigner", @@ -69,7 +73,7 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "PYTHONPATH": "./apps/ttkDesigner" + "PYTHONPATH": "./libs/pyTermTk:./apps/ttkDesigner" } }, { @@ -80,7 +84,7 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "PYTHONPATH": "./tools" + "PYTHONPATH": "./libs/pyTermTk:./tools" }, "args": [ "ttkDesigner/tui/newWindow.tui.json" @@ -94,7 +98,7 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "PYTHONPATH": "./apps/dumbPaintTool" + "PYTHONPATH": "./libs/pyTermTk:./apps/dumbPaintTool" } }, { @@ -105,7 +109,7 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "PYTHONPATH": "./tools" + "PYTHONPATH": "./libs/pyTermTk:./tools" }, "args": [ "experiments/untitled.DPT.json" @@ -130,7 +134,7 @@ "console": "integratedTerminal", "justMyCode": true, "env": { - "PYTHONPATH": "./apps/tlogg" + "PYTHONPATH": "./apps/tlogg:./libs/pyTermTk" } }, { @@ -139,7 +143,10 @@ "request": "launch", "program": "demo/demo.py", "console": "integratedTerminal", - "justMyCode": true + "justMyCode": true, + "env": { + "PYTHONPATH": "./libs/pyTermTk" + } }, { "name": "Python: Demo Mouse tracking", @@ -150,7 +157,10 @@ "justMyCode": true, "args": [ "-t" - ] + ], + "env": { + "PYTHONPATH": "./libs/pyTermTk" + } }, { "name": "Python: sphinx", diff --git a/TermTk b/TermTk deleted file mode 120000 index 547ca510..00000000 --- a/TermTk +++ /dev/null @@ -1 +0,0 @@ -libs/pyTermTk/TermTk \ No newline at end of file diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidget.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidget.py index 03488b7d..30fc8dfd 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidget.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidget.py @@ -158,8 +158,6 @@ class TTkFileTreeWidget(TTkTreeWidget): self.resizeColumnToContents(1) self.resizeColumnToContents(2) self.resizeColumnToContents(3) - self.itemExpanded.connect(self._folderExpanded) - self.itemCollapsed.connect(self._folderCollapsed) self.itemExpanded.connect(self._updateChildren) self.itemActivated.connect(self._activated) @@ -222,7 +220,6 @@ class TTkFileTreeWidget(TTkTreeWidget): raw = [ n , -1 , typef , rawTime ], path=nodePath, type=TTkFileTreeWidgetItem.DIR, - icon=TTkString() + TTkCfg.theme.folderIconColor + TTkCfg.theme.fileIcon.folderClose + TTkColor.RST, childIndicatorPolicy=TTkK.ShowIndicator)) elif os.path.isfile(nodePath) or os.path.islink(nodePath): @@ -252,18 +249,9 @@ class TTkFileTreeWidget(TTkTreeWidget): raw = [ n , rawSize , typef , rawTime ], path=nodePath, type=TTkFileTreeWidgetItem.FILE, - icon=TTkString() + TTkCfg.theme.fileIconColor + TTkCfg.theme.fileIcon.getIcon(n) + TTkColor.RST, childIndicatorPolicy=TTkK.DontShowIndicator)) return ret - @staticmethod - def _folderExpanded(item): - item.setIcon(0, TTkString() + TTkCfg.theme.folderIconColor + TTkCfg.theme.fileIcon.folderOpen + TTkColor.RST,) - - @staticmethod - def _folderCollapsed(item): - item.setIcon(0, TTkString() + TTkCfg.theme.folderIconColor + TTkCfg.theme.fileIcon.folderClose + TTkColor.RST,) - @pyTTkSlot(TTkFileTreeWidgetItem) def _updateChildren(self, item): if item.children(): return diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidgetitem.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidgetitem.py index ca334de2..e119f119 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidgetitem.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/filetreewidgetitem.py @@ -24,6 +24,8 @@ __all__ = ['TTkFileTreeWidgetItem'] import re +from TermTk.TTkCore.cfg import TTkCfg +from TermTk.TTkCore.string import TTkString from TermTk.TTkCore.constant import TTkK from TermTk.TTkWidgets.TTkModelView.treewidgetitem import TTkTreeWidgetItem @@ -59,6 +61,17 @@ class TTkFileTreeWidgetItem(TTkTreeWidgetItem): else: self.setHidden(True) + def icon(self, col): + if col > 0: + return super().icon(col) + if self._type == TTkFileTreeWidgetItem.FILE: + return TTkString( ' '+TTkCfg.theme.fileIcon.getIcon(self._path)+' ', TTkCfg.theme.fileIconColor) + else: + if self._expanded: + return TTkString(' '+TTkCfg.theme.fileIcon.folderOpen+' ', TTkCfg.theme.folderIconColor) + else: + return TTkString(' '+TTkCfg.theme.fileIcon.folderClose+' ', TTkCfg.theme.folderIconColor) + def sortData(self, col:int): return self._raw[col] diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py index 6cb2d22a..66b02805 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py @@ -22,7 +22,7 @@ __all__ = ['TTkTreeWidget'] -from typing import List +from typing import List,Tuple,Optional from TermTk.TTkCore.cfg import TTkCfg from TermTk.TTkCore.log import TTkLog @@ -40,6 +40,25 @@ from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot from dataclasses import dataclass +class _RootWidgetItem(TTkTreeWidgetItem): + def __init__(self): + super().__init__(expanded=True) + + def _getColumnContentSize(self, column:int, offset:int) -> int: + if offset+0x200 > (_sz:=self.size()): + offset = _sz-0x200 + if offset < 0x200: + offset = 0x200 + limited_page = self._get_page_root(offset-0x200,0x400) + if column==0: + size = max(max(_l+_i.icon(column).termWidth()+_t.termWidth() for _t in _i.data(column).split('\n')) for _l,_y,_i in limited_page if not _y) + else: + size = max(max((_i.icon(column)+_t).termWidth() for _t in _i.data(column).split('\n')) for _l,_y,_i in limited_page if not _y) + return size-1 + + def _get_page_root(self, index:int, size:int) -> List[Tuple[int,int,TTkTreeWidgetItem]]: + return super()._get_page(-1, index+1, size) + class TTkTreeWidget(TTkAbstractScrollView): ''' The :py:class:`TTkTreeWidget` class is a convenience class that provides a standard tree @@ -178,6 +197,7 @@ class TTkTreeWidget(TTkAbstractScrollView): ) _selected:List[TTkTreeWidgetItem] + _rootItem:_RootWidgetItem @dataclass(frozen=True) class _DropTreeData: @@ -220,7 +240,7 @@ class TTkTreeWidget(TTkAbstractScrollView): self._sortingEnabled=sortingEnabled self._sortColumn = -1 self._sortOrder = TTkK.AscendingOrder - self._rootItem = TTkTreeWidgetItem(expanded=True) + self._rootItem = _RootWidgetItem() super().__init__(**kwargs) self.setMinimumHeight(1) self.setFocusPolicy(TTkK.ClickFocus) @@ -247,7 +267,7 @@ class TTkTreeWidget(TTkAbstractScrollView): ri.setTreeItemParent(None) if self._rootItem: self._rootItem.dataChanged.disconnect(self._refreshCache) - self._rootItem = TTkTreeWidgetItem(expanded=True) + self._rootItem = _RootWidgetItem() self._rootItem.dataChanged.connect(self._refreshCache) self.sortItems(self._sortColumn, self._sortOrder) self._refreshCache() @@ -358,9 +378,8 @@ class TTkTreeWidget(TTkAbstractScrollView): def resizeColumnToContents(self, column:int) -> None: '''resizeColumnToContents''' - TTkLog.critical('resizeColumnToContents Method Unimplemented') - return - contentSize = max(row.data[column].termWidth() for row in self._cache) + _,oy = self.getViewOffsets() + contentSize = self._rootItem._getColumnContentSize(column, oy) self.setColumnWidth(column, contentSize) @pyTTkSlot() @@ -631,7 +650,7 @@ class TTkTreeWidget(TTkAbstractScrollView): canvas.drawChar(pos=(sx-x,sy), char=tt[4], color=lineColor) col_slices = list(zip([0]+[_p+1 for _p in self._columnsPos], self._columnsPos)) - for _y, (_l, _yi, _i) in enumerate(self._rootItem._get_page(-1,1+y,h+1)): + for _y, (_l, _yi, _i) in enumerate(self._rootItem._get_page_root(y,h)): for il in range(len(self._header)): _lx,_lx1 = col_slices[il] _width = _lx1-_lx @@ -639,7 +658,7 @@ class TTkTreeWidget(TTkAbstractScrollView): _data = _i.data(il).split('\n') + [TTkString()]*_ih if il==0: # First Column if _yi == 0: - _icon = f"{' '*_l} "+_i.icon(il)+" " + _icon = f"{' '*_l}"+_i.icon(il) elif _yi == _ih-1: _icon = TTkString(f"{' '*_l} ╽ ", lineHeightColor) elif _yi == 1: diff --git a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py index f2001646..4b8fe605 100644 --- a/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py +++ b/libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py @@ -29,7 +29,7 @@ from typing import List, Tuple, Iterator, Generator, Optional, Callable, Any from TermTk.TTkCore.cfg import TTkCfg from TermTk.TTkCore.constant import TTkK -from TermTk.TTkCore.string import TTkString +from TermTk.TTkCore.string import TTkString, TTkStringType from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal from TermTk.TTkWidgets import TTkWidget from TermTk.TTkAbstract.abstractitemmodel import TTkAbstractItemModel @@ -157,6 +157,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): '_sizeChangedHandler' ) + _icon:List[TTkString] _children:List[TTkTreeWidgetItem] _buffer:_TTkTreeBuffer _sizeChangedHandler: Callable[[TTkTreeWidgetItem,int,int], None] @@ -166,7 +167,7 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): expanded:bool=False, selected:bool=False, hidden:bool=False, - icon:TTkString=None, + icon:TTkStringType='', childIndicatorPolicy:TTkK.ChildIndicatorPolicy =TTkK.ChildIndicatorPolicy.DontShowIndicatorWhenChildless, **kwargs) -> None: # Signals @@ -208,15 +209,15 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): self._data, self._widgets = self._processDataInput(data) self._alignment = [TTkK.LEFT_ALIGN]*len(self._data) - self._icon = ['']*len(self._data) + self._icon = [TTkString()]*len(self._data) self._setDefaultIcon() if icon: - self._icon[0] = icon + self._icon[0] = ' '+TTkString(icon)+TTkString(' ') self._defaultIcon = False if parent: parent.addChild(self) - def _processDataInputWidget(self, widget, index): + def _processDataInputWidget(self, widget, index) -> TTkString: self._hasWidgets = True widget.hide() widget.sizeChanged.connect(self._widgetSizeChanged) @@ -256,13 +257,13 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): def _setDefaultIcon(self): if not self._defaultIcon: return - self._icon[0] = TTkCfg.theme.tree[0] + self._icon[0] = TTkString(' '+TTkCfg.theme.tree[0]+' ') if self._childIndicatorPolicy == TTkK.DontShowIndicatorWhenChildless and self._children or \ self._childIndicatorPolicy == TTkK.ShowIndicator: if self._expanded: - self._icon[0] = TTkCfg.theme.tree[2] + self._icon[0] = TTkString(' '+TTkCfg.theme.tree[2]+' ') else: - self._icon[0] = TTkCfg.theme.tree[1] + self._icon[0] = TTkString(' '+TTkCfg.theme.tree[1]+' ') @pyTTkSlot(int, int) def _widgetSizeChanged(self, _, h): @@ -449,15 +450,18 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): return self._children.index(child) return None - def icon(self, col): + def icon(self, col) -> TTkString: if col >= len(self._icon): - return '' + return TTkString() return self._icon[col] - def setIcon(self, col, icon): + def setIcon(self, col:int, icon:TTkStringType) -> None: if col==0: self._defaultIcon = False - self._icon[col] = icon + if isinstance(icon,str): + self._icon[col] = TTkString(' '+icon+' ') + else: + self._icon[col] = ' '+icon+TTkString(' ') self.dataChanged.emit() def textAlignment(self, col): @@ -469,9 +473,9 @@ class TTkTreeWidgetItem(TTkAbstractItemModel): self._alignment[col] = alignment self.dataChanged.emit() - def data(self, col, role=None): + def data(self, col, role=None) -> TTkString: if col >= len(self._data): - return '' + return TTkString() return self._data[col] def widget(self, col, role=None):