bec-widgets 0.110.0__py3-none-any.whl → 0.112.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.
@@ -0,0 +1 @@
1
+ {'files': ['console.py']}
@@ -0,0 +1,58 @@
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
+
7
+ import bec_widgets
8
+ from bec_widgets.utils.bec_designer import designer_material_icon
9
+ from bec_widgets.widgets.console.console import BECConsole
10
+
11
+ DOM_XML = """
12
+ <ui language='c++'>
13
+ <widget class='BECConsole' name='bec_console'>
14
+ </widget>
15
+ </ui>
16
+ """
17
+
18
+ MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
+
20
+
21
+ class BECConsolePlugin(QDesignerCustomWidgetInterface): # pragma: no cover
22
+ def __init__(self):
23
+ super().__init__()
24
+ self._form_editor = None
25
+
26
+ def createWidget(self, parent):
27
+ t = BECConsole(parent)
28
+ return t
29
+
30
+ def domXml(self):
31
+ return DOM_XML
32
+
33
+ def group(self):
34
+ return "BEC Console"
35
+
36
+ def icon(self):
37
+ return designer_material_icon(BECConsole.ICON_NAME)
38
+
39
+ def includeFile(self):
40
+ return "bec_console"
41
+
42
+ def initialize(self, form_editor):
43
+ self._form_editor = form_editor
44
+
45
+ def isContainer(self):
46
+ return False
47
+
48
+ def isInitialized(self):
49
+ return self._form_editor is not None
50
+
51
+ def name(self):
52
+ return "BECConsole"
53
+
54
+ def toolTip(self):
55
+ return "A terminal-like vt100 widget."
56
+
57
+ def whatsThis(self):
58
+ 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.console.console_plugin import BECConsolePlugin
10
+
11
+ QPyDesignerCustomWidgetCollection.addCustomWidget(BECConsolePlugin())
12
+
13
+
14
+ if __name__ == "__main__": # pragma: no cover
15
+ main()
@@ -1,67 +1,285 @@
1
- from qtpy.QtCore import Qt, Slot
2
- from qtpy.QtGui import QPainter, QPen
1
+ import numpy as np
2
+ from qtpy.QtCore import Property, QSize, Qt, Slot
3
+ from qtpy.QtGui import QBrush, QColor, QPainter, QPainterPath, QPen
3
4
  from qtpy.QtWidgets import QWidget
4
5
 
6
+ from bec_widgets.utils.bec_widget import BECWidget
7
+ from bec_widgets.utils.colors import get_accent_colors, get_theme_palette
5
8
 
6
- class PositionIndicator(QWidget):
9
+
10
+ class PositionIndicator(BECWidget, QWidget):
11
+ USER_ACCESS = ["set_value", "set_range", "vertical", "indicator_width", "rounded_corners"]
7
12
 
8
13
  ICON_NAME = "horizontal_distribute"
9
14
 
10
- def __init__(self, parent=None):
11
- super().__init__(parent)
12
- self.position = 0.5
15
+ def __init__(self, parent=None, client=None, config=None, gui_id=None):
16
+ super().__init__(client=client, config=config, gui_id=gui_id)
17
+ QWidget.__init__(self, parent=parent)
18
+ self.position = 50
13
19
  self.min_value = 0
14
20
  self.max_value = 100
15
21
  self.scaling_factor = 0.5
16
- self.setMinimumHeight(10)
22
+ self.is_vertical = False
23
+ self._current_indicator_position = 0
24
+ self._draw_position = 0
25
+ self._rounded_corners = 10
26
+ self._indicator_width = 2
27
+ self._indicator_color = get_accent_colors().success
28
+ self._background_color = get_theme_palette().mid().color()
29
+ self._use_color_palette = True
30
+
31
+ def set_range(self, min_value: float, max_value: float):
32
+ """
33
+ Set the range of the position indicator
34
+
35
+ Args:
36
+ min_value(float): Minimum value of the range
37
+ max_value(float): Maximum value of the range
38
+ """
39
+ self.minimum = min_value
40
+ self.maximum = max_value
41
+
42
+ @Property(float)
43
+ def minimum(self):
44
+ """
45
+ Property to get the minimum value of the position indicator
46
+ """
47
+ return self.min_value
17
48
 
18
- def set_range(self, min_value, max_value):
49
+ @minimum.setter
50
+ def minimum(self, min_value: float):
51
+ """
52
+ Setter for the minimum property
53
+
54
+ Args:
55
+ min_value: The minimum value of the position indicator
56
+ """
19
57
  self.min_value = min_value
58
+ self.update()
59
+
60
+ @Property(float)
61
+ def maximum(self):
62
+ """
63
+ Property to get the maximum value of the position indicator
64
+ """
65
+ return self.max_value
66
+
67
+ @maximum.setter
68
+ def maximum(self, max_value: float):
69
+ """
70
+ Setter for the maximum property
71
+
72
+ Args:
73
+ max_value: The maximum value of the position indicator
74
+ """
20
75
  self.max_value = max_value
76
+ self.update()
77
+
78
+ @Property(bool)
79
+ def vertical(self):
80
+ """
81
+ Property to determine the orientation of the position indicator
82
+ """
83
+ return self.is_vertical
84
+
85
+ @vertical.setter
86
+ def vertical(self, is_vertical: bool):
87
+ """
88
+ Setter for the vertical property
89
+
90
+ Args:
91
+ is_vertical: True if the indicator should be vertical, False if horizontal
92
+ """
93
+
94
+ self.is_vertical = is_vertical
95
+ self.update()
96
+
97
+ @Property(float)
98
+ def value(self):
99
+ """
100
+ Property to get the current value of the position indicator
101
+ """
102
+ return self.position
103
+
104
+ @value.setter
105
+ def value(self, position: float):
106
+ """
107
+ Setter for the value property
108
+
109
+ Args:
110
+ position: The new position of the indicator
111
+ """
112
+ self.set_value(position)
113
+
114
+ @Property(int)
115
+ def indicator_width(self):
116
+ """
117
+ Property to get the width of the indicator
118
+ """
119
+ return self._indicator_width
120
+
121
+ @indicator_width.setter
122
+ def indicator_width(self, width: int):
123
+ """
124
+ Setter for the indicator width property
125
+
126
+ Args:
127
+ width: The new width of the indicator
128
+ """
129
+ self._indicator_width = width
130
+ self.update()
131
+
132
+ @Property(int)
133
+ def rounded_corners(self):
134
+ """
135
+ Property to get the rounded corners of the position indicator
136
+ """
137
+ return self._rounded_corners
138
+
139
+ @rounded_corners.setter
140
+ def rounded_corners(self, value: int):
141
+ """
142
+ Setter for the rounded corners property
143
+
144
+ Args:
145
+ value: The new value for the rounded corners
146
+ """
147
+ self._rounded_corners = value
148
+ self.update()
21
149
 
150
+ @Property(QColor)
151
+ def indicator_color(self):
152
+ """
153
+ Property to get the color of the indicator
154
+ """
155
+ return self._indicator_color
156
+
157
+ @indicator_color.setter
158
+ def indicator_color(self, color: QColor):
159
+ """
160
+ Setter for the indicator color property
161
+
162
+ Args:
163
+ color: The new color for the indicator
164
+ """
165
+ self._indicator_color = color
166
+ self.update()
167
+
168
+ @Property(QColor)
169
+ def background_color(self):
170
+ """
171
+ Property to get the background color of the position indicator
172
+ """
173
+ return self._background_color
174
+
175
+ @background_color.setter
176
+ def background_color(self, color: QColor):
177
+ """
178
+ Setter for the background color property
179
+
180
+ Args:
181
+ color: The new background color
182
+ """
183
+ self._background_color = color
184
+ self.update()
185
+
186
+ @Property(bool)
187
+ def use_color_palette(self):
188
+ """
189
+ Property to determine if the indicator should use the color palette or the custom color.
190
+ """
191
+ return self._use_color_palette
192
+
193
+ @use_color_palette.setter
194
+ def use_color_palette(self, use_palette: bool):
195
+ """
196
+ Setter for the use color palette property
197
+
198
+ Args:
199
+ use_palette: True if the indicator should use the color palette, False if custom color
200
+ """
201
+ self._use_color_palette = use_palette
202
+ self.update()
203
+
204
+ # @Property(float)
205
+ @Slot(int)
22
206
  @Slot(float)
23
- def on_position_update(self, position: float):
207
+ def set_value(self, position: float):
24
208
  self.position = position
25
209
  self.update()
26
210
 
211
+ def _get_indicator_color(self):
212
+ if self._use_color_palette:
213
+ return get_accent_colors().success
214
+ return self._indicator_color
215
+
216
+ def _get_background_brush(self):
217
+ if self._use_color_palette:
218
+ return get_theme_palette().mid()
219
+ return QBrush(self._background_color)
220
+
27
221
  def paintEvent(self, event):
28
222
  painter = QPainter(self)
29
- painter.setRenderHint(QPainter.Antialiasing)
30
-
31
223
  width = self.width()
32
224
  height = self.height()
33
225
 
34
- # Draw horizontal line
35
- painter.setPen(Qt.black)
36
- painter.drawLine(0, height // 2, width, height // 2)
37
-
38
- # Draw shorter vertical line at the current position
39
- x_pos = int(self.position * width)
40
- painter.setPen(QPen(Qt.red, 2))
41
- short_line_height = int(height * self.scaling_factor)
42
- painter.drawLine(
43
- x_pos,
44
- (height // 2) - (short_line_height // 2),
45
- x_pos,
46
- (height // 2) + (short_line_height // 2),
226
+ # Set up the brush for the background
227
+ painter.setBrush(self._get_background_brush())
228
+
229
+ # Create a QPainterPath with a rounded rectangle for clipping
230
+ path = QPainterPath()
231
+ path.addRoundedRect(0, 0, width, height, self._rounded_corners, self._rounded_corners)
232
+
233
+ # Set clipping to the rounded rectangle
234
+ painter.setClipPath(path)
235
+
236
+ # Draw the rounded rectangle background first
237
+ painter.setPen(Qt.NoPen)
238
+ painter.drawRoundedRect(0, 0, width, height, self._rounded_corners, self._rounded_corners)
239
+
240
+ # get the position scaled to the defined min and max values
241
+ self._current_indicator_position = position = np.interp(
242
+ self.position, [self.min_value, self.max_value], [0, 100]
47
243
  )
48
244
 
49
- # Draw thicker vertical lines at the ends
50
- end_line_pen = QPen(Qt.blue, 5)
51
- painter.setPen(end_line_pen)
52
- painter.drawLine(0, 0, 0, height)
53
- painter.drawLine(width - 1, 0, width - 1, height)
245
+ if self.is_vertical:
246
+ # If vertical, rotate the coordinate system by -90 degrees
247
+ painter.translate(width // 2, height // 2) # Move origin to center
248
+ painter.rotate(-90) # Rotate by -90 degrees for vertical drawing
249
+ painter.translate(-height // 2, -width // 2) # Restore the origin for drawing
250
+
251
+ # Switch width and height for the vertical orientation
252
+ width, height = height, width
54
253
 
254
+ # Draw the moving vertical indicator, respecting the clip path
255
+ self._draw_position = x_pos = round(
256
+ position * width / 100
257
+ ) # Position for the vertical line
55
258
 
56
- if __name__ == "__main__":
259
+ indicator_pen = QPen(self._get_indicator_color(), self._indicator_width)
260
+ painter.setPen(indicator_pen)
261
+ painter.drawLine(x_pos, 0, x_pos, height)
262
+
263
+ painter.end()
264
+
265
+ def minimumSizeHint(self):
266
+ # Set the smallest possible size
267
+ return QSize(10, 10)
268
+
269
+
270
+ if __name__ == "__main__": # pragma: no cover
271
+ from bec_qthemes import setup_theme
57
272
  from qtpy.QtWidgets import QApplication, QSlider, QVBoxLayout
58
273
 
59
274
  app = QApplication([])
60
-
275
+ setup_theme("dark")
276
+ # Create position indicator and slider
61
277
  position_indicator = PositionIndicator()
278
+ # position_indicator.set_range(0, 1)
62
279
  slider = QSlider(Qt.Horizontal)
63
- slider.valueChanged.connect(lambda value: position_indicator.on_position_update(value / 100))
64
-
280
+ slider.valueChanged.connect(lambda value: position_indicator.set_value(value))
281
+ position_indicator.is_vertical = False
282
+ # position_indicator.set_value(100)
65
283
  layout = QVBoxLayout()
66
284
  layout.addWidget(position_indicator)
67
285
  layout.addWidget(slider)
@@ -16,7 +16,7 @@ from qtpy.QtWidgets import QDialog, QDoubleSpinBox, QPushButton, QVBoxLayout, QW
16
16
 
17
17
  from bec_widgets.utils import UILoader
18
18
  from bec_widgets.utils.bec_widget import BECWidget
19
- from bec_widgets.utils.colors import set_theme
19
+ from bec_widgets.utils.colors import get_accent_colors, set_theme
20
20
  from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
21
21
 
22
22
  logger = bec_logger.logger
@@ -73,6 +73,10 @@ class PositionerBox(BECWidget, QWidget):
73
73
 
74
74
  self.ui.step_size.setStepType(QDoubleSpinBox.AdaptiveDecimalStepType)
75
75
  self.ui.stop.clicked.connect(self.on_stop)
76
+ self.ui.stop.setToolTip("Stop")
77
+ self.ui.stop.setStyleSheet(
78
+ f"QPushButton {{background-color: {get_accent_colors().emergency.name()}; color: white;}}"
79
+ )
76
80
  self.ui.tweak_right.clicked.connect(self.on_tweak_right)
77
81
  self.ui.tweak_right.setToolTip("Tweak right")
78
82
  self.ui.tweak_left.clicked.connect(self.on_tweak_left)
@@ -249,7 +253,7 @@ class PositionerBox(BECWidget, QWidget):
249
253
  self.update_limits(limits)
250
254
  if limits is not None and readback_val is not None and limits[0] != limits[1]:
251
255
  pos = (readback_val - limits[0]) / (limits[1] - limits[0])
252
- self.ui.position_indicator.on_position_update(pos)
256
+ self.ui.position_indicator.set_value(pos)
253
257
 
254
258
  def update_limits(self, limits: tuple):
255
259
  """Update limits
@@ -170,7 +170,20 @@
170
170
  </layout>
171
171
  </item>
172
172
  <item>
173
- <widget class="PositionIndicator" name="position_indicator"/>
173
+ <widget class="PositionIndicator" name="position_indicator">
174
+ <property name="maximum" stdset="0">
175
+ <double>1.000000000000000</double>
176
+ </property>
177
+ <property name="value" stdset="0">
178
+ <double>0.500000000000000</double>
179
+ </property>
180
+ <property name="indicator_width" stdset="0">
181
+ <number>4</number>
182
+ </property>
183
+ <property name="rounded_corners" stdset="0">
184
+ <number>4</number>
185
+ </property>
186
+ </widget>
174
187
  </item>
175
188
  <item>
176
189
  <widget class="QLabel" name="readback">
@@ -24,11 +24,9 @@ class PositionerControlLine(PositionerBox):
24
24
  if __name__ == "__main__": # pragma: no cover
25
25
  import sys
26
26
 
27
- import qdarktheme
28
27
  from qtpy.QtWidgets import QApplication
29
28
 
30
29
  app = QApplication(sys.argv)
31
- qdarktheme.setup_theme("dark")
32
30
  widget = PositionerControlLine(device="samy")
33
31
 
34
32
  widget.show()
@@ -6,7 +6,7 @@
6
6
  <rect>
7
7
  <x>0</x>
8
8
  <y>0</y>
9
- <width>785</width>
9
+ <width>612</width>
10
10
  <height>91</height>
11
11
  </rect>
12
12
  </property>
@@ -59,16 +59,6 @@
59
59
  </item>
60
60
  <item>
61
61
  <layout class="QHBoxLayout" name="horizontalLayout_2">
62
- <item>
63
- <widget class="PositionIndicator" name="position_indicator">
64
- <property name="minimumSize">
65
- <size>
66
- <width>80</width>
67
- <height>10</height>
68
- </size>
69
- </property>
70
- </widget>
71
- </item>
72
62
  <item>
73
63
  <widget class="SpinnerWidget" name="spinner_widget">
74
64
  <property name="minimumSize">
@@ -139,14 +129,14 @@
139
129
  <widget class="QToolButton" name="tweak_left">
140
130
  <property name="minimumSize">
141
131
  <size>
142
- <width>30</width>
143
- <height>30</height>
132
+ <width>25</width>
133
+ <height>25</height>
144
134
  </size>
145
135
  </property>
146
136
  <property name="maximumSize">
147
137
  <size>
148
- <width>30</width>
149
- <height>30</height>
138
+ <width>25</width>
139
+ <height>25</height>
150
140
  </size>
151
141
  </property>
152
142
  <property name="text">
@@ -154,8 +144,8 @@
154
144
  </property>
155
145
  <property name="iconSize">
156
146
  <size>
157
- <width>30</width>
158
- <height>30</height>
147
+ <width>25</width>
148
+ <height>25</height>
159
149
  </size>
160
150
  </property>
161
151
  <property name="arrowType">
@@ -170,14 +160,14 @@
170
160
  <widget class="QToolButton" name="tweak_right">
171
161
  <property name="minimumSize">
172
162
  <size>
173
- <width>30</width>
174
- <height>30</height>
163
+ <width>25</width>
164
+ <height>25</height>
175
165
  </size>
176
166
  </property>
177
167
  <property name="maximumSize">
178
168
  <size>
179
- <width>30</width>
180
- <height>30</height>
169
+ <width>25</width>
170
+ <height>25</height>
181
171
  </size>
182
172
  </property>
183
173
  <property name="text">
@@ -185,8 +175,8 @@
185
175
  </property>
186
176
  <property name="iconSize">
187
177
  <size>
188
- <width>30</width>
189
- <height>30</height>
178
+ <width>25</width>
179
+ <height>25</height>
190
180
  </size>
191
181
  </property>
192
182
  <property name="arrowType">
@@ -194,6 +184,34 @@
194
184
  </property>
195
185
  </widget>
196
186
  </item>
187
+ <item>
188
+ <widget class="PositionIndicator" name="position_indicator">
189
+ <property name="minimumSize">
190
+ <size>
191
+ <width>15</width>
192
+ <height>10</height>
193
+ </size>
194
+ </property>
195
+ <property name="maximumSize">
196
+ <size>
197
+ <width>15</width>
198
+ <height>16777215</height>
199
+ </size>
200
+ </property>
201
+ <property name="maximum" stdset="0">
202
+ <double>1.000000000000000</double>
203
+ </property>
204
+ <property name="vertical" stdset="0">
205
+ <bool>true</bool>
206
+ </property>
207
+ <property name="value" stdset="0">
208
+ <double>0.500000000000000</double>
209
+ </property>
210
+ <property name="rounded_corners" stdset="0">
211
+ <number>2</number>
212
+ </property>
213
+ </widget>
214
+ </item>
197
215
  </layout>
198
216
  </widget>
199
217
  </item>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.110.0
3
+ Version: 0.112.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