mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix(toolbar): adjusted to future plot base
This commit is contained in:
@ -5,7 +5,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import List, Literal, Tuple
|
from typing import Dict, List, Literal, Tuple
|
||||||
|
|
||||||
from bec_qthemes._icon.material_icons import material_icon
|
from bec_qthemes._icon.material_icons import material_icon
|
||||||
from qtpy.QtCore import QSize, Qt
|
from qtpy.QtCore import QSize, Qt
|
||||||
@ -95,6 +95,7 @@ class MaterialIconAction(ToolBarAction):
|
|||||||
filled (bool, optional): Whether the icon is filled. Defaults to False.
|
filled (bool, optional): Whether the icon is filled. Defaults to False.
|
||||||
color (str | tuple | QColor | dict[Literal["dark", "light"], str] | None, optional): The color of the icon.
|
color (str | tuple | QColor | dict[Literal["dark", "light"], str] | None, optional): The color of the icon.
|
||||||
Defaults to None.
|
Defaults to None.
|
||||||
|
parent (QWidget or None, optional): Parent widget for the underlying QAction.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -104,27 +105,42 @@ class MaterialIconAction(ToolBarAction):
|
|||||||
checkable: bool = False,
|
checkable: bool = False,
|
||||||
filled: bool = False,
|
filled: bool = False,
|
||||||
color: str | tuple | QColor | dict[Literal["dark", "light"], str] | None = None,
|
color: str | tuple | QColor | dict[Literal["dark", "light"], str] | None = None,
|
||||||
|
parent=None,
|
||||||
):
|
):
|
||||||
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
|
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
|
||||||
self.icon_name = icon_name
|
self.icon_name = icon_name
|
||||||
self.filled = filled
|
self.filled = filled
|
||||||
self.color = color
|
self.color = color
|
||||||
|
# Generate the icon
|
||||||
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
self.icon = material_icon(
|
||||||
icon = self.get_icon()
|
|
||||||
self.action = QAction(icon, self.tooltip, target)
|
|
||||||
self.action.setCheckable(self.checkable)
|
|
||||||
toolbar.addAction(self.action)
|
|
||||||
|
|
||||||
def get_icon(self):
|
|
||||||
icon = material_icon(
|
|
||||||
self.icon_name,
|
self.icon_name,
|
||||||
size=(20, 20),
|
size=(20, 20),
|
||||||
convert_to_pixmap=False,
|
convert_to_pixmap=False,
|
||||||
filled=self.filled,
|
filled=self.filled,
|
||||||
color=self.color,
|
color=self.color,
|
||||||
)
|
)
|
||||||
return icon
|
# Immediately create an QAction with the given parent
|
||||||
|
self.action = QAction(self.icon, self.tooltip, parent=parent)
|
||||||
|
self.action.setCheckable(self.checkable)
|
||||||
|
|
||||||
|
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
||||||
|
"""
|
||||||
|
Adds the action to the toolbar.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
toolbar(QToolBar): The toolbar to add the action to.
|
||||||
|
target(QWidget): The target widget for the action.
|
||||||
|
"""
|
||||||
|
toolbar.addAction(self.action)
|
||||||
|
|
||||||
|
def get_icon(self):
|
||||||
|
"""
|
||||||
|
Returns the icon for the action.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QIcon: The icon for the action.
|
||||||
|
"""
|
||||||
|
return self.icon
|
||||||
|
|
||||||
|
|
||||||
class DeviceSelectionAction(ToolBarAction):
|
class DeviceSelectionAction(ToolBarAction):
|
||||||
@ -258,18 +274,53 @@ class ExpandableMenuAction(ToolBarAction):
|
|||||||
toolbar.addWidget(button)
|
toolbar.addWidget(button)
|
||||||
|
|
||||||
|
|
||||||
class Bundle:
|
class ToolbarBundle:
|
||||||
"""
|
"""
|
||||||
Represents a bundle of toolbar actions.
|
Represents a bundle of toolbar actions, keyed by action_id.
|
||||||
|
Allows direct dictionary-like access: self.actions["some_id"] -> ToolBarAction object.
|
||||||
Args:
|
|
||||||
bundle_id (str): Unique identifier for the bundle.
|
|
||||||
actions (List[Tuple[str, ToolBarAction]]): List of tuples containing action IDs and their corresponding ToolBarAction instances.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, bundle_id: str, actions: List[Tuple[str, ToolBarAction]]):
|
def __init__(self, bundle_id: str = None, actions=None):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
bundle_id (str): Unique identifier for the bundle.
|
||||||
|
actions: Either None or a list of (action_id, ToolBarAction) tuples.
|
||||||
|
"""
|
||||||
self.bundle_id = bundle_id
|
self.bundle_id = bundle_id
|
||||||
self.actions = actions # List of tuples (action_id, ToolBarAction)
|
self._actions: dict[str, ToolBarAction] = {}
|
||||||
|
|
||||||
|
# If you passed in a list of tuples, load them into the dictionary
|
||||||
|
if actions is not None:
|
||||||
|
for action_id, action in actions:
|
||||||
|
self._actions[action_id] = action
|
||||||
|
|
||||||
|
def add_action(self, action_id: str, action: ToolBarAction):
|
||||||
|
"""
|
||||||
|
Adds or replaces an action in the bundle.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action_id (str): Unique identifier for the action.
|
||||||
|
action (ToolBarAction): The action to add.
|
||||||
|
"""
|
||||||
|
self._actions[action_id] = action
|
||||||
|
|
||||||
|
def remove_action(self, action_id: str):
|
||||||
|
"""
|
||||||
|
Removes an action from the bundle by ID.
|
||||||
|
Ignores if not present.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action_id (str): Unique identifier for the action to remove.
|
||||||
|
"""
|
||||||
|
self._actions.pop(action_id, None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def actions(self) -> dict[str, ToolBarAction]:
|
||||||
|
"""
|
||||||
|
Return the internal dictionary of actions so that you can do
|
||||||
|
bundle.actions["drag_mode"] -> ToolBarAction instance.
|
||||||
|
"""
|
||||||
|
return self._actions
|
||||||
|
|
||||||
|
|
||||||
class ModularToolBar(QToolBar):
|
class ModularToolBar(QToolBar):
|
||||||
@ -407,29 +458,30 @@ class ModularToolBar(QToolBar):
|
|||||||
action.action.setVisible(True)
|
action.action.setVisible(True)
|
||||||
self.update_separators() # Update separators after showing the action
|
self.update_separators() # Update separators after showing the action
|
||||||
|
|
||||||
def add_bundle(self, bundle: Bundle, target_widget: QWidget):
|
def add_bundle(self, bundle: ToolbarBundle, target_widget: QWidget):
|
||||||
"""
|
"""
|
||||||
Adds a bundle of actions to the toolbar, separated by a separator.
|
Adds a bundle of actions to the toolbar, separated by a separator.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bundle (Bundle): The bundle to add.
|
bundle (ToolbarBundle): The bundle to add.
|
||||||
target_widget (QWidget): The target widget for the actions.
|
target_widget (QWidget): The target widget for the actions.
|
||||||
"""
|
"""
|
||||||
if bundle.bundle_id in self.bundles:
|
if bundle.bundle_id in self.bundles:
|
||||||
raise ValueError(f"Bundle with ID '{bundle.bundle_id}' already exists.")
|
raise ValueError(f"ToolbarBundle with ID '{bundle.bundle_id}' already exists.")
|
||||||
|
|
||||||
# Add a separator before the bundle
|
# Add a separator before the bundle (but not to first one)
|
||||||
separator = SeparatorAction()
|
if self.toolbar_items:
|
||||||
separator.add_to_toolbar(self, target_widget)
|
sep = SeparatorAction()
|
||||||
self.toolbar_items.append(("separator", None))
|
sep.add_to_toolbar(self, target_widget)
|
||||||
|
self.toolbar_items.append(("separator", None))
|
||||||
|
|
||||||
# Add each action in the bundle
|
# Add each action in the bundle
|
||||||
for action_id, action in bundle.actions:
|
for action_id, action_obj in bundle.actions.items():
|
||||||
action.add_to_toolbar(self, target_widget)
|
action_obj.add_to_toolbar(self, target_widget)
|
||||||
self.widgets[action_id] = action
|
self.widgets[action_id] = action_obj
|
||||||
|
|
||||||
# Register the bundle
|
# Register the bundle
|
||||||
self.bundles[bundle.bundle_id] = [action_id for action_id, _ in bundle.actions]
|
self.bundles[bundle.bundle_id] = list(bundle.actions.keys())
|
||||||
self.toolbar_items.append(("bundle", bundle.bundle_id))
|
self.toolbar_items.append(("bundle", bundle.bundle_id))
|
||||||
|
|
||||||
self.update_separators() # Update separators after adding the bundle
|
self.update_separators() # Update separators after adding the bundle
|
||||||
@ -448,48 +500,70 @@ class ModularToolBar(QToolBar):
|
|||||||
if item_type == "separator":
|
if item_type == "separator":
|
||||||
menu.addSeparator()
|
menu.addSeparator()
|
||||||
elif item_type == "bundle":
|
elif item_type == "bundle":
|
||||||
# Get actions in the bundle
|
self.handle_bundle_context_menu(menu, identifier)
|
||||||
action_ids = self.bundles.get(identifier, [])
|
|
||||||
for action_id in action_ids:
|
|
||||||
toolbar_action = self.widgets.get(action_id)
|
|
||||||
if isinstance(toolbar_action, ToolBarAction) and hasattr(
|
|
||||||
toolbar_action, "action"
|
|
||||||
):
|
|
||||||
qaction = toolbar_action.action
|
|
||||||
if isinstance(qaction, QAction):
|
|
||||||
display_name = qaction.text() or toolbar_action.tooltip or action_id
|
|
||||||
menu_action = QAction(display_name, self)
|
|
||||||
menu_action.setCheckable(True)
|
|
||||||
menu_action.setChecked(qaction.isVisible())
|
|
||||||
menu_action.setData(action_id) # Store the action_id
|
|
||||||
|
|
||||||
# Set the icon if available
|
|
||||||
if qaction.icon() and not qaction.icon().isNull():
|
|
||||||
menu_action.setIcon(qaction.icon())
|
|
||||||
|
|
||||||
menu.addAction(menu_action)
|
|
||||||
elif item_type == "action":
|
elif item_type == "action":
|
||||||
# Standalone action
|
self.handle_action_context_menu(menu, identifier)
|
||||||
toolbar_action = self.widgets.get(identifier)
|
|
||||||
if isinstance(toolbar_action, ToolBarAction) and hasattr(toolbar_action, "action"):
|
|
||||||
qaction = toolbar_action.action
|
|
||||||
if isinstance(qaction, QAction):
|
|
||||||
display_name = qaction.text() or toolbar_action.tooltip or identifier
|
|
||||||
menu_action = QAction(display_name, self)
|
|
||||||
menu_action.setCheckable(True)
|
|
||||||
menu_action.setChecked(qaction.isVisible())
|
|
||||||
menu_action.setData(identifier) # Store the action_id
|
|
||||||
|
|
||||||
# Set the icon if available
|
|
||||||
if qaction.icon() and not qaction.icon().isNull():
|
|
||||||
menu_action.setIcon(qaction.icon())
|
|
||||||
|
|
||||||
menu.addAction(menu_action)
|
|
||||||
|
|
||||||
# Connect the triggered signal after all actions are added
|
# Connect the triggered signal after all actions are added
|
||||||
menu.triggered.connect(self.handle_menu_triggered)
|
menu.triggered.connect(self.handle_menu_triggered)
|
||||||
menu.exec_(event.globalPos())
|
menu.exec_(event.globalPos())
|
||||||
|
|
||||||
|
def handle_bundle_context_menu(self, menu: QMenu, bundle_id: str):
|
||||||
|
"""
|
||||||
|
Adds a set of bundle actions to the context menu.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
menu (QMenu): The context menu to which the actions are added.
|
||||||
|
bundle_id (str): The identifier for the bundle.
|
||||||
|
"""
|
||||||
|
action_ids = self.bundles.get(bundle_id, [])
|
||||||
|
for act_id in action_ids:
|
||||||
|
toolbar_action = self.widgets.get(act_id)
|
||||||
|
if not isinstance(toolbar_action, ToolBarAction) or not hasattr(
|
||||||
|
toolbar_action, "action"
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
qaction = toolbar_action.action
|
||||||
|
if not isinstance(qaction, QAction):
|
||||||
|
continue
|
||||||
|
display_name = qaction.text() or toolbar_action.tooltip or act_id
|
||||||
|
menu_action = QAction(display_name, self)
|
||||||
|
menu_action.setCheckable(True)
|
||||||
|
menu_action.setChecked(qaction.isVisible())
|
||||||
|
menu_action.setData(act_id) # Store the action_id
|
||||||
|
|
||||||
|
# Set the icon if available
|
||||||
|
if qaction.icon() and not qaction.icon().isNull():
|
||||||
|
menu_action.setIcon(qaction.icon())
|
||||||
|
|
||||||
|
menu.addAction(menu_action)
|
||||||
|
|
||||||
|
def handle_action_context_menu(self, menu: QMenu, action_id: str):
|
||||||
|
"""
|
||||||
|
Adds a single toolbar action to the context menu.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
menu (QMenu): The context menu to which the action is added.
|
||||||
|
action_id (str): Unique identifier for the action.
|
||||||
|
"""
|
||||||
|
toolbar_action = self.widgets.get(action_id)
|
||||||
|
if not isinstance(toolbar_action, ToolBarAction) or not hasattr(toolbar_action, "action"):
|
||||||
|
return
|
||||||
|
qaction = toolbar_action.action
|
||||||
|
if not isinstance(qaction, QAction):
|
||||||
|
return
|
||||||
|
display_name = qaction.text() or toolbar_action.tooltip or action_id
|
||||||
|
menu_action = QAction(display_name, self)
|
||||||
|
menu_action.setCheckable(True)
|
||||||
|
menu_action.setChecked(qaction.isVisible())
|
||||||
|
menu_action.setData(action_id) # Store the action_id
|
||||||
|
|
||||||
|
# Set the icon if available
|
||||||
|
if qaction.icon() and not qaction.icon().isNull():
|
||||||
|
menu_action.setIcon(qaction.icon())
|
||||||
|
|
||||||
|
menu.addAction(menu_action)
|
||||||
|
|
||||||
def handle_menu_triggered(self, action):
|
def handle_menu_triggered(self, action):
|
||||||
"""Handles the toggling of toolbar actions from the context menu."""
|
"""Handles the toggling of toolbar actions from the context menu."""
|
||||||
action_id = action.data()
|
action_id = action.data()
|
||||||
@ -504,13 +578,13 @@ class ModularToolBar(QToolBar):
|
|||||||
action_id(str): Unique identifier for the action to toggle.
|
action_id(str): Unique identifier for the action to toggle.
|
||||||
visible(bool): Whether the action should be visible.
|
visible(bool): Whether the action should be visible.
|
||||||
"""
|
"""
|
||||||
try:
|
if action_id not in self.widgets:
|
||||||
action = self.widgets[action_id]
|
return
|
||||||
if hasattr(action, "action") and isinstance(action.action, QAction):
|
|
||||||
action.action.setVisible(visible)
|
tool_action = self.widgets[action_id]
|
||||||
self.update_separators() # Update separators after toggling visibility
|
if hasattr(tool_action, "action") and isinstance(tool_action.action, QAction):
|
||||||
except KeyError:
|
tool_action.action.setVisible(visible)
|
||||||
pass
|
self.update_separators()
|
||||||
|
|
||||||
def update_separators(self):
|
def update_separators(self):
|
||||||
"""
|
"""
|
||||||
@ -519,50 +593,55 @@ class ModularToolBar(QToolBar):
|
|||||||
toolbar_actions = self.actions()
|
toolbar_actions = self.actions()
|
||||||
|
|
||||||
for i, action in enumerate(toolbar_actions):
|
for i, action in enumerate(toolbar_actions):
|
||||||
if action.isSeparator():
|
if not action.isSeparator():
|
||||||
# Find the previous visible action
|
continue
|
||||||
prev_visible = None
|
# Find the previous visible action
|
||||||
for j in range(i - 1, -1, -1):
|
prev_visible = None
|
||||||
if toolbar_actions[j].isVisible():
|
for j in range(i - 1, -1, -1):
|
||||||
prev_visible = toolbar_actions[j]
|
if toolbar_actions[j].isVisible():
|
||||||
break
|
prev_visible = toolbar_actions[j]
|
||||||
|
break
|
||||||
|
|
||||||
# Find the next visible action
|
# Find the next visible action
|
||||||
next_visible = None
|
next_visible = None
|
||||||
for j in range(i + 1, len(toolbar_actions)):
|
for j in range(i + 1, len(toolbar_actions)):
|
||||||
if toolbar_actions[j].isVisible():
|
if toolbar_actions[j].isVisible():
|
||||||
next_visible = toolbar_actions[j]
|
next_visible = toolbar_actions[j]
|
||||||
break
|
break
|
||||||
|
|
||||||
# Determine if the separator should be hidden
|
# Determine if the separator should be hidden
|
||||||
# Hide if both previous and next visible actions are separators or non-existent
|
# Hide if both previous and next visible actions are separators or non-existent
|
||||||
if (prev_visible is None or prev_visible.isSeparator()) and (
|
if (prev_visible is None or prev_visible.isSeparator()) and (
|
||||||
next_visible is None or next_visible.isSeparator()
|
next_visible is None or next_visible.isSeparator()
|
||||||
):
|
):
|
||||||
action.setVisible(False)
|
action.setVisible(False)
|
||||||
else:
|
else:
|
||||||
action.setVisible(True)
|
action.setVisible(True)
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow): # pragma: no cover
|
class MainWindow(QMainWindow): # pragma: no cover
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.setWindowTitle("Toolbar / ToolbarBundle Demo")
|
||||||
|
|
||||||
self.central_widget = QWidget()
|
self.central_widget = QWidget()
|
||||||
self.setCentralWidget(self.central_widget)
|
self.setCentralWidget(self.central_widget)
|
||||||
|
|
||||||
# Initialize the ModularToolBar
|
# Create a modular toolbar
|
||||||
self.toolbar = ModularToolBar(parent=self, target_widget=self)
|
self.toolbar = ModularToolBar(parent=self, target_widget=self)
|
||||||
self.addToolBar(self.toolbar)
|
self.addToolBar(self.toolbar)
|
||||||
|
|
||||||
# Define individual MaterialIconActions for the first bundle
|
# Example: Add a single bundle
|
||||||
home_action = MaterialIconAction(icon_name="home", tooltip="Home", checkable=True)
|
home_action = MaterialIconAction(
|
||||||
settings_action = MaterialIconAction(
|
icon_name="home", tooltip="Home", checkable=True, parent=self
|
||||||
icon_name="settings", tooltip="Settings", checkable=True
|
|
||||||
)
|
)
|
||||||
profile_action = MaterialIconAction(icon_name="person", tooltip="Profile", checkable=True)
|
settings_action = MaterialIconAction(
|
||||||
|
icon_name="settings", tooltip="Settings", checkable=True, parent=self
|
||||||
# Create the first Bundle with these actions
|
)
|
||||||
main_actions_bundle = Bundle(
|
profile_action = MaterialIconAction(
|
||||||
|
icon_name="person", tooltip="Profile", checkable=True, parent=self
|
||||||
|
)
|
||||||
|
main_actions_bundle = ToolbarBundle(
|
||||||
bundle_id="main_actions",
|
bundle_id="main_actions",
|
||||||
actions=[
|
actions=[
|
||||||
("home_action", home_action),
|
("home_action", home_action),
|
||||||
@ -570,26 +649,20 @@ class MainWindow(QMainWindow): # pragma: no cover
|
|||||||
("profile_action", profile_action),
|
("profile_action", profile_action),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add the first bundle to the toolbar
|
|
||||||
self.toolbar.add_bundle(main_actions_bundle, target_widget=self)
|
self.toolbar.add_bundle(main_actions_bundle, target_widget=self)
|
||||||
|
|
||||||
# Define individual MaterialIconActions for the second bundle
|
# Another bundle
|
||||||
search_action = MaterialIconAction(icon_name="search", tooltip="Search", checkable=True)
|
search_action = MaterialIconAction(
|
||||||
help_action = MaterialIconAction(icon_name="help", tooltip="Help", checkable=True)
|
icon_name="search", tooltip="Search", checkable=True, parent=self
|
||||||
|
)
|
||||||
# Create the second Bundle with these actions
|
help_action = MaterialIconAction(
|
||||||
secondary_actions_bundle = Bundle(
|
icon_name="help", tooltip="Help", checkable=True, parent=self
|
||||||
|
)
|
||||||
|
second_bundle = ToolbarBundle(
|
||||||
bundle_id="secondary_actions",
|
bundle_id="secondary_actions",
|
||||||
actions=[("search_action", search_action), ("help_action", help_action)],
|
actions=[("search_action", search_action), ("help_action", help_action)],
|
||||||
)
|
)
|
||||||
|
self.toolbar.add_bundle(second_bundle, target_widget=self)
|
||||||
# Add the second bundle to the toolbar
|
|
||||||
self.toolbar.add_bundle(secondary_actions_bundle, target_widget=self)
|
|
||||||
|
|
||||||
# Define a standalone action
|
|
||||||
info_action = MaterialIconAction(icon_name="info", tooltip="Info", checkable=True)
|
|
||||||
self.toolbar.add_action("info_action", info_action, target_widget=self)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from qtpy.QtCore import Qt
|
from qtpy.QtCore import QPoint, Qt
|
||||||
from qtpy.QtWidgets import QComboBox, QLabel, QToolButton, QWidget
|
from qtpy.QtGui import QContextMenuEvent
|
||||||
|
from qtpy.QtWidgets import QComboBox, QLabel, QMenu, QToolButton, QWidget
|
||||||
|
|
||||||
from bec_widgets.qt_utils.toolbar import (
|
from bec_widgets.qt_utils.toolbar import (
|
||||||
Bundle,
|
|
||||||
DeviceSelectionAction,
|
DeviceSelectionAction,
|
||||||
ExpandableMenuAction,
|
ExpandableMenuAction,
|
||||||
IconAction,
|
IconAction,
|
||||||
MaterialIconAction,
|
MaterialIconAction,
|
||||||
ModularToolBar,
|
ModularToolBar,
|
||||||
SeparatorAction,
|
SeparatorAction,
|
||||||
|
ToolbarBundle,
|
||||||
WidgetAction,
|
WidgetAction,
|
||||||
)
|
)
|
||||||
|
from tests.unit_tests.conftest import create_widget
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -281,8 +283,9 @@ def test_show_action_nonexistent(toolbar_fixture):
|
|||||||
|
|
||||||
|
|
||||||
def test_add_bundle(toolbar_fixture, dummy_widget, icon_action, material_icon_action):
|
def test_add_bundle(toolbar_fixture, dummy_widget, icon_action, material_icon_action):
|
||||||
|
"""Test adding a bundle of actions to the toolbar."""
|
||||||
toolbar = toolbar_fixture
|
toolbar = toolbar_fixture
|
||||||
bundle = Bundle(
|
bundle = ToolbarBundle(
|
||||||
bundle_id="test_bundle",
|
bundle_id="test_bundle",
|
||||||
actions=[
|
actions=[
|
||||||
("icon_action_in_bundle", icon_action),
|
("icon_action_in_bundle", icon_action),
|
||||||
@ -298,12 +301,14 @@ def test_add_bundle(toolbar_fixture, dummy_widget, icon_action, material_icon_ac
|
|||||||
|
|
||||||
|
|
||||||
def test_invalid_orientation(dummy_widget):
|
def test_invalid_orientation(dummy_widget):
|
||||||
|
"""Test that an invalid orientation raises a ValueError."""
|
||||||
toolbar = ModularToolBar(target_widget=dummy_widget, orientation="horizontal")
|
toolbar = ModularToolBar(target_widget=dummy_widget, orientation="horizontal")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
toolbar.set_orientation("diagonal")
|
toolbar.set_orientation("diagonal")
|
||||||
|
|
||||||
|
|
||||||
def test_widgetaction_calculate_minimum_width(qtbot):
|
def test_widget_action_calculate_minimum_width(qtbot):
|
||||||
|
"""Test calculate_minimum_width with various combo box items."""
|
||||||
combo = QComboBox()
|
combo = QComboBox()
|
||||||
combo.addItems(["Short", "Longer Item", "The Longest Item In Combo"])
|
combo.addItems(["Short", "Longer Item", "The Longest Item In Combo"])
|
||||||
widget_action = WidgetAction(label="Test", widget=combo)
|
widget_action = WidgetAction(label="Test", widget=combo)
|
||||||
@ -311,3 +316,81 @@ def test_widgetaction_calculate_minimum_width(qtbot):
|
|||||||
assert width > 0
|
assert width > 0
|
||||||
# Width should be large enough to accommodate the longest item plus additional space
|
# Width should be large enough to accommodate the longest item plus additional space
|
||||||
assert width > 100
|
assert width > 100
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME test is stucking CI, works locally
|
||||||
|
# def test_context_menu_contains_added_actions(
|
||||||
|
# qtbot, icon_action, material_icon_action, dummy_widget
|
||||||
|
# ):
|
||||||
|
# """
|
||||||
|
# Test that the toolbar's context menu lists all added toolbar actions.
|
||||||
|
# """
|
||||||
|
# toolbar = create_widget(
|
||||||
|
# qtbot, widget=ModularToolBar, target_widget=dummy_widget, orientation="horizontal"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# # Add two different actions
|
||||||
|
# toolbar.add_action("icon_action", icon_action, dummy_widget)
|
||||||
|
# toolbar.add_action("material_icon_action", material_icon_action, dummy_widget)
|
||||||
|
#
|
||||||
|
# # Manually trigger the context menu event
|
||||||
|
# event = QContextMenuEvent(QContextMenuEvent.Mouse, QPoint(10, 10))
|
||||||
|
# toolbar.contextMenuEvent(event)
|
||||||
|
#
|
||||||
|
# # The QMenu is executed in contextMenuEvent, so we can fetch all possible actions
|
||||||
|
# # from the displayed menu by searching for QMenu in the immediate children of the toolbar.
|
||||||
|
# menus = toolbar.findChildren(QMenu)
|
||||||
|
# assert len(menus) > 0
|
||||||
|
# menu = menus[-1] # The most recently created menu
|
||||||
|
#
|
||||||
|
# menu_action_texts = [action.text() for action in menu.actions()]
|
||||||
|
# # Check if the menu contains entries for both added actions
|
||||||
|
# assert any(icon_action.tooltip in text or "icon_action" in text for text in menu_action_texts)
|
||||||
|
# assert any(
|
||||||
|
# material_icon_action.tooltip in text or "material_icon_action" in text
|
||||||
|
# for text in menu_action_texts
|
||||||
|
# )
|
||||||
|
# menu.actions()[0].trigger() # Trigger the first action to close the menu
|
||||||
|
# toolbar.close()
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME test is stucking CI, works locally
|
||||||
|
# def test_context_menu_toggle_action_visibility(qtbot, icon_action, dummy_widget):
|
||||||
|
# """
|
||||||
|
# Test that toggling action visibility works correctly through the toolbar's context menu.
|
||||||
|
# """
|
||||||
|
# toolbar = create_widget(
|
||||||
|
# qtbot, widget=ModularToolBar, target_widget=dummy_widget, orientation="horizontal"
|
||||||
|
# )
|
||||||
|
# # Add an action
|
||||||
|
# toolbar.add_action("icon_action", icon_action, dummy_widget)
|
||||||
|
# assert icon_action.action.isVisible()
|
||||||
|
#
|
||||||
|
# # Manually trigger the context menu event
|
||||||
|
# event = QContextMenuEvent(QContextMenuEvent.Mouse, QPoint(10, 10))
|
||||||
|
# toolbar.contextMenuEvent(event)
|
||||||
|
#
|
||||||
|
# # Grab the menu that was created
|
||||||
|
# menus = toolbar.findChildren(QMenu)
|
||||||
|
# assert len(menus) > 0
|
||||||
|
# menu = menus[-1]
|
||||||
|
#
|
||||||
|
# # Locate the QAction in the menu
|
||||||
|
# matching_actions = [m for m in menu.actions() if m.text() == icon_action.tooltip]
|
||||||
|
# assert len(matching_actions) == 1
|
||||||
|
# action_in_menu = matching_actions[0]
|
||||||
|
#
|
||||||
|
# # Toggle it off (uncheck)
|
||||||
|
# action_in_menu.setChecked(False)
|
||||||
|
# menu.triggered.emit(action_in_menu)
|
||||||
|
# # The action on the toolbar should now be hidden
|
||||||
|
# assert not icon_action.action.isVisible()
|
||||||
|
#
|
||||||
|
# # Toggle it on (check)
|
||||||
|
# action_in_menu.setChecked(True)
|
||||||
|
# menu.triggered.emit(action_in_menu)
|
||||||
|
# # The action on the toolbar should be visible again
|
||||||
|
# assert icon_action.action.isVisible()
|
||||||
|
#
|
||||||
|
# menu.actions()[0].trigger() # Trigger the first action to close the menu
|
||||||
|
# toolbar.close()
|
||||||
|
Reference in New Issue
Block a user