bec-widgets 0.117.0__py3-none-any.whl → 0.118.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 +24 -26
- PKG-INFO +1 -1
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +1 -1
- bec_widgets/qt_utils/toolbar.py +51 -12
- bec_widgets/widgets/figure/figure.py +10 -1
- bec_widgets/widgets/figure/plots/image/image.py +86 -19
- bec_widgets/widgets/figure/plots/plot_base.py +3 -1
- bec_widgets/widgets/image/image_widget.py +15 -2
- bec_widgets/widgets/vscode/vscode.py +109 -2
- {bec_widgets-0.117.0.dist-info → bec_widgets-0.118.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.117.0.dist-info → bec_widgets-0.118.0.dist-info}/RECORD +15 -15
- pyproject.toml +1 -1
- {bec_widgets-0.117.0.dist-info → bec_widgets-0.118.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.117.0.dist-info → bec_widgets-0.118.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.117.0.dist-info → bec_widgets-0.118.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v0.118.0 (2024-10-13)
|
5
|
+
|
6
|
+
### Documentation
|
7
|
+
|
8
|
+
* docs(sphinx-build): adjusted pyside verion ([`b236951`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b23695167ab969f754a058ffdccca2b40f00a008))
|
9
|
+
|
10
|
+
### Features
|
11
|
+
|
12
|
+
* feat(image): image widget can take data from monitor_1d endpoint ([`9ef1d1c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9ef1d1c9ac2178d9fa2e655942208f8abbdf5c1b))
|
13
|
+
|
14
|
+
|
15
|
+
## v0.117.1 (2024-10-11)
|
16
|
+
|
17
|
+
### Fixes
|
18
|
+
|
19
|
+
* fix(FPS): qtimer cleanup leaking ([`3a22392`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3a2239278075de7489ad10a58c31d7d89715e221))
|
20
|
+
|
21
|
+
### Unknown
|
22
|
+
|
23
|
+
* feature(vscode): added support for vscode instructions ([`f5f1f6c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f5f1f6c304b890dc162e8653005233bce4ea82e4))
|
24
|
+
|
25
|
+
* feature(vscode): support for controlling vscode from widgets ([`9238679`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/923867947f62db026ac0378c30ef62c883596058))
|
26
|
+
|
27
|
+
|
4
28
|
## v0.117.0 (2024-10-11)
|
5
29
|
|
6
30
|
### Features
|
@@ -148,29 +172,3 @@ Fixes #361, do not try to change x axis when not permitted ([`efa2763`](https://
|
|
148
172
|
|
149
173
|
|
150
174
|
## v0.109.1 (2024-09-09)
|
151
|
-
|
152
|
-
### Fixes
|
153
|
-
|
154
|
-
* fix: refactor textbox widget, remove inheritance, adhere to bec style; closes #324 ([`b0d786b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b0d786b991677c0846a0c6ba3f2252d48d94ccaa))
|
155
|
-
|
156
|
-
|
157
|
-
## v0.109.0 (2024-09-06)
|
158
|
-
|
159
|
-
### Features
|
160
|
-
|
161
|
-
* feat(accent colors): added helper function to get all accent colors ([`84a59f7`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/84a59f70eed6d8a3c3aeeabc77a5f9ea4e864f61))
|
162
|
-
|
163
|
-
### Fixes
|
164
|
-
|
165
|
-
* fix(theme): fixed theme access for themecontainer ([`de303f0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/de303f0227fc9d3a74a0410f1e7999ac5132273c))
|
166
|
-
|
167
|
-
|
168
|
-
## v0.108.0 (2024-09-06)
|
169
|
-
|
170
|
-
### Documentation
|
171
|
-
|
172
|
-
* docs(progressbar): added docs ([`7d07cea`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/7d07cea946f9c884477b01bebfb60b332ff09e0a))
|
173
|
-
|
174
|
-
### Features
|
175
|
-
|
176
|
-
* feat(progressbar): added bec progressbar ([`f6d1d0b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f6d1d0bbe3ba30a3b7291cd36a1f7f8e6bd5b895))
|
PKG-INFO
CHANGED
@@ -164,7 +164,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
|
|
164
164
|
|
165
165
|
self.d1 = self.dock.add_dock(name="dock_1", position="right")
|
166
166
|
self.im = self.d1.add_widget("BECImageWidget")
|
167
|
-
self.im.image("
|
167
|
+
self.im.image("waveform", "1d")
|
168
168
|
|
169
169
|
self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
|
170
170
|
self.wf = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
|
bec_widgets/qt_utils/toolbar.py
CHANGED
@@ -7,9 +7,18 @@ from collections import defaultdict
|
|
7
7
|
from typing import Literal
|
8
8
|
|
9
9
|
from bec_qthemes._icon.material_icons import material_icon
|
10
|
-
from qtpy.QtCore import QSize
|
10
|
+
from qtpy.QtCore import QSize, Qt
|
11
11
|
from qtpy.QtGui import QAction, QColor, QIcon
|
12
|
-
from qtpy.QtWidgets import
|
12
|
+
from qtpy.QtWidgets import (
|
13
|
+
QComboBox,
|
14
|
+
QHBoxLayout,
|
15
|
+
QLabel,
|
16
|
+
QMenu,
|
17
|
+
QSizePolicy,
|
18
|
+
QToolBar,
|
19
|
+
QToolButton,
|
20
|
+
QWidget,
|
21
|
+
)
|
13
22
|
|
14
23
|
import bec_widgets
|
15
24
|
|
@@ -154,22 +163,52 @@ class WidgetAction(ToolBarAction):
|
|
154
163
|
|
155
164
|
"""
|
156
165
|
|
157
|
-
def __init__(self, label: str | None = None, widget: QWidget = None):
|
158
|
-
super().__init__()
|
166
|
+
def __init__(self, label: str | None = None, widget: QWidget = None, parent=None):
|
167
|
+
super().__init__(parent)
|
159
168
|
self.label = label
|
160
169
|
self.widget = widget
|
161
170
|
|
162
|
-
def add_to_toolbar(self, toolbar, target):
|
163
|
-
|
164
|
-
layout = QHBoxLayout(
|
171
|
+
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
172
|
+
container = QWidget()
|
173
|
+
layout = QHBoxLayout(container)
|
165
174
|
layout.setContentsMargins(0, 0, 0, 0)
|
175
|
+
layout.setSpacing(5)
|
176
|
+
|
166
177
|
if self.label is not None:
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
178
|
+
label_widget = QLabel(f"{self.label}")
|
179
|
+
label_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
|
180
|
+
label_widget.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
|
181
|
+
layout.addWidget(label_widget)
|
182
|
+
|
183
|
+
if isinstance(self.widget, QComboBox):
|
184
|
+
self.widget.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
185
|
+
|
186
|
+
size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
187
|
+
self.widget.setSizePolicy(size_policy)
|
188
|
+
|
189
|
+
self.widget.setMinimumWidth(self.calculate_minimum_width(self.widget))
|
190
|
+
|
191
|
+
else:
|
192
|
+
self.widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
193
|
+
|
171
194
|
layout.addWidget(self.widget)
|
172
|
-
|
195
|
+
|
196
|
+
toolbar.addWidget(container)
|
197
|
+
|
198
|
+
@staticmethod
|
199
|
+
def calculate_minimum_width(combo_box: QComboBox) -> int:
|
200
|
+
"""
|
201
|
+
Calculate the minimum width required to display the longest item in the combo box.
|
202
|
+
|
203
|
+
Args:
|
204
|
+
combo_box (QComboBox): The combo box to calculate the width for.
|
205
|
+
|
206
|
+
Returns:
|
207
|
+
int: The calculated minimum width in pixels.
|
208
|
+
"""
|
209
|
+
font_metrics = combo_box.fontMetrics()
|
210
|
+
max_width = max(font_metrics.width(combo_box.itemText(i)) for i in range(combo_box.count()))
|
211
|
+
return max_width + 60
|
173
212
|
|
174
213
|
|
175
214
|
class ExpandableMenuAction(ToolBarAction):
|
@@ -321,6 +321,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
|
321
321
|
self,
|
322
322
|
image,
|
323
323
|
monitor: str = None,
|
324
|
+
monitor_type: Literal["1d", "2d"] = "2d",
|
324
325
|
color_bar: Literal["simple", "full"] = "full",
|
325
326
|
color_map: str = "magma",
|
326
327
|
data: np.ndarray = None,
|
@@ -337,7 +338,13 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
|
337
338
|
data (np.ndarray): Custom data to display.
|
338
339
|
"""
|
339
340
|
if monitor is not None and data is None:
|
340
|
-
image.image(
|
341
|
+
image.image(
|
342
|
+
monitor=monitor,
|
343
|
+
monitor_type=monitor_type,
|
344
|
+
color_map=color_map,
|
345
|
+
vrange=vrange,
|
346
|
+
color_bar=color_bar,
|
347
|
+
)
|
341
348
|
elif data is not None and monitor is None:
|
342
349
|
image.add_custom_image(
|
343
350
|
name="custom", data=data, color_map=color_map, vrange=vrange, color_bar=color_bar
|
@@ -355,6 +362,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
|
355
362
|
def image(
|
356
363
|
self,
|
357
364
|
monitor: str = None,
|
365
|
+
monitor_type: Literal["1d", "2d"] = "2d",
|
358
366
|
color_bar: Literal["simple", "full"] = "full",
|
359
367
|
color_map: str = "magma",
|
360
368
|
data: np.ndarray = None,
|
@@ -393,6 +401,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
|
|
393
401
|
image = self._init_image(
|
394
402
|
image=image,
|
395
403
|
monitor=monitor,
|
404
|
+
monitor_type=monitor_type,
|
396
405
|
color_bar=color_bar,
|
397
406
|
color_map=color_map,
|
398
407
|
data=data,
|
@@ -7,10 +7,10 @@ import numpy as np
|
|
7
7
|
from bec_lib.endpoints import MessageEndpoints
|
8
8
|
from bec_lib.logger import bec_logger
|
9
9
|
from pydantic import BaseModel, Field, ValidationError
|
10
|
-
from qtpy.QtCore import QThread
|
10
|
+
from qtpy.QtCore import QThread, Slot
|
11
11
|
from qtpy.QtWidgets import QWidget
|
12
12
|
|
13
|
-
from bec_widgets.qt_utils.error_popups import SafeSlot as Slot
|
13
|
+
# from bec_widgets.qt_utils.error_popups import SafeSlot as Slot
|
14
14
|
from bec_widgets.utils import EntryValidator
|
15
15
|
from bec_widgets.widgets.figure.plots.image.image_item import BECImageItem, ImageItemConfig
|
16
16
|
from bec_widgets.widgets.figure.plots.image.image_processor import (
|
@@ -80,6 +80,8 @@ class BECImageShow(BECPlotBase):
|
|
80
80
|
)
|
81
81
|
# Get bec shortcuts dev, scans, queue, scan_storage, dap
|
82
82
|
self.single_image = single_image
|
83
|
+
self.image_type = "device_monitor_2d"
|
84
|
+
self.scan_id = None
|
83
85
|
self.get_bec_shortcuts()
|
84
86
|
self.entry_validator = EntryValidator(self.dev)
|
85
87
|
self._images = defaultdict(dict)
|
@@ -105,7 +107,7 @@ class BECImageShow(BECPlotBase):
|
|
105
107
|
|
106
108
|
def find_image_by_monitor(self, item_id: str) -> BECImageItem:
|
107
109
|
"""
|
108
|
-
Find the
|
110
|
+
Find the image item by its gui_id.
|
109
111
|
|
110
112
|
Args:
|
111
113
|
item_id(str): The gui_id of the widget.
|
@@ -230,6 +232,7 @@ class BECImageShow(BECPlotBase):
|
|
230
232
|
def image(
|
231
233
|
self,
|
232
234
|
monitor: str,
|
235
|
+
monitor_type: Literal["1d", "2d"] = "2d",
|
233
236
|
color_map: Optional[str] = "magma",
|
234
237
|
color_bar: Optional[Literal["simple", "full"]] = "full",
|
235
238
|
downsample: Optional[bool] = True,
|
@@ -243,6 +246,7 @@ class BECImageShow(BECPlotBase):
|
|
243
246
|
|
244
247
|
Args:
|
245
248
|
monitor(str): The name of the monitor to display.
|
249
|
+
monitor_type(Literal["1d","2d"]): The type of monitor to display.
|
246
250
|
color_bar(Literal["simple","full"]): The type of color bar to display.
|
247
251
|
color_map(str): The color map to use for the image.
|
248
252
|
data(np.ndarray): Custom data to display.
|
@@ -251,7 +255,12 @@ class BECImageShow(BECPlotBase):
|
|
251
255
|
Returns:
|
252
256
|
BECImageItem: The image item.
|
253
257
|
"""
|
254
|
-
|
258
|
+
if monitor_type == "1d":
|
259
|
+
image_source = "device_monitor_1d"
|
260
|
+
self.image_type = "device_monitor_1d"
|
261
|
+
elif monitor_type == "2d":
|
262
|
+
image_source = "device_monitor_2d"
|
263
|
+
self.image_type = "device_monitor_2d"
|
255
264
|
|
256
265
|
image_exits = self._check_image_id(monitor, self._images)
|
257
266
|
if image_exits:
|
@@ -292,7 +301,6 @@ class BECImageShow(BECPlotBase):
|
|
292
301
|
**kwargs,
|
293
302
|
):
|
294
303
|
image_source = "custom"
|
295
|
-
# image_source = "device_monitor_2d"
|
296
304
|
|
297
305
|
image_exits = self._check_image_id(name, self._images)
|
298
306
|
if image_exits:
|
@@ -516,9 +524,58 @@ class BECImageShow(BECPlotBase):
|
|
516
524
|
"""
|
517
525
|
data = msg["data"]
|
518
526
|
device = msg["device"]
|
519
|
-
|
520
|
-
|
521
|
-
|
527
|
+
if self.image_type == "device_monitor_1d":
|
528
|
+
image = self._images["device_monitor_1d"][device]
|
529
|
+
current_scan_id = metadata.get("scan_id", None)
|
530
|
+
if current_scan_id is None:
|
531
|
+
return
|
532
|
+
if current_scan_id != self.scan_id:
|
533
|
+
self.reset()
|
534
|
+
self.scan_id = current_scan_id
|
535
|
+
image.image_buffer_list = []
|
536
|
+
image.max_len = 0
|
537
|
+
image_buffer = self.adjust_image_buffer(image, data)
|
538
|
+
image.raw_data = image_buffer
|
539
|
+
self.process_image(device, image, image_buffer)
|
540
|
+
elif self.image_type == "device_monitor_2d":
|
541
|
+
image = self._images["device_monitor_2d"][device]
|
542
|
+
image.raw_data = data
|
543
|
+
self.process_image(device, image, data)
|
544
|
+
|
545
|
+
def adjust_image_buffer(self, image: BECImageItem, new_data: np.ndarray) -> np.ndarray:
|
546
|
+
"""
|
547
|
+
Adjusts the image buffer to accommodate the new data, ensuring that all rows have the same length.
|
548
|
+
|
549
|
+
Args:
|
550
|
+
image: The image object (used to store buffer list and max_len).
|
551
|
+
new_data (np.ndarray): The new incoming 1D waveform data.
|
552
|
+
|
553
|
+
Returns:
|
554
|
+
np.ndarray: The updated image buffer with adjusted shapes.
|
555
|
+
"""
|
556
|
+
new_len = new_data.shape[0]
|
557
|
+
if not hasattr(image, "image_buffer_list"):
|
558
|
+
image.image_buffer_list = []
|
559
|
+
image.max_len = 0
|
560
|
+
|
561
|
+
if new_len > image.max_len:
|
562
|
+
image.max_len = new_len
|
563
|
+
for i in range(len(image.image_buffer_list)):
|
564
|
+
wf = image.image_buffer_list[i]
|
565
|
+
pad_width = image.max_len - wf.shape[0]
|
566
|
+
if pad_width > 0:
|
567
|
+
image.image_buffer_list[i] = np.pad(
|
568
|
+
wf, (0, pad_width), mode="constant", constant_values=0
|
569
|
+
)
|
570
|
+
image.image_buffer_list.append(new_data)
|
571
|
+
else:
|
572
|
+
pad_width = image.max_len - new_len
|
573
|
+
if pad_width > 0:
|
574
|
+
new_data = np.pad(new_data, (0, pad_width), mode="constant", constant_values=0)
|
575
|
+
image.image_buffer_list.append(new_data)
|
576
|
+
|
577
|
+
image_buffer = np.array(image.image_buffer_list)
|
578
|
+
return image_buffer
|
522
579
|
|
523
580
|
@Slot(str, np.ndarray)
|
524
581
|
def update_image(self, device: str, data: np.ndarray):
|
@@ -529,7 +586,7 @@ class BECImageShow(BECPlotBase):
|
|
529
586
|
device(str): The name of the device.
|
530
587
|
data(np.ndarray): The data to be updated.
|
531
588
|
"""
|
532
|
-
image_to_update = self._images[
|
589
|
+
image_to_update = self._images[self.image_type][device]
|
533
590
|
image_to_update.updateImage(data, autoLevels=image_to_update.config.autorange)
|
534
591
|
|
535
592
|
@Slot(str, ImageStats)
|
@@ -540,7 +597,7 @@ class BECImageShow(BECPlotBase):
|
|
540
597
|
Args:
|
541
598
|
stats(ImageStats): The statistics of the image.
|
542
599
|
"""
|
543
|
-
image_to_update = self._images[
|
600
|
+
image_to_update = self._images[self.image_type][device]
|
544
601
|
if image_to_update.config.autorange:
|
545
602
|
image_to_update.auto_update_vrange(stats)
|
546
603
|
|
@@ -553,7 +610,7 @@ class BECImageShow(BECPlotBase):
|
|
553
610
|
data = image.raw_data
|
554
611
|
self.process_image(image_id, image, data)
|
555
612
|
|
556
|
-
def
|
613
|
+
def _connect_device_monitor(self, monitor: str):
|
557
614
|
"""
|
558
615
|
Connect to the device monitor.
|
559
616
|
|
@@ -566,29 +623,36 @@ class BECImageShow(BECPlotBase):
|
|
566
623
|
except AttributeError:
|
567
624
|
previous_monitor = None
|
568
625
|
if previous_monitor and image_item.connected is True:
|
626
|
+
self.bec_dispatcher.disconnect_slot(
|
627
|
+
self.on_image_update, MessageEndpoints.device_monitor_1d(previous_monitor)
|
628
|
+
)
|
569
629
|
self.bec_dispatcher.disconnect_slot(
|
570
630
|
self.on_image_update, MessageEndpoints.device_monitor_2d(previous_monitor)
|
571
631
|
)
|
572
632
|
image_item.connected = False
|
573
633
|
if monitor and image_item.connected is False:
|
574
634
|
self.entry_validator.validate_monitor(monitor)
|
575
|
-
self.
|
576
|
-
self.
|
577
|
-
|
635
|
+
if self.image_type == "device_monitor_1d":
|
636
|
+
self.bec_dispatcher.connect_slot(
|
637
|
+
self.on_image_update, MessageEndpoints.device_monitor_1d(monitor)
|
638
|
+
)
|
639
|
+
elif self.image_type == "device_monitor_2d":
|
640
|
+
self.bec_dispatcher.connect_slot(
|
641
|
+
self.on_image_update, MessageEndpoints.device_monitor_2d(monitor)
|
642
|
+
)
|
578
643
|
image_item.set_monitor(monitor)
|
579
644
|
image_item.connected = True
|
580
645
|
|
581
646
|
def _add_image_object(
|
582
647
|
self, source: str, name: str, config: ImageItemConfig, data=None
|
583
|
-
) -> BECImageItem:
|
648
|
+
) -> BECImageItem:
|
584
649
|
config.parent_id = self.gui_id
|
585
650
|
if self.single_image is True and len(self.images) > 0:
|
586
651
|
self.remove_image(0)
|
587
652
|
image = BECImageItem(config=config, parent_image=self)
|
588
653
|
self.plot_item.addItem(image)
|
589
654
|
self._images[source][name] = image
|
590
|
-
|
591
|
-
self._connect_device_monitor_2d(config.monitor)
|
655
|
+
self._connect_device_monitor(config.monitor)
|
592
656
|
self.config.images[name] = config
|
593
657
|
if data is not None:
|
594
658
|
image.setImage(data)
|
@@ -673,6 +737,9 @@ class BECImageShow(BECPlotBase):
|
|
673
737
|
"""
|
674
738
|
image = self.find_image_by_monitor(image_id)
|
675
739
|
if image:
|
740
|
+
self.bec_dispatcher.disconnect_slot(
|
741
|
+
self.on_image_update, MessageEndpoints.device_monitor_1d(image.config.monitor)
|
742
|
+
)
|
676
743
|
self.bec_dispatcher.disconnect_slot(
|
677
744
|
self.on_image_update, MessageEndpoints.device_monitor_2d(image.config.monitor)
|
678
745
|
)
|
@@ -681,9 +748,9 @@ class BECImageShow(BECPlotBase):
|
|
681
748
|
"""
|
682
749
|
Clean up the widget.
|
683
750
|
"""
|
684
|
-
for monitor in self._images[
|
751
|
+
for monitor in self._images[self.image_type]:
|
685
752
|
self.bec_dispatcher.disconnect_slot(
|
686
|
-
self.on_image_update, MessageEndpoints.
|
753
|
+
self.on_image_update, MessageEndpoints.device_monitor_1d(monitor)
|
687
754
|
)
|
688
755
|
self.images.clear()
|
689
756
|
|
@@ -452,13 +452,14 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
|
|
452
452
|
|
453
453
|
self.fps_monitor.sigFpsUpdate.connect(self.update_fps_label)
|
454
454
|
|
455
|
-
def unhook_fps_monitor(self):
|
455
|
+
def unhook_fps_monitor(self, delete_label=True):
|
456
456
|
"""Unhook the FPS monitor from the plot."""
|
457
457
|
if self.fps_monitor is not None:
|
458
458
|
# Remove Monitor
|
459
459
|
self.fps_monitor.cleanup()
|
460
460
|
self.fps_monitor.deleteLater()
|
461
461
|
self.fps_monitor = None
|
462
|
+
if self.fps_label is not None and delete_label:
|
462
463
|
# Remove Label
|
463
464
|
self.removeItem(self.fps_label)
|
464
465
|
self.fps_label.deleteLater()
|
@@ -490,6 +491,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
|
|
490
491
|
def cleanup_pyqtgraph(self):
|
491
492
|
"""Cleanup pyqtgraph items."""
|
492
493
|
self.unhook_crosshair()
|
494
|
+
self.unhook_fps_monitor(delete_label=False)
|
493
495
|
self.tick_item.cleanup()
|
494
496
|
self.arrow_item.cleanup()
|
495
497
|
item = self.plot_item
|
@@ -4,7 +4,7 @@ import sys
|
|
4
4
|
from typing import Literal, Optional
|
5
5
|
|
6
6
|
import pyqtgraph as pg
|
7
|
-
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
7
|
+
from qtpy.QtWidgets import QComboBox, QVBoxLayout, QWidget
|
8
8
|
|
9
9
|
from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
|
10
10
|
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
@@ -13,6 +13,7 @@ from bec_widgets.qt_utils.toolbar import (
|
|
13
13
|
MaterialIconAction,
|
14
14
|
ModularToolBar,
|
15
15
|
SeparatorAction,
|
16
|
+
WidgetAction,
|
16
17
|
)
|
17
18
|
from bec_widgets.utils.bec_widget import BECWidget
|
18
19
|
from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
|
@@ -63,11 +64,14 @@ class BECImageWidget(BECWidget, QWidget):
|
|
63
64
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
64
65
|
|
65
66
|
self.fig = BECFigure()
|
67
|
+
self.dim_combo_box = QComboBox()
|
68
|
+
self.dim_combo_box.addItems(["1d", "2d"])
|
66
69
|
self.toolbar = ModularToolBar(
|
67
70
|
actions={
|
68
71
|
"monitor": DeviceSelectionAction(
|
69
72
|
"Monitor:", DeviceComboBox(device_filter="Device")
|
70
73
|
),
|
74
|
+
"monitor_type": WidgetAction(widget=self.dim_combo_box),
|
71
75
|
"connect": MaterialIconAction(icon_name="link", tooltip="Connect Device"),
|
72
76
|
"separator_0": SeparatorAction(),
|
73
77
|
"save": MaterialIconAction(icon_name="save", tooltip="Open Export Dialog"),
|
@@ -163,7 +167,8 @@ class BECImageWidget(BECWidget, QWidget):
|
|
163
167
|
def _connect_action(self):
|
164
168
|
monitor_combo = self.toolbar.widgets["monitor"].device_combobox
|
165
169
|
monitor_name = monitor_combo.currentText()
|
166
|
-
self.
|
170
|
+
monitor_type = self.toolbar.widgets["monitor_type"].widget.currentText()
|
171
|
+
self.image(monitor=monitor_name, monitor_type=monitor_type)
|
167
172
|
monitor_combo.setStyleSheet("QComboBox { background-color: " "; }")
|
168
173
|
|
169
174
|
def show_axis_settings(self):
|
@@ -182,6 +187,7 @@ class BECImageWidget(BECWidget, QWidget):
|
|
182
187
|
def image(
|
183
188
|
self,
|
184
189
|
monitor: str,
|
190
|
+
monitor_type: Optional[Literal["1d", "2d"]] = "2d",
|
185
191
|
color_map: Optional[str] = "magma",
|
186
192
|
color_bar: Optional[Literal["simple", "full"]] = "full",
|
187
193
|
downsample: Optional[bool] = True,
|
@@ -195,8 +201,14 @@ class BECImageWidget(BECWidget, QWidget):
|
|
195
201
|
self.toolbar.widgets["monitor"].device_combobox.setStyleSheet(
|
196
202
|
"QComboBox {{ background-color: " "; }}"
|
197
203
|
)
|
204
|
+
if self.toolbar.widgets["monitor_type"].widget.currentText() != monitor_type:
|
205
|
+
self.toolbar.widgets["monitor_type"].widget.setCurrentText(monitor_type)
|
206
|
+
self.toolbar.widgets["monitor_type"].widget.setStyleSheet(
|
207
|
+
"QComboBox {{ background-color: " "; }}"
|
208
|
+
)
|
198
209
|
return self._image.image(
|
199
210
|
monitor=monitor,
|
211
|
+
monitor_type=monitor_type,
|
200
212
|
color_map=color_map,
|
201
213
|
color_bar=color_bar,
|
202
214
|
downsample=downsample,
|
@@ -486,6 +498,7 @@ def main(): # pragma: no cover
|
|
486
498
|
|
487
499
|
app = QApplication(sys.argv)
|
488
500
|
widget = BECImageWidget()
|
501
|
+
widget.image("waveform", "1d")
|
489
502
|
widget.show()
|
490
503
|
sys.exit(app.exec_())
|
491
504
|
|
@@ -5,10 +5,19 @@ import signal
|
|
5
5
|
import socket
|
6
6
|
import subprocess
|
7
7
|
import sys
|
8
|
+
from typing import Literal
|
9
|
+
|
10
|
+
from pydantic import BaseModel
|
11
|
+
from qtpy.QtCore import Signal, Slot
|
8
12
|
|
9
13
|
from bec_widgets.widgets.website.website import WebsiteWidget
|
10
14
|
|
11
15
|
|
16
|
+
class VSCodeInstructionMessage(BaseModel):
|
17
|
+
command: Literal["open", "write", "close", "zenMode", "save", "new", "setCursor"]
|
18
|
+
content: str = ""
|
19
|
+
|
20
|
+
|
12
21
|
def get_free_port():
|
13
22
|
"""
|
14
23
|
Get a free port on the local machine.
|
@@ -28,6 +37,8 @@ class VSCodeEditor(WebsiteWidget):
|
|
28
37
|
A widget to display the VSCode editor.
|
29
38
|
"""
|
30
39
|
|
40
|
+
file_saved = Signal(str)
|
41
|
+
|
31
42
|
token = "bec"
|
32
43
|
host = "127.0.0.1"
|
33
44
|
|
@@ -41,6 +52,7 @@ class VSCodeEditor(WebsiteWidget):
|
|
41
52
|
self._url = f"http://{self.host}:{self.port}?tkn={self.token}"
|
42
53
|
super().__init__(parent=parent, config=config, client=client, gui_id=gui_id)
|
43
54
|
self.start_server()
|
55
|
+
self.bec_dispatcher.connect_slot(self.on_vscode_event, f"vscode-events/{self.gui_id}")
|
44
56
|
|
45
57
|
def start_server(self):
|
46
58
|
"""
|
@@ -49,11 +61,19 @@ class VSCodeEditor(WebsiteWidget):
|
|
49
61
|
This method starts the server for the VSCode editor in a subprocess.
|
50
62
|
"""
|
51
63
|
|
64
|
+
env = os.environ.copy()
|
65
|
+
env["BEC_Widgets_GUIID"] = self.gui_id
|
66
|
+
env["BEC_REDIS_HOST"] = self.client.connector.host
|
52
67
|
cmd = shlex.split(
|
53
68
|
f"code serve-web --port {self.port} --connection-token={self.token} --accept-server-license-terms"
|
54
69
|
)
|
55
70
|
self.process = subprocess.Popen(
|
56
|
-
cmd,
|
71
|
+
cmd,
|
72
|
+
text=True,
|
73
|
+
stdout=subprocess.PIPE,
|
74
|
+
stderr=subprocess.DEVNULL,
|
75
|
+
preexec_fn=os.setsid,
|
76
|
+
env=env,
|
57
77
|
)
|
58
78
|
|
59
79
|
os.set_blocking(self.process.stdout.fileno(), False)
|
@@ -66,6 +86,92 @@ class VSCodeEditor(WebsiteWidget):
|
|
66
86
|
self.set_url(self._url)
|
67
87
|
self.wait_until_loaded()
|
68
88
|
|
89
|
+
@Slot(str)
|
90
|
+
def open_file(self, file_path: str):
|
91
|
+
"""
|
92
|
+
Open a file in the VSCode editor.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
file_path: The file path to open
|
96
|
+
"""
|
97
|
+
msg = VSCodeInstructionMessage(command="open", content=f"file://{file_path}")
|
98
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
99
|
+
|
100
|
+
@Slot(dict, dict)
|
101
|
+
def on_vscode_event(self, content, _metadata):
|
102
|
+
"""
|
103
|
+
Handle the VSCode event. VSCode events are received as RawMessages.
|
104
|
+
|
105
|
+
Args:
|
106
|
+
content: The content of the event
|
107
|
+
metadata: The metadata of the event
|
108
|
+
"""
|
109
|
+
|
110
|
+
# the message also contains the content but I think is fine for now to just emit the file path
|
111
|
+
if not isinstance(content["data"], dict):
|
112
|
+
return
|
113
|
+
if "uri" not in content["data"]:
|
114
|
+
return
|
115
|
+
if not content["data"]["uri"].startswith("file://"):
|
116
|
+
return
|
117
|
+
file_path = content["data"]["uri"].split("file://")[1]
|
118
|
+
self.file_saved.emit(file_path)
|
119
|
+
|
120
|
+
@Slot()
|
121
|
+
def save_file(self):
|
122
|
+
"""
|
123
|
+
Save the file in the VSCode editor.
|
124
|
+
"""
|
125
|
+
msg = VSCodeInstructionMessage(command="save")
|
126
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
127
|
+
|
128
|
+
@Slot()
|
129
|
+
def new_file(self):
|
130
|
+
"""
|
131
|
+
Create a new file in the VSCode editor.
|
132
|
+
"""
|
133
|
+
msg = VSCodeInstructionMessage(command="new")
|
134
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
135
|
+
|
136
|
+
@Slot()
|
137
|
+
def close_file(self):
|
138
|
+
"""
|
139
|
+
Close the file in the VSCode editor.
|
140
|
+
"""
|
141
|
+
msg = VSCodeInstructionMessage(command="close")
|
142
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
143
|
+
|
144
|
+
@Slot(str)
|
145
|
+
def write_file(self, content: str):
|
146
|
+
"""
|
147
|
+
Write content to the file in the VSCode editor.
|
148
|
+
|
149
|
+
Args:
|
150
|
+
content: The content to write
|
151
|
+
"""
|
152
|
+
msg = VSCodeInstructionMessage(command="write", content=content)
|
153
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
154
|
+
|
155
|
+
@Slot()
|
156
|
+
def zen_mode(self):
|
157
|
+
"""
|
158
|
+
Toggle the Zen mode in the VSCode editor.
|
159
|
+
"""
|
160
|
+
msg = VSCodeInstructionMessage(command="zenMode")
|
161
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
162
|
+
|
163
|
+
@Slot(int, int)
|
164
|
+
def set_cursor(self, line: int, column: int):
|
165
|
+
"""
|
166
|
+
Set the cursor in the VSCode editor.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
line: The line number
|
170
|
+
column: The column number
|
171
|
+
"""
|
172
|
+
msg = VSCodeInstructionMessage(command="setCursor", content=f"{line},{column}")
|
173
|
+
self.client.connector.raw_send(f"vscode-instructions/{self.gui_id}", msg.model_dump_json())
|
174
|
+
|
69
175
|
def cleanup_vscode(self):
|
70
176
|
"""
|
71
177
|
Cleanup the VSCode editor.
|
@@ -79,6 +185,7 @@ class VSCodeEditor(WebsiteWidget):
|
|
79
185
|
"""
|
80
186
|
Cleanup the widget. This method is called from the dock area when the widget is removed.
|
81
187
|
"""
|
188
|
+
self.bec_dispatcher.disconnect_slot(self.on_vscode_event, f"vscode-events/{self.gui_id}")
|
82
189
|
self.cleanup_vscode()
|
83
190
|
return super().cleanup()
|
84
191
|
|
@@ -89,7 +196,7 @@ if __name__ == "__main__": # pragma: no cover
|
|
89
196
|
from qtpy.QtWidgets import QApplication
|
90
197
|
|
91
198
|
app = QApplication(sys.argv)
|
92
|
-
widget = VSCodeEditor()
|
199
|
+
widget = VSCodeEditor(gui_id="unknown")
|
93
200
|
widget.show()
|
94
201
|
app.exec_()
|
95
202
|
widget.bec_dispatcher.disconnect_all()
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=Dc1iDjsc72UxdUtihx4uSZU0lrTQeR8hZwGx1MQBfKE,8432
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=HNKObLHRdn9EU6yqjOfIWmErsDeBt7ffe7yyRbZS3NA,7465
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=hV96OUPMuSpWBtmpNtWNAb0beAY0hjUEDESVB7pQbAI,1334
|
8
8
|
README.md,sha256=Od69x-RS85Hph0-WwWACwal4yUd67XkEn4APEfHhHFw,2649
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=4rIuf_3lQm4rURa8VikhNvgRpIszEI-2SDRmR_IFX0Y,2594
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
|
12
12
|
.gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
|
@@ -36,7 +36,7 @@ bec_widgets/examples/general_app/general_app.py,sha256=PoFCTuA_1yqrpgthASpYFgH7J
|
|
36
36
|
bec_widgets/examples/general_app/general_app.ui,sha256=TsejkM3Z8znnixyqxoj4SwhIIpIzTAuGAMkGXSS1aT8,10479
|
37
37
|
bec_widgets/examples/general_app/web_links.py,sha256=d5OgzgI9zb-NAC0pOGanOtJX3nZoe4x8QuQTw-_hK_8,434
|
38
38
|
bec_widgets/examples/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=
|
39
|
+
bec_widgets/examples/jupyter_console/jupyter_console_window.py,sha256=ghtbw0rZjjLMq3Kn01PTPn7ubJ9O20Y0VFgIFlOkWXY,6776
|
40
40
|
bec_widgets/examples/plugin_example_pyside/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
bec_widgets/examples/plugin_example_pyside/main.py,sha256=zDP5wO7wb3BVsQ15HOCRT1nNmCujIVRvSXZ3Txje8L0,549
|
42
42
|
bec_widgets/examples/plugin_example_pyside/registertictactoe.py,sha256=cVhBnP0qx5j9Jft-VeKvlTFE-bX58hbP45CX0f4r5pM,535
|
@@ -50,7 +50,7 @@ bec_widgets/qt_utils/error_popups.py,sha256=y9gKKWaafp468ioHr96nBhf02ZpEgjDc-BAV
|
|
50
50
|
bec_widgets/qt_utils/palette_viewer.py,sha256=PGhJ-4XI0f7gNnC1djNgcIHYg6HDO6hPju4pfWj9rvg,6311
|
51
51
|
bec_widgets/qt_utils/redis_message_waiter.py,sha256=fvL_QgC0cTDv_FPJdRyp5AKjf401EJU4z3r38p47ydY,1745
|
52
52
|
bec_widgets/qt_utils/settings_dialog.py,sha256=NhtzTer_xzlB2lLLrGklkI1QYLJEWQpJoZbCz4o5daI,3645
|
53
|
-
bec_widgets/qt_utils/toolbar.py,sha256=
|
53
|
+
bec_widgets/qt_utils/toolbar.py,sha256=yR2WNPv7dD8jU12aHgUMAi5-FYyCKe2MNSsqMzsa5pg,9856
|
54
54
|
bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
|
55
55
|
bec_widgets/utils/bec_connector.py,sha256=I9M_4g-_-WaMmhyXzChFCGXAElelx0mG6E1g0KvtEQs,10059
|
56
56
|
bec_widgets/utils/bec_designer.py,sha256=Z3MeMju-KmTz8POtm23VQfp4rvtD2sF6eIOKQkl2F7w,4729
|
@@ -160,13 +160,13 @@ bec_widgets/widgets/dock/dock_area.pyproject,sha256=URW0UrDXCnkzk80rbQmUMgF6Uqay
|
|
160
160
|
bec_widgets/widgets/dock/dock_area_plugin.py,sha256=hfA1r13hmlXaDO6kzbk6vBlhVlGh2eSTXrnftjzZj0Q,1320
|
161
161
|
bec_widgets/widgets/dock/register_dock_area.py,sha256=Yqd1mq6CcHwlxHZxX5EHKONy4P44nMm8pso-4X0tvJI,464
|
162
162
|
bec_widgets/widgets/figure/__init__.py,sha256=3hGx_KOV7QHCYAV06aNuUgKq4QIYCjUTad-DrwkUaBM,44
|
163
|
-
bec_widgets/widgets/figure/figure.py,sha256=
|
163
|
+
bec_widgets/widgets/figure/figure.py,sha256=dHH27Fwr9dFBx4g6CXfDQr09LVAUi7xghxukhjoRND8,29110
|
164
164
|
bec_widgets/widgets/figure/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
165
165
|
bec_widgets/widgets/figure/plots/axis_settings.py,sha256=grgrX4t4eAzccW4jj4HYtMSxy8Wgcd9N9J1aU7UHtIs,3723
|
166
166
|
bec_widgets/widgets/figure/plots/axis_settings.ui,sha256=ye-guaRU_jhu7sHZS-9AjBjLrCtA1msOD0dszu4o9x8,11785
|
167
|
-
bec_widgets/widgets/figure/plots/plot_base.py,sha256=
|
167
|
+
bec_widgets/widgets/figure/plots/plot_base.py,sha256=7c1HQaGwxsN2vQOFuF5Z68Gp-hbeHOI04C4wvWQs89w,18180
|
168
168
|
bec_widgets/widgets/figure/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
169
|
-
bec_widgets/widgets/figure/plots/image/image.py,sha256=
|
169
|
+
bec_widgets/widgets/figure/plots/image/image.py,sha256=tTtBoAA5CRhSEMae0k8dElM-MznnhcgTg0flXIIduq0,28052
|
170
170
|
bec_widgets/widgets/figure/plots/image/image_item.py,sha256=TwHo6FwCiQgJBdr-KKy_7Y_vYSB0pPjBl1AubuZSrE0,11002
|
171
171
|
bec_widgets/widgets/figure/plots/image/image_processor.py,sha256=GeTtWjbldy6VejMwPGQgM-o3d6bmLglCjdoktu19xfA,5262
|
172
172
|
bec_widgets/widgets/figure/plots/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -177,7 +177,7 @@ bec_widgets/widgets/figure/plots/waveform/waveform_curve.py,sha256=RUo4GfXwlaCei
|
|
177
177
|
bec_widgets/widgets/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
178
178
|
bec_widgets/widgets/image/bec_image_widget.pyproject,sha256=PHisdBo5_5UCApd27GkizzqgfdjsDx2bFZa_p9LiSW8,30
|
179
179
|
bec_widgets/widgets/image/bec_image_widget_plugin.py,sha256=3nOHJTukHsEkaCLAivPHIY4qdshAj86LUKb5fYF3C-Y,1369
|
180
|
-
bec_widgets/widgets/image/image_widget.py,sha256=
|
180
|
+
bec_widgets/widgets/image/image_widget.py,sha256=o639hbSJVrCGwx2r0KV8JUJ-inaME-GWMR7YDmzFHhg,17796
|
181
181
|
bec_widgets/widgets/image/register_bec_image_widget.py,sha256=01YLZQTMSSIXvH1TSL-1AYsRs1a4EbSwKLVAwh9AjeA,478
|
182
182
|
bec_widgets/widgets/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
183
183
|
bec_widgets/widgets/jupyter_console/jupyter_console.py,sha256=-e7HQOECeH5eDrJYh4BFIzRL78LDkooU4otabyN0aX4,2343
|
@@ -248,7 +248,7 @@ bec_widgets/widgets/vscode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
248
248
|
bec_widgets/widgets/vscode/register_vs_code_editor.py,sha256=JATKBkTEuReeQ2Jj402xasjgVRMFI8uUOAAwmnFOWRA,473
|
249
249
|
bec_widgets/widgets/vscode/vs_code_editor.pyproject,sha256=bxx0jZlSfBo-Em7p15W1QIJ9lFr9jqTqGynUQG01ocU,24
|
250
250
|
bec_widgets/widgets/vscode/vs_code_editor_plugin.py,sha256=exFR6HTVdLLPfn2U6BMDugPoxZaebcHTnHWMrX2n_d4,1338
|
251
|
-
bec_widgets/widgets/vscode/vscode.py,sha256=
|
251
|
+
bec_widgets/widgets/vscode/vscode.py,sha256=c4Uef-xp5gJqVJdw82nWJWF-iTWz4Zsx4HhgbsGhe-E,6181
|
252
252
|
bec_widgets/widgets/waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
253
253
|
bec_widgets/widgets/waveform/bec_waveform_widget.pyproject,sha256=GLD8GN9dXx9wNbtnevrxqqcwk7vKV-Uv8QYSycdaoaI,33
|
254
254
|
bec_widgets/widgets/waveform/bec_waveform_widget_plugin.py,sha256=qSQTeCzIUn8rgDkjIM47Rr3-fqg1uk8rDf_lCoY9gZw,1402
|
@@ -265,8 +265,8 @@ bec_widgets/widgets/website/register_website_widget.py,sha256=LIQJpV9uqcBiPR9cEA
|
|
265
265
|
bec_widgets/widgets/website/website.py,sha256=42pncCc_zI2eqeMArIurVmPUukRo5bTxa2h1Skah-io,3012
|
266
266
|
bec_widgets/widgets/website/website_widget.pyproject,sha256=scOiV3cV1_BjbzpPzy2N8rIJL5P2qIZz8ObTJ-Uvdtg,25
|
267
267
|
bec_widgets/widgets/website/website_widget_plugin.py,sha256=pz38_C2cZ0yvPPS02wdIPcmhFo_yiwUhflsASocAPQQ,1341
|
268
|
-
bec_widgets-0.
|
269
|
-
bec_widgets-0.
|
270
|
-
bec_widgets-0.
|
271
|
-
bec_widgets-0.
|
272
|
-
bec_widgets-0.
|
268
|
+
bec_widgets-0.118.0.dist-info/METADATA,sha256=hV96OUPMuSpWBtmpNtWNAb0beAY0hjUEDESVB7pQbAI,1334
|
269
|
+
bec_widgets-0.118.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
270
|
+
bec_widgets-0.118.0.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
271
|
+
bec_widgets-0.118.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
272
|
+
bec_widgets-0.118.0.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|