mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-06-13 16:40:56 +02:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18c104fc12 | |||
| 499d0a5986 | |||
| 487feebcbf |
@@ -5,31 +5,28 @@ import xml.etree.ElementTree as ET
|
||||
from typing import TYPE_CHECKING, Callable
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_qthemes import enable_hover_gradient
|
||||
from qtpy.QtCore import Qt, Signal # type: ignore
|
||||
from qtpy.QtGui import QFontMetrics, QPainter, QPainterPath, QPixmap
|
||||
from qtpy.QtWidgets import (
|
||||
QApplication,
|
||||
QComboBox,
|
||||
QFileDialog,
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QSpacerItem,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
import bec_widgets
|
||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
||||
from bec_widgets.utils.bec_plugin_helper import get_all_plugin_widgets
|
||||
from bec_widgets.utils.colors import apply_theme
|
||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||
from bec_widgets.utils.error_popups import SafeSlot
|
||||
from bec_widgets.utils.name_utils import pascal_to_snake
|
||||
from bec_widgets.utils.plugin_utils import get_plugin_auto_updates
|
||||
from bec_widgets.utils.round_frame import RoundedFrame
|
||||
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
|
||||
from bec_widgets.utils.ui_loader import UILoader
|
||||
from bec_widgets.widgets.containers.auto_update.auto_updates import AutoUpdates
|
||||
@@ -46,7 +43,7 @@ logger = bec_logger.logger
|
||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
|
||||
class LaunchTile(QFrame):
|
||||
class LaunchTile(RoundedFrame):
|
||||
DEFAULT_SIZE = (250, 300)
|
||||
open_signal = Signal()
|
||||
|
||||
@@ -59,14 +56,8 @@ class LaunchTile(QFrame):
|
||||
description: str | None = None,
|
||||
show_selector: bool = False,
|
||||
tile_size: tuple[int, int] | None = None,
|
||||
gradient: list[str] | None = None,
|
||||
):
|
||||
super().__init__(parent=parent)
|
||||
self.setProperty("skip_settings", True)
|
||||
self.setProperty("variant", "tile")
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||
super().__init__(parent=parent, orientation="vertical")
|
||||
|
||||
# Provide a per‑instance TILE_SIZE so the class can compute layout
|
||||
if tile_size is None:
|
||||
@@ -162,12 +153,6 @@ class LaunchTile(QFrame):
|
||||
"""
|
||||
)
|
||||
self.layout.addWidget(self.action_button, alignment=Qt.AlignCenter)
|
||||
if gradient is not None:
|
||||
enable_hover_gradient(self, colours=gradient)
|
||||
|
||||
def apply_theme(self, theme: str):
|
||||
"""Allow tiles to be theme-aware without custom styling logic."""
|
||||
self.update()
|
||||
|
||||
def _fit_label_to_width(self, label: QLabel, max_width: int, min_pt: int = 10):
|
||||
"""
|
||||
@@ -230,7 +215,6 @@ class LaunchWindow(BECMainWindow):
|
||||
description="Highly flexible and customizable dock area application with modular widgets.",
|
||||
action_button=lambda: self.launch("dock_area"),
|
||||
show_selector=False,
|
||||
gradient=["#B73665", "#232770"],
|
||||
)
|
||||
|
||||
self.available_auto_updates: dict[str, type[AutoUpdates]] = (
|
||||
@@ -245,7 +229,6 @@ class LaunchWindow(BECMainWindow):
|
||||
action_button=self._open_auto_update,
|
||||
show_selector=True,
|
||||
selector_items=list(self.available_auto_updates.keys()) + ["Default"],
|
||||
gradient=["#EE0678", "#FF6A00"],
|
||||
)
|
||||
|
||||
self.register_tile(
|
||||
@@ -256,7 +239,6 @@ class LaunchWindow(BECMainWindow):
|
||||
description="GUI application with custom UI file.",
|
||||
action_button=self._open_custom_ui_file,
|
||||
show_selector=False,
|
||||
gradient=["#155799", "#179655"],
|
||||
)
|
||||
|
||||
# plugin widgets
|
||||
@@ -275,7 +257,6 @@ class LaunchWindow(BECMainWindow):
|
||||
action_button=self._open_widget,
|
||||
show_selector=True,
|
||||
selector_items=list(self.available_widgets.keys()),
|
||||
gradient=["#000046", "#1CB5E0"],
|
||||
)
|
||||
|
||||
self._update_theme()
|
||||
@@ -294,7 +275,6 @@ class LaunchWindow(BECMainWindow):
|
||||
action_button: Callable | None = None,
|
||||
show_selector: bool = False,
|
||||
selector_items: list[str] | None = None,
|
||||
gradient: list[str] | None = None,
|
||||
):
|
||||
"""
|
||||
Register a tile in the launcher window.
|
||||
@@ -317,7 +297,6 @@ class LaunchWindow(BECMainWindow):
|
||||
description=description,
|
||||
show_selector=show_selector,
|
||||
tile_size=self.TILE_SIZE,
|
||||
gradient=gradient,
|
||||
)
|
||||
tile.setFixedWidth(self.TILE_SIZE[0])
|
||||
tile.setMinimumHeight(self.TILE_SIZE[1])
|
||||
@@ -606,7 +585,6 @@ if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
apply_theme("dark")
|
||||
launcher = LaunchWindow()
|
||||
launcher.show()
|
||||
sys.exit(app.exec())
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
import markdown
|
||||
@@ -13,6 +15,7 @@ from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
||||
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
|
||||
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
|
||||
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
|
||||
from bec_widgets.widgets.containers.qt_ads import CDockWidget
|
||||
from bec_widgets.widgets.editors.monaco.monaco_dock import MonacoDock
|
||||
from bec_widgets.widgets.editors.monaco.monaco_widget import MonacoWidget
|
||||
from bec_widgets.widgets.editors.web_console.web_console import WebConsole
|
||||
@@ -124,6 +127,7 @@ class DeveloperWidget(DockAreaWidget):
|
||||
# Connect editor signals
|
||||
self.explorer.file_open_requested.connect(self._open_new_file)
|
||||
self.monaco.macro_file_updated.connect(self.explorer.refresh_macro_file)
|
||||
self.monaco.focused_editor.connect(self._on_focused_editor_changed)
|
||||
|
||||
self.toolbar.show_bundles(["save", "execution", "settings"])
|
||||
|
||||
@@ -280,14 +284,17 @@ class DeveloperWidget(DockAreaWidget):
|
||||
|
||||
@SafeSlot()
|
||||
def on_save(self):
|
||||
"""Save the currently focused file in the Monaco editor."""
|
||||
self.monaco.save_file()
|
||||
|
||||
@SafeSlot()
|
||||
def on_save_as(self):
|
||||
"""Save the currently focused file in the Monaco editor with a 'Save As' dialog."""
|
||||
self.monaco.save_file(force_save_as=True)
|
||||
|
||||
@SafeSlot()
|
||||
def on_vim_triggered(self):
|
||||
"""Toggle Vim mode in the Monaco editor."""
|
||||
self.monaco.set_vim_mode(self.toolbar.components.get_action("vim").action.isChecked())
|
||||
|
||||
@SafeSlot(bool)
|
||||
@@ -310,16 +317,26 @@ class DeveloperWidget(DockAreaWidget):
|
||||
|
||||
@SafeSlot()
|
||||
def on_stop(self):
|
||||
"""Stop the execution of the currently running script"""
|
||||
if not self.current_script_id:
|
||||
return
|
||||
self.console.send_ctrl_c()
|
||||
|
||||
@property
|
||||
def current_script_id(self):
|
||||
"""Get the ID of the currently running script."""
|
||||
return self._current_script_id
|
||||
|
||||
@current_script_id.setter
|
||||
def current_script_id(self, value: str | None):
|
||||
"""
|
||||
Set the ID of the currently running script.
|
||||
|
||||
Args:
|
||||
value (str | None): The script ID to set.
|
||||
Raises:
|
||||
ValueError: If the provided value is not a string or None.
|
||||
"""
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise ValueError("Script ID must be a string.")
|
||||
old_script_id = self._current_script_id
|
||||
@@ -336,6 +353,28 @@ class DeveloperWidget(DockAreaWidget):
|
||||
self.on_script_execution_info, MessageEndpoints.script_execution_info(new_script_id)
|
||||
)
|
||||
|
||||
@SafeSlot(CDockWidget)
|
||||
def _on_focused_editor_changed(self, tab_widget: CDockWidget):
|
||||
"""
|
||||
Disable the run button if the focused editor is a macro file.
|
||||
Args:
|
||||
tab_widget: The currently focused tab widget in the Monaco editor.
|
||||
"""
|
||||
if not isinstance(tab_widget, CDockWidget):
|
||||
return
|
||||
widget = tab_widget.widget()
|
||||
if not isinstance(widget, MonacoWidget):
|
||||
return
|
||||
file_scope = widget.metadata.get("scope", "")
|
||||
run_action = self.toolbar.components.get_action("run")
|
||||
stop_action = self.toolbar.components.get_action("stop")
|
||||
if "macro" in file_scope:
|
||||
run_action.action.setEnabled(False)
|
||||
stop_action.action.setEnabled(False)
|
||||
else:
|
||||
run_action.action.setEnabled(True)
|
||||
stop_action.action.setEnabled(True)
|
||||
|
||||
@SafeSlot(dict, dict)
|
||||
def on_script_execution_info(self, content: dict, metadata: dict):
|
||||
"""
|
||||
@@ -359,6 +398,7 @@ class DeveloperWidget(DockAreaWidget):
|
||||
widget.set_highlighted_lines(line_number, line_number)
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up resources used by the developer widget."""
|
||||
self.delete_all()
|
||||
return super().cleanup()
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import pyqtgraph as pg
|
||||
from qtpy.QtCore import Property, Qt
|
||||
from qtpy.QtWidgets import QApplication, QFrame, QHBoxLayout, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
||||
|
||||
|
||||
class RoundedFrame(QFrame):
|
||||
# TODO this should be removed completely in favor of QSS styling, no time now
|
||||
"""
|
||||
A custom QFrame with rounded corners and optional theme updates.
|
||||
The frame can contain any QWidget, however it is mainly designed to wrap PlotWidgets to provide a consistent look and feel with other BEC Widgets.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
content_widget: QWidget = None,
|
||||
background_color: str = None,
|
||||
orientation: str = "horizontal",
|
||||
radius: int = 10,
|
||||
):
|
||||
QFrame.__init__(self, parent)
|
||||
|
||||
self.background_color = background_color
|
||||
self._radius = radius
|
||||
|
||||
# Apply rounded frame styling
|
||||
self.setProperty("skip_settings", True)
|
||||
self.setObjectName("roundedFrame")
|
||||
|
||||
# Ensure QSS can paint background/border on this widget
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
|
||||
# Create a layout for the frame
|
||||
if orientation == "vertical":
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||
else:
|
||||
self.layout = QHBoxLayout(self)
|
||||
self.layout.setContentsMargins(5, 5, 5, 5) # Set 5px margin
|
||||
|
||||
# Add the content widget to the layout
|
||||
if content_widget:
|
||||
self.layout.addWidget(content_widget)
|
||||
|
||||
# Store reference to the content widget
|
||||
self.content_widget = content_widget
|
||||
|
||||
# Automatically apply initial styles to the GraphicalLayoutWidget if applicable
|
||||
self.apply_plot_widget_style()
|
||||
self.update_style()
|
||||
|
||||
def apply_theme(self, theme: str):
|
||||
"""Deprecated: RoundedFrame no longer handles theme; styling is QSS-driven."""
|
||||
self.update_style()
|
||||
|
||||
@Property(int)
|
||||
def radius(self):
|
||||
"""Radius of the rounded corners."""
|
||||
return self._radius
|
||||
|
||||
@radius.setter
|
||||
def radius(self, value: int):
|
||||
self._radius = value
|
||||
self.update_style()
|
||||
|
||||
def update_style(self):
|
||||
"""
|
||||
Update the style of the frame based on the background color.
|
||||
"""
|
||||
self.setStyleSheet(
|
||||
f"""
|
||||
QFrame#roundedFrame {{
|
||||
border-radius: {self._radius}px;
|
||||
}}
|
||||
"""
|
||||
)
|
||||
self.apply_plot_widget_style()
|
||||
|
||||
def apply_plot_widget_style(self, border: str = "none"):
|
||||
"""
|
||||
Let QSS/pyqtgraph handle plot styling; avoid overriding here.
|
||||
"""
|
||||
if isinstance(self.content_widget, pg.GraphicsLayoutWidget):
|
||||
self.content_widget.setStyleSheet("")
|
||||
|
||||
|
||||
class ExampleApp(QWidget): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("Rounded Plots Example")
|
||||
|
||||
# Main layout
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
dark_button = DarkModeButton()
|
||||
|
||||
# Create PlotWidgets
|
||||
plot1 = pg.GraphicsLayoutWidget()
|
||||
plot_item_1 = pg.PlotItem()
|
||||
plot_item_1.plot([1, 3, 2, 4, 6, 5], pen="r")
|
||||
plot1.plot_item = plot_item_1
|
||||
|
||||
plot2 = pg.GraphicsLayoutWidget()
|
||||
plot_item_2 = pg.PlotItem()
|
||||
plot_item_2.plot([1, 2, 4, 8, 16, 32], pen="r")
|
||||
plot2.plot_item = plot_item_2
|
||||
|
||||
# Add to layout (no RoundedFrame wrapper; QSS styles plots)
|
||||
layout.addWidget(dark_button)
|
||||
layout.addWidget(plot1)
|
||||
layout.addWidget(plot2)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
# Theme flip demo removed; global theming applies automatically
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
app = QApplication([])
|
||||
|
||||
window = ExampleApp()
|
||||
window.show()
|
||||
|
||||
app.exec()
|
||||
@@ -142,9 +142,12 @@ class MonacoDock(DockAreaWidget):
|
||||
# Temporarily disable read-only mode if the editor is read-only
|
||||
# so we can clear the content for reuse
|
||||
monaco_widget.set_readonly(False)
|
||||
monaco_widget.set_text("")
|
||||
monaco_widget.set_text("", reset=True)
|
||||
dock.setWindowTitle("Untitled")
|
||||
dock.setTabToolTip("Untitled")
|
||||
monaco_widget.metadata["scope"] = ""
|
||||
icon = self._resolve_dock_icon(monaco_widget, dock_icon=None, apply_widget_icon=True)
|
||||
dock.setIcon(icon)
|
||||
return
|
||||
|
||||
# Otherwise, proceed to close and delete the dock
|
||||
@@ -249,10 +252,15 @@ class MonacoDock(DockAreaWidget):
|
||||
self.last_focused_editor = dock
|
||||
return dock
|
||||
|
||||
def open_file(self, file_name: str, scope: str | None = None) -> None:
|
||||
def open_file(self, file_name: str, scope: str = "") -> None:
|
||||
"""
|
||||
Open a file in the specified area. If the file is already open, activate it.
|
||||
|
||||
Args:
|
||||
file_name (str): The path to the file to open.
|
||||
scope (str): The scope to set for the editor metadata.
|
||||
"""
|
||||
|
||||
open_files = self._get_open_files()
|
||||
if file_name in open_files:
|
||||
dock = self._get_editor_dock(file_name)
|
||||
@@ -281,8 +289,7 @@ class MonacoDock(DockAreaWidget):
|
||||
editor_dock.setWindowTitle(file)
|
||||
editor_dock.setTabToolTip(file_name)
|
||||
editor_widget.open_file(file_name)
|
||||
if scope is not None:
|
||||
editor_widget.metadata["scope"] = scope
|
||||
editor_widget.metadata["scope"] = scope
|
||||
self.last_focused_editor = editor_dock
|
||||
return
|
||||
|
||||
@@ -290,8 +297,7 @@ class MonacoDock(DockAreaWidget):
|
||||
editor_dock = self.add_editor(title=file, tooltip=file_name)
|
||||
widget = cast(MonacoWidget, editor_dock.widget())
|
||||
widget.open_file(file_name)
|
||||
if scope is not None:
|
||||
widget.metadata["scope"] = scope
|
||||
widget.metadata["scope"] = scope
|
||||
editor_dock.setAsCurrentTab()
|
||||
self.last_focused_editor = editor_dock
|
||||
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import pyqtgraph as pg
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QFrame, QVBoxLayout
|
||||
|
||||
from bec_widgets.utils.round_frame import RoundedFrame
|
||||
from bec_widgets.widgets.plots.plot_base import BECViewBox
|
||||
|
||||
|
||||
class ImageROIPlot(QFrame):
|
||||
class ImageROIPlot(RoundedFrame):
|
||||
"""
|
||||
A widget for displaying an image with a region of interest (ROI) overlay.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
self.setProperty("variant", "plot_background")
|
||||
self.setProperty("frameless", True)
|
||||
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||
self.layout.setSpacing(0)
|
||||
|
||||
self.content_widget = pg.GraphicsLayoutWidget(self)
|
||||
self.layout.addWidget(self.content_widget)
|
||||
@@ -35,15 +27,7 @@ class ImageROIPlot(QFrame):
|
||||
self.curve_color = "k"
|
||||
for curve in self.plot_item.curves:
|
||||
curve.setPen(pg.mkPen(self.curve_color, width=3))
|
||||
|
||||
self.apply_plot_widget_style()
|
||||
|
||||
def apply_plot_widget_style(self, border: str = "none"):
|
||||
"""Keep pyqtgraph widgets styled by QSS/themes."""
|
||||
if border != "none":
|
||||
self.content_widget.setStyleSheet(f"border: {border};")
|
||||
else:
|
||||
self.content_widget.setStyleSheet("")
|
||||
super().apply_theme(theme)
|
||||
|
||||
def cleanup_pyqtgraph(self):
|
||||
"""Cleanup pyqtgraph items."""
|
||||
|
||||
@@ -6,13 +6,14 @@ import numpy as np
|
||||
import pyqtgraph as pg
|
||||
from bec_lib import bec_logger
|
||||
from qtpy.QtCore import QPoint, QPointF, Qt, Signal
|
||||
from qtpy.QtWidgets import QFrame, QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget
|
||||
from qtpy.QtWidgets import QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget
|
||||
|
||||
from bec_widgets.utils import ConnectionConfig, Crosshair, EntryValidator
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||
from bec_widgets.utils.fps_counter import FPSCounter
|
||||
from bec_widgets.utils.plot_indicator_items import BECArrowItem, BECTickItem
|
||||
from bec_widgets.utils.round_frame import RoundedFrame
|
||||
from bec_widgets.utils.side_panel import SidePanel
|
||||
from bec_widgets.utils.toolbars.performance import PerformanceConnection, performance_bundle
|
||||
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
|
||||
@@ -143,43 +144,25 @@ class PlotBase(BECWidget, QWidget):
|
||||
self._update_theme(None)
|
||||
|
||||
def apply_theme(self, theme: str):
|
||||
self.apply_plot_widget_style()
|
||||
super().apply_theme(theme)
|
||||
self.round_plot_widget.apply_theme(theme)
|
||||
|
||||
def _init_ui(self):
|
||||
self.layout.addWidget(self.layout_manager)
|
||||
self.round_plot_widget = QFrame(parent=self)
|
||||
self.round_plot_widget.setAttribute(Qt.WA_StyledBackground, True)
|
||||
self.round_plot_widget = RoundedFrame(parent=self, content_widget=self.plot_widget)
|
||||
self.round_plot_widget.setProperty("variant", "plot_background")
|
||||
self.round_plot_widget.setProperty("frameless", True)
|
||||
|
||||
plot_frame_layout = QVBoxLayout(self.round_plot_widget)
|
||||
plot_frame_layout.setContentsMargins(5, 5, 5, 5)
|
||||
plot_frame_layout.setSpacing(0)
|
||||
plot_frame_layout.addWidget(self.plot_widget)
|
||||
|
||||
self.layout_manager.add_widget(self.round_plot_widget)
|
||||
self.layout_manager.add_widget_relative(self.fps_label, self.round_plot_widget, "top")
|
||||
self.fps_label.hide()
|
||||
self.layout_manager.add_widget_relative(self.side_panel, self.round_plot_widget, "left")
|
||||
self.layout_manager.add_widget_relative(self.toolbar, self.fps_label, "top")
|
||||
|
||||
self.apply_plot_widget_style()
|
||||
|
||||
self.ui_mode = self._ui_mode # to initiate the first time
|
||||
|
||||
# PlotItem ViewBox Signals
|
||||
self.plot_item.vb.sigStateChanged.connect(self.viewbox_state_changed)
|
||||
|
||||
def apply_plot_widget_style(self, border: str = "none"):
|
||||
"""Let theme/QSS style the plot widget; keep custom overrides minimal."""
|
||||
if not isinstance(self.plot_widget, pg.GraphicsLayoutWidget):
|
||||
return
|
||||
if border != "none":
|
||||
self.plot_widget.setStyleSheet(f"border: {border};")
|
||||
else:
|
||||
self.plot_widget.setStyleSheet("")
|
||||
|
||||
def _init_toolbar(self):
|
||||
self.toolbar.add_bundle(performance_bundle(self.toolbar.components))
|
||||
self.toolbar.add_bundle(plot_export_bundle(self.toolbar.components))
|
||||
|
||||
@@ -575,7 +575,7 @@ class Waveform(PlotBase):
|
||||
self.async_signal_update.emit()
|
||||
self.sync_signal_update.emit()
|
||||
self.plot_item.enableAutoRange(x=True)
|
||||
self.apply_plot_widget_style() # To keep the correct theme
|
||||
self.round_plot_widget.apply_plot_widget_style() # To keep the correct theme
|
||||
|
||||
@SafeProperty(str)
|
||||
def x_entry(self) -> str | None:
|
||||
@@ -604,7 +604,7 @@ class Waveform(PlotBase):
|
||||
self.async_signal_update.emit()
|
||||
self.sync_signal_update.emit()
|
||||
self.plot_item.enableAutoRange(x=True)
|
||||
self.apply_plot_widget_style()
|
||||
self.round_plot_widget.apply_plot_widget_style()
|
||||
|
||||
@SafeProperty(str)
|
||||
def color_palette(self) -> str:
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import pyqtgraph as pg
|
||||
import pytest
|
||||
|
||||
from bec_widgets.utils.round_frame import RoundedFrame
|
||||
|
||||
|
||||
def cleanup_pyqtgraph(plot_widget):
|
||||
item = plot_widget.getPlotItem()
|
||||
item.vb.menu.close()
|
||||
item.vb.menu.deleteLater()
|
||||
item.ctrlMenu.close()
|
||||
item.ctrlMenu.deleteLater()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def basic_rounded_frame(qtbot):
|
||||
frame = RoundedFrame()
|
||||
qtbot.addWidget(frame)
|
||||
qtbot.waitExposed(frame)
|
||||
yield frame
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plot_rounded_frame(qtbot):
|
||||
plot_widget = pg.PlotWidget()
|
||||
plot_widget.plot([0, 1, 2], [2, 1, 0])
|
||||
frame = RoundedFrame(content_widget=plot_widget)
|
||||
qtbot.addWidget(frame)
|
||||
qtbot.waitExposed(frame)
|
||||
yield frame
|
||||
cleanup_pyqtgraph(plot_widget)
|
||||
|
||||
|
||||
def test_basic_rounded_frame_initialization(basic_rounded_frame):
|
||||
assert basic_rounded_frame.radius == 10
|
||||
assert basic_rounded_frame.content_widget is None
|
||||
assert basic_rounded_frame.background_color is None
|
||||
|
||||
|
||||
def test_set_radius(basic_rounded_frame):
|
||||
basic_rounded_frame.radius = 20
|
||||
assert basic_rounded_frame.radius == 20
|
||||
|
||||
|
||||
def test_apply_plot_widget_style(plot_rounded_frame):
|
||||
# Verify that a PlotWidget can have its style applied
|
||||
plot_rounded_frame.apply_plot_widget_style(border="1px solid red")
|
||||
|
||||
# Ensure style application did not break anything
|
||||
assert plot_rounded_frame.content_widget is not None
|
||||
assert isinstance(plot_rounded_frame.content_widget, pg.PlotWidget)
|
||||
Reference in New Issue
Block a user