bec-widgets 0.83.0__py3-none-any.whl → 0.84.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +50 -54
- PKG-INFO +2 -2
- bec_widgets/cli/client.py +61 -8
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +107 -59
- bec_widgets/qt_utils/toolbar.py +3 -1
- bec_widgets/utils/bec_dispatcher.py +5 -2
- bec_widgets/utils/colors.py +27 -0
- bec_widgets/widgets/bec_status_box/bec_status_box.py +2 -2
- bec_widgets/widgets/device_box/device_box.py +2 -2
- bec_widgets/widgets/figure/figure.py +23 -117
- bec_widgets/widgets/figure/plots/axis_settings.py +2 -2
- bec_widgets/widgets/figure/plots/waveform/waveform.py +651 -94
- bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +9 -2
- bec_widgets/widgets/scan_control/scan_control.py +2 -2
- bec_widgets/widgets/spinner/spinner.py +4 -3
- {bec_widgets-0.83.0.dist-info → bec_widgets-0.84.0.dist-info}/METADATA +2 -2
- {bec_widgets-0.83.0.dist-info → bec_widgets-0.84.0.dist-info}/RECORD +29 -30
- pyproject.toml +2 -2
- tests/references/SpinnerWidget/SpinnerWidget_darwin.png +0 -0
- tests/references/SpinnerWidget/SpinnerWidget_linux.png +0 -0
- tests/references/SpinnerWidget/SpinnerWidget_started_darwin.png +0 -0
- tests/references/SpinnerWidget/SpinnerWidget_started_linux.png +0 -0
- tests/unit_tests/client_mocks.py +13 -4
- tests/unit_tests/test_device_input_widgets.py +2 -0
- tests/unit_tests/test_spinner.py +2 -2
- tests/unit_tests/test_waveform1d.py +202 -23
- bec_widgets/examples/jupyter_console/jupyter_console_window.ui +0 -54
- {bec_widgets-0.83.0.dist-info → bec_widgets-0.84.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.83.0.dist-info → bec_widgets-0.84.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.83.0.dist-info → bec_widgets-0.84.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,5 +1,55 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v0.84.0 (2024-07-15)
|
4
|
+
|
5
|
+
### Feature
|
6
|
+
|
7
|
+
* feat(waveform): async readback update implemented for async devices ([`0c6a9f2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0c6a9f2310df31ddcd68050a17cfbf52c3e2e226))
|
8
|
+
|
9
|
+
* feat(waveform): data are taken directly from ScanItem which is defined from scan_status endpoint; scan update is triggered from scan_segment; plots can be added just specifying y_name -> best effort for setting x reported device ([`b8717f1`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b8717f13276734dd655ab03cd6005985ad5af9fb))
|
10
|
+
|
11
|
+
### Fix
|
12
|
+
|
13
|
+
* fix(waveform): timestamp are not converted to human readable format ([`e495fd3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e495fd30c4c16474689943c7263e3060cb09ffb4))
|
14
|
+
|
15
|
+
* fix(waveform): set_x method various bugs fixed ([`8516a1d`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8516a1d639925a877f174fa13f427a71131cc918))
|
16
|
+
|
17
|
+
* fix(waveform): x axis switching logic fixed when axis are not compatible ([`e4e1a90`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e4e1a905d19def22f970b364c18c953f00e10389))
|
18
|
+
|
19
|
+
* fix(waveform): dap leaked RID for all daps in current process; dap RID is now f"{scan_id}-{gui_id}" to distinguish for each plot instance ([`d23fd8b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d23fd8bd074ede6e14eb8e85e025cbced4bd45ef))
|
20
|
+
|
21
|
+
* fix(waveform): only one type of x axis allowed; x mode validated ([`9d6ae87`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9d6ae87d0f03ca227570fcca8af2d8190828d271))
|
22
|
+
|
23
|
+
* fix(waveform): data for axis are taken by separate method; validation consolidated ([`fc5a8bd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fc5a8bdd8b260f5e9b59ec71a4610c57442e43fe))
|
24
|
+
|
25
|
+
* fix(bec_dispatcher): connect_slot can accept kwargs ([`0aa317a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/0aa317aae58d3612d46f05b85f8b0db3d12bbe14))
|
26
|
+
|
27
|
+
### Refactor
|
28
|
+
|
29
|
+
* refactor(waveform): plot can be prompted without specifying kwargs ([`48911e9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/48911e934815923c94edb5ced6042058a11a97f5))
|
30
|
+
|
31
|
+
* refactor(jupyter_console_window): added more examples of waveforms ([`fc935d9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fc935d9fc81067c3a67389ff88ea97da2e0c903e))
|
32
|
+
|
33
|
+
### Test
|
34
|
+
|
35
|
+
* test(waveform): tests extended ([`006992e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/006992e43cc56d56261bc4fd3e9cae9abcab2153))
|
36
|
+
|
37
|
+
## v0.83.1 (2024-07-14)
|
38
|
+
|
39
|
+
### Fix
|
40
|
+
|
41
|
+
* fix(toolbar): default transparent background ([`eab7883`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/eab78839792f175b7ac127ca603385c6baa5ff15))
|
42
|
+
|
43
|
+
* fix: use apply_theme ([`2d4249e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2d4249e73a792fed1c2c7ab79bb8aec38c57466c))
|
44
|
+
|
45
|
+
* fix: spinner: update reference image for widget test, use apply_theme ([`63db135`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/63db1352ee883d35670b3a692dbe51d6d01872ae))
|
46
|
+
|
47
|
+
* fix: replace pyqtdarktheme by qdarkstyle, add 'apply_theme' function (in utils/colors.py) ([`8308115`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8308115f3646245d825fc47ab57297d3460bbcf5))
|
48
|
+
|
49
|
+
### Test
|
50
|
+
|
51
|
+
* test(toolbar): added reference pngs for spinner for Darwin ([`11a7204`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/11a7204c98e0bf211a8721d296b45d24a3102b97))
|
52
|
+
|
3
53
|
## v0.83.0 (2024-07-08)
|
4
54
|
|
5
55
|
### Feature
|
@@ -89,57 +139,3 @@
|
|
89
139
|
* feat(color_button): can get colors in RGBA or HEX ([`9594be2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9594be260680d11c8550ff74ffb8d679e5a5b8f6))
|
90
140
|
|
91
141
|
## v0.80.1 (2024-07-06)
|
92
|
-
|
93
|
-
### Fix
|
94
|
-
|
95
|
-
* fix(entry_validator): check for entry == "" ([`61de7e9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/61de7e9e221c766b9fb3ec23246da6a11c96a986))
|
96
|
-
|
97
|
-
## v0.80.0 (2024-07-06)
|
98
|
-
|
99
|
-
### Feature
|
100
|
-
|
101
|
-
* feat(qt5): dropped support for qt5; pyside2 and pyqt5 ([`fadbf77`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fadbf77866903beff6580802bc203d53367fc7e7))
|
102
|
-
|
103
|
-
* feat(plugins): moved plugin dict to dataclass and container ([`03819a3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/03819a3d902b4a51f3e882d52aedd971b2a8e127))
|
104
|
-
|
105
|
-
* feat(plugins): added support for pyqt6 ui files ([`d6d0777`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d6d07771135335cb78dc648508ce573b8970261a))
|
106
|
-
|
107
|
-
* feat(plugins): added bec widgets base class ([`1aa83e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1aa83e0ef1ffe45b01677b0b4590535cb0ca1cff))
|
108
|
-
|
109
|
-
## v0.79.3 (2024-07-05)
|
110
|
-
|
111
|
-
### Fix
|
112
|
-
|
113
|
-
* fix: changed inheritance to adress qt designer bug in rendering ([`e403870`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e403870874bd5e45840a034d6f1b3dd576d9c846))
|
114
|
-
|
115
|
-
* fix: add designer plugin classes ([`1586ce2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/1586ce2d6cba2bb086b2ef596e724bb9e40ab4f2))
|
116
|
-
|
117
|
-
### Refactor
|
118
|
-
|
119
|
-
* refactor: simplify logic in bec_status_box ([`576353c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/576353cfe8c6fd64db561f0b6e2bc951300643d3))
|
120
|
-
|
121
|
-
## v0.79.2 (2024-07-04)
|
122
|
-
|
123
|
-
### Fix
|
124
|
-
|
125
|
-
* fix: overwrite closeEvent and call super class ([`bc0ef78`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/bc0ef7893ef100b71b62101c459655509b534a56))
|
126
|
-
|
127
|
-
## v0.79.1 (2024-07-03)
|
128
|
-
|
129
|
-
### Fix
|
130
|
-
|
131
|
-
* fix: use libdir env var to preload Python library, also for Linux platform ([`d7718d4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d7718d4dcb9728c050b6421388af4d484f3741f2))
|
132
|
-
|
133
|
-
## v0.79.0 (2024-07-03)
|
134
|
-
|
135
|
-
### Feature
|
136
|
-
|
137
|
-
* feat(motor_map_widget): standalone MotorMap Widget with toolbar + plugin ([`6e75642`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6e756420907d7093557e945bc92bc4cfc0138d07))
|
138
|
-
|
139
|
-
* feat(motor_map): method to reset history trace ([`5960918`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5960918137dd41cdeb94e50f8abc4f169cf45c11))
|
140
|
-
|
141
|
-
### Fix
|
142
|
-
|
143
|
-
* fix(toolbar): change default color to black to match BECFigure theme ([`b8774e0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b8774e0b0bc43dcd00f94f42539a778e507ca27d))
|
144
|
-
|
145
|
-
* fix(motor_map): fixed bug with residual trace after changing motors ([`aaa0d10`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/aaa0d1003d2e94b45bafe4f700852c2c05288aea))
|
PKG-INFO
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: bec_widgets
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.84.0
|
4
4
|
Summary: BEC Widgets
|
5
5
|
Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
|
6
6
|
Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
|
@@ -14,9 +14,9 @@ Requires-Dist: bec-lib~=2.16
|
|
14
14
|
Requires-Dist: black~=24.0
|
15
15
|
Requires-Dist: isort>=5.13.2,~=5.13
|
16
16
|
Requires-Dist: pydantic~=2.0
|
17
|
-
Requires-Dist: pyqtdarktheme~=2.1
|
18
17
|
Requires-Dist: pyqtgraph~=0.13
|
19
18
|
Requires-Dist: pyte
|
19
|
+
Requires-Dist: qdarkstyle>=3.2.2
|
20
20
|
Requires-Dist: qtconsole>=5.5.1,~=5.5
|
21
21
|
Requires-Dist: qtpy~=2.4
|
22
22
|
Provides-Extra: dev
|
bec_widgets/cli/client.py
CHANGED
@@ -19,6 +19,9 @@ class Widgets(str, enum.Enum):
|
|
19
19
|
BECMotorMapWidget = "BECMotorMapWidget"
|
20
20
|
BECQueue = "BECQueue"
|
21
21
|
BECStatusBox = "BECStatusBox"
|
22
|
+
DeviceBox = "DeviceBox"
|
23
|
+
DeviceComboBox = "DeviceComboBox"
|
24
|
+
DeviceLineEdit = "DeviceLineEdit"
|
22
25
|
RingProgressBar = "RingProgressBar"
|
23
26
|
ScanControl = "ScanControl"
|
24
27
|
StopButton = "StopButton"
|
@@ -465,8 +468,9 @@ class BECFigure(RPCBase):
|
|
465
468
|
@rpc_call
|
466
469
|
def plot(
|
467
470
|
self,
|
468
|
-
|
471
|
+
arg1: "list | np.ndarray | str | None" = None,
|
469
472
|
y: "list | np.ndarray | None" = None,
|
473
|
+
x: "list | np.ndarray | None" = None,
|
470
474
|
x_name: "str | None" = None,
|
471
475
|
y_name: "str | None" = None,
|
472
476
|
z_name: "str | None" = None,
|
@@ -488,8 +492,9 @@ class BECFigure(RPCBase):
|
|
488
492
|
Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure.
|
489
493
|
|
490
494
|
Args:
|
491
|
-
|
495
|
+
arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name.
|
492
496
|
y(list | np.ndarray): Custom y data to plot.
|
497
|
+
x(list | np.ndarray): Custom x data to plot.
|
493
498
|
x_name(str): The name of the device for the x-axis.
|
494
499
|
y_name(str): The name of the device for the y-axis.
|
495
500
|
z_name(str): The name of the device for the z-axis.
|
@@ -1494,8 +1499,9 @@ class BECWaveform(RPCBase):
|
|
1494
1499
|
@rpc_call
|
1495
1500
|
def plot(
|
1496
1501
|
self,
|
1497
|
-
|
1502
|
+
arg1: "list | np.ndarray | str | None" = None,
|
1498
1503
|
y: "list | np.ndarray | None" = None,
|
1504
|
+
x: "list | np.ndarray | None" = None,
|
1499
1505
|
x_name: "str | None" = None,
|
1500
1506
|
y_name: "str | None" = None,
|
1501
1507
|
z_name: "str | None" = None,
|
@@ -1507,13 +1513,20 @@ class BECWaveform(RPCBase):
|
|
1507
1513
|
label: "str | None" = None,
|
1508
1514
|
validate: "bool" = True,
|
1509
1515
|
dap: "str | None" = None,
|
1516
|
+
**kwargs,
|
1510
1517
|
) -> "BECCurve":
|
1511
1518
|
"""
|
1512
1519
|
Plot a curve to the plot widget.
|
1520
|
+
|
1513
1521
|
Args:
|
1514
|
-
|
1522
|
+
arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name.
|
1515
1523
|
y(list | np.ndarray): Custom y data to plot.
|
1516
|
-
|
1524
|
+
x(list | np.ndarray): Custom y data to plot.
|
1525
|
+
x_name(str): Name of the x signal.
|
1526
|
+
- "best_effort": Use the best effort signal.
|
1527
|
+
- "timestamp": Use the timestamp signal.
|
1528
|
+
- "index": Use the index signal.
|
1529
|
+
- Custom signal name of device from BEC.
|
1517
1530
|
y_name(str): The name of the device for the y-axis.
|
1518
1531
|
z_name(str): The name of the device for the z-axis.
|
1519
1532
|
x_entry(str): The name of the entry for the x-axis.
|
@@ -1523,7 +1536,7 @@ class BECWaveform(RPCBase):
|
|
1523
1536
|
color_map_z(str): The color map to use for the z-axis.
|
1524
1537
|
label(str): The label of the curve.
|
1525
1538
|
validate(bool): If True, validate the device names and entries.
|
1526
|
-
dap(str): The dap model to use for the curve. If not specified, none will be added.
|
1539
|
+
dap(str): The dap model to use for the curve, only available for sync devices. If not specified, none will be added.
|
1527
1540
|
|
1528
1541
|
Returns:
|
1529
1542
|
BECCurve: The curve object.
|
@@ -1532,12 +1545,13 @@ class BECWaveform(RPCBase):
|
|
1532
1545
|
@rpc_call
|
1533
1546
|
def add_dap(
|
1534
1547
|
self,
|
1535
|
-
x_name: "str",
|
1536
|
-
y_name: "str",
|
1548
|
+
x_name: "str | None" = None,
|
1549
|
+
y_name: "str | None" = None,
|
1537
1550
|
x_entry: "Optional[str]" = None,
|
1538
1551
|
y_entry: "Optional[str]" = None,
|
1539
1552
|
color: "Optional[str]" = None,
|
1540
1553
|
dap: "str" = "GaussianModel",
|
1554
|
+
validate_bec: "bool" = True,
|
1541
1555
|
**kwargs,
|
1542
1556
|
) -> "BECCurve":
|
1543
1557
|
"""
|
@@ -1552,12 +1566,27 @@ class BECWaveform(RPCBase):
|
|
1552
1566
|
color_map_z(str): The color map to use for the z-axis.
|
1553
1567
|
label(str, optional): Label of the curve. Defaults to None.
|
1554
1568
|
dap(str): The dap model to use for the curve.
|
1569
|
+
validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
|
1555
1570
|
**kwargs: Additional keyword arguments for the curve configuration.
|
1556
1571
|
|
1557
1572
|
Returns:
|
1558
1573
|
BECCurve: The curve object.
|
1559
1574
|
"""
|
1560
1575
|
|
1576
|
+
@rpc_call
|
1577
|
+
def set_x(self, x_name: "str", x_entry: "str | None" = None):
|
1578
|
+
"""
|
1579
|
+
Change the x axis of the plot widget.
|
1580
|
+
|
1581
|
+
Args:
|
1582
|
+
x_name(str): Name of the x signal.
|
1583
|
+
- "best_effort": Use the best effort signal.
|
1584
|
+
- "timestamp": Use the timestamp signal.
|
1585
|
+
- "index": Use the index signal.
|
1586
|
+
- Custom signal name of device from BEC.
|
1587
|
+
x_entry(str): Entry of the x signal.
|
1588
|
+
"""
|
1589
|
+
|
1561
1590
|
@rpc_call
|
1562
1591
|
def get_dap_params(self) -> "dict":
|
1563
1592
|
"""
|
@@ -1742,6 +1771,12 @@ class BECWaveform(RPCBase):
|
|
1742
1771
|
Remove the plot widget from the figure.
|
1743
1772
|
"""
|
1744
1773
|
|
1774
|
+
@rpc_call
|
1775
|
+
def clear_all(self):
|
1776
|
+
"""
|
1777
|
+
None
|
1778
|
+
"""
|
1779
|
+
|
1745
1780
|
@rpc_call
|
1746
1781
|
def set_legend_label_size(self, size: "int" = None):
|
1747
1782
|
"""
|
@@ -1752,6 +1787,24 @@ class BECWaveform(RPCBase):
|
|
1752
1787
|
"""
|
1753
1788
|
|
1754
1789
|
|
1790
|
+
class DeviceBox(RPCBase):
|
1791
|
+
@property
|
1792
|
+
@rpc_call
|
1793
|
+
def _config_dict(self) -> "dict":
|
1794
|
+
"""
|
1795
|
+
Get the configuration of the widget.
|
1796
|
+
|
1797
|
+
Returns:
|
1798
|
+
dict: The configuration of the widget.
|
1799
|
+
"""
|
1800
|
+
|
1801
|
+
@rpc_call
|
1802
|
+
def _get_all_rpc(self) -> "dict":
|
1803
|
+
"""
|
1804
|
+
Get all registered RPC objects.
|
1805
|
+
"""
|
1806
|
+
|
1807
|
+
|
1755
1808
|
class DeviceComboBox(RPCBase):
|
1756
1809
|
@property
|
1757
1810
|
@rpc_call
|
@@ -2,14 +2,20 @@ import os
|
|
2
2
|
|
3
3
|
import numpy as np
|
4
4
|
import pyqtgraph as pg
|
5
|
-
import qdarktheme
|
6
|
-
from qtconsole.inprocess import QtInProcessKernelManager
|
7
|
-
from qtconsole.rich_jupyter_widget import RichJupyterWidget
|
8
5
|
from qtpy.QtCore import QSize
|
9
6
|
from qtpy.QtGui import QIcon
|
10
|
-
from qtpy.QtWidgets import
|
11
|
-
|
12
|
-
|
7
|
+
from qtpy.QtWidgets import (
|
8
|
+
QApplication,
|
9
|
+
QGroupBox,
|
10
|
+
QHBoxLayout,
|
11
|
+
QSplitter,
|
12
|
+
QTabWidget,
|
13
|
+
QVBoxLayout,
|
14
|
+
QWidget,
|
15
|
+
)
|
16
|
+
|
17
|
+
from bec_widgets.utils import BECDispatcher
|
18
|
+
from bec_widgets.utils.colors import apply_theme
|
13
19
|
from bec_widgets.widgets.dock.dock_area import BECDockArea
|
14
20
|
from bec_widgets.widgets.figure import BECFigure
|
15
21
|
from bec_widgets.widgets.jupyter_console.jupyter_console import BECJupyterConsole
|
@@ -21,14 +27,8 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
21
27
|
def __init__(self, parent=None):
|
22
28
|
super().__init__(parent)
|
23
29
|
|
24
|
-
current_path = os.path.dirname(__file__)
|
25
|
-
self.ui = UILoader().load_ui(os.path.join(current_path, "jupyter_console_window.ui"), self)
|
26
|
-
|
27
30
|
self._init_ui()
|
28
31
|
|
29
|
-
self.ui.splitter.setSizes([200, 100])
|
30
|
-
self.safe_close = False
|
31
|
-
|
32
32
|
# console push
|
33
33
|
if self.console.inprocess is True:
|
34
34
|
self.console.kernel_manager.kernel.shell.push(
|
@@ -40,10 +40,12 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
40
40
|
"w1": self.w1,
|
41
41
|
"w2": self.w2,
|
42
42
|
"w3": self.w3,
|
43
|
-
"w1_c": self.w1_c,
|
44
|
-
"w2_c": self.w2_c,
|
45
|
-
"w3_c": self.w3_c,
|
46
43
|
"w4": self.w4,
|
44
|
+
"w5": self.w5,
|
45
|
+
"w6": self.w6,
|
46
|
+
"w7": self.w7,
|
47
|
+
"w8": self.w8,
|
48
|
+
"w9": self.w9,
|
47
49
|
"d0": self.d0,
|
48
50
|
"d1": self.d1,
|
49
51
|
"d2": self.d2,
|
@@ -53,14 +55,30 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
53
55
|
)
|
54
56
|
|
55
57
|
def _init_ui(self):
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
self.layout = QHBoxLayout(self)
|
59
|
+
|
60
|
+
# Horizontal splitter
|
61
|
+
splitter = QSplitter(self)
|
62
|
+
self.layout.addWidget(splitter)
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
+
tab_widget = QTabWidget(splitter)
|
65
|
+
|
66
|
+
first_tab = QWidget()
|
67
|
+
first_tab_layout = QVBoxLayout(first_tab)
|
68
|
+
self.dock = BECDockArea(gui_id="dock")
|
69
|
+
first_tab_layout.addWidget(self.dock)
|
70
|
+
tab_widget.addTab(first_tab, "Dock Area")
|
71
|
+
|
72
|
+
second_tab = QWidget()
|
73
|
+
second_tab_layout = QVBoxLayout(second_tab)
|
74
|
+
self.figure = BECFigure(parent=self, gui_id="figure")
|
75
|
+
second_tab_layout.addWidget(self.figure)
|
76
|
+
tab_widget.addTab(second_tab, "BEC Figure")
|
77
|
+
|
78
|
+
group_box = QGroupBox("Jupyter Console", splitter)
|
79
|
+
group_box_layout = QVBoxLayout(group_box)
|
80
|
+
self.console = BECJupyterConsole(inprocess=True)
|
81
|
+
group_box_layout.addWidget(self.console)
|
64
82
|
|
65
83
|
# add stuff to figure
|
66
84
|
self._init_figure()
|
@@ -68,44 +86,70 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
68
86
|
# init dock for testing
|
69
87
|
self._init_dock()
|
70
88
|
|
71
|
-
self.
|
72
|
-
self.console = BECJupyterConsole(inprocess=True)
|
73
|
-
self.console_layout.addWidget(self.console)
|
89
|
+
self.setWindowTitle("Jupyter Console Window")
|
74
90
|
|
75
91
|
def _init_figure(self):
|
76
|
-
self.figure.plot(
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
92
|
+
self.w1 = self.figure.plot(
|
93
|
+
x_name="samx",
|
94
|
+
y_name="bpm4i",
|
95
|
+
# title="Standard Plot with sync device, custom labels - w1",
|
96
|
+
# x_label="Motor Position",
|
97
|
+
# y_label="Intensity (A.U.)",
|
98
|
+
row=0,
|
99
|
+
col=0,
|
100
|
+
)
|
101
|
+
self.w1.set(
|
102
|
+
title="Standard Plot with sync device, custom labels - w1",
|
103
|
+
x_label="Motor Position",
|
104
|
+
y_label="Intensity (A.U.)",
|
105
|
+
)
|
106
|
+
self.w2 = self.figure.motor_map("samx", "samy", row=0, col=1)
|
107
|
+
self.w3 = self.figure.image(
|
108
|
+
"eiger", color_map="viridis", vrange=(0, 100), title="Eiger Image - w3", row=0, col=2
|
109
|
+
)
|
110
|
+
self.w4 = self.figure.plot(
|
111
|
+
x_name="samx",
|
112
|
+
y_name="samy",
|
113
|
+
z_name="bpm4i",
|
114
|
+
color_map_z="magma",
|
115
|
+
new=True,
|
116
|
+
title="2D scatter plot - w4",
|
117
|
+
row=0,
|
118
|
+
col=3,
|
119
|
+
)
|
120
|
+
self.w5 = self.figure.plot(
|
121
|
+
y_name="bpm4i",
|
122
|
+
new=True,
|
123
|
+
title="Best Effort Plot - w5",
|
124
|
+
dap="GaussianModel",
|
125
|
+
row=1,
|
126
|
+
col=0,
|
127
|
+
)
|
128
|
+
self.w6 = self.figure.plot(
|
129
|
+
x_name="timestamp", y_name="bpm4i", new=True, title="Timestamp Plot - w6", row=1, col=1
|
130
|
+
)
|
131
|
+
self.w7 = self.figure.plot(
|
132
|
+
x_name="index", y_name="bpm4i", new=True, title="Index Plot - w7", row=1, col=2
|
133
|
+
)
|
134
|
+
self.w8 = self.figure.plot(
|
135
|
+
y_name="monitor_async", new=True, title="Async Plot - Best Effort - w8", row=2, col=0
|
136
|
+
)
|
137
|
+
self.w9 = self.figure.plot(
|
138
|
+
x_name="timestamp",
|
139
|
+
y_name="monitor_async",
|
140
|
+
new=True,
|
141
|
+
title="Async Plot - timestamp - w9",
|
142
|
+
row=2,
|
143
|
+
col=1,
|
144
|
+
)
|
145
|
+
self.w10 = self.figure.plot(
|
146
|
+
x_name="index",
|
147
|
+
y_name="monitor_async",
|
148
|
+
new=True,
|
149
|
+
title="Async Plot - index - w10",
|
150
|
+
row=2,
|
151
|
+
col=2,
|
81
152
|
)
|
82
|
-
|
83
|
-
self.figure.change_layout(2, 2)
|
84
|
-
|
85
|
-
self.w1 = self.figure[0, 0]
|
86
|
-
self.w2 = self.figure[0, 1]
|
87
|
-
self.w3 = self.figure[1, 0]
|
88
|
-
self.w4 = self.figure[1, 1]
|
89
|
-
|
90
|
-
# Plot Customisation
|
91
|
-
self.w1.set_title("Waveform 1")
|
92
|
-
self.w1.set_x_label("Motor Position (samx)")
|
93
|
-
self.w1.set_y_label("Intensity A.U.")
|
94
|
-
|
95
|
-
# Image Customisation
|
96
|
-
self.w3.set_title("Eiger Image")
|
97
|
-
self.w3.set_x_label("X")
|
98
|
-
self.w3.set_y_label("Y")
|
99
|
-
|
100
|
-
# Configs to try to pass
|
101
|
-
self.w1_c = self.w1._config_dict
|
102
|
-
self.w2_c = self.w2._config_dict
|
103
|
-
self.w3_c = self.w3._config_dict
|
104
|
-
|
105
|
-
# curves for w1
|
106
|
-
self.c1 = self.w1.get_config()
|
107
|
-
|
108
|
-
self.fig_c = self.figure._config_dict
|
109
153
|
|
110
154
|
def _init_dock(self):
|
111
155
|
|
@@ -131,9 +175,13 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
131
175
|
|
132
176
|
def closeEvent(self, event):
|
133
177
|
"""Override to handle things when main window is closed."""
|
178
|
+
self.dock.clear_all()
|
134
179
|
self.dock.cleanup()
|
180
|
+
self.dock.close()
|
135
181
|
self.figure.clear_all()
|
136
|
-
self.figure.
|
182
|
+
self.figure.cleanup()
|
183
|
+
self.figure.close()
|
184
|
+
|
137
185
|
super().closeEvent(event)
|
138
186
|
|
139
187
|
|
@@ -147,7 +195,7 @@ if __name__ == "__main__": # pragma: no cover
|
|
147
195
|
app = QApplication(sys.argv)
|
148
196
|
app.setApplicationName("Jupyter Console")
|
149
197
|
app.setApplicationDisplayName("Jupyter Console")
|
150
|
-
|
198
|
+
apply_theme("dark")
|
151
199
|
icon = QIcon()
|
152
200
|
icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
|
153
201
|
app.setWindowIcon(icon)
|
bec_widgets/qt_utils/toolbar.py
CHANGED
@@ -26,7 +26,9 @@ class ModularToolBar(QToolBar):
|
|
26
26
|
color (str, optional): The background color of the toolbar. Defaults to "black".
|
27
27
|
"""
|
28
28
|
|
29
|
-
def __init__(
|
29
|
+
def __init__(
|
30
|
+
self, parent=None, actions=None, target_widget=None, color: str = "rgba(255, 255, 255, 0)"
|
31
|
+
):
|
30
32
|
super().__init__(parent)
|
31
33
|
|
32
34
|
self.widgets = defaultdict(dict)
|
@@ -134,7 +134,10 @@ class BECDispatcher:
|
|
134
134
|
cls.qapp = None
|
135
135
|
|
136
136
|
def connect_slot(
|
137
|
-
self,
|
137
|
+
self,
|
138
|
+
slot: Callable,
|
139
|
+
topics: Union[EndpointInfo, str, list[Union[EndpointInfo, str]]],
|
140
|
+
**kwargs,
|
138
141
|
) -> None:
|
139
142
|
"""Connect widget's pyqt slot, so that it is called on new pub/sub topic message.
|
140
143
|
|
@@ -144,7 +147,7 @@ class BECDispatcher:
|
|
144
147
|
topics (EndpointInfo | str | list): A topic or list of topics that can typically be acquired via bec_lib.MessageEndpoints
|
145
148
|
"""
|
146
149
|
slot = QtThreadSafeCallback(slot)
|
147
|
-
self.client.connector.register(topics, cb=slot)
|
150
|
+
self.client.connector.register(topics, cb=slot, **kwargs)
|
148
151
|
topics_str, _ = self.client.connector._convert_endpointinfo(topics)
|
149
152
|
self._slots[slot].update(set(topics_str))
|
150
153
|
|
bec_widgets/utils/colors.py
CHANGED
@@ -1,10 +1,37 @@
|
|
1
|
+
import itertools
|
1
2
|
import re
|
2
3
|
from typing import Literal
|
3
4
|
|
4
5
|
import numpy as np
|
5
6
|
import pyqtgraph as pg
|
7
|
+
import qdarkstyle
|
6
8
|
from pydantic_core import PydanticCustomError
|
9
|
+
from qdarkstyle import DarkPalette, LightPalette
|
7
10
|
from qtpy.QtGui import QColor
|
11
|
+
from qtpy.QtWidgets import QApplication
|
12
|
+
|
13
|
+
CURRENT_THEME = "dark"
|
14
|
+
|
15
|
+
|
16
|
+
def get_theme_palette():
|
17
|
+
return DarkPalette if CURRENT_THEME == "dark" else LightPalette
|
18
|
+
|
19
|
+
|
20
|
+
def apply_theme(theme: Literal["dark", "light"]):
|
21
|
+
global CURRENT_THEME
|
22
|
+
CURRENT_THEME = theme
|
23
|
+
|
24
|
+
app = QApplication.instance()
|
25
|
+
# go through all pyqtgraph widgets and set background
|
26
|
+
children = itertools.chain.from_iterable(
|
27
|
+
top.findChildren(pg.GraphicsLayoutWidget) for top in app.topLevelWidgets()
|
28
|
+
)
|
29
|
+
for pg_widget in children:
|
30
|
+
pg_widget.setBackground("k" if theme == "dark" else "w")
|
31
|
+
|
32
|
+
# now define stylesheet according to theme and apply it
|
33
|
+
style = qdarkstyle.load_stylesheet(palette=get_theme_palette())
|
34
|
+
app.setStyleSheet(style)
|
8
35
|
|
9
36
|
|
10
37
|
class Colors:
|
@@ -9,12 +9,12 @@ from collections import defaultdict
|
|
9
9
|
from dataclasses import dataclass
|
10
10
|
from typing import TYPE_CHECKING
|
11
11
|
|
12
|
-
import qdarktheme
|
13
12
|
from bec_lib.utils.import_utils import lazy_import_from
|
14
13
|
from qtpy.QtCore import QObject, QTimer, Signal, Slot
|
15
14
|
from qtpy.QtWidgets import QHBoxLayout, QTreeWidget, QTreeWidgetItem, QWidget
|
16
15
|
|
17
16
|
from bec_widgets.utils.bec_connector import BECConnector
|
17
|
+
from bec_widgets.utils.colors import apply_theme
|
18
18
|
from bec_widgets.widgets.bec_status_box.status_item import StatusItem
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
@@ -306,7 +306,7 @@ def main():
|
|
306
306
|
from qtpy.QtWidgets import QApplication
|
307
307
|
|
308
308
|
app = QApplication(sys.argv)
|
309
|
-
|
309
|
+
apply_theme("dark")
|
310
310
|
main_window = BECStatusBox()
|
311
311
|
main_window.show()
|
312
312
|
sys.exit(app.exec())
|
@@ -9,6 +9,7 @@ from qtpy.QtWidgets import QDoubleSpinBox, QVBoxLayout, QWidget
|
|
9
9
|
|
10
10
|
from bec_widgets.utils import UILoader
|
11
11
|
from bec_widgets.utils.bec_connector import BECConnector
|
12
|
+
from bec_widgets.utils.colors import apply_theme
|
12
13
|
|
13
14
|
|
14
15
|
class DeviceBox(BECConnector, QWidget):
|
@@ -186,11 +187,10 @@ class DeviceBox(BECConnector, QWidget):
|
|
186
187
|
if __name__ == "__main__": # pragma: no cover
|
187
188
|
import sys
|
188
189
|
|
189
|
-
import qdarktheme
|
190
190
|
from qtpy.QtWidgets import QApplication
|
191
191
|
|
192
192
|
app = QApplication(sys.argv)
|
193
|
-
|
193
|
+
apply_theme("light")
|
194
194
|
widget = DeviceBox(device="samx")
|
195
195
|
|
196
196
|
widget.show()
|