0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-13 11:11:49 +02:00

WIP very messy ui as a server window, however, works as expected

This commit is contained in:
2025-03-19 16:50:08 +01:00
parent d27edbbf6d
commit 1b680b0b1d
8 changed files with 517 additions and 12 deletions

View File

@ -335,6 +335,13 @@ class BECDock(RPCBase):
class BECDockArea(RPCBase):
@property
@rpc_call
def all_connections(self) -> "list":
"""
None
"""
@rpc_call
def new(
self,
@ -468,6 +475,21 @@ class BECDockArea(RPCBase):
extra(str): Extra docks that are in the dockarea but that are not mentioned in state will be added to the bottom of the dockarea, unless otherwise specified by the extra argument.
"""
@rpc_call
def list_all_rpc(self) -> "dict":
"""
List all the registered RPC objects.
Returns:
dict: A dictionary containing all the registered RPC objects.
"""
@property
@rpc_call
def widget_list(self) -> "list":
"""
Return a list of all widgets in the application.
"""
class BECFigure(RPCBase):
@property
@ -1198,9 +1220,32 @@ class BECImageShow(RPCBase):
class BECMainWindow(RPCBase):
@rpc_call
def remove(self):
def new_dock_area(
self, name: "str | None" = None, geometry: "tuple[int, int, int, int] | None" = None
) -> "BECDockArea":
"""
Cleanup the BECConnector
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.
"""
@rpc_call
def change_theme(self, theme):
"""
None
"""
@rpc_call
def list_all_rpc(self) -> "list":
"""
List all the registered RPC objects.
Returns:
dict: A dictionary containing all the registered RPC objects.
"""
@ -4956,3 +5001,63 @@ class WebsiteWidget(RPCBase):
"""
Go forward in the history
"""
class WindowWithUi(RPCBase):
"""A class that represents a window with a user interface."""
@rpc_call
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.
"""
@property
@rpc_call
def all_connections(self) -> "list":
"""
None
"""
@rpc_call
def change_theme(self, theme):
"""
None
"""
@rpc_call
def list_all_rpc(self) -> "list":
"""
List all the registered RPC objects.
Returns:
dict: A dictionary containing all the registered RPC objects.
"""
@property
@rpc_call
def dock_area(self):
"""
None
"""
@rpc_call
def register_all_rpc(self):
"""
None
"""
@property
@rpc_call
def widget_list(self) -> "list":
"""
Return a list of all widgets in the application.
"""

View File

@ -249,6 +249,12 @@ class BECGuiClient(RPCBase):
raise RuntimeError("No GUI connected. Call 'connect_gui(gui_id)' first.")
return self._run_rpc(action, *(args or []), timeout=timeout, **(kwargs or {}))
# @property
# def all_connections(self):
# """Get all connections to the GUI."""
# all_connections = self.
# # pylint: disable=protected-access
# return client.RPCRegister()._rpc_register
@property
def windows(self) -> dict:
"""Dictionary with dock areas in the GUI."""
@ -444,6 +450,11 @@ class BECGuiClient(RPCBase):
self._top_level[widget.widget_name] = widget
return widget
def list_all_rpc(self) -> dict:
"""List all RPC connections."""
rpc_client = RPCBase(gui_id=f"{self._gui_id}:window", parent=self)
list = rpc_client._run_rpc("list_all_rpc") # pylint: disable=protected-access
def delete(self, name: str) -> None:
"""Delete a dock area.

View File

@ -23,7 +23,7 @@ from bec_widgets.utils import BECDispatcher
from bec_widgets.utils.bec_connector import BECConnector
from bec_widgets.widgets.containers.dock import BECDockArea
from bec_widgets.widgets.containers.figure import BECFigure
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow, WindowWithUi
messages = lazy_import("bec_lib.messages")
logger = bec_logger.logger
@ -60,7 +60,7 @@ class BECWidgetsCLIServer:
dispatcher: BECDispatcher = None,
client=None,
config=None,
gui_class: Union[BECFigure, BECDockArea] = BECDockArea,
gui_class: Union[BECFigure, BECDockArea, WindowWithUi] = BECDockArea,
gui_class_id: str = "bec",
) -> None:
self.status = messages.BECStatus.BUSY
@ -191,7 +191,7 @@ class SimpleFileLikeFromLogOutputFunc:
def _start_server(
gui_id: str,
gui_class: Union[BECFigure, BECDockArea],
gui_class: Union[BECFigure, BECDockArea, BECMainWindow],
gui_class_id: str = "bec",
config: str | None = None,
):
@ -255,12 +255,14 @@ def main():
gui_class = BECDockArea
elif args.gui_class == "BECFigure":
gui_class = BECFigure
elif args.gui_class == "MainWindow":
gui_class = WindowWithUi
else:
print(
"Please specify a valid gui_class to run. Use -h for help."
"\n Starting with default gui_class BECFigure."
)
gui_class = BECDockArea
gui_class = WindowWithUi
with redirect_stdout(SimpleFileLikeFromLogOutputFunc(logger.info)):
with redirect_stderr(SimpleFileLikeFromLogOutputFunc(logger.error)):

View File

@ -3,6 +3,8 @@ import os
import numpy as np
import pyqtgraph as pg
from bec_qthemes import material_icon
from bec_widgets.examples.qapp_custom.bec_qapp import BECQApplication
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
from qtpy.QtWidgets import (
QApplication,
QGroupBox,
@ -240,7 +242,7 @@ if __name__ == "__main__": # pragma: no cover
module_path = os.path.dirname(bec_widgets.__file__)
app = QApplication(sys.argv)
app = BECQApplication(sys.argv)
app.setApplicationName("Jupyter Console")
app.setApplicationDisplayName("Jupyter Console")
icon = material_icon("terminal", color=(255, 255, 255, 255), filled=True)
@ -250,7 +252,9 @@ if __name__ == "__main__": # pragma: no cover
client = bec_dispatcher.client
client.start()
win = JupyterConsoleWindow()
win = BECMainWindow()
widget = JupyterConsoleWindow()
win.setCentralWidget(widget)
win.show()
win.resize(1500, 800)

View File

@ -1,5 +1,6 @@
import os
from bec_widgets.utils.bec_widget import BECWidget
from qtpy.QtCore import QSize
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QApplication
@ -55,6 +56,25 @@ class BECQApplication(QApplication):
self.setWindowIcon(icon)
print("[BECQApplication]: Window icon set.")
def register_all(self):
widgets = self.allWidgets()
all_connections = self.rpc_register.list_all_connections()
for widget in widgets:
gui_id = getattr(widget, "gui_id", None)
if gui_id and widget not in all_connections:
self.rpc_register.add_rpc(widget)
print(
f"[BECQApplication]: Registered widget {widget.__class__} with GUI ID: {gui_id}"
)
def list_all_bec_widgets(self):
widgets = self.allWidgets()
bec_widgets = []
for widget in widgets:
if isinstance(widget, BECWidget):
bec_widgets.append(widget)
return bec_widgets
def shutdown(self):
self.dispatcher.disconnect_all()
super().shutdown()

View File

@ -49,6 +49,7 @@ class DockAreaConfig(ConnectionConfig):
class BECDockArea(BECWidget, QWidget):
PLUGIN = True
USER_ACCESS = [
"all_connections",
"new",
"show",
"hide",
@ -62,6 +63,8 @@ class BECDockArea(BECWidget, QWidget):
"selected_device",
"save_state",
"restore_state",
"list_all_rpc",
"widget_list",
]
def __init__(
@ -249,6 +252,12 @@ class BECDockArea(BECWidget, QWidget):
except AttributeError:
return None
@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
@property
def panels(self) -> dict[str, BECDock]:
"""
@ -272,6 +281,13 @@ class BECDockArea(BECWidget, QWidget):
"""
return list(self.dock_area.docks.values())
@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
@property
def temp_areas(self) -> list:
"""
@ -476,6 +492,16 @@ class BECDockArea(BECWidget, QWidget):
raise ValueError(f"Dock with name {dock_name} does not exist.")
# self._broadcast_update()
def list_all_rpc(self) -> dict:
"""
List all the registered RPC objects.
Returns:
dict: A dictionary containing all the registered RPC objects.
"""
rpc_register = RPCRegister()
all_connections = rpc_register.list_all_connections()
return all_connections
def remove(self) -> None:
"""Remove the dock area."""
self.close()

View File

@ -0,0 +1,262 @@
<?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>

View File

@ -1,10 +1,13 @@
from __future__ import annotations
import os
import sys
from bec_lib.logger import bec_logger
from PySide6.QtCore import QSize
from PySide6.QtGui import QAction, QActionGroup, QIcon
from PySide6.QtWidgets import QFileDialog, QMessageBox, QStyle, QWidget
from bec_widgets.examples.qapp_custom.bec_qapp import upgrade_to_becqapp
from bec_widgets.examples.qapp_custom.bec_qapp import upgrade_to_becqapp, BECQApplication
from bec_widgets.utils import UILoader
from qtpy.QtCore import Qt
from qtpy.QtWidgets import QApplication, QMainWindow
@ -21,10 +24,12 @@ logger = bec_logger.logger
class BECMainWindow(BECWidget, QMainWindow):
USER_ACCESS = ["new_dock_area", "change_theme", "show_gui_id"]
USER_ACCESS = ["new_dock_area", "change_theme", "list_all_rpc"]
def __init__(self, gui_id: str = None, default_widget=QWidget, *args, **kwargs):
BECWidget.__init__(self, gui_id=gui_id, **kwargs)
def __init__(
self, gui_id: str = None, name: str = None, default_widget=QWidget, *args, **kwargs
):
BECWidget.__init__(self, gui_id=gui_id, name=name, **kwargs)
QMainWindow.__init__(self, *args, **kwargs)
# Upgrade qApp if necessary
self.app = QApplication.instance()
@ -160,5 +165,75 @@ class BECMainWindow(BECWidget, QMainWindow):
new_q_main_window.show()
return dock_area
def list_all_rpc(self) -> list:
"""
List all the registered RPC objects.
Returns:
dict: A dictionary containing all the registered RPC objects.
"""
all_connections = self.rpc_register.list_all_connections()
all_connections_keys = list(all_connections.keys())
return all_connections_keys
def cleanup(self):
super().close()
class WindowWithUi(BECMainWindow):
"""
A class that represents a window with a user interface.
It inherits from BECMainWindow and provides additional functionality.
"""
USER_ACCESS = [
"new_dock_area",
"all_connections",
"change_theme",
"list_all_rpc",
"dock_area",
"register_all_rpc",
"widget_list",
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
ui_file_path = os.path.join(os.path.dirname(__file__), "general_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)
@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__":
app = BECQApplication(sys.argv)
window = WindowWithUi()
window.resize(1280, 720)
window.show()
sys.exit(app.exec())