mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
refactor(launcher,main_window): launcher window moved to inherit from BECMainWindow
This commit is contained in:
@ -13,116 +13,30 @@ from bec_widgets.utils.colors import apply_theme
|
|||||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||||
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
|
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
|
||||||
from bec_widgets.widgets.containers.main_window.addons.web_links import BECWebLinksMixin
|
from bec_widgets.widgets.containers.main_window.addons.web_links import BECWebLinksMixin
|
||||||
|
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||||
|
|
||||||
|
|
||||||
class LaunchWindow(BECWidget, QMainWindow):
|
class LaunchWindow(BECMainWindow):
|
||||||
def __init__(self, parent=None, gui_id: str = None, *args, **kwargs):
|
RPC = True
|
||||||
super().__init__(parent=parent, gui_id=gui_id, **kwargs)
|
|
||||||
|
def __init__(
|
||||||
|
self, parent=None, gui_id: str = None, window_title="BEC Launcher", *args, **kwargs
|
||||||
|
):
|
||||||
|
super().__init__(parent=parent, gui_id=gui_id, window_title=window_title, **kwargs)
|
||||||
|
|
||||||
self.app = QApplication.instance()
|
self.app = QApplication.instance()
|
||||||
|
|
||||||
self.resize(500, 300)
|
self.resize(500, 300)
|
||||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||||
|
|
||||||
self._init_ui()
|
|
||||||
|
|
||||||
def _init_ui(self):
|
|
||||||
# Set the window title
|
|
||||||
self.setWindowTitle("BEC Launcher")
|
|
||||||
|
|
||||||
# Load ui file
|
|
||||||
ui_file_path = os.path.join(MODULE_PATH, "applications/launch_dialog.ui")
|
ui_file_path = os.path.join(MODULE_PATH, "applications/launch_dialog.ui")
|
||||||
self.load_ui(ui_file_path)
|
self.load_ui(ui_file_path)
|
||||||
|
|
||||||
# Set Menu and Status bar
|
|
||||||
self._setup_menu_bar()
|
|
||||||
|
|
||||||
# BEC Specific UI
|
|
||||||
self._init_bec_specific_ui()
|
|
||||||
|
|
||||||
# TODO can be implemented for toolbar
|
|
||||||
def load_ui(self, ui_file):
|
|
||||||
loader = UILoader(self)
|
|
||||||
self.ui = loader.loader(ui_file)
|
|
||||||
self.setCentralWidget(self.ui)
|
|
||||||
self.ui.open_dock_area.setText("Open Dock Area")
|
self.ui.open_dock_area.setText("Open Dock Area")
|
||||||
self.ui.open_dock_area.clicked.connect(lambda: self.launch("dock_area"))
|
self.ui.open_dock_area.clicked.connect(lambda: self.launch("dock_area"))
|
||||||
|
|
||||||
def _init_bec_specific_ui(self):
|
|
||||||
if getattr(self.app, "gui_id", None):
|
|
||||||
self.statusBar().showMessage(f"App ID: {self.app.gui_id}")
|
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
"Application is not a BECApplication instance. Status bar will not show App ID. Please initialize the application with BECApplication."
|
|
||||||
)
|
|
||||||
|
|
||||||
def list_app_hierarchy(self):
|
|
||||||
"""
|
|
||||||
List the hierarchy of the application.
|
|
||||||
"""
|
|
||||||
self.app.list_hierarchy()
|
|
||||||
|
|
||||||
def _setup_menu_bar(self):
|
|
||||||
"""
|
|
||||||
Setup the menu bar for the main window.
|
|
||||||
"""
|
|
||||||
menu_bar = self.menuBar()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Theme menu
|
|
||||||
theme_menu = menu_bar.addMenu("Theme")
|
|
||||||
|
|
||||||
theme_group = QActionGroup(self)
|
|
||||||
light_theme_action = QAction("Light Theme", self, checkable=True)
|
|
||||||
dark_theme_action = QAction("Dark Theme", self, checkable=True)
|
|
||||||
theme_group.addAction(light_theme_action)
|
|
||||||
theme_group.addAction(dark_theme_action)
|
|
||||||
theme_group.setExclusive(True)
|
|
||||||
|
|
||||||
theme_menu.addAction(light_theme_action)
|
|
||||||
theme_menu.addAction(dark_theme_action)
|
|
||||||
|
|
||||||
# Connect theme actions
|
|
||||||
light_theme_action.triggered.connect(lambda: self.change_theme("light"))
|
|
||||||
dark_theme_action.triggered.connect(lambda: self.change_theme("dark"))
|
|
||||||
|
|
||||||
# Set the default theme
|
|
||||||
# TODO can be fetched from app
|
|
||||||
dark_theme_action.setChecked(True)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Help menu
|
|
||||||
help_menu = menu_bar.addMenu("Help")
|
|
||||||
|
|
||||||
help_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxQuestion)
|
|
||||||
bug_icon = QApplication.style().standardIcon(QStyle.SP_MessageBoxInformation)
|
|
||||||
|
|
||||||
bec_docs = QAction("BEC Docs", self)
|
|
||||||
bec_docs.setIcon(help_icon)
|
|
||||||
widgets_docs = QAction("BEC Widgets Docs", self)
|
|
||||||
widgets_docs.setIcon(help_icon)
|
|
||||||
bug_report = QAction("Bug Report", self)
|
|
||||||
bug_report.setIcon(bug_icon)
|
|
||||||
|
|
||||||
bec_docs.triggered.connect(BECWebLinksMixin.open_bec_docs)
|
|
||||||
widgets_docs.triggered.connect(BECWebLinksMixin.open_bec_widgets_docs)
|
|
||||||
bug_report.triggered.connect(BECWebLinksMixin.open_bec_bug_report)
|
|
||||||
|
|
||||||
help_menu.addAction(bec_docs)
|
|
||||||
help_menu.addAction(widgets_docs)
|
|
||||||
help_menu.addAction(bug_report)
|
|
||||||
|
|
||||||
debug_bar = menu_bar.addMenu(f"DEBUG {self.__class__.__name__}")
|
|
||||||
list_hierarchy = QAction("List App Hierarchy", self)
|
|
||||||
list_hierarchy.triggered.connect(self.list_app_hierarchy)
|
|
||||||
debug_bar.addAction(list_hierarchy)
|
|
||||||
|
|
||||||
def change_theme(self, theme):
|
|
||||||
apply_theme(theme)
|
|
||||||
|
|
||||||
def launch(
|
def launch(
|
||||||
self,
|
self,
|
||||||
launch_script: str,
|
launch_script: str,
|
||||||
@ -137,7 +51,7 @@ class LaunchWindow(BECWidget, QMainWindow):
|
|||||||
Returns:
|
Returns:
|
||||||
BECDockArea: The newly created dock area.
|
BECDockArea: The newly created dock area.
|
||||||
"""
|
"""
|
||||||
from bec_widgets.applications.bw_launch import dock_area
|
from bec_widgets.applications import bw_launch
|
||||||
|
|
||||||
with RPCRegister.delayed_broadcast() as rpc_register:
|
with RPCRegister.delayed_broadcast() as rpc_register:
|
||||||
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(BECDockArea)
|
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(BECDockArea)
|
||||||
@ -149,16 +63,30 @@ class LaunchWindow(BECWidget, QMainWindow):
|
|||||||
else:
|
else:
|
||||||
name = "dock_area"
|
name = "dock_area"
|
||||||
name = WidgetContainerUtils.generate_unique_name(name, existing_dock_areas)
|
name = WidgetContainerUtils.generate_unique_name(name, existing_dock_areas)
|
||||||
dock_area = dock_area(name) # BECDockArea(name=name)
|
|
||||||
dock_area.resize(dock_area.minimumSizeHint())
|
if launch_script is None:
|
||||||
|
launch_script = "dock_area"
|
||||||
|
if not isinstance(launch_script, str):
|
||||||
|
raise ValueError(f"Launch script must be a string, but got {type(launch_script)}.")
|
||||||
|
launch = getattr(bw_launch, launch_script, None)
|
||||||
|
if launch is None:
|
||||||
|
raise ValueError(f"Launch script {launch_script} not found.")
|
||||||
|
|
||||||
|
result_widget = launch(name)
|
||||||
|
result_widget.resize(result_widget.minimumSizeHint())
|
||||||
# TODO Should we simply use the specified name as title here?
|
# TODO Should we simply use the specified name as title here?
|
||||||
dock_area.window().setWindowTitle(f"BEC - {name}")
|
result_widget.window().setWindowTitle(f"BEC - {name}")
|
||||||
logger.info(f"Created new dock area: {name}")
|
logger.info(f"Created new dock area: {name}")
|
||||||
logger.info(f"Existing dock areas: {geometry}")
|
logger.info(f"Existing dock areas: {geometry}")
|
||||||
if geometry is not None:
|
if geometry is not None:
|
||||||
dock_area.setGeometry(*geometry)
|
result_widget.setGeometry(*geometry)
|
||||||
dock_area.show()
|
if isinstance(result_widget, BECMainWindow):
|
||||||
return dock_area
|
result_widget.show()
|
||||||
|
else:
|
||||||
|
window = BECMainWindow()
|
||||||
|
window.setCentralWidget(result_widget)
|
||||||
|
window.show()
|
||||||
|
return result_widget
|
||||||
|
|
||||||
def show_launcher(self):
|
def show_launcher(self):
|
||||||
self.show()
|
self.show()
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>Form</class>
|
|
||||||
<widget class="QWidget" name="Form">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>824</width>
|
|
||||||
<height>1234</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="Waveform" name="waveform"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="BECDockArea" name="dock_area_2"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="BECDockArea" name="dock_area"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>BECDockArea</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>dock_area</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>Waveform</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>waveform</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,262 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MainWindow</class>
|
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1718</width>
|
|
||||||
<height>1139</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>MainWindow</string>
|
|
||||||
</property>
|
|
||||||
<property name="tabShape">
|
|
||||||
<enum>QTabWidget::TabShape::Rounded</enum>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QTabWidget" name="central_tab">
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="dock_area_tab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Dock Area</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="BECDockArea" name="dock_area"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="vscode_tab">
|
|
||||||
<attribute name="icon">
|
|
||||||
<iconset theme="QIcon::ThemeIcon::Computer"/>
|
|
||||||
</attribute>
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Visual Studio Code</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="VSCodeEditor" name="vscode"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenuBar" name="menubar">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1718</width>
|
|
||||||
<height>31</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<widget class="QMenu" name="menuHelp">
|
|
||||||
<property name="title">
|
|
||||||
<string>Help</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="action_BEC_docs"/>
|
|
||||||
<addaction name="action_BEC_widgets_docs"/>
|
|
||||||
<addaction name="action_bug_report"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuTheme">
|
|
||||||
<property name="title">
|
|
||||||
<string>Theme</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="action_light"/>
|
|
||||||
<addaction name="action_dark"/>
|
|
||||||
</widget>
|
|
||||||
<addaction name="menuTheme"/>
|
|
||||||
<addaction name="menuHelp"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
|
||||||
<widget class="QDockWidget" name="dock_scan_control">
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Scan Control</string>
|
|
||||||
</property>
|
|
||||||
<attribute name="dockWidgetArea">
|
|
||||||
<number>2</number>
|
|
||||||
</attribute>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents_2">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="ScanControl" name="scan_control"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<widget class="QDockWidget" name="dock_status_2">
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>BEC Service Status</string>
|
|
||||||
</property>
|
|
||||||
<attribute name="dockWidgetArea">
|
|
||||||
<number>2</number>
|
|
||||||
</attribute>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents_3">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="BECStatusBox" name="bec_status_box_2"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<widget class="QDockWidget" name="dock_queue">
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Scan Queue</string>
|
|
||||||
</property>
|
|
||||||
<attribute name="dockWidgetArea">
|
|
||||||
<number>2</number>
|
|
||||||
</attribute>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents_4">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="BECQueue" name="bec_queue">
|
|
||||||
<row/>
|
|
||||||
<column/>
|
|
||||||
<column/>
|
|
||||||
<column/>
|
|
||||||
<item row="0" column="0"/>
|
|
||||||
<item row="0" column="1"/>
|
|
||||||
<item row="0" column="2"/>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<action name="action_BEC_docs">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>BEC Docs</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_BEC_widgets_docs">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>BEC Widgets Docs</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_bug_report">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset theme="QIcon::ThemeIcon::DialogError"/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Bug Report</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_light">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Light</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_dark">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Dark</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>WebsiteWidget</class>
|
|
||||||
<extends>QWebEngineView</extends>
|
|
||||||
<header>website_widget</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>BECQueue</class>
|
|
||||||
<extends>QTableWidget</extends>
|
|
||||||
<header>bec_queue</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>ScanControl</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>scan_control</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>VSCodeEditor</class>
|
|
||||||
<extends>WebsiteWidget</extends>
|
|
||||||
<header>vs_code_editor</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>BECStatusBox</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>bec_status_box</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>BECDockArea</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>dock_area</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>QWebEngineView</class>
|
|
||||||
<extends></extends>
|
|
||||||
<header location="global">QtWebEngineWidgets/QWebEngineView</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,65 +1,74 @@
|
|||||||
import os
|
import os
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
from bec_lib.logger import bec_logger
|
from qtpy.QtCore import QSize
|
||||||
from qtpy.QtGui import QAction, QActionGroup
|
from qtpy.QtGui import QAction, QActionGroup, QIcon
|
||||||
from qtpy.QtWidgets import QApplication, QMainWindow, QStyle
|
from qtpy.QtWidgets import QApplication, QMainWindow, QStyle
|
||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
import bec_widgets
|
||||||
from bec_widgets.utils import UILoader
|
from bec_widgets.utils import UILoader
|
||||||
from bec_widgets.utils.bec_qapp import BECApplication
|
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
from bec_widgets.utils.colors import apply_theme
|
from bec_widgets.utils.colors import apply_theme
|
||||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||||
|
from bec_widgets.utils.error_popups import SafeSlot
|
||||||
|
from bec_widgets.utils.widget_io import WidgetHierarchy
|
||||||
from bec_widgets.widgets.containers.main_window.addons.web_links import BECWebLinksMixin
|
from bec_widgets.widgets.containers.main_window.addons.web_links import BECWebLinksMixin
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
||||||
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
|
|
||||||
|
|
||||||
logger = bec_logger.logger
|
|
||||||
|
|
||||||
|
|
||||||
class BECMainWindow(BECWidget, QMainWindow):
|
class BECMainWindow(BECWidget, QMainWindow):
|
||||||
def __init__(self, parent=None, gui_id: str = None, *args, **kwargs):
|
RPC = False
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent=None,
|
||||||
|
gui_id: str = None,
|
||||||
|
client=None,
|
||||||
|
window_title: str = "BEC",
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
super().__init__(parent=parent, gui_id=gui_id, **kwargs)
|
super().__init__(parent=parent, gui_id=gui_id, **kwargs)
|
||||||
|
|
||||||
self.app = QApplication.instance()
|
self.app = QApplication.instance()
|
||||||
|
self.setWindowTitle(window_title)
|
||||||
# self._upgrade_qapp() #TODO consider to make upgrade function to any QApplication to BECQApplication
|
|
||||||
self._init_ui()
|
self._init_ui()
|
||||||
|
|
||||||
def _init_ui(self):
|
def _init_ui(self):
|
||||||
# Set the window title
|
|
||||||
self.setWindowTitle("BEC")
|
# Set the icon
|
||||||
|
self._init_bec_icon()
|
||||||
|
|
||||||
# Set Menu and Status bar
|
# Set Menu and Status bar
|
||||||
self._setup_menu_bar()
|
self._setup_menu_bar()
|
||||||
|
|
||||||
# BEC Specific UI
|
# BEC Specific UI
|
||||||
self._init_bec_specific_ui()
|
self.display_app_id()
|
||||||
# self.ui = UILoader
|
|
||||||
# ui_file_path = os.path.join(os.path.dirname(__file__), "general_app.ui")
|
def _init_bec_icon(self):
|
||||||
# self.load_ui(ui_file_path)
|
icon = self.app.windowIcon()
|
||||||
|
if icon.isNull():
|
||||||
|
print("No icon is set, setting default icon")
|
||||||
|
icon = QIcon()
|
||||||
|
icon.addFile(
|
||||||
|
os.path.join(MODULE_PATH, "assets", "app_icons", "bec_widgets_icon.png"),
|
||||||
|
size=QSize(48, 48),
|
||||||
|
)
|
||||||
|
self.app.setWindowIcon(icon)
|
||||||
|
else:
|
||||||
|
print("An icon is set")
|
||||||
|
|
||||||
# TODO can be implemented for toolbar
|
|
||||||
def load_ui(self, ui_file):
|
def load_ui(self, ui_file):
|
||||||
loader = UILoader(self)
|
loader = UILoader(self)
|
||||||
self.ui = loader.loader(ui_file)
|
self.ui = loader.loader(ui_file)
|
||||||
self.setCentralWidget(self.ui)
|
self.setCentralWidget(self.ui)
|
||||||
|
|
||||||
def _init_bec_specific_ui(self):
|
def display_app_id(self):
|
||||||
if getattr(self.app, "is_bec_app", False):
|
server_id = self.bec_dispatcher.cli_server.gui_id
|
||||||
self.statusBar().showMessage(f"App ID: {self.app.gui_id}")
|
self.statusBar().showMessage(f"App ID: {server_id}")
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
"Application is not a BECApplication instance. Status bar will not show App ID. Please initialize the application with BECApplication."
|
|
||||||
)
|
|
||||||
|
|
||||||
def list_app_hierarchy(self):
|
def _fetch_theme(self) -> str:
|
||||||
"""
|
return self.app.theme.theme
|
||||||
List the hierarchy of the application.
|
|
||||||
"""
|
|
||||||
self.app.list_hierarchy()
|
|
||||||
|
|
||||||
def _setup_menu_bar(self):
|
def _setup_menu_bar(self):
|
||||||
"""
|
"""
|
||||||
@ -86,8 +95,11 @@ class BECMainWindow(BECWidget, QMainWindow):
|
|||||||
dark_theme_action.triggered.connect(lambda: self.change_theme("dark"))
|
dark_theme_action.triggered.connect(lambda: self.change_theme("dark"))
|
||||||
|
|
||||||
# Set the default theme
|
# Set the default theme
|
||||||
# TODO can be fetched from app
|
theme = self.app.theme.theme
|
||||||
dark_theme_action.setChecked(True)
|
if theme == "light":
|
||||||
|
light_theme_action.setChecked(True)
|
||||||
|
elif theme == "dark":
|
||||||
|
dark_theme_action.setChecked(True)
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Help menu
|
# Help menu
|
||||||
@ -111,139 +123,12 @@ class BECMainWindow(BECWidget, QMainWindow):
|
|||||||
help_menu.addAction(widgets_docs)
|
help_menu.addAction(widgets_docs)
|
||||||
help_menu.addAction(bug_report)
|
help_menu.addAction(bug_report)
|
||||||
|
|
||||||
debug_bar = menu_bar.addMenu(f"DEBUG {self.__class__.__name__}")
|
@SafeSlot(str)
|
||||||
list_hierarchy = QAction("List App Hierarchy", self)
|
def change_theme(self, theme: str):
|
||||||
list_hierarchy.triggered.connect(self.list_app_hierarchy)
|
|
||||||
debug_bar.addAction(list_hierarchy)
|
|
||||||
|
|
||||||
def change_theme(self, theme):
|
|
||||||
apply_theme(theme)
|
apply_theme(theme)
|
||||||
|
|
||||||
def _dump(self):
|
|
||||||
"""Return a dictionary with informations about the application state, for use in tests"""
|
|
||||||
# TODO: ModularToolBar and something else leak top-level widgets (3 or 4 QMenu + 2 QWidget);
|
|
||||||
# so, a filtering based on title is applied here, but the solution is to not have those widgets
|
|
||||||
# as top-level (so for now, a window with no title does not appear in _dump() result)
|
|
||||||
|
|
||||||
# NOTE: the main window itself is excluded, since we want to dump dock areas
|
|
||||||
info = {
|
|
||||||
tlw.gui_id: {
|
|
||||||
"title": tlw.windowTitle(),
|
|
||||||
"visible": tlw.isVisible(),
|
|
||||||
"class": str(type(tlw)),
|
|
||||||
}
|
|
||||||
for tlw in QApplication.instance().topLevelWidgets()
|
|
||||||
if tlw is not self and tlw.windowTitle()
|
|
||||||
}
|
|
||||||
# Add the main window dock area
|
|
||||||
info[self.centralWidget().gui_id] = {
|
|
||||||
"title": self.windowTitle(),
|
|
||||||
"visible": self.isVisible(),
|
|
||||||
"class": str(type(self.centralWidget())),
|
|
||||||
}
|
|
||||||
return info
|
|
||||||
|
|
||||||
def new_dock_area(
|
|
||||||
self, name: str | None = None, geometry: tuple[int, int, int, int] | None = None
|
|
||||||
) -> "BECDockArea":
|
|
||||||
"""Create a new dock area.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name(str): The name of the dock area.
|
|
||||||
geometry(tuple): The geometry parameters to be passed to the dock area.
|
|
||||||
Returns:
|
|
||||||
BECDockArea: The newly created dock area.
|
|
||||||
"""
|
|
||||||
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
|
|
||||||
|
|
||||||
with RPCRegister.delayed_broadcast() as rpc_register:
|
|
||||||
existing_dock_areas = rpc_register.get_names_of_rpc_by_class_type(BECDockArea)
|
|
||||||
if name is not None:
|
|
||||||
if name in existing_dock_areas:
|
|
||||||
raise ValueError(
|
|
||||||
f"Name {name} must be unique for dock areas, but already exists: {existing_dock_areas}."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
name = "dock_area"
|
|
||||||
name = WidgetContainerUtils.generate_unique_name(name, existing_dock_areas)
|
|
||||||
dock_area = WindowWithUi() # BECDockArea(name=name)
|
|
||||||
dock_area.resize(dock_area.minimumSizeHint())
|
|
||||||
# TODO Should we simply use the specified name as title here?
|
|
||||||
dock_area.window().setWindowTitle(f"BEC - {name}")
|
|
||||||
logger.info(f"Created new dock area: {name}")
|
|
||||||
logger.info(f"Existing dock areas: {geometry}")
|
|
||||||
if geometry is not None:
|
|
||||||
dock_area.setGeometry(*geometry)
|
|
||||||
dock_area.show()
|
|
||||||
return dock_area
|
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
super().close()
|
central_widget = self.centralWidget()
|
||||||
|
central_widget.close()
|
||||||
|
central_widget.deleteLater()
|
||||||
class WindowWithUi(BECMainWindow):
|
super().cleanup()
|
||||||
"""
|
|
||||||
This is just testing app wiht UI file which could be connected to RPC.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
USER_ACCESS = [
|
|
||||||
"new_dock_area",
|
|
||||||
"all_connections",
|
|
||||||
"change_theme",
|
|
||||||
"dock_area",
|
|
||||||
"register_all_rpc",
|
|
||||||
"widget_list",
|
|
||||||
"list_app_hierarchy",
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, *args, name: str = None, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
if name is None:
|
|
||||||
name = self.__class__.__name__
|
|
||||||
else:
|
|
||||||
if not WidgetContainerUtils.has_name_valid_chars(name):
|
|
||||||
raise ValueError(f"Name {name} contains invalid characters.")
|
|
||||||
self._name = name if name else self.__class__.__name__
|
|
||||||
ui_file_path = os.path.join(os.path.dirname(__file__), "example_app.ui")
|
|
||||||
self.load_ui(ui_file_path)
|
|
||||||
|
|
||||||
def load_ui(self, ui_file):
|
|
||||||
loader = UILoader(self)
|
|
||||||
self.ui = loader.loader(ui_file)
|
|
||||||
self.setCentralWidget(self.ui)
|
|
||||||
|
|
||||||
# TODO actually these propertiers are not much exposed now in the real CLI
|
|
||||||
@property
|
|
||||||
def dock_area(self):
|
|
||||||
dock_area = self.ui.dock_area
|
|
||||||
return dock_area
|
|
||||||
|
|
||||||
@property
|
|
||||||
def all_connections(self) -> list:
|
|
||||||
all_connections = self.rpc_register.list_all_connections()
|
|
||||||
all_connections_keys = list(all_connections.keys())
|
|
||||||
return all_connections_keys
|
|
||||||
|
|
||||||
def register_all_rpc(self):
|
|
||||||
app = QApplication.instance()
|
|
||||||
app.register_all()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def widget_list(self) -> list:
|
|
||||||
"""Return a list of all widgets in the application."""
|
|
||||||
app = QApplication.instance()
|
|
||||||
all_widgets = app.list_all_bec_widgets()
|
|
||||||
return all_widgets
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
print(id(app))
|
|
||||||
# app = BECApplication(sys.argv)
|
|
||||||
# print(id(app))
|
|
||||||
main_window = WindowWithUi()
|
|
||||||
main_window.show()
|
|
||||||
sys.exit(app.exec())
|
|
||||||
|
@ -14,7 +14,7 @@ from bec_widgets.utils.colors import set_theme
|
|||||||
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
||||||
from bec_widgets.utils.settings_dialog import SettingsDialog
|
from bec_widgets.utils.settings_dialog import SettingsDialog
|
||||||
from bec_widgets.utils.toolbar import MaterialIconAction
|
from bec_widgets.utils.toolbar import MaterialIconAction
|
||||||
from bec_widgets.widgets.plots.plot_base import PlotBase
|
from bec_widgets.widgets.plots.plot_base import PlotBase, UIMode
|
||||||
from bec_widgets.widgets.plots.scatter_waveform.scatter_curve import (
|
from bec_widgets.widgets.plots.scatter_waveform.scatter_curve import (
|
||||||
ScatterCurve,
|
ScatterCurve,
|
||||||
ScatterCurveConfig,
|
ScatterCurveConfig,
|
||||||
@ -129,7 +129,8 @@ class ScatterWaveform(PlotBase):
|
|||||||
self.proxy_update_sync = pg.SignalProxy(
|
self.proxy_update_sync = pg.SignalProxy(
|
||||||
self.sync_signal_update, rateLimit=25, slot=self.update_sync_curves
|
self.sync_signal_update, rateLimit=25, slot=self.update_sync_curves
|
||||||
)
|
)
|
||||||
self._init_scatter_curve_settings()
|
if self.ui_mode == UIMode.SIDE:
|
||||||
|
self._init_scatter_curve_settings()
|
||||||
self.update_with_scan_history(-1)
|
self.update_with_scan_history(-1)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@ -512,7 +513,6 @@ class ScatterWaveform(PlotBase):
|
|||||||
self.scatter_dialog.deleteLater()
|
self.scatter_dialog.deleteLater()
|
||||||
if self.scatter_curve_settings is not None:
|
if self.scatter_curve_settings is not None:
|
||||||
self.scatter_curve_settings.cleanup()
|
self.scatter_curve_settings.cleanup()
|
||||||
print("scatter_curve_settings celanup called")
|
|
||||||
self.bec_dispatcher.disconnect_slot(self.on_scan_status, MessageEndpoints.scan_status())
|
self.bec_dispatcher.disconnect_slot(self.on_scan_status, MessageEndpoints.scan_status())
|
||||||
self.bec_dispatcher.disconnect_slot(self.on_scan_progress, MessageEndpoints.scan_progress())
|
self.bec_dispatcher.disconnect_slot(self.on_scan_progress, MessageEndpoints.scan_progress())
|
||||||
self.plot_item.removeItem(self._main_curve)
|
self.plot_item.removeItem(self._main_curve)
|
||||||
|
Reference in New Issue
Block a user