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.
 
 
 
 
 

886 lines
25 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
# ============================================================================
# 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
# ============================================================================
# Keyboard Navigation Tests
# ============================================================================
def test_tabbar_highlight_navigation_with_arrow_keys():
'''
Test that arrow keys navigate through highlighted tabs.
'''
tabBar = ttk.TTkTabBar()
tabBar.addTab("Tab 0")
tabBar.addTab("Tab 1")
tabBar.addTab("Tab 2")
tabBar.addTab("Tab 3")
# Initial state - highlighted should be 0
assert tabBar._tabStatus.highlighted == -1
assert tabBar.currentIndex() == 0
# Press Right arrow
evt = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt)
assert result is True
assert tabBar._tabStatus.highlighted == 0
assert tabBar.currentIndex() == 0 # Current doesn't change yet
# Press Right arrow again
result = tabBar.keyEvent(evt)
assert result is True
assert tabBar._tabStatus.highlighted == 1
# Press Left arrow
evt = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Left, "", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt)
assert result is True
assert tabBar._tabStatus.highlighted == 0
def test_tabbar_enter_activates_highlighted_tab():
'''
Test that pressing Enter activates the highlighted tab.
'''
tabBar = ttk.TTkTabBar()
tabBar.addTab("Tab 0")
tabBar.addTab("Tab 1")
tabBar.addTab("Tab 2")
# Set current to Tab 0
tabBar.setCurrentIndex(0)
assert tabBar.currentIndex() == 0
# Highlight Tab 2 using arrow keys
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
assert tabBar._tabStatus.highlighted == 2
assert tabBar.currentIndex() == 0 # Still on Tab 0
# Press Enter to activate highlighted tab
evt_enter = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Enter, "", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt_enter)
assert result is True
assert tabBar.currentIndex() == 2 # Now switched to Tab 2
def test_tabbar_space_activates_highlighted_tab():
'''
Test that pressing Space activates the highlighted tab.
'''
tabBar = ttk.TTkTabBar()
tabBar.addTab("Tab 0")
tabBar.addTab("Tab 1")
tabBar.addTab("Tab 2")
# Set current to Tab 0
tabBar.setCurrentIndex(0)
assert tabBar.currentIndex() == 0
# Highlight Tab 1 using arrow key
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
assert tabBar._tabStatus.highlighted == 1
assert tabBar.currentIndex() == 0 # Still on Tab 0
# Press Space to activate highlighted tab
evt_space = ttk.TTkKeyEvent(ttk.TTkK.Character, " ", " ", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt_space)
assert result is True
assert tabBar.currentIndex() == 1 # Now switched to Tab 1
def test_tabwidget_enter_shows_highlighted_widget():
'''
Test that pressing Enter shows the widget of the highlighted tab.
'''
tabWidget = ttk.TTkTabWidget()
tabBar = tabWidget._tabStatus.tabBar
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 Tab 0 is current
assert tabWidget.currentIndex() == 0
assert tabWidget.currentWidget() == widget0
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
assert tabBar._tabStatus.highlighted == 2
# Press Enter to activate
evt_enter = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Enter, "", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt_enter)
# Verify the widget changed
assert tabWidget.currentIndex() == 2
assert tabWidget.currentWidget() == widget2
def test_tabwidget_space_shows_highlighted_widget():
'''
Test that pressing Space shows the widget of the highlighted tab.
'''
tabWidget = ttk.TTkTabWidget()
tabBar = tabWidget._tabStatus.tabBar
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 Tab 0 is current
assert tabWidget.currentIndex() == 0
assert tabWidget.currentWidget() == widget0
# Navigate to Tab 1 using arrow key
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.setFocus()
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
assert tabWidget._tabStatus.highlighted == 1
# Press Space to activate
evt_space = ttk.TTkKeyEvent(ttk.TTkK.Character, " ", " ", ttk.TTkK.NoModifier)
result = tabBar.keyEvent(evt_space)
# Verify the widget changed
assert tabWidget.currentIndex() == 1
assert tabWidget.currentWidget() == widget1
def test_tabbar_highlight_bounds():
'''
Test that highlight stays within bounds when navigating.
'''
tabBar = ttk.TTkTabBar()
tabBar.addTab("Tab 0")
tabBar.addTab("Tab 1")
tabBar.addTab("Tab 2")
# At start
assert tabBar._tabStatus.highlighted == -1
# Try to go left from first tab
evt_left = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Left, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_left)
tabBar.keyEvent(evt_left)
assert tabBar._tabStatus.highlighted == 0 # Should stay at 0
# Navigate to last tab
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
assert tabBar._tabStatus.highlighted == 2
# Try to go right from last tab
tabBar.keyEvent(evt_right)
assert tabBar._tabStatus.highlighted == 2 # Should stay at 2
def test_tabwidget_keyboard_navigation_with_signals():
'''
Test that currentChanged signal is emitted when activating with Enter/Space.
'''
tabWidget = ttk.TTkTabWidget()
tabBar = tabWidget._tabStatus.tabBar
widget0 = ttk.TTkWidget()
widget1 = ttk.TTkWidget()
tabWidget.addTab(widget0, "Tab 0")
tabWidget.addTab(widget1, "Tab 1")
current_changed_calls = []
tabWidget.currentChanged.connect(lambda i: current_changed_calls.append(i))
# Clear initial signal
current_changed_calls.clear()
# Highlight Tab 1 and activate with Enter
tabBar.setFocus()
evt_right = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Right, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_right)
tabBar.keyEvent(evt_right)
evt_enter = ttk.TTkKeyEvent(ttk.TTkK.SpecialKey, ttk.TTkK.Key_Enter, "", ttk.TTkK.NoModifier)
tabBar.keyEvent(evt_enter)
# Signal should be emitted
assert len(current_changed_calls) == 1
assert current_changed_calls[0] == 1