mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-04-08 17:57:54 +02:00
Compare commits
4 Commits
scratch/de
...
feat/alt-d
| Author | SHA1 | Date | |
|---|---|---|---|
| 873937f33b | |||
| 81dffa11f0 | |||
| 66c0e4ecfc | |||
| c5cd3e3c3b |
@@ -2,6 +2,8 @@ import os
|
||||
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
import qdarktheme
|
||||
from PyQt6.QtWidgets import QPushButton, QTextEdit
|
||||
from pyqtgraph.Qt import QtWidgets, uic
|
||||
from qtconsole.inprocess import QtInProcessKernelManager
|
||||
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
||||
@@ -13,6 +15,7 @@ from bec_widgets.cli.rpc_register import RPCRegister
|
||||
from bec_widgets.utils import BECDispatcher
|
||||
from bec_widgets.widgets import BECFigure
|
||||
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
||||
from bec_widgets.widgets.dock_area.dock_area import BECDockAreaAlt
|
||||
from bec_widgets.widgets.spiral_progress_bar.spiral_progress_bar import SpiralProgressBar
|
||||
|
||||
|
||||
@@ -95,7 +98,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
self.console.set_default_style("linux")
|
||||
|
||||
def _init_figure(self):
|
||||
self.figure.plot(x_name="samx", y_name="bpm4d")
|
||||
self.figure.plot("samx", "bpm4d")
|
||||
self.figure.motor_map("samx", "samy")
|
||||
self.figure.image("eiger", color_map="viridis", vrange=(0, 100))
|
||||
|
||||
@@ -111,28 +114,40 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
self.c1 = self.w1.get_config()
|
||||
|
||||
def _init_dock(self):
|
||||
self.button_1 = QtWidgets.QPushButton("Button 1 ")
|
||||
self.button_2_a = QtWidgets.QPushButton("Button to be added at place 0,0 in d3")
|
||||
self.button_2_b = QtWidgets.QPushButton("button after without postions specified")
|
||||
self.button_2_c = QtWidgets.QPushButton("button super late")
|
||||
self.button_3 = QtWidgets.QPushButton("Button above Figure ")
|
||||
self.bar = SpiralProgressBar()
|
||||
|
||||
self.label_2 = QtWidgets.QLabel("label which is added separately")
|
||||
self.label_3 = QtWidgets.QLabel("Label above figure")
|
||||
self.d0 = self.dock.add_dock(name="dock_0")
|
||||
self.fig0 = self.d0.add_widget_bec("BECFigure")
|
||||
self.fig0.image("eiger", vrange=(0, 100))
|
||||
|
||||
self.d1 = self.dock.add_dock(widget=self.button_1, position="left")
|
||||
self.d1.addWidget(self.label_2)
|
||||
self.d2 = self.dock.add_dock(widget=self.bar, position="right")
|
||||
self.d3 = self.dock.add_dock(name="figure")
|
||||
self.fig_dock3 = BECFigure()
|
||||
self.fig_dock3.plot(x_name="samx", y_name="bpm4d")
|
||||
self.d3.add_widget(self.label_3)
|
||||
self.d3.add_widget(self.button_3)
|
||||
self.d3.add_widget(self.fig_dock3)
|
||||
self.d1 = self.dock.add_dock(name="dock_1", position="right")
|
||||
self.fig1 = self.d1.add_widget_bec("BECFigure")
|
||||
self.fig1.plot("samx", "bpm4i")
|
||||
self.fig1.plot("samx", "bpm3a")
|
||||
|
||||
self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
|
||||
self.fi2 = self.d2.add_widget_bec("BECFigure", row=0, col=0)
|
||||
self.fi2.motor_map("samx", "samy")
|
||||
self.bar2 = self.d2.add_widget_bec("SpiralProgressBar", row=0, col=1)
|
||||
self.bar2.set_diameter(200)
|
||||
|
||||
self.dock.save_state()
|
||||
|
||||
def ini_dock_alt(self):
|
||||
self.d0_alt = self.dock_alt.add_dock(title="dock_0", layout="grid", position="top")
|
||||
self.fig0_alt = self.d0_alt.add_widget_bec("BECFigure")
|
||||
self.fig0_alt.image("eiger", vrange=(0, 100))
|
||||
|
||||
self.d1_alt = self.dock_alt.add_dock(title="dock_1", layout="grid", position="top")
|
||||
self.fig1_alt = self.d1_alt.add_widget_bec("BECFigure")
|
||||
self.fig1_alt.plot("samx", "bpm4i")
|
||||
self.fig1_alt.plot("samx", "bpm3a")
|
||||
|
||||
self.d2_alt = self.dock_alt.add_dock(title="dock_2", layout="grid", position="bottom")
|
||||
self.fi2_alt = self.d2_alt.add_widget_bec("BECFigure", row=0, col=0)
|
||||
self.fi2_alt.motor_map("samx", "samy")
|
||||
self.bar2_alt = self.d2_alt.add_widget_bec("SpiralProgressBar", row=0, col=1)
|
||||
self.bar2_alt.set_diameter(200)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Override to handle things when main window is closed."""
|
||||
self.dock.cleanup()
|
||||
@@ -144,10 +159,6 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
import sys
|
||||
|
||||
import bec_widgets
|
||||
|
||||
module_path = os.path.dirname(bec_widgets.__file__)
|
||||
|
||||
bec_dispatcher = BECDispatcher()
|
||||
client = bec_dispatcher.client
|
||||
client.start()
|
||||
@@ -155,8 +166,9 @@ if __name__ == "__main__": # pragma: no cover
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Jupyter Console")
|
||||
app.setApplicationDisplayName("Jupyter Console")
|
||||
qdarktheme.setup_theme("auto")
|
||||
icon = QIcon()
|
||||
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
||||
icon.addFile("terminal_icon.png", size=QSize(48, 48))
|
||||
app.setWindowIcon(icon)
|
||||
win = JupyterConsoleWindow()
|
||||
win.show()
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
</property>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_1">
|
||||
<attribute name="title">
|
||||
<string>BECDock</string>
|
||||
<string>Dock - Pyqtgraph</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -33,6 +33,16 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Dock - Qt Native</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="dock_alt_placeholder" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>BECFigure</string>
|
||||
|
||||
0
bec_widgets/widgets/dock_area/__init__.py
Normal file
0
bec_widgets/widgets/dock_area/__init__.py
Normal file
0
bec_widgets/widgets/dock_area/dock/__init__.py
Normal file
0
bec_widgets/widgets/dock_area/dock/__init__.py
Normal file
115
bec_widgets/widgets/dock_area/dock/dock.py
Normal file
115
bec_widgets/widgets/dock_area/dock/dock.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Literal, Optional
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
from pydantic import Field
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtWidgets import QGridLayout, QHBoxLayout, QVBoxLayout
|
||||
from qtpy.QtWidgets import QDockWidget, QSizePolicy
|
||||
|
||||
from bec_widgets.cli.rpc_wigdet_handler import RPCWidgetHandler
|
||||
from bec_widgets.utils import BECConnector, ConnectionConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from qtpy.QtWidgets import QWidget
|
||||
|
||||
from bec_widgets.widgets.dock_area.dock_area import BECDockAreaAlt
|
||||
|
||||
|
||||
class DockConfig(ConnectionConfig):
|
||||
widgets: dict[str, ConnectionConfig] = Field({}, description="The widgets in the dock.")
|
||||
position: Literal["bottom", "top", "left", "right", "above", "below"] = Field(
|
||||
"bottom", description="The position of the dock."
|
||||
)
|
||||
parent_dock_area: Optional[str] = Field(
|
||||
None, description="The GUI ID of parent dock area of the dock."
|
||||
)
|
||||
|
||||
|
||||
class BECDockAlt(BECConnector, QDockWidget):
|
||||
USER_ACCESS = []
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: QWidget | None = None,
|
||||
parent_dock_area: BECDockAreaAlt | None = None,
|
||||
config: DockConfig | None = None,
|
||||
title: str | None = None, # TODO maybe rename to title
|
||||
client=None,
|
||||
gui_id: str | None = None,
|
||||
layout: Literal["horizontal", "vertical", "grid"] = "vertical",
|
||||
) -> None:
|
||||
if config is None:
|
||||
config = DockConfig(
|
||||
widget_class=self.__class__.__name__, parent_dock_area=parent_dock_area.gui_id
|
||||
)
|
||||
else:
|
||||
if isinstance(config, dict):
|
||||
config = DockConfig(**config)
|
||||
super().__init__(client=client, config=config, gui_id=gui_id)
|
||||
QDockWidget.__init__(self, title, parent)
|
||||
|
||||
self._parent_dock_area = parent_dock_area
|
||||
self._init_setup()
|
||||
self.setup_layout(layout)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
# self._grid_layout_manager = GridLayoutManager(self)
|
||||
# self._widget_handler.init()
|
||||
# self._grid_layout_manager.init
|
||||
|
||||
def _init_setup(self):
|
||||
self.setAllowedAreas(Qt.DockWidgetArea.AllDockWidgetAreas)
|
||||
self._widget_handler = RPCWidgetHandler()
|
||||
self._base_widget = QWidget()
|
||||
self._widgets = WeakValueDictionary()
|
||||
|
||||
def setup_layout(self, layout: Literal["horizontal", "vertical", "grid"] = "grid"):
|
||||
if layout == "horizontal":
|
||||
self.layout = QHBoxLayout()
|
||||
elif layout == "vertical":
|
||||
self.layout = QVBoxLayout()
|
||||
elif layout == "grid":
|
||||
self.layout = QGridLayout()
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self._base_widget.setLayout(self.layout)
|
||||
self.setWidget(self._base_widget)
|
||||
|
||||
def add_widget(self, widget: QWidget, row: int = None, col: int = None):
|
||||
|
||||
if isinstance(self.layout, QVBoxLayout) or isinstance(self.layout, QHBoxLayout):
|
||||
self.layout.addWidget(widget)
|
||||
if row or col:
|
||||
print(f"Warning: row and column are not used in this layout - {self.layout}")
|
||||
elif isinstance(self.layout, QGridLayout):
|
||||
if row is None:
|
||||
row = self.layout.rowCount()
|
||||
if col is None:
|
||||
col = self.layout.columnCount()
|
||||
self.layout.addWidget(widget, row, col)
|
||||
|
||||
return widget
|
||||
|
||||
def add_widget_bec(self, widget_type: str, row: int = None, col: int = None):
|
||||
widget = self._widget_handler.create_widget(widget_type)
|
||||
self.add_widget(widget, row, col)
|
||||
return widget
|
||||
|
||||
def remove_widget(self, widget_id: str):
|
||||
widget = self.widgets.pop(widget_id)
|
||||
widget.deleteLater()
|
||||
return widget
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Clean up the dock, including all its widgets.
|
||||
"""
|
||||
for widget in self.widgets:
|
||||
if hasattr(widget, "cleanup"):
|
||||
widget.cleanup()
|
||||
super().cleanup()
|
||||
|
||||
def close(self):
|
||||
self.cleanup()
|
||||
super().close()
|
||||
82
bec_widgets/widgets/dock_area/dock_area.py
Normal file
82
bec_widgets/widgets/dock_area/dock_area.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
from weakref import WeakValueDictionary
|
||||
|
||||
from pydantic import Field
|
||||
from qtpy.QtCore import Qt
|
||||
from qtpy.QtWidgets import QMainWindow, QWidget
|
||||
|
||||
from bec_widgets.utils import BECConnector, ConnectionConfig, WidgetContainerUtils
|
||||
from bec_widgets.widgets.dock_area.dock.dock import BECDockAlt, DockConfig
|
||||
|
||||
|
||||
class DockAreaConfig(ConnectionConfig):
|
||||
docks: dict[str, DockConfig] = Field({}, description="The docks in the dock area.")
|
||||
|
||||
|
||||
class BECDockAreaAlt(BECConnector, QMainWindow):
|
||||
USER_ACCESS = []
|
||||
positions = {
|
||||
"top": Qt.DockWidgetArea.TopDockWidgetArea,
|
||||
"bottom": Qt.DockWidgetArea.BottomDockWidgetArea,
|
||||
"left": Qt.DockWidgetArea.LeftDockWidgetArea,
|
||||
"right": Qt.DockWidgetArea.RightDockWidgetArea,
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent: QWidget | None = None,
|
||||
config: DockAreaConfig | None = None,
|
||||
client=None,
|
||||
gui_id: str = None,
|
||||
) -> None:
|
||||
if config is None:
|
||||
config = DockAreaConfig(widget_class=self.__class__.__name__)
|
||||
else:
|
||||
if isinstance(config, dict):
|
||||
config = DockAreaConfig(**config)
|
||||
self.config = config
|
||||
super().__init__(client=client, config=config, gui_id=gui_id)
|
||||
QMainWindow.__init__(self, parent=parent)
|
||||
# TODO experimetn with the options and features
|
||||
# self.setDockNestingEnabled(True)
|
||||
# self.setDockOptions(
|
||||
# QMainWindow.DockOption.AllowTabbedDocks | QMainWindow.DockOption.AllowNestedDocks
|
||||
# )
|
||||
self._instructions_visible = True # TODO do not know how to translate yet to native qt
|
||||
|
||||
self._docks = WeakValueDictionary()
|
||||
|
||||
@property
|
||||
def docks(self) -> dict:
|
||||
"""
|
||||
Get the docks in the dock area.
|
||||
Returns:
|
||||
dock_dict(dict): The docks in the dock area.
|
||||
"""
|
||||
return dict(self._docks)
|
||||
|
||||
@docks.setter
|
||||
def docks(self, value: dict):
|
||||
self._docks = WeakValueDictionary(value)
|
||||
|
||||
def add_dock(
|
||||
self,
|
||||
title: str = None,
|
||||
layout: Literal["horizontal", "vertical", "grid"] = "vertical",
|
||||
prefix: str = "dock",
|
||||
position: Literal["top", "bottom", "left", "right"] = "bottom",
|
||||
):
|
||||
|
||||
if title is None:
|
||||
title = WidgetContainerUtils.generate_unique_widget_id(self._docks, prefix=prefix)
|
||||
|
||||
if title in set(self.docks.keys()):
|
||||
raise ValueError(f"Dock with name {title} already exists.")
|
||||
|
||||
dock = BECDockAlt(title=title, parent=self, parent_dock_area=self, layout=layout)
|
||||
self.addDockWidget(self.positions[position], dock)
|
||||
self._docks[title] = dock
|
||||
|
||||
return dock
|
||||
Reference in New Issue
Block a user