bec-widgets 0.79.3__py3-none-any.whl → 0.82.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.
- .gitlab-ci.yml +0 -1
- .pylintrc +1 -1
- CHANGELOG.md +52 -62
- PKG-INFO +1 -4
- README.md +2 -2
- bec_widgets/cli/client.py +3 -2
- bec_widgets/cli/generate_cli.py +11 -10
- bec_widgets/cli/rpc_wigdet_handler.py +1 -1
- bec_widgets/examples/__init__.py +0 -9
- bec_widgets/utils/bec_connector.py +2 -1
- bec_widgets/utils/bec_dispatcher.py +3 -3
- bec_widgets/utils/bec_widget.py +2 -0
- bec_widgets/utils/entry_validator.py +1 -1
- bec_widgets/utils/plugin_utils.py +80 -10
- bec_widgets/utils/ui_loader.py +85 -26
- bec_widgets/widgets/{device_inputs → base_classes}/device_input_base.py +2 -0
- bec_widgets/widgets/color_button/color_button.py +36 -0
- bec_widgets/widgets/{buttons/color_button → color_button}/color_button_plugin.py +1 -1
- bec_widgets/widgets/{buttons/color_button → color_button}/register_color_button.py +1 -1
- bec_widgets/widgets/device_combobox/assets/device_combobox_icon.png +0 -0
- bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/device_combobox.py +2 -2
- bec_widgets/widgets/device_combobox/device_combobox.pyproject +3 -0
- bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/device_combobox_plugin.py +6 -3
- bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/register_device_combobox.py +1 -3
- bec_widgets/widgets/device_line_edit/assets/line_edit_icon.png +0 -0
- bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/device_line_edit.py +2 -2
- bec_widgets/widgets/device_line_edit/device_line_edit.pyproject +3 -0
- bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/device_line_edit_plugin.py +6 -3
- bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/register_device_line_edit.py +1 -3
- bec_widgets/widgets/figure/plots/waveform/waveform.py +8 -2
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_settings.py +1 -1
- bec_widgets/widgets/motor_map/motor_map_dialog/motor_map_toolbar.py +1 -1
- bec_widgets/widgets/motor_map/motor_map_widget.py +0 -12
- bec_widgets/widgets/scan_control/scan_control.py +1 -1
- bec_widgets/widgets/scan_control/scan_group_box.py +1 -1
- bec_widgets/widgets/stop_button/assets/stop.png +0 -0
- bec_widgets/widgets/stop_button/register_stop_button.py +15 -0
- bec_widgets/widgets/{buttons/stop_button → stop_button}/stop_button.py +5 -12
- bec_widgets/widgets/stop_button/stop_button.pyproject +1 -0
- bec_widgets/widgets/stop_button/stop_button_plugin.py +57 -0
- bec_widgets/widgets/toggle/register_toggle_switch.py +15 -0
- bec_widgets/widgets/toggle/toggle.py +149 -0
- bec_widgets/widgets/toggle/toggle_switch.pyproject +1 -0
- bec_widgets/widgets/toggle/toggle_switch_plugin.py +54 -0
- {bec_widgets-0.79.3.dist-info → bec_widgets-0.82.0.dist-info}/METADATA +1 -4
- {bec_widgets-0.79.3.dist-info → bec_widgets-0.82.0.dist-info}/RECORD +66 -74
- docs/introduction/introduction.md +1 -1
- docs/user/getting_started/installation.md +2 -2
- pyproject.toml +1 -2
- tests/unit_tests/test_device_input_base.py +1 -1
- tests/unit_tests/test_device_input_widgets.py +2 -2
- tests/unit_tests/test_generate_cli_client.py +41 -17
- tests/unit_tests/test_plugin_utils.py +2 -3
- tests/unit_tests/test_stop_button.py +5 -2
- tests/unit_tests/test_toggle.py +38 -0
- bec_widgets/examples/motor_movement/__init__.py +0 -9
- bec_widgets/examples/motor_movement/motor_control_compilations.py +0 -250
- bec_widgets/examples/motor_movement/motor_controller.ui +0 -926
- bec_widgets/widgets/buttons/__init__.py +0 -1
- bec_widgets/widgets/buttons/color_button/color_button.py +0 -17
- bec_widgets/widgets/device_inputs/__init__.py +0 -2
- bec_widgets/widgets/device_inputs/device_combobox/device_combobox.pyproject +0 -4
- bec_widgets/widgets/device_inputs/device_combobox/launch_device_combobox.py +0 -11
- bec_widgets/widgets/device_inputs/device_line_edit/device_line_edit.pyproject +0 -4
- bec_widgets/widgets/device_inputs/device_line_edit/launch_device_line_edit.py +0 -11
- bec_widgets/widgets/motor_control/motor_control.py +0 -252
- bec_widgets/widgets/motor_control/motor_table/motor_table.py +0 -484
- bec_widgets/widgets/motor_control/motor_table/motor_table.ui +0 -113
- bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +0 -159
- bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui +0 -149
- bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +0 -230
- bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui +0 -298
- bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
- bec_widgets/widgets/motor_control/selection/selection.py +0 -110
- bec_widgets/widgets/motor_control/selection/selection.ui +0 -69
- tests/unit_tests/test_motor_control.py +0 -588
- /bec_widgets/widgets/{buttons/color_button → base_classes}/__init__.py +0 -0
- /bec_widgets/widgets/{buttons/stop_button → color_button}/__init__.py +0 -0
- /bec_widgets/widgets/{buttons/color_button → color_button}/assets/color_button.png +0 -0
- /bec_widgets/widgets/{buttons/color_button → color_button}/color_button.pyproject +0 -0
- /bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/__init__.py +0 -0
- /bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/__init__.py +0 -0
- /bec_widgets/widgets/{motor_control → stop_button}/__init__.py +0 -0
- /bec_widgets/widgets/{motor_control/motor_table → toggle}/__init__.py +0 -0
- {bec_widgets-0.79.3.dist-info → bec_widgets-0.82.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.79.3.dist-info → bec_widgets-0.82.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.79.3.dist-info → bec_widgets-0.82.0.dist-info}/licenses/LICENSE +0 -0
Binary file
|
@@ -2,10 +2,10 @@ from typing import TYPE_CHECKING
|
|
2
2
|
|
3
3
|
from qtpy.QtWidgets import QComboBox
|
4
4
|
|
5
|
-
from bec_widgets.widgets.
|
5
|
+
from bec_widgets.widgets.base_classes.device_input_base import DeviceInputBase, DeviceInputConfig
|
6
6
|
|
7
7
|
if TYPE_CHECKING:
|
8
|
-
from bec_widgets.widgets.
|
8
|
+
from bec_widgets.widgets.base_classes.device_input_base import DeviceInputConfig
|
9
9
|
|
10
10
|
|
11
11
|
class DeviceComboBox(DeviceInputBase, QComboBox):
|
bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/device_combobox_plugin.py
RENAMED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Copyright (C) 2022 The Qt Company Ltd.
|
2
2
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
import os
|
3
4
|
|
4
5
|
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
5
6
|
from qtpy.QtGui import QIcon
|
6
7
|
|
7
|
-
from bec_widgets.widgets.
|
8
|
+
from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
|
8
9
|
|
9
10
|
DOM_XML = """
|
10
11
|
<ui language='c++'>
|
@@ -27,10 +28,12 @@ class DeviceComboBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
|
27
28
|
return DOM_XML
|
28
29
|
|
29
30
|
def group(self):
|
30
|
-
return ""
|
31
|
+
return "BEC Device Inputs"
|
31
32
|
|
32
33
|
def icon(self):
|
33
|
-
|
34
|
+
current_path = os.path.dirname(__file__)
|
35
|
+
icon_path = os.path.join(current_path, "assets", "device_combobox_icon.png")
|
36
|
+
return QIcon(icon_path)
|
34
37
|
|
35
38
|
def includeFile(self):
|
36
39
|
return "device_combobox"
|
bec_widgets/widgets/{device_inputs/device_combobox → device_combobox}/register_device_combobox.py
RENAMED
@@ -6,9 +6,7 @@ def main(): # pragma: no cover
|
|
6
6
|
return
|
7
7
|
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
8
|
|
9
|
-
from bec_widgets.widgets.
|
10
|
-
DeviceComboBoxPlugin,
|
11
|
-
)
|
9
|
+
from bec_widgets.widgets.device_combobox.device_combobox_plugin import DeviceComboBoxPlugin
|
12
10
|
|
13
11
|
QPyDesignerCustomWidgetCollection.addCustomWidget(DeviceComboBoxPlugin())
|
14
12
|
|
Binary file
|
@@ -3,10 +3,10 @@ from typing import TYPE_CHECKING
|
|
3
3
|
from qtpy.QtCore import QSize
|
4
4
|
from qtpy.QtWidgets import QCompleter, QLineEdit, QSizePolicy
|
5
5
|
|
6
|
-
from bec_widgets.widgets.
|
6
|
+
from bec_widgets.widgets.base_classes.device_input_base import DeviceInputBase, DeviceInputConfig
|
7
7
|
|
8
8
|
if TYPE_CHECKING:
|
9
|
-
from bec_widgets.widgets.
|
9
|
+
from bec_widgets.widgets.base_classes.device_input_base import DeviceInputConfig
|
10
10
|
|
11
11
|
|
12
12
|
class DeviceLineEdit(DeviceInputBase, QLineEdit):
|
bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/device_line_edit_plugin.py
RENAMED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Copyright (C) 2022 The Qt Company Ltd.
|
2
2
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
import os
|
3
4
|
|
4
5
|
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
5
6
|
from qtpy.QtGui import QIcon
|
6
7
|
|
7
|
-
from bec_widgets.widgets.
|
8
|
+
from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
|
8
9
|
|
9
10
|
DOM_XML = """
|
10
11
|
<ui language='c++'>
|
@@ -27,10 +28,12 @@ class DeviceLineEditPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
|
27
28
|
return DOM_XML
|
28
29
|
|
29
30
|
def group(self):
|
30
|
-
return ""
|
31
|
+
return "BEC Device Inputs"
|
31
32
|
|
32
33
|
def icon(self):
|
33
|
-
|
34
|
+
current_path = os.path.dirname(__file__)
|
35
|
+
icon_path = os.path.join(current_path, "assets", "line_edit_icon.png")
|
36
|
+
return QIcon(icon_path)
|
34
37
|
|
35
38
|
def includeFile(self):
|
36
39
|
return "device_line_edit"
|
bec_widgets/widgets/{device_inputs/device_line_edit → device_line_edit}/register_device_line_edit.py
RENAMED
@@ -6,9 +6,7 @@ def main(): # pragma: no cover
|
|
6
6
|
return
|
7
7
|
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
8
|
|
9
|
-
from bec_widgets.widgets.
|
10
|
-
DeviceLineEditPlugin,
|
11
|
-
)
|
9
|
+
from bec_widgets.widgets.device_line_edit.device_line_edit_plugin import DeviceLineEditPlugin
|
12
10
|
|
13
11
|
QPyDesignerCustomWidgetCollection.addCustomWidget(DeviceLineEditPlugin())
|
14
12
|
|
@@ -221,6 +221,7 @@ class BECWaveform(BECPlotBase):
|
|
221
221
|
label: str | None = None,
|
222
222
|
validate: bool = True,
|
223
223
|
dap: str | None = None, # TODO add dap custom curve wrapper
|
224
|
+
**kwargs,
|
224
225
|
) -> BECCurve:
|
225
226
|
"""
|
226
227
|
Plot a curve to the plot widget.
|
@@ -244,7 +245,7 @@ class BECWaveform(BECPlotBase):
|
|
244
245
|
"""
|
245
246
|
|
246
247
|
if x is not None and y is not None:
|
247
|
-
return self.add_curve_custom(x=x, y=y, label=label, color=color)
|
248
|
+
return self.add_curve_custom(x=x, y=y, label=label, color=color, **kwargs)
|
248
249
|
else:
|
249
250
|
if dap:
|
250
251
|
self.add_dap(x_name=x_name, y_name=y_name, dap=dap)
|
@@ -259,6 +260,7 @@ class BECWaveform(BECPlotBase):
|
|
259
260
|
color_map_z=color_map_z,
|
260
261
|
label=label,
|
261
262
|
validate_bec=validate,
|
263
|
+
**kwargs,
|
262
264
|
)
|
263
265
|
|
264
266
|
def add_curve_custom(
|
@@ -754,7 +756,11 @@ class BECWaveform(BECPlotBase):
|
|
754
756
|
self.update_dap, MessageEndpoints.dap_response(self.scan_id)
|
755
757
|
)
|
756
758
|
if scan_index is not None:
|
757
|
-
|
759
|
+
try:
|
760
|
+
self.scan_id = self.queue.scan_storage.storage[scan_index].scan_id
|
761
|
+
except IndexError:
|
762
|
+
print(f"Scan index {scan_index} out of range.")
|
763
|
+
return
|
758
764
|
elif scan_id is not None:
|
759
765
|
self.scan_id = scan_id
|
760
766
|
|
@@ -36,7 +36,7 @@ class MotorMapSettings(QWidget):
|
|
36
36
|
precision = WidgetIO.get_value(self.ui.precision)
|
37
37
|
scatter_size = WidgetIO.get_value(self.ui.scatter_size)
|
38
38
|
background_intensity = int(WidgetIO.get_value(self.ui.background_value) * 0.01 * 255)
|
39
|
-
color = self.ui.color.
|
39
|
+
color = self.ui.color.get_color("RGBA")
|
40
40
|
|
41
41
|
if self.target_widget is not None:
|
42
42
|
self.target_widget.set_max_points(max_points)
|
@@ -4,7 +4,7 @@ from qtpy.QtCore import QSize
|
|
4
4
|
from qtpy.QtGui import QAction, QIcon
|
5
5
|
from qtpy.QtWidgets import QHBoxLayout, QLabel, QWidget
|
6
6
|
|
7
|
-
from bec_widgets.widgets.
|
7
|
+
from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
|
8
8
|
from bec_widgets.widgets.toolbar.toolbar import ToolBarAction
|
9
9
|
|
10
10
|
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import sys
|
4
4
|
|
5
|
-
from qtpy import PYSIDE6
|
6
5
|
from qtpy.QtWidgets import QVBoxLayout, QWidget
|
7
6
|
|
8
7
|
from bec_widgets.utils import BECConnector
|
@@ -37,10 +36,6 @@ class BECMotorMapWidget(BECConnector, QWidget):
|
|
37
36
|
client=None,
|
38
37
|
gui_id: str | None = None,
|
39
38
|
) -> None:
|
40
|
-
if not PYSIDE6:
|
41
|
-
raise RuntimeError(
|
42
|
-
"PYSIDE6 is not available in the environment. This widget is compatible only with PySide6."
|
43
|
-
)
|
44
39
|
if config is None:
|
45
40
|
config = MotorMapConfig(widget_class=self.__class__.__name__)
|
46
41
|
else:
|
@@ -216,13 +211,6 @@ class BECMotorMapWidget(BECConnector, QWidget):
|
|
216
211
|
|
217
212
|
|
218
213
|
def main(): # pragma: no cover
|
219
|
-
|
220
|
-
if not PYSIDE6:
|
221
|
-
print(
|
222
|
-
"PYSIDE6 is not available in the environment. UI files with BEC custom widgets are runnable only with PySide6."
|
223
|
-
)
|
224
|
-
return
|
225
|
-
|
226
214
|
from qtpy.QtWidgets import QApplication
|
227
215
|
|
228
216
|
app = QApplication(sys.argv)
|
@@ -12,8 +12,8 @@ from qtpy.QtWidgets import (
|
|
12
12
|
)
|
13
13
|
|
14
14
|
from bec_widgets.utils import BECConnector
|
15
|
-
from bec_widgets.widgets.buttons.stop_button.stop_button import StopButton
|
16
15
|
from bec_widgets.widgets.scan_control.scan_group_box import ScanGroupBox
|
16
|
+
from bec_widgets.widgets.stop_button.stop_button import StopButton
|
17
17
|
|
18
18
|
|
19
19
|
class ScanControl(BECConnector, QWidget):
|
@@ -12,7 +12,7 @@ from qtpy.QtWidgets import (
|
|
12
12
|
)
|
13
13
|
|
14
14
|
from bec_widgets.utils.widget_io import WidgetIO
|
15
|
-
from bec_widgets.widgets.
|
15
|
+
from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
|
16
16
|
|
17
17
|
|
18
18
|
class ScanArgType:
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def main(): # pragma: no cover
|
2
|
+
from qtpy import PYSIDE6
|
3
|
+
|
4
|
+
if not PYSIDE6:
|
5
|
+
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
6
|
+
return
|
7
|
+
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
|
+
|
9
|
+
from bec_widgets.widgets.stop_button.stop_button_plugin import StopButtonPlugin
|
10
|
+
|
11
|
+
QPyDesignerCustomWidgetCollection.addCustomWidget(StopButtonPlugin())
|
12
|
+
|
13
|
+
|
14
|
+
if __name__ == "__main__": # pragma: no cover
|
15
|
+
main()
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from qtpy.QtCore import Slot
|
1
2
|
from qtpy.QtWidgets import QPushButton
|
2
3
|
|
3
4
|
from bec_widgets.utils import BECConnector
|
@@ -12,21 +13,13 @@ class StopButton(BECConnector, QPushButton):
|
|
12
13
|
|
13
14
|
self.get_bec_shortcuts()
|
14
15
|
self.setText("Stop")
|
15
|
-
self.setStyleSheet(
|
16
|
+
self.setStyleSheet(
|
17
|
+
"background-color: #cc181e; color: white; font-weight: bold; font-size: 12px;"
|
18
|
+
)
|
16
19
|
self.clicked.connect(self.stop_scan)
|
17
20
|
|
21
|
+
@Slot()
|
18
22
|
def stop_scan(self):
|
19
23
|
"""Stop the scan."""
|
20
24
|
self.queue.request_scan_abortion()
|
21
25
|
self.queue.request_queue_reset()
|
22
|
-
|
23
|
-
|
24
|
-
if __name__ == "__main__": # pragma: no cover
|
25
|
-
import sys
|
26
|
-
|
27
|
-
from qtpy.QtWidgets import QApplication
|
28
|
-
|
29
|
-
app = QApplication(sys.argv)
|
30
|
-
widget = StopButton()
|
31
|
-
widget.show()
|
32
|
-
sys.exit(app.exec_())
|
@@ -0,0 +1 @@
|
|
1
|
+
{'files': ['stop_button.py']}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (C) 2022 The Qt Company Ltd.
|
2
|
+
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
import os
|
4
|
+
|
5
|
+
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
6
|
+
from qtpy.QtGui import QIcon
|
7
|
+
|
8
|
+
from bec_widgets.widgets.stop_button.stop_button import StopButton
|
9
|
+
|
10
|
+
DOM_XML = """
|
11
|
+
<ui language='c++'>
|
12
|
+
<widget class='StopButton' name='stop_button'>
|
13
|
+
</widget>
|
14
|
+
</ui>
|
15
|
+
"""
|
16
|
+
|
17
|
+
|
18
|
+
class StopButtonPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
19
|
+
def __init__(self):
|
20
|
+
super().__init__()
|
21
|
+
self._form_editor = None
|
22
|
+
|
23
|
+
def createWidget(self, parent):
|
24
|
+
t = StopButton(parent)
|
25
|
+
return t
|
26
|
+
|
27
|
+
def domXml(self):
|
28
|
+
return DOM_XML
|
29
|
+
|
30
|
+
def group(self):
|
31
|
+
return "BEC Buttons"
|
32
|
+
|
33
|
+
def icon(self):
|
34
|
+
current_path = os.path.dirname(__file__)
|
35
|
+
icon_path = os.path.join(current_path, "assets", "stop.png")
|
36
|
+
return QIcon(icon_path)
|
37
|
+
|
38
|
+
def includeFile(self):
|
39
|
+
return "stop_button"
|
40
|
+
|
41
|
+
def initialize(self, form_editor):
|
42
|
+
self._form_editor = form_editor
|
43
|
+
|
44
|
+
def isContainer(self):
|
45
|
+
return False
|
46
|
+
|
47
|
+
def isInitialized(self):
|
48
|
+
return self._form_editor is not None
|
49
|
+
|
50
|
+
def name(self):
|
51
|
+
return "StopButton"
|
52
|
+
|
53
|
+
def toolTip(self):
|
54
|
+
return "A button that stops the current scan."
|
55
|
+
|
56
|
+
def whatsThis(self):
|
57
|
+
return self.toolTip()
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def main(): # pragma: no cover
|
2
|
+
from qtpy import PYSIDE6
|
3
|
+
|
4
|
+
if not PYSIDE6:
|
5
|
+
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
6
|
+
return
|
7
|
+
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
|
+
|
9
|
+
from bec_widgets.widgets.toggle.toggle_switch_plugin import ToggleSwitchPlugin
|
10
|
+
|
11
|
+
QPyDesignerCustomWidgetCollection.addCustomWidget(ToggleSwitchPlugin())
|
12
|
+
|
13
|
+
|
14
|
+
if __name__ == "__main__": # pragma: no cover
|
15
|
+
main()
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
from qtpy.QtCore import Property, QEasingCurve, QPointF, QPropertyAnimation, Qt
|
4
|
+
from qtpy.QtGui import QColor, QPainter
|
5
|
+
from qtpy.QtWidgets import QApplication, QWidget
|
6
|
+
|
7
|
+
|
8
|
+
class ToggleSwitch(QWidget):
|
9
|
+
"""
|
10
|
+
A simple toggle.
|
11
|
+
"""
|
12
|
+
|
13
|
+
def __init__(self, parent=None):
|
14
|
+
super().__init__(parent)
|
15
|
+
self.setFixedSize(40, 21)
|
16
|
+
|
17
|
+
self._thumb_pos = QPointF(3, 2) # Use QPointF for the thumb position
|
18
|
+
self._active_track_color = QColor(33, 150, 243)
|
19
|
+
self._active_thumb_color = QColor(255, 255, 255)
|
20
|
+
self._inactive_track_color = QColor(200, 200, 200)
|
21
|
+
self._inactive_thumb_color = QColor(255, 255, 255)
|
22
|
+
|
23
|
+
self._checked = False
|
24
|
+
self._track_color = self.inactive_track_color
|
25
|
+
self._thumb_color = self.inactive_thumb_color
|
26
|
+
|
27
|
+
self._animation = QPropertyAnimation(self, b"thumb_pos")
|
28
|
+
self._animation.setDuration(200)
|
29
|
+
self._animation.setEasingCurve(QEasingCurve.Type.OutBack)
|
30
|
+
self.setProperty("checked", True)
|
31
|
+
|
32
|
+
@Property(bool)
|
33
|
+
def checked(self):
|
34
|
+
"""
|
35
|
+
The checked state of the toggle switch.
|
36
|
+
"""
|
37
|
+
return self._checked
|
38
|
+
|
39
|
+
@checked.setter
|
40
|
+
def checked(self, state):
|
41
|
+
self._checked = state
|
42
|
+
self.update_colors()
|
43
|
+
self.set_thumb_pos_to_state()
|
44
|
+
|
45
|
+
@Property(QPointF)
|
46
|
+
def thumb_pos(self):
|
47
|
+
return self._thumb_pos
|
48
|
+
|
49
|
+
@thumb_pos.setter
|
50
|
+
def thumb_pos(self, pos):
|
51
|
+
self._thumb_pos = pos
|
52
|
+
self.update()
|
53
|
+
|
54
|
+
@Property(QColor)
|
55
|
+
def active_track_color(self):
|
56
|
+
return self._active_track_color
|
57
|
+
|
58
|
+
@active_track_color.setter
|
59
|
+
def active_track_color(self, color):
|
60
|
+
self._active_track_color = color
|
61
|
+
self.update_colors()
|
62
|
+
self.update()
|
63
|
+
|
64
|
+
@Property(QColor)
|
65
|
+
def active_thumb_color(self):
|
66
|
+
return self._active_thumb_color
|
67
|
+
|
68
|
+
@active_thumb_color.setter
|
69
|
+
def active_thumb_color(self, color):
|
70
|
+
self._active_thumb_color = color
|
71
|
+
self.update_colors()
|
72
|
+
self.update()
|
73
|
+
|
74
|
+
@Property(QColor)
|
75
|
+
def inactive_track_color(self):
|
76
|
+
return self._inactive_track_color
|
77
|
+
|
78
|
+
@inactive_track_color.setter
|
79
|
+
def inactive_track_color(self, color):
|
80
|
+
self._inactive_track_color = color
|
81
|
+
self.update_colors()
|
82
|
+
self.update()
|
83
|
+
|
84
|
+
@Property(QColor)
|
85
|
+
def inactive_thumb_color(self):
|
86
|
+
return self._inactive_thumb_color
|
87
|
+
|
88
|
+
@inactive_thumb_color.setter
|
89
|
+
def inactive_thumb_color(self, color):
|
90
|
+
self._inactive_thumb_color = color
|
91
|
+
self.update_colors()
|
92
|
+
self.update()
|
93
|
+
|
94
|
+
def paintEvent(self, event):
|
95
|
+
painter = QPainter(self)
|
96
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
97
|
+
|
98
|
+
# Draw track
|
99
|
+
painter.setBrush(self._track_color)
|
100
|
+
painter.setPen(Qt.NoPen)
|
101
|
+
painter.drawRoundedRect(
|
102
|
+
0, 0, self.width(), self.height(), self.height() / 2, self.height() / 2
|
103
|
+
)
|
104
|
+
|
105
|
+
# Draw thumb
|
106
|
+
painter.setBrush(self._thumb_color)
|
107
|
+
diameter = int(self.height() * 0.8)
|
108
|
+
painter.drawEllipse(int(self._thumb_pos.x()), int(self._thumb_pos.y()), diameter, diameter)
|
109
|
+
|
110
|
+
def mousePressEvent(self, event):
|
111
|
+
if event.button() == Qt.LeftButton:
|
112
|
+
self._checked = not self._checked
|
113
|
+
self.update_colors()
|
114
|
+
self.animate_thumb()
|
115
|
+
|
116
|
+
def update_colors(self):
|
117
|
+
|
118
|
+
self._thumb_color = self.active_thumb_color if self._checked else self.inactive_thumb_color
|
119
|
+
self._track_color = self.active_track_color if self._checked else self.inactive_track_color
|
120
|
+
|
121
|
+
def get_thumb_pos(self, checked):
|
122
|
+
return QPointF(self.width() - self.height() + 3, 2) if checked else QPointF(3, 2)
|
123
|
+
|
124
|
+
def set_thumb_pos_to_state(self):
|
125
|
+
# this is to avoid that linter complains about the thumb_pos setter
|
126
|
+
self.setProperty("thumb_pos", self.get_thumb_pos(self._checked))
|
127
|
+
self.update_colors()
|
128
|
+
|
129
|
+
def animate_thumb(self):
|
130
|
+
start_pos = self.thumb_pos
|
131
|
+
end_pos = self.get_thumb_pos(self._checked)
|
132
|
+
|
133
|
+
self._animation.stop()
|
134
|
+
self._animation.setStartValue(start_pos)
|
135
|
+
self._animation.setEndValue(end_pos)
|
136
|
+
self._animation.start()
|
137
|
+
|
138
|
+
def sizeHint(self):
|
139
|
+
return self.minimumSizeHint()
|
140
|
+
|
141
|
+
def minimumSizeHint(self):
|
142
|
+
return self.size()
|
143
|
+
|
144
|
+
|
145
|
+
if __name__ == "__main__": # pragma: no cover
|
146
|
+
app = QApplication(sys.argv)
|
147
|
+
window = ToggleSwitch()
|
148
|
+
window.show()
|
149
|
+
sys.exit(app.exec())
|
@@ -0,0 +1 @@
|
|
1
|
+
{'files': ['toggle.py']}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (C) 2022 The Qt Company Ltd.
|
2
|
+
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
|
4
|
+
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
5
|
+
from qtpy.QtGui import QIcon
|
6
|
+
|
7
|
+
from bec_widgets.widgets.toggle.toggle import ToggleSwitch
|
8
|
+
|
9
|
+
DOM_XML = """
|
10
|
+
<ui language='c++'>
|
11
|
+
<widget class='ToggleSwitch' name='toggle_switch'>
|
12
|
+
</widget>
|
13
|
+
</ui>
|
14
|
+
"""
|
15
|
+
|
16
|
+
|
17
|
+
class ToggleSwitchPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
18
|
+
def __init__(self):
|
19
|
+
super().__init__()
|
20
|
+
self._form_editor = None
|
21
|
+
|
22
|
+
def createWidget(self, parent):
|
23
|
+
t = ToggleSwitch(parent)
|
24
|
+
return t
|
25
|
+
|
26
|
+
def domXml(self):
|
27
|
+
return DOM_XML
|
28
|
+
|
29
|
+
def group(self):
|
30
|
+
return ""
|
31
|
+
|
32
|
+
def icon(self):
|
33
|
+
return QIcon()
|
34
|
+
|
35
|
+
def includeFile(self):
|
36
|
+
return "toggle_switch"
|
37
|
+
|
38
|
+
def initialize(self, form_editor):
|
39
|
+
self._form_editor = form_editor
|
40
|
+
|
41
|
+
def isContainer(self):
|
42
|
+
return False
|
43
|
+
|
44
|
+
def isInitialized(self):
|
45
|
+
return self._form_editor is not None
|
46
|
+
|
47
|
+
def name(self):
|
48
|
+
return "ToggleSwitch"
|
49
|
+
|
50
|
+
def toolTip(self):
|
51
|
+
return "ToggleSwitch"
|
52
|
+
|
53
|
+
def whatsThis(self):
|
54
|
+
return self.toolTip()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: bec_widgets
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.82.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
|
@@ -28,9 +28,6 @@ Requires-Dist: pytest-random-order~=1.1; extra == 'dev'
|
|
28
28
|
Requires-Dist: pytest-timeout~=2.2; extra == 'dev'
|
29
29
|
Requires-Dist: pytest-xvfb~=3.0; extra == 'dev'
|
30
30
|
Requires-Dist: pytest~=8.0; extra == 'dev'
|
31
|
-
Provides-Extra: pyqt5
|
32
|
-
Requires-Dist: pyqt5>=5.9; extra == 'pyqt5'
|
33
|
-
Requires-Dist: pyqtwebengine>=5.9; extra == 'pyqt5'
|
34
31
|
Provides-Extra: pyqt6
|
35
32
|
Requires-Dist: pyqt6-webengine>=6.7; extra == 'pyqt6'
|
36
33
|
Requires-Dist: pyqt6>=6.7; extra == 'pyqt6'
|