Browse Source

Improved the documentation

pull/278/head
Eugenio Parodi 1 year ago
parent
commit
96f8afc037
  1. 37
      TermTk/TTkCore/constant.py
  2. 11
      TermTk/TTkCore/ttk.py
  3. 56
      TermTk/TTkTemplates/keyevents.py
  4. 20
      TermTk/TTkTemplates/mouseevents.py
  5. 31
      TermTk/TTkWidgets/about.py
  6. 146
      TermTk/TTkWidgets/apptemplate.py
  7. 30
      TermTk/TTkWidgets/button.py
  8. 27
      TermTk/TTkWidgets/checkbox.py
  9. 139
      TermTk/TTkWidgets/combobox.py
  10. 196
      TermTk/TTkWidgets/container.py
  11. 318
      TermTk/TTkWidgets/widget.py
  12. 34
      docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py
  13. 29
      docs/source/templates/custom-class-template.01.rst
  14. 63
      tests/timeit/02.array.07.namedTuple.py
  15. 2
      tutorial/002-layout.rst

37
TermTk/TTkCore/constant.py

@ -42,12 +42,37 @@ class TTkConstant:
Background = ColorType.Background
Modifier = ColorType.Modifier
# Focus Policies
NoFocus = 0x0000
ClickFocus = 0x0001
WheelFocus = 0x0002
TabFocus = 0x0004
ParentFocus = 0x0101
class FocusPolicy(int):
'''
This Class type defines the various policies a widget
can have with respect to acquiring keyboard focus.
.. autosummary::
NoFocus
ClickFocus
WheelFocus
TabFocus
ParentFocus
'''
NoFocus = 0x0000
'''The widget does not accept focus.'''
ClickFocus = 0x0001
'''The widget accepts focus by clicking.'''
WheelFocus = 0x0002
'''The widget accepts focus by using the mouse wheel.'''
TabFocus = 0x0004
'''The widget accepts focus by tabbing.'''
ParentFocus = 0x0101
'''The parent widget forward the focus to this widget'''
StrongFocus = TabFocus | ClickFocus | 0x8
'''the widget accepts focus by both tabbing and clicking.'''
NoFocus = FocusPolicy.NoFocus
ClickFocus = FocusPolicy.ClickFocus
WheelFocus = FocusPolicy.WheelFocus
TabFocus = FocusPolicy.TabFocus
ParentFocus = FocusPolicy.ParentFocus
StrongFocus = FocusPolicy.StrongFocus
# positions
NONE = 0x0000

11
TermTk/TTkCore/ttk.py

@ -42,6 +42,7 @@ from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.timer import TTkTimer
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.shortcut import TTkShortcut
from TermTk.TTkWidgets.about import TTkAbout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
@ -369,3 +370,13 @@ class TTk(TTkContainer):
def isVisibleAndParent(self):
return self.isVisible()
@pyTTkSlot()
def aboutTermTk(self):
'''
Displays a simple message box about `pyTermTk <https://github.com/ceccopierangiolieugenio/pyTermTk>`__.
The message includes the version number of TermTk being used by the application.
This is useful for inclusion in the Help menu of an application, as shown in the Menus example.
'''
TTkHelper.overlay(None, TTkAbout(), 30,10)

56
TermTk/TTkTemplates/keyevents.py

@ -20,35 +20,37 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
class TKeyEvents():
def keyPressEvent(self, evt) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive key press events for the widget.
.. note:: Reimplement this function to handle this event
:param evt: The keyboard event
:type evt: :py:class:`TTkKeyEvent`
:return: **True** if the event has been handled
:rtype: bool
'''
return False
def keyReleaseEvent(self, evt) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive key release events for the widget.
.. note:: Reimplement this function to handle this event
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
:param evt: The keyboard event
:type evt: :py:class:`TTkKeyEvent`
:return: **True** if the event has been handled
:rtype: bool
'''
return False
class TKeyEvents():
# def keyPressEvent(self, evt:TTkKeyEvent) -> bool :
# '''
# This event handler, can be reimplemented in a subclass to receive key press events for the widget.
#
# .. note:: Reimplement this function to handle this event
#
# :param evt: The keyboard event
# :type evt: :py:class:`TTkKeyEvent`
#
# :return: **True** if the event has been handled
# :rtype: bool
# '''
# return False
# def keyReleaseEvent(self, evt:TTkKeyEvent) -> bool :
# '''
# This event handler, can be reimplemented in a subclass to receive key release events for the widget.
#
# .. note:: Reimplement this function to handle this event
#
# :param evt: The keyboard event
# :type evt: :py:class:`TTkKeyEvent`
#
# :return: **True** if the event has been handled
# :rtype: bool
# '''
# return False
def keyEvent(self, evt) -> bool :
def keyEvent(self, evt:TTkKeyEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive key events for the widget.

20
TermTk/TTkTemplates/mouseevents.py

@ -20,8 +20,10 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
class TMouseEvents():
def mouseTapEvent(self, evt) -> bool :
def mouseTapEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse click events for the widget.
@ -35,7 +37,7 @@ class TMouseEvents():
'''
return True
def mouseDoubleClickEvent(self, evt) -> bool :
def mouseDoubleClickEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse click events for the widget.
@ -49,7 +51,7 @@ class TMouseEvents():
'''
return False
def mouseMoveEvent(self, evt) -> bool :
def mouseMoveEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse move events for the widget.
@ -63,7 +65,7 @@ class TMouseEvents():
'''
return False
def mouseDragEvent(self, evt) -> bool :
def mouseDragEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse drag events for the widget.
@ -77,7 +79,7 @@ class TMouseEvents():
'''
return False
def mousePressEvent(self, evt) -> bool :
def mousePressEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse press events for the widget.
@ -91,7 +93,7 @@ class TMouseEvents():
'''
return False
def mouseReleaseEvent(self, evt) -> bool :
def mouseReleaseEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse release events for the widget.
@ -105,7 +107,7 @@ class TMouseEvents():
'''
return False
def wheelEvent(self, evt) -> bool :
def wheelEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse wheel events for the widget.
@ -119,7 +121,7 @@ class TMouseEvents():
'''
return False
def enterEvent(self, evt) -> bool :
def enterEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse enter events for the widget.
@ -133,7 +135,7 @@ class TMouseEvents():
'''
return self._processStyleEvent(self._S_HOVER)
def leaveEvent(self, evt) -> bool :
def leaveEvent(self, evt:TTkMouseEvent) -> bool :
'''
This event handler, can be reimplemented in a subclass to receive mouse leave events for the widget.

31
TermTk/TTkWidgets/about.py

@ -41,6 +41,37 @@ _peppered_image = TTkUtil.base64_deflate_2_obj(
"4Zf9GYaCzmMK1e6+dLH7AkxADRtZ3ojHUrmNqNtco9mqF7pzbppx0GQSQ3Op8FcJ2G5ltCNVLuI74ZeG5vr8rDHAaP/o5bQnnOawWcPyRePnp/8KRQkp")
class TTkAbout(TTkWindow):
'''
This is a basic window widget that displays a simple message box about TermTk.
The message includes the version number of TermTk being used by the application.
This is useful for inclusion in the Help menu of an application, as shown in the Menus example.
:py:class:`TTk` provides this functionality as a slot (:py:meth:`TTk.aboutTermTk`).
.. code-block:: python
import TermTk
root = TermTk.TTk()
TermTk.TTkAbout(parent=root)
root.mainloop()
.. code-block:: python
from TermTk import TTk, TTkButton
root = TTk()
btn = TTkButton(parent=root, size=(15,3), border=True, text="About!!!")
btn.clicked.connect(root.aboutTermTk)
root.mainloop()
'''
peppered=[
[(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x01,0x00),(0x39,0x61,0x00),(0x76,0x9e,0x17),(0x87,0x9f,0x3a),(0x3d,0x4c,0x14),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00)],
[(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x02,0x11,0x00),(0x21,0x44,0x01),(0x99,0xc1,0x33),(0x4e,0x71,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00),(0x00,0x00,0x00)],

146
TermTk/TTkWidgets/apptemplate.py

@ -23,11 +23,12 @@
__all__ = ['TTkAppTemplate']
from dataclasses import dataclass
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkLayouts import TTkLayout, TTkGridLayout
from TermTk.TTkWidgets.container import TTkWidget, TTkContainer
from TermTk.TTkWidgets.menubar import TTkMenuBarLayout
@ -55,14 +56,52 @@ class TTkAppTemplate(TTkContainer):
R L
'''
MAIN = TTkK.CENTER
TOP = TTkK.TOP
BOTTOM = TTkK.BOTTOM
LEFT = TTkK.LEFT
RIGHT = TTkK.RIGHT
CENTER = TTkK.CENTER
HEADER = TTkK.HEADER
FOOTER = TTkK.FOOTER
class Position(int):
''' This Class enumerate the different panels available in the layout of :py:class:`TTkAppTemplate`
.. autosummary::
MAIN
TOP
BOTTOM
LEFT
RIGHT
CENTER
HEADER
FOOTER
'''
MAIN = TTkK.CENTER
'''Main'''
TOP = TTkK.TOP
'''Top'''
BOTTOM = TTkK.BOTTOM
'''Bottom'''
LEFT = TTkK.LEFT
'''Left'''
RIGHT = TTkK.RIGHT
'''Right'''
CENTER = TTkK.CENTER
'''Center'''
HEADER = TTkK.HEADER
'''Header'''
FOOTER = TTkK.FOOTER
'''Footer'''
MAIN = Position.MAIN
''':py:class:`Position.MAIN`'''
TOP = Position.TOP
''':py:class:`Position.TOP`'''
BOTTOM = Position.BOTTOM
''':py:class:`Position.BOTTOM`'''
LEFT = Position.LEFT
''':py:class:`Position.LEFT`'''
RIGHT = Position.RIGHT
''':py:class:`Position.RIGHT`'''
CENTER = Position.CENTER
''':py:class:`Position.CENTER`'''
HEADER = Position.HEADER
''':py:class:`Position.HEADER`'''
FOOTER = Position.FOOTER
''':py:class:`Position.FOOTER`'''
@dataclass(frozen=False)
class _Panel:
@ -162,7 +201,26 @@ class TTkAppTemplate(TTkContainer):
self._updateGeometries(force=True)
self.setFocusPolicy(TTkK.ClickFocus)
def setWidget(self, widget, position=MAIN, size=None, title="", border=None, fixed=None):
def setWidget(self,
widget:TTkWidget, position:Position=Position.MAIN,
size:int=None, title:TTkString="",
border:bool=None, fixed:bool=None) -> None:
'''
Place the :py:class:`TTkWidget` in the :py:class:`TTkAppTemplate`'s panel identified by its :py:class:`Position`
:param widget:
:type widget: :py:class:`TTkWidget`
:param position: defaults to :py:class:`Position.MAIN`
:type position: :py:class:`Position`, optional
:param size: defaults to None
:type size: int, optional
:param title: defaults to ""
:type title: :py:class:`TTkString`, optional
:param border: defaults to True
:type border: bool, optional
:param fixed: defaults to False
:type fixed: bool, optional
'''
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
if wid:=self._panels[position].widget:
@ -184,7 +242,26 @@ class TTkAppTemplate(TTkContainer):
widget.minimumHeight() )
self._updateGeometries(force=True)
def setItem(self, item, position=MAIN, size=None, title="", border=None, fixed=None):
def setItem(self,
item:TTkLayout, position:Position=Position.MAIN,
size:int=None, title:TTkString="",
border:bool=None, fixed:bool=None) -> None:
'''
Place the :py:class:`TTkLayout` in the :py:class:`TTkAppTemplate`'s panel identified by its :py:class:`Position`
:param item:
:type item: :py:class:`TTkLayout`
:param position: defaults to :py:class:`Position.MAIN`
:type position: :py:class:`Position`, optional
:param size: defaults to None
:type size: int, optional
:param title: defaults to ""
:type title: :py:class:`TTkString`, optional
:param border: defaults to True
:type border: bool, optional
:param fixed: defaults to False
:type fixed: bool, optional
'''
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
if wid:=self._panels[position].widget:
@ -206,15 +283,28 @@ class TTkAppTemplate(TTkContainer):
item.minimumHeight() )
self._updateGeometries(force=True)
def setTitle(self, position=MAIN, title=""):
def setTitle(self, position:Position=Position.MAIN, title:str=""):
'''Set the title of the panel identified by the "position"
:param position: defaults to :py:class:`Position.MAIN`
:type position: :py:class:`Position`, optional
:param title: defaults to ""
:type title: :py:class:`TTkString`, optional
'''
if not self._panels[position]: return
self._panels[position].title = TTkString(title) if title else ""
self._updateGeometries(force=True)
def menuBar(self, position=MAIN):
def menuBar(self, position:Position=MAIN) -> TTkMenuBarLayout:
'''
Retrieve the :py:class:`TTkMenuBarLayout` in the panel identified by the position.
:param position: defaults to :py:class:`Position.MAIN`
:type position: :py:class:`Position`, optional
'''
return None if not self._panels[position] else self._panels[position].menubar
def setMenuBar(self, menuBar, position=MAIN):
def setMenuBar(self, menuBar:TTkMenuBarLayout, position:Position=MAIN) -> None:
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
p = self._panels[position]
@ -226,31 +316,31 @@ class TTkAppTemplate(TTkContainer):
self.rootLayout().addItem(p.menubar)
self._updateGeometries(force=True)
def setBorder(self, border=True, position=MAIN):
def setBorder(self, border=True, position=MAIN) -> None:
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
self._panels[position].border = border
self._updateGeometries(force=True)
def setFixed(self, fixed=False, position=MAIN):
def setFixed(self, fixed=False, position=MAIN) -> None:
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
self._panels[position].fixed = fixed
self._updateGeometries(force=True)
def resizeEvent(self, w, h):
def resizeEvent(self, width: int, height: int) -> None:
self._updateGeometries()
def focusOutEvent(self):
def focusOutEvent(self) -> None:
self._selected = None
self.update()
def mouseReleaseEvent(self, evt):
def mouseReleaseEvent(self, evt: TTkMouseEvent) -> bool:
self._selected = None
self.update()
return True
def mousePressEvent(self, evt):
def mousePressEvent(self, evt: TTkMouseEvent) -> bool:
self._selected = []
self._updateGeometries()
spl = self._splitters
@ -263,7 +353,7 @@ class TTkAppTemplate(TTkContainer):
self._selected.append(loc)
return True
def mouseDragEvent(self, evt):
def mouseDragEvent(self, evt: TTkMouseEvent) -> bool:
if not self._selected: return False
pns = self._panels
for loc in self._selected:
@ -279,7 +369,7 @@ class TTkAppTemplate(TTkContainer):
self._updateGeometries()
return True
def minimumWidth(self):
def minimumWidth(self) -> int:
pns = self._panels
# Header and Footer sizes
@ -301,7 +391,7 @@ class TTkAppTemplate(TTkContainer):
return max(mh, mf, mcr+mcl+max(mct, mcb, mcm)) + (2 if p.border else 0)
def maximumWidth(self):
def maximumWidth(self) -> int:
pns = self._panels
# Header and Footer sizes
@ -323,7 +413,7 @@ class TTkAppTemplate(TTkContainer):
return min(mh, mf, mcr+mcl+min(mct, mcb, mcm)) + (2 if p.border else 0)
def minimumHeight(self):
def minimumHeight(self) -> int:
pns = self._panels
# Retrieve all the panels parameters and hide the menubar if required
@ -352,7 +442,7 @@ class TTkAppTemplate(TTkContainer):
return mh+mf+max(mr ,ml, mm+mt+mb ) + ( 2 if bm else 0 )
def maximumHeight(self):
def maximumHeight(self) -> int:
pns = self._panels
# Retrieve all the panels parameters and hide the menubar if required
@ -386,7 +476,7 @@ class TTkAppTemplate(TTkContainer):
return mh+mf+min(mr ,ml, mm+mt+mb ) + ( 2 if bm else 0 )
def _updateGeometries(self, force=False):
def _updateGeometries(self, force:bool=False) -> None:
w,h = self.size()
if w<=0 or h<=0 or (not force and not self.isVisibleAndParent()): return
pns = self._panels
@ -513,7 +603,7 @@ class TTkAppTemplate(TTkContainer):
self.update()
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False):
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False) -> None:
if updateLayout:
self._updateGeometries()
super().update(repaint=repaint,updateLayout=updateLayout,updateParent=updateParent)
@ -524,7 +614,7 @@ class TTkAppTemplate(TTkContainer):
#def setLayout(self, layout):
# self._panels[TTkAppTemplate.MAIN].item = layout
def paintEvent(self, canvas: TTkCanvas):
def paintEvent(self, canvas: TTkCanvas) -> None:
w,h = self.size()
pns = self._panels
spl = self._splitters

30
TermTk/TTkWidgets/button.py

@ -27,6 +27,9 @@ from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.signal import pyTTkSignal
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkWidgets.widget import TTkWidget
class TTkButton(TTkWidget):
@ -144,17 +147,21 @@ class TTkButton(TTkWidget):
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus)
def border(self):
def border(self) -> bool:
''' This property holds whether the button has a border
:return: bool
'''
return self._border
def isCheckable(self):
def isCheckable(self) -> bool:
''' This property holds whether the button is checkable
:return: bool
'''
return self._checkable
def setCheckable(self, ch):
def setCheckable(self, ch:bool) -> None:
''' Enable/Disable the checkable property
:param ch: Checkable
@ -163,7 +170,7 @@ class TTkButton(TTkWidget):
self._checkable = ch
self.update()
def isChecked(self):
def isChecked(self) -> bool:
''' This property holds whether the button is checked
Only checkable buttons can be checked. By default, the button is unchecked.
@ -172,7 +179,7 @@ class TTkButton(TTkWidget):
'''
return self._checked
def setChecked(self, ch):
def setChecked(self, ch:bool) -> None:
''' Set the checked status
:param ch: Checked
@ -182,14 +189,14 @@ class TTkButton(TTkWidget):
self.toggled.emit(self._checked)
self.update()
def text(self):
def text(self) -> TTkString:
''' This property holds the text shown on the button
:return: :py:class:`TTkString`
'''
return TTkString('\n').join(self._text)
def setText(self, text):
def setText(self, text:TTkString) -> None:
''' This property holds the text shown on the button
:param text:
@ -205,12 +212,13 @@ class TTkButton(TTkWidget):
self.setMaximumHeight(len(self._text))
self.update()
def mousePressEvent(self, evt):
def mousePressEvent(self, evt: TTkMouseEvent) -> bool:
# TTkLog.debug(f"{self._text} Test Mouse {evt}")
self.update()
return True
def mouseReleaseEvent(self, evt):
def mouseReleaseEvent(self, evt: TTkMouseEvent) -> bool:
# TTkLog.debug(f"{self._text} Test Mouse {evt}")
if self._checkable:
self._checked = not self._checked
@ -219,7 +227,7 @@ class TTkButton(TTkWidget):
self.clicked.emit()
return True
def keyEvent(self, evt):
def keyEvent(self, evt: TTkKeyEvent) -> bool:
if ( evt.type == TTkK.Character and evt.key==" " ) or \
( evt.type == TTkK.SpecialKey and evt.key == TTkK.Key_Enter ):
if self._checkable:
@ -230,7 +238,7 @@ class TTkButton(TTkWidget):
return True
return False
def paintEvent(self, canvas):
def paintEvent(self, canvas: TTkCanvas) -> None:
if self.isEnabled() and self._checkable:
if self._checked:
style = self.style()['checked']

27
TermTk/TTkWidgets/checkbox.py

@ -25,8 +25,11 @@ __all__ = ['TTkCheckbox']
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkWidgets.widget import *
class TTkCheckbox(TTkWidget):
@ -112,7 +115,7 @@ class TTkCheckbox(TTkWidget):
self.setMaximumHeight(1)
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus)
def text(self):
def text(self) -> TTkString:
''' This property holds the text shown on the checkhox
:return: :py:class:`TTkString`
@ -120,7 +123,7 @@ class TTkCheckbox(TTkWidget):
return self._text
pyTTkSlot(str)
def setText(self, text):
def setText(self, text:TTkString) -> None:
''' This property holds the text shown on the checkhox
:param text:
@ -131,14 +134,14 @@ class TTkCheckbox(TTkWidget):
self.setMinimumSize(3 + len(self._text), 1)
self.update()
def isTristate(self):
def isTristate(self) -> bool:
''' This property holds whether the checkbox is a tri-state checkbox
:return: bool
'''
return self._tristate
def setTristate(self, tristate):
def setTristate(self, tristate:bool):
''' Enable/Disable the tristate property
:param tristate:
@ -148,7 +151,7 @@ class TTkCheckbox(TTkWidget):
self._tristate = tristate
self.update()
def isChecked(self):
def isChecked(self) -> bool:
''' This property holds whether the checkbox is checked
:return: bool - True if :py:class:`~TermTk.TTkCore.constant.TTkConstant.CheckState.Checked` or :py:class:`~TermTk.TTkCore.constant.TTkConstant.CheckState.PartiallyChecked`
@ -156,7 +159,7 @@ class TTkCheckbox(TTkWidget):
return self._checkStatus != TTkK.Unchecked
@pyTTkSlot(bool)
def setChecked(self, state):
def setChecked(self, state:bool) -> None:
''' Set the check status
:param state:
@ -164,7 +167,7 @@ class TTkCheckbox(TTkWidget):
'''
self.setCheckState(TTkK.Checked if state else TTkK.Unchecked)
def checkState(self):
def checkState(self) -> TTkK.CheckState:
''' Retrieve the state of the checkbox
:return: :py:class:`TTkConstant.CheckState` : the checkbox status
@ -172,7 +175,7 @@ class TTkCheckbox(TTkWidget):
return self._checkStatus
@pyTTkSlot(TTkK.CheckState)
def setCheckState(self, state):
def setCheckState(self, state:TTkK.CheckState) -> None:
''' Sets the checkbox's check state.
:param state: state of the checkbox
@ -183,7 +186,7 @@ class TTkCheckbox(TTkWidget):
self._checkStatus = state
self.update()
def paintEvent(self, canvas):
def paintEvent(self, canvas: TTkCanvas) -> None:
style = self.currentStyle()
borderColor = style['borderColor']
@ -198,7 +201,7 @@ class TTkCheckbox(TTkWidget):
TTkK.PartiallyChecked: "/"}.get(self._checkStatus, " ")
canvas.drawText(pos=(1,0), color=xColor ,text=text)
def _pressEvent(self):
def _pressEvent(self) -> bool:
self._checkStatus = {
TTkK.Unchecked: TTkK.PartiallyChecked,
TTkK.PartiallyChecked: TTkK.Checked,
@ -212,11 +215,11 @@ class TTkCheckbox(TTkWidget):
self.update()
return True
def mousePressEvent(self, evt):
def mousePressEvent(self, evt: TTkMouseEvent) -> bool:
self._pressEvent()
return True
def keyEvent(self, evt):
def keyEvent(self, evt: TTkKeyEvent) -> bool:
if ( evt.type == TTkK.Character and evt.key==" " ) or \
( evt.type == TTkK.SpecialKey and evt.key == TTkK.Key_Enter ):
self._pressEvent()

139
TermTk/TTkWidgets/combobox.py

@ -29,6 +29,9 @@ from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
@ -92,7 +95,7 @@ class TTkComboBox(TTkContainer):
self.setMinimumSize(5, 1)
self.setMaximumHeight(1)
def _lineEditChanged(self):
def _lineEditChanged(self) -> None:
text = self._lineEdit.text()
self._id=-1
if text in self._list:
@ -119,14 +122,14 @@ class TTkComboBox(TTkContainer):
self.currentTextChanged.emit(text)
self.editTextChanged.emit(text)
def textAlign(self):
def textAlign(self) -> TTkK.Alignment:
'''his property holds the displayed text alignment
:return: :py:class:`TTkConstant.Alignment`
'''
return self._textAlign
def setTextAlign(self, align):
def setTextAlign(self, align:TTkK.Alignment) -> None:
'''This property holds the displayed text alignment
:param align:
@ -136,35 +139,50 @@ class TTkComboBox(TTkContainer):
self._textAlign = align
self.update()
def addItem(self, text, userData=None):
'''addItem
def addItem(self, text:TTkString):
'''
Adds an item to the combobox with the given text.
The item is appended to the list of existing items.
Adds an item to the combobox with the given text, and containing the specified userData (stored in the Qt::UserRole). The item is appended to the list of existing items.
:param text:
:type text: :py:class:`TTkString`
'''
self._list.append(text)
self.update()
def addItems(self,items):
'''addItems'''
def addItems(self, items:list[TTkString]) -> None:
'''
Adds a list of items to the combobox with the given text.
The items are appended to the list of existing items.
:param items:
:type items: list[:py:class:`TTkString`]
'''
for item in items:
self.addItem(item)
pyTTkSlot()
def clear(self):
'''clear'''
def clear(self) -> None:
'''Remove all the items.'''
self._lineEdit.setText("")
self._list = []
self._id = -1
self.update()
def lineEdit(self):
def lineEdit(self) -> TTkLineEdit|None:
'''
Returns the :py:class:`TTkLineEdit` widget used if the editable flag is enabled
:return: :py:class:`TTkLineEdit`
'''
return self._lineEdit if self._editable else None
def resizeEvent(self, w: int, h: int):
w,h = self.size()
self._lineEdit.setGeometry(1,0,w-4,h)
def resizeEvent(self, width: int, height: int) -> None:
self._lineEdit.setGeometry(1,0,width-4,height)
def paintEvent(self, canvas):
def paintEvent(self, canvas: TTkCanvas) -> None:
style = self.currentStyle()
color = style['color']
@ -183,21 +201,34 @@ class TTkComboBox(TTkContainer):
else:
canvas.drawText(pos=(w-2,0), text="^]", color=borderColor)
def currentText(self):
'''currentText'''
def currentText(self) -> TTkString:
'''
Returns the selected text
:return: :py:class:`TTkString`
'''
if self._editable:
return self._lineEdit.text()
elif self._id >= 0:
return self._list[self._id]
return ""
def currentIndex(self):
'''currentIndex'''
def currentIndex(self) -> int:
'''
Return the current seleccted index.
:return: int
'''
return self._id
@pyTTkSlot(int)
def setCurrentIndex(self, index):
'''setCurrentIndex'''
def setCurrentIndex(self, index:int) -> None:
'''
Set the selected index
:param index:
:type index: int
'''
if index < 0: return
if index > len(self._list)-1: return
if self._id == index: return
@ -210,8 +241,13 @@ class TTkComboBox(TTkContainer):
self.update()
@pyTTkSlot(str)
def setCurrentText(self, text):
'''setCurrentText'''
def setCurrentText(self, text:TTkString) -> None:
'''
Set the selected Text
:param text:
:type text: :py:class:`TTkString`
'''
if self._editable:
self.setEditText(text)
else:
@ -222,25 +258,48 @@ class TTkComboBox(TTkContainer):
self.setCurrentIndex(id)
@pyTTkSlot(str)
def setEditText(self, text):
'''setEditText'''
def setEditText(self, text:TTkString) -> None:
'''
Set the text in the :py:class:`TTkLineEdit` widget
:param text:
:type text: :py:class:`TTkString`
'''
if self._editable:
self._lineEdit.setText(text)
def insertPolicy(self):
'''insertPolicy'''
def insertPolicy(self) -> TTkK.InsertPolicy:
'''
Retrieve the insert policy used when a new item is added if the combobox editable flag is true.
:return: :py:class:`TTkK.InsertPolicy`
'''
return self._insertPolicy
def setInsertPolicy(self, ip):
'''setInsertPolicy'''
self._insertPolicy = ip
def setInsertPolicy(self, policy:TTkK.InsertPolicy) -> None:
'''
Define the insert policy used when a new item is inserted when the widget is editable.
:param policy:
:type policy: :py:class:`TTkK.InsertPolicy`
'''
self._insertPolicy = policy
def isEditable(self) -> bool:
'''
This field holds the editable status of this widget.
def isEditable(self):
'''isEditable'''
:return: bool
'''
return self._editable
def setEditable(self, editable):
'''setEditable'''
def setEditable(self, editable:bool) -> None:
'''
Set the editable status of this widget.
:param editable:
:type editable: bool
'''
self._editable = editable
if editable:
self._lineEdit.show()
@ -250,7 +309,7 @@ class TTkComboBox(TTkContainer):
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus)
@pyTTkSlot(str)
def _callback(self, label):
def _callback(self, label:TTkString) -> None:
if self._editable:
self._lineEdit.setText(label)
self.setCurrentIndex(self._list.index(label))
@ -259,7 +318,7 @@ class TTkComboBox(TTkContainer):
self.setFocus()
self.update()
def _pressEvent(self):
def _pressEvent(self) -> bool:
frameHeight = len(self._list) + 2
frameWidth = self.width()
if frameHeight > 20: frameHeight = 20
@ -278,24 +337,24 @@ class TTkComboBox(TTkContainer):
self.update()
return True
def wheelEvent(self, evt):
def wheelEvent(self, evt: TTkMouseEvent) -> bool:
if evt.evt == TTkK.WHEEL_Up:
self.setCurrentIndex(self._id-1)
else:
self.setCurrentIndex(self._id+1)
return True
def mousePressEvent(self, evt):
def mousePressEvent(self, evt: TTkMouseEvent) -> bool:
self._pressEvent()
return True
def keyEvent(self, evt):
def keyEvent(self, evt: TTkKeyEvent) -> bool:
if ( evt.type == TTkK.Character and evt.key==" " ) or \
( evt.type == TTkK.SpecialKey and evt.key in [TTkK.Key_Enter,TTkK.Key_Down] ):
self._pressEvent()
return True
return False
def focusInEvent(self):
def focusInEvent(self) -> None:
if self._editable:
self._lineEdit.setFocus()

196
TermTk/TTkWidgets/container.py

@ -20,44 +20,99 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkContainer']
__all__ = ['TTkContainer', 'TTkPadding']
from typing import NamedTuple
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkLayouts.layout import TTkLayout
from TermTk.TTkWidgets.widget import TTkWidget
class TTkPadding(NamedTuple):
top : int = 0
bottom : int = 0
left : int = 0
right : int = 0
class TTkContainer(TTkWidget):
''' TTkContainer Layout sizes:
'''
:py:class:`TTkContainer` include the layout management through :py:class:`TTkLayout` or one of its implementations.
It is the base class of all the composite widgets like :py:class:`TTkSpinBox`
where a :py:class:`TTkLineEdit` is placed and shown when edited, or in the :py:class:`TTkFrame` and
its extension :py:class:`TTkWindow` where the :py:class:`TTkLayout` is used for the child
widgets placements or the :py:class:`TTkMenuBarLayout`,
the main root widget :py:class:`TTk` inherit the layout capabilities of :py:class:`TTkContainer` for any widget placed in the `pyTermTk <https://github.com/ceccopierangiolieugenio/pyTermTk>`__ app.
Main widgets subclassing :py:class:`TTkContainer`:
#. :py:class:`TTk`
#. :py:class:`TTkFrame`
#. :py:class:`TTkWindow`
#. :py:class:`TTkSplitter`
#. :py:class:`TTkAppTemplate`
#. :py:class:`TTkTabWidget`
#. :py:class:`TTkTreeWidget`
More info and examples are available in the :ref:`Tutorial <Layout-Tutorial_Intro>`
.. _Container-Layout-Topology:
:py:class:`TTkContainer` Layout topology:
::
Terminal area (i.e. XTerm) = TTk
TTkContainer width
(x,y)
padt (Top Padding)
height
padl Layout/child padr
padb (Bottom Pad.)
:param bool forwardStyle: any change of style will reflect the children, defaults to False
:type forwardStyle: bool
TTkContainer
< -------- width ----->
(x,y) ^
padt (Top Padding) |
| height
padl Layout padr |
|
padb (Bottom Pad.) |
v
Example:
.. code-block:: python
:param int padding: the padding (top, bottom, left, right) of the widget, defaults to 0
:param int paddingTop: the Top padding, override Top padding if already defined, optional, default=padding
:param int paddingBottom: the Bottom padding, override Bottom padding if already defined, optional, default=padding
:param int paddingLeft: the Left padding, override Left padding if already defined, optional, default=padding
:param int paddingRight: the Right padding, override Right padding if already defined, optional, default=padding
from TermTk import TTk, TTkButton, TTkHBoxLayout
# The class TTk, that could be referred as the terminal layout, is a subclass of TTkContainer
root = TTk( layout=TTkHBoxLayout(), padding=(1,2,4,8))
TTkButton(parent=root, border=True, text="Btn 1!")
TTkButton(parent=root, border=True, text="Btn 2!")
TTkButton(parent=root, border=True, text="Btn 3!")
TTkButton(parent=root, border=True, text="Btn 4!")
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__ = (
@ -65,29 +120,28 @@ class TTkContainer(TTkWidget):
'_forwardStyle',
'_layout')
def __init__(self, *, padding=(0,0,0,0), forwardStyle=False,**kwargs):
def __init__(self, *, layout:TTkLayout=None, padding:TTkPadding=(0,0,0,0), forwardStyle=False, **kwargs):
self._forwardStyle = forwardStyle
padding = kwargs.get('padding', 0 )
self._padt = kwargs.get('paddingTop', padding )
self._padb = kwargs.get('paddingBottom', padding )
self._padl = kwargs.get('paddingLeft', padding )
self._padr = kwargs.get('paddingRight', padding )
self._padt = kwargs.get('paddingTop', padding[0] )
self._padb = kwargs.get('paddingBottom', padding[1] )
self._padl = kwargs.get('paddingLeft', padding[2] )
self._padr = kwargs.get('paddingRight', padding[3] )
self._layout = TTkLayout() # root layout
self._layout.addItem(kwargs.get('layout',TTkLayout())) # main layout
self._layout.addItem(layout if layout else TTkLayout()) # main layout
super().__init__(**kwargs)
self._layout.setParent(self)
self.update(updateLayout=True)
def addWidget(self, widget):
def addWidget(self, widget:TTkWidget) -> None:
'''
.. warning::
Method Deprecated,
use :py:class:`TTkWidget` -> :py:class:`TTkWidget.layout` -> :py:class:`TTkLayout.addWidget`
use :py:class:`TTkContainer` -> :py:meth:`layout` -> :py:class:`TTkLayout.addWidget`
i.e.
@ -98,12 +152,12 @@ class TTkContainer(TTkWidget):
TTkLog.error("<TTkWidget>.addWidget(...) is deprecated, use <TTkWidget>.layout().addWidget(...)")
if self.layout(): self.layout().addWidget(widget)
def removeWidget(self, widget):
def removeWidget(self, widget:TTkWidget) -> None:
'''
.. warning::
Method Deprecated,
use :py:class:`TTkWidget` -> :py:class:`TTkWidget.layout` -> :py:class:`TTkLayout.removeWidget`
use :py:class:`TTkContainer` -> :py:meth:`layout` -> :py:class:`TTkLayout.removeWidget`
i.e.
@ -118,7 +172,7 @@ class TTkContainer(TTkWidget):
# widget._currentStyle |= self._currentStyle
# widget.update()
def _processForwardStyle(self):
def _processForwardStyle(self) -> None:
if not self._forwardStyle: return
def _getChildren():
for w in self.rootLayout().iterWidgets(onlyVisible=True, recurse=False):
@ -131,7 +185,7 @@ class TTkContainer(TTkWidget):
if issubclass(type(w),TTkContainer):
w._processForwardStyle()
def setCurrentStyle(self, *args, **kwargs):
def setCurrentStyle(self, *args, **kwargs) -> None:
super().setCurrentStyle(*args, **kwargs)
self._processForwardStyle()
@ -167,19 +221,19 @@ class TTkContainer(TTkWidget):
bh = min(iy+ih,ly+lh)-by
TTkContainer._paintChildCanvas(canvas, child, (bx,by,bw,bh), (ix+iox,iy+ioy))
def paintChildCanvas(self):
def paintChildCanvas(self) -> None:
''' .. caution:: Don't touch this! '''
TTkContainer._paintChildCanvas(self._canvas, self.rootLayout(), self.rootLayout().geometry(), self.rootLayout().offset())
def getPadding(self) -> (int, int, int, int):
''' Retrieve the widget padding sizes
def getPadding(self) -> TTkPadding:
''' Retrieve the :py:class:`TTkContainer`'s paddings sizes as shown in :ref:`Layout Topology <Container-Layout-Topology>`
:return: list[top, bottom, left, right]: the 4 padding sizes
:return: :py:class:`TTkPadding` the NamedTuple representing a 4 int values tuple (top,bottom,left,right)
'''
return self._padt, self._padb, self._padl, self._padr
return TTkPadding(self._padt, self._padb, self._padl, self._padr)
def setPadding(self, top: int, bottom: int, left: int, right: int):
''' Set the padding of the widget
def setPadding(self, top: int, bottom: int, left: int, right: int) -> None:
''' Set the :py:class:`TTkContainer`'s paddings sizes as shown in :ref:`Layout Topology <Container-Layout-Topology>`
:param int top: top padding
:param int bottom: bottom padding
@ -226,7 +280,7 @@ class TTkContainer(TTkWidget):
_mouseOver = None
_mouseOverTmp = None
_mouseOverProcessed = False
def mouseEvent(self, evt):
def mouseEvent(self, evt: TTkMouseEvent) -> bool:
''' .. caution:: Don't touch this! '''
if not self._enabled: return False
@ -325,29 +379,44 @@ class TTkContainer(TTkWidget):
return False
def setLayout(self, layout):
def setLayout(self, layout:TTkLayout) -> None:
'''
Set the :ref:`Layout <Layout-Tutorial_Intro>` used by this widget to place all the child widgets.
:param layout:
:type layout: :py:class:`TTkLayout`
'''
self._layout.replaceItem(layout, 0)
#self.layout().setParent(self)
self.update(repaint=True, updateLayout=True)
def layout(self):
''' Get the layout
def layout(self) -> TTkLayout:
'''
Get the :ref:`Layout <Layout-Tutorial_Intro>`
:return: The layout used
:return: The :ref:`Layout <Layout-Tutorial_Intro>` used
:rtype: :py:class:`TTkLayout` or derived
'''
return self._layout.itemAt(0)
def rootLayout(self): return self._layout
def rootLayout(self) -> TTkLayout:
'''
This is a root layout mainly used to place items that are not supposed to be inside the main layout (i.e. the menu elements)
.. caution:: Use this layout only if you know what you are doing
:return: :py:class:``TTkLayout`
'''
return self._layout
def maximumHeight(self):
def maximumHeight(self) -> int:
wMaxH = self._maxh
if self.layout() is not None:
lMaxH = self.layout().maximumHeight() + self._padt + self._padb
if lMaxH < wMaxH:
return lMaxH
return wMaxH
def maximumWidth(self):
def maximumWidth(self) -> int:
wMaxW = self._maxw
if self.layout() is not None:
lMaxW = self.layout().maximumWidth() + self._padl + self._padr
@ -355,21 +424,14 @@ class TTkContainer(TTkWidget):
return lMaxW
return wMaxW
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
def minDimension(self, orientation) -> int:
if orientation == TTkK.HORIZONTAL:
return self.minimumWidth()
else:
return self.minimumHeight()
def minimumHeight(self):
def minimumHeight(self) -> int:
wMinH = self._minh
if self.layout() is not None:
lMinH = self.layout().minimumHeight() + self._padt + self._padb
if lMinH > wMinH:
return lMinH
return wMinH
def minimumWidth(self):
def minimumWidth(self) -> int:
wMinW = self._minw
if self.layout() is not None:
lMinW = self.layout().minimumWidth() + self._padl + self._padr
@ -378,8 +440,7 @@ class TTkContainer(TTkWidget):
return wMinW
@pyTTkSlot()
def show(self):
'''show'''
def show(self) -> None:
if self._visible: return
self._visible = True
self._canvas.show()
@ -388,14 +449,13 @@ class TTkContainer(TTkWidget):
w.update()
@pyTTkSlot()
def hide(self):
'''hide'''
def hide(self) -> None:
if not self._visible: return
self._visible = False
self._canvas.hide()
self.update(repaint=False, updateParent=True)
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False):
def update(self, repaint: bool = True, updateLayout: bool = False, updateParent: bool = False) -> None:
super().update(repaint=repaint, updateLayout=updateLayout, updateParent=updateParent)
if updateLayout and self.rootLayout() is not None and self.size() != (0,0):
self.rootLayout().setGeometry(0,0,self._width,self._height)
@ -405,7 +465,15 @@ class TTkContainer(TTkWidget):
self._height - self._padt - self._padb)
self.rootLayout().update()
def getWidgetByName(self, name: str):
def getWidgetByName(self, name: str) -> TTkWidget:
'''
Return the widget from its name.
:param name: the widget's name, normally defined in the constructor or through :py:meth:`TTkWidget.setName`
:type name:
:return: :py:class:`TTkWidget`
'''
if name == self._name:
return self
for w in self.rootLayout().iterWidgets(onlyVisible=False, recurse=True):

318
TermTk/TTkWidgets/widget.py

@ -224,40 +224,76 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
'''name'''
return self._name
def setName(self, name:str):
'''setName'''
def setName(self, name:str) -> None:
'''
Set the name of this Instance
:param name: the name to be set
:type name: str
'''
self._name = name
def widgetItem(self): return self._widgetItem
def widgetItem(self) -> TTkWidgetItem:
return self._widgetItem
def paintEvent(self, canvas:TTkCanvas):
def paintEvent(self, canvas:TTkCanvas) -> None:
'''
Paint Event callback,
this need to be overridden in the widget.
.. note:: Override this method to handle this event
:param canvas: the canvas where the content need to be drawn
:type canvas: :py:class:`TTkCanvas`
'''
pass
def getPixmap(self) -> TTkCanvas:
'''
Convenience function which return a pixmap representing the current widget status
:return: :py:class:`TTkCanvas`
'''
self.paintEvent(self._canvas)
self.paintChildCanvas()
return self._canvas.copy()
@staticmethod
def _paintChildCanvas(canvas, item, geometry, offset):
def _paintChildCanvas(canvas, item, geometry, offset) -> None:
pass
def paintChildCanvas(self):
def paintChildCanvas(self) -> None:
pass
def moveEvent(self, x: int, y: int):
''' Event Callback triggered after a successful move'''
def moveEvent(self, x: int, y: int) -> None:
'''
Convenience function,
Event Callback triggered after a successful move
.. note:: Override this method to handle this event
:param x: the new horizontal position
:type x: int
:param y: the new vertical position
:type y: int
'''
pass
@pyTTkSlot(int,int)
def resizeEvent(self, w: int, h: int):
''' Event Callback triggered after a successful resize'''
def resizeEvent(self, width: int, height: int) -> None:
'''
Convenience function,
Event Callback triggered after a successful resize
.. note:: Override this method to handle this event
:param width: the new width
:type width: int
:param height: the new height
:type height: int
'''
pass
def setDefaultSize(self, arg, width: int, height: int):
def setDefaultSize(self, arg, width: int, height: int) -> None:
if ( 'size' in arg or
'width' in arg or
'height' in arg ):
@ -265,11 +301,13 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
arg['width'] = width
arg['height'] = height
def move(self, x: int, y: int):
def move(self, x: int, y: int) -> None:
''' Move the widget
:param int x: x position
:param int y: y position
:param x: the horizontal position
:type x: int
:param y: the vertical position
:type y: int
'''
if x==self._x and y==self._y: return
self._x = x
@ -277,40 +315,54 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self.update(repaint=False, updateLayout=False)
self.moveEvent(x,y)
def resize(self, w: int, h: int):
def resize(self, width: int, height: int) -> None:
''' Resize the widget
:param int w: the new width
:param int h: the new height
:param width: the new width
:type width: int
:param height: the new height
:type height: int
'''
# TTkLog.debug(f"resize: {w,h} {self._name}")
if w!=self._width or h!=self._height:
self._width = w
self._height = h
if width!=self._width or height!=self._height:
self._width = width
self._height = height
self._canvas.resize(self._width, self._height)
self.update(repaint=True, updateLayout=True)
self.resizeEvent(w,h)
self.sizeChanged.emit(w,h)
self.resizeEvent(width,height)
self.sizeChanged.emit(width,height)
def setGeometry(self, x: int, y: int, w: int, h: int):
def setGeometry(self, x: int, y: int, width: int, height: int):
''' Resize and move the widget
:param int x: x position
:param int y: y position
:param int w: the new width
:param int h: the new height
:param x: the horizontal position
:type x: int
:param y: the vertical position
:type y: int
:param width: the new width
:type width: int
:param height: the new height
:type height: int
'''
self.resize(w, h)
self.resize(width, height)
self.move(x, y)
def pasteEvent(self, txt:str):
def pasteEvent(self, txt:str) -> None:
'''
Callback triggered when a paste event is forwarded to this widget.
.. note:: Reimplement this function to handle this event
:param txt: the paste object
:type txt: str
'''
return False
_mouseOver = None
_mouseOverTmp = None
_mouseOverProcessed = False
def mouseEvent(self, evt):
''' .. caution:: Don't touch this! '''
def mouseEvent(self, evt:TTkMouseEvent) -> bool:
''' .. caution:: Don Not touch this! '''
if not self._enabled: return False
# Saving self in this global variable
@ -408,42 +460,42 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
return False
def setParent(self, parent):
def setParent(self, parent) -> None:
self._parent = parent
def parentWidget(self):
return self._parent
def x(self): return self._x
def y(self): return self._y
def width(self): return self._width
def height(self): return self._height
def x(self) -> int: return self._x
def y(self) -> int: return self._y
def width(self) -> int: return self._width
def height(self) -> int: return self._height
def pos(self): return self._x, self._y
def size(self): return self._width, self._height
def geometry(self): return self._x, self._y, self._width, self._height
def pos(self) -> tuple[int,int]: return self._x, self._y
def size(self) -> tuple[int,int]: return self._width, self._height
def geometry(self) -> tuple[int,int,int,int]: return self._x, self._y, self._width, self._height
def maximumSize(self):
def maximumSize(self) -> tuple[int,int]:
return self.maximumWidth(), self.maximumHeight()
def maxDimension(self, orientation) -> int:
def maxDimension(self, orientation:TTkK.Direction) -> int:
if orientation == TTkK.HORIZONTAL:
return self.maximumWidth()
else:
return self.maximumHeight()
def maximumHeight(self):
def maximumHeight(self) -> int:
return self._maxh
def maximumWidth(self):
def maximumWidth(self) -> int:
return self._maxw
def minimumSize(self):
def minimumSize(self) -> tuple[int,int]:
return self.minimumWidth(), self.minimumHeight()
def minDimension(self, orientation) -> int:
def minDimension(self, orientation:TTkK.Direction) -> int:
if orientation == TTkK.HORIZONTAL:
return self.minimumWidth()
else:
return self.minimumHeight()
def minimumHeight(self):
def minimumHeight(self) -> int:
return self._minh
def minimumWidth(self):
def minimumWidth(self) -> int:
return self._minw
def setMaximumSize(self, maxw: int, maxh: int):
@ -471,24 +523,24 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self.update(updateLayout=True, updateParent=True)
@pyTTkSlot()
def show(self):
'''show'''
def show(self) -> None:
'''show the widget'''
if self._visible: return
self._visible = True
self._canvas.show()
self.update(updateLayout=True, updateParent=True)
@pyTTkSlot()
def hide(self):
'''hide'''
def hide(self) -> None:
'''hide the widget'''
if not self._visible: return
self._visible = False
self._canvas.hide()
self.update(repaint=False, updateParent=True)
@pyTTkSlot()
def raiseWidget(self, raiseParent=True):
'''raiseWidget'''
def raiseWidget(self, raiseParent:bool=True) -> None:
'''Raise the Widget above its relatives'''
if self._parent is not None and \
self._parent.rootLayout() is not None:
if raiseParent:
@ -496,16 +548,16 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._parent.rootLayout().raiseWidget(self)
@pyTTkSlot()
def lowerWidget(self):
'''lowerWidget'''
def lowerWidget(self) -> None:
'''Lower the Widget below its relatives'''
if self._parent is not None and \
self._parent.rootLayout() is not None:
self._parent.lowerWidget()
self._parent.rootLayout().lowerWidget(self)
@pyTTkSlot()
def close(self):
'''close'''
def close(self) -> None:
'''Close (Destroy/Remove) the widget'''
if _p := self._parent:
if _rl := _p.rootLayout():
_rl.removeWidget(self)
@ -516,20 +568,57 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self.closed.emit(self)
@pyTTkSlot(bool)
def setVisible(self, visible: bool):
'''setVisible'''
def setVisible(self, visible: bool) -> None:
'''
Set the visibility status of this widget
:param visible: status
:type visible: bool:
'''
if visible: self.show()
else: self.hide()
def isVisibleAndParent(self):
def isVisibleAndParent(self) -> bool:
return ( self._visible and
( self._parent is not None ) and
self._parent.isVisibleAndParent() )
def isVisible(self):
def isVisible(self) -> bool:
'''
Retrieve the visibility status of this widget
:return: bool
'''
return self._visible
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False):
@pyTTkSlot()
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False) -> None:
'''
Notify the drawing routine that the widget changed and needs to draw its new content.
It is important to call this method anytime a canvas update is required after a a status update.
Once :py:meth:`update` is called, the :py:meth:`paintEvent` is executed during the next screen refresh.
i.e.
.. code-block:: python
class NewLabel(TTkWidget):
def __init__(self,**kwargs):
self.text = ""
super().__init__(**kwargs)
def setText(self, text:str) -> None:
self.text = text
# Notify the runtime that un update
# is required will trigger the paintEvent
# at the next screen (terminal) refresh
self.update()
def paintEvent(self, canvas:TTkCanvas) -> None:
canvas.drawText(pos=(0,0), text=self.text)
'''
if repaint:
TTkHelper.addUpdateBuffer(self)
TTkHelper.addUpdateWidget(self)
@ -537,8 +626,8 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._parent.update(updateLayout=True)
@pyTTkSlot()
def setFocus(self):
'''setFocus'''
def setFocus(self) -> None:
'''Focus the widget'''
# TTkLog.debug(f"setFocus: {self._name} - {self._focus}")
if self._focus and self == TTkHelper.getFocus(): return
tmp = TTkHelper.getFocus()
@ -553,7 +642,8 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._pushWidgetCursor()
self._processStyleEvent(TTkWidget._S_DEFAULT)
def clearFocus(self):
def clearFocus(self) -> None:
'''Remove the Focus state of this widget'''
# TTkLog.debug(f"clearFocus: {self._name} - {self._focus}")
if not self._focus and self != TTkHelper.getFocus(): return
TTkHelper.clearFocus()
@ -563,44 +653,96 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._processStyleEvent(TTkWidget._S_DEFAULT)
self.update(repaint=True, updateLayout=False)
def hasFocus(self):
def hasFocus(self) -> bool:
'''
This property holds the focus status of this widget
:return: bool
'''
return self._focus
def getCanvas(self) -> TTkCanvas:
return self._canvas
def focusPolicy(self):
def focusPolicy(self) -> TTkK.FocusPolicy:
return self._focus_policy
def setFocusPolicy(self, policy):
def setFocusPolicy(self, policy:TTkK.FocusPolicy) -> None:
'''
This property holds the way the widget accepts keyboard focus
The policy is :py:class:`TTkK.FocusPolicy.TabFocus` if the widget accepts keyboard focus by tabbing,
:py:class:`TTkK.FocusPolicy.ClickFocus` if the widget accepts focus by clicking,
:py:class:`TTkK.FocusPolicy.StrongFocus` if it accepts both,
and :py:class:`TTkK.FocusPolicy.NoFocus` (the default) if it does not accept focus at all.
You must enable keyboard focus for a widget if it processes keyboard events.
This is normally done from the widget's constructor. For instance,
the :py:class:`TTkLineEdit` constructor calls :py:meth:`setFocusPolicy` with :py:class:`TTkK.FocusPolicy.StrongFocus`.
If the widget has a focus proxy, then the focus policy will be propagated to it.
:param policy: the focus policy
:type policy: :py:class:`TTkK.FocusPolicy`
'''
self._focus_policy = policy
def focusInEvent(self): pass
def focusOutEvent(self): pass
def focusInEvent(self) -> None: pass
def focusOutEvent(self) -> None: pass
def isEntered(self):
def isEntered(self) -> bool:
return self._mouseOver == self
def isEnabled(self):
def isEnabled(self) -> bool:
'''
This property holds whether the widget is enabled
use :py:meth:`setEnabled` or :py:meth:`setDisabled` to change this property
:return: bool
'''
return self._enabled
@pyTTkSlot(bool)
def setEnabled(self, enabled: bool=True):
'''setEnabled'''
def setEnabled(self, enabled:bool=True) -> None:
'''
This property holds whether the widget is enabled
In general an enabled widget handles keyboard and mouse events;
a disabled widget does not.
Some widgets display themselves differently when they are disabled.
For example a button might draw its label grayed out.
If your widget needs to know when it becomes enabled or disabled.
Disabling a widget implicitly disables all its children.
Enabling respectively enables all child widgets unless they have been explicitly disabled.
By default, this property is true.
:param enabled: the enabled status, defaults to True
:type enabled: bool
'''
if self._enabled == enabled: return
self._enabled = enabled
self._processStyleEvent(TTkWidget._S_DEFAULT if enabled else TTkWidget._S_DISABLED)
self.update()
@pyTTkSlot(bool)
def setDisabled(self, disabled=True):
'''setDisabled'''
def setDisabled(self, disabled:bool=True) -> None:
'''This property holds whether the widget is disnabled
This is a convenience function wrapped around :py:meth:`setEnabled` where (not disabled) is used
:param disabled: the disabled status, defaults to True
:type disabled: bool
'''
self.setEnabled(not disabled)
def toolTip(self):
def toolTip(self) -> TTkString:
return self._toolTip
def setToolTip(self, toolTip: TTkString):
def setToolTip(self, toolTip: TTkString) -> None:
self._toolTip = TTkString(toolTip)
def getWidgetByName(self, name: str):
@ -619,19 +761,19 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
_S_PRESSED = 0x20
_S_RELEASED = 0x40
def style(self):
def style(self) -> dict:
return self._style.copy()
def currentStyle(self):
def currentStyle(self) -> dict:
return self._currentStyle
def setCurrentStyle(self, style):
def setCurrentStyle(self, style) -> dict:
if style == self._currentStyle: return
self._currentStyle = style
self.currentStyleChanged.emit(style)
self.update()
def setStyle(self, style=None):
def setStyle(self, style=None) -> None:
if not style:
style = self.classStyle.copy()
if 'default' not in style:
@ -649,7 +791,7 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._style = mergeStyle
self._processStyleEvent(TTkWidget._S_DEFAULT)
def mergeStyle(self, style):
def mergeStyle(self, style) -> None:
cs = None
# for field in style:
# if field in self._style:
@ -664,7 +806,7 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
if cs:
self.setCurrentStyle(self._style[cs])
def _processStyleEvent(self, evt=_S_DEFAULT):
def _processStyleEvent(self, evt=_S_DEFAULT) -> bool:
if not self._style: return False
if not self._enabled and 'disabled' in self._style:
self.setCurrentStyle(self._style['disabled'])
@ -694,15 +836,15 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
return False
# Widget Cursor Helpers
def enableWidgetCursor(self, enable=True):
def enableWidgetCursor(self, enable:bool=True) -> None:
self._widgetCursorEnabled = enable
self._pushWidgetCursor()
def disableWidgetCursor(self, disable=True):
def disableWidgetCursor(self, disable:bool=True) -> None:
self._widgetCursorEnabled = not disable
self._pushWidgetCursor()
def setWidgetCursor(self, pos=None, type=None):
def setWidgetCursor(self, pos=None, type=None) -> None:
self._widgetCursor = pos if pos else self._widgetCursor
self._widgetCursorType = type if type else self._widgetCursorType
self._pushWidgetCursor()

34
docs/source/sphinx_modules/sphinx_ext_autosummary_reworked.py

@ -135,7 +135,12 @@ def setup(app: Sphinx) -> ExtensionMetadata:
for cc in _obj.__mro__:
if cc==_obj: continue
# if hasattr(cc,'_ttkProperties'):
if issubclass(cc, ttk.TTkWidget) or issubclass(cc, ttk.TTkLayout):
if (
issubclass(cc, ttk.TTkTemplates.dragevents.TDragEvents) or
issubclass(cc, ttk.TTkTemplates.mouseevents.TMouseEvents) or
issubclass(cc, ttk.TTkTemplates.keyevents.TKeyEvents) or
issubclass(cc, ttk.TTkWidget) or
issubclass(cc, ttk.TTkLayout) ) :
ccName = cc.__name__
ret.append(ccName)
# print(ccName)
@ -238,6 +243,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
ttkSlots = []
ttkSlotsInherited = {}
ttkMethods = []
ttkMethodsInherited = {}
ttkInheritedMethods = []
ttkSubClasses = modSorted.get(name,[])
ttkSubModules = modSubSorted.get(name,[])
@ -249,6 +255,13 @@ def setup(app: Sphinx) -> ExtensionMetadata:
ttkSlots, ttkSlotsInherited = _get_slots_in_obj(qualname)
def _get_methods_in_obj(_name):
_methodsInherited = {_sub : sorted(ttkAllMethods.get(_sub,[])) for _sub in ttkInherited.get(_name,[])}
_methods = set(ttkAllMethods.get(_name,[])) - set([_sl for _subSl in _methodsInherited.values() for _sl in _subSl])
return sorted(list(_methods)), _methodsInherited
ttkMethods, ttkInheritedMethods = _get_methods_in_obj(qualname)
def _get_attributes_in_obj(_obj,_name):
_allMethods = ttkAllMethods.get(_name,[])
_slots = ttkAllSlots.get(_name,[])
@ -270,15 +283,16 @@ def setup(app: Sphinx) -> ExtensionMetadata:
ttkAttributes = sorted(set(_get_simple_attributes(obj)) - set(ttkAllSignals.get(qualname,'')))
context |= {
'TTkAttributes':ttkAttributes,
'TTkClasses':_get_classes(obj,ttkMethods+ttkSlots+ttkAllSignals.get(qualname,[])),
'TTkStyle':modStyles.get(qualname,''),
'TTkSignals':ttkAllSignals.get(qualname,''),
'TTkSubClasses': ttkSubClasses,
'TTkSubModules': ttkSubModules,
'TTkMethods':ttkAllMethods.get(qualname,''),
'TTkSlots':ttkSlots,
'TTkSlotsInherited':ttkSlotsInherited,
'TTkAttributes': sorted( ttkAttributes ),
'TTkClasses': sorted( _get_classes(obj,ttkMethods+ttkSlots+ttkAllSignals.get(qualname,[])) ),
'TTkSignals': sorted( ttkAllSignals.get(qualname,'') ),
'TTkSubClasses': sorted( ttkSubClasses ),
'TTkSubModules': sorted( ttkSubModules ),
'TTkSlots': sorted( ttkSlots ),
'TTkMethods': sorted( ttkMethods ),
'TTkStyle': modStyles.get(qualname,'') ,
'TTkSlotsInherited': ttkSlotsInherited ,
'TTkMethodsInherited': ttkInheritedMethods ,
}
print('\n'.join([f" * {x}={context[x]}" for x in context]))

29
docs/source/templates/custom-class-template.01.rst

@ -1,7 +1,5 @@
{{ objname | escape | underline }}
Pippo CUSTOM_CLASS_TEMPLATE.001
.. currentmodule:: {{ module }}
.. autoclass:: {{ objname }}
@ -45,16 +43,17 @@ Pippo CUSTOM_CLASS_TEMPLATE.001
{% if TTkSlotsInherited %}
{% for name in TTkSlotsInherited %}
Inherited from: :py:class:`{{ name }}`
{% if TTkSlotsInherited[name] %}
Slots Inherited from: :py:class:`{{ name }}`
.. autosummary::
{% for item in TTkSlotsInherited[name] %}
{{ item }}
{%- endfor %}
{%- endfor %}
{% endif %}
{%- endfor %}
{% endif %}
{% if TTkSignals %}
@ -66,9 +65,12 @@ Pippo CUSTOM_CLASS_TEMPLATE.001
{%- endfor %}
{% endif %}
{% if TTkMethods %}
{% if TTkMethods or TTkMethodsInherited %}
Methods
-------
{% endif %}
{% if TTkMethods %}
{% for item in TTkMethods %}
.. automethod:: {{ item }}
@ -76,6 +78,21 @@ Pippo CUSTOM_CLASS_TEMPLATE.001
{% endif %}
{% if TTkMethodsInherited %}
{% for name in TTkMethodsInherited %}
{% if TTkMethodsInherited[name] %}
Methods Inherited from: :py:class:`{{ name }}`
.. autosummary::
{% for item in TTkMethodsInherited[name] %}
{{ item }}
{%- endfor %}
{% endif %}
{%- endfor %}
{% endif %}
{% if TTkClasses %}

63
tests/timeit/02.array.07.namedTuple.py

@ -0,0 +1,63 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2024 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# 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
import sys
import argparse
import operator
import json
import timeit
import random
from typing import NamedTuple
class TTkPadding(NamedTuple):
top : int = 0
bottom : int = 0
left : int = 0
right : int = 0
def test_ti_1_00():
return len([[x,x,x,x] for x in range(1000)])
def test_ti_2_00():
return len([(x,x,x,x) for x in range(1000)])
def test_ti_2_01():
return len([(1,1,1,1) for x in range(1000)])
def test_ti_3_00():
return len([TTkPadding(x,x,x,x) for x in range(1000)])
loop = 500
a = {}
for testName in sorted([tn for tn in globals() if tn.startswith('test_ti_')]):
result = timeit.timeit(f'{testName}(*a)', globals=globals(), number=loop)
# print(f"test{iii}) fps {loop / result :.3f} - s {result / loop:.10f} - {result / loop} {globals()[testName](*a)}")
print(f"{testName} | {result / loop:.10f} sec. | {loop / result : 15.3f} Fps ╞╡-> {globals()[testName](*a)}")

2
tutorial/002-layout.rst

@ -25,6 +25,8 @@
pyTermTk_ - Layouts
=============================================================================
.. _Layout-Tutorial_Intro:
Intro
=====

Loading…
Cancel
Save