From 6f51b291102ac4531276782145a51e7b25e3ac71 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Thu, 7 Nov 2024 17:19:32 +0000 Subject: [PATCH] Reworked the 'Abstract Scroll' generic initializatioon and documentation --- Makefile | 15 +- TermTk/TTkAbstract/abstractscrollview.py | 105 +++++- TermTk/TTkCore/constant.py | 30 +- TermTk/TTkTemplates/dragevents.py | 2 + TermTk/TTkTemplates/keyevents.py | 2 + TermTk/TTkTemplates/mouseevents.py | 2 + TermTk/TTkTestWidgets/logviewer.py | 3 - TermTk/TTkTestWidgets/testabstractscroll.py | 2 - TermTk/TTkTestWidgets/tominspector.py | 6 - TermTk/TTkWidgets/Fancy/tableview.py | 7 - .../TTkWidgets/TTkModelView/filetreewidget.py | 2 + TermTk/TTkWidgets/TTkModelView/table.py | 6 +- .../TTkWidgets/TTkModelView/tablemodelcsv.py | 16 +- .../TTkWidgets/TTkModelView/tablemodellist.py | 23 +- TermTk/TTkWidgets/TTkModelView/tablewidget.py | 46 ++- TermTk/TTkWidgets/TTkModelView/tree.py | 4 + TermTk/TTkWidgets/TTkModelView/treewidget.py | 10 +- TermTk/TTkWidgets/TTkPickers/textpicker.py | 3 - TermTk/TTkWidgets/TTkTerminal/terminal.py | 35 +- TermTk/TTkWidgets/TTkTerminal/terminalview.py | 132 ++++++- TermTk/TTkWidgets/button.py | 23 +- TermTk/TTkWidgets/checkbox.py | 22 +- TermTk/TTkWidgets/combobox.py | 25 +- TermTk/TTkWidgets/container.py | 37 +- TermTk/TTkWidgets/frame.py | 17 +- TermTk/TTkWidgets/list_.py | 61 ++-- TermTk/TTkWidgets/listwidget.py | 75 +++- TermTk/TTkWidgets/menu.py | 3 - TermTk/TTkWidgets/radiobutton.py | 19 +- TermTk/TTkWidgets/scrollarea.py | 3 - TermTk/TTkWidgets/texedit.py | 337 ++++++------------ TermTk/TTkWidgets/widget.py | 91 ++--- docs/source/conf.py | 3 +- .../sphinx_modules/sphinx_PyRefRole_hacked.py | 8 +- .../sphinx_ext_autosummary_reworked.py | 56 ++- docs/source/static/theme_overrides.css | 3 +- tutorial/000-examples.rst | 2 + 37 files changed, 729 insertions(+), 507 deletions(-) diff --git a/Makefile b/Makefile index 3d832a93..f49a2a55 100644 --- a/Makefile +++ b/Makefile @@ -85,17 +85,20 @@ deployDoc: pyTermTk-Docs cd pyTermTk-Docs ; \ git checkout main ; \ git pull ; \ - rm -rf _* info tutorial ; \ - cp -a ../docs/source/_build/html/* \ - ../docs/source/_build/html/.buildinfo \ - ../docs/source/_build/html/.nojekyll \ - . ; \ + rm -rf _* info tutorial ; + + cp -a docs/source/_build/html/* \ + docs/source/_build/html/.buildinfo \ + docs/source/_build/html/.nojekyll \ + pyTermTk-Docs ; \ + cd pyTermTk-Docs ; \ git add . ; \ git commit -m "Updated Docs" ; \ git push origin main ; \ git checkout gh-pages ; \ git merge main ; \ - git push origin gh-pages ; \ + git push origin gh-pages ; + echo "Docs Deployed!!!" deploySandbox: diff --git a/TermTk/TTkAbstract/abstractscrollview.py b/TermTk/TTkAbstract/abstractscrollview.py index 2389edcb..cfb397f4 100644 --- a/TermTk/TTkAbstract/abstractscrollview.py +++ b/TermTk/TTkAbstract/abstractscrollview.py @@ -30,25 +30,104 @@ from TermTk.TTkLayouts.layout import TTkLayout from TermTk.TTkLayouts.gridlayout import TTkGridLayout class TTkAbstractScrollViewInterface(): - '''TTkAbstractScrollViewInterface''' + ''' + The :py:class:`TTkAbstractScrollViewInterface` provide the basic interface that can be used in :py:class:`TTkAbstractScrollArea` to enable on-demand scroll bars. + + When subclassing :py:class:`TTkAbstractScrollViewInterface`, + you must implement :meth:`viewFullAreaSize`, :meth:`viewDisplayedSize`, :meth:`getViewOffsets`, and :meth:`viewMoveTo`. + + This interface is implemented in the following specialised classes: + + * :py:class:`TTkAbstractScrollView` + * :py:class:`TTkAbstractScrollViewLayout` + * :py:class:`TTkAbstractScrollViewGridLayout` + ''' + + def __init__(self) -> None: pass # Override this function def viewFullAreaSize(self) -> (int, int): + ''' + This method returns the full widget area size of the :py:class:`TTkAbstractScrollViewInterface` implementation. + + This is required to `TTkAbstractScrollArea` implementation to handle the on-demand scroll bars. + + .. note:: Reimplement this function to handle this event + + :return: the full area size as a tuple of 2 int elements (width,height) + :rtype: tuple[int,int] + ''' raise NotImplementedError() # Override this function def viewDisplayedSize(self) -> (int, int): + ''' + This method returns the displayed size of the :py:class:`TTkAbstractScrollViewInterface` implementation. + + .. note:: + + Reimplement this function to handle this event + + This method is already implemented in the following classes: + + * :py:class:`TTkAbstractScrollView` + * :py:class:`TTkAbstractScrollViewLayout` + * :py:class:`TTkAbstractScrollViewGridLayout` + + Unless a different iplementation is required, by default it should return :py:meth:`TTkWidget.size` + + :return: the displayed size as a tuple of 2 int elements (width,height) + :rtype: tuple[int,int] + ''' raise NotImplementedError() @pyTTkSlot(int, int) def viewMoveTo(self, x: int, y: int): + ''' + This method is used to set the vertical and horizontal offsets of the :py:class:`TTkAbstractScrollViewInterface` + + .. note:: + + Reimplement this function to handle this event + + This method is already implemented in the following classes: + * :py:class:`TTkAbstractScrollView` + * :py:class:`TTkAbstractScrollViewLayout` + * :py:class:`TTkAbstractScrollViewGridLayout` + + :param x: the horizontal position + :type x: int + :param y: the vertical position + :type y: int + ''' raise NotImplementedError() - def getViewOffsets(self): + def getViewOffsets(self) -> tuple: + ''' + Retrieve the vertical and horizontal offsets of the :py:class:`TTkAbstractScrollViewInterface` + + .. note:: + + Reimplement this function to handle this event + + This method is already implemented in the following classes: + * :py:class:`TTkAbstractScrollView` + * :py:class:`TTkAbstractScrollViewLayout` + * :py:class:`TTkAbstractScrollViewGridLayout` + + :return: the (x,y) offset + :rtype: tuple[int,int] + ''' return self._viewOffsetX, self._viewOffsetY class TTkAbstractScrollView(TTkContainer, TTkAbstractScrollViewInterface): - '''TTkAbstractScrollView''' + ''' + The :py:class:`TTkAbstractScrollView` is a :py:class:`TTkContainer` widget that incude :py:class:`TTkAbstractScrollViewInterface` api. + + The placement of any widget inside this container will change accordingly to the offset of this view. + + This class is used in the convenience widget :py:class:`TTkScrollArea` + ''' viewMovedTo:pyTTkSignal ''' @@ -91,6 +170,9 @@ class TTkAbstractScrollView(TTkContainer, TTkAbstractScrollViewInterface): # Do NOT use super() TTkContainer.__init__(self, **kwargs) + def viewDisplayedSize(self) -> (int, int): + return self.size() + @pyTTkSlot(int, int) def viewMoveTo(self, x: int, y: int): fw, fh = self.viewFullAreaSize() @@ -110,6 +192,9 @@ class TTkAbstractScrollView(TTkContainer, TTkAbstractScrollViewInterface): self.viewChanged.emit() self.update() + def getViewOffsets(self) -> tuple: + return self._viewOffsetX, self._viewOffsetY + def wheelEvent(self, evt): delta = TTkCfg.scrollDelta offx, offy = self.getViewOffsets() @@ -129,7 +214,9 @@ class TTkAbstractScrollView(TTkContainer, TTkAbstractScrollViewInterface): return super().update(repaint, updateLayout, updateParent) class TTkAbstractScrollViewLayout(TTkLayout, TTkAbstractScrollViewInterface): - '''TTkAbstractScrollViewLayout''' + ''' + :py:class:`TTkAbstractScrollViewLayout` + ''' viewMovedTo:pyTTkSignal ''' @@ -184,12 +271,17 @@ class TTkAbstractScrollViewLayout(TTkLayout, TTkAbstractScrollViewInterface): def viewMoveTo(self, x: int, y: int): self.setOffset(-x,-y) + def getViewOffsets(self) -> tuple: + return self._viewOffsetX, self._viewOffsetY + def setGeometry(self, x, y, w, h): TTkLayout.setGeometry(self, x, y, w, h) self.viewChanged.emit() class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterface): - '''TTkAbstractScrollViewGridLayout''' + ''' + :py:class:`TTkAbstractScrollViewGridLayout` + ''' viewMovedTo:pyTTkSignal ''' @@ -256,6 +348,9 @@ class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterf self.viewChanged.emit() self.update() + def getViewOffsets(self) -> tuple: + return self._viewOffsetX, self._viewOffsetY + def setGeometry(self, x, y, w, h): TTkGridLayout.setGeometry(self, x, y, w, h) self.viewChanged.emit() diff --git a/TermTk/TTkCore/constant.py b/TermTk/TTkCore/constant.py index 7a88bec1..5bf89725 100644 --- a/TermTk/TTkCore/constant.py +++ b/TermTk/TTkCore/constant.py @@ -84,12 +84,32 @@ class TTkConstant: HEADER = 0x0020 FOOTER = 0x0040 + class SelectionMode(int): + ''' + This class type indicates how the view responds to user selections. + + .. autosummary:: + NoSelection + SingleSelection + MultiSelection + ''' + NoSelection = 0x00 + '''Items cannot be selected.''' + SingleSelection = 0x01 + '''When the user selects an item, any already-selected item becomes unselected. It is possible for the user to deselect the selected item by pressing the Ctrl key when clicking the selected item.''' + # ContiguousSelection = 0x04 + # '''When the user selects an item in the usual way, the selection is cleared and the new item selected. However, if the user presses the Shift key while clicking on an item, all items between the current item and the clicked item are selected or unselected, depending on the state of the clicked item.''' + # ExtendedSelection = 0x03 + # '''When the user selects an item in the usual way, the selection is cleared and the new item selected. However, if the user presses the Ctrl key when clicking on an item, the clicked item gets toggled and all other items are left untouched. If the user presses the Shift key while clicking on an item, all items between the current item and the clicked item are selected or unselected, depending on the state of the clicked item. Multiple items can be selected by dragging the mouse over them.''' + MultiSelection = 0x02 + '''When the user selects an item in the usual way, the selection status of that item is toggled and the other items are left alone. Multiple items can be toggled by dragging the mouse over them.''' + # SelectionMode - NoSelection = 0x00 - SingleSelection = 0x01 - MultiSelection = 0x02 - ExtendedSelection = 0x03 - ContiguousSelection = 0x04 + NoSelection = SelectionMode.NoSelection + SingleSelection = SelectionMode.SingleSelection + # ExtendedSelection = SelectionMode.ExtendedSelection + # ContiguousSelection = SelectionMode.ContiguousSelection + MultiSelection = SelectionMode.MultiSelection # Graph types FILLED = 0x0001 diff --git a/TermTk/TTkTemplates/dragevents.py b/TermTk/TTkTemplates/dragevents.py index 3a60c23e..aa07f212 100644 --- a/TermTk/TTkTemplates/dragevents.py +++ b/TermTk/TTkTemplates/dragevents.py @@ -23,6 +23,8 @@ __all__ = ['TDragEvents'] class TDragEvents(): + def __init__(self) -> None: pass + def dragEnterEvent(self, evt) -> bool: ''' This event handler, can be reimplemented in a subclass to receive drag events for the widget. diff --git a/TermTk/TTkTemplates/keyevents.py b/TermTk/TTkTemplates/keyevents.py index 9b489d35..74eab618 100644 --- a/TermTk/TTkTemplates/keyevents.py +++ b/TermTk/TTkTemplates/keyevents.py @@ -25,6 +25,8 @@ __all__ = ['TKeyEvents'] from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent class TKeyEvents(): + def __init__(self) -> None: pass + # def keyPressEvent(self, evt:TTkKeyEvent) -> bool : # ''' # This event handler, can be reimplemented in a subclass to receive key press events for the widget. diff --git a/TermTk/TTkTemplates/mouseevents.py b/TermTk/TTkTemplates/mouseevents.py index dd3d84ae..fa158b2e 100644 --- a/TermTk/TTkTemplates/mouseevents.py +++ b/TermTk/TTkTemplates/mouseevents.py @@ -25,6 +25,8 @@ __all__ = ['TMouseEvents'] from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent class TMouseEvents(): + def __init__(self) -> None: pass + def mouseTapEvent(self, evt:TTkMouseEvent) -> bool : ''' This event handler, can be reimplemented in a subclass to receive mouse click events for the widget. diff --git a/TermTk/TTkTestWidgets/logviewer.py b/TermTk/TTkTestWidgets/logviewer.py index 4654d374..160db2fc 100644 --- a/TermTk/TTkTestWidgets/logviewer.py +++ b/TermTk/TTkTestWidgets/logviewer.py @@ -53,9 +53,6 @@ class _TTkLogViewer(TTkAbstractScrollView): h = len(self._messages) return w , h - def viewDisplayedSize(self) -> (int, int): - return self.size() - def loggingCallback(self, mode, context, message): logType = "NONE" if mode == TTkLog.InfoMsg: logType = TTkString("INFO " ,TTkColor.fg("#00ff00")) diff --git a/TermTk/TTkTestWidgets/testabstractscroll.py b/TermTk/TTkTestWidgets/testabstractscroll.py index 672d449c..98fc0025 100644 --- a/TermTk/TTkTestWidgets/testabstractscroll.py +++ b/TermTk/TTkTestWidgets/testabstractscroll.py @@ -63,7 +63,5 @@ class TTkTestAbstractScrollWidget(TTkAbstractScrollView): def viewFullAreaSize(self) -> (int, int): return self._areaSize - def viewDisplayedSize(self) -> (int, int): - return self.size() diff --git a/TermTk/TTkTestWidgets/tominspector.py b/TermTk/TTkTestWidgets/tominspector.py index eb190f7e..482b671c 100644 --- a/TermTk/TTkTestWidgets/tominspector.py +++ b/TermTk/TTkTestWidgets/tominspector.py @@ -73,9 +73,6 @@ class _DetailGridView(TTkAbstractScrollView): _,_,w,h = self._gridLayout.fullWidgetAreaGeometry() return w , h - def viewDisplayedSize(self) -> (int, int): - return self.size() - class _DetailLazyFormView(TTkAbstractScrollView): __slots__ = ('_gridLayout', '_lazyRows', '_lastRow') def __init__(self, *args, **kwargs) -> None: @@ -122,9 +119,6 @@ class _DetailLazyFormView(TTkAbstractScrollView): _,_,w,h = self.layout().fullWidgetAreaGeometry() return w , h+1 - def viewDisplayedSize(self) -> (int, int): - return self.size() - def paintEvent(self, canvas): x,y = self.getViewOffsets() w,h = self.size() diff --git a/TermTk/TTkWidgets/Fancy/tableview.py b/TermTk/TTkWidgets/Fancy/tableview.py index 161ae195..982cba45 100644 --- a/TermTk/TTkWidgets/Fancy/tableview.py +++ b/TermTk/TTkWidgets/Fancy/tableview.py @@ -48,10 +48,6 @@ class _TTkFancyTableViewHeader(TTkAbstractScrollView): def viewFullAreaSize(self) -> (int, int): return self.size() - # Override this function - def viewDisplayedSize(self) -> (int, int): - return self.size() - @pyTTkSlot(int, int) def viewMoveTo(self, x: int, y: int): pass @@ -197,9 +193,6 @@ class _TTkFancyTableView(TTkAbstractScrollView): def viewFullAreaSize(self) -> (int, int): return self._tableWidth, len(self._tableDataText) - def viewDisplayedSize(self) -> (int, int): - return self.size() - # def items(self): return self._tableDataText def setAlignment(self, alignments): diff --git a/TermTk/TTkWidgets/TTkModelView/filetreewidget.py b/TermTk/TTkWidgets/TTkModelView/filetreewidget.py index f95192f7..89935850 100644 --- a/TermTk/TTkWidgets/TTkModelView/filetreewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/filetreewidget.py @@ -64,6 +64,8 @@ class TTkFileTreeWidget(TTkTreeWidget): + TTkWidgets/ │ │Folder │2024-11-04 20:37:22 │┊ ∙ __init__.py │ 327 bytes│File │2024-11-04 19:56:26 │▼ + Quickstart: + .. code-block:: python import TermTk as ttk diff --git a/TermTk/TTkWidgets/TTkModelView/table.py b/TermTk/TTkWidgets/TTkModelView/table.py index fcd8e15d..b2fb7bad 100644 --- a/TermTk/TTkWidgets/TTkModelView/table.py +++ b/TermTk/TTkWidgets/TTkModelView/table.py @@ -38,7 +38,7 @@ class TTkTable(TTkAbstractScrollArea): __slots__ = tuple( ['_tableView'] + - (_forwardedSignals:=[ # Forwarded Signals + (_forwardedSignals:=[ # Forwarded Signals From TTkTable # 'cellActivated', 'cellChanged', 'cellClicked', 'cellDoubleClicked', @@ -70,6 +70,10 @@ class TTkTable(TTkAbstractScrollArea): sortingEnabled=False, dataPadding=1, **kwargs) -> None: + ''' + :param tableWidget: a custom Table Widget to be used instead of the default one. + :type tableWidget: :py:class:`TTkTableWidget`, optional + ''' self._tableView = None self._tableView:TTkTableWidget = tableWidget if tableWidget else TTkTableWidget( tableModel=tableModel, diff --git a/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py b/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py index b92d8105..d209edaa 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py +++ b/TermTk/TTkWidgets/TTkModelView/tablemodelcsv.py @@ -44,14 +44,18 @@ class TTkTableModelCSV(TTkTableModelList): with open('path/file.csv') as fd: tm2 = ttk.TTkTableModelCSV(fd=fd) - :param filename: the csv filename, if missing the file descriptor is used instead. - :type filename: str, optional - - :param fd: the FileDescriptor - :type fd: io, optional ''' - def __init__(self, *, filename:str=None, fd=None): + def __init__(self, *, + filename:str=None, + fd=None) -> None: + ''' + :param filename: the csv filename, if missing the file descriptor is used instead. + :type filename: str, optional + + :param fd: the FileDescriptor + :type fd: io, optional + ''' data, head, idx = [[]], [], [] if filename: with open(filename, "r") as fd: diff --git a/TermTk/TTkWidgets/TTkModelView/tablemodellist.py b/TermTk/TTkWidgets/TTkModelView/tablemodellist.py index 614dcd17..4f1be458 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablemodellist.py +++ b/TermTk/TTkWidgets/TTkModelView/tablemodellist.py @@ -50,19 +50,24 @@ class TTkTableModelList(TTkAbstractTableModel): :py:class:`TTkTableModelList` extends :py:class:`TTkAbstractTableModel`, including a basic model with a 2d list data structure - :param data: the 2D List model for the view to present. - :type data: list[list] - - :param header: the header labels, defaults to the column number. - :type header: list[str], optional - - :param indexes: the index labels, defaults to the line number. - :type indexes: list[str], optional ''' __slots__ = ('_data','_dataOriginal', '_hheader', '_vheader') - def __init__(self, *, data:list[list[object]]=[], header:list[str]=[], indexes:list[str]=[]) -> None: + def __init__(self, *, + data:list[list[object]]=[], + header:list[str]=[], + indexes:list[str]=[]) -> None: + ''' + :param data: the 2D List model for the view to present. + :type data: list[list] + + :param header: the header labels, defaults to the column number. + :type header: list[str], optional + + :param indexes: the index labels, defaults to the line number. + :type indexes: list[str], optional + ''' self._data = self._dataOriginal = data if data else [['']] self._hheader = header self._vheader = indexes diff --git a/TermTk/TTkWidgets/TTkModelView/tablewidget.py b/TermTk/TTkWidgets/TTkModelView/tablewidget.py index fcf998ec..6f339224 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/tablewidget.py @@ -150,26 +150,6 @@ class TTkTableWidget(TTkAbstractScrollView): To distribute the available space according to the space requirement of each column or row, call the view's :meth:`resizeColumnsToContents` or :meth:`resizeRowsToContents` functions. - :param tableModel: the model for the view to present. - :type tableModel: :py:class:`TTkAbstractTableModel` - - :param vSeparator: show the vertical separators, defaults to True - :type vSeparator: bool, optional - - :param hSeparator: show the horizontal separators, defaults to True - :type hSeparator: bool, optional - - :param vHeader: show the vertical header, defaults to True - :type vHeader: bool, optional - - :param hHeader: show the horizontal header, defaults to True - :type hHeader: bool, optional - - :param sortingEnabled: enable the column sorting, defaults to False - :type sortingEnabled: bool, optional - - :param dataPadding: the right column padding, defaults to 1 - :type dataPadding: int, optional ''' cellChanged:pyTTkSignal @@ -280,6 +260,28 @@ class TTkTableWidget(TTkAbstractScrollView): sortingEnabled=False, dataPadding=1, **kwargs) -> None: + ''' + :param tableModel: the model for the view to present. + :type tableModel: :py:class:`TTkAbstractTableModel` + + :param vSeparator: show the vertical separators, defaults to True + :type vSeparator: bool, optional + + :param hSeparator: show the horizontal separators, defaults to True + :type hSeparator: bool, optional + + :param vHeader: show the vertical header, defaults to True + :type vHeader: bool, optional + + :param hHeader: show the horizontal header, defaults to True + :type hHeader: bool, optional + + :param sortingEnabled: enable the column sorting, defaults to False + :type sortingEnabled: bool, optional + + :param dataPadding: the right column padding, defaults to 1 + :type dataPadding: int, optional + ''' # Signals # self.itemActivated = pyTTkSignal(TTkTableWidgetItem, int) # self.itemChanged = pyTTkSignal(TTkTableWidgetItem, int) @@ -569,10 +571,6 @@ class TTkTableWidget(TTkAbstractScrollView): h = hhs+self._rowsPos[-1]+1 return w,h - # Overridden function - def viewDisplayedSize(self) -> tuple[int, int]: - return self.size() - def clearSelection(self) -> None: ''' Deselects all selected items. diff --git a/TermTk/TTkWidgets/TTkModelView/tree.py b/TermTk/TTkWidgets/TTkModelView/tree.py index c498a0d0..ff195715 100644 --- a/TermTk/TTkWidgets/TTkModelView/tree.py +++ b/TermTk/TTkWidgets/TTkModelView/tree.py @@ -49,6 +49,10 @@ class TTkTree(TTkAbstractScrollArea): def __init__(self, *, treeWidget:TTkTreeWidget=None, **kwargs) -> None: + ''' + :param treeWidget: a custom Tree Widget to be used instead of the default one. + :type treeWidget: :py:class:`TTkTreeWidget`, optional + ''' super().__init__(**kwargs) kwargs.pop('parent',None) kwargs.pop('visible',None) diff --git a/TermTk/TTkWidgets/TTkModelView/treewidget.py b/TermTk/TTkWidgets/TTkModelView/treewidget.py index 8dfc8cb8..06822d18 100644 --- a/TermTk/TTkWidgets/TTkModelView/treewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/treewidget.py @@ -160,7 +160,10 @@ class TTkTreeWidget(TTkAbstractScrollView): widgets: list firstLine: bool - def __init__(self, *, header=[], sortingEnabled=True, **kwargs) -> None: + def __init__(self, *, + header=[], + sortingEnabled=True, + **kwargs) -> None: # Signals self.itemActivated = pyTTkSignal(TTkTreeWidgetItem, int) self.itemChanged = pyTTkSignal(TTkTreeWidgetItem, int) @@ -198,11 +201,6 @@ class TTkTreeWidget(TTkAbstractScrollView): # TTkLog.debug(f"{w=} {h=}") return w,h - # Overridden function - def viewDisplayedSize(self) -> tuple[int, int]: - # TTkLog.debug(f"{self.size()=}") - return self.size() - def clear(self) -> None: '''clear''' # Remove all the widgets diff --git a/TermTk/TTkWidgets/TTkPickers/textpicker.py b/TermTk/TTkWidgets/TTkPickers/textpicker.py index 62f59360..9170b6e4 100644 --- a/TermTk/TTkWidgets/TTkPickers/textpicker.py +++ b/TermTk/TTkWidgets/TTkPickers/textpicker.py @@ -111,9 +111,6 @@ class _emojiPickerView(TTkAbstractScrollView): _,_,w,h = self.layout().fullWidgetAreaGeometry() return w , h - def viewDisplayedSize(self) -> (int, int): - return self.size() - def maximumWidth(self): return 0x10000 def maximumHeight(self): return 0x10000 def minimumWidth(self): return 0 diff --git a/TermTk/TTkWidgets/TTkTerminal/terminal.py b/TermTk/TTkWidgets/TTkTerminal/terminal.py index de442874..504cd717 100644 --- a/TermTk/TTkWidgets/TTkTerminal/terminal.py +++ b/TermTk/TTkWidgets/TTkTerminal/terminal.py @@ -28,20 +28,21 @@ from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea from TermTk.TTkWidgets.TTkTerminal.terminalview import TTkTerminalView class TTkTerminal(TTkAbstractScrollArea): - '''TTkTerminal + __doc__ = ''' + :py:class:`TTkTerminal` is a container widget which place :py:class:`TTkTerminalView` in a scrolling area with on-demand scroll bars. - This is a terminal emulator fot TermTk + ''' + TTkTerminalView.__doc__ - .. warning:: - This is an Alpha feature, it is not optimized and the API definition may change in the future + __slots__ = tuple( + ['_terminalView'] + + (_forwardedSignals:=[# Forwarded Signals From TTkTreeWidget + 'bell', 'titleChanged', 'terminalClosed', 'textSelected', + 'termData', 'termResized']) + + (_forwardedMethods:=[# Forwarded Methods From TTkTreeWidget + 'termWrite', 'termSize']) + ) + _forwardWidget = TTkTerminalView - ''' - __slots__ = ('_terminalView', - # Exported methods - 'termWrite', 'termSize', - # Exported Signals - 'titleChanged', 'bell', 'terminalClosed', 'textSelected', - 'termData', 'termResized') def __init__(self, **kwargs) -> None: super().__init__(**kwargs) kwargs.pop('parent',None) @@ -50,16 +51,8 @@ class TTkTerminal(TTkAbstractScrollArea): self.setFocusPolicy(TTkK.ClickFocus) self.setViewport(self._terminalView) - # Export Methods - self.termSize = self._terminalView.termSize - self.termWrite = self._terminalView.termWrite - - # Export Signals - self.bell = self._terminalView.bell - self.termData = self._terminalView.termData - self.termResized = self._terminalView.termResized - self.titleChanged = self._terminalView.titleChanged - self.textSelected = self._terminalView.textSelected + for _attr in self._forwardedSignals+self._forwardedMethods: + setattr(self,_attr,getattr(self._terminalView,_attr)) self.terminalClosed = pyTTkSignal(TTkTerminal) self._terminalView.terminalClosed.connect(lambda : self.terminalClosed.emit(self)) diff --git a/TermTk/TTkWidgets/TTkTerminal/terminalview.py b/TermTk/TTkWidgets/TTkTerminal/terminalview.py index 1caf3e1f..09262dc8 100644 --- a/TermTk/TTkWidgets/TTkTerminal/terminalview.py +++ b/TermTk/TTkWidgets/TTkTerminal/terminalview.py @@ -61,6 +61,66 @@ class _termLog(): mouse = lambda _:None class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): + ''' + + :py:class:`TTkTerminalView` is a terminal emulator fot TermTk + + .. warning:: + This is an Alpha feature, it is not optimized and the API definition may change in the future + + + TermShot from: `tests/t.pty/test.pty.006.terminal.07.py `_ + + :: + + ╔════════════════════════════════════════════════════════════════════════════════════╗ + ║ Terminello n.1 [_][^][x]║ + ╟────────────────────────────────────────────────────────────────────────────────────╢ + ║ $ neofetch ▲║ + ║`.-::---.. PierCecco@FrankenstOne ┊║ + ║ .:++++ooooosssoo:. --------------------------- ┊║ + ║ .+o++::. `.:oos+. OS: LMDE 6 (faye) x86_64 ┊║ + ║ :oo:.` -+oo: Host: Lemur Pro lemp11 ┊║ + ║ `+o/` .::::::-. .++-` Kernel: 6.1.0-26-amd64 ▓║ + ║`/s/ .yyyyyyyyyyo: +o-` Uptime: 27 days, 2 hours, 33 mins ▓║ + ║`so .ss ohyo` :s-: Packages: 2787 (dpkg), 38 (flatpak) ▓║ + ║`s/ .ss h m myy/ /s`` Shell: bash 5.2.15 ▓║ + ║`s: `oo s m Myy+-o:` Resolution: 1920x1080, 3440x1440 ▓║ + ║`oo :+sdoohyoydyso/. DE: Cinnamon 6.2.9 ▓║ + ║ :o. .:////////++: WM: Mutter (Muffin) ▓║ + ║ `/++ -:::::- WM Theme: Mint-Y-Dark-Orange (Mint-Y) ▓║ + ║ `++- Theme: Mint-L-Dark [GTK2/3] ▓║ + ║ `/+- Icons: Mint-X-Orange [GTK2/3] ▓║ + ║ .+/. Terminal: tmux ▓║ + ║ .:+-. CPU: 12th Gen Intel i7-1255U (12) @ 4.700GHz ▓║ + ║ `--.`` GPU: Intel Alder Lake-UP3 GT2 [Iris Xe Graphics] ▓║ + ║ Memory: 32111MiB / 39956MiB ▓║ + ║ ▓║ + ║23 PierCecco FrankenstOne < 12:24 > (1052) ~/github/Varie/pyTermTk ▓║ + ║ $ ▼║ + ╚════════════════════════════════════════════════════════════════════════════════════╝ + + Quickstart: + + .. code-block:: python + + import TermTk as ttk + + root = ttk.TTk(mouseTrack=True) + + win = ttk.TTkWindow(parent=root, title="Terminal", size=(80+2,24+4), layout=ttk.TTkGridLayout()) + + term = ttk.TTkTerminal(parent=win) + + th = ttk.TTkTerminalHelper(term=term) + th.runShell() + + root.mainloop() + + More examples are available :ref:`here `. + + ''' + @dataclass class _Terminal(): bracketedMode: bool = False @@ -78,6 +138,55 @@ class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): reportMove: bool = False sgrMode: bool = False + bell:pyTTkSignal + ''' + This signal is emitted when the `bell `__ is received. + ''' + + terminalClosed:pyTTkSignal + ''' + This signal is emitted when the terminl is closed. + ''' + + titleChanged:pyTTkSignal + ''' + This signal is emitted when the terminal title change through OSC "ESC ]0;" + + :param title: the new title + :type title: str + ''' + + textSelected:pyTTkSignal + ''' + This signal is emitted when a text is selected. + + :param text: the selected text + :type text: :py:class:`ttkString` + ''' + + termData:pyTTkSignal + ''' + This signal is emitted when data event fires. + + This happens for example when the user types or pastes into the terminal. + The event value is whatever 'str' results, in a typical setup, + this should be passed on to the backing pty. + + This signal is used in :py:class:`TTkTerminalHelper` through :py:meth:`TTkTerminalHelper.attachTTkTerminal` + to frward all the terminal events to the pty interface. + + :param data: the event data + :type data: str + ''' + + termResized:pyTTkSignal + ''' + This signal is emitted when the terminal is resized. + + :param size: the new size [width, height] of the terminal + :type size: (int,int) + ''' + __slots__ = ( '_termLoop', '_newSize', '_clipboard', '_selecting', @@ -89,13 +198,14 @@ class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): 'titleChanged', 'terminalClosed', 'textSelected', 'termData','termResized') def __init__(self, **kwargs) -> None: + #Signals self.bell = pyTTkSignal() self.terminalClosed = pyTTkSignal() self.titleChanged = pyTTkSignal(str) - self.textSelected = pyTTkSignal(str) - + self.textSelected = pyTTkSignal(TTkString) self.termData = pyTTkSignal(str) self.termResized = pyTTkSignal(int,int) + self._newSize = None self._terminal = TTkTerminalView._Terminal() self._keyboard = TTkTerminalView._Keyboard() @@ -114,6 +224,7 @@ class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): next(self._termLoop) self._termLoop.send("") + # Do NOT use super() due to the multiple imports TTkAbstractScrollView.__init__(self, **kwargs) w,h = self.size() @@ -140,10 +251,13 @@ class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): h += len(self._screen_current._bufferedLines) return w,h - def viewDisplayedSize(self) -> (int, int): - return self.size() + def termSize(self) -> tuple[int,int]: + ''' + This property holds the size of the terminal - def termSize(self): + :return: a tuple of 2 integers (width, height) + :rtype: tuple + ''' return self.size() def resizeEvent(self, w: int, h: int): @@ -172,7 +286,13 @@ class TTkTerminalView(TTkAbstractScrollView, _TTkTerminal_CSI_DEC): re_XTWINOPS = re.compile(r'^') - def termWrite(self, data): + def termWrite(self, data:str) -> None: + ''' + Write data to the terminal. + + :params data: the data to write + :type data: str + ''' if data: self._termLoop.send(data) diff --git a/TermTk/TTkWidgets/button.py b/TermTk/TTkWidgets/button.py index ceb4d553..8b30ef88 100644 --- a/TermTk/TTkWidgets/button.py +++ b/TermTk/TTkWidgets/button.py @@ -55,17 +55,6 @@ class TTkButton(TTkWidget): ╽ Line ╽ Demo: `formwidgets.py `_ - - :param str text: the text shown on the button, defaults to "" - :type text: str, optional - - :param bool border: the border of the button, defaults to "False" - :type border: bool, optional - - :param bool checked: checked status if the button is checkable, defaults to "False" - :type checked: bool, optional - :param bool checkable: define if the button is checkable, defaults to "False" - :type checkable: bool, optional ''' clicked:pyTTkSignal @@ -118,6 +107,18 @@ class TTkButton(TTkWidget): checked:bool=False, checkable:bool=False, **kwargs) -> None: + ''' + :param str text: the text shown on the button, defaults to "" + :type text: str, optional + + :param bool border: the border of the button, defaults to "False" + :type border: bool, optional + + :param bool checked: checked status if the button is checkable, defaults to "False" + :type checked: bool, optional + :param bool checkable: define if the button is checkable, defaults to "False" + :type checkable: bool, optional + ''' self._text = TTkString(text).split('\n') textWidth = max(t.termWidth() for t in self._text) self._border = border diff --git a/TermTk/TTkWidgets/checkbox.py b/TermTk/TTkWidgets/checkbox.py index 844e8bb4..76580061 100644 --- a/TermTk/TTkWidgets/checkbox.py +++ b/TermTk/TTkWidgets/checkbox.py @@ -50,16 +50,6 @@ class TTkCheckbox(TTkWidget): [/]CheckBox :Demo: `formwidgets.py `_ - - :param str text: the text shown on the checkbox, defaults to "" - :type text: str, optional - - :param checked: Checked status, defaults to "False" - :type checked: bool, optional - :param checkStatus: If defined, override the option defined in the 'checked' field otherwise defaults to :py:class:`TTkK.CheckState.Checked` or :py:class:`TTkK.CheckState.Unchecked` based on the checked status - :type checkStatus: :py:class:`TTkK.CheckState` , optional - :param tristate: Tristate status, if enabled the checkbox is able to assume the :py:class:`TTkK.CheckState.PartiallyChecked` status, defaults to "False" - :type tristate: bool, optional ''' clicked:pyTTkSignal @@ -108,6 +98,18 @@ class TTkCheckbox(TTkWidget): checkStatus:TTkK.CheckState = None, tristate:bool=False, **kwargs) -> None: + ''' + :param str text: the text shown on the checkbox, defaults to "" + :type text: str, optional + + :param checked: Checked status, defaults to "False" + :type checked: bool, optional + :param checkStatus: If defined, override the option defined in the 'checked' field otherwise defaults to :py:class:`TTkK.CheckState.Checked` or :py:class:`TTkK.CheckState.Unchecked` based on the checked status + :type checkStatus: :py:class:`TTkK.CheckState` , optional + :param tristate: Tristate status, if enabled the checkbox is able to assume the :py:class:`TTkK.CheckState.PartiallyChecked` status, defaults to "False" + :type tristate: bool, optional + ''' + # Define Signals self.stateChanged = pyTTkSignal(TTkK.CheckState) self.clicked = pyTTkSignal(bool) diff --git a/TermTk/TTkWidgets/combobox.py b/TermTk/TTkWidgets/combobox.py index de0d191b..9e740165 100644 --- a/TermTk/TTkWidgets/combobox.py +++ b/TermTk/TTkWidgets/combobox.py @@ -52,17 +52,6 @@ class TTkComboBox(TTkContainer): [ Text [^] - :param list: the list of the items selectable by this combobox, defaults to "[]" - :type list: list(str), optional - - :param insertPolicy: the policy used to determine where user-inserted items should appear in the combobox, defaults to :py:class:`TTkConstant.InsertPolicy.InsertAtBottom` - :type insertPolicy: :py:class:`TTkConstant.InsertPolicy`, optional - - :param textAlign: This enum type is used to define the text alignment, defaults to :py:class:`TTkConstant.Alignment.CENTER_ALIGN` - :tye textAlign: :py:class:`TTkConstant.Alignment`, optional - - :param editable: This property holds whether the combo box can be edited by the user, defaults to False - :type editable: bool, optional ''' classStyle = { @@ -84,6 +73,20 @@ class TTkComboBox(TTkContainer): textAlign:TTkK.Alignment = TTkK.CENTER_ALIGN, editable:bool = False, **kwargs) -> None: + ''' + :param list: the list of the items selectable by this combobox, defaults to "[]" + :type list: list(str), optional + + :param insertPolicy: the policy used to determine where user-inserted items should appear in the combobox, defaults to :py:class:`TTkConstant.InsertPolicy.InsertAtBottom` + :type insertPolicy: :py:class:`TTkConstant.InsertPolicy`, optional + + :param textAlign: This enum type is used to define the text alignment, defaults to :py:class:`TTkConstant.Alignment.CENTER_ALIGN` + :tye textAlign: :py:class:`TTkConstant.Alignment`, optional + + :param editable: This property holds whether the combo box can be edited by the user, defaults to False + :type editable: bool, optional + ''' + # Define Signals self.currentIndexChanged = pyTTkSignal(int) self.currentTextChanged = pyTTkSignal(str) diff --git a/TermTk/TTkWidgets/container.py b/TermTk/TTkWidgets/container.py index 147b8ac2..0477961c 100644 --- a/TermTk/TTkWidgets/container.py +++ b/TermTk/TTkWidgets/container.py @@ -96,23 +96,6 @@ class TTkContainer(TTkWidget): root.mainloop() - :param layout: the layout of this widget, optional, defaults to :py:class:`TTkLayout` - :type layout: :mod:`TermTk.TTkLayouts` - - :param padding: the padding (top, bottom, left, right) of the widget, defaults to (0,0,0,0) - :type padding: :py:class:`TTkPadding` - - :param paddingTop: the Top padding, override Top padding if already defined, optional, default=0 if padding is not defined - :type paddingTop: int - :param paddingBottom: the Bottom padding, override Bottom padding if already defined, optional, default=0 if padding is not defined - :type paddingBottom: int - :param paddingLeft: the Left padding, override Left padding if already defined, optional, default=0 if padding is not defined - :type paddingLeft: int - :param paddingRight: the Right padding, override Right padding if already defined, optional, default=0 if padding is not defined - :type paddingRight: int - - :param bool forwardStyle: [**Experimental**] any change of style will reflect the children, defaults to False - :type forwardStyle: bool ''' __slots__ = ( @@ -129,7 +112,25 @@ class TTkContainer(TTkWidget): paddingRight:int = 0, forwardStyle:bool = False, **kwargs) -> None: - + ''' + :param layout: the layout of this widget, optional, defaults to :py:class:`TTkLayout` + :type layout: :mod:`TermTk.TTkLayouts` + + :param padding: the padding (top, bottom, left, right) of the widget, defaults to (0,0,0,0) + :type padding: :py:class:`TTkPadding` + + :param paddingTop: the Top padding, override Top padding if already defined, optional, default=0 if padding is not defined + :type paddingTop: int + :param paddingBottom: the Bottom padding, override Bottom padding if already defined, optional, default=0 if padding is not defined + :type paddingBottom: int + :param paddingLeft: the Left padding, override Left padding if already defined, optional, default=0 if padding is not defined + :type paddingLeft: int + :param paddingRight: the Right padding, override Right padding if already defined, optional, default=0 if padding is not defined + :type paddingRight: int + + :param bool forwardStyle: [**Experimental**] any change of style will reflect the children, defaults to False + :type forwardStyle: bool + ''' self._forwardStyle = forwardStyle if padding: self._padt = padding[0] diff --git a/TermTk/TTkWidgets/frame.py b/TermTk/TTkWidgets/frame.py index ace98183..486f1d52 100644 --- a/TermTk/TTkWidgets/frame.py +++ b/TermTk/TTkWidgets/frame.py @@ -44,15 +44,7 @@ class TTkFrame(TTkContainer): Demo2: `splitter.py `_ - :param title: the title displayed at the top border of the frame, defaults to "" - :type title: TTkString, optional - :param titleAlign: the position of the title, defaults to :py:class:`TTkK.Alignment.CENTER_ALIGN` - :type titleAlign: :py:class:`TTkK.Alignment`, optional - :param border: Enable/Disable the border, defaults to **True** - :type border: bool, optional - ''' - classStyle = { 'default': {'color': TTkColor.fg("#dddddd")+TTkColor.bg("#222222"), 'borderColor': TTkColor.RST}, @@ -68,6 +60,15 @@ class TTkFrame(TTkContainer): border:bool=True, titleAlign:TTkK.Alignment=TTkK.CENTER_ALIGN, **kwargs) -> None: + ''' + :param title: the title displayed at the top border of the frame, defaults to "" + :type title: TTkString, optional + :param titleAlign: the position of the title, defaults to :py:class:`TTkK.Alignment.CENTER_ALIGN` + :type titleAlign: :py:class:`TTkK.Alignment`, optional + :param border: Enable/Disable the border, defaults to **True** + :type border: bool, optional + ''' + self._titleAlign = titleAlign self._title = TTkString(title) self._border = border diff --git a/TermTk/TTkWidgets/list_.py b/TermTk/TTkWidgets/list_.py index 6d23a136..4442349e 100644 --- a/TermTk/TTkWidgets/list_.py +++ b/TermTk/TTkWidgets/list_.py @@ -27,51 +27,42 @@ from TermTk.TTkWidgets.listwidget import TTkListWidget from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea class TTkList(TTkAbstractScrollArea): - '''TTkList''' - __slots__ = ( - '_listView', 'itemClicked', 'textClicked', - # Forwarded Methods - 'items', - 'dragDropMode', 'setDragDropMode', - 'addItem', 'addItemAt', 'addItems', 'addItemsAt', - 'indexOf', 'itemAt', 'moveItem', - 'removeAt', 'removeItem', 'removeItems', - 'selectionMode', 'setSelectionMode', 'selectedItems', 'selectedLabels', - 'setCurrentRow', 'setCurrentItem', ) + __doc__ = ''' + :py:class:`TTkList` is a container widget which place :py:class:`TTkListWidget` in a scrolling area with on-demand scroll bars. + + ''' + TTkListWidget.__doc__ + + __slots__ = tuple( + ['_listView'] + + (_forwardedSignals:=[ # Forwarded Signals From TTkTable + 'itemClicked', 'textClicked']) + + (_forwardedMethods:=[ # Forwarded Methods From TTkTable + 'items', + 'dragDropMode', 'setDragDropMode', + 'addItem', 'addItemAt', 'addItems', 'addItemsAt', + 'indexOf', 'itemAt', 'moveItem', + 'removeAt', 'removeItem', 'removeItems', + 'selectionMode', 'setSelectionMode', 'selectedItems', 'selectedLabels', + 'setCurrentRow', 'setCurrentItem']) + ) + _forwardWidget = TTkListWidget def __init__(self, *, listWidget:TTkListWidget=None, selectionMode:int=TTkK.SingleSelection, dragDropMode:TTkK.DragDropMode=TTkK.DragDropMode.NoDragDrop, **kwargs) -> None: - TTkAbstractScrollArea.__init__(self, **kwargs) + ''' + :param listWidget: a custom List Widget to be used instead of the default one. + :type listWidget: :py:class:`TTkListWidget`, optional + ''' self._listView = listWidget if listWidget else TTkListWidget( selectionMode=selectionMode, dragDropMode=dragDropMode, **kwargs|{'parent':None,'visible':True}) + super().__init__(**kwargs) self.setViewport(self._listView) - self.itemClicked = self._listView.itemClicked - self.textClicked = self._listView.textClicked - # self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus) - # Forwearded Methods - self.items = self._listView.items - self.indexOf = self._listView.indexOf - self.itemAt = self._listView.itemAt - self.moveItem = self._listView.moveItem - self.removeAt = self._listView.removeAt - self.removeItem = self._listView.removeItem - self.removeItems = self._listView.removeItems - self.addItem = self._listView.addItem - self.addItems = self._listView.addItems - self.addItemAt = self._listView.addItemAt - self.addItemsAt = self._listView.addItemsAt - self.selectionMode = self._listView.selectionMode - self.setSelectionMode = self._listView.setSelectionMode - self.selectedItems = self._listView.selectedItems - self.selectedLabels = self._listView.selectedLabels - self.setCurrentRow = self._listView.setCurrentRow - self.setCurrentItem = self._listView.setCurrentItem - self.dragDropMode = self._listView.dragDropMode - self.setDragDropMode = self._listView.setDragDropMode + for _attr in self._forwardedSignals+self._forwardedMethods: + setattr(self,_attr,getattr(self._listView,_attr)) diff --git a/TermTk/TTkWidgets/listwidget.py b/TermTk/TTkWidgets/listwidget.py index dfa2ccfe..bc870190 100644 --- a/TermTk/TTkWidgets/listwidget.py +++ b/TermTk/TTkWidgets/listwidget.py @@ -108,20 +108,81 @@ class TTkAbstractListItem(TTkWidget): canvas.drawTTkString(pos=(0,0), width=w, color=color ,text=self._text) class TTkListWidget(TTkAbstractScrollView): + ''' + A :py:class:`TTkListWidget` implements a list view that displays a set of selectable items. + + :: + + ╔════════════════════════════════╗ + ║S-0) --Zero-3- officia ▲║ + ║S-1) ad ipsum ▓║ + ║S-2) irure nisi ┊║ + ║S-3) minim --Zero-3- ┊║ + ║S-4) ea sunt ┊║ + ║S-5) qui mollit ┊║ + ║S-6) magna sunt ┊║ + ║S-7) sunt officia ▼║ + ╚════════════════════════════════╝ + + Quickstart: + + .. code-block:: python + + import TermTk as ttk + + root = ttk.TTk(layout=ttk.TTkHBoxLayout(), mouseTrack=True) + + ttk.TTkList(parent=root, items=["Item 1","Item 2","Item 3"]) + ttk.TTkList(parent=root, items=[f"Item 0x{i:03X}" for i in range(100)]) + + ttkList = ttk.TTkList(parent=root) + ttkList.addItems([f"Item 0x{i:04X}" for i in range(200)]) + + root.mainloop() + + ''' + + itemClicked:pyTTkSignal + ''' + This signal is emitted whenever an item is clicked. + + :param item: the item selected + :type item: :py:class:`TTkAbstractListItem` + ''' + textClicked:pyTTkSignal + ''' + This signal is emitted whenever an item is clicked. + + :param text: the text of the item selected + :type text: str + ''' + @dataclass(frozen=True) class _DropListData: widget: TTkAbstractScrollView items: list - '''TTkListWidget''' __slots__ = ('itemClicked', 'textClicked', '_selectedItems', '_selectionMode', '_highlighted', '_items', '_dragPos', '_dndMode') def __init__(self, *, - selectionMode:int=TTkK.SingleSelection, + items:list[str]=[], + selectionMode:int=TTkK.SelectionMode.SingleSelection, dragDropMode:TTkK.DragDropMode=TTkK.DragDropMode.NoDragDrop, **kwargs) -> None: + ''' + :param items: Use this field to intialize the :py:class:`TTkListWidget` with the entries in the items list, defaults to "[]" + :type items: list[str], optional + :param selectionMode: This property controls whether the user can select one or many items, defaults to :py:class:`TTkK.SelectionMode.SingleSelection`. + :type selectionMode: :py:class:`TTkK.SelectionMode`, optional + :param dragDropMode: This property holds the drag and drop event the view will act upon, defaults to :py:class:`TTkK.DragDropMode.NoDragDrop`. + :type dragDropMode: :py:class:`TTkK.DragDropMode`, optional + ''' + # Signals + self.itemClicked = pyTTkSignal(TTkAbstractListItem) + self.textClicked = pyTTkSignal(str) + # Default Class Specific Values self._selectionMode = selectionMode self._selectedItems = [] @@ -129,11 +190,9 @@ class TTkListWidget(TTkAbstractScrollView): self._highlighted = None self._dragPos = None self._dndMode = dragDropMode - # Signals - self.itemClicked = pyTTkSignal(TTkAbstractListItem) - self.textClicked = pyTTkSignal(str) # Init Super super().__init__(**kwargs) + self.addItems(items) self.viewChanged.connect(self._viewChangedHandler) self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus) @@ -207,16 +266,14 @@ class TTkListWidget(TTkAbstractScrollView): _,_,w,h = self.layout().fullWidgetAreaGeometry() return w, h - def viewDisplayedSize(self) -> (int, int): - return self.size() - def addItem(self, item, data=None): '''addItem''' self.addItemAt(item, len(self._items), data) def addItems(self, items): '''addItems''' - self.addItemAt(items, len(self._items)) + for item in items: + self.addItem(item) def _placeItems(self): minw = self.width() diff --git a/TermTk/TTkWidgets/menu.py b/TermTk/TTkWidgets/menu.py index 5a2b7f80..449a9bac 100644 --- a/TermTk/TTkWidgets/menu.py +++ b/TermTk/TTkWidgets/menu.py @@ -346,9 +346,6 @@ class _TTkMenuAreaWidget(TTkAbstractScrollView): _,_,w,h = self.layout().fullWidgetAreaGeometry() return w , h - def viewDisplayedSize(self) -> tuple: - return self.size() - def maximumWidth(self): return 0x10000 def maximumHeight(self): return 0x10000 def minimumWidth(self): return 0 diff --git a/TermTk/TTkWidgets/radiobutton.py b/TermTk/TTkWidgets/radiobutton.py index dc2c0701..0806b256 100644 --- a/TermTk/TTkWidgets/radiobutton.py +++ b/TermTk/TTkWidgets/radiobutton.py @@ -43,14 +43,6 @@ class TTkRadioButton(TTkWidget): Demo: `formwidgets.py `_ - :param str text: the text shown on the radio button, defaults to "" - :type text: str, optional - :param str radiogroup: the text used to group the RadioButtons, only one checked status is allowed in between all the radio buttons with the same radiogroup, defaults to "DefaultGroup" - :type radiogroup: str, optional - :param bool checked: Checked status, defaults to "False" - :type checked: bool, optional - :param checkStatus: If defined, override the option defined in the 'checked' field otherwise defaults to :py:class:`TTkK.CheckState.Checked` or :py:class:`TTkK.CheckState.Unchecked` based on the checked status - :type checkStatus: :py:class:`TTkK.CheckState` , optional ''' clicked:pyTTkSignal @@ -82,6 +74,17 @@ class TTkRadioButton(TTkWidget): checkStatus:TTkK.CheckState = None, text:TTkString='', **kwargs) -> None: + ''' + :param str text: the text shown on the radio button, defaults to "" + :type text: str, optional + :param str radiogroup: the text used to group the RadioButtons, only one checked status is allowed in between all the radio buttons with the same radiogroup, defaults to "DefaultGroup" + :type radiogroup: str, optional + :param bool checked: Checked status, defaults to "False" + :type checked: bool, optional + :param checkStatus: If defined, override the option defined in the 'checked' field otherwise defaults to :py:class:`TTkK.CheckState.Checked` or :py:class:`TTkK.CheckState.Unchecked` based on the checked status + :type checkStatus: :py:class:`TTkK.CheckState` , optional + ''' + # Define Signals self.clicked = pyTTkSignal() self.toggled = pyTTkSignal(bool) diff --git a/TermTk/TTkWidgets/scrollarea.py b/TermTk/TTkWidgets/scrollarea.py index 4a3fba13..e07a8327 100644 --- a/TermTk/TTkWidgets/scrollarea.py +++ b/TermTk/TTkWidgets/scrollarea.py @@ -43,9 +43,6 @@ class _TTkAreaWidget(TTkAbstractScrollView): _,_,w,h = self.layout().fullWidgetAreaGeometry() return w , h - def viewDisplayedSize(self) -> (int, int): - return self.size() - def maximumWidth(self): return 0x10000 def maximumHeight(self): return 0x10000 def minimumWidth(self): return 0 diff --git a/TermTk/TTkWidgets/texedit.py b/TermTk/TTkWidgets/texedit.py index 83b21ec3..0df38119 100644 --- a/TermTk/TTkWidgets/texedit.py +++ b/TermTk/TTkWidgets/texedit.py @@ -77,9 +77,6 @@ class _TTkTextEditViewLineNumber(TTkAbstractScrollView): else: return self.size() - def viewDisplayedSize(self) -> (int, int): - return self.size() - def paintEvent(self, canvas): if not self._textWrap: return _, oy = self.getViewOffsets() @@ -104,7 +101,62 @@ class _TTkTextEditViewLineNumber(TTkAbstractScrollView): canvas.drawChar(pos=(w-1,y), char='▌', color=separatorColor) class TTkTextEditView(TTkAbstractScrollView): - '''TTkTextEditView''' + ''' + :py:class:`TTkTextEditView` + + :: + + ╔═══════════════════════════════════════════════════════════════════════════════════════╗ + ║ 0▌"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ╥ ║ + ║ <▌incididunt ut labore et dolore magna aliqua. ║ ║ + ║ 1▌ ║ ║ + ║ 2▌Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliqu║ ║ + ║ <▌ip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate ║ ║ + ║ <▌velit esse cillum dolore eu fugiat nulla pariatur. ║ ║ + ║ 3▌ ║ ║ + ║ 4▌Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru║ ║ + ║ <▌nt mollit anim id est laborum." ╨ ║ + ╚═══════════════════════════════════════════════════════════════════════════════════════╝ + + Demo: `textedit.py `_ + (`Try Online `__) + + `ttkdesigner Tutorial `_ + + ''' + + currentColorChanged:pyTTkSignal + ''' + This signal is emitted if the current character color has changed, + for example caused by a change of the cursor position. + + :param color: the new color + :type color: :py:class:`TTkColor` + ''' + + undoAvailable:pyTTkSignal + ''' + This signal is emitted whenever undo operations become available (available is true) + or unavailable (available is false). + + :param available: the availability of undo + :type available: bool + ''' + + redoAvailable:pyTTkSignal + ''' + This signal is emitted whenever redo operations become available (available is true) + or unavailable (available is false). + + :param available: the availability of redo + :type available: bool + ''' + + textChanged:pyTTkSignal + ''' + This signal is emitted whenever the document's content changes; + for example, when text is inserted or deleted, or when formatting is applied. + ''' classStyle = { 'default': {'color': TTkColor.fg("#dddddd")+TTkColor.bg("#222222"), @@ -135,24 +187,38 @@ class TTkTextEditView(TTkAbstractScrollView): 'undoAvailable', 'redoAvailable', 'textChanged' ) - ''' - in order to support the line wrap, I need to divide the full data text in; - _textDocument = the entire text divided in lines, easy to add/remove/append lines - _textWrap._lines = an array of tuples for each displayed line with a pointer to a - specific line and its slice to be shown at this coordinate; - [ (line, (posFrom, posTo)), ... ] - This is required to support the wrap feature - ''' + + # in order to support the line wrap, I need to divide the full data text in; + # _textDocument = the entire text divided in lines, easy to add/remove/append lines + # _textWrap._lines = an array of tuples for each displayed line with a pointer to a + # specific line and its slice to be shown at this coordinate; + # [ (line, (posFrom, posTo)), ... ] + # This is required to support the wrap feature + def __init__(self, *, readOnly:bool=False, multiLine:bool=True, document:TTkTextDocument=None, **kwargs) -> None: - super().__init__(**kwargs) + ''' + :param lineNumber: Show the line number on the left, defaults to **False** + :type lineNumber: bool, optional + + :param readOnly: In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible, defaults to **True** + :type readOnly: bool, optional + + :param multiLine: In a multiline text edit the user can split the text in multiple lines, defaults to **True** + :type multiLine: bool, optional + + :param document: If required an external Document can be used in this text editor, this option is useful if multiple editors share the same document as in the `demo `__, defaults to a new Document + :type document: :py:class:`TTkTextDocument`, optional + ''' + self.currentColorChanged = pyTTkSignal(TTkColor) self.undoAvailable = pyTTkSignal(bool) self.redoAvailable = pyTTkSignal(bool) self.textChanged = pyTTkSignal() + self._readOnly = readOnly self._multiLine = multiLine self._multiCursor = True @@ -165,6 +231,9 @@ class TTkTextEditView(TTkAbstractScrollView): self._textCursor = None self._textWrap = None self._clipboard = TTkClipboard() + + super().__init__(**kwargs) + self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus) self.setDocument(document if document else TTkTextDocument()) self.disableWidgetCursor(self._readOnly) @@ -366,9 +435,6 @@ class TTkTextEditView(TTkAbstractScrollView): elif self.lineWrapMode() == TTkK.FixedWidth: return self.wrapWidth(), self._textWrap.size() - def viewDisplayedSize(self) -> (int, int): - return self.size() - def _pushCursor(self): ox, oy = self.getViewOffsets() @@ -625,181 +691,20 @@ class TTkTextEditView(TTkAbstractScrollView): canvas.drawVLine(pos=(self._textWrap._wrapWidth,0), size=h, color=lineColor) class TTkTextEdit(TTkAbstractScrollArea): - '''TTkTextEdit - - :: - - ╔═══════════════════════════════════════════════════════════════════════════════════════╗ - ║ 0▌"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ╥ ║ - ║ <▌incididunt ut labore et dolore magna aliqua. ║ ║ - ║ 1▌ ║ ║ - ║ 2▌Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliqu║ ║ - ║ <▌ip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate ║ ║ - ║ <▌velit esse cillum dolore eu fugiat nulla pariatur. ║ ║ - ║ 3▌ ║ ║ - ║ 4▌Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru║ ║ - ║ <▌nt mollit anim id est laborum." ╨ ║ - ╚═══════════════════════════════════════════════════════════════════════════════════════╝ - - Demo: `textedit.py `_ - (`Try Online `__) - - `ttkdesigner Tutorial `_ - - :param lineNumber: Show the line number on the left, defaults to **False** - :type lineNumber: bool, optional - - :param readOnly: In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible, defaults to **True** - :type readOnly: bool, optional - - :param multiLine: In a multiline text edit the user can split the text in multiple lines, defaults to **True** - :type multiLine: bool, optional - - :param document: If required an external Document can be used in this text editor, this option is useful if multiple editors share the same document as in the `demo `__, defaults to a new Document - :type document: :py:class:`TTkTextDocument`, optional - + __doc__ = ''' + :py:class:`TTkTextEdit` is a container widget which place :py:class:`TTkTextEditView` in a scrolling area with on-demand scroll bars. - .. py:method:: toAnsi() - - - .. py:method:: clear() - - This method is forwarded to :meth:`TTkTextEditView.clear` - - .. py:method:: setText(text) - - This method is forwarded to :meth:`TTkTextEditView.setText` - - .. py:method:: append(text) - - This method is forwarded to :meth:`TTkTextEditView.append` - - .. py:method:: isReadOnly() - - This method is forwarded to :meth:`TTkTextEditView.isReadOnly` - - .. py:method:: setReadOnly(ro) - - This method is forwarded to :meth:`TTkTextEditView.setReadOnly` - - .. py:method:: document() - - This method is forwarded to :meth:`TTkTextEditView.document` - - .. py:method:: wrapWidth() - - This method is forwarded to :meth:`TTkTextEditView.wrapWidth` - - .. py:method:: setWrapWidth(width) - - This method is forwarded to :meth:`TTkTextEditView.setWrapWidth` - - .. py:method:: multiLine() - - This method is forwarded to :meth:`TTkTextEditView.multiLine` - - .. py:method:: lineWrapMode() - - This method is forwarded to :meth:`TTkTextEditView.lineWrapMode` - - .. py:method:: setLineWrapMode(mode) - - This method is forwarded to :meth:`TTkTextEditView.setLineWrapMode` - - .. py:method:: wordWrapMode() - - This method is forwarded to :meth:`TTkTextEditView.wordWrapMode` - - .. py:method:: setWordWrapMode(mode) - - This method is forwarded to :meth:`TTkTextEditView.setWordWrapMode` - - .. py:method:: textCursor() - - This method is forwarded to :meth:`TTkTextEditView.textCursor` - - .. py:method:: setColor(color) - - This method is forwarded to :meth:`TTkTextEditView.setColor` - - .. py:method:: cut() - - This method is forwarded to :meth:`TTkTextEditView.cut` - - .. py:method:: copy() - - This method is forwarded to :meth:`TTkTextEditView.copy` - - .. py:method:: paste() - - This method is forwarded to :meth:`TTkTextEditView.paste` - - .. py:method:: undo() - - This method is forwarded to :meth:`TTkTextEditView.undo` - - .. py:method:: redo() - - This method is forwarded to :meth:`TTkTextEditView.redo` - - .. py:method:: isUndoAvailable() - - This method is forwarded to :meth:`TTkTextEditView.isUndoAvailable` - - .. py:method:: isRedoAvailable() - - This method is forwarded to :meth:`TTkTextEditView.isRedoAvailable` - - .. py:method:: toAnsi() - - This method is forwarded to :meth:`TTkTextEditView.toAnsi` - - .. py:method:: toRawText() - - This method is forwarded to :meth:`TTkTextEditView.toRawText` - - .. py:method:: toPlainText() - - This method is forwarded to :meth:`TTkTextEditView.toPlainText` - - ''' - - currentColorChanged:pyTTkSignal - ''' - This signal is emitted if the current character color has changed, - for example caused by a change of the cursor position. - - :param color: the new color - :type color: :py:class:`TTkColor` - ''' - - undoAvailable:pyTTkSignal - ''' - This signal is emitted whenever undo operations become available (available is true) - or unavailable (available is false). - - :param available: the availability of undo - :type available: bool - ''' - - redoAvailable:pyTTkSignal - ''' - This signal is emitted whenever redo operations become available (available is true) - or unavailable (available is false). - - :param available: the availability of redo - :type available: bool - ''' - - textChanged:pyTTkSignal - ''' - This signal is emitted whenever the document's content changes; - for example, when text is inserted or deleted, or when formatting is applied. - ''' + ''' + TTkTextEditView.__doc__ __slots__ = ( - '_textEditView', - '_lineNumberView', '_lineNumber', + ['_textEditView', + '_lineNumberView', '_lineNumber'] + + (_forwardedSignals:=[ # Forwarded Signals From TTkTexteditView + # Signals + 'focusChanged', 'currentColorChanged', + 'undoAvailable', 'redoAvailable', + 'textChanged']) + + (_forwardedMethods:=[ # Forwarded Methods From TTkTexteditView # Forwarded Methods 'clear', 'setText', 'append', 'isReadOnly', 'setReadOnly', 'document', 'wrapWidth', 'setWrapWidth', @@ -811,11 +716,10 @@ class TTkTextEdit(TTkAbstractScrollArea): 'undo', 'redo', 'isUndoAvailable', 'isRedoAvailable', # Export Methods, 'toAnsi', 'toRawText', 'toPlainText', # 'toHtml', 'toMarkdown', - # Signals - 'focusChanged', 'currentColorChanged', - 'undoAvailable', 'redoAvailable', - 'textChanged' + ]) ) + _forwardWidget = TTkTextEditView + def __init__(self, *, # TTkWidget init parent:TTkWidget=None, @@ -831,6 +735,14 @@ class TTkTextEdit(TTkAbstractScrollArea): lineNumber:bool=False, lineNumberStarting:int=0, **kwargs) -> None: + ''' + :param textEditView: a custom TextEdit View to be used instead of the default one. + :type textEditView: :py:class:`TTkTextEditView`, optional + :param lineNumber: show the line number on the left side, defaults to False + :type lineNumber: bool, optional + :param lineNumberStarting: set the starting number of the left line number column, defaults to 0 + :type lineNumberStarting: int, optional + ''' super().__init__(parent=parent, visible=visible, **kwargs) self._textEditView = textEditView if textEditView else TTkTextEditView(readOnly=readOnly, multiLine=multiLine, document=document) # self.setFocusPolicy(self._textEditView.focusPolicy()) @@ -844,44 +756,11 @@ class TTkTextEdit(TTkAbstractScrollArea): textEditLayout.addWidget(self._lineNumberView,0,0) self.setViewport(textEditLayout) - self.clear = self._textEditView.clear - self.setText = self._textEditView.setText - self.append = self._textEditView.append - self.document = self._textEditView.document - self.isReadOnly = self._textEditView.isReadOnly - self.setReadOnly = self._textEditView.setReadOnly - self.textCursor = self._textEditView.textCursor - self.setFocus = self._textEditView.setFocus - self.multiLine = self._textEditView.multiLine - self.setColor = self._textEditView.setColor - self.cut = self._textEditView.cut - self.copy = self._textEditView.copy - self.paste = self._textEditView.paste - self.undo = self._textEditView.undo - self.redo = self._textEditView.redo - self.isUndoAvailable = self._textEditView.isUndoAvailable - self.isRedoAvailable = self._textEditView.isRedoAvailable - # Forward export methods - self.toAnsi = self._textEditView.toAnsi - self.toRawText = self._textEditView.toRawText - self.toPlainText = self._textEditView.toPlainText - # self.toHtml = self._textEditView.toHtml - # self.toMarkdown = self._textEditView.toMarkdown - # Forward Wrap Methods - self.wrapWidth = self._textEditView.wrapWidth - self.setWrapWidth = self._textEditView.setWrapWidth - self.lineWrapMode = self._textEditView.lineWrapMode - self.setLineWrapMode = self._textEditView.setLineWrapMode - self.wordWrapMode = self._textEditView.wordWrapMode - self.setWordWrapMode = self._textEditView.setWordWrapMode - # Forward Signals - self.focusChanged = self._textEditView.focusChanged - self.currentColorChanged = self._textEditView.currentColorChanged - self.undoAvailable = self._textEditView.undoAvailable - self.redoAvailable = self._textEditView.redoAvailable - self.textChanged = self._textEditView.textChanged + for _attr in self._forwardedSignals+self._forwardedMethods: + setattr(self,_attr,getattr(self._textEditView,_attr)) def textEditView(self): + '''textEditView''' return self._textEditView def getLineNumber(self): @@ -894,10 +773,12 @@ class TTkTextEdit(TTkAbstractScrollArea): self._lineNumberView.setVisible(ln) def lineNumberStarting(self): + '''lineNumberStarting''' return self._lineNumberView._startingNumber @pyTTkSlot(int) def setLineNumberStarting(self, starting): + '''setLineNumberStarting''' self._lineNumberView._startingNumber = starting self._lineNumberView._wrapChanged() diff --git a/TermTk/TTkWidgets/widget.py b/TermTk/TTkWidgets/widget.py index b4cd18fa..fd3676b5 100644 --- a/TermTk/TTkWidgets/widget.py +++ b/TermTk/TTkWidgets/widget.py @@ -61,50 +61,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): The TTkWidget class is the base class of all user interface objects - :param name: the name of the widget, defaults to "" - :type name: str, optional - :param parent: the parent widget, defaults to None - :type parent: :py:class:`TTkWidget`, optional - - :param x: the x position, defaults to 0 - :type x: int, optional - :param y: the y position, defaults to 0 - :type y: int, optional - :param pos: the [x,y] position (override the previously defined x, y), defaults to (x,y) - :type pos: (int,int), optional - - :param width: the width of the widget, defaults to 0 - :type width: int, optional - :param height: the height of the widget, defaults to 0 - :type height: int, optional - :param size: the size [width, height] of the widget (override the previously defined sizes), defaults to (width,height) - :type size: (int,int), optional - - :param maxWidth: the maxWidth of the widget, defaults to 0x10000 - :type maxWidth: int, optional - :param maxHeight: the maxHeight of the widget, defaults to 0x10000 - :type maxHeight: int, optional - :param maxSize: the max [width,height] of the widget, optional, defaults to (maxWidth,maxHeight) - :type maxSize: (int,int), optional - :param minWidth: the minWidth of the widget, defaults to 0 - :type minWidth: int, optional - :param minHeight: the minHeight of the widget, defaults to 0 - :type minHeight: int, optional - :param minSize: the minSize [width,height] of the widget, optional, defaults to (minWidth,minHeight) - :type minSize: (int,int), optional - - :param toolTip: This property holds the widget's tooltip, defaults to '' - :type toolTip: :py:class:`TTkString`, optional - - :param style: this field hold the custom style to be used by this widget - :type style: dict, optional - :param addStyle: this field is required to override/merge the new style on top of the current one, useful if only few params need to be changed - :type addStyle: dict, optional - - :param visible: the visibility, optional, defaults to True - :type visible: bool, optional - :param enabled: the ability to handle input events, optional, defaults to True - :type enabled: bool, optional ''' focusChanged:pyTTkSignal @@ -182,7 +138,52 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents): style : dict = None, addStyle : dict = None, **kwargs) -> None: - + ''' + :param name: the name of the widget, defaults to "" + :type name: str, optional + :param parent: the parent widget, defaults to None + :type parent: :py:class:`TTkWidget`, optional + + :param x: the x position, defaults to 0 + :type x: int, optional + :param y: the y position, defaults to 0 + :type y: int, optional + :param pos: the [x,y] position (override the previously defined x, y), defaults to (x,y) + :type pos: (int,int), optional + + :param width: the width of the widget, defaults to 0 + :type width: int, optional + :param height: the height of the widget, defaults to 0 + :type height: int, optional + :param size: the size [width, height] of the widget (override the previously defined sizes), defaults to (width,height) + :type size: (int,int), optional + + :param maxWidth: the maxWidth of the widget, defaults to 0x10000 + :type maxWidth: int, optional + :param maxHeight: the maxHeight of the widget, defaults to 0x10000 + :type maxHeight: int, optional + :param maxSize: the max [width,height] of the widget, optional, defaults to (maxWidth,maxHeight) + :type maxSize: (int,int), optional + :param minWidth: the minWidth of the widget, defaults to 0 + :type minWidth: int, optional + :param minHeight: the minHeight of the widget, defaults to 0 + :type minHeight: int, optional + :param minSize: the minSize [width,height] of the widget, optional, defaults to (minWidth,minHeight) + :type minSize: (int,int), optional + + :param toolTip: This property holds the widget's tooltip, defaults to '' + :type toolTip: :py:class:`TTkString`, optional + + :param style: this field hold the custom style to be used by this widget + :type style: dict, optional + :param addStyle: this field is required to override/merge the new style on top of the current one, useful if only few params need to be changed + :type addStyle: dict, optional + + :param visible: the visibility, optional, defaults to True + :type visible: bool, optional + :param enabled: the ability to handle input events, optional, defaults to True + :type enabled: bool, optional + ''' if kwargs: TTkLog.warn(f"Unhandled init params {self.__class__.__name__} -> {kwargs}") diff --git a/docs/source/conf.py b/docs/source/conf.py index 8d0532e1..42a47a60 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -130,7 +130,8 @@ html_permalinks_icon = '🌶️' html_theme_options = { "home_page_in_toc": True, "use_fullscreen_button": True, - "show_toc_level": 2, + # "toc_title": "{your-title}", + "show_toc_level": 3, "repository_url": "https://github.com/ceccopierangiolieugenio/pyTermTk", } diff --git a/docs/source/sphinx_modules/sphinx_PyRefRole_hacked.py b/docs/source/sphinx_modules/sphinx_PyRefRole_hacked.py index 92441425..cef2704b 100644 --- a/docs/source/sphinx_modules/sphinx_PyRefRole_hacked.py +++ b/docs/source/sphinx_modules/sphinx_PyRefRole_hacked.py @@ -57,20 +57,20 @@ def setup(app: Sphinx) -> ExtensionMetadata: for _module in sys.modules: _parseModules(sys.modules[_module]) - for x in modules.items(): - print(x) + # for x in modules.items(): + # print(x) def _resolve(txt) -> str: oldTxt = txt if txt in modules: txt = f"~{modules[txt]}.{txt}" - print(f"-----------> {oldTxt=} -> {txt=}") + # print(f"-----------> {oldTxt=} -> {txt=}") else: txts = txt.split('.') if txts[0] in modules: txts[0] = f"~{modules[txts[0]]}.{txts[0]}" txt = '.'.join(txts) - print(f"-----------> {oldTxt=} -> {txt=}") + # print(f"-----------> {oldTxt=} -> {txt=}") return txt _process_link_bk = sphinxPythonDomain.PyXRefRole.process_link diff --git a/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py index a8ca8857..680b0614 100644 --- a/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py +++ b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py @@ -115,6 +115,7 @@ def setup(app: Sphinx) -> ExtensionMetadata: ttkAllSlots={} ttkAllMembers={} # List all the member of a class ttkInherited={} # List of the inherited classes for each class + ttkClasses={} def _getMethodsAndSlots(_obj): retSlots = [] @@ -198,6 +199,8 @@ def setup(app: Sphinx) -> ExtensionMetadata: modStyles[_name] = _get_classStyleCode(_obj) if _name not in modules: modules[_name] = _mod.__name__ + if _name not in ttkClasses: + ttkClasses[_name] = _obj modules[_name] = _mod.__name__ if len(_mod.__name__)>len(modules[_name]) else modules[_name] print(f" * {_name=} = {_obj}") @@ -236,6 +239,55 @@ def setup(app: Sphinx) -> ExtensionMetadata: for (x,y) in ttkInherited.items(): print(f"Inherited {x} -> {y}") + ############################################### + # Rework inherited init params in the __doc__ # + ############################################### + # ttk.TTkTemplates.dragevents.TDragEvents.__init__.__doc__='' + # ttk.TTkTemplates.mouseevents.TMouseEvents.__init__.__doc__='' + # ttk.TTkTemplates.keyevents.TKeyEvents.__init__.__doc__='' + for _name in ttkClasses: + def _mergeDoc(_da,_db,_title=''): + if not _da and not _db: + return '' + if not _da: + return _db + if not _db: + return _da + _dal = _da.split('\n') + _dbl = _db.split('\n') + _mina = min(len(_l) - len(_l.lstrip()) for _l in _dal if _l and _l.lstrip()) + _minb = min(len(_l) - len(_l.lstrip()) for _l in _dbl if _l and _l.lstrip()) + if _title: + _dbl = [' '*_minb+_l for _l in _title.split('\n')] + _dbl + if _mina<_minb: + _diff = _minb-_mina + _dc = '\n'.join([(' '*_diff)+_l for _l in _dal]+_dbl) + else: + _diff = _mina-_minb + _dc = '\n'.join(_dal + [(' '*_diff)+_l for _l in _dbl]) + # for _l in _dal+_dbl: + # print(f"--{_l}--") + # print(f"{_mina=} {_minb=}") + # print(_dc) + return _dc + + + _obj = ttkClasses[_name] + if _obj.__doc__ and ":param" in _obj.__doc__: + print(ttk.TTkString(f"[{_name}] Params in the class docstring", ttk.TTkColor.BG_RED + ttk.TTkColor.FG_YELLOW).toAnsi()) + if hasattr(_obj,'__init__'): + _obj.__doc__ = _mergeDoc(_obj.__doc__, _obj.__init__.__doc__) + if hasattr(_obj,'_forwardWidget') and hasattr(_obj._forwardWidget,'__init__'): + _obj.__doc__ = _mergeDoc(_obj.__doc__, + _obj._forwardWidget.__init__.__doc__, + f"\n:py:class:`{_obj._forwardWidget.__name__}`'s forwarded init params:\n") + for _iname in ttkInherited[_name]: + if _iname not in ttkClasses: + continue + _iobj = ttkClasses[_iname] + if hasattr(_iobj,'__init__'): + _obj.__doc__ = _mergeDoc(_obj.__doc__, _iobj.__init__.__doc__, f"\n:py:class:`{_iname}`'s inherited init params:\n") + # print(modStyles) # raise Exception @@ -287,7 +339,7 @@ def setup(app: Sphinx) -> ExtensionMetadata: _baseClass = _allForwarded['baseClass'] _allSlots = set(ttkAllSlots.get(_baseClass,[])) _allMethods = set(ttkAllMethods.get(_baseClass,[])) - print(f"{_name=} {_baseClass=}\n{_allForwarded=}\n{_allSlots=}\n{_allMethods=}") + # print(f"{_name=} {_baseClass=}\n{_allForwarded=}\n{_allSlots=}\n{_allMethods=}") _fwSlots = { 'baseClass': _baseClass, 'methods': sorted([_m for _m in _allForwarded['methods'] if _m in _allSlots])} @@ -338,7 +390,7 @@ def setup(app: Sphinx) -> ExtensionMetadata: 'TTkMethodsInherited': ttkInheritedMethods , } - print('\n'.join([f" * {x}={context[x]}" for x in context])) + # print('\n'.join([f" * {x}={context[x]}" for x in context])) return generate_autosummary_content_old( name, obj, parent, template, template_name, imported_members, diff --git a/docs/source/static/theme_overrides.css b/docs/source/static/theme_overrides.css index 39d76d68..96a821f2 100644 --- a/docs/source/static/theme_overrides.css +++ b/docs/source/static/theme_overrides.css @@ -20,7 +20,8 @@ html[data-theme="dark"] .bd-content img:not(.only-dark, .dark-light) { } @media (min-width: 992px) { .bd-sidebar-primary { - flex-basis: 18%; + flex-basis: 17%; + padding: 0.5rem; } } diff --git a/tutorial/000-examples.rst b/tutorial/000-examples.rst index f096879f..d8821f2a 100644 --- a/tutorial/000-examples.rst +++ b/tutorial/000-examples.rst @@ -40,6 +40,8 @@ Events `TTkLineEdit/SetGet.01.py `_ - (`tryItOnline `__): +.. _Examples-Terminal: + TTkTerminal ===========