bec-widgets 0.87.1__py3-none-any.whl → 0.88.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.
Files changed (59) hide show
  1. CHANGELOG.md +58 -62
  2. PKG-INFO +1 -1
  3. bec_widgets/assets/designer_icons/BECWaveformWidget.png +0 -0
  4. bec_widgets/assets/designer_icons/colormap_selector.png +0 -0
  5. bec_widgets/assets/toolbar_icons/add.svg +3 -0
  6. bec_widgets/assets/toolbar_icons/auto_range.svg +3 -0
  7. bec_widgets/assets/toolbar_icons/drag_pan_mode.svg +3 -0
  8. bec_widgets/assets/toolbar_icons/export.svg +9 -0
  9. bec_widgets/assets/toolbar_icons/fitting_parameters.svg +3 -0
  10. bec_widgets/assets/toolbar_icons/import.svg +9 -0
  11. bec_widgets/assets/toolbar_icons/line_axis.svg +3 -0
  12. bec_widgets/assets/toolbar_icons/photo_library.svg +3 -0
  13. bec_widgets/assets/toolbar_icons/rectangle_mode.svg +3 -0
  14. bec_widgets/assets/toolbar_icons/remove.svg +5 -0
  15. bec_widgets/assets/toolbar_icons/save.svg +3 -0
  16. bec_widgets/assets/toolbar_icons/settings.svg +4 -0
  17. bec_widgets/cli/client.py +307 -5
  18. bec_widgets/cli/server.py +2 -1
  19. bec_widgets/examples/jupyter_console/jupyter_console_window.py +12 -5
  20. bec_widgets/examples/plugin_example_pyside/tictactoe.py +1 -0
  21. bec_widgets/widgets/{color_map_selector/color_map_selector.py → colormap_selector/colormap_selector.py} +3 -1
  22. bec_widgets/widgets/colormap_selector/colormap_selector.pyproject +1 -0
  23. bec_widgets/widgets/{color_map_selector/color_map_selector_plugin.py → colormap_selector/colormap_selector_plugin.py} +8 -6
  24. bec_widgets/widgets/{color_map_selector/register_color_map_selector.py → colormap_selector/register_colormap_selector.py} +1 -1
  25. bec_widgets/widgets/figure/figure.py +12 -0
  26. bec_widgets/widgets/figure/plots/axis_settings.py +38 -11
  27. bec_widgets/widgets/figure/plots/image/image.py +1 -0
  28. bec_widgets/widgets/figure/plots/motor_map/motor_map.py +1 -0
  29. bec_widgets/widgets/figure/plots/plot_base.py +7 -3
  30. bec_widgets/widgets/figure/plots/waveform/waveform.py +48 -50
  31. bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +9 -0
  32. bec_widgets/widgets/motor_map/bec_motor_map_widget_plugin.py +1 -1
  33. bec_widgets/widgets/motor_map/motor_map_widget.py +7 -0
  34. bec_widgets/widgets/waveform/__init__.py +0 -0
  35. bec_widgets/widgets/waveform/bec_waveform_widget.pyproject +1 -0
  36. bec_widgets/widgets/waveform/bec_waveform_widget_plugin.py +59 -0
  37. bec_widgets/widgets/waveform/register_bec_waveform_widget.py +15 -0
  38. bec_widgets/widgets/waveform/waveform_toolbar/__init__.py +0 -0
  39. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/__init__.py +0 -0
  40. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py +341 -0
  41. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui +358 -0
  42. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/__init__.py +0 -0
  43. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary.ui +127 -0
  44. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary_dialog.py +69 -0
  45. bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py +117 -0
  46. bec_widgets/widgets/waveform/waveform_widget.py +571 -0
  47. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/METADATA +1 -1
  48. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/RECORD +57 -30
  49. pyproject.toml +1 -1
  50. tests/unit_tests/test_color_map_selector.py +1 -1
  51. tests/unit_tests/test_waveform_widget.py +264 -0
  52. bec_widgets/widgets/color_map_selector/assets/color_map_selector_icon.png +0 -0
  53. bec_widgets/widgets/color_map_selector/color_map_selector.pyproject +0 -1
  54. /bec_widgets/assets/{bec_widgets_icon.png → app_icons/bec_widgets_icon.png} +0 -0
  55. /bec_widgets/assets/{terminal_icon.png → app_icons/terminal_icon.png} +0 -0
  56. /bec_widgets/widgets/{color_map_selector → colormap_selector}/__init__.py +0 -0
  57. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/WHEEL +0 -0
  58. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/entry_points.txt +0 -0
  59. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,341 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Literal
5
+
6
+ from pydantic import BaseModel
7
+ from qtpy.QtCore import QObject, QSize, Slot
8
+ from qtpy.QtGui import QIcon
9
+ from qtpy.QtWidgets import QComboBox, QLineEdit, QPushButton, QSpinBox, QTableWidget, QVBoxLayout
10
+
11
+ import bec_widgets
12
+ from bec_widgets.qt_utils.error_popups import WarningPopupUtility
13
+ from bec_widgets.qt_utils.settings_dialog import SettingWidget
14
+ from bec_widgets.utils import Colors, UILoader
15
+ from bec_widgets.widgets.color_button.color_button import ColorButton
16
+ from bec_widgets.widgets.device_line_edit.device_line_edit import DeviceLineEdit
17
+
18
+ MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
+
20
+
21
+ class CurveSettings(SettingWidget):
22
+ def __init__(self, parent=None, *args, **kwargs):
23
+ super().__init__(parent, *args, **kwargs)
24
+ current_path = os.path.dirname(__file__)
25
+
26
+ self.ui = UILoader(self).loader(os.path.join(current_path, "curve_dialog.ui"))
27
+ self._setup_icons()
28
+
29
+ self.warning_util = WarningPopupUtility(self)
30
+
31
+ self.layout = QVBoxLayout(self)
32
+ self.layout.addWidget(self.ui)
33
+
34
+ self.ui.add_curve.clicked.connect(self.add_curve)
35
+ self.ui.add_dap.clicked.connect(self.add_dap)
36
+ self.ui.x_mode.currentIndexChanged.connect(self.set_x_mode)
37
+ self.ui.normalize_colors_scan.clicked.connect(lambda: self.change_colormap("scan"))
38
+ self.ui.normalize_colors_dap.clicked.connect(lambda: self.change_colormap("dap"))
39
+
40
+ def _setup_icons(self):
41
+ add_icon = QIcon()
42
+ add_icon.addFile(
43
+ os.path.join(MODULE_PATH, "assets", "toolbar_icons", "add.svg"), size=QSize(20, 20)
44
+ )
45
+ self.ui.add_dap.setIcon(add_icon)
46
+ self.ui.add_dap.setToolTip("Add DAP Curve")
47
+ self.ui.add_curve.setIcon(add_icon)
48
+ self.ui.add_curve.setToolTip("Add Scan Curve")
49
+
50
+ @Slot(dict)
51
+ def display_current_settings(self, config: dict | BaseModel):
52
+
53
+ # What elements should be enabled
54
+ x_name = self.target_widget.waveform._x_axis_mode["name"]
55
+ x_entry = self.target_widget.waveform._x_axis_mode["entry"]
56
+ self._enable_ui_elements(x_name, x_entry)
57
+ cm = self.target_widget.config.color_palette
58
+ self.ui.color_map_selector_scan.combo.setCurrentText(cm)
59
+
60
+ # Scan Curve Table
61
+ for label, curve in config["scan_segment"].items():
62
+ row_count = self.ui.scan_table.rowCount()
63
+ self.ui.scan_table.insertRow(row_count)
64
+ DialogRow(
65
+ parent=self,
66
+ table_widget=self.ui.scan_table,
67
+ client=self.target_widget.client,
68
+ row=row_count,
69
+ config=curve.config,
70
+ ).add_scan_row()
71
+
72
+ # Add DAP Curves
73
+ for label, curve in config["DAP"].items():
74
+ row_count = self.ui.dap_table.rowCount()
75
+ self.ui.dap_table.insertRow(row_count)
76
+ DialogRow(
77
+ parent=self,
78
+ table_widget=self.ui.dap_table,
79
+ client=self.target_widget.client,
80
+ row=row_count,
81
+ config=curve.config,
82
+ ).add_dap_row()
83
+
84
+ def _enable_ui_elements(self, name, entry):
85
+ if name is None:
86
+ name = "best_effort"
87
+ if name in ["index", "timestamp", "best_effort"]:
88
+ self.ui.x_mode.setCurrentText(name)
89
+ self.set_x_mode()
90
+ else:
91
+ self.ui.x_mode.setCurrentText("device")
92
+ self.set_x_mode()
93
+ self.ui.x_name.setText(name)
94
+ self.ui.x_entry.setText(entry)
95
+
96
+ @Slot()
97
+ def set_x_mode(self):
98
+ x_mode = self.ui.x_mode.currentText()
99
+ if x_mode in ["index", "timestamp", "best_effort"]:
100
+ self.ui.x_name.setEnabled(False)
101
+ self.ui.x_entry.setEnabled(False)
102
+ self.ui.dap_table.setEnabled(False)
103
+ self.ui.add_dap.setEnabled(False)
104
+ if self.ui.dap_table.rowCount() > 0:
105
+ self.warning_util.show_warning(
106
+ title="DAP Warning",
107
+ message="DAP is not supported without specific x-axis device. All current DAP curves will be removed.",
108
+ detailed_text=f"Affected curves: {[self.ui.dap_table.cellWidget(row, 0).text() for row in range(self.ui.dap_table.rowCount())]}",
109
+ )
110
+ else:
111
+ self.ui.x_name.setEnabled(True)
112
+ self.ui.x_entry.setEnabled(True)
113
+ self.ui.dap_table.setEnabled(True)
114
+ self.ui.add_dap.setEnabled(True)
115
+
116
+ @Slot()
117
+ def change_colormap(self, target: Literal["scan", "dap"]):
118
+ if target == "scan":
119
+ cm = self.ui.color_map_selector_scan.combo.currentText()
120
+ table = self.ui.scan_table
121
+ if target == "dap":
122
+ cm = self.ui.color_map_selector_dap.combo.currentText()
123
+ table = self.ui.dap_table
124
+ rows = table.rowCount()
125
+ colors = Colors.golden_angle_color(colormap=cm, num=rows + 1, format="HEX")
126
+ color_button_col = 2 if target == "scan" else 3
127
+ for row, color in zip(range(rows), colors):
128
+ table.cellWidget(row, color_button_col).setColor(color)
129
+
130
+ @Slot()
131
+ def accept_changes(self):
132
+ self.accept_curve_changes()
133
+
134
+ def accept_curve_changes(self):
135
+ old_curves_scans = list(self.target_widget.waveform._curves_data["scan_segment"].values())
136
+ old_curves_dap = list(self.target_widget.waveform._curves_data["DAP"].values())
137
+ for curve in old_curves_scans:
138
+ curve.remove()
139
+ for curve in old_curves_dap:
140
+ curve.remove()
141
+ self.get_curve_params()
142
+
143
+ def get_curve_params(self):
144
+ x_mode = self.ui.x_mode.currentText()
145
+
146
+ if x_mode in ["index", "timestamp", "best_effort"]:
147
+ x_name = x_mode
148
+ x_entry = x_mode
149
+ else:
150
+ x_name = self.ui.x_name.text()
151
+ x_entry = self.ui.x_entry.text()
152
+
153
+ self.target_widget.set_x(x_name=x_name, x_entry=x_entry)
154
+
155
+ for row in range(self.ui.scan_table.rowCount()):
156
+ y_name = self.ui.scan_table.cellWidget(row, 0).text()
157
+ y_entry = self.ui.scan_table.cellWidget(row, 1).text()
158
+ color = self.ui.scan_table.cellWidget(row, 2).get_color()
159
+ style = self.ui.scan_table.cellWidget(row, 3).currentText()
160
+ width = self.ui.scan_table.cellWidget(row, 4).value()
161
+ symbol_size = self.ui.scan_table.cellWidget(row, 5).value()
162
+ self.target_widget.plot(
163
+ y_name=y_name,
164
+ y_entry=y_entry,
165
+ color=color,
166
+ pen_style=style,
167
+ pen_width=width,
168
+ symbol_size=symbol_size,
169
+ )
170
+
171
+ if x_mode not in ["index", "timestamp", "best_effort"]:
172
+
173
+ for row in range(self.ui.dap_table.rowCount()):
174
+ y_name = self.ui.dap_table.cellWidget(row, 0).text()
175
+ y_entry = self.ui.dap_table.cellWidget(row, 1).text()
176
+ dap = self.ui.dap_table.cellWidget(row, 2).currentText()
177
+ color = self.ui.dap_table.cellWidget(row, 3).get_color()
178
+ style = self.ui.dap_table.cellWidget(row, 4).currentText()
179
+ width = self.ui.dap_table.cellWidget(row, 5).value()
180
+ symbol_size = self.ui.dap_table.cellWidget(row, 6).value()
181
+
182
+ self.target_widget.add_dap(
183
+ x_name=x_name,
184
+ x_entry=x_entry,
185
+ y_name=y_name,
186
+ y_entry=y_entry,
187
+ dap=dap,
188
+ color=color,
189
+ pen_style=style,
190
+ pen_width=width,
191
+ symbol_size=symbol_size,
192
+ )
193
+ self.target_widget.scan_history(-1)
194
+
195
+ def add_curve(self):
196
+ row_count = self.ui.scan_table.rowCount()
197
+ self.ui.scan_table.insertRow(row_count)
198
+ DialogRow(
199
+ parent=self,
200
+ table_widget=self.ui.scan_table,
201
+ client=self.target_widget.client,
202
+ row=row_count,
203
+ config=None,
204
+ ).add_scan_row()
205
+
206
+ def add_dap(self):
207
+ row_count = self.ui.dap_table.rowCount()
208
+ self.ui.dap_table.insertRow(row_count)
209
+ DialogRow(
210
+ parent=self,
211
+ table_widget=self.ui.dap_table,
212
+ client=self.target_widget.client,
213
+ row=row_count,
214
+ config=None,
215
+ ).add_dap_row()
216
+
217
+
218
+ class DialogRow(QObject):
219
+ def __init__(
220
+ self,
221
+ parent=None,
222
+ table_widget: QTableWidget = None,
223
+ row: int = None,
224
+ config: dict = None,
225
+ client=None,
226
+ ):
227
+
228
+ super().__init__(parent=parent)
229
+ self.client = client
230
+
231
+ self.table_widget = table_widget
232
+ self.row = row
233
+ self.config = config
234
+ self.init_default_widgets()
235
+
236
+ def init_default_widgets(self):
237
+
238
+ # Remove Button
239
+ self.remove_button = RemoveButton()
240
+
241
+ # Name and Entry
242
+ self.device_line_edit = DeviceLineEdit()
243
+ self.entry_line_edit = QLineEdit()
244
+
245
+ self.dap_combo = QComboBox()
246
+ self.populate_dap_combobox()
247
+
248
+ # Styling
249
+ self.color_button = ColorButton()
250
+ self.style_combo = StyleComboBox()
251
+ self.width = QSpinBox()
252
+ self.width.setMinimum(1)
253
+ self.width.setMaximum(20)
254
+ self.width.setValue(2)
255
+
256
+ self.symbol_size = QSpinBox()
257
+ self.symbol_size.setMinimum(1)
258
+ self.symbol_size.setMaximum(20)
259
+ self.symbol_size.setValue(5)
260
+
261
+ self.remove_button.clicked.connect(
262
+ lambda: self.remove_row()
263
+ ) # From some reason do not work without lambda
264
+
265
+ def populate_dap_combobox(self):
266
+ available_models = [
267
+ attr
268
+ for attr in dir(self.client.dap)
269
+ if not attr.startswith("__")
270
+ and not callable(getattr(self.client.dap, attr))
271
+ and not attr.startswith("_")
272
+ ]
273
+ self.dap_combo.addItems(available_models)
274
+
275
+ def add_scan_row(self):
276
+ if self.config is not None:
277
+ self.device_line_edit.setText(self.config.signals.y.name)
278
+ self.entry_line_edit.setText(self.config.signals.y.entry)
279
+ self.color_button.setColor(self.config.color)
280
+ self.style_combo.setCurrentText(self.config.pen_style)
281
+ self.width.setValue(self.config.pen_width)
282
+ self.symbol_size.setValue(self.config.symbol_size)
283
+ else:
284
+ default_color = Colors.golden_angle_color(
285
+ colormap="magma", num=self.row + 1, format="HEX"
286
+ )[-1]
287
+ self.color_button.setColor(default_color)
288
+
289
+ self.table_widget.setCellWidget(self.row, 0, self.device_line_edit)
290
+ self.table_widget.setCellWidget(self.row, 1, self.entry_line_edit)
291
+ self.table_widget.setCellWidget(self.row, 2, self.color_button)
292
+ self.table_widget.setCellWidget(self.row, 3, self.style_combo)
293
+ self.table_widget.setCellWidget(self.row, 4, self.width)
294
+ self.table_widget.setCellWidget(self.row, 5, self.symbol_size)
295
+ self.table_widget.setCellWidget(self.row, 6, self.remove_button)
296
+
297
+ def add_dap_row(self):
298
+ if self.config is not None:
299
+ self.device_line_edit.setText(self.config.signals.y.name)
300
+ self.entry_line_edit.setText(self.config.signals.y.entry)
301
+ self.dap_combo.setCurrentText(self.config.signals.dap)
302
+ self.color_button.setColor(self.config.color)
303
+ self.style_combo.setCurrentText(self.config.pen_style)
304
+ self.width.setValue(self.config.pen_width)
305
+ self.symbol_size.setValue(self.config.symbol_size)
306
+ else:
307
+ default_color = Colors.golden_angle_color(
308
+ colormap="magma", num=self.row + 1, format="HEX"
309
+ )[-1]
310
+ self.color_button.setColor(default_color)
311
+
312
+ self.table_widget.setCellWidget(self.row, 0, self.device_line_edit)
313
+ self.table_widget.setCellWidget(self.row, 1, self.entry_line_edit)
314
+ self.table_widget.setCellWidget(self.row, 2, self.dap_combo)
315
+ self.table_widget.setCellWidget(self.row, 3, self.color_button)
316
+ self.table_widget.setCellWidget(self.row, 4, self.style_combo)
317
+ self.table_widget.setCellWidget(self.row, 5, self.width)
318
+ self.table_widget.setCellWidget(self.row, 6, self.symbol_size)
319
+ self.table_widget.setCellWidget(self.row, 7, self.remove_button)
320
+
321
+ @Slot()
322
+ def remove_row(self):
323
+ row = self.table_widget.indexAt(self.remove_button.pos()).row()
324
+ self.cleanup()
325
+ self.table_widget.removeRow(row)
326
+
327
+ def cleanup(self):
328
+ self.device_line_edit.cleanup()
329
+
330
+
331
+ class StyleComboBox(QComboBox):
332
+ def __init__(self, parent=None):
333
+ super().__init__(parent)
334
+ self.addItems(["solid", "dash", "dot", "dashdot"])
335
+
336
+
337
+ class RemoveButton(QPushButton):
338
+ def __init__(self, parent=None):
339
+ super().__init__(parent)
340
+ icon_path = os.path.join(MODULE_PATH, "assets", "toolbar_icons", "remove.svg")
341
+ self.setIcon(QIcon(icon_path))
@@ -0,0 +1,358 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>720</width>
10
+ <height>806</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QVBoxLayout" name="verticalLayout_2">
17
+ <property name="leftMargin">
18
+ <number>2</number>
19
+ </property>
20
+ <property name="topMargin">
21
+ <number>2</number>
22
+ </property>
23
+ <property name="rightMargin">
24
+ <number>2</number>
25
+ </property>
26
+ <property name="bottomMargin">
27
+ <number>2</number>
28
+ </property>
29
+ <item>
30
+ <widget class="QGroupBox" name="x_group_box">
31
+ <property name="title">
32
+ <string>X Axis</string>
33
+ </property>
34
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,3,1,3">
35
+ <item>
36
+ <widget class="QLabel" name="x_mode_label">
37
+ <property name="text">
38
+ <string>X Axis Mode</string>
39
+ </property>
40
+ </widget>
41
+ </item>
42
+ <item>
43
+ <widget class="QComboBox" name="x_mode">
44
+ <property name="minimumSize">
45
+ <size>
46
+ <width>150</width>
47
+ <height>26</height>
48
+ </size>
49
+ </property>
50
+ <item>
51
+ <property name="text">
52
+ <string>best_effort</string>
53
+ </property>
54
+ </item>
55
+ <item>
56
+ <property name="text">
57
+ <string>device</string>
58
+ </property>
59
+ </item>
60
+ <item>
61
+ <property name="text">
62
+ <string>index</string>
63
+ </property>
64
+ </item>
65
+ <item>
66
+ <property name="text">
67
+ <string>timestamp</string>
68
+ </property>
69
+ </item>
70
+ </widget>
71
+ </item>
72
+ <item>
73
+ <spacer name="horizontalSpacer_3">
74
+ <property name="orientation">
75
+ <enum>Qt::Orientation::Horizontal</enum>
76
+ </property>
77
+ <property name="sizeHint" stdset="0">
78
+ <size>
79
+ <width>40</width>
80
+ <height>20</height>
81
+ </size>
82
+ </property>
83
+ </spacer>
84
+ </item>
85
+ <item>
86
+ <spacer name="horizontalSpacer_4">
87
+ <property name="orientation">
88
+ <enum>Qt::Orientation::Horizontal</enum>
89
+ </property>
90
+ <property name="sizeHint" stdset="0">
91
+ <size>
92
+ <width>40</width>
93
+ <height>20</height>
94
+ </size>
95
+ </property>
96
+ </spacer>
97
+ </item>
98
+ <item>
99
+ <widget class="QLabel" name="x_name_label">
100
+ <property name="text">
101
+ <string>Name</string>
102
+ </property>
103
+ </widget>
104
+ </item>
105
+ <item>
106
+ <widget class="DeviceLineEdit" name="x_name"/>
107
+ </item>
108
+ <item>
109
+ <widget class="QLabel" name="x_entry_label">
110
+ <property name="text">
111
+ <string>Entry</string>
112
+ </property>
113
+ </widget>
114
+ </item>
115
+ <item>
116
+ <widget class="QLineEdit" name="x_entry"/>
117
+ </item>
118
+ </layout>
119
+ </widget>
120
+ </item>
121
+ <item>
122
+ <widget class="QGroupBox" name="y_group_box">
123
+ <property name="title">
124
+ <string>Y Axis</string>
125
+ </property>
126
+ <layout class="QVBoxLayout" name="verticalLayout">
127
+ <item>
128
+ <widget class="QTabWidget" name="tabWidget">
129
+ <property name="currentIndex">
130
+ <number>0</number>
131
+ </property>
132
+ <widget class="QWidget" name="tab_scan">
133
+ <attribute name="title">
134
+ <string>Scan</string>
135
+ </attribute>
136
+ <layout class="QGridLayout" name="gridLayout">
137
+ <property name="leftMargin">
138
+ <number>5</number>
139
+ </property>
140
+ <property name="topMargin">
141
+ <number>5</number>
142
+ </property>
143
+ <property name="rightMargin">
144
+ <number>5</number>
145
+ </property>
146
+ <property name="bottomMargin">
147
+ <number>5</number>
148
+ </property>
149
+ <item row="0" column="2">
150
+ <widget class="QPushButton" name="normalize_colors_scan">
151
+ <property name="text">
152
+ <string>Normalize Colors</string>
153
+ </property>
154
+ </widget>
155
+ </item>
156
+ <item row="1" column="0" colspan="4">
157
+ <widget class="QTableWidget" name="scan_table">
158
+ <property name="rowCount">
159
+ <number>0</number>
160
+ </property>
161
+ <attribute name="horizontalHeaderCascadingSectionResizes">
162
+ <bool>false</bool>
163
+ </attribute>
164
+ <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
165
+ <bool>true</bool>
166
+ </attribute>
167
+ <attribute name="horizontalHeaderStretchLastSection">
168
+ <bool>true</bool>
169
+ </attribute>
170
+ <attribute name="verticalHeaderStretchLastSection">
171
+ <bool>false</bool>
172
+ </attribute>
173
+ <column>
174
+ <property name="text">
175
+ <string>Name</string>
176
+ </property>
177
+ </column>
178
+ <column>
179
+ <property name="text">
180
+ <string>Entry</string>
181
+ </property>
182
+ </column>
183
+ <column>
184
+ <property name="text">
185
+ <string>Color</string>
186
+ </property>
187
+ </column>
188
+ <column>
189
+ <property name="text">
190
+ <string>Style</string>
191
+ </property>
192
+ </column>
193
+ <column>
194
+ <property name="text">
195
+ <string>Width</string>
196
+ </property>
197
+ </column>
198
+ <column>
199
+ <property name="text">
200
+ <string>Symbol Size</string>
201
+ </property>
202
+ </column>
203
+ <column>
204
+ <property name="text">
205
+ <string>Delete</string>
206
+ </property>
207
+ </column>
208
+ </widget>
209
+ </item>
210
+ <item row="0" column="1">
211
+ <spacer name="horizontalSpacer">
212
+ <property name="orientation">
213
+ <enum>Qt::Orientation::Horizontal</enum>
214
+ </property>
215
+ <property name="sizeHint" stdset="0">
216
+ <size>
217
+ <width>40</width>
218
+ <height>20</height>
219
+ </size>
220
+ </property>
221
+ </spacer>
222
+ </item>
223
+ <item row="0" column="0">
224
+ <widget class="QPushButton" name="add_curve">
225
+ <property name="toolTip">
226
+ <string/>
227
+ </property>
228
+ <property name="text">
229
+ <string/>
230
+ </property>
231
+ </widget>
232
+ </item>
233
+ <item row="0" column="3">
234
+ <widget class="ColormapSelector" name="color_map_selector_scan"/>
235
+ </item>
236
+ </layout>
237
+ </widget>
238
+ <widget class="QWidget" name="tab_DAP">
239
+ <attribute name="title">
240
+ <string>DAP</string>
241
+ </attribute>
242
+ <layout class="QGridLayout" name="gridLayout_2">
243
+ <property name="leftMargin">
244
+ <number>5</number>
245
+ </property>
246
+ <property name="topMargin">
247
+ <number>5</number>
248
+ </property>
249
+ <property name="rightMargin">
250
+ <number>5</number>
251
+ </property>
252
+ <property name="bottomMargin">
253
+ <number>5</number>
254
+ </property>
255
+ <item row="1" column="0" colspan="4">
256
+ <widget class="QTableWidget" name="dap_table">
257
+ <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
258
+ <bool>true</bool>
259
+ </attribute>
260
+ <attribute name="horizontalHeaderStretchLastSection">
261
+ <bool>true</bool>
262
+ </attribute>
263
+ <column>
264
+ <property name="text">
265
+ <string>Name</string>
266
+ </property>
267
+ </column>
268
+ <column>
269
+ <property name="text">
270
+ <string>Entry</string>
271
+ </property>
272
+ </column>
273
+ <column>
274
+ <property name="text">
275
+ <string>Model</string>
276
+ </property>
277
+ </column>
278
+ <column>
279
+ <property name="text">
280
+ <string>Color</string>
281
+ </property>
282
+ </column>
283
+ <column>
284
+ <property name="text">
285
+ <string>Style</string>
286
+ </property>
287
+ </column>
288
+ <column>
289
+ <property name="text">
290
+ <string>Width</string>
291
+ </property>
292
+ </column>
293
+ <column>
294
+ <property name="text">
295
+ <string>Symbol Size</string>
296
+ </property>
297
+ </column>
298
+ <column>
299
+ <property name="text">
300
+ <string>Delete</string>
301
+ </property>
302
+ </column>
303
+ </widget>
304
+ </item>
305
+ <item row="0" column="2">
306
+ <widget class="QPushButton" name="normalize_colors_dap">
307
+ <property name="text">
308
+ <string>Normalize Colors</string>
309
+ </property>
310
+ </widget>
311
+ </item>
312
+ <item row="0" column="1">
313
+ <spacer name="horizontalSpacer_2">
314
+ <property name="orientation">
315
+ <enum>Qt::Orientation::Horizontal</enum>
316
+ </property>
317
+ <property name="sizeHint" stdset="0">
318
+ <size>
319
+ <width>585</width>
320
+ <height>20</height>
321
+ </size>
322
+ </property>
323
+ </spacer>
324
+ </item>
325
+ <item row="0" column="0">
326
+ <widget class="QPushButton" name="add_dap">
327
+ <property name="text">
328
+ <string/>
329
+ </property>
330
+ </widget>
331
+ </item>
332
+ <item row="0" column="3">
333
+ <widget class="ColormapSelector" name="color_map_selector_dap"/>
334
+ </item>
335
+ </layout>
336
+ </widget>
337
+ </widget>
338
+ </item>
339
+ </layout>
340
+ </widget>
341
+ </item>
342
+ </layout>
343
+ </widget>
344
+ <customwidgets>
345
+ <customwidget>
346
+ <class>DeviceLineEdit</class>
347
+ <extends>QLineEdit</extends>
348
+ <header>device_line_edit</header>
349
+ </customwidget>
350
+ <customwidget>
351
+ <class>ColormapSelector</class>
352
+ <extends>QWidget</extends>
353
+ <header>colormap_selector</header>
354
+ </customwidget>
355
+ </customwidgets>
356
+ <resources/>
357
+ <connections/>
358
+ </ui>