You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

430 lines
15 KiB

# 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.layout().addWidget(widget1)
assert widget1.parentWidget() is container
container.layout().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.layout().addWidget(widget)
assert widget.parentWidget() is container
container.layout().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.layout().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.layout().addWidget(widget)
assert widget.parentWidget() is container1
# Move to second container
container1.layout().removeWidget(widget)
container2.layout().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