1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-03-10 10:47:49 +01:00

feat(actions): actions can be created with label text with beside or under alignment

This commit is contained in:
2025-10-02 12:33:32 +02:00
parent 3dd688540e
commit 663c00f1a4
2 changed files with 90 additions and 4 deletions

View File

@@ -33,6 +33,32 @@ logger = bec_logger.logger
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
def create_action_with_text(toolbar_action, toolbar: QToolBar):
"""
Helper function to create a toolbar button with text beside or under the icon.
Args:
toolbar_action(ToolBarAction): The toolbar action to create the button for.
toolbar(ModularToolBar): The toolbar to add the button to.
"""
btn = QToolButton(parent=toolbar)
if getattr(toolbar_action, "label_text", None):
toolbar_action.action.setText(toolbar_action.label_text)
if getattr(toolbar_action, "tooltip", None):
toolbar_action.action.setToolTip(toolbar_action.tooltip)
btn.setToolTip(toolbar_action.tooltip)
btn.setDefaultAction(toolbar_action.action)
btn.setAutoRaise(True)
if toolbar_action.text_position == "beside":
btn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
else:
btn.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
btn.setText(toolbar_action.label_text)
toolbar.addWidget(btn)
class NoCheckDelegate(QStyledItemDelegate):
"""To reduce space in combo boxes by removing the checkmark."""
@@ -114,15 +140,39 @@ class SeparatorAction(ToolBarAction):
class QtIconAction(ToolBarAction):
def __init__(self, standard_icon, tooltip=None, checkable=False, parent=None):
def __init__(
self,
standard_icon,
tooltip=None,
checkable=False,
label_text: str | None = None,
text_position: Literal["beside", "under"] | None = None,
parent=None,
):
"""
Action with a standard Qt icon for the toolbar.
Args:
standard_icon: The standard icon from QStyle.
tooltip(str, optional): The tooltip for the action. Defaults to None.
checkable(bool, optional): Whether the action is checkable. Defaults to False.
label_text(str | None, optional): Optional label text to display beside or under the icon.
text_position(Literal["beside", "under"] | None, optional): Position of text relative to icon.
parent(QWidget or None, optional): Parent widget for the underlying QAction.
"""
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
self.standard_icon = standard_icon
self.icon = QApplication.style().standardIcon(standard_icon)
self.action = QAction(icon=self.icon, text=self.tooltip, parent=parent)
self.action.setCheckable(self.checkable)
self.label_text = label_text
self.text_position = text_position
def add_to_toolbar(self, toolbar, target):
toolbar.addAction(self.action)
if self.label_text is not None:
create_action_with_text(toolbar_action=self, toolbar=toolbar)
else:
toolbar.addAction(self.action)
def get_icon(self):
return self.icon
@@ -139,6 +189,8 @@ class MaterialIconAction(ToolBarAction):
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.
Defaults to None.
label_text (str | None, optional): Optional label text to display beside or under the icon.
text_position (Literal["beside", "under"] | None, optional): Position of text relative to icon.
parent (QWidget or None, optional): Parent widget for the underlying QAction.
"""
@@ -149,12 +201,20 @@ class MaterialIconAction(ToolBarAction):
checkable: bool = False,
filled: bool = False,
color: str | tuple | QColor | dict[Literal["dark", "light"], str] | None = None,
label_text: str | None = None,
text_position: Literal["beside", "under"] | None = None,
parent=None,
):
"""
MaterialIconAction for toolbar: if label_text and text_position are provided, show text beside or under icon.
This enables per-action icon text without breaking the existing API.
"""
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
self.icon_name = icon_name
self.filled = filled
self.color = color
self.label_text = label_text
self.text_position = text_position
# Generate the icon using the material_icon helper
self.icon = material_icon(
self.icon_name,
@@ -178,7 +238,10 @@ class MaterialIconAction(ToolBarAction):
toolbar(QToolBar): The toolbar to add the action to.
target(QWidget): The target widget for the action.
"""
toolbar.addAction(self.action)
if self.label_text is not None:
create_action_with_text(toolbar_action=self, toolbar=toolbar)
else:
toolbar.addAction(self.action)
def get_icon(self):
"""

View File

@@ -6,7 +6,7 @@ from collections import defaultdict
from typing import DefaultDict, Literal
from bec_lib.logger import bec_logger
from qtpy.QtCore import QSize, Qt
from qtpy.QtCore import QSize, Qt, QTimer
from qtpy.QtGui import QAction, QColor
from qtpy.QtWidgets import QApplication, QLabel, QMainWindow, QMenu, QToolBar, QVBoxLayout, QWidget
@@ -492,10 +492,33 @@ if __name__ == "__main__": # pragma: no cover
self.toolbar.connect_bundle(
"base", PerformanceConnection(self.toolbar.components, self)
)
self.toolbar.components.add_safe(
"text",
MaterialIconAction(
"text_fields",
tooltip="Test Text Action",
checkable=True,
label_text="text",
text_position="under",
),
)
self.toolbar.show_bundles(["performance", "plot_export"])
self.toolbar.get_bundle("performance").add_action("save")
self.toolbar.get_bundle("performance").add_action("text")
self.toolbar.refresh()
# Timer to disable and enable text button each 2s
self.timer = QTimer()
self.timer.timeout.connect(self.toggle_text_action)
self.timer.start(2000)
def toggle_text_action(self):
text_action = self.toolbar.components.get_action("text")
if text_action.action.isEnabled():
text_action.action.setEnabled(False)
else:
text_action.action.setEnabled(True)
def enable_fps_monitor(self, enabled: bool):
"""
Example method to enable or disable FPS monitoring.