mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
refactor: cleanup rpc reference tracking, fix appquit, fix namespace updates edge cases
This commit is contained in:
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import importlib
|
|
||||||
import importlib.metadata as imd
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import select
|
import select
|
||||||
@ -21,24 +19,19 @@ from rich.console import Console
|
|||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
|
|
||||||
import bec_widgets.cli.client as client
|
import bec_widgets.cli.client as client
|
||||||
|
|
||||||
# from bec_widgets.cli.auto_updates import AutoUpdates
|
|
||||||
from bec_widgets.cli.rpc.rpc_base import RPCBase, RPCReference
|
from bec_widgets.cli.rpc.rpc_base import RPCBase, RPCReference
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_lib import messages
|
|
||||||
from bec_lib.connector import MessageObject
|
|
||||||
from bec_lib.device import DeviceBase
|
|
||||||
from bec_lib.redis_connector import StreamMessage
|
from bec_lib.redis_connector import StreamMessage
|
||||||
else:
|
else:
|
||||||
messages = lazy_import("bec_lib.messages")
|
|
||||||
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
|
|
||||||
StreamMessage = lazy_import_from("bec_lib.redis_connector", ("StreamMessage",))
|
StreamMessage = lazy_import_from("bec_lib.redis_connector", ("StreamMessage",))
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
IGNORE_WIDGETS = ["BECDockArea", "BECDock"]
|
IGNORE_WIDGETS = ["BECDockArea", "BECDock"]
|
||||||
|
|
||||||
|
# pylint: disable=redefined-outer-scope
|
||||||
|
|
||||||
|
|
||||||
def _filter_output(output: str) -> str:
|
def _filter_output(output: str) -> str:
|
||||||
"""
|
"""
|
||||||
@ -258,7 +251,7 @@ class BECGuiClient(RPCBase):
|
|||||||
"""Show the GUI window."""
|
"""Show the GUI window."""
|
||||||
if self._check_if_server_is_alive():
|
if self._check_if_server_is_alive():
|
||||||
return self._show_all()
|
return self._show_all()
|
||||||
return self._start(wait=True)
|
return self.start(wait=True)
|
||||||
|
|
||||||
def hide(self):
|
def hide(self):
|
||||||
"""Hide the GUI window."""
|
"""Hide the GUI window."""
|
||||||
@ -279,7 +272,8 @@ class BECGuiClient(RPCBase):
|
|||||||
Returns:
|
Returns:
|
||||||
client.BECDockArea: The new dock area.
|
client.BECDockArea: The new dock area.
|
||||||
"""
|
"""
|
||||||
self.show()
|
if not self._check_if_server_is_alive():
|
||||||
|
self.start(wait=True)
|
||||||
if wait:
|
if wait:
|
||||||
with wait_for_server(self):
|
with wait_for_server(self):
|
||||||
rpc_client = RPCBase(gui_id=f"{self._gui_id}:window", parent=self)
|
rpc_client = RPCBase(gui_id=f"{self._gui_id}:window", parent=self)
|
||||||
@ -313,11 +307,7 @@ class BECGuiClient(RPCBase):
|
|||||||
|
|
||||||
def kill_server(self) -> None:
|
def kill_server(self) -> None:
|
||||||
"""Kill the GUI server."""
|
"""Kill the GUI server."""
|
||||||
self._top_level.clear()
|
|
||||||
# Unregister the registry state
|
# Unregister the registry state
|
||||||
self._client.connector.unregister(
|
|
||||||
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
|
|
||||||
)
|
|
||||||
self._killed = True
|
self._killed = True
|
||||||
|
|
||||||
if self._gui_started_timer is not None:
|
if self._gui_started_timer is not None:
|
||||||
@ -339,6 +329,9 @@ class BECGuiClient(RPCBase):
|
|||||||
self._client.connector.unregister(
|
self._client.connector.unregister(
|
||||||
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
|
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
|
||||||
)
|
)
|
||||||
|
# Remove all reference from top level
|
||||||
|
self._top_level.clear()
|
||||||
|
self._registry_state.clear()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Deprecated. Use kill_server() instead."""
|
"""Deprecated. Use kill_server() instead."""
|
||||||
@ -358,24 +351,14 @@ class BECGuiClient(RPCBase):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _gui_post_startup(self):
|
def _gui_post_startup(self):
|
||||||
timeout = 10
|
timeout = 60
|
||||||
|
# Wait for 'bec' gui to be registered, this may take some time
|
||||||
|
# After 60s timeout. Should this raise an exception on timeout?
|
||||||
while time.time() < time.time() + timeout:
|
while time.time() < time.time() + timeout:
|
||||||
if len(list(self._registry_state.keys())) == 0:
|
if len(list(self._registry_state.keys())) == 0:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
# FIXME AUTO UPDATES
|
|
||||||
# if self._auto_updates_enabled:
|
|
||||||
# if self._auto_updates is None:
|
|
||||||
# auto_updates = self._get_update_script()
|
|
||||||
# if auto_updates is None:
|
|
||||||
# AutoUpdates.create_default_dock = True
|
|
||||||
# AutoUpdates.enabled = True
|
|
||||||
# auto_updates = AutoUpdates(self._top_level["main"].widget)
|
|
||||||
# if auto_updates.create_default_dock:
|
|
||||||
# auto_updates.start_default_dock()
|
|
||||||
# self._start_update_script()
|
|
||||||
# self._auto_updates = auto_updates
|
|
||||||
self._do_show_all()
|
self._do_show_all()
|
||||||
self._gui_started_event.set()
|
self._gui_started_event.set()
|
||||||
|
|
||||||
@ -416,15 +399,19 @@ class BECGuiClient(RPCBase):
|
|||||||
|
|
||||||
def _start(self, wait: bool = False) -> None:
|
def _start(self, wait: bool = False) -> None:
|
||||||
self._killed = False
|
self._killed = False
|
||||||
|
# Clear the registry state
|
||||||
|
self._registry_state.clear()
|
||||||
|
# Clear top level
|
||||||
|
self._top_level.clear()
|
||||||
self._client.connector.register(
|
self._client.connector.register(
|
||||||
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
|
MessageEndpoints.gui_registry_state(self._gui_id), cb=self._handle_registry_update
|
||||||
)
|
)
|
||||||
return self._start_server(wait=wait)
|
return self._start_server(wait=wait)
|
||||||
|
|
||||||
def _handle_registry_update(self, msg: StreamMessage) -> None:
|
def _handle_registry_update(self, msg: StreamMessage) -> None:
|
||||||
# with self._lock:
|
with self._lock:
|
||||||
self._registry_state = msg["data"].state
|
self._registry_state = msg["data"].state
|
||||||
self._update_dynamic_namespace()
|
self._update_dynamic_namespace()
|
||||||
|
|
||||||
def _do_show_all(self):
|
def _do_show_all(self):
|
||||||
rpc_client = RPCBase(gui_id=f"{self._gui_id}:window", parent=self)
|
rpc_client = RPCBase(gui_id=f"{self._gui_id}:window", parent=self)
|
||||||
@ -446,6 +433,8 @@ class BECGuiClient(RPCBase):
|
|||||||
|
|
||||||
def _update_dynamic_namespace(self):
|
def _update_dynamic_namespace(self):
|
||||||
"""Update the dynamic name space"""
|
"""Update the dynamic name space"""
|
||||||
|
# Clear the top level
|
||||||
|
self._top_level.clear()
|
||||||
# First we update the name space based on the new registry state
|
# First we update the name space based on the new registry state
|
||||||
self._add_registry_to_namespace()
|
self._add_registry_to_namespace()
|
||||||
# Then we clear the ipython registry from old objects
|
# Then we clear the ipython registry from old objects
|
||||||
@ -559,75 +548,6 @@ class BECGuiClient(RPCBase):
|
|||||||
obj = RPCReference(registry=self._ipython_registry, gui_id=gui_id)
|
obj = RPCReference(registry=self._ipython_registry, gui_id=gui_id)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
################################
|
|
||||||
#### Auto updates ####
|
|
||||||
#### potentially deprecated ####
|
|
||||||
################################
|
|
||||||
|
|
||||||
# FIXME AUTO UPDATES
|
|
||||||
# @property
|
|
||||||
# def auto_updates(self):
|
|
||||||
# if self._auto_updates_enabled:
|
|
||||||
# with wait_for_server(self):
|
|
||||||
# return self._auto_updates
|
|
||||||
|
|
||||||
# def _get_update_script(self) -> AutoUpdates | None:
|
|
||||||
# eps = imd.entry_points(group="bec.widgets.auto_updates")
|
|
||||||
# for ep in eps:
|
|
||||||
# if ep.name == "plugin_widgets_update":
|
|
||||||
# try:
|
|
||||||
# spec = importlib.util.find_spec(ep.module)
|
|
||||||
# # if the module is not found, we skip it
|
|
||||||
# if spec is None:
|
|
||||||
# continue
|
|
||||||
# return ep.load()(gui=self._top_level["main"])
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.error(f"Error loading auto update script from plugin: {str(e)}")
|
|
||||||
# return None
|
|
||||||
|
|
||||||
# FIXME AUTO UPDATES
|
|
||||||
# @property
|
|
||||||
# def selected_device(self) -> str | None:
|
|
||||||
# """
|
|
||||||
# Selected device for the plot.
|
|
||||||
# """
|
|
||||||
# auto_update_config_ep = MessageEndpoints.gui_auto_update_config(self._gui_id)
|
|
||||||
# auto_update_config = self._client.connector.get(auto_update_config_ep)
|
|
||||||
# if auto_update_config:
|
|
||||||
# return auto_update_config.selected_device
|
|
||||||
# return None
|
|
||||||
|
|
||||||
# @selected_device.setter
|
|
||||||
# def selected_device(self, device: str | DeviceBase):
|
|
||||||
# if isinstance_based_on_class_name(device, "bec_lib.device.DeviceBase"):
|
|
||||||
# self._client.connector.set_and_publish(
|
|
||||||
# MessageEndpoints.gui_auto_update_config(self._gui_id),
|
|
||||||
# messages.GUIAutoUpdateConfigMessage(selected_device=device.name),
|
|
||||||
# )
|
|
||||||
# elif isinstance(device, str):
|
|
||||||
# self._client.connector.set_and_publish(
|
|
||||||
# MessageEndpoints.gui_auto_update_config(self._gui_id),
|
|
||||||
# messages.GUIAutoUpdateConfigMessage(selected_device=device),
|
|
||||||
# )
|
|
||||||
# else:
|
|
||||||
# raise ValueError("Device must be a string or a device object")
|
|
||||||
|
|
||||||
# FIXME AUTO UPDATES
|
|
||||||
# def _start_update_script(self) -> None:
|
|
||||||
# self._client.connector.register(MessageEndpoints.scan_status(), cb=self._handle_msg_update)
|
|
||||||
|
|
||||||
# def _handle_msg_update(self, msg: StreamMessage) -> None:
|
|
||||||
# if self.auto_updates is not None:
|
|
||||||
# # pylint: disable=protected-access
|
|
||||||
# return self._update_script_msg_parser(msg.value)
|
|
||||||
|
|
||||||
# def _update_script_msg_parser(self, msg: messages.BECMessage) -> None:
|
|
||||||
# if isinstance(msg, messages.ScanStatusMessage):
|
|
||||||
# if not self._gui_is_alive():
|
|
||||||
# return
|
|
||||||
# if self._auto_updates_enabled:
|
|
||||||
# return self.auto_updates.do_update(msg)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
from bec_lib.client import BECClient
|
from bec_lib.client import BECClient
|
||||||
@ -642,8 +562,7 @@ if __name__ == "__main__": # pragma: no cover
|
|||||||
gui = BECGuiClient()
|
gui = BECGuiClient()
|
||||||
|
|
||||||
gui.start(wait=True)
|
gui.start(wait=True)
|
||||||
print(gui.window_list)
|
gui.new().new(widget="Waveform")
|
||||||
gui.new()
|
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
finally:
|
finally:
|
||||||
gui.kill_server()
|
gui.kill_server()
|
||||||
|
@ -4,7 +4,7 @@ import inspect
|
|||||||
import threading
|
import threading
|
||||||
import uuid
|
import uuid
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import TYPE_CHECKING, Any, cast
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from bec_lib.client import BECClient
|
from bec_lib.client import BECClient
|
||||||
from bec_lib.endpoints import MessageEndpoints
|
from bec_lib.endpoints import MessageEndpoints
|
||||||
@ -20,6 +20,8 @@ else:
|
|||||||
# from bec_lib.connector import MessageObject
|
# from bec_lib.connector import MessageObject
|
||||||
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
|
MessageObject = lazy_import_from("bec_lib.connector", ("MessageObject",))
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
|
||||||
|
|
||||||
def rpc_call(func):
|
def rpc_call(func):
|
||||||
"""
|
"""
|
||||||
@ -40,6 +42,7 @@ def rpc_call(func):
|
|||||||
while caller_frame:
|
while caller_frame:
|
||||||
if "jedi" in caller_frame.f_globals:
|
if "jedi" in caller_frame.f_globals:
|
||||||
# Jedi module is present, likely tab completion
|
# Jedi module is present, likely tab completion
|
||||||
|
# Do not run the RPC call
|
||||||
return None # func(*args, **kwargs)
|
return None # func(*args, **kwargs)
|
||||||
caller_frame = caller_frame.f_back
|
caller_frame = caller_frame.f_back
|
||||||
|
|
||||||
@ -160,7 +163,7 @@ class RPCBase:
|
|||||||
parent = parent._parent
|
parent = parent._parent
|
||||||
return parent
|
return parent
|
||||||
|
|
||||||
def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=3, **kwargs) -> Any:
|
def _run_rpc(self, method, *args, wait_for_rpc_response=True, timeout=300, **kwargs) -> Any:
|
||||||
"""
|
"""
|
||||||
Run the RPC call.
|
Run the RPC call.
|
||||||
|
|
||||||
@ -179,7 +182,6 @@ class RPCBase:
|
|||||||
parameter={"args": args, "kwargs": kwargs, "gui_id": self._gui_id},
|
parameter={"args": args, "kwargs": kwargs, "gui_id": self._gui_id},
|
||||||
metadata={"request_id": request_id},
|
metadata={"request_id": request_id},
|
||||||
)
|
)
|
||||||
print(f"running and rpc {method}")
|
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
receiver = self._root._gui_id
|
receiver = self._root._gui_id
|
||||||
if wait_for_rpc_response:
|
if wait_for_rpc_response:
|
||||||
@ -233,7 +235,12 @@ class RPCBase:
|
|||||||
return msg_result
|
return msg_result
|
||||||
|
|
||||||
cls = getattr(client, cls)
|
cls = getattr(client, cls)
|
||||||
# print(msg_result)
|
# The namespace of the object will be updated dynamically on the client side
|
||||||
|
# Therefor it is important to check if the object is already in the registry
|
||||||
|
# If yes, we return the reference to the object, otherwise we create a new object
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if msg_result["gui_id"] in self._root._ipython_registry:
|
||||||
|
return RPCReference(self._root._ipython_registry, msg_result["gui_id"])
|
||||||
ret = cls(parent=self, **msg_result)
|
ret = cls(parent=self, **msg_result)
|
||||||
self._root._ipython_registry[ret._gui_id] = ret
|
self._root._ipython_registry[ret._gui_id] = ret
|
||||||
obj = RPCReference(self._root._ipython_registry, ret._gui_id)
|
obj = RPCReference(self._root._ipython_registry, ret._gui_id)
|
||||||
|
@ -37,7 +37,7 @@ def broadcast_update(func):
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(self, *args, **kwargs):
|
def wrapper(self, *args, **kwargs):
|
||||||
result = func(self, *args, **kwargs)
|
result = func(self, *args, **kwargs)
|
||||||
self.broadcast()
|
# self.broadcast()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
@ -130,7 +130,6 @@ class RPCRegister:
|
|||||||
"""
|
"""
|
||||||
Broadcast the update to all the callbacks.
|
Broadcast the update to all the callbacks.
|
||||||
"""
|
"""
|
||||||
# print("Broadcasting")
|
|
||||||
connections = self.list_all_connections()
|
connections = self.list_all_connections()
|
||||||
for callback in self.callbacks:
|
for callback in self.callbacks:
|
||||||
callback(connections)
|
callback(connections)
|
||||||
|
@ -117,6 +117,7 @@ class BECWidgetsCLIServer:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
def run_rpc(self, obj, method, args, kwargs):
|
def run_rpc(self, obj, method, args, kwargs):
|
||||||
|
# Run with rpc registry broadcast, but only once
|
||||||
with rpc_register_broadcast(self.rpc_register):
|
with rpc_register_broadcast(self.rpc_register):
|
||||||
logger.debug(f"Running RPC instruction: {method} with args: {args}, kwargs: {kwargs}")
|
logger.debug(f"Running RPC instruction: {method} with args: {args}, kwargs: {kwargs}")
|
||||||
method_obj = getattr(obj, method)
|
method_obj = getattr(obj, method)
|
||||||
@ -315,6 +316,12 @@ def main():
|
|||||||
def sigint_handler(*args):
|
def sigint_handler(*args):
|
||||||
# display message, for people to let it terminate gracefully
|
# display message, for people to let it terminate gracefully
|
||||||
print("Caught SIGINT, exiting")
|
print("Caught SIGINT, exiting")
|
||||||
|
# Close all widgets
|
||||||
|
rpc_register = RPCRegister()
|
||||||
|
with rpc_register_broadcast(rpc_register):
|
||||||
|
for widget in QApplication.instance().topLevelWidgets():
|
||||||
|
widget.close()
|
||||||
|
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, sigint_handler)
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
@ -318,7 +318,6 @@ class BECConnector:
|
|||||||
self.deleteLater()
|
self.deleteLater()
|
||||||
else:
|
else:
|
||||||
self.rpc_register.remove_rpc(self)
|
self.rpc_register.remove_rpc(self)
|
||||||
self.rpc_register.broadcast()
|
|
||||||
|
|
||||||
def get_config(self, dict_output: bool = True) -> dict | BaseModel:
|
def get_config(self, dict_output: bool = True) -> dict | BaseModel:
|
||||||
"""
|
"""
|
||||||
|
@ -7,9 +7,9 @@ from bec_lib.logger import bec_logger
|
|||||||
from qtpy.QtCore import Slot
|
from qtpy.QtCore import Slot
|
||||||
from qtpy.QtWidgets import QApplication, QWidget
|
from qtpy.QtWidgets import QApplication, QWidget
|
||||||
|
|
||||||
|
from bec_widgets.cli.rpc.rpc_register import rpc_register_broadcast
|
||||||
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
|
from bec_widgets.utils.bec_connector import BECConnector, ConnectionConfig
|
||||||
from bec_widgets.utils.colors import set_theme
|
from bec_widgets.utils.colors import set_theme
|
||||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from bec_widgets.widgets.containers.dock import BECDock
|
from bec_widgets.widgets.containers.dock import BECDock
|
||||||
@ -101,8 +101,9 @@ class BECWidget(BECConnector):
|
|||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
"""Cleanup the widget."""
|
"""Cleanup the widget."""
|
||||||
# All widgets need to call super().cleanup() in their cleanup method
|
with rpc_register_broadcast(self.rpc_register):
|
||||||
self.rpc_register.remove_rpc(self)
|
# All widgets need to call super().cleanup() in their cleanup method
|
||||||
|
self.rpc_register.remove_rpc(self)
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Wrap the close even to ensure the rpc_register is cleaned up."""
|
"""Wrap the close even to ensure the rpc_register is cleaned up."""
|
||||||
|
@ -8,7 +8,6 @@ from pyqtgraph.dockarea import Dock, DockLabel
|
|||||||
from qtpy import QtCore, QtGui
|
from qtpy import QtCore, QtGui
|
||||||
|
|
||||||
from bec_widgets.cli.client_utils import IGNORE_WIDGETS
|
from bec_widgets.cli.client_utils import IGNORE_WIDGETS
|
||||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
|
||||||
from bec_widgets.cli.rpc.rpc_widget_handler import widget_handler
|
from bec_widgets.cli.rpc.rpc_widget_handler import widget_handler
|
||||||
from bec_widgets.utils import ConnectionConfig, GridLayoutManager
|
from bec_widgets.utils import ConnectionConfig, GridLayoutManager
|
||||||
from bec_widgets.utils.bec_widget import BECWidget
|
from bec_widgets.utils.bec_widget import BECWidget
|
||||||
@ -336,13 +335,8 @@ class BECDock(BECWidget, Dock):
|
|||||||
if hasattr(widget, "config"):
|
if hasattr(widget, "config"):
|
||||||
widget.config.gui_id = widget.gui_id
|
widget.config.gui_id = widget.gui_id
|
||||||
self.config.widgets[widget._name] = widget.config # pylint: disable=protected-access
|
self.config.widgets[widget._name] = widget.config # pylint: disable=protected-access
|
||||||
self._broadcast_update()
|
|
||||||
return widget
|
return widget
|
||||||
|
|
||||||
def _broadcast_update(self):
|
|
||||||
rpc_register = RPCRegister()
|
|
||||||
rpc_register.broadcast()
|
|
||||||
|
|
||||||
def move_widget(self, widget: QWidget, new_row: int, new_col: int):
|
def move_widget(self, widget: QWidget, new_row: int, new_col: int):
|
||||||
"""
|
"""
|
||||||
Move a widget to a new position in the layout.
|
Move a widget to a new position in the layout.
|
||||||
@ -400,7 +394,6 @@ class BECDock(BECWidget, Dock):
|
|||||||
if widget in self.widgets:
|
if widget in self.widgets:
|
||||||
self.widgets.remove(widget)
|
self.widgets.remove(widget)
|
||||||
widget.close()
|
widget.close()
|
||||||
# self._broadcast_update()
|
|
||||||
|
|
||||||
def delete_all(self):
|
def delete_all(self):
|
||||||
"""
|
"""
|
||||||
@ -423,15 +416,6 @@ class BECDock(BECWidget, Dock):
|
|||||||
self.label.deleteLater()
|
self.label.deleteLater()
|
||||||
super().cleanup()
|
super().cleanup()
|
||||||
|
|
||||||
# def closeEvent(self, event): # pylint: disable=uselsess-parent-delegation
|
|
||||||
# """Close Event for dock and cleanup.
|
|
||||||
|
|
||||||
# This wrapper ensures that the BECWidget close event is triggered.
|
|
||||||
# If removed, the closeEvent from pyqtgraph will be triggered, which
|
|
||||||
# is not calling super().closeEvent(event) and will not trigger the BECWidget close event.
|
|
||||||
# """
|
|
||||||
# return super().closeEvent(event)
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Close the dock area and cleanup.
|
Close the dock area and cleanup.
|
||||||
|
@ -11,7 +11,7 @@ from qtpy.QtCore import QSize, Qt
|
|||||||
from qtpy.QtGui import QPainter, QPaintEvent
|
from qtpy.QtGui import QPainter, QPaintEvent
|
||||||
from qtpy.QtWidgets import QApplication, QSizePolicy, QVBoxLayout, QWidget
|
from qtpy.QtWidgets import QApplication, QSizePolicy, QVBoxLayout, QWidget
|
||||||
|
|
||||||
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
from bec_widgets.cli.rpc.rpc_register import RPCRegister, rpc_register_broadcast
|
||||||
from bec_widgets.qt_utils.error_popups import SafeSlot
|
from bec_widgets.qt_utils.error_popups import SafeSlot
|
||||||
from bec_widgets.qt_utils.toolbar import (
|
from bec_widgets.qt_utils.toolbar import (
|
||||||
ExpandableMenuAction,
|
ExpandableMenuAction,
|
||||||
@ -225,8 +225,11 @@ class BECDockArea(BECWidget, QWidget):
|
|||||||
|
|
||||||
@SafeSlot()
|
@SafeSlot()
|
||||||
def _create_widget_from_toolbar(self, widget_name: str) -> None:
|
def _create_widget_from_toolbar(self, widget_name: str) -> None:
|
||||||
dock_name = WidgetContainerUtils.generate_unique_name(widget_name, self.panels.keys())
|
rpc_register = RPCRegister()
|
||||||
self.new(name=dock_name, widget=widget_name)
|
# Run with RPC broadcast to namespace of all widgets
|
||||||
|
with rpc_register_broadcast(rpc_register):
|
||||||
|
dock_name = WidgetContainerUtils.generate_unique_name(widget_name, self.panels.keys())
|
||||||
|
self.new(name=dock_name, widget=widget_name)
|
||||||
|
|
||||||
def paintEvent(self, event: QPaintEvent): # TODO decide if we want any default instructions
|
def paintEvent(self, event: QPaintEvent): # TODO decide if we want any default instructions
|
||||||
super().paintEvent(event)
|
super().paintEvent(event)
|
||||||
@ -381,14 +384,8 @@ class BECDockArea(BECWidget, QWidget):
|
|||||||
self.update()
|
self.update()
|
||||||
if floating:
|
if floating:
|
||||||
dock.detach()
|
dock.detach()
|
||||||
# Run broadcast update
|
|
||||||
self._broadcast_update()
|
|
||||||
return dock
|
return dock
|
||||||
|
|
||||||
def _broadcast_update(self):
|
|
||||||
rpc_register = RPCRegister()
|
|
||||||
rpc_register.broadcast()
|
|
||||||
|
|
||||||
def detach_dock(self, dock_name: str) -> BECDock:
|
def detach_dock(self, dock_name: str) -> BECDock:
|
||||||
"""
|
"""
|
||||||
Undock a dock from the dock area.
|
Undock a dock from the dock area.
|
||||||
|
Reference in New Issue
Block a user