10 changed files with 1807 additions and 250 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,595 @@
|
||||
# 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 |
||||
from TermTk.TTkWidgets.kodetab import _TTkKodeTab |
||||
from TermTk.TTkWidgets.tabwidget import _TTkTabWidgetDragData, _TTkNewTabWidgetDragData |
||||
from TermTk.TTkGui.drag import TTkDnDEvent |
||||
|
||||
# ============================================================================ |
||||
# TTkKodeTab Basic Tests |
||||
# ============================================================================ |
||||
|
||||
def test_kodetab_initialization(): |
||||
''' |
||||
Test that TTkKodeTab initializes correctly. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
assert kodeTab is not None |
||||
assert isinstance(kodeTab, ttk.TTkSplitter) |
||||
|
||||
# Should have at least one internal _TTkKodeTab widget |
||||
first_widget = kodeTab._getFirstWidget() |
||||
assert first_widget is not None |
||||
assert isinstance(first_widget, _TTkKodeTab) |
||||
|
||||
def test_kodetab_add_single_tab(): |
||||
''' |
||||
Test adding a single tab to TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
|
||||
index = kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
assert index == 0 |
||||
assert kodeTab._lastKodeTabWidget.count() == 1 |
||||
assert kodeTab._lastKodeTabWidget.widget(0) == widget |
||||
|
||||
def test_kodetab_add_multiple_tabs(): |
||||
''' |
||||
Test adding multiple tabs to TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget3 = ttk.TTkWidget() |
||||
|
||||
index1 = kodeTab.addTab(widget1, "Tab 1") |
||||
index2 = kodeTab.addTab(widget2, "Tab 2") |
||||
index3 = kodeTab.addTab(widget3, "Tab 3") |
||||
|
||||
assert index1 == 0 |
||||
assert index2 == 1 |
||||
assert index3 == 2 |
||||
assert kodeTab._lastKodeTabWidget.count() == 3 |
||||
|
||||
def test_kodetab_add_tab_with_data(): |
||||
''' |
||||
Test adding tabs with associated data. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1", data="data1") |
||||
kodeTab.addTab(widget2, "Tab 2", data={"key": "value"}) |
||||
|
||||
assert kodeTab._lastKodeTabWidget.tabData(0) == "data1" |
||||
assert kodeTab._lastKodeTabWidget.tabData(1) == {"key": "value"} |
||||
|
||||
def test_kodetab_set_current_widget(): |
||||
''' |
||||
Test setting the current widget in TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget3 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
kodeTab.addTab(widget3, "Tab 3") |
||||
|
||||
kodeTab.setCurrentWidget(widget2) |
||||
assert kodeTab._lastKodeTabWidget.currentWidget() == widget2 |
||||
|
||||
kodeTab.setCurrentWidget(widget3) |
||||
assert kodeTab._lastKodeTabWidget.currentWidget() == widget3 |
||||
|
||||
def test_kodetab_iter_items(): |
||||
''' |
||||
Test iterating over all tabs in TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget3 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
kodeTab.addTab(widget3, "Tab 3") |
||||
|
||||
items = list(kodeTab.iterItems()) |
||||
|
||||
assert len(items) == 3 |
||||
for tab_widget, index in items: |
||||
assert isinstance(tab_widget, _TTkKodeTab) |
||||
assert 0 <= index < tab_widget.count() |
||||
|
||||
def test_kodetab_signals(): |
||||
''' |
||||
Test that TTkKodeTab signals are emitted correctly. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
current_changed_called = [] |
||||
tab_clicked_called = [] |
||||
tab_added_called = [] |
||||
|
||||
kodeTab.currentChanged.connect( |
||||
lambda tw, i, w, d: current_changed_called.append((tw, i, w, d)) |
||||
) |
||||
kodeTab.tabBarClicked.connect( |
||||
lambda tw, i, w, d: tab_clicked_called.append((tw, i, w, d)) |
||||
) |
||||
kodeTab.tabAdded.connect( |
||||
lambda tw, i: tab_added_called.append((tw, i)) |
||||
) |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
assert len(tab_added_called) == 1 |
||||
assert len(current_changed_called) == 1 |
||||
|
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
assert len(tab_added_called) == 2 |
||||
|
||||
def test_kodetab_close_requested_signal(): |
||||
''' |
||||
Test that kodeTabCloseRequested signal is emitted correctly. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab(closable=True) |
||||
|
||||
close_requested_called = [] |
||||
kodeTab.kodeTabCloseRequested.connect( |
||||
lambda tw, i: close_requested_called.append((tw, i)) |
||||
) |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
|
||||
# Simulate close request |
||||
kodeTab._lastKodeTabWidget._handleTabCloseRequested(0) |
||||
|
||||
assert len(close_requested_called) == 1 |
||||
assert close_requested_called[0][1] == 0 |
||||
|
||||
# ============================================================================ |
||||
# TTkKodeTab Remove/Close Tests |
||||
# ============================================================================ |
||||
|
||||
def test_kodetab_remove_tab(): |
||||
''' |
||||
Test removing tabs from the internal tab widget. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget3 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
kodeTab.addTab(widget3, "Tab 3") |
||||
|
||||
assert kodeTab._lastKodeTabWidget.count() == 3 |
||||
|
||||
kodeTab._lastKodeTabWidget.removeTab(1) |
||||
|
||||
assert kodeTab._lastKodeTabWidget.count() == 2 |
||||
assert kodeTab._lastKodeTabWidget.widget(0) == widget1 |
||||
assert kodeTab._lastKodeTabWidget.widget(1) == widget3 |
||||
|
||||
def test_kodetab_remove_all_tabs(): |
||||
''' |
||||
Test removing all tabs triggers cleanup of empty widgets. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
internal_tab.removeTab(0) |
||||
internal_tab.removeTab(0) |
||||
|
||||
# Should still have the base internal tab widget |
||||
assert kodeTab.count() >= 0 |
||||
|
||||
def test_kodetab_kode_tab_closed(): |
||||
''' |
||||
Test _kodeTabClosed cleanup logic. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Remove the tab |
||||
internal_tab.removeTab(0) |
||||
|
||||
# Trigger cleanup |
||||
internal_tab._kodeTabClosed() |
||||
|
||||
# Verify state |
||||
assert isinstance(kodeTab._getFirstWidget(), _TTkKodeTab) |
||||
|
||||
# ============================================================================ |
||||
# TTkKodeTab Drag and Drop Tests |
||||
# ============================================================================ |
||||
|
||||
def test_kodetab_drag_enter_event(): |
||||
''' |
||||
Test drag enter event handling. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Create a mock drag event |
||||
evt = TTkDnDEvent(pos=(5,5), data=None) |
||||
|
||||
# Test drag enter |
||||
result = internal_tab.dragEnterEvent(evt) |
||||
assert result is True |
||||
|
||||
def test_kodetab_drag_leave_event(): |
||||
''' |
||||
Test drag leave event handling. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
internal_tab._frameOverlay = (0, 0, 10, 10) |
||||
|
||||
evt = TTkDnDEvent(pos=(5,5), data=None) |
||||
|
||||
result = internal_tab.dragLeaveEvent(evt) |
||||
assert result is True |
||||
assert internal_tab._frameOverlay is None |
||||
|
||||
def test_kodetab_drop_event_new_tab_data(): |
||||
''' |
||||
Test dropping new tab data onto TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget1 = ttk.TTkWidget() |
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Create new tab drag data |
||||
new_widget = ttk.TTkWidget() |
||||
drag_data = _TTkNewTabWidgetDragData("New Tab", new_widget, data="test_data") |
||||
|
||||
# Create drop event in center (should add to existing tab bar) |
||||
evt = TTkDnDEvent(pos=(50,25), data=drag_data) |
||||
|
||||
result = internal_tab.dropEvent(evt) |
||||
|
||||
# Verify drop was handled |
||||
assert result in (True, False) # Depends on implementation details |
||||
|
||||
# def test_kodetab_drop_event_tab_widget_data(): |
||||
# ''' |
||||
# Test dropping tab from another widget. |
||||
# ''' |
||||
# kodeTab1 = ttk.TTkKodeTab() |
||||
# kodeTab2 = ttk.TTkKodeTab() |
||||
|
||||
# widget1 = ttk.TTkWidget() |
||||
# widget2 = ttk.TTkWidget() |
||||
|
||||
# kodeTab1.addTab(widget1, "Tab 1") |
||||
# kodeTab2.addTab(widget2, "Tab 2") |
||||
|
||||
# internal_tab1 = kodeTab1._lastKodeTabWidget |
||||
# internal_tab2 = kodeTab2._lastKodeTabWidget |
||||
|
||||
# # Get the tab button to drag |
||||
# button = internal_tab2.tabButton(0) |
||||
|
||||
# # Create drag data |
||||
# drag_data = _TTkTabWidgetDragData(button, internal_tab2) |
||||
|
||||
# # Drop in center |
||||
# evt = TTkDnDEvent(pos=(50,25), data=drag_data) |
||||
|
||||
# result = internal_tab1.dropEvent(evt) |
||||
|
||||
# # Verify handling occurred |
||||
# assert result in (True, False) |
||||
|
||||
def test_kodetab_drop_event_list_of_new_tabs(): |
||||
''' |
||||
Test dropping a list of new tabs. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget1 = ttk.TTkWidget() |
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Create list of new tab data |
||||
new_widget1 = ttk.TTkWidget() |
||||
new_widget2 = ttk.TTkWidget() |
||||
|
||||
drag_data_list = [ |
||||
_TTkNewTabWidgetDragData("New Tab 1", new_widget1), |
||||
_TTkNewTabWidgetDragData("New Tab 2", new_widget2) |
||||
] |
||||
|
||||
# Drop in center |
||||
evt = TTkDnDEvent(pos=(50,25), data=drag_data_list) |
||||
|
||||
result = internal_tab.dropEvent(evt) |
||||
|
||||
assert result in (True, False) |
||||
|
||||
def test_kodetab_drop_creates_horizontal_split(): |
||||
''' |
||||
Test that dropping on left/right zones creates horizontal splits. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget1 = ttk.TTkWidget() |
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Mock size for positioning |
||||
internal_tab._size = (100, 50) |
||||
|
||||
new_widget = ttk.TTkWidget() |
||||
drag_data = _TTkNewTabWidgetDragData("New Tab", new_widget) |
||||
|
||||
# Drop on left zone (x < w/4) |
||||
evt = TTkDnDEvent(pos=(10,25), data=drag_data) |
||||
|
||||
initial_count = kodeTab.count() |
||||
result = internal_tab.dropEvent(evt) |
||||
|
||||
# A split may have been created |
||||
# Exact behavior depends on implementation |
||||
assert kodeTab.count() >= initial_count |
||||
|
||||
def test_kodetab_drop_creates_vertical_split(): |
||||
''' |
||||
Test that dropping on top/bottom zones creates vertical splits. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget1 = ttk.TTkWidget() |
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Mock size |
||||
internal_tab._size = (100, 50) |
||||
|
||||
new_widget = ttk.TTkWidget() |
||||
drag_data = _TTkNewTabWidgetDragData("New Tab", new_widget) |
||||
|
||||
# Drop on top zone (y < h/4, adjusted for tab bar) |
||||
evt = TTkDnDEvent(pos=(50,5), data=drag_data) |
||||
|
||||
initial_count = kodeTab.count() |
||||
result = internal_tab.dropEvent(evt) |
||||
|
||||
assert kodeTab.count() >= initial_count |
||||
|
||||
def test_kodetab_set_drop_event_proxy(): |
||||
''' |
||||
Test setting drop event proxy propagates to internal widgets. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
proxy_called = [] |
||||
|
||||
def proxy(evt): |
||||
proxy_called.append(evt) |
||||
return True |
||||
|
||||
kodeTab.setDropEventProxy(proxy) |
||||
|
||||
# Verify proxy is set |
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
assert internal_tab._dropEventProxy == proxy |
||||
|
||||
# ============================================================================ |
||||
# TTkKodeTab Complex Scenarios |
||||
# ============================================================================ |
||||
|
||||
def test_kodetab_multiple_splits(): |
||||
''' |
||||
Test creating multiple splits through tab operations. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
|
||||
# Count all tab items |
||||
items_before = list(kodeTab.iterItems()) |
||||
assert len(items_before) == 2 |
||||
|
||||
def test_kodetab_get_first_widget(): |
||||
''' |
||||
Test getting the first internal widget. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
first = kodeTab._getFirstWidget() |
||||
assert isinstance(first, _TTkKodeTab) |
||||
assert first._baseWidget == kodeTab |
||||
|
||||
def test_kodetab_has_menu(): |
||||
''' |
||||
Test checking if internal tab has menu. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Initially should not have menu |
||||
assert internal_tab._hasMenu() is False |
||||
|
||||
def test_kodetab_add_menu(): |
||||
''' |
||||
Test adding menu to TTkKodeTab. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
# Add a menu item |
||||
menu_item = kodeTab.addMenu("File", data="file_data") |
||||
|
||||
assert menu_item is not None |
||||
|
||||
def test_kodetab_bar_type(): |
||||
''' |
||||
Test different bar types for TTkKodeTab. |
||||
''' |
||||
from TermTk.TTkWidgets.tabwidget import TTkBarType |
||||
|
||||
kodeTab1 = ttk.TTkKodeTab(barType=TTkBarType.DEFAULT_3) |
||||
kodeTab2 = ttk.TTkKodeTab(barType=TTkBarType.NERD_1) |
||||
|
||||
assert kodeTab1._barType == TTkBarType.DEFAULT_3 |
||||
assert kodeTab2._barType == TTkBarType.NERD_1 |
||||
|
||||
def test_kodetab_empty_after_all_removals(): |
||||
''' |
||||
Test that TTkKodeTab handles becoming empty gracefully. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
kodeTab.addTab(widget1, "Tab 1") |
||||
kodeTab.addTab(widget2, "Tab 2") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Remove all tabs |
||||
internal_tab.removeTab(0) |
||||
internal_tab.removeTab(0) |
||||
|
||||
# Trigger cleanup |
||||
internal_tab._kodeTabClosed() |
||||
|
||||
# Should still be in valid state |
||||
assert kodeTab._getFirstWidget() is not None |
||||
|
||||
def test_kodetab_paint_child_canvas(): |
||||
''' |
||||
Test that paintChildCanvas handles frame overlay correctly. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Set frame overlay |
||||
internal_tab._frameOverlay = (10, 10, 50, 30) |
||||
|
||||
# Call paintChildCanvas (should not raise) |
||||
try: |
||||
internal_tab.paintChildCanvas() |
||||
assert True |
||||
except Exception as e: |
||||
assert False, f"paintChildCanvas raised exception: {e}" |
||||
|
||||
# Clear overlay |
||||
internal_tab._frameOverlay = None |
||||
internal_tab.paintChildCanvas() |
||||
|
||||
def test_kodetab_drop_invalid_data(): |
||||
''' |
||||
Test that dropping invalid data returns False. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
widget = ttk.TTkWidget() |
||||
kodeTab.addTab(widget, "Tab 1") |
||||
|
||||
internal_tab = kodeTab._lastKodeTabWidget |
||||
|
||||
# Create event with invalid data |
||||
evt = TTkDnDEvent(pos=(50,25), data="invalid_data") |
||||
|
||||
result = internal_tab.dropEvent(evt) |
||||
|
||||
# Should not accept invalid data |
||||
assert result is False |
||||
|
||||
def test_kodetab_iter_items_after_operations(): |
||||
''' |
||||
Test that iterItems works correctly after add/remove operations. |
||||
''' |
||||
kodeTab = ttk.TTkKodeTab() |
||||
|
||||
widgets = [ttk.TTkWidget() for _ in range(5)] |
||||
|
||||
for i, widget in enumerate(widgets): |
||||
kodeTab.addTab(widget, f"Tab {i}") |
||||
|
||||
items = list(kodeTab.iterItems()) |
||||
assert len(items) == 5 |
||||
|
||||
# Remove some tabs |
||||
kodeTab._lastKodeTabWidget.removeTab(2) |
||||
kodeTab._lastKodeTabWidget.removeTab(1) |
||||
|
||||
items = list(kodeTab.iterItems()) |
||||
assert len(items) == 3 |
||||
@ -0,0 +1,666 @@
|
||||
# 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 |
||||
|
||||
# ============================================================================ |
||||
# TTkTabBar Tests |
||||
# ============================================================================ |
||||
|
||||
def test_tabbar_add_tabs(): |
||||
''' |
||||
Test adding tabs to TTkTabBar using addTab(). |
||||
Verifies that tabs are added correctly and currentIndex is updated. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
assert tabBar.currentIndex() == -1 |
||||
|
||||
index0 = tabBar.addTab("Tab 1") |
||||
assert index0 == 0 |
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
index1 = tabBar.addTab("Tab 2", data="data2") |
||||
assert index1 == 1 |
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
index2 = tabBar.addTab("Tab 3") |
||||
assert index2 == 2 |
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
def test_tabbar_insert_tabs(): |
||||
''' |
||||
Test inserting tabs at specific positions in TTkTabBar. |
||||
Verifies that tabs are inserted at correct indices and currentIndex is adjusted. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 1") |
||||
tabBar.addTab("Tab 2") |
||||
tabBar.addTab("Tab 3") |
||||
|
||||
# Insert at beginning |
||||
index = tabBar.insertTab(0, "Tab 0") |
||||
assert index == 0 |
||||
assert tabBar.currentIndex() == 1 # Current should shift |
||||
|
||||
# Insert in middle |
||||
index = tabBar.insertTab(2, "Tab 1.5") |
||||
assert index == 2 |
||||
assert tabBar.currentIndex() == 1 # Current shouldn't change |
||||
|
||||
def test_tabbar_remove_tabs(): |
||||
''' |
||||
Test removing tabs from TTkTabBar. |
||||
Verifies that tabs are removed correctly and currentIndex is adjusted. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
tabBar.addTab("Tab 1") |
||||
tabBar.addTab("Tab 2") |
||||
tabBar.addTab("Tab 3") |
||||
|
||||
tabBar.setCurrentIndex(2) |
||||
assert tabBar.currentIndex() == 2 |
||||
|
||||
# Remove tab before current |
||||
tabBar.removeTab(0) |
||||
assert tabBar.currentIndex() == 1 # Should decrement |
||||
|
||||
# Remove current tab |
||||
tabBar.removeTab(1) |
||||
assert tabBar.currentIndex() == 0 # Should stay but point to next tab |
||||
|
||||
# Remove last tab |
||||
tabBar.removeTab(1) |
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
def test_tabbar_tab_data(): |
||||
''' |
||||
Test setting and getting tab data. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 1", data="data1") |
||||
tabBar.addTab("Tab 2", data={"key": "value"}) |
||||
tabBar.addTab("Tab 3") |
||||
|
||||
assert tabBar.tabData(0) == "data1" |
||||
assert tabBar.tabData(1) == {"key": "value"} |
||||
assert tabBar.tabData(2) is None |
||||
|
||||
# Test setTabData |
||||
tabBar.setTabData(2, "new_data") |
||||
assert tabBar.tabData(2) == "new_data" |
||||
|
||||
# Test currentData |
||||
tabBar.setCurrentIndex(1) |
||||
assert tabBar.currentData() == {"key": "value"} |
||||
|
||||
def test_tabbar_current_index(): |
||||
''' |
||||
Test setting and getting current index. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
tabBar.addTab("Tab 1") |
||||
tabBar.addTab("Tab 2") |
||||
|
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
tabBar.setCurrentIndex(1) |
||||
assert tabBar.currentIndex() == 1 |
||||
|
||||
tabBar.setCurrentIndex(2) |
||||
assert tabBar.currentIndex() == 2 |
||||
|
||||
# Test invalid index (should not change) |
||||
tabBar.setCurrentIndex(10) |
||||
assert tabBar.currentIndex() == 2 |
||||
|
||||
tabBar.setCurrentIndex(-1) |
||||
assert tabBar.currentIndex() == 2 |
||||
|
||||
def test_tabbar_signals(): |
||||
''' |
||||
Test that signals are emitted correctly. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
current_changed_called = [] |
||||
tab_clicked_called = [] |
||||
tab_close_called = [] |
||||
|
||||
tabBar.currentChanged.connect(lambda i: current_changed_called.append(i)) |
||||
tabBar.tabBarClicked.connect(lambda i: tab_clicked_called.append(i)) |
||||
tabBar.tabCloseRequested.connect(lambda i: tab_close_called.append(i)) |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
assert len(current_changed_called) == 1 |
||||
assert current_changed_called[0] == 0 |
||||
|
||||
tabBar.addTab("Tab 1") |
||||
tabBar.setCurrentIndex(1) |
||||
assert len(current_changed_called) == 2 |
||||
assert current_changed_called[1] == 1 |
||||
|
||||
def test_tabbar_closable_tabs(): |
||||
''' |
||||
Test closable tabs functionality. |
||||
''' |
||||
tabBar = ttk.TTkTabBar(closable=True) |
||||
|
||||
assert tabBar.tabsClosable() is True |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
tabBar.addTab("Tab 1", closable=False) # Override for this tab |
||||
tabBar.addTab("Tab 2") |
||||
|
||||
# Test that tabs can be added with different closable settings |
||||
button0 = tabBar.tabButton(0) |
||||
button1 = tabBar.tabButton(1) |
||||
button2 = tabBar.tabButton(2) |
||||
|
||||
assert button0 is not None |
||||
assert button1 is not None |
||||
assert button2 is not None |
||||
|
||||
# ============================================================================ |
||||
# TTkTabWidget Tests |
||||
# ============================================================================ |
||||
|
||||
def test_tabwidget_add_tabs(): |
||||
''' |
||||
Test adding tabs to TTkTabWidget with widgets. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
assert tabWidget.count() == 0 |
||||
assert tabWidget.currentIndex() == -1 |
||||
|
||||
index0 = tabWidget.addTab(widget0, "Tab 0") |
||||
assert index0 == 0 |
||||
assert tabWidget.count() == 1 |
||||
assert tabWidget.currentIndex() == 0 |
||||
assert widget0.parentWidget() == tabWidget |
||||
|
||||
index1 = tabWidget.addTab(widget1, "Tab 1", data="data1") |
||||
assert index1 == 1 |
||||
assert tabWidget.count() == 2 |
||||
|
||||
index2 = tabWidget.addTab(widget2, "Tab 2") |
||||
assert index2 == 2 |
||||
assert tabWidget.count() == 3 |
||||
|
||||
def test_tabwidget_insert_tabs(): |
||||
''' |
||||
Test inserting tabs at specific positions. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget3 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
# Insert at beginning |
||||
index = tabWidget.insertTab(0, widget3, "Tab -1") |
||||
assert index == 0 |
||||
assert tabWidget.count() == 4 |
||||
assert tabWidget.widget(0) == widget3 |
||||
assert tabWidget.currentIndex() == 1 # Should shift |
||||
|
||||
def test_tabwidget_remove_tabs(): |
||||
''' |
||||
Test removing tabs from TTkTabWidget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
assert tabWidget.count() == 3 |
||||
|
||||
tabWidget.removeTab(1) |
||||
assert tabWidget.count() == 2 |
||||
assert tabWidget.widget(0) == widget0 |
||||
assert tabWidget.widget(1) == widget2 |
||||
|
||||
tabWidget.removeTab(0) |
||||
assert tabWidget.count() == 1 |
||||
assert tabWidget.widget(0) == widget2 |
||||
|
||||
def test_tabwidget_current_widget(): |
||||
''' |
||||
Test getting and setting current widget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
assert tabWidget.currentWidget() == widget0 |
||||
|
||||
tabWidget.setCurrentWidget(widget1) |
||||
assert tabWidget.currentWidget() == widget1 |
||||
assert tabWidget.currentIndex() == 1 |
||||
|
||||
tabWidget.setCurrentWidget(widget2) |
||||
assert tabWidget.currentWidget() == widget2 |
||||
assert tabWidget.currentIndex() == 2 |
||||
|
||||
def test_tabwidget_widget_by_index(): |
||||
''' |
||||
Test accessing widgets by index. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
assert tabWidget.widget(0) == widget0 |
||||
assert tabWidget.widget(1) == widget1 |
||||
assert tabWidget.widget(2) == widget2 |
||||
assert tabWidget.widget(10) is None |
||||
assert tabWidget.widget(-1) is None |
||||
|
||||
def test_tabwidget_index_of(): |
||||
''' |
||||
Test finding index of a widget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
widget_not_added = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
assert tabWidget.indexOf(widget0) == 0 |
||||
assert tabWidget.indexOf(widget1) == 1 |
||||
assert tabWidget.indexOf(widget2) == 2 |
||||
assert tabWidget.indexOf(widget_not_added) == -1 |
||||
|
||||
def test_tabwidget_tab_data(): |
||||
''' |
||||
Test tab data in TTkTabWidget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0", data="data0") |
||||
tabWidget.addTab(widget1, "Tab 1", data={"key": "value"}) |
||||
|
||||
assert tabWidget.tabData(0) == "data0" |
||||
assert tabWidget.tabData(1) == {"key": "value"} |
||||
|
||||
tabWidget.setTabData(0, "new_data") |
||||
assert tabWidget.tabData(0) == "new_data" |
||||
|
||||
assert tabWidget.currentData() == "new_data" |
||||
|
||||
def test_tabwidget_signals(): |
||||
''' |
||||
Test that TTkTabWidget signals are emitted correctly. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
current_changed_called = [] |
||||
tab_clicked_called = [] |
||||
|
||||
tabWidget.currentChanged.connect(lambda i: current_changed_called.append(i)) |
||||
tabWidget.tabBarClicked.connect(lambda i: tab_clicked_called.append(i)) |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
assert len(current_changed_called) == 1 |
||||
|
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.setCurrentIndex(1) |
||||
assert len(current_changed_called) == 2 |
||||
assert current_changed_called[1] == 1 |
||||
|
||||
def test_tabwidget_widget_visibility(): |
||||
''' |
||||
Test that only the current widget is visible. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
# Initially all should be hidden (added hidden) |
||||
assert widget0.isVisible() is True |
||||
assert widget1.isVisible() is False |
||||
assert widget2.isVisible() is False |
||||
|
||||
# After setting index, current should be visible |
||||
tabWidget.setCurrentIndex(0) |
||||
# Note: Visibility is controlled internally, check currentWidget |
||||
assert tabWidget.currentWidget() == widget0 |
||||
|
||||
tabWidget.setCurrentIndex(1) |
||||
assert tabWidget.currentWidget() == widget1 |
||||
|
||||
tabWidget.setCurrentIndex(2) |
||||
assert tabWidget.currentWidget() == widget2 |
||||
|
||||
def test_tabwidget_closable(): |
||||
''' |
||||
Test closable tabs in TTkTabWidget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget(closable=True) |
||||
|
||||
assert tabWidget.tabsClosable() is True |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1", closable=False) |
||||
|
||||
# Both tabs should be added |
||||
assert tabWidget.count() == 2 |
||||
|
||||
def test_tabwidget_remove_all_tabs(): |
||||
''' |
||||
Test removing all tabs from TTkTabWidget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
widget2 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
tabWidget.addTab(widget2, "Tab 2") |
||||
|
||||
assert tabWidget.count() == 3 |
||||
|
||||
tabWidget.removeTab(0) |
||||
tabWidget.removeTab(0) |
||||
tabWidget.removeTab(0) |
||||
|
||||
assert tabWidget.count() == 0 |
||||
assert tabWidget.currentIndex() == -1 |
||||
|
||||
def test_tabwidget_bar_type(): |
||||
''' |
||||
Test different bar types. |
||||
''' |
||||
from TermTk.TTkWidgets.tabwidget import TTkBarType |
||||
|
||||
tabWidget1 = ttk.TTkTabWidget(barType=TTkBarType.DEFAULT_3) |
||||
tabWidget2 = ttk.TTkTabWidget(barType=TTkBarType.DEFAULT_2) |
||||
tabWidget3 = ttk.TTkTabWidget(barType=TTkBarType.NERD_1) |
||||
|
||||
# Just verify they can be created |
||||
assert tabWidget1 is not None |
||||
assert tabWidget2 is not None |
||||
assert tabWidget3 is not None |
||||
|
||||
# ============================================================================ |
||||
# Drag and Drop Related Tests |
||||
# ============================================================================ |
||||
|
||||
def test_tabwidget_drag_data_classes(): |
||||
''' |
||||
Test that drag data classes exist and can be instantiated. |
||||
''' |
||||
from TermTk.TTkWidgets.tabwidget import ( |
||||
_TTkTabWidgetDragData, |
||||
_TTkNewTabWidgetDragData, |
||||
_TTkTabBarDragData |
||||
) |
||||
|
||||
tabWidget = ttk.TTkTabWidget() |
||||
widget = ttk.TTkWidget() |
||||
tabWidget.addTab(widget, "Tab 0") |
||||
|
||||
button = tabWidget.tabButton(0) |
||||
|
||||
# Test _TTkTabWidgetDragData |
||||
drag_data1 = _TTkTabWidgetDragData(button, tabWidget) |
||||
assert drag_data1.tabButton() == button |
||||
assert drag_data1.tabWidget() == tabWidget |
||||
|
||||
# Test _TTkNewTabWidgetDragData |
||||
new_widget = ttk.TTkWidget() |
||||
drag_data2 = _TTkNewTabWidgetDragData("Label", new_widget, data="test", closable=True) |
||||
assert drag_data2.label() == "Label" |
||||
assert drag_data2.widget() == new_widget |
||||
assert drag_data2.data() == "test" |
||||
assert drag_data2.closable() is True |
||||
|
||||
# Test _TTkTabBarDragData |
||||
tabBar = ttk.TTkTabBar() |
||||
tabBar.addTab("Tab") |
||||
bar_button = tabBar.tabButton(0) |
||||
drag_data3 = _TTkTabBarDragData(bar_button, tabBar) |
||||
assert drag_data3.tabButton() == bar_button |
||||
assert drag_data3.tabBar() == tabBar |
||||
|
||||
def test_tabbar_tab_button(): |
||||
''' |
||||
Test accessing tab buttons from TTkTabBar. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
tabBar.addTab("Tab 1") |
||||
tabBar.addTab("Tab 2") |
||||
|
||||
button0 = tabBar.tabButton(0) |
||||
button1 = tabBar.tabButton(1) |
||||
button2 = tabBar.tabButton(2) |
||||
|
||||
assert button0 is not None |
||||
assert button1 is not None |
||||
assert button2 is not None |
||||
|
||||
# Test button text |
||||
assert button0.text() == "Tab 0" |
||||
assert button1.text() == "Tab 1" |
||||
assert button2.text() == "Tab 2" |
||||
|
||||
# Test invalid index |
||||
assert tabBar.tabButton(10) is None |
||||
assert tabBar.tabButton(-1) is None |
||||
|
||||
def test_tabwidget_tab_button(): |
||||
''' |
||||
Test accessing tab buttons from TTkTabWidget. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
|
||||
button0 = tabWidget.tabButton(0) |
||||
button1 = tabWidget.tabButton(1) |
||||
|
||||
assert button0 is not None |
||||
assert button1 is not None |
||||
assert button0.text() == "Tab 0" |
||||
assert button1.text() == "Tab 1" |
||||
|
||||
def test_tabbar_multiple_add_remove(): |
||||
''' |
||||
Test multiple add/remove operations to ensure state consistency. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
# Add multiple tabs |
||||
for i in range(5): |
||||
tabBar.addTab(f"Tab {i}") |
||||
|
||||
assert tabBar.currentIndex() == 0 |
||||
|
||||
# Remove some tabs |
||||
tabBar.removeTab(2) |
||||
tabBar.removeTab(1) |
||||
|
||||
# Add more tabs |
||||
tabBar.addTab("New Tab 1") |
||||
tabBar.addTab("New Tab 2") |
||||
|
||||
# Verify state is consistent |
||||
assert tabBar.tabButton(0) is not None |
||||
assert tabBar.tabButton(0).text() == "Tab 0" |
||||
|
||||
def test_tabwidget_multiple_add_remove(): |
||||
''' |
||||
Test multiple add/remove operations with widgets. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widgets = [ttk.TTkWidget() for _ in range(5)] |
||||
|
||||
# Add all widgets |
||||
for i, widget in enumerate(widgets): |
||||
tabWidget.addTab(widget, f"Tab {i}") |
||||
|
||||
assert tabWidget.count() == 5 |
||||
|
||||
# Remove some |
||||
tabWidget.removeTab(2) |
||||
tabWidget.removeTab(1) |
||||
|
||||
assert tabWidget.count() == 3 |
||||
|
||||
# Add more |
||||
new_widget = ttk.TTkWidget() |
||||
tabWidget.addTab(new_widget, "New Tab") |
||||
|
||||
assert tabWidget.count() == 4 |
||||
|
||||
def test_tabbar_set_current_after_remove(): |
||||
''' |
||||
Test that setting current index works correctly after removing tabs. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
tabBar.addTab("Tab 0") |
||||
tabBar.addTab("Tab 1") |
||||
tabBar.addTab("Tab 2") |
||||
tabBar.addTab("Tab 3") |
||||
|
||||
tabBar.setCurrentIndex(3) |
||||
assert tabBar.currentIndex() == 3 |
||||
|
||||
# Remove current tab |
||||
tabBar.removeTab(3) |
||||
|
||||
# Current should be adjusted |
||||
assert tabBar.currentIndex() < 3 |
||||
|
||||
# Should be able to set to valid index |
||||
tabBar.setCurrentIndex(1) |
||||
assert tabBar.currentIndex() == 1 |
||||
|
||||
def test_tabwidget_parent_relationship(): |
||||
''' |
||||
Test that widgets maintain correct parent relationships when added to tabs. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
widget0 = ttk.TTkWidget() |
||||
widget1 = ttk.TTkWidget() |
||||
|
||||
assert widget0.parentWidget() is None |
||||
assert widget1.parentWidget() is None |
||||
|
||||
tabWidget.addTab(widget0, "Tab 0") |
||||
assert widget0.parentWidget() == tabWidget |
||||
|
||||
tabWidget.addTab(widget1, "Tab 1") |
||||
assert widget1.parentWidget() == tabWidget |
||||
|
||||
# After removal, parent should still be tabWidget (it's in the layout) |
||||
tabWidget.removeTab(0) |
||||
# Note: The widget may still have tabWidget as parent depending on implementation |
||||
|
||||
def test_tabbar_empty_initialization(): |
||||
''' |
||||
Test that empty TTkTabBar initializes correctly. |
||||
''' |
||||
tabBar = ttk.TTkTabBar() |
||||
|
||||
assert tabBar.currentIndex() == -1 |
||||
assert tabBar.tabButton(0) is None |
||||
assert tabBar.tabData(0) is None |
||||
assert tabBar.currentData() is None |
||||
|
||||
def test_tabwidget_empty_initialization(): |
||||
''' |
||||
Test that empty TTkTabWidget initializes correctly. |
||||
''' |
||||
tabWidget = ttk.TTkTabWidget() |
||||
|
||||
assert tabWidget.count() == 0 |
||||
assert tabWidget.currentIndex() == -1 |
||||
assert tabWidget.widget(0) is None |
||||
assert tabWidget.indexOf(ttk.TTkWidget()) == -1 |
||||
@ -0,0 +1,87 @@
|
||||
#!/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 |
||||
|
||||
root = ttk.TTk(mouseTrack=True) |
||||
|
||||
winTabbed1 = ttk.TTkWindow(parent=root,pos=(0,0), size=(80,20), title="Test Tab 1", border=True, layout=ttk.TTkGridLayout()) |
||||
tabWidget1 = ttk.TTkTabWidget(parent=winTabbed1, border=True, barType=ttk.TTkBarType.DEFAULT_3) |
||||
tabWidget1.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame1.1"), "Label 1.1") |
||||
tabWidget1.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame1.2"), "Label 1.2") |
||||
tabWidget1.addTab(ttk.TTkTestWidget(border=True, title="Frame1.3"), "Label Test 1.3") |
||||
tabWidget1.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame1.4"), "Label 1.4") |
||||
tabWidget1.addTab(ttk.TTkTestWidget(border=True, title="Frame1.5"), "Label Test 1.5") |
||||
tabWidget1.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame1.6"), "Label 1.6") |
||||
|
||||
winTabbed2 = ttk.TTkWindow(parent=root,pos=(10,2), size=(80,20), title="Test Tab 2", border=True, layout=ttk.TTkGridLayout()) |
||||
tabWidget2 = ttk.TTkTabWidget(parent=winTabbed2, border=True, barType=ttk.TTkBarType.DEFAULT_3) |
||||
tabWidget2.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame2.1"), "Label 2.1") |
||||
tabWidget2.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame2.2"), "Label 2.2") |
||||
tabWidget2.addTab(ttk.TTkTestWidget(border=True, title="Frame2.3"), "Label Test 2.3") |
||||
tabWidget2.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame2.4"), "Label 2.4") |
||||
tabWidget2.addTab(ttk.TTkTestWidget(border=True, title="Frame2.5"), "Label Test 2.5") |
||||
tabWidget2.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame2.6"), "Label 2.6") |
||||
tabWidget2.addMenu("Foo") |
||||
tabWidget2.addMenu("Bar", ttk.TTkK.RIGHT) |
||||
|
||||
winTabbed3 = ttk.TTkWindow(parent=root,pos=(20,4), size=(80,20), title="Test Tab 3", border=True, layout=ttk.TTkGridLayout()) |
||||
tabWidget3 = ttk.TTkTabWidget(parent=winTabbed3, border=True, barType=ttk.TTkBarType.DEFAULT_2) |
||||
tabWidget3.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame3.1"), "Label 3.1") |
||||
tabWidget3.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame3.2"), "Label 3.2") |
||||
tabWidget3.addTab(ttk.TTkTestWidget(border=True, title="Frame3.3"), "Label Test 3.3") |
||||
tabWidget3.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame3.4"), "Label 3.4") |
||||
tabWidget3.addTab(ttk.TTkTestWidget(border=True, title="Frame3.5"), "Label Test 3.5") |
||||
tabWidget3.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame3.6"), "Label 3.6") |
||||
|
||||
winTabbed4 = ttk.TTkWindow(parent=root,pos=(30,6), size=(80,20), title="Test Tab 4", border=True, layout=ttk.TTkGridLayout()) |
||||
tabWidget4 = ttk.TTkTabWidget(parent=winTabbed4, border=True, barType=ttk.TTkBarType.DEFAULT_2) |
||||
tabWidget4.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame4.1"), "Label 4.1") |
||||
tabWidget4.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame4.2"), "Label 4.2") |
||||
tabWidget4.addTab(ttk.TTkTestWidget(border=True, title="Frame4.3"), "Label Test 4.3") |
||||
tabWidget4.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame4.4"), "Label 4.4") |
||||
tabWidget4.addTab(ttk.TTkTestWidget(border=True, title="Frame4.5"), "Label Test 4.5") |
||||
tabWidget4.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame4.6"), "Label 4.6") |
||||
tabWidget4.addMenu("Baz") |
||||
tabWidget4.addMenu("Foo", ttk.TTkK.RIGHT) |
||||
|
||||
winTabbed5 = ttk.TTkWindow(parent=root,pos=(40,8), size=(80,20), title="Test Tab 5", border=True, layout=ttk.TTkGridLayout()) |
||||
tabWidget5 = ttk.TTkTabWidget(parent=winTabbed5, border=True, barType=ttk.TTkBarType.NERD_1) |
||||
tabWidget5.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame5.1"), "Label 5.1") |
||||
tabWidget5.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame5.2"), "Label 5.2") |
||||
tabWidget5.addTab(ttk.TTkTestWidget(border=True, title="Frame5.3"), "Label Test 5.3") |
||||
tabWidget5.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame5.4"), "Label 5.4") |
||||
tabWidget5.addTab(ttk.TTkTestWidget(border=True, title="Frame5.5"), "Label Test 5.5") |
||||
tabWidget5.addTab(ttk.TTkTestWidgetSizes(border=True, title="Frame5.6"), "Label 5.6") |
||||
|
||||
winLogs = ttk.TTkWindow(parent=root,pos=(45,10), size=(100,30), title="Logs", border=True, layout=ttk.TTkGridLayout()) |
||||
ttk.TTkLogViewer(parent=winLogs) |
||||
|
||||
winKeys = ttk.TTkWindow(parent=root,pos=(50,15), size=(100,7), title="Key Press", border=True, layout=ttk.TTkGridLayout()) |
||||
ttk.TTkKeyPressView(parent=winKeys) |
||||
|
||||
root.mainloop() |
||||
Loading…
Reference in new issue