From 02642c6e35940ced72c53cd309fb3495b8992338 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 27 Oct 2024 22:26:50 +0000 Subject: [PATCH] MAssive DOC reworking --- Makefile | 2 +- TermTk/TTkAbstract/abstractitemmodel.py | 1 + TermTk/TTkAbstract/abstracttablemodel.py | 32 ++- TermTk/TTkCore/TTkTerm/term_base.py | 1 + TermTk/TTkCore/signal.py | 18 +- TermTk/TTkWidgets/TTkModelView/tablewidget.py | 125 +++++----- TermTk/TTkWidgets/TTkModelView/treewidget.py | 156 ++++++++++-- .../TTkWidgets/TTkModelView/treewidgetitem.py | 1 + .../TTkWidgets/TTkTerminal/debugterminal.py | 2 + .../TTkWidgets/TTkTerminal/terminalhelper.py | 2 + docs/requirements.txt | 114 +++++---- docs/source/.gitignore | 4 +- docs/{ => source}/Makefile | 6 +- docs/source/conf.py | 175 +++++++------ docs/source/index.rst | 71 ++++-- docs/source/info/installing.rst | 32 +-- docs/source/make.bat | 35 +++ docs/source/sphinx_modules/method_signal.py | 43 ++++ .../sphinx_ext_autosummary_reworked.py | 229 ++++++++++++++++++ docs/source/sphinx_modules/test_01.py | 58 +++++ .../{_static => static}/theme_overrides.css | 11 + docs/source/{_static => static}/ttk.css | 0 docs/source/templates/autosummary/base.rst | 5 + docs/source/templates/autosummary/class.rst | 29 +++ docs/source/templates/autosummary/module.rst | 60 +++++ .../templates/custom-class-template.01.rst | 60 +++++ .../templates/custom-class-template.rst | 40 +++ .../templates/custom-module-template.01.rst | 31 +++ .../templates/custom-module-template.rst | 66 +++++ docs/sphynx.001.signal.patch | 12 +- .../test.classes.001.slots.typing.py | 120 +++++++++ tutorial/000-examples.rst | 28 +-- tutorial/001-helloworld.rst | 4 +- tutorial/002-layout.rst | 12 +- tutorial/003-signalslots.rst | 4 +- tutorial/004-logging.rst | 8 +- tutorial/005-calculator.rst | 10 +- tutorial/ttkDesigner/textEdit/README.rst | 6 +- 38 files changed, 1268 insertions(+), 345 deletions(-) rename docs/{ => source}/Makefile (83%) create mode 100644 docs/source/make.bat create mode 100644 docs/source/sphinx_modules/method_signal.py create mode 100644 docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py create mode 100644 docs/source/sphinx_modules/test_01.py rename docs/source/{_static => static}/theme_overrides.css (82%) rename docs/source/{_static => static}/ttk.css (100%) create mode 100644 docs/source/templates/autosummary/base.rst create mode 100644 docs/source/templates/autosummary/class.rst create mode 100644 docs/source/templates/autosummary/module.rst create mode 100644 docs/source/templates/custom-class-template.01.rst create mode 100644 docs/source/templates/custom-class-template.rst create mode 100644 docs/source/templates/custom-module-template.01.rst create mode 100644 docs/source/templates/custom-module-template.rst create mode 100644 tests/t.generic/test.classes.001.slots.typing.py diff --git a/Makefile b/Makefile index c0547f19..859a9fdc 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ . .venv/bin/activate ; \ pip install -r docs/requirements.txt # Add "Signal" option in the method domains - patch -p3 -d .venv/lib/python3*/ < docs/sphynx.001.signal.patch + # patch -p3 -d .venv/lib/python3*/ < docs/sphynx.001.signal.patch # Update/Regen # # Docs # pip install sphinx sphinx-epytext sphinx-autodocgen sphinx-rtd-theme diff --git a/TermTk/TTkAbstract/abstractitemmodel.py b/TermTk/TTkAbstract/abstractitemmodel.py index 7abf8c87..b33f0907 100644 --- a/TermTk/TTkAbstract/abstractitemmodel.py +++ b/TermTk/TTkAbstract/abstractitemmodel.py @@ -25,6 +25,7 @@ __all__ = ['TTkAbstractItemModel'] from TermTk.TTkCore.signal import pyTTkSignal class TTkAbstractItemModel(): + '''TTkAbstractItemModel''' __slots__ = ( # Signals 'dataChanged' diff --git a/TermTk/TTkAbstract/abstracttablemodel.py b/TermTk/TTkAbstract/abstracttablemodel.py index 0e19ad2d..b1d9f07c 100644 --- a/TermTk/TTkAbstract/abstracttablemodel.py +++ b/TermTk/TTkAbstract/abstracttablemodel.py @@ -119,29 +119,27 @@ class TTkAbstractTableModel(): :class:`~TermTk.TTkWidgets.TTkModelView.tablemodelcsv.TTkTableModelCSV` subclass of :class:`~TermTk.TTkWidgets.TTkModelView.tablemodellist.TTkTableModelList` including the api to import csv data - +-----------------------------------------------------------------------------------------------+ - | `Signals `_ | - +-----------------------------------------------------------------------------------------------+ + ''' - .. py:method:: dataChanged(pos,size) - :signal: + __slots__ = ( + # Signals + 'dataChanged' + ) - This signal is emitted whenever the data in an existing item changes. + dataChanged:pyTTkSignal[int,int] + ''' + This signal is emitted whenever the data in an existing item changes. - If more items are affected, the pos/size definne the minimum area including all of those changes. + If more items are affected, the pos/size definne the minimum area including all of those changes. - When reimplementing the :meth:`setData` function, this signal must be emitted explicitly. + When reimplementing the :meth:`setData` function, this signal must be emitted explicitly. - :param pos: the topLeft margin of the modified area - :type pos: tuple(int,int) + :param pos: the topLeft margin of the modified area + :type pos: tuple(int,int) - :param size: the size of the modified area - :type size: tuple(int,int) - ''' - __slots__ = ( - # Signals - 'dataChanged' - ) + :param size: the size of the modified area + :type size: tuple(int,int) + ''' def __init__(self): self.dataChanged = pyTTkSignal(tuple[int,int],tuple[int,int]) diff --git a/TermTk/TTkCore/TTkTerm/term_base.py b/TermTk/TTkCore/TTkTerm/term_base.py index 2585c434..8054f3e7 100644 --- a/TermTk/TTkCore/TTkTerm/term_base.py +++ b/TermTk/TTkCore/TTkTerm/term_base.py @@ -23,6 +23,7 @@ import os class TTkTermBase(): + '''TTkTermBase''' CLEAR = "\033[2J\033[0;0f" # Clear screen and set cursor to position 0,0 ALT_SCREEN = "\033[?1049h" #* Switch to alternate screen NORMAL_SCREEN = "\033[?1049l" #* Switch to normal screen diff --git a/TermTk/TTkCore/signal.py b/TermTk/TTkCore/signal.py index 25b2054b..dd3e116c 100644 --- a/TermTk/TTkCore/signal.py +++ b/TermTk/TTkCore/signal.py @@ -57,23 +57,23 @@ Methods __all__ = ['pyTTkSlot', 'pyTTkSignal'] +from typing import TypeVar, TypeVarTuple, Generic, List from inspect import getfullargspec from types import LambdaType from threading import Lock -def pyTTkSlot(*args, **kwargs): +def pyTTkSlot(*args): def pyTTkSlot_d(func): # Add signature attributes to the function func._TTkslot_attr = args return func return pyTTkSlot_d -def pyTTkSignal(*args, **kwargs): - return _pyTTkSignal_obj(*args, **kwargs) +Ts = TypeVarTuple("Ts") -class _pyTTkSignal_obj(): +class pyTTkSignal(Generic[*Ts]): _signals = [] - __slots__ = ('_types', '_name', '_revision', '_connected_slots', '_mutex') + __slots__ = ('_types', '_connected_slots', '_mutex') def __init__(self, *args, **kwargs): # ref: http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#PyQt5.QtCore.pyqtSignal @@ -82,17 +82,13 @@ class _pyTTkSignal_obj(): # Parameters: # types - the types that define the C++ signature of the signal. Each type may be a Python type object or a string that is the name of a C++ type. Alternatively each may be a sequence of type arguments. In this case each sequence defines the signature of a different signal overload. The first overload will be the default. - # name - the name of the signal. If it is omitted then the name of the class attribute is used. This may only be given as a keyword argument. - # revision - the revision of the signal that is exported to QML. This may only be given as a keyword argument. # arguments - the sequence of the names of the signal's arguments that is exported to QML. This may only be given as a keyword argument. # Return type: # an unbound signal self._types = args - self._name = kwargs.get('name', None) - self._revision = kwargs.get('revision', 0) self._connected_slots = {} self._mutex = Lock() - _pyTTkSignal_obj._signals.append(self) + pyTTkSignal._signals.append(self) def connect(self, slot): # ref: http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#connect @@ -148,7 +144,7 @@ class _pyTTkSignal_obj(): @staticmethod def clearAll(): - for s in _pyTTkSignal_obj._signals: + for s in pyTTkSignal._signals: s.clear() def forward(self): diff --git a/TermTk/TTkWidgets/TTkModelView/tablewidget.py b/TermTk/TTkWidgets/TTkModelView/tablewidget.py index 42f1615d..447f208c 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/tablewidget.py @@ -170,70 +170,6 @@ class TTkTableWidget(TTkAbstractScrollView): :param dataPadding: the right column padding, defaults to 1 :type dataPadding: int, optional - - +-----------------------------------------------------------------------------------------------+ - | `Signals `_ | - +-----------------------------------------------------------------------------------------------+ - - .. py:method:: cellChanged(row, col) - :signal: - - This signal is emitted whenever the data of the item in the cell specified by row and column has changed. - - :param row: the row - :type row: int - :param col: the column - :type col: int - - .. py:method:: cellClicked(row, col) - :signal: - - This signal is emitted whenever a cell in the table is clicked. - The row and column specified is the cell that was clicked. - - :param row: the row - :type row: int - :param col: the column - :type col: int - - .. py:method:: cellDoubleClicked(row, col) - :signal: - - This signal is emitted whenever a cell in the table is double clicked. - The row and column specified is the cell that was double clicked. - - :param row: the row - :type row: int - :param col: the column - :type col: int - - .. py:method:: cellEntered(row, col) - :signal: - - This signal is emitted when the mouse cursor enters a cell. - The cell is specified by row and column. - - :param row: the row - :type row: int - :param col: the column - :type col: int - - .. py:method:: currentCellChanged(currRow, currCol, prevRow, prevCol) - :signal: - - This signal is emitted whenever the current cell changes. - The cell specified by **prevRow** and **prevCol** is the cell that previously had the focus, - the cell specified by **currRow** and **currCol** is the new current cell. - - :param currRow: the current row - :type currRow: int - :param currColumn: the current column - :type currColumn: int - :param prevRow: the previous row - :type prevRow: int - :param prevCol: the previous column - :type prevCol: int - ''' classStyle = { @@ -278,6 +214,61 @@ class TTkTableWidget(TTkAbstractScrollView): 'cellEntered', # 'cellPressed', 'currentCellChanged', ) + cellChanged:pyTTkSignal[int,int] + ''' + This signal is emitted whenever the data of the item in the cell specified by row and column has changed. + + :param row: the row + :type row: int + :param col: the column + :type col: int + ''' + cellClicked:pyTTkSignal[int,int] + ''' + This signal is emitted whenever a cell in the table is clicked. + The row and column specified is the cell that was clicked. + + :param row: the row + :type row: int + :param col: the column + :type col: int + ''' + cellDoubleClicked:pyTTkSignal[int,int] + ''' + This signal is emitted whenever a cell in the table is double clicked. + The row and column specified is the cell that was double clicked. + + :param row: the row + :type row: int + :param col: the column + :type col: int + ''' + cellEntered:pyTTkSignal[int,int] + ''' + This signal is emitted when the mouse cursor enters a cell. + The cell is specified by row and column. + + :param row: the row + :type row: int + :param col: the column + :type col: int + ''' + # self.cellPressed = pyTTkSignal(int,int) + currentCellChanged:pyTTkSignal[int,int,int,int] + ''' + This signal is emitted whenever the current cell changes. + The cell specified by **prevRow** and **prevCol** is the cell that previously had the focus, + the cell specified by **currRow** and **currCol** is the new current cell. + + :param currRow: the current row + :type currRow: int + :param currColumn: the current column + :type currColumn: int + :param prevRow: the previous row + :type prevRow: int + :param prevCol: the previous column + :type prevCol: int + ''' def __init__(self, *, tableModel:TTkAbstractTableModel=None, @@ -324,7 +315,7 @@ class TTkTableWidget(TTkAbstractScrollView): self._vSeparatorSelected = None self._sortColumn = -1 self._sortOrder = TTkK.AscendingOrder - self._tableModel = tableModel if tableModel else TTkTableModelList(list=[['']*10 for _ in range(10)]) + self._tableModel = tableModel if tableModel else TTkTableModelList(data=[['']*10 for _ in range(10)]) self._tableModel.dataChanged.connect(self.update) super().__init__(**kwargs) self._refreshLayout() @@ -1898,7 +1889,3 @@ class TTkTableWidget(TTkAbstractScrollView): # Draw Top/Left Corner canvas.drawText(pos=(0,0), text=' ', width=vhs, color=separatorColor.invertFgBg() ) - - - - diff --git a/TermTk/TTkWidgets/TTkModelView/treewidget.py b/TermTk/TTkWidgets/TTkModelView/treewidget.py index 2fb88fdf..41e00e56 100644 --- a/TermTk/TTkWidgets/TTkModelView/treewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/treewidget.py @@ -33,7 +33,96 @@ from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot from dataclasses import dataclass class TTkTreeWidget(TTkAbstractScrollView): - '''TTkTreeWidget''' + '''TTkTreeWidget + + The :class:`TTkTreeWidget` class is a convenience class that provides a standard tree + widget with a classic item-based interface. + This class is based on TTk's Model/View architecture and uses a default model to hold items, + each of which is a :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem`. + + In its simplest form, a tree widget can be constructed in the following way: + + .. code-block:: python + + tree = ttk.TTkTree(parent=root) + tree.setHeaderLabels(["Column 1", "Column 2", "Column 3"]) + + top = ttk.TTkTreeWidgetItem(["String A", "String B", "String C"]) + + tree.addTopLevelItem(top) + + for i in range(5): + child = ttk.TTkTreeWidgetItem(["Child A" + str(i), "Child B" + str(i), "Child C" + str(i)]) + top.addChild(child) + + Before items can be added to the tree widget, + the number of columns must be set with :meth:`setHeaderLabels`. + This allows each item to have one label. + + The tree can have a header that contains a section for each column in the widget. + It is easiest to set up the labels for each section by supplying a list of strings with :meth:`setHeaderLabels`. + + The items in the tree can be sorted by column according to a predefined sort order. + If sorting is enabled, the user can sort the items by clicking on a column header. + Sorting can be enabled or disabled by calling setSortingEnabled(). + The isSortingEnabled() function indicates whether sorting is enabled. + ''' + + itemActivated:pyTTkSignal[TTkTreeWidgetItem, int] + ''' + This signal is emitted when the user activates an item by double-clicking + or pressing a special key (e.g., Enter). + + :param item: the item that was clicked. + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + :param col: the item's column that was clicked. + :type col: int + ''' + itemChanged:pyTTkSignal[TTkTreeWidgetItem, int] + ''' + This signal is emitted when the contents of the column in the specified item changes. + + :param item: the item reported by this signal + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + :param col: the item's column + :type col: int + ''' + itemClicked:pyTTkSignal[TTkTreeWidgetItem, int] + ''' + This signal is emitted when the user clicks inside the widget. + + If no item was clicked, no signal will be emitted. + + :param item: the item that was clicked. + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + :param col: the item's column that was clicked. + :type col: int + ''' + itemDoubleClicked:pyTTkSignal[TTkTreeWidgetItem, int] + ''' + This signal is emitted when the user double clicks inside the widget. + + If no item was double clicked, no signal will be emitted. + + :param item: the item that was clicked. + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + :param col: the item's column that was clicked. + :type col: int + ''' + itemExpanded:pyTTkSignal[TTkTreeWidgetItem] + ''' + This signal is emitted when the specified item is expanded so that all of its children are displayed. + + :param item: the item reported by this signal + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + ''' + itemCollapsed:pyTTkSignal[TTkTreeWidgetItem] + ''' + This signal is emitted when the specified item is collapsed so that none of its children are displayed. + + :param item: the item reported by this signal + :type item: :class:`~TermTk.TTkWidgets.TTkModelView.treewidgetitem.TTkTreeWidgetItem` + ''' classStyle = { 'default': { @@ -53,7 +142,7 @@ class TTkTreeWidget(TTkAbstractScrollView): __slots__ = ( '_rootItem', '_cache', '_header', '_columnsPos', '_selectedId', '_selected', '_separatorSelected', - '_sortColumn', '_sortOrder', + '_sortColumn', '_sortOrder', '_sortingEnabled', # Signals 'itemChanged', 'itemClicked', 'itemDoubleClicked', 'itemExpanded', 'itemCollapsed', 'itemActivated' ) @@ -65,7 +154,7 @@ class TTkTreeWidget(TTkAbstractScrollView): widgets: list firstLine: bool - def __init__(self, **kwargs) -> None: + def __init__(self, *, header=[], sortingEnabled=True, **kwargs) -> None: # Signals self.itemActivated = pyTTkSignal(TTkTreeWidgetItem, int) self.itemChanged = pyTTkSignal(TTkTreeWidgetItem, int) @@ -81,6 +170,7 @@ class TTkTreeWidget(TTkAbstractScrollView): self._header = kwargs.get('header',[]) self._columnsPos = [] self._cache = [] + self._sortingEnabled=sortingEnabled self._sortColumn = -1 self._sortOrder = TTkK.AscendingOrder self.setMinimumHeight(1) @@ -108,6 +198,7 @@ class TTkTreeWidget(TTkAbstractScrollView): return self.size() def clear(self) -> None: + '''clear''' # Remove all the widgets for ri in self._rootItem.children(): ri.setTreeItemParent(None) @@ -121,6 +212,7 @@ class TTkTreeWidget(TTkAbstractScrollView): self.update() def addTopLevelItem(self, item:TTkTreeWidgetItem) -> None: + '''addTopLevelItem''' self._rootItem.addChild(item) item.setTreeItemParent(self) self._refreshCache() @@ -128,6 +220,7 @@ class TTkTreeWidget(TTkAbstractScrollView): self.update() def addTopLevelItems(self, items:TTkTreeWidgetItem) -> None: + '''addTopLevelItems''' self._rootItem.addChildren(items) self._rootItem.setTreeItemParent(self) #for item in items: @@ -137,46 +230,64 @@ class TTkTreeWidget(TTkAbstractScrollView): self.update() def takeTopLevelItem(self, index) -> None: + '''takeTopLevelItem''' self._rootItem.takeChild(index) self._refreshCache() self.viewChanged.emit() self.update() def topLevelItem(self, index) -> TTkTreeWidgetItem: + '''topLevelItem''' return self._rootItem.child(index) def indexOfTopLevelItem(self, item:TTkTreeWidgetItem) -> int: + '''indexOfTopLevelItem''' return self._rootItem.indexOfChild(item) def selectedItems(self) -> list[TTkTreeWidgetItem]: + '''selectedItems''' if self._selected: return [self._selected] return None - def setHeaderLabels(self, labels:str): + def setHeaderLabels(self, labels:str) -> None: + '''setHeaderLabels''' self._header = labels # Set 20 as default column size self._columnsPos = [20+x*20 for x in range(len(labels))] self.viewChanged.emit() self.update() + def isSortingEnabled(self) -> bool: + 'isSortingEnabled' + return self._sortingEnabled + + def setSortingEnabled(self, enabled) -> None: + 'setSortingEnabled' + if enabled != self._sortingEnabled: + self._sortingEnabled = enabled + self.update() + def sortColumn(self): '''Returns the column used to sort the contents of the widget.''' return self._sortColumn - def sortItems(self, col:int, order:TTkK.SortOrder): + def sortItems(self, col:int, order:TTkK.SortOrder) -> None: '''Sorts the items in the widget in the specified order by the values in the given column.''' + if not self._sortingEnabled: return self._sortColumn = col self._sortOrder = order self._rootItem.sortChildren(col, order) def columnWidth(self, column:int) -> int: + '''columnWidth''' if column==0: return self._columnsPos[column] else: return self._columnsPos[column]-self._columnsPos[column-1]-1 def setColumnWidth(self, column:int, width: int) -> None: + '''setColumnWidth''' i = column newSize = ((1+self._columnsPos[i-1]) if i>0 else 0) + width oldSize = self._columnsPos[i] @@ -187,6 +298,7 @@ class TTkTreeWidget(TTkAbstractScrollView): self.update() def resizeColumnToContents(self, column:int) -> None: + '''resizeColumnToContents''' contentSize = max(row.data[column].termWidth() for row in self._cache) self.setColumnWidth(column, contentSize) @@ -283,18 +395,13 @@ class TTkTreeWidget(TTkAbstractScrollView): return True def mouseDragEvent(self, evt) -> bool: - ''' - :: - - columnPos (Selected = 2) - 0 1 2 3 4 - ----|-------|--------|----------|---| - Mouse (Drag) Pos - ^ - I consider at least 4 char (3+1) as spacing - Min Selected Pos = (Selected+1) * 4 - - ''' + # columnPos (Selected = 2) + # 0 1 2 3 4 + # ----|-------|--------|----------|---| + # Mouse (Drag) Pos + # ^ + # I consider at least 4 char (3+1) as spacing + # Min Selected Pos = (Selected+1) * 4 if self._separatorSelected is not None: x,y = evt.x, evt.y ox, oy = self.getViewOffsets() @@ -329,13 +436,12 @@ class TTkTreeWidget(TTkAbstractScrollView): @pyTTkSlot() def _refreshCache(self) -> None: - ''' I save a representation of the displayed tree in a cache array - to avoid eccessve recursion over the items and - identify quickly the nth displayed line to improve the interaction - - _cache is an array of TTkTreeWidget._Cache: - [ item, level, data=[txtCol1, txtCol2, txtCol3, ... ]] - ''' + # I save a representation of the displayed tree in a cache array + # to avoid eccessve recursion over the items and + # identify quickly the nth displayed line to improve the interaction + # + # _cache is an array of TTkTreeWidget._Cache: + # [ item, level, data=[txtCol1, txtCol2, txtCol3, ... ]] self._cache = [] def _addToCache(_child, _level:int) -> None: _data = [] @@ -401,7 +507,7 @@ class TTkTreeWidget(TTkAbstractScrollView): hx = 0 if i==0 else self._columnsPos[i-1]+1 hx1 = self._columnsPos[i] canvas.drawText(pos=(hx-x,0), text=l, width=hx1-hx, color=headerColor) - if i == self._sortColumn: + if self._sortingEnabled and i == self._sortColumn: s = tt[6] if self._sortOrder == TTkK.AscendingOrder else tt[7] canvas.drawText(pos=(hx1-x-1,0), text=s, color=headerColor) # Draw header separators diff --git a/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py b/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py index bfd24d79..6aadd854 100644 --- a/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py +++ b/TermTk/TTkWidgets/TTkModelView/treewidgetitem.py @@ -30,6 +30,7 @@ from TermTk.TTkWidgets import TTkWidget from TermTk.TTkAbstract.abstractitemmodel import TTkAbstractItemModel class TTkTreeWidgetItem(TTkAbstractItemModel): + '''TTkTreeWidgetItem''' __slots__ = ('_parent', '_data', '_widgets', '_height', '_alignment', '_children', '_expanded', '_selected', '_hidden', '_childIndicatorPolicy', '_icon', '_defaultIcon', '_sortColumn', '_sortOrder', '_hasWidgets', '_parentWidget', diff --git a/TermTk/TTkWidgets/TTkTerminal/debugterminal.py b/TermTk/TTkWidgets/TTkTerminal/debugterminal.py index 085d5931..5035629c 100644 --- a/TermTk/TTkWidgets/TTkTerminal/debugterminal.py +++ b/TermTk/TTkWidgets/TTkTerminal/debugterminal.py @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +__all__ = ['DebugTTkTerminal'] + import os, pty, threading import struct, fcntl, termios diff --git a/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py b/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py index 0ec33111..ae3102aa 100644 --- a/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py +++ b/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +__all__ = ['TTkTerminalHelper'] + import os, pty, threading import struct, fcntl, termios from select import select diff --git a/docs/requirements.txt b/docs/requirements.txt index 2494dfa5..1f71528f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,56 +1,74 @@ -alabaster==0.7.12 -attrs==22.1.0 -Babel==2.10.3 -bleach==5.0.1 -build==0.8.0 -certifi==2022.6.15 -cffi==1.15.1 -charset-normalizer==2.1.0 -commonmark==0.9.1 -cryptography==37.0.4 -docutils==0.17.1 -flake8==5.0.4 -idna==3.3 +accessible-pygments==0.0.5 +alabaster==1.0.0 +babel==2.16.0 +backports.tarfile==1.2.0 +beautifulsoup4==4.12.3 +build==1.2.2.post1 +certifi==2024.8.30 +cffi==1.17.1 +charset-normalizer==3.4.0 +cryptography==43.0.3 +css-html-js-minify==2.5.5 +docutils==0.21.2 +flake8==7.1.1 +furo==2024.8.6 +idna==3.10 imagesize==1.4.1 -importlib-metadata==4.12.0 -iniconfig==1.1.1 +importlib_metadata==8.5.0 +iniconfig==2.0.0 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.1.0 jeepney==0.8.0 -Jinja2==3.1.2 -keyring==23.8.2 -MarkupSafe==2.1.1 +Jinja2==3.1.4 +keyring==25.4.1 +lxml==5.3.0 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 mccabe==0.7.0 -packaging==21.3 -pep517==0.13.0 -pkginfo==1.8.3 -pluggy==1.0.0 -py==1.11.0 -pycodestyle==2.9.1 -pycparser==2.21 -pyflakes==2.5.0 -Pygments==2.12.0 -pyparsing==3.0.9 -pytest==7.1.2 -pytz==2022.1 -readme-renderer==36.0 -requests==2.28.1 -requests-toolbelt==0.9.1 +mdurl==0.1.2 +more-itertools==10.5.0 +nh3==0.2.18 +packaging==24.1 +piccolo_theme==0.24.0 +pkginfo==1.10.0 +pluggy==1.5.0 +pycodestyle==2.12.1 +pycparser==2.22 +pydata-sphinx-theme==0.16.0 +pyflakes==3.2.0 +Pygments==2.18.0 +pyproject_hooks==1.2.0 +pytest==8.3.3 +python-slugify==8.0.4 +readme_renderer==44.0 +requests==2.32.3 +requests-toolbelt==1.0.0 rfc3986==2.0.0 -rich==12.5.1 -SecretStorage==3.3.2 -six==1.16.0 +rich==13.9.3 +SecretStorage==3.3.3 snowballstemmer==2.2.0 -Sphinx==5.1.1 +soupsieve==2.6 +Sphinx==8.1.3 sphinx-autodocgen==1.3 +sphinx-basic-ng==1.0.0b2 +sphinx-book-theme==1.1.3 sphinx-epytext==0.0.4 -sphinx-rtd-theme==1.0.0 -sphinxcontrib-applehelp==1.0.2 -sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==2.0.0 +sphinx-material==0.0.36 +sphinx-rtd-theme==3.0.1 +sphinx-wagtail-theme==6.3.0 +sphinx_press_theme==0.9.1 +sphinxawesome-theme==5.3.1 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jquery==4.1 sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 -tomli==2.0.1 -twine==4.0.1 -urllib3==1.26.11 -webencodings==0.5.1 -zipp==3.8.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +text-unidecode==1.3 +twine==5.1.1 +typing_extensions==4.12.2 +Unidecode==1.3.8 +urllib3==2.2.3 +zipp==3.20.2 diff --git a/docs/source/.gitignore b/docs/source/.gitignore index f7a70aec..193c3ada 100644 --- a/docs/source/.gitignore +++ b/docs/source/.gitignore @@ -1 +1,3 @@ -autogen.* \ No newline at end of file +autogen.* +_build +_autosummary diff --git a/docs/Makefile b/docs/source/Makefile similarity index 83% rename from docs/Makefile rename to docs/source/Makefile index d0c3cbf1..7e8d8760 100644 --- a/docs/Makefile +++ b/docs/source/Makefile @@ -5,8 +5,8 @@ # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build +SOURCEDIR = . +BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @@ -17,4 +17,6 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile + rm -rf _autosummary $(BUILDDIR) @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + cp -a ../images $(BUILDDIR)/html/_images diff --git a/docs/source/conf.py b/docs/source/conf.py index 94077944..18e82a70 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,19 +1,17 @@ # Configuration file for the Sphinx documentation builder. # -# This file only contains a selection of the most common options. For a full -# list see the documentation: +# For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html -# -- Path setup -------------------------------------------------------------- +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# import os import sys sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath('sphinx_modules')) +import TermTk # -- Project information ----------------------------------------------------- @@ -29,57 +27,37 @@ else: release = 'X.XX.X-a' # -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = [ - 'sphinx.ext.intersphinx', - 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', + # 'sphinx.ext.linkcode', # Create a link to the source through linkcode_resolve 'sphinx.ext.githubpages', - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.autosectionlabel', - 'sphinx_epytext', - 'sphinxcontrib_autodocgen', - #'sphinxcontrib.fulltoc', + #'sphinx.ext.intersphinx', + #'sphinx.ext.ifconfig', + #'sphinx.ext.autosectionlabel', + #'sphinx_epytext', + 'sphinx.ext.autodoc', # Core library for html generation from docstrings + #'sphinx.ext.autosummary', # Create neat summary tables + 'sphinx_ext_autosummary_reworked', # Create neat summary tables + 'method_signal', ] -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ['templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] # -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. - -html_theme = 'sphinx_rtd_theme' # read-the-docs theme looks better than the default "classic" one but has bugs e.g. no table wrapping - -html_theme_options = { - 'display_version': True, - #'prev_next_buttons_location': 'bottom', - #'style_external_links': False, - #'vcs_pageview_mode': '', - #'style_nav_header_background': 'white', - # Toc options - 'collapse_navigation': True, - 'sticky_navigation': True, - #'navigation_depth': 4, - 'includehidden': True, - #'titles_only': False -} +# html_theme = 'alabaster' +# html_static_path = ['_static'] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['static'] html_css_files = [ # Workaround for RTD 0.4.3 bug https://github.com/readthedocs/sphinx_rtd_theme/issues/117 @@ -89,60 +67,68 @@ html_css_files = [ html_favicon = "https://ceccopierangiolieugenio.github.io/pyTermTk/sandbox/www/favicon.ico" +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-toc_object_entries_show_parents +# Use 'hide' to only show the name of the element without any parents (i.e. method()). +toc_object_entries_show_parents='hide' + +# read-the-docs theme looks better than the default "classic" one but has bugs e.g. no table wrapping +# html_theme = 'sphinx_rtd_theme' +# html_theme_options = { +# 'display_version': True, +# #'prev_next_buttons_location': 'bottom', +# #'style_external_links': False, +# #'vcs_pageview_mode': '', +# #'style_nav_header_background': 'white', +# # Toc options +# 'collapse_navigation': True, +# 'sticky_navigation': True, +# #'navigation_depth': 4, +# 'includehidden': True, +# #'titles_only': False +# 'flyout_display': 'attached', +# } + # html_theme = 'bizstyle' +# html_theme_options = { +# "sidebar_width": '240px', +# "stickysidebar": True, +# "stickysidebarscrollable": True, +# "contribute": True, +# "github_fork": "useblocks/groundwork", +# "github_user": "useblocks", +# } -#html_theme_options = { -# "sidebar_width": '240px', -# "stickysidebar": True, -# "stickysidebarscrollable": True, -# "contribute": True, -# "github_fork": "useblocks/groundwork", -# "github_user": "useblocks", -#} +# Nice theme but it does not allows full-width +# html_theme = 'furo' +# html_theme_options = {} +# html_theme = 'press' +# html_theme_options = {} -# import m2r -# -# def docstring(app, what, name, obj, options, lines): -# md = '\n'.join(lines) -# rst = m2r.convert(md) -# lines.clear() -# lines += rst.splitlines() -# -# def setup(app): -# app.connect('autodoc-process-docstring', docstring) +# html_theme = 'piccolo_theme' +# html_theme_options = {} -import TermTk +# extensions.append("sphinx_wagtail_theme") +# html_theme = 'sphinx_wagtail_theme' -add_module_names = False -autosummary_generate = True -autosummary_generate_overwrite = False - -autodocgen_config = { - 'modules':[TermTk], - 'generated_source_dir': os.path.abspath('.')+'/autogen.TermTk/', - #'add_module_names': False, - - # if module matches this then it and any of its submodules will be skipped - # 'skip_module_regex': '(.*[.]__|myskippedmodule)', - 'skip_module_regex': '(.*[.]__|myskippedmodule)', - - # produce a text file containing a list of everything documented. you can use this in a test to notice when you've - # intentionally added/removed/changed a documented API - 'write_documented_items_output_file': 'autodocgen_documented_items.txt', - - # customize autodoc on a per-module basis - # 'autodoc_options_decider': {}, - # 'autodoc_options_decider': {'members':True, 'inherited-members':True}, - # Can you believe I had to debug autodoc to figure out this FUCKING thing? - # People are complainig to the lack of documentation of pyTermTk - # but aat least i hacve examples that cover most use cases - 'autodoc_options_decider': lambda app, what, fullname, obj, docstring, defaultOptions, extra: {'members': True, 'inherited-members':True}, - - # choose a different title for specific modules, e.g. the toplevel one - #'module_title_decider': lambda modulename: 'API Reference' if modulename=='TermTk' else modulename, +# html_theme = 'sphinx_material' + +# html_permalinks_icon = '#' +# html_theme = 'sphinxawesome_theme' + +html_theme = 'sphinx_book_theme' +html_theme_options = { + "home_page_in_toc": True, + "use_fullscreen_button": True, + "show_toc_level": 2, + "repository_url": "https://github.com/ceccopierangiolieugenio/pyTermTk", } +add_module_names = True +autosummary_generate = True +autosummary_generate_overwrite = True +autosummary_imported_members = False + # autodoc_default_options = { 'inherited-members':True } autodoc_default_options = { 'exclude-members': ('as_integer_ratio , bit_count , bit_length , ' @@ -159,3 +145,14 @@ sys.modules['pyodide'] = pyodide class windll(): pass sys.modules['ctypes.windll'] = windll + + +def linkcode_resolve(domain, info): + if domain != 'py': + return None + if not info['module']: + return None + filename = info['module'].replace('.', '/') + # print(f"{domain=} {info=}") + # print(f"https://github.com/ceccopierangiolieugenio/pyTermTk/blob/main/{filename}.py") + return f"https://github.com/ceccopierangiolieugenio/pyTermTk/blob/main/{filename}.py" \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index dc35c336..f971788a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,8 +1,12 @@ .. pyTermTk documentation master file, created by - sphinx-quickstart on Fri Apr 2 12:13:00 2021. + sphinx-quickstart on Wed Oct 23 16:32:12 2024. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. Add your content using ``reStructuredText`` syntax. See the + https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html + documentation for details. + Welcome to pyTermTk_'s documentation! ===================================== @@ -76,34 +80,53 @@ Intro info/debug info/resources/index +.. currentmodule:: TermTk -.. toctree:: +.. autosummary:: :caption: API Reference - :maxdepth: 1 - :hidden: - - autogen.TermTk/TermTk.TTkAbstract - autogen.TermTk/TermTk.TTkCore - autogen.TermTk/TermTk.TTkCore.TTkTerm - autogen.TermTk/TermTk.TTkGui - autogen.TermTk/TermTk.TTkLayouts - autogen.TermTk/TermTk.TTkTemplates - autogen.TermTk/TermTk.TTkTestWidgets - autogen.TermTk/TermTk.TTkTheme - autogen.TermTk/TermTk.TTkTypes - autogen.TermTk/TermTk.TTkUiTools - autogen.TermTk/TermTk.TTkWidgets - autogen.TermTk/TermTk.TTkWidgets.TTkModelView - autogen.TermTk/TermTk.TTkWidgets.TTkPickers - autogen.TermTk/TermTk.TTkWidgets.TTkTerminal + :toctree: _autosummary + :template: custom-module-template.01.rst + :recursive: + + TTkCore + TTkLayouts + TTkAbstract + TTkWidgets.TTkModelView + + +| TermTk.TTkAbstract +| TermTk.TTkCore +| TermTk.TTkCore.TTkTerm +| TermTk.TTkGui +| TermTk.TTkLayouts +| TermTk.TTkTemplates +| TermTk.TTkTestWidgets +| TermTk.TTkTheme +| TermTk.TTkTypes +| TermTk.TTkUiTools +| TermTk.TTkWidgets +| TermTk.TTkWidgets.TTkModelView +| TermTk.TTkWidgets.TTkPickers +| TermTk.TTkWidgets.TTkTerminal + +| TTkAbstract +| TermTk.TTkCore +| TermTk.TTkCore.TTkTerm +| TermTk.TTkGui +| TermTk.TTkLayouts +| TermTk.TTkTemplates +| TermTk.TTkTestWidgets +| TermTk.TTkTheme +| TermTk.TTkTypes +| TermTk.TTkUiTools +| TermTk.TTkWidgets +| TermTk.TTkWidgets.TTkModelView +| TermTk.TTkWidgets.TTkPickers +| TermTk.TTkWidgets.TTkTerminal Indices and tables ================== * :ref:`genindex` * :ref:`modindex` -* :ref:`search` - - - - +* :ref:`search` \ No newline at end of file diff --git a/docs/source/info/installing.rst b/docs/source/info/installing.rst index d704b644..a668ccfe 100644 --- a/docs/source/info/installing.rst +++ b/docs/source/info/installing.rst @@ -95,9 +95,9 @@ Clone or `Download `_ (`tryItOnline `_) -* paint demo `paint.py `_ (`tryItOnline `_) -* ttkode prototype `ttkode.py `_ (`tryItOnline `_) +* Main demo `demo.py `_ (`tryItOnline `__) +* paint demo `paint.py `_ (`tryItOnline `__) +* ttkode prototype `ttkode.py `_ (`tryItOnline `__) .. code:: bash @@ -116,19 +116,19 @@ Showcase **Highlight:** -* Text Editor `textedit.py `_ (`tryItOnline `_) -* Animation `animation.01.py `_ (`tryItOnline `_) -* color picker `colorpicker.py `_ (`tryItOnline `_) -* file picker `filepicker.py `_ (`tryItOnline `_) -* drag & drop `dragndrop.py `_ (`tryItOnline `_) -* d&d with tabs `dndtabs.py `_ (`tryItOnline `_) -* d&d with list `list.py `_ (`tryItOnline `_) -* base widgets `formwidgets02.py `_ (`tryItOnline `_) -* messagebox `messagebox.py `_ (`tryItOnline `_) -* splitter `splitter.py `_ (`tryItOnline `_) -* Windows `windowsflags.py `_ (`tryItOnline `_) -* AppTemplate `apptemplate.py `_ (`tryItOnline `_) -* Tooltip `test.ui.026.toolTip.py `_ (`tryItOnline `_) +* Text Editor `textedit.py `_ (`tryItOnline `__) +* Animation `animation.01.py `_ (`tryItOnline `__) +* color picker `colorpicker.py `_ (`tryItOnline `__) +* file picker `filepicker.py `_ (`tryItOnline `__) +* drag & drop `dragndrop.py `_ (`tryItOnline `__) +* d&d with tabs `dndtabs.py `_ (`tryItOnline `__) +* d&d with list `list.py `_ (`tryItOnline `__) +* base widgets `formwidgets02.py `_ (`tryItOnline `__) +* messagebox `messagebox.py `_ (`tryItOnline `__) +* splitter `splitter.py `_ (`tryItOnline `__) +* Windows `windowsflags.py `_ (`tryItOnline `__) +* AppTemplate `apptemplate.py `_ (`tryItOnline `__) +* Tooltip `test.ui.026.toolTip.py `_ (`tryItOnline `__) .. code:: bash diff --git a/docs/source/make.bat b/docs/source/make.bat new file mode 100644 index 00000000..32bb2452 --- /dev/null +++ b/docs/source/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/sphinx_modules/method_signal.py b/docs/source/sphinx_modules/method_signal.py new file mode 100644 index 00000000..bb5c3e2b --- /dev/null +++ b/docs/source/sphinx_modules/method_signal.py @@ -0,0 +1,43 @@ +"""Sphinx extension to handle the signal directive in the method.""" + +__version__ = '2024.10' + +from typing import get_overloads +from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, cast + +from sphinx.util.inspect import signature, stringify_signature + +from sphinx import addnodes +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.domains.python import PyMethod, PyObject + +if True or TYPE_CHECKING: + from collections.abc import Sequence + + from docutils.nodes import Node, system_message + + from sphinx.application import Sphinx + from sphinx.extension import Extension + from sphinx.util.typing import ExtensionMetadata, OptionSpec + from sphinx.writers.html5 import HTML5Translator + + + +class TermTkMethod(PyMethod): + option_spec: ClassVar[OptionSpec] = PyMethod.option_spec.copy() + option_spec.update({ + 'signal': directives.flag, + }) + + def get_signature_prefix(self, sig: str) -> list[nodes.Node]: + prefix: list[nodes.Node] = super().get_signature_prefix(sig) + if 'signal' in self.options: + prefix.append(nodes.Text('signal')) + prefix.append(addnodes.desc_sig_space()) + return prefix + +def setup(app: Sphinx) -> ExtensionMetadata: + '''Initialise the extension.''' + + app.add_directive_to_domain("py", "method", TermTkMethod, override=True) diff --git a/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py new file mode 100644 index 00000000..79ee2ef9 --- /dev/null +++ b/docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py @@ -0,0 +1,229 @@ +"""Sphinx extension to handle the signal directive in the method.""" + +__version__ = '2024.10' + +import inspect +import ast +import sys +import types +import re +from typing import get_type_hints +from typing import get_overloads +from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, cast + +from sphinx.util.inspect import signature, stringify_signature + +from sphinx import addnodes +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.domains.python import PyMethod, PyObject + +if True or TYPE_CHECKING: + from collections.abc import Sequence + + from docutils.nodes import Node, system_message + + from sphinx.application import Sphinx + from sphinx.extension import Extension + from sphinx.util.typing import ExtensionMetadata, OptionSpec + from sphinx.writers.html5 import HTML5Translator + +import sphinx.ext.autosummary as seauto +import sphinx.ext.autosummary.generate as seautogenerate + +import TermTk as ttk + +import ast +import inspect + +# From +# https://stackoverflow.com/questions/3232024/introspection-to-get-decorator-names-on-a-method + +def get_decorators(cls): + target = cls + decorators = {} + + def visit_FunctionDef(node): + decorators[node.name] = [] + for n in node.decorator_list: + name = '' + if isinstance(n, ast.Call): + name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id + else: + name = n.attr if isinstance(n, ast.Attribute) else n.id + + decorators[node.name].append(name) + + node_iter = ast.NodeVisitor() + node_iter.visit_FunctionDef = visit_FunctionDef + node_iter.visit(ast.parse(inspect.getsource(target))) + return decorators + + +_styleMatch = re.compile('^ *classStyle') +_colorMatch = re.compile('^#[0-9a-fA-F]{6}') +def _get_classStyleCode(obj) -> list[str]: + ret = [] + curlyBraket = 0 + def _processLine(line): + cbRet = 0 + for i,ch in enumerate(line): + if ch=='#': + if not _colorMatch.match(line[i:]): + continue + if ch == '{': + cbRet+=1 + elif ch == '}': + cbRet-=1 + if cbRet == 0: + return cbRet + return cbRet + + for line in inspect.getsource(obj).split('\n'): + # print(line) + # print(f"{_styleMatch.match(line)=}") + if curlyBraket == 0 and _styleMatch.match(line): + print(line) + ret.append(line) + curlyBraket += _processLine(line) + elif curlyBraket > 0: + print(line) + ret.append(line) + curlyBraket += _processLine(line) + if curlyBraket == 0: + return ret + return ret + +def setup(app: Sphinx) -> ExtensionMetadata: + '''Initialise the extension.''' + + modules = {} + modSorted = {} + modSub = {} + modSubSorted = {} + modStyles = {} + def _parseModules(_mod): + if _file:=getattr(_mod,'__file__',None): + if '__init__.py' in _file and '/TermTk/' in _file: + print(_file) + for _name, _obj in inspect.getmembers(_mod): + if inspect.isclass(_obj): + if _name not in modStyles: + modStyles[_name] = _get_classStyleCode(_obj) + if _name not in modules: + modules[_name] = _mod.__name__ + modules[_name] = _mod.__name__ if len(_mod.__name__)>len(modules[_name]) else modules[_name] + print(f" * {_name=} = {_obj}") + + for _module in sys.modules: + _parseModules(sys.modules[_module]) + + for x in modules.items(): + print(x) + a,b = x + if b not in modSorted: + modSorted[b] = [] + modSorted[b].append(a) + + for (a,b) in modSorted.items(): + print(a) + modSub[a] = '.'.join(a.split('.')[:-1]) + for x in b: + print (f" - {x}") + + for x in modSub.items(): + print(x) + + for x in modSub.items(): + print(x) + a,b = x + if b not in modSubSorted: + modSubSorted[b] = [] + modSubSorted[b].append(a) + + for (a,b) in modSubSorted.items(): + print(a) + for x in b: + print (f" - {x}") + + # print(modStyles) + + # raise Exception + + def generate_autosummary_content( + name, obj, parent, template, template_name, imported_members, + app, recursive, context, modname, qualname, + generate_autosummary_content_old = seautogenerate.generate_autosummary_content + ) -> str: + print(f"-----------------> OVERRIDEEEEE!!! {type(context)}") + print(f"{name=}") + print(f"{obj=}") + print(f"{parent=}") + print(f"{template=}") + print(f"{template_name=}") + print(f"{imported_members=}") + print(f"{app=}") + print(f"{recursive=}") + print(f"{context=}") + print(f"{modname=}") + print(f"{qualname=}") + ttkSignals = [] + ttkSlots = [] + ttkMethods = [] + ttkInheritedMethods = [] + ttkSubClasses = modSorted.get(name,[]) + ttkSubModules = modSubSorted.get(name,[]) + + # ns['members'] = dir(obj) + # ns['inherited_members'] = set(dir(obj)) - set(obj.__dict__.keys()) + # ns['methods'], ns['all_methods'] = _get_members( + # doc, app, obj, {'method'}, include_public={'__init__'} + # ) + # ns['attributes'], ns['all_attributes'] = _get_members( + # doc, app, obj, {'attribute', 'property'} + # ) + + print(f"{obj=}") + # for member in inspect.getmembers(obj): + # _name = member[0] + # if _name.startswith('_'): continue + # _hint = get_type_hints(obj)[_name] + print(f"{obj=} - {get_type_hints(obj)=}") + for _name in (_th:=get_type_hints(obj)): + print(f"{_th=}") + if _name.startswith('_'): continue + if 'pyTTkSignal' in str(_th[_name]): + ttkSignals.append(_name) + else: + print(ttk.TTkString(f"element not typed: {_name} - { _th[_name]}",ttk.TTkColor.BG_CYAN)) + print(ttkSignals) + + def _hasmethod(obj, name): + return hasattr(obj, name) and type(getattr(obj, name)) in (types.MethodType, types.FunctionType) + + for _name in (_dec:=get_decorators(obj)): + if _name.startswith('_'): continue + if _hasmethod(obj,_name): + ttkMethods.append(_name) + for _decorator in _dec[_name]: + if "pyTTkSlot"in _decorator: + ttkSlots.append(_name) + break + + context |= { + 'TTkStyle':modStyles.get(qualname,''), + 'TTkSubClasses': ttkSubClasses, + 'TTkSubModules': ttkSubModules, + 'TTkMethods':ttkMethods, + 'TTkSignals':ttkSignals, + 'TTkSlots':ttkSlots} + + print('\n'.join([f" * {x}={context[x]}" for x in context])) + + return generate_autosummary_content_old( + name, obj, parent, template, template_name, imported_members, + app, recursive, context, modname, qualname) + + seautogenerate.generate_autosummary_content = generate_autosummary_content + + return seauto.setup(app) diff --git a/docs/source/sphinx_modules/test_01.py b/docs/source/sphinx_modules/test_01.py new file mode 100644 index 00000000..e8343416 --- /dev/null +++ b/docs/source/sphinx_modules/test_01.py @@ -0,0 +1,58 @@ +"""Sphinx extension to render inherited overloads with autodoc.""" + +__version__ = '2023.4' + +from typing import get_overloads +from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, cast + +from sphinx.util.inspect import signature, stringify_signature + +from sphinx import addnodes +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx.domains.python import PyMethod, PyObject + +if True or TYPE_CHECKING: + from collections.abc import Sequence + + from docutils.nodes import Node, system_message + + from sphinx.application import Sphinx + from sphinx.extension import Extension + from sphinx.util.typing import ExtensionMetadata, OptionSpec + from sphinx.writers.html5 import HTML5Translator + + +def test_process_signature(app, what, name, obj, options, sig, ret_ann): + '''Callback function to provide new signatures.''' + print(f"{app=}\n{what=}\n{name=}\n{obj=}\n{options=}\n{sig=}\n{ret_ann=}") + return '\n'.join(["a","b","c"]), "Pipppo Pippero" + +def test_process_docstring(app, what, name, obj, options, lines:list[str]): + '''Callback function to provide overloaded signatures.''' + print(f"{app=}\n{what=}\n{name=}\n{obj=}\n{options=}\n{lines=}") + for i,line in enumerate(lines): + lines[i] = line.replace("Table","PIPPO") + +class TermTkMethod(PyMethod): + option_spec: ClassVar[OptionSpec] = PyMethod.option_spec.copy() + option_spec.update({ + 'signal': directives.flag, + }) + + def get_signature_prefix(self, sig: str) -> list[nodes.Node]: + prefix: list[nodes.Node] = super().get_signature_prefix(sig) + if 'signal' in self.options: + prefix.append(nodes.Text('signal')) + prefix.append(addnodes.desc_sig_space()) + return prefix + +def setup(app: Sphinx) -> ExtensionMetadata: + '''Initialise the extension.''' + # from: + # https://smobsc.readthedocs.io/en/stable/usage/extensions/autodoc.html + # https://github.com/ntessore/autodoc_inherit_overload/blob/main/sphinxcontrib/autodoc_inherit_overload.py + # app.connect('autodoc-process-signature', test_process_signature) + # app.connect('autodoc-process-docstring', test_process_docstring) + + app.add_directive_to_domain("py", "method", TermTkMethod, override=True) diff --git a/docs/source/_static/theme_overrides.css b/docs/source/static/theme_overrides.css similarity index 82% rename from docs/source/_static/theme_overrides.css rename to docs/source/static/theme_overrides.css index dc8140ff..b8084ed1 100644 --- a/docs/source/_static/theme_overrides.css +++ b/docs/source/static/theme_overrides.css @@ -3,6 +3,17 @@ .wy-nav-content { max-width: none; } +/* Temporary workaround for the sphinxawesome theme */ +@media (min-width: 1400px) { + .container { + max-width: 1400px; + } + } + +/* Temporary workaround for the https://sphinx-themes.org/sample-sites/sphinx-book-theme/ theme */ +.bd-page-width { + max-width: none; +} /* Temporary workaround for RTD 0.4.3 bug https://github.com/readthedocs/sphinx_rtd_theme/issues/117 which will hopefully be fixed soon diff --git a/docs/source/_static/ttk.css b/docs/source/static/ttk.css similarity index 100% rename from docs/source/_static/ttk.css rename to docs/source/static/ttk.css diff --git a/docs/source/templates/autosummary/base.rst b/docs/source/templates/autosummary/base.rst new file mode 100644 index 00000000..b7556ebf --- /dev/null +++ b/docs/source/templates/autosummary/base.rst @@ -0,0 +1,5 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/source/templates/autosummary/class.rst b/docs/source/templates/autosummary/class.rst new file mode 100644 index 00000000..0f7d6f32 --- /dev/null +++ b/docs/source/templates/autosummary/class.rst @@ -0,0 +1,29 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + + {% block methods %} + .. automethod:: __init__ + + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + {% for item in methods %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block attributes %} + {% if attributes %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/source/templates/autosummary/module.rst b/docs/source/templates/autosummary/module.rst new file mode 100644 index 00000000..3ff0de9e --- /dev/null +++ b/docs/source/templates/autosummary/module.rst @@ -0,0 +1,60 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {%- if attributes %} + .. rubric:: {{ _('Module Attributes') }} + + .. autosummary:: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {%- endblock %} + + {%- block functions %} + {%- if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {%- endblock %} + + {%- block classes %} + {%- if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {%- endblock %} + + {%- block exceptions %} + {%- if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {%- endblock %} + +{%- block modules %} +{%- if modules %} +.. rubric:: Modules + +.. autosummary:: + :toctree: + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{%- endblock %} diff --git a/docs/source/templates/custom-class-template.01.rst b/docs/source/templates/custom-class-template.01.rst new file mode 100644 index 00000000..8525e596 --- /dev/null +++ b/docs/source/templates/custom-class-template.01.rst @@ -0,0 +1,60 @@ +{{ objname | escape | underline}} + +Pippo CUSTOM_CLASS_TEMPLATE.001 + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + + {% if TTkStyle %} + Style + ----- + + .. code-block:: python + + {% for line in TTkStyle %} + {{ line }} + {%- endfor %} + {% endif %} + + {% if TTkSignals %} + :ref:`Signals ` + --------------------------------- + + .. autosummary:: + {% for item in TTkSignals %} + {{ item }} + {%- endfor %} + {% endif %} + + {% if TTkSlots %} + :ref:`Slots ` + ------------------------------- + + .. autosummary:: + {% for item in TTkSlots %} + {{ item }} + {%- endfor %} + {% endif %} + + + {% if TTkSignals %} + + Members + ------- + + {% for item in TTkSignals %} + .. autoattribute:: {{ item }} + {%- endfor %} + {% endif %} + + {% if TTkMethods %} + + Methods + ------- + + {% for item in TTkMethods %} + .. automethod:: {{ item }} + {%- endfor %} + + {% endif %} diff --git a/docs/source/templates/custom-class-template.rst b/docs/source/templates/custom-class-template.rst new file mode 100644 index 00000000..1805c0d9 --- /dev/null +++ b/docs/source/templates/custom-class-template.rst @@ -0,0 +1,40 @@ +{{ fullname | escape | underline}} + +EugenioPOPOPPOPOPOPOPOPOPOP + + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :show-inheritance: + :inherited-members: + + POPOPPOPOPOPOPOPOPOP + + .. {% block methods %} + .. automethod:: __init__ + + POPOPPOPOPOPOPOPOPOP 2 + + + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + {% for item in methods %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block attributes %} + {% if attributes %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/source/templates/custom-module-template.01.rst b/docs/source/templates/custom-module-template.01.rst new file mode 100644 index 00000000..c37c9271 --- /dev/null +++ b/docs/source/templates/custom-module-template.01.rst @@ -0,0 +1,31 @@ +{{ fullname | escape | underline}} + +Pippo CUSTOM_MODULE_TEMPLATE.001 + +.. automodule:: {{ fullname }} + + {% if TTkSubClasses %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :caption: Classes: + :toctree: + :template: custom-class-template.01.rst + + {% for item in TTkSubClasses %} + {{ item }} + {%- endfor %} + {% endif %} + +{% if TTkSubModules %} +.. rubric:: Modules + +.. autosummary:: + :toctree: Modules: + :template: custom-module-template.01.rst + :recursive: + +{% for item in TTkSubModules %} + {{ item }} +{%- endfor %} +{% endif %} diff --git a/docs/source/templates/custom-module-template.rst b/docs/source/templates/custom-module-template.rst new file mode 100644 index 00000000..74078355 --- /dev/null +++ b/docs/source/templates/custom-module-template.rst @@ -0,0 +1,66 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Module Attributes + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :template: custom-class-template.rst + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} +{% if modules %} +.. rubric:: Modules + +.. autosummary:: + :toctree: + :template: custom-module-template.rst + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/docs/sphynx.001.signal.patch b/docs/sphynx.001.signal.patch index 77d848bd..a032ccd0 100644 --- a/docs/sphynx.001.signal.patch +++ b/docs/sphynx.001.signal.patch @@ -1,14 +1,14 @@ ---- .venv/lib/python3.X/site-packages/sphinx/domains/python.py 2022-03-08 11:00:06.152347159 +0000 -+++ .venv/lib/python3.X/site-packages/sphinx/domains/python.py 2022-03-08 11:03:07.292940495 +0000 -@@ -768,6 +768,7 @@ - - option_spec: OptionSpec = PyObject.option_spec.copy() +--- .venv/lib/python3.11/site-packages/sphinx/domains/python/__init__.py.old 2024-10-23 10:51:56.882646206 +0100 ++++ .venv/lib/python3.11/site-packages/sphinx/domains/python/__init__.py 2024-10-23 10:53:16.557626613 +0100 +@@ -204,6 +204,7 @@ + + option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy() option_spec.update({ + 'signal': directives.flag, 'abstractmethod': directives.flag, 'async': directives.flag, 'classmethod': directives.flag, -@@ -787,6 +788,9 @@ +@@ -219,6 +220,9 @@ if 'final' in self.options: prefix.append(nodes.Text('final')) prefix.append(addnodes.desc_sig_space()) diff --git a/tests/t.generic/test.classes.001.slots.typing.py b/tests/t.generic/test.classes.001.slots.typing.py new file mode 100644 index 00000000..c3bd31b3 --- /dev/null +++ b/tests/t.generic/test.classes.001.slots.typing.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# vim:ts=4:sw=4:fdm=indent:cc=79: + +# 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 os,sys +from typing import get_type_hints +import inspect + +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + +class A(): + __slots__ = ('a','b','c') + def __init__(self,a,b,c) -> None: + self.a=a + self.b=b + self.c=c + + def __str__(self) -> str: + return f"A: {id(self)} -> {self.a=}, {self.b=}, {self.c}" + self.c=c + +class B(): + __slots__ = ('a','b','c') + a:int + b:str + c:A + def __init__(self,a:int,b:str,c:A) -> None: + self.a=a + self.b=b + self.c=c + + def __str__(self) -> str: + return f"B: {id(self)} -> {self.a=}, {self.b=}, {self.c}" + +b1 = B(123,'Eugenio',A(1,2,3)) +b2 = B(456,'Parodi ',A(4,5,6)) +b3 = B(789,'Pappala',A(7,8,9)) + +tw = ttk.TTkTableWidget +tm = inspect.getmembers(ttk.TTkTableWidget) +th = get_type_hints(ttk.TTkTableWidget) +th = get_type_hints(ttk.TTkConstant) + +for i in th: + print(i) + +print(b1) +print(b2) +print(b3) +print(f"{B.a=}, {B.b=}, {B.c=}") +print(f"{A.a=}, {A.b=}, {A.c=}") +print(get_type_hints(B)) +print(get_type_hints(B)[B.c.__name__]) +print(get_type_hints(ttk.TTkTableWidget)[ttk.TTkTableWidget.cellChanged.__name__]) +print(get_type_hints(ttk.TTkTableWidget)) +print(inspect.getmembers(ttk.TTkTableWidget)) + +def template(func): + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + return wrapper + +baz = template +che = template + +import ast +import inspect + +# From +# https://stackoverflow.com/questions/3232024/introspection-to-get-decorator-names-on-a-method + +class Foo(object): + @baz + @che + def bar(self): + pass + +def get_decorators(cls): + target = cls + decorators = {} + + def visit_FunctionDef(node): + decorators[node.name] = [] + for n in node.decorator_list: + name = '' + if isinstance(n, ast.Call): + name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id + else: + name = n.attr if isinstance(n, ast.Attribute) else n.id + + decorators[node.name].append(name) + + node_iter = ast.NodeVisitor() + node_iter.visit_FunctionDef = visit_FunctionDef + node_iter.visit(ast.parse(inspect.getsource(target))) + return decorators + +print(inspect.getsource(Foo)) +print(get_decorators(Foo)) \ No newline at end of file diff --git a/tutorial/000-examples.rst b/tutorial/000-examples.rst index 6144aee7..f096879f 100644 --- a/tutorial/000-examples.rst +++ b/tutorial/000-examples.rst @@ -12,7 +12,7 @@ Init ---- `TTkLineEdit/Init.01.py `_ - -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -25,7 +25,7 @@ Set/Get Text ------------ `TTkLineEdit/SetGet.01.py `_ - -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -38,7 +38,7 @@ Events ------ `TTkLineEdit/SetGet.01.py `_ - -(`tryItOnline `_): +(`tryItOnline `__): TTkTerminal =========== @@ -58,37 +58,37 @@ TTkTable ======== `TTkTable/table.01.basic.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.02.custom.model.01.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.02.custom.model.02.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.02.custom.model.03.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.03.theming.color.01.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.03.theming.color.02.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.03.theming.color.03.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.03.theming.headers.01.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.03.theming.lines.01.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.04.methods.py `_ -(`tryItOnline `_): +(`tryItOnline `__): `TTkTable/table.05.events.py `_ -(`tryItOnline `_): +(`tryItOnline `__): TTkTextEdit =========== diff --git a/tutorial/001-helloworld.rst b/tutorial/001-helloworld.rst index e7fc630e..7bb1a491 100644 --- a/tutorial/001-helloworld.rst +++ b/tutorial/001-helloworld.rst @@ -24,7 +24,7 @@ Example 1 --------- Following is the code to execute `helloworld.001.py `_ -in pyTermTk_ (`tryItOnline `_): +in pyTermTk_ (`tryItOnline `__): .. code:: python @@ -44,7 +44,7 @@ Example 2 - Your first Window ----------------------------- Following is the code to execute `helloworld.002.py `_ -in pyTermTk_ (`tryItOnline `_): +in pyTermTk_ (`tryItOnline `__): .. code:: python diff --git a/tutorial/002-layout.rst b/tutorial/002-layout.rst index f13afb62..14b902b0 100644 --- a/tutorial/002-layout.rst +++ b/tutorial/002-layout.rst @@ -118,7 +118,7 @@ Examples 1 - Simple TTkLayout_ --------------------- -Following is the code to execute `Layout Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `Layout Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python @@ -153,7 +153,7 @@ The above code produces the following output: 2 - Simple TTkVBoxLayout_ ------------------------- -Following is the code to execute `VBox Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `VBox Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python @@ -199,7 +199,7 @@ The above code produces the following output: 3 - Simple TTkHBoxLayout_ ------------------------- -Following is the code to execute `HBox Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `HBox Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python @@ -246,7 +246,7 @@ The above code produces the following output 4 - Simple TTkGridLayout_ ------------------------- -Following is the code to execute `Grid Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `Grid Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python @@ -291,7 +291,7 @@ The above code produces the following output 5 - Nested Layouts ------------------ -Following is the code to execute `Nested Layouts Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `Nested Layouts Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python @@ -346,7 +346,7 @@ The above code produces the following output 6 - Rowspan/Colspan in Grid Layout ---------------------------------- -Following is the code to execute `row/colspan Example`_ in pyTermTk_ (`tryItOnline `_) +Following is the code to execute `row/colspan Example`_ in pyTermTk_ (`tryItOnline `__) .. code:: python diff --git a/tutorial/003-signalslots.rst b/tutorial/003-signalslots.rst index 8ccf71b0..e1df423a 100644 --- a/tutorial/003-signalslots.rst +++ b/tutorial/003-signalslots.rst @@ -53,7 +53,7 @@ Example 1 - basic signal slots ------------------------------ From `example1.basic.signalslots.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python @@ -108,7 +108,7 @@ Example 2 - Use widgets signals and slots ----------------------------------------- From `example2.widgets.signalslots.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python diff --git a/tutorial/004-logging.rst b/tutorial/004-logging.rst index 7185e9c2..9cf9d8ea 100644 --- a/tutorial/004-logging.rst +++ b/tutorial/004-logging.rst @@ -20,7 +20,7 @@ Example 1 - Log to file ----------------------- From `example1.logtofile.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python @@ -41,7 +41,7 @@ Example 2 - Log to stdout ------------------------- From `example2.logtostdout.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python @@ -61,7 +61,7 @@ Example 3 - custom logging -------------------------- From `example3.customlogging.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python @@ -92,7 +92,7 @@ Example 4 - Use TTkLogViewer_ widget -------------------------------------------------- From `example4.ttklogviewer.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: python diff --git a/tutorial/005-calculator.rst b/tutorial/005-calculator.rst index 525f2a03..175d7923 100644 --- a/tutorial/005-calculator.rst +++ b/tutorial/005-calculator.rst @@ -53,7 +53,7 @@ Initialize the window --------------------- From `calculator.001.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -83,7 +83,7 @@ Add all the widgets of calculator to it --------------------------------------- From `calculator.002.py `_ -(`tryItOnline `_): +(`tryItOnline `__): Based on the positions and sizes defined in the `design layout <#design>`_, I place all the widgets on the TTkGridLayout_ (**winLayout**) @@ -165,7 +165,7 @@ Numeric Button Events --------------------------------------- From `calculator.003.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -212,7 +212,7 @@ Operation and results events ---------------------------- From `calculator.004.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -256,7 +256,7 @@ Beware the Mystery Button ----------------------------------------- From `calculator.005.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash diff --git a/tutorial/ttkDesigner/textEdit/README.rst b/tutorial/ttkDesigner/textEdit/README.rst index 0236f5bf..0484acee 100644 --- a/tutorial/ttkDesigner/textEdit/README.rst +++ b/tutorial/ttkDesigner/textEdit/README.rst @@ -166,7 +166,7 @@ Preview and Quick Export controls="controls" muted="muted" class="d-block rounded-bottom-2 border-top width-fit" > Exported: `texteditor.01.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -187,7 +187,7 @@ Option 1) Include the Open/Save routine and link them to the widget Once (quick)exported the code, we need to define the appropriate routines and link them to the file(open/save) pickers `signals `__ `texteditor.02.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash @@ -228,7 +228,7 @@ Option 2) Extend a custom widget including the open/save methods ---------------------------------------------------------------- `texteditor.03.py `_ -(`tryItOnline `_): +(`tryItOnline `__): .. code:: bash