25 changed files with 2192 additions and 324 deletions
@ -0,0 +1,70 @@ |
|||||||
|
# Current |
||||||
|
|
||||||
|
## Current Status of the focus/keypress logic |
||||||
|
|
||||||
|
``` |
||||||
|
<INPUT> |
||||||
|
└─▶ KeyEvent |
||||||
|
└─▶ TTk._key_event() |
||||||
|
try 1 ─▶ send KeyEvent to Focus Widget |
||||||
|
try 2 ─▶ send KeyEvent to Shortcut Engine |
||||||
|
try 3 ─▶ Check and handle for next Focus |
||||||
|
try 4 ─▶ check and handle for prev focus |
||||||
|
``` |
||||||
|
|
||||||
|
## Reworked Status of the focus/keypress logic |
||||||
|
|
||||||
|
1) Add default KeyPress handler |
||||||
|
|
||||||
|
This handler is supposed to switch the focus (next/prev) or return False |
||||||
|
|
||||||
|
1) Add focus proxy/orchestrator/helper in TTkContainer (New Class? or internally Managed?) |
||||||
|
|
||||||
|
####ß Require (so far) |
||||||
|
|
||||||
|
* Next Focus |
||||||
|
* Prev Focus |
||||||
|
* First Focus |
||||||
|
* Last Focus |
||||||
|
* Get Focussed |
||||||
|
* Focus Widget |
||||||
|
* UnFocus Widget |
||||||
|
* Add Widget(s) |
||||||
|
* Remove Widget(s) |
||||||
|
* Insert Widget(s) |
||||||
|
|
||||||
|
1) Key Propagation |
||||||
|
|
||||||
|
``` |
||||||
|
<INPUT> |
||||||
|
└─▶ KeyEvent |
||||||
|
└─▶ TTk.keyEvent(kevt) |
||||||
|
try 1 ─▶ send KeyEvent to |
||||||
|
└─▶ super().keyEvent(kevt) (TTkContainer) |
||||||
|
try 1 : send key event to the focussed |
||||||
|
if return False; |
||||||
|
try 2 : if Tab/Right focus Next |
||||||
|
try 3 : if ^Tab/Left focus Prev |
||||||
|
If nothing execute return False |
||||||
|
if not handled, the tab/direction key switch reached the last/first widget: |
||||||
|
try 3 ─▶ Tab/Right focus the first |
||||||
|
try 4 ─▶ ^Tab/Left focus the last |
||||||
|
``` |
||||||
|
|
||||||
|
2) Focus Propagation |
||||||
|
|
||||||
|
``` |
||||||
|
``` |
||||||
|
|
||||||
|
# TODO |
||||||
|
|
||||||
|
[x] - Implement root handler to handle overlay widgets where the focus switch should be contained in the overlay |
||||||
|
[x] - Remove nextFocus,prevFocus from the helper |
||||||
|
[ ] - Investigate other widgets focus propagation |
||||||
|
[ ] - Switch Focus to the menu |
||||||
|
[ ] - Type TTkLayout and add docstrings |
||||||
|
[ ] - Add deprecated methods in ttkhelper |
||||||
|
[x] - Investigate lineedit of the combobox |
||||||
|
[x] - Tab Widget: Adapt to the new logic |
||||||
|
[x] - DateTime: Adapt to the new logic |
||||||
|
[ ] - Tab Widget: Apply Highlight colors |
||||||
@ -0,0 +1,393 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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. |
||||||
|
|
||||||
|
__all__ = [] |
||||||
|
|
||||||
|
from typing import Optional, List, Tuple |
||||||
|
|
||||||
|
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent |
||||||
|
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent |
||||||
|
from TermTk.TTkCore.constant import TTkK |
||||||
|
from TermTk.TTkCore.shortcut import TTkShortcut |
||||||
|
from TermTk.TTkWidgets.container import TTkContainer |
||||||
|
from TermTk.TTkWidgets.widget import TTkWidget |
||||||
|
|
||||||
|
def _absPos(widget: TTkWidget) -> Tuple[int,int]: |
||||||
|
wx, wy = 0,0 |
||||||
|
layout = widget.widgetItem() |
||||||
|
while layout: |
||||||
|
px, py = layout.pos() |
||||||
|
ox, oy = layout.offset() |
||||||
|
wx, wy = wx+px+ox, wy+py+oy |
||||||
|
layout = layout.parent() |
||||||
|
return (wx, wy) |
||||||
|
|
||||||
|
class _TTkOverlay(): |
||||||
|
__slots__ = ('_widget','_prevFocus','_modal') |
||||||
|
|
||||||
|
_widget:TTkWidget |
||||||
|
_prevFocus:Optional[TTkWidget] |
||||||
|
_modal:bool |
||||||
|
|
||||||
|
def __init__( |
||||||
|
self, |
||||||
|
pos:Tuple[int,int], |
||||||
|
widget:TTkWidget, |
||||||
|
prevFocus:Optional[TTkWidget], |
||||||
|
modal:bool): |
||||||
|
self._widget = widget |
||||||
|
self._prevFocus = prevFocus |
||||||
|
self._modal = modal |
||||||
|
widget.move(*pos) |
||||||
|
|
||||||
|
class _TTkRootContainer(TTkContainer): |
||||||
|
''' _TTkRootContainer: |
||||||
|
|
||||||
|
Internal root container class that manages the application's root widget hierarchy and focus navigation. |
||||||
|
|
||||||
|
This class is not meant to be used directly by application code. It is instantiated internally by :py:class:`TTk` |
||||||
|
to provide the top-level container for all widgets and handle keyboard-based focus traversal. |
||||||
|
|
||||||
|
The root container manages focus cycling when Tab/Shift+Tab or arrow keys are pressed and no widget |
||||||
|
consumes the event, ensuring focus loops back to the first/last focusable widget. |
||||||
|
''' |
||||||
|
__slots__ = ( |
||||||
|
'_focusWidget', |
||||||
|
'_overlay') |
||||||
|
|
||||||
|
_focusWidget:Optional[TTkWidget] |
||||||
|
_overlay:List[_TTkOverlay] |
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None: |
||||||
|
self._focusWidget = None |
||||||
|
self._overlay = [] |
||||||
|
super().__init__(**kwargs) |
||||||
|
|
||||||
|
def _getFocusWidget(self) -> Optional[TTkWidget]: |
||||||
|
''' |
||||||
|
Returns the currently focused widget. |
||||||
|
|
||||||
|
:return: the widget with focus, or None if no widget has focus |
||||||
|
:rtype: :py:class:`TTkWidget` or None |
||||||
|
''' |
||||||
|
return self._focusWidget |
||||||
|
|
||||||
|
def _setFocusWidget(self, widget:Optional[TTkWidget]) -> None: |
||||||
|
''' |
||||||
|
Sets the currently focused widget and triggers a repaint. |
||||||
|
|
||||||
|
:param widget: the widget to receive focus, or None to clear focus |
||||||
|
:type widget: :py:class:`TTkWidget` or None |
||||||
|
''' |
||||||
|
if self._focusWidget is widget: |
||||||
|
return |
||||||
|
self._focusWidget = widget |
||||||
|
self.update() |
||||||
|
|
||||||
|
def _loopFocus(self, container:TTkContainer, evt:TTkKeyEvent) -> bool: |
||||||
|
if ( (evt.key == TTkK.Key_Tab and evt.mod == TTkK.NoModifier) or |
||||||
|
(evt.key in (TTkK.Key_Right, TTkK.Key_Down ) ) ) : |
||||||
|
if _nfw:=container._getFirstFocus(widget=None,focusPolicy=TTkK.FocusPolicy.TabFocus): |
||||||
|
_nfw.setFocus() |
||||||
|
return True |
||||||
|
if ( (evt.key == TTkK.Key_Tab and evt.mod == TTkK.ShiftModifier) or |
||||||
|
(evt.key in ( TTkK.Key_Left, TTkK.Key_Up ) ) ) : |
||||||
|
if _pfw:=container._getLastFocus(widget=None,focusPolicy=TTkK.FocusPolicy.TabFocus): |
||||||
|
_pfw.setFocus() |
||||||
|
return True |
||||||
|
return False |
||||||
|
|
||||||
|
def _handleOverlay(self, evt:TTkKeyEvent) -> bool: |
||||||
|
if not self._overlay: |
||||||
|
return False |
||||||
|
_overlay = self._overlay[-1] |
||||||
|
_widget = _overlay._widget |
||||||
|
if _widget.keyEvent(evt=evt): |
||||||
|
return True |
||||||
|
if isinstance(_widget, TTkContainer) and self._loopFocus(evt=evt, container=_widget): |
||||||
|
return True |
||||||
|
|
||||||
|
def overlay(self, |
||||||
|
caller: Optional[TTkWidget], |
||||||
|
widget: TTkWidget, |
||||||
|
pos:Tuple[int,int], |
||||||
|
modal:bool=False, |
||||||
|
forceBoundaries:bool=True, |
||||||
|
toolWindow:bool=False) -> None: |
||||||
|
''' |
||||||
|
Adds a widget as an overlay on top of the current widget hierarchy. |
||||||
|
|
||||||
|
The overlay widget is positioned relative to the caller widget and automatically |
||||||
|
adjusted to stay within the root container boundaries (if forceBoundaries is True). |
||||||
|
Overlays can be modal (blocking interaction with underlying widgets) or non-modal. |
||||||
|
|
||||||
|
:param caller: the widget relative to which the overlay is positioned, or None to use root |
||||||
|
:type caller: :py:class:`TTkWidget` or None |
||||||
|
:param widget: the widget to display as an overlay |
||||||
|
:type widget: :py:class:`TTkWidget` |
||||||
|
:param pos: the (x, y) position offset relative to the caller widget |
||||||
|
:type pos: tuple[int, int] |
||||||
|
:param modal: if True, blocks interaction with underlying widgets |
||||||
|
:type modal: bool |
||||||
|
:param forceBoundaries: if True, adjusts position and size to keep overlay within root boundaries |
||||||
|
:type forceBoundaries: bool |
||||||
|
:param toolWindow: if True, treats the overlay as a tool window without focus management |
||||||
|
:type toolWindow: bool |
||||||
|
''' |
||||||
|
if not caller: |
||||||
|
caller = self |
||||||
|
x,y = pos |
||||||
|
wx, wy = _absPos(caller) |
||||||
|
w,h = widget.size() |
||||||
|
rw,rh = self.rootLayout().size() |
||||||
|
|
||||||
|
# Try to keep the overlay widget inside the rootContainer boundaries |
||||||
|
if forceBoundaries: |
||||||
|
wx = max(0, wx+x if wx+x+w < rw else rw-w ) |
||||||
|
wy = max(0, wy+y if wy+y+h < rh else rh-h ) |
||||||
|
mw,mh = widget.minimumSize() |
||||||
|
ww = min(w,max(mw, rw)) |
||||||
|
wh = min(h,max(mh, rh)) |
||||||
|
widget.resize(ww,wh) |
||||||
|
else: |
||||||
|
wx += x |
||||||
|
wy += y |
||||||
|
|
||||||
|
wi = widget.widgetItem() |
||||||
|
# Forcing the layer to: |
||||||
|
# TTkLayoutItem.LAYER1 = 0x40000000 |
||||||
|
wi.setLayer(wi.LAYER1) |
||||||
|
|
||||||
|
if toolWindow: |
||||||
|
widget.move(wx,wy) |
||||||
|
else: |
||||||
|
_fw = self._getFocusWidget() |
||||||
|
self._overlay.append(_TTkOverlay( |
||||||
|
pos=(wx,wy), |
||||||
|
widget=widget, |
||||||
|
prevFocus=_fw, |
||||||
|
modal=modal)) |
||||||
|
|
||||||
|
self.rootLayout().addWidget(widget) |
||||||
|
widget.raiseWidget() |
||||||
|
widget.setFocus() |
||||||
|
if isinstance(widget, TTkContainer): |
||||||
|
for w in widget.rootLayout().iterWidgets(onlyVisible=True): |
||||||
|
w.update() |
||||||
|
|
||||||
|
def _removeOverlay(self) -> None: |
||||||
|
''' |
||||||
|
Removes the topmost overlay widget and restores focus to the previous widget. |
||||||
|
|
||||||
|
If the overlay is modal, it must be explicitly removed before any underlying |
||||||
|
overlays can be removed. Focus is restored to the widget that had focus before |
||||||
|
the overlay was added. |
||||||
|
''' |
||||||
|
if not self._overlay: |
||||||
|
return |
||||||
|
bkFocus = None |
||||||
|
# Remove the first element also if it is modal |
||||||
|
self._overlay[-1]._modal = False |
||||||
|
while self._overlay: |
||||||
|
if self._overlay[-1]._modal: |
||||||
|
break |
||||||
|
owidget = self._overlay.pop() |
||||||
|
bkFocus = owidget._prevFocus |
||||||
|
self.rootLayout().removeWidget(owidget._widget) |
||||||
|
if _fw:=self._getFocusWidget(): |
||||||
|
_fw.clearFocus() |
||||||
|
if bkFocus: |
||||||
|
bkFocus.setFocus() |
||||||
|
|
||||||
|
def _removeOverlayAndChild(self, widget: Optional[TTkWidget]) -> None: |
||||||
|
''' |
||||||
|
Removes the specified overlay widget and all overlays added after it. |
||||||
|
|
||||||
|
This method finds the root overlay containing the given widget and removes it |
||||||
|
along with any child overlays that were added on top of it. Focus is restored |
||||||
|
to the widget that had focus before the overlay stack was created. |
||||||
|
|
||||||
|
:param widget: the widget whose root overlay (and children) should be removed |
||||||
|
:type widget: :py:class:`TTkWidget` or None |
||||||
|
''' |
||||||
|
if not widget: |
||||||
|
return |
||||||
|
if not self._isOverlay(widget): |
||||||
|
return |
||||||
|
if len(self._overlay) <= 1: |
||||||
|
return self._removeOverlay() |
||||||
|
rootWidget = self._rootOverlay(widget) |
||||||
|
bkFocus = None |
||||||
|
found = False |
||||||
|
newOverlay = [] |
||||||
|
for o in self._overlay: |
||||||
|
if o._widget == rootWidget: |
||||||
|
found = True |
||||||
|
bkFocus = o._prevFocus |
||||||
|
if not found: |
||||||
|
newOverlay.append(o) |
||||||
|
else: |
||||||
|
self.rootLayout().removeWidget(o._widget) |
||||||
|
self._overlay = newOverlay |
||||||
|
if bkFocus: |
||||||
|
bkFocus.setFocus() |
||||||
|
if not found: |
||||||
|
self._removeOverlay() |
||||||
|
|
||||||
|
def _removeOverlayChild(self, widget: TTkWidget) -> None: |
||||||
|
''' |
||||||
|
Removes all overlay widgets that were added after the specified widget. |
||||||
|
|
||||||
|
This method preserves the overlay containing the given widget but removes |
||||||
|
all overlays that were added on top of it. If the widget is not found in |
||||||
|
the overlay stack, removes the topmost overlay. |
||||||
|
|
||||||
|
:param widget: the widget whose child overlays should be removed |
||||||
|
:type widget: :py:class:`TTkWidget` |
||||||
|
''' |
||||||
|
rootWidget = self._rootOverlay(widget) |
||||||
|
found = False |
||||||
|
newOverlay = [] |
||||||
|
for o in self._overlay: |
||||||
|
if o._widget == rootWidget: |
||||||
|
found = True |
||||||
|
newOverlay.append(o) |
||||||
|
continue |
||||||
|
if not found: |
||||||
|
newOverlay.append(o) |
||||||
|
else: |
||||||
|
self.rootLayout().removeWidget(o._widget) |
||||||
|
self._overlay = newOverlay |
||||||
|
if not found: |
||||||
|
self._removeOverlay() |
||||||
|
|
||||||
|
def _focusLastModal(self) -> None: |
||||||
|
''' |
||||||
|
Sets focus to the last modal overlay widget in the stack. |
||||||
|
|
||||||
|
This method is used internally to ensure modal overlays maintain focus |
||||||
|
when interaction is attempted with underlying widgets. |
||||||
|
''' |
||||||
|
if modal := self._getLastModal(): |
||||||
|
modal._widget.setFocus() |
||||||
|
|
||||||
|
def _checkModalOverlay(self, widget: TTkWidget) -> bool: |
||||||
|
''' |
||||||
|
Checks if a widget is allowed to receive input given the current modal overlay state. |
||||||
|
|
||||||
|
:param widget: the widget to check for input permission |
||||||
|
:type widget: :py:class:`TTkWidget` |
||||||
|
|
||||||
|
:return: True if the widget can receive input, False if blocked by a modal overlay |
||||||
|
:rtype: bool |
||||||
|
''' |
||||||
|
#if not TTkHelper._overlay: |
||||||
|
# # There are no Overlays |
||||||
|
# return True |
||||||
|
|
||||||
|
if not (lastModal := self._getLastModal()): |
||||||
|
return True |
||||||
|
|
||||||
|
# if not TTkHelper._overlay[-1]._modal: |
||||||
|
# # The last window is not modal |
||||||
|
# return True |
||||||
|
if not (rootWidget := self._rootOverlay(widget)): |
||||||
|
# This widget is not overlay |
||||||
|
return False |
||||||
|
if rootWidget in [ o._widget for o in self._overlay[self._overlay.index(lastModal):]]: |
||||||
|
return True |
||||||
|
# if TTkHelper._overlay[-1]._widget == rootWidget: |
||||||
|
# return True |
||||||
|
return False |
||||||
|
|
||||||
|
def _getLastModal(self) -> Optional[_TTkOverlay]: |
||||||
|
''' |
||||||
|
Returns the last modal overlay in the stack. |
||||||
|
|
||||||
|
:return: the last modal overlay wrapper, or None if no modal overlays exist |
||||||
|
:rtype: :py:class:`_TTkOverlay` or None |
||||||
|
''' |
||||||
|
modal = None |
||||||
|
for o in self._overlay: |
||||||
|
if o._modal: |
||||||
|
modal = o |
||||||
|
return modal |
||||||
|
|
||||||
|
def _isOverlay(self, widget: Optional[TTkWidget]) -> bool: |
||||||
|
''' |
||||||
|
Checks if a widget is part of the overlay hierarchy. |
||||||
|
|
||||||
|
:param widget: the widget to check |
||||||
|
:type widget: :py:class:`TTkWidget` or None |
||||||
|
|
||||||
|
:return: True if the widget is contained in any overlay, False otherwise |
||||||
|
:rtype: bool |
||||||
|
''' |
||||||
|
return self._rootOverlay(widget) is not None |
||||||
|
|
||||||
|
def _rootOverlay(self, widget: Optional[TTkWidget]) -> Optional[TTkWidget]: |
||||||
|
''' |
||||||
|
Finds the root overlay widget that contains the specified widget. |
||||||
|
|
||||||
|
Traverses the widget's parent hierarchy to find which overlay (if any) |
||||||
|
contains it as a child. |
||||||
|
|
||||||
|
:param widget: the widget to search for in the overlay hierarchy |
||||||
|
:type widget: :py:class:`TTkWidget` or None |
||||||
|
|
||||||
|
:return: the root overlay widget containing the specified widget, or None if not in any overlay |
||||||
|
:rtype: :py:class:`TTkWidget` or None |
||||||
|
''' |
||||||
|
if not widget: |
||||||
|
return None |
||||||
|
if not self._overlay: |
||||||
|
return None |
||||||
|
overlayWidgets = [o._widget for o in self._overlay] |
||||||
|
while widget is not None: |
||||||
|
if widget in overlayWidgets: |
||||||
|
return widget |
||||||
|
widget = widget.parentWidget() |
||||||
|
return None |
||||||
|
|
||||||
|
def keyEvent(self, evt:TTkKeyEvent) -> bool: |
||||||
|
''' |
||||||
|
Handles keyboard events for focus navigation. |
||||||
|
|
||||||
|
Implements focus cycling behavior when Tab/Shift+Tab or arrow keys are pressed |
||||||
|
and no child widget consumes the event. When the last focusable widget is reached, |
||||||
|
focus cycles back to the first widget (and vice versa). |
||||||
|
|
||||||
|
:param evt: the keyboard event |
||||||
|
:type evt: :py:class:`TTkKeyEvent` |
||||||
|
|
||||||
|
:return: True if the event was handled, False otherwise |
||||||
|
:rtype: bool |
||||||
|
''' |
||||||
|
if self._handleOverlay(evt=evt): |
||||||
|
return True |
||||||
|
if super().keyEvent(evt=evt): |
||||||
|
return True |
||||||
|
|
||||||
|
# If this is reached after a tab focus event, it means that either |
||||||
|
# no focus widgets are defined |
||||||
|
# or the last/first focus is reached - the focus need to go to start from the opposite side |
||||||
|
return self._loopFocus(evt=evt, container=self) |
||||||
@ -0,0 +1,430 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
|
||||||
|
def test_add_widget_to_container(): |
||||||
|
''' |
||||||
|
Test that adding widgets to a container using addWidget() correctly sets the parent relationship. |
||||||
|
Verifies that widgets initially have no parent, and after being added to a container, |
||||||
|
their parentWidget() returns the container. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
container.addWidget(widget1) |
||||||
|
assert widget1.parentWidget() is container |
||||||
|
|
||||||
|
container.addWidget(widget2) |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
def test_add_widget_to_container_02(): |
||||||
|
''' |
||||||
|
Test that widgets added via parent= constructor parameter correctly establish |
||||||
|
the parent-child relationship immediately upon construction. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
def test_remove_widget_from_container(): |
||||||
|
''' |
||||||
|
Test that removing a widget from a container using removeWidget() correctly |
||||||
|
unsets the parent relationship, returning the widget to an orphaned state. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget = ttk.TTkWidget() |
||||||
|
|
||||||
|
container.addWidget(widget) |
||||||
|
assert widget.parentWidget() is container |
||||||
|
|
||||||
|
container.removeWidget(widget) |
||||||
|
assert widget.parentWidget() is None |
||||||
|
|
||||||
|
def test_remove_widget_from_container_02(): |
||||||
|
''' |
||||||
|
Test that removing a widget that was added via parent= constructor parameter |
||||||
|
correctly unsets the parent relationship. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget = ttk.TTkWidget(parent=container) |
||||||
|
|
||||||
|
assert widget.parentWidget() is container |
||||||
|
container.removeWidget(widget) |
||||||
|
assert widget.parentWidget() is None |
||||||
|
|
||||||
|
def test_gridlayout_add_remove(): |
||||||
|
''' |
||||||
|
Test :py:class:`TTkGridLayout` add/remove operations using container.layout().addWidget(). |
||||||
|
Verifies that widgets added to specific grid positions have their parent correctly set |
||||||
|
to the container, and that removing widgets unsets the parent relationship while |
||||||
|
preserving other widgets' parents. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
layout = ttk.TTkGridLayout() |
||||||
|
container.setLayout(layout) |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
widget3 = ttk.TTkWidget() |
||||||
|
|
||||||
|
# Add widgets to grid using container.layout() |
||||||
|
container.layout().addWidget(widget1, 0, 0) |
||||||
|
container.layout().addWidget(widget2, 0, 1) |
||||||
|
container.layout().addWidget(widget3, 1, 0) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
assert widget3.parentWidget() is container |
||||||
|
|
||||||
|
# Remove widget using container.layout() |
||||||
|
container.layout().removeWidget(widget2) |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget3.parentWidget() is container |
||||||
|
|
||||||
|
|
||||||
|
def test_hboxlayout_add_remove(): |
||||||
|
''' |
||||||
|
Test :py:class:`TTkHBoxLayout` add/remove operations using container.layout().addWidget(). |
||||||
|
Verifies that widgets are correctly parented when added sequentially, and that |
||||||
|
removing specific widgets from the middle of the layout updates their parent |
||||||
|
relationships while preserving others. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
layout = ttk.TTkHBoxLayout() |
||||||
|
container.setLayout(layout) |
||||||
|
|
||||||
|
widgets = [ttk.TTkWidget() for _ in range(4)] |
||||||
|
|
||||||
|
# Add all widgets using container.layout() |
||||||
|
for widget in widgets: |
||||||
|
container.layout().addWidget(widget) |
||||||
|
assert widget.parentWidget() is container |
||||||
|
|
||||||
|
# Remove middle widgets using container.layout() |
||||||
|
container.layout().removeWidget(widgets[1]) |
||||||
|
container.layout().removeWidget(widgets[2]) |
||||||
|
|
||||||
|
assert widgets[0].parentWidget() is container |
||||||
|
assert widgets[1].parentWidget() is None |
||||||
|
assert widgets[2].parentWidget() is None |
||||||
|
assert widgets[3].parentWidget() is container |
||||||
|
|
||||||
|
|
||||||
|
def test_vboxlayout_add_remove(): |
||||||
|
''' |
||||||
|
Test :py:class:`TTkVBoxLayout` add/remove operations using container.layout().addWidget(). |
||||||
|
Verifies parent relationships when adding button widgets vertically, and that |
||||||
|
removing the first widget correctly unsets its parent while preserving others. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
layout = ttk.TTkVBoxLayout() |
||||||
|
container.setLayout(layout) |
||||||
|
|
||||||
|
widget1 = ttk.TTkButton(text='Button 1') |
||||||
|
widget2 = ttk.TTkButton(text='Button 2') |
||||||
|
widget3 = ttk.TTkButton(text='Button 3') |
||||||
|
|
||||||
|
container.layout().addWidget(widget1) |
||||||
|
container.layout().addWidget(widget2) |
||||||
|
container.layout().addWidget(widget3) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
assert widget3.parentWidget() is container |
||||||
|
|
||||||
|
# Remove first widget using container.layout() |
||||||
|
container.layout().removeWidget(widget1) |
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
|
||||||
|
def test_nested_layouts(): |
||||||
|
''' |
||||||
|
Test parent relationships with nested layouts using container.layout().addWidget(). |
||||||
|
Verifies that when a container with its own layout is added to another container, |
||||||
|
the parent relationships form a proper hierarchy. Widgets remain parented to their |
||||||
|
immediate container even when that container is removed from the root. |
||||||
|
''' |
||||||
|
root = ttk.TTkContainer() |
||||||
|
root_layout = ttk.TTkVBoxLayout() |
||||||
|
root.setLayout(root_layout) |
||||||
|
|
||||||
|
# Create nested container |
||||||
|
nested = ttk.TTkContainer() |
||||||
|
nested_layout = ttk.TTkHBoxLayout() |
||||||
|
nested.setLayout(nested_layout) |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
# Add nested container to root using root.layout() |
||||||
|
root.layout().addWidget(nested) |
||||||
|
assert nested.parentWidget() is root |
||||||
|
|
||||||
|
# Add widgets to nested layout using nested.layout() |
||||||
|
nested.layout().addWidget(widget1) |
||||||
|
nested.layout().addWidget(widget2) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is nested |
||||||
|
assert widget2.parentWidget() is nested |
||||||
|
|
||||||
|
# Remove nested container using root.layout() |
||||||
|
root.layout().removeWidget(nested) |
||||||
|
assert nested.parentWidget() is None |
||||||
|
assert widget1.parentWidget() is nested # Still parented to nested |
||||||
|
|
||||||
|
|
||||||
|
def test_replace_widget_in_layout(): |
||||||
|
''' |
||||||
|
Test that replacing a widget in the same layout position correctly maintains |
||||||
|
parent relationships using container.layout() operations. The removed widget |
||||||
|
should have no parent, while the replacement widget should be parented to the container. |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
layout = ttk.TTkGridLayout() |
||||||
|
container.setLayout(layout) |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
container.layout().addWidget(widget1, 0, 0) |
||||||
|
assert widget1.parentWidget() is container |
||||||
|
|
||||||
|
# Replace widget1 with widget2 using container.layout() |
||||||
|
container.layout().removeWidget(widget1) |
||||||
|
container.layout().addWidget(widget2, 0, 0) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
|
||||||
|
def test_move_widget_between_containers(): |
||||||
|
''' |
||||||
|
Test that moving a widget between containers correctly updates the parent relationship. |
||||||
|
The widget should first be parented to the first container, then have no parent briefly, |
||||||
|
then be parented to the second container. |
||||||
|
''' |
||||||
|
container1 = ttk.TTkContainer() |
||||||
|
container2 = ttk.TTkContainer() |
||||||
|
widget = ttk.TTkWidget() |
||||||
|
|
||||||
|
container1.addWidget(widget) |
||||||
|
assert widget.parentWidget() is container1 |
||||||
|
|
||||||
|
# Move to second container |
||||||
|
container1.removeWidget(widget) |
||||||
|
container2.addWidget(widget) |
||||||
|
|
||||||
|
assert widget.parentWidget() is container2 |
||||||
|
|
||||||
|
|
||||||
|
def test_complex_layout_operations(): |
||||||
|
''' |
||||||
|
Test complex add/remove operations across multiple layout types using container.layout().addWidget(). |
||||||
|
Creates a hierarchy with :py:class:`TTkVBoxLayout`, :py:class:`TTkHBoxLayout`, and :py:class:`TTkGridLayout`. |
||||||
|
Verifies that all parent relationships are correctly maintained throughout the hierarchy, |
||||||
|
and that removing a section of the layout tree properly updates parent relationships. |
||||||
|
''' |
||||||
|
root = ttk.TTkContainer() |
||||||
|
vbox = ttk.TTkVBoxLayout() |
||||||
|
root.setLayout(vbox) |
||||||
|
|
||||||
|
# Create horizontal section |
||||||
|
hbox_container = ttk.TTkContainer() |
||||||
|
hbox = ttk.TTkHBoxLayout() |
||||||
|
hbox_container.setLayout(hbox) |
||||||
|
|
||||||
|
# Create grid section |
||||||
|
grid_container = ttk.TTkContainer() |
||||||
|
grid = ttk.TTkGridLayout() |
||||||
|
grid_container.setLayout(grid) |
||||||
|
|
||||||
|
widgets = [ttk.TTkButton(text=f'Btn{i}') for i in range(6)] |
||||||
|
|
||||||
|
# Add to vbox using root.layout() |
||||||
|
root.layout().addWidget(hbox_container) |
||||||
|
root.layout().addWidget(grid_container) |
||||||
|
|
||||||
|
# Add to hbox using hbox_container.layout() |
||||||
|
hbox_container.layout().addWidget(widgets[0]) |
||||||
|
hbox_container.layout().addWidget(widgets[1]) |
||||||
|
|
||||||
|
# Add to grid using grid_container.layout() |
||||||
|
grid_container.layout().addWidget(widgets[2], 0, 0) |
||||||
|
grid_container.layout().addWidget(widgets[3], 0, 1) |
||||||
|
grid_container.layout().addWidget(widgets[4], 1, 0) |
||||||
|
grid_container.layout().addWidget(widgets[5], 1, 1) |
||||||
|
|
||||||
|
# Verify all parents |
||||||
|
assert hbox_container.parentWidget() is root |
||||||
|
assert grid_container.parentWidget() is root |
||||||
|
assert widgets[0].parentWidget() is hbox_container |
||||||
|
assert widgets[1].parentWidget() is hbox_container |
||||||
|
assert widgets[2].parentWidget() is grid_container |
||||||
|
assert widgets[3].parentWidget() is grid_container |
||||||
|
|
||||||
|
# Remove grid section using root.layout() |
||||||
|
root.layout().removeWidget(grid_container) |
||||||
|
assert grid_container.parentWidget() is None |
||||||
|
assert widgets[2].parentWidget() is grid_container # Still parented to grid_container |
||||||
|
|
||||||
|
# Remove widgets from hbox using hbox_container.layout() |
||||||
|
hbox_container.layout().removeWidget(widgets[0]) |
||||||
|
assert widgets[0].parentWidget() is None |
||||||
|
assert widgets[1].parentWidget() is hbox_container |
||||||
|
|
||||||
|
def test_nested_layout_widgets_01(): |
||||||
|
''' |
||||||
|
Test that widgets added to a nested layout (one layout containing another) correctly |
||||||
|
inherit the parent from the container that owns the root layout. Widgets added to |
||||||
|
the nested layout should be parented to the container, not to the layout itself. |
||||||
|
''' |
||||||
|
layout1 = ttk.TTkLayout() |
||||||
|
layout2 = ttk.TTkLayout() |
||||||
|
|
||||||
|
layout1.addItem(layout2) |
||||||
|
|
||||||
|
container = ttk.TTkContainer(layout=layout1) |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
layout2.addWidget(widget1) |
||||||
|
assert widget1.parentWidget() is container |
||||||
|
|
||||||
|
layout2.addWidget(widget2) |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
def test_nested_layout_widgets_02(): |
||||||
|
''' |
||||||
|
Test that widgets added to a nested layout before the layout is attached to a container |
||||||
|
get their parent set correctly when setLayout() is called. Also verifies that removing |
||||||
|
the nested layout from the parent layout unsets the widgets' parents. |
||||||
|
''' |
||||||
|
layout1 = ttk.TTkLayout() |
||||||
|
layout2 = ttk.TTkLayout() |
||||||
|
|
||||||
|
layout1.addItem(layout2) |
||||||
|
|
||||||
|
container = ttk.TTkContainer() |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
layout2.addWidget(widget1) |
||||||
|
layout2.addWidget(widget2) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
container.setLayout(layout1) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
layout1.removeItem(layout2) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
def test_nested_layout_widgets_03(): |
||||||
|
''' |
||||||
|
Test that replacing a container's layout with a different layout correctly unsets |
||||||
|
the parent relationships for widgets in the old layout's hierarchy. Widgets in |
||||||
|
nested layouts should have their parents cleared when the root layout is replaced. |
||||||
|
''' |
||||||
|
layout1 = ttk.TTkLayout() |
||||||
|
layout2 = ttk.TTkLayout() |
||||||
|
layout3 = ttk.TTkLayout() |
||||||
|
|
||||||
|
layout1.addItem(layout2) |
||||||
|
|
||||||
|
container = ttk.TTkContainer() |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget() |
||||||
|
widget2 = ttk.TTkWidget() |
||||||
|
|
||||||
|
layout2.addWidget(widget1) |
||||||
|
layout2.addWidget(widget2) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
container.setLayout(layout1) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is container |
||||||
|
assert widget2.parentWidget() is container |
||||||
|
|
||||||
|
container.setLayout(layout3) |
||||||
|
|
||||||
|
assert widget1.parentWidget() is None |
||||||
|
assert widget2.parentWidget() is None |
||||||
|
|
||||||
|
def test_nested_layout_widgets_04(): |
||||||
|
''' |
||||||
|
Test complex parent relationships where a container with its own child widgets |
||||||
|
is added to a nested layout within another container. Verifies that the container |
||||||
|
maintains its parent relationship to its widgets, while also being correctly parented |
||||||
|
to the outer container. Removing the nested layout should only affect the intermediate |
||||||
|
container's parent, not the leaf widgets' relationship to their immediate parent. |
||||||
|
''' |
||||||
|
layout1 = ttk.TTkLayout() |
||||||
|
layout2 = ttk.TTkLayout() |
||||||
|
|
||||||
|
layout1.addItem(layout2) |
||||||
|
|
||||||
|
container1 = ttk.TTkContainer(layout=layout1) |
||||||
|
container2 = ttk.TTkContainer() |
||||||
|
|
||||||
|
widget1 = ttk.TTkWidget(parent=container2) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
|
||||||
|
assert container2.parentWidget() is None |
||||||
|
assert widget1.parentWidget() is container2 |
||||||
|
assert widget2.parentWidget() is container2 |
||||||
|
|
||||||
|
layout2.addWidget(container2) |
||||||
|
assert container2.parentWidget() is container1 |
||||||
|
assert widget1.parentWidget() is container2 |
||||||
|
assert widget2.parentWidget() is container2 |
||||||
|
|
||||||
|
layout1.removeItem(layout2) |
||||||
|
assert container2.parentWidget() is None |
||||||
|
assert widget1.parentWidget() is container2 |
||||||
|
assert widget2.parentWidget() is container2 |
||||||
|
|
||||||
@ -0,0 +1,202 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
def test_focus_01_no_root(): |
||||||
|
''' |
||||||
|
Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget3 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
widget3 = ttk.TTkWidget(parent=container) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.clearFocus() |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_01_with_root(): |
||||||
|
''' |
||||||
|
Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget3 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
widget3 = ttk.TTkWidget(parent=root) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.clearFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_02(): |
||||||
|
''' |
||||||
|
Root ─▶ Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container = ttk.TTkContainer(parent=root) |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
widget3 = ttk.TTkWidget(parent=container) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.clearFocus() |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_03_sequential(): |
||||||
|
'''Test sequential focus changes between widgets''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
widget3 = ttk.TTkWidget(parent=root) |
||||||
|
|
||||||
|
widget1.setFocus() |
||||||
|
assert False is root.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget3.setFocus() |
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_04_nested_containers(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 ─┬─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
widget1.setFocus() |
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_05_multiple_setFocus(): |
||||||
|
'''Test calling setFocus multiple times on same widget''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
|
||||||
|
widget1.setFocus() |
||||||
|
widget1.setFocus() |
||||||
|
assert (widget1.hasFocus(), widget2.hasFocus()) == (True, False) |
||||||
|
|
||||||
|
def test_focus_06_clearFocus_without_focus(): |
||||||
|
'''Test clearFocus on widget that doesn't have focus''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
|
||||||
|
widget1.setFocus() |
||||||
|
widget2.clearFocus() |
||||||
|
assert (widget1.hasFocus(), widget2.hasFocus()) == (True, False) |
||||||
|
|
||||||
|
def test_focus_07_single_widget(): |
||||||
|
'''Test focus behavior with single widget''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget = ttk.TTkWidget(parent=root) |
||||||
|
|
||||||
|
assert (root.hasFocus(), widget.hasFocus()) == (False, False) |
||||||
|
|
||||||
|
widget.setFocus() |
||||||
|
assert (root.hasFocus(), widget.hasFocus()) == (False, True) |
||||||
|
|
||||||
|
widget.clearFocus() |
||||||
|
assert (root.hasFocus(), widget.hasFocus()) == (False, False) |
||||||
@ -0,0 +1,113 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
|
||||||
|
def test_next_prev_widget_01(): |
||||||
|
''' |
||||||
|
Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
container = ttk.TTkContainer() |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
widget3 = ttk.TTkWidget(parent=container) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
# Forward |
||||||
|
ff = container._getFirstFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget1 |
||||||
|
ff = container._getFirstFocus(widget=widget1, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget2 |
||||||
|
ff = container._getFirstFocus(widget=widget2, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget3 |
||||||
|
ff = container._getFirstFocus(widget=widget3, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is None |
||||||
|
|
||||||
|
# Reverse |
||||||
|
ff = container._getLastFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget3 |
||||||
|
ff = container._getLastFocus(widget=widget3, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget2 |
||||||
|
ff = container._getLastFocus(widget=widget2, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget1 |
||||||
|
ff = container._getLastFocus(widget=widget1, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is None |
||||||
|
|
||||||
|
def test_next_prev_widget_02_nested(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 ─┬─▶ Widget2 |
||||||
|
├─▶ Widget3 |
||||||
|
└─▶ Widget4 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
widget4 = ttk.TTkWidget(parent=container2) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget4.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
# Forward |
||||||
|
ff = container1._getFirstFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget1 |
||||||
|
ff = container2._getFirstFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget2 |
||||||
|
|
||||||
|
ff = container1._getFirstFocus(widget=widget1, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget2 |
||||||
|
|
||||||
|
ff = container2._getFirstFocus(widget=widget2, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget3 |
||||||
|
ff = container2._getFirstFocus(widget=widget3, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget4 |
||||||
|
ff = container2._getFirstFocus(widget=widget4, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is None |
||||||
|
|
||||||
|
# Reverse |
||||||
|
ff = container1._getLastFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget4 |
||||||
|
ff = container2._getLastFocus(widget=None, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget4 |
||||||
|
|
||||||
|
ff = container1._getLastFocus(widget=widget1, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is None |
||||||
|
|
||||||
|
ff = container2._getLastFocus(widget=widget4, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget3 |
||||||
|
ff = container2._getLastFocus(widget=widget3, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is widget2 |
||||||
|
ff = container2._getLastFocus(widget=widget2, focusPolicy=ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
assert ff is None |
||||||
|
|
||||||
@ -0,0 +1,556 @@ |
|||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
|
||||||
|
def test_focus_01_tab(): |
||||||
|
''' |
||||||
|
Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
widget3 = ttk.TTkWidget(parent=root) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.NoModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_01_tab_reverse(): |
||||||
|
''' |
||||||
|
Container ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
widget1 = ttk.TTkWidget(parent=root) |
||||||
|
widget2 = ttk.TTkWidget(parent=root) |
||||||
|
widget3 = ttk.TTkWidget(parent=root) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.ShiftModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_04_nested_containers(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 ─┬─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.NoModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_04_nested_containers_reversed(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 ─┬─▶ Widget2 |
||||||
|
├─▶ Widget3 |
||||||
|
└─▶ Widget4 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
widget4 = ttk.TTkWidget(parent=container2) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget4.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget3.setFocus() |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.ShiftModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert True is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is root.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
def test_focus_container_with_tab_focus(): |
||||||
|
''' |
||||||
|
Container (TabFocus) ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container = ttk.TTkContainer(parent=root) |
||||||
|
container.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
widget3 = ttk.TTkWidget(parent=container) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
container.setFocus() |
||||||
|
|
||||||
|
assert True is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.NoModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert True is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_nested_containers_with_tab_focus(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 (TabFocus) ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 (TabFocus) ─┬─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
container1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
container2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
container1.setFocus() |
||||||
|
|
||||||
|
assert True is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.NoModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert True is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_nested_containers_with_tab_focus_reversed(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 (TabFocus) ─┬─▶ Widget1 |
||||||
|
└─▶ Container2 (TabFocus) ─┬─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(name='container1', parent=root) |
||||||
|
widget1 = ttk.TTkWidget(name='widget1', parent=container1) |
||||||
|
container2 = ttk.TTkContainer(name='container2', parent=container1) |
||||||
|
widget2 = ttk.TTkWidget(name='widget2', parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(name='widget3', parent=container2) |
||||||
|
container1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
container2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.ShiftModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert True is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container1.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
def test_focus_mixed_containers_tab_focus(): |
||||||
|
''' |
||||||
|
Root ─▶ Container1 (No TabFocus) ─┬─▶ Widget1 |
||||||
|
├─▶ Container2 (TabFocus) ─┬─▶ Widget2 |
||||||
|
│ └─▶ Widget3 |
||||||
|
└─▶ Widget4 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container1 = ttk.TTkContainer(parent=root) |
||||||
|
widget1 = ttk.TTkWidget(parent=container1) |
||||||
|
container2 = ttk.TTkContainer(parent=container1) |
||||||
|
container2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2 = ttk.TTkWidget(parent=container2) |
||||||
|
widget3 = ttk.TTkWidget(parent=container2) |
||||||
|
widget4 = ttk.TTkWidget(parent=container1) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget4.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget1.setFocus() |
||||||
|
|
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.NoModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert True is widget4.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is container2.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
assert False is widget4.hasFocus() |
||||||
|
|
||||||
|
def test_focus_container_tab_focus_reversed(): |
||||||
|
''' |
||||||
|
Container (TabFocus) ─┬─▶ Widget1 |
||||||
|
├─▶ Widget2 |
||||||
|
└─▶ Widget3 |
||||||
|
''' |
||||||
|
root = ttk.TTk() |
||||||
|
container = ttk.TTkContainer(parent=root) |
||||||
|
container.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget1 = ttk.TTkWidget(parent=container) |
||||||
|
widget2 = ttk.TTkWidget(parent=container) |
||||||
|
widget3 = ttk.TTkWidget(parent=container) |
||||||
|
widget1.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget2.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
widget3.setFocusPolicy(ttk.TTkK.FocusPolicy.TabFocus) |
||||||
|
|
||||||
|
widget2.setFocus() |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
tab_key = ttk.TTkKeyEvent( |
||||||
|
type=ttk.TTkK.KeyType.SpecialKey, |
||||||
|
key=ttk.TTkK.Key_Tab, |
||||||
|
mod=ttk.TTkK.ShiftModifier, |
||||||
|
code='',) |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert True is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert True is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert False is widget2.hasFocus() |
||||||
|
assert True is widget3.hasFocus() |
||||||
|
|
||||||
|
root.keyEvent(evt=tab_key) |
||||||
|
|
||||||
|
assert False is container.hasFocus() |
||||||
|
assert False is widget1.hasFocus() |
||||||
|
assert True is widget2.hasFocus() |
||||||
|
assert False is widget3.hasFocus() |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
|
||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
|
||||||
|
class MovementContainer(ttk.TTkContainer): |
||||||
|
def __init__(self, *, widget=ttk.TTkWidget, **kwargs): |
||||||
|
super().__init__(**kwargs) |
||||||
|
self.layout().addWidget(widget=widget) |
||||||
|
widget.sizeChanged.connect(self._sizeChanged) |
||||||
|
# widget.positionChanged.connect(self._positionChanged) |
||||||
|
|
||||||
|
|
||||||
|
@ttk.pyTTkSlot(int,int) |
||||||
|
def _sizeChanged(self,w,h): |
||||||
|
self.resize(w,h) |
||||||
|
|
||||||
|
@ttk.pyTTkSlot(int,int) |
||||||
|
def _positionChanged(self,x,y): |
||||||
|
ox,oy = self.layout().offset() |
||||||
|
self.layout().setOffset(-x,-y) |
||||||
|
self.move(x,y) |
||||||
|
|
||||||
|
def paintEvent(self, canvas): |
||||||
|
canvas.fill(color=ttk.TTkColor.BG_RED) |
||||||
|
|
||||||
|
root = ttk.TTk() |
||||||
|
|
||||||
|
win = ttk.TTkWindow(size=(40,15)) |
||||||
|
frame = ttk.TTkResizableFrame(size=(40,15), border=True) |
||||||
|
|
||||||
|
mcWin = MovementContainer(widget=win, parent=root, pos=(10,5), size=(40,15)) |
||||||
|
mcFrame = MovementContainer(widget=frame, parent=root, pos=(5,2), size=(40,15)) |
||||||
|
|
||||||
|
|
||||||
|
root.mainloop() |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2025 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
|
||||||
|
class TryModal(ttk.TTkWindow): |
||||||
|
def __init__(self, **kwargs): |
||||||
|
super().__init__(**kwargs) |
||||||
|
overlay_btn = ttk.TTkButton(parent=self, pos=(0,0), size=(15,3), border=True, text='Overlay') |
||||||
|
modal_btn = ttk.TTkButton(parent=self, pos=(0,3), size=(15,3), border=True, text='Modal') |
||||||
|
toolbox_btn = ttk.TTkButton(parent=self, pos=(0,6), size=(15,3), border=True, text='Toolbox') |
||||||
|
|
||||||
|
def _overlay(): |
||||||
|
win = TryModal(size=(30,13), title="Overlay") |
||||||
|
ttk.TTkHelper.overlay( |
||||||
|
caller=overlay_btn, |
||||||
|
widget=win, |
||||||
|
x=0,y=0) |
||||||
|
overlay_btn.clicked.connect(_overlay) |
||||||
|
|
||||||
|
def _modal(): |
||||||
|
win = TryModal(size=(30,13), title="Modal") |
||||||
|
ttk.TTkHelper.overlay( |
||||||
|
caller=modal_btn, |
||||||
|
widget=win, |
||||||
|
modal=True, |
||||||
|
x=0,y=0) |
||||||
|
modal_btn.clicked.connect(_modal) |
||||||
|
|
||||||
|
def _toolbox(): |
||||||
|
win = TryModal(size=(30,13), title="Toolbox") |
||||||
|
ttk.TTkHelper.overlay( |
||||||
|
caller=toolbox_btn, |
||||||
|
widget=win, |
||||||
|
toolWindow=True, |
||||||
|
x=0,y=0) |
||||||
|
toolbox_btn.clicked.connect(_toolbox) |
||||||
|
|
||||||
|
root = ttk.TTk() |
||||||
|
|
||||||
|
TryModal(parent=root, pos=(5,2), size=(30,13), title="Root") |
||||||
|
|
||||||
|
root.mainloop() |
||||||
|
|
||||||
@ -0,0 +1,46 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
|
||||||
|
# MIT License |
||||||
|
# |
||||||
|
# Copyright (c) 2021 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 sys, os |
||||||
|
|
||||||
|
sys.path.append(os.path.join(sys.path[0],'../../libs/pyTermTk')) |
||||||
|
import TermTk as ttk |
||||||
|
|
||||||
|
ttk.TTkLog.use_default_file_logging() |
||||||
|
|
||||||
|
root = ttk.TTk() |
||||||
|
|
||||||
|
win1 = ttk.TTkWindow(parent=root, title='1', pos=( 0,0), size=(40,10), border=True) |
||||||
|
win2 = ttk.TTkWindow(parent=root, title='2', pos=(20,3), size=(40,15), border=True) |
||||||
|
win3 = ttk.TTkWindow(parent=win2, title='3', pos=( 0,0), size=(30,10), border=True) |
||||||
|
win4 = ttk.TTkWindow(parent=win2, title='4', pos=( 5,4), size=(30,5), border=True) |
||||||
|
win5 = ttk.TTkWindow(parent=win3, title='5', pos=( 0,0), size=(20,5), border=True) |
||||||
|
|
||||||
|
win1.setFocusPolicy(ttk.TTkK.TabFocus | ttk.TTkK.ClickFocus) |
||||||
|
win2.setFocusPolicy(ttk.TTkK.TabFocus | ttk.TTkK.ClickFocus) |
||||||
|
win3.setFocusPolicy(ttk.TTkK.TabFocus | ttk.TTkK.ClickFocus) |
||||||
|
win4.setFocusPolicy(ttk.TTkK.TabFocus | ttk.TTkK.ClickFocus) |
||||||
|
win5.setFocusPolicy(ttk.TTkK.TabFocus | ttk.TTkK.ClickFocus) |
||||||
|
|
||||||
|
root.mainloop() |
||||||
Loading…
Reference in new issue