microeye 2.3.2__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 (190) hide show
  1. microEye/__init__.py +47 -0
  2. microEye/_version.py +2 -0
  3. microEye/analysis/__init__.py +1 -0
  4. microEye/analysis/checklist_dialog.py +143 -0
  5. microEye/analysis/cmosMaps.py +228 -0
  6. microEye/analysis/filters/__init__.py +9 -0
  7. microEye/analysis/filters/base.py +21 -0
  8. microEye/analysis/filters/spatial.py +338 -0
  9. microEye/analysis/filters/temporal.py +76 -0
  10. microEye/analysis/fitting/__init__.py +0 -0
  11. microEye/analysis/fitting/fit.py +680 -0
  12. microEye/analysis/fitting/nena.py +375 -0
  13. microEye/analysis/fitting/phasor_fit.py +90 -0
  14. microEye/analysis/fitting/processing.py +317 -0
  15. microEye/analysis/fitting/psf/__init__.py +6 -0
  16. microEye/analysis/fitting/psf/extract.py +1129 -0
  17. microEye/analysis/fitting/psf/rubost_mean.py +150 -0
  18. microEye/analysis/fitting/psf/spline.py +167 -0
  19. microEye/analysis/fitting/psf/stats/__init__.py +12 -0
  20. microEye/analysis/fitting/psf/stats/core.py +295 -0
  21. microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
  22. microEye/analysis/fitting/psf/stats/io.py +104 -0
  23. microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
  24. microEye/analysis/fitting/psf/temp.py +147 -0
  25. microEye/analysis/fitting/psf/test.py +47 -0
  26. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
  27. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
  28. microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
  29. microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
  30. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
  31. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
  32. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
  33. microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
  34. microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
  35. microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
  36. microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
  37. microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
  38. microEye/analysis/fitting/results.py +917 -0
  39. microEye/analysis/fitting/results_stats.py +251 -0
  40. microEye/analysis/fitting/tardis.py +209 -0
  41. microEye/analysis/multi_viewer.py +568 -0
  42. microEye/analysis/processing/__init__.py +1 -0
  43. microEye/analysis/processing/frc.py +120 -0
  44. microEye/analysis/rendering/__init__.py +3 -0
  45. microEye/analysis/rendering/base.py +452 -0
  46. microEye/analysis/rendering/cloud.py +215 -0
  47. microEye/analysis/rendering/core.py +47 -0
  48. microEye/analysis/rendering/volumetric.py +198 -0
  49. microEye/analysis/tools/__init__.py +0 -0
  50. microEye/analysis/tools/kymograms.py +1079 -0
  51. microEye/analysis/tools/roi_selectors.py +556 -0
  52. microEye/analysis/utils/__init__.py +3 -0
  53. microEye/analysis/utils/coordinates.py +18 -0
  54. microEye/analysis/utils/images.py +68 -0
  55. microEye/analysis/utils/windows.py +19 -0
  56. microEye/analysis/viewer/__init__.py +3 -0
  57. microEye/analysis/viewer/image_options_widget.py +615 -0
  58. microEye/analysis/viewer/images.py +1225 -0
  59. microEye/analysis/viewer/layers_widget.py +415 -0
  60. microEye/analysis/viewer/localizations.py +1304 -0
  61. microEye/analysis/viewer/psf.py +1003 -0
  62. microEye/analysis/viewer/volume.py +456 -0
  63. microEye/hardware/__init__.py +3 -0
  64. microEye/hardware/cams/__init__.py +29 -0
  65. microEye/hardware/cams/camera_calibration.py +99 -0
  66. microEye/hardware/cams/camera_list.py +528 -0
  67. microEye/hardware/cams/camera_options.py +694 -0
  68. microEye/hardware/cams/camera_panel.py +941 -0
  69. microEye/hardware/cams/dummy/__init__.py +1 -0
  70. microEye/hardware/cams/dummy/dummy_panel.py +759 -0
  71. microEye/hardware/cams/jobs.py +497 -0
  72. microEye/hardware/cams/line_profiler.py +99 -0
  73. microEye/hardware/cams/linescan/IR_Cam.py +474 -0
  74. microEye/hardware/cams/linescan/__init__.py +1 -0
  75. microEye/hardware/cams/micam.py +524 -0
  76. microEye/hardware/cams/pco/__init__.py +58 -0
  77. microEye/hardware/cams/pco/enums.py +382 -0
  78. microEye/hardware/cams/pco/pco_cam.py +761 -0
  79. microEye/hardware/cams/pco/pco_panel.py +477 -0
  80. microEye/hardware/cams/shortcuts.py +312 -0
  81. microEye/hardware/cams/thorlabs/__init__.py +1 -0
  82. microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
  83. microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
  84. microEye/hardware/cams/ueye/__init__.py +1 -0
  85. microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
  86. microEye/hardware/cams/ueye/ueye_panel.py +861 -0
  87. microEye/hardware/cams/vimba/__init__.py +1 -0
  88. microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
  89. microEye/hardware/cams/vimba/vimba_panel.py +813 -0
  90. microEye/hardware/device.py +60 -0
  91. microEye/hardware/lasers/__init__.py +13 -0
  92. microEye/hardware/lasers/io_matchbox.py +791 -0
  93. microEye/hardware/lasers/io_params.py +85 -0
  94. microEye/hardware/lasers/io_single_laser.py +742 -0
  95. microEye/hardware/lasers/laser_relay.py +594 -0
  96. microEye/hardware/mieye/__init__.py +1 -0
  97. microEye/hardware/mieye/acquisition_manager.py +467 -0
  98. microEye/hardware/mieye/devices_manager.py +533 -0
  99. microEye/hardware/mieye/miEye.py +659 -0
  100. microEye/hardware/misc/__init__.py +0 -0
  101. microEye/hardware/misc/acquisition_view.py +71 -0
  102. microEye/hardware/misc/reglo.py +761 -0
  103. microEye/hardware/misc/temp.py +188 -0
  104. microEye/hardware/port_config.py +59 -0
  105. microEye/hardware/protocols/__init__.py +2 -0
  106. microEye/hardware/protocols/actions.py +402 -0
  107. microEye/hardware/protocols/actions_items.py +703 -0
  108. microEye/hardware/protocols/designer.py +244 -0
  109. microEye/hardware/protocols/scene_manager.py +191 -0
  110. microEye/hardware/protocols/serialization.py +97 -0
  111. microEye/hardware/pycromanager/__init__.py +16 -0
  112. microEye/hardware/pycromanager/core.py +1433 -0
  113. microEye/hardware/pycromanager/devices.py +461 -0
  114. microEye/hardware/pycromanager/enums.py +107 -0
  115. microEye/hardware/pycromanager/headless.py +153 -0
  116. microEye/hardware/pycromanager/utils.py +34 -0
  117. microEye/hardware/pycromanager/widgets/__init__.py +5 -0
  118. microEye/hardware/pycromanager/widgets/bridges.py +407 -0
  119. microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
  120. microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
  121. microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
  122. microEye/hardware/stages/__init__.py +18 -0
  123. microEye/hardware/stages/elliptec/__init__.py +5 -0
  124. microEye/hardware/stages/elliptec/baseDevice.py +314 -0
  125. microEye/hardware/stages/elliptec/device.py +384 -0
  126. microEye/hardware/stages/elliptec/deviceID.py +212 -0
  127. microEye/hardware/stages/elliptec/devicePort.py +379 -0
  128. microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
  129. microEye/hardware/stages/elliptec/devicesView.py +706 -0
  130. microEye/hardware/stages/elliptec/ellDevices.py +134 -0
  131. microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
  132. microEye/hardware/stages/elliptec/motorInfo.py +153 -0
  133. microEye/hardware/stages/elliptec/stage.py +62 -0
  134. microEye/hardware/stages/elliptec/test.py +139 -0
  135. microEye/hardware/stages/kinesis/__init__.py +1 -0
  136. microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
  137. microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
  138. microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
  139. microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
  140. microEye/hardware/stages/kinesis/kinesis.py +776 -0
  141. microEye/hardware/stages/piezo_concept.py +607 -0
  142. microEye/hardware/stages/stabilizer.py +785 -0
  143. microEye/hardware/stages/stage.py +89 -0
  144. microEye/hardware/widgets/__init__.py +10 -0
  145. microEye/hardware/widgets/controller.py +246 -0
  146. microEye/hardware/widgets/devices.py +133 -0
  147. microEye/hardware/widgets/focusWidget.py +264 -0
  148. microEye/hardware/widgets/qlist_slider.py +113 -0
  149. microEye/hardware/widgets/scan_acquisition.py +424 -0
  150. microEye/icons/1024.png +0 -0
  151. microEye/icons/128.png +0 -0
  152. microEye/icons/16.png +0 -0
  153. microEye/icons/24.png +0 -0
  154. microEye/icons/256.png +0 -0
  155. microEye/icons/32.png +0 -0
  156. microEye/icons/48.png +0 -0
  157. microEye/icons/512.png +0 -0
  158. microEye/icons/64.png +0 -0
  159. microEye/icons/__init__.py +0 -0
  160. microEye/icons/close.svg +88 -0
  161. microEye/icons/mieye.png +0 -0
  162. microEye/icons/min.svg +83 -0
  163. microEye/icons/viewer.png +0 -0
  164. microEye/launcher.py +42 -0
  165. microEye/qt.py +181 -0
  166. microEye/utils/__init__.py +2 -0
  167. microEye/utils/enum_encoder.py +10 -0
  168. microEye/utils/expandable_groupbox.py +93 -0
  169. microEye/utils/gui_helper.py +457 -0
  170. microEye/utils/hid/__init__.py +8 -0
  171. microEye/utils/hid/controller.py +153 -0
  172. microEye/utils/hid/device.py +63 -0
  173. microEye/utils/hid/enums.py +140 -0
  174. microEye/utils/hid/utils.py +58 -0
  175. microEye/utils/labelled_slider.py +134 -0
  176. microEye/utils/metadata.py +599 -0
  177. microEye/utils/metadata_tree.py +718 -0
  178. microEye/utils/micro_launcher.py +245 -0
  179. microEye/utils/parameter_tree.py +325 -0
  180. microEye/utils/pyscripting.py +444 -0
  181. microEye/utils/retry_exec.py +35 -0
  182. microEye/utils/start_gui.py +112 -0
  183. microEye/utils/thread_worker.py +115 -0
  184. microEye/utils/uImage.py +1512 -0
  185. microeye-2.3.2.dist-info/METADATA +401 -0
  186. microeye-2.3.2.dist-info/RECORD +190 -0
  187. microeye-2.3.2.dist-info/WHEEL +5 -0
  188. microeye-2.3.2.dist-info/entry_points.txt +2 -0
  189. microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
  190. microeye-2.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,457 @@
1
+ from typing import Union
2
+
3
+ import numpy as np
4
+
5
+ from microEye.qt import QApplication, QtWidgets
6
+
7
+
8
+ def create_line_edit(
9
+ label,
10
+ default_text,
11
+ layout: Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout],
12
+ ) -> QtWidgets.QLineEdit:
13
+ '''
14
+ Create a QLineEdit widget with label.
15
+
16
+ Parameters
17
+ ----------
18
+ label : str
19
+ The label for the line edit.
20
+ default_text : str
21
+ The default text to display in the line edit.
22
+ layout : Union[QVBoxLayout, QHBoxLayout, QFormLayout]
23
+ The layout to which the line edit will be added.
24
+
25
+ Returns
26
+ -------
27
+ QLineEdit
28
+ The created QLineEdit widget.
29
+ '''
30
+ line_edit = QtWidgets.QLineEdit(default_text)
31
+
32
+ if isinstance(layout, QtWidgets.QFormLayout):
33
+ layout.addRow(QtWidgets.QLabel(label), line_edit)
34
+ else:
35
+ layout.addWidget(QtWidgets.QLabel(label))
36
+ layout.addWidget(line_edit)
37
+
38
+ return line_edit
39
+
40
+
41
+ def create_text_edit(
42
+ label,
43
+ default_text,
44
+ layout: Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout],
45
+ ) -> QtWidgets.QTextEdit:
46
+ '''
47
+ Create a QLineEdit widget with label.
48
+
49
+ Parameters
50
+ ----------
51
+ label : str
52
+ The label for the line edit.
53
+ default_text : str
54
+ The default text to display in the line edit.
55
+ layout : Union[QVBoxLayout, QHBoxLayout, QFormLayout]
56
+ The layout to which the line edit will be added.
57
+
58
+ Returns
59
+ -------
60
+ QLineEdit
61
+ The created QLineEdit widget.
62
+ '''
63
+ text_edit = QtWidgets.QTextEdit(default_text)
64
+ if isinstance(layout, QtWidgets.QFormLayout):
65
+ layout.addRow(QtWidgets.QLabel(label))
66
+ layout.addRow(text_edit)
67
+ else:
68
+ layout.addWidget(QtWidgets.QLabel(label))
69
+ layout.addWidget(text_edit)
70
+ return text_edit
71
+
72
+
73
+ def create_combo_box(
74
+ label,
75
+ items,
76
+ default_item,
77
+ layout: Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout],
78
+ ) -> QtWidgets.QComboBox:
79
+ '''
80
+ Create a QComboBox widget with label.
81
+
82
+ Parameters
83
+ ----------
84
+ label : str
85
+ The label for the combo box.
86
+ items : list
87
+ The list of items to populate the combo box.
88
+ default_item : str
89
+ The default item to select in the combo box.
90
+ layout : Union[QVBoxLayout, QHBoxLayout, QFormLayout]
91
+ The layout to which the combo box will be added.
92
+
93
+ Returns
94
+ -------
95
+ QComboBox
96
+ The created QComboBox widget.
97
+ '''
98
+ combo_box = QtWidgets.QComboBox()
99
+ combo_box.addItems(items)
100
+ combo_box.setCurrentText(default_item)
101
+ if isinstance(layout, QtWidgets.QFormLayout):
102
+ layout.addRow(QtWidgets.QLabel(label), combo_box)
103
+ else:
104
+ layout.addWidget(QtWidgets.QLabel(label))
105
+ layout.addWidget(combo_box)
106
+ return combo_box
107
+
108
+
109
+ def create_double_spin_box(
110
+ min_value=0, max_value=1, single_step=0.01, decimals=3, initial_value=0, slot=None
111
+ ):
112
+ '''
113
+ Create a QDoubleSpinBox widget.
114
+
115
+ Parameters
116
+ ----------
117
+ min_value : float, optional
118
+ Minimum allowed value.
119
+ max_value : float, optional
120
+ Maximum allowed value.
121
+ single_step : float, optional
122
+ Step size for increment/decrement.
123
+ decimals : int, optional
124
+ Number of decimal places.
125
+ initial_value : float, optional
126
+ Initial value of the spin box.
127
+ slot : Callable, optional
128
+ Function to connect to the valueChanged signal.
129
+
130
+ Returns
131
+ -------
132
+ QDoubleSpinBox
133
+ The created QDoubleSpinBox widget.
134
+ '''
135
+ double_spin_box = QtWidgets.QDoubleSpinBox()
136
+ double_spin_box.setMinimum(min_value)
137
+ double_spin_box.setMaximum(max_value)
138
+ double_spin_box.setSingleStep(single_step)
139
+ double_spin_box.setDecimals(decimals)
140
+ double_spin_box.setValue(initial_value)
141
+ if slot:
142
+ double_spin_box.valueChanged.connect(slot)
143
+ return double_spin_box
144
+
145
+
146
+ def create_labelled_double_spin_box(
147
+ label,
148
+ min_val,
149
+ max_val,
150
+ default_val,
151
+ layout: Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout],
152
+ ) -> QtWidgets.QDoubleSpinBox:
153
+ '''
154
+ Create a QDoubleSpinBox widget with a label.
155
+
156
+ Parameters
157
+ ----------
158
+ label : str
159
+ The label for the spin box.
160
+ min_val : float
161
+ Minimum allowed value.
162
+ max_val : float
163
+ Maximum allowed value.
164
+ default_val : float
165
+ Initial value of the spin box.
166
+ layout : Union[QVBoxLayout, QHBoxLayout, QFormLayout]
167
+ The layout to which the spin box will be added.
168
+
169
+ Returns
170
+ -------
171
+ QDoubleSpinBox
172
+ The created QDoubleSpinBox widget.
173
+ '''
174
+ spin_box = QtWidgets.QDoubleSpinBox()
175
+ spin_box.setMinimum(min_val)
176
+ spin_box.setMaximum(max_val)
177
+ spin_box.setValue(default_val)
178
+
179
+ if isinstance(layout, QtWidgets.QFormLayout):
180
+ layout.addRow(QtWidgets.QLabel(label), spin_box)
181
+ else:
182
+ layout.addWidget(QtWidgets.QLabel(label))
183
+ layout.addWidget(spin_box)
184
+ return spin_box
185
+
186
+
187
+ def create_spin_box(
188
+ min_value=0, max_value=100, single_step=1, initial_value=0, slot=None
189
+ ):
190
+ '''
191
+ Create a QSpinBox widget.
192
+
193
+ Parameters
194
+ ----------
195
+ min_value : int, optional
196
+ Minimum allowed value.
197
+ max_value : int, optional
198
+ Maximum allowed value.
199
+ single_step : int, optional
200
+ Step size for increment/decrement.
201
+ initial_value : int, optional
202
+ Initial value of the spin box.
203
+ slot : Callable, optional
204
+ Function to connect to the valueChanged signal.
205
+
206
+ Returns
207
+ -------
208
+ QSpinBox
209
+ The created QSpinBox widget.
210
+ '''
211
+
212
+ spin_box = QtWidgets.QSpinBox()
213
+ spin_box.setMinimum(min_value)
214
+ spin_box.setMaximum(max_value)
215
+ spin_box.setSingleStep(single_step)
216
+ spin_box.setValue(initial_value)
217
+ if slot:
218
+ spin_box.valueChanged.connect(slot)
219
+ return spin_box
220
+
221
+
222
+ def create_check_box(text, initial_state=False, state_changed_slot=None):
223
+ '''
224
+ Create a QCheckBox widget.
225
+
226
+ Parameters
227
+ ----------
228
+ text : str
229
+ Text to display next to the checkbox.
230
+ initial_state : bool, optional
231
+ Initial state of the checkbox.
232
+ state_changed_slot : Callable, optional
233
+ Function to connect to the stateChanged signal.
234
+
235
+ Returns
236
+ -------
237
+ QCheckBox
238
+ The created QCheckBox widget.
239
+ '''
240
+ check_box = QtWidgets.QCheckBox(text)
241
+ check_box.setChecked(initial_state)
242
+
243
+ if state_changed_slot:
244
+ check_box.stateChanged.connect(state_changed_slot)
245
+
246
+ return check_box
247
+
248
+
249
+ def create_group_box(
250
+ title,
251
+ layout_type: Union[
252
+ QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout
253
+ ] = QtWidgets.QVBoxLayout,
254
+ ):
255
+ '''
256
+ Create a QGroupBox with a specified layout type.
257
+
258
+ Parameters
259
+ ----------
260
+ title : str
261
+ Title of the group box.
262
+ layout_type : QVBoxLayout or QHBoxLayout or QFormLayout, optional
263
+ Type of layout to use inside the group box.
264
+
265
+ Returns
266
+ -------
267
+ QGroupBox, QLayout
268
+ The created QGroupBox and its associated layout.
269
+ '''
270
+ group_box = QtWidgets.QGroupBox(title)
271
+ layout = layout_type()
272
+ group_box.setLayout(layout)
273
+ return group_box, layout
274
+
275
+
276
+ def create_widget(
277
+ layout_type: Union[
278
+ QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout
279
+ ] = QtWidgets.QVBoxLayout,
280
+ ) -> tuple[
281
+ QtWidgets.QWidget,
282
+ Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout, QtWidgets.QFormLayout],
283
+ ]:
284
+ '''
285
+ Create a QWidget with a specified layout type.
286
+
287
+ Parameters
288
+ ----------
289
+ layout_type : QVBoxLayout or QHBoxLayout or QFormLayout, optional
290
+ Type of layout to use inside the widget.
291
+
292
+ Returns
293
+ -------
294
+ QWidget, QLayout
295
+ The created QWidget and its associated layout.
296
+ '''
297
+ widget = QtWidgets.QWidget()
298
+ layout = layout_type()
299
+ widget.setLayout(layout)
300
+ return widget, layout
301
+
302
+
303
+ def create_hbox_layout(*args):
304
+ '''
305
+ Create a QHBoxLayout and add the specified widgets to it.
306
+
307
+ Parameters
308
+ ----------
309
+ *args : QWidget
310
+ Widgets to add to the layout.
311
+
312
+ Returns
313
+ -------
314
+ QHBoxLayout
315
+ The created QHBoxLayout.
316
+ '''
317
+ hbox_layout = QtWidgets.QHBoxLayout()
318
+
319
+ for widget in args:
320
+ hbox_layout.addWidget(widget)
321
+
322
+ return hbox_layout
323
+
324
+
325
+ def create_vbox_layout(*args):
326
+ '''
327
+ Create a QVBoxLayout and add the specified widgets to it.
328
+
329
+ Parameters
330
+ ----------
331
+ *args : QWidget
332
+ Widgets to add to the layout.
333
+
334
+ Returns
335
+ -------
336
+ QVBoxLayout
337
+ The created QVBoxLayout.
338
+ '''
339
+ vbox_layout = QtWidgets.QVBoxLayout()
340
+
341
+ for widget in args:
342
+ vbox_layout.addWidget(widget)
343
+
344
+ return vbox_layout
345
+
346
+
347
+ def layout_add_elements(
348
+ layout: Union[QtWidgets.QVBoxLayout, QtWidgets.QHBoxLayout], *args
349
+ ):
350
+ '''
351
+ Add elements to a QVBoxLayout or QHBoxLayout.
352
+
353
+ Parameters
354
+ ----------
355
+ layout : QVBoxLayout or QHBoxLayout
356
+ The layout to which elements will be added.
357
+ *args : QWidget or QLayout
358
+ Elements to add to the layout.
359
+ '''
360
+ for widget in args:
361
+ if isinstance(widget, QtWidgets.QWidget):
362
+ layout.addWidget(widget)
363
+ elif isinstance(widget, QtWidgets.QLayout):
364
+ layout.addLayout(widget)
365
+
366
+
367
+ def get_scaling_factor(height, width, target_percentage=0.8):
368
+ '''
369
+ Calculate the scaling factor to fill the specified percentage of the screen.
370
+
371
+ Parameters
372
+ ----------
373
+ height : int
374
+ Height of the content.
375
+ width : int
376
+ Width of the content.
377
+ target_percentage : float, optional
378
+ Target percentage of the screen to fill.
379
+
380
+ Returns
381
+ -------
382
+ float
383
+ The calculated scaling factor.
384
+ '''
385
+ main_screen = QApplication.primaryScreen().availableGeometry()
386
+ screen_info = (main_screen.width(), main_screen.height())
387
+
388
+ # Calculate scaling factor to fill the specified percentage of the screen
389
+ target_height = screen_info[1] * target_percentage
390
+ target_width = screen_info[0] * target_percentage
391
+
392
+ scaling_factor_height = target_height / height
393
+ scaling_factor_width = target_width / width
394
+
395
+ return min(scaling_factor_height, scaling_factor_width)
396
+
397
+
398
+ def time_string_ms(value: float):
399
+ '''
400
+ Convert time in milliseconds to a formatted string.
401
+
402
+ Parameters
403
+ ----------
404
+ value : float
405
+ Time value in milliseconds.
406
+
407
+ Returns
408
+ -------
409
+ str
410
+ Formatted time string in minutes and seconds.
411
+ '''
412
+ seconds = value / 1000
413
+ return f'{seconds // 60:.0f} min {seconds % 60} seconds'
414
+
415
+
416
+ def time_string_s(value: float):
417
+ '''
418
+ Convert time in seconds to a formatted string.
419
+
420
+ Parameters
421
+ ----------
422
+ value : float
423
+ Time value in seconds.
424
+
425
+ Returns
426
+ -------
427
+ str
428
+ Formatted time string in minutes and seconds.
429
+ '''
430
+ return f'{value // 60:.0f} min {value % 60} seconds'
431
+
432
+
433
+ def GaussianOffSet(x, a, x0, sigma, offset):
434
+ '''
435
+ Returns a Gaussian function with an offset.
436
+
437
+ f(x) = a * exp(-(x - x0)**2 / (2 * sigma**2)) + offset
438
+
439
+ Parameters
440
+ ----------
441
+ x : np.ndarray
442
+ Input values.
443
+ a : float
444
+ Amplitude.
445
+ x0 : float
446
+ Center or mean.
447
+ sigma : float
448
+ Standard deviation.
449
+ offset : float
450
+ Y offset.
451
+
452
+ Returns
453
+ -------
454
+ np.ndarray
455
+ Gaussian function f(x).
456
+ '''
457
+ return a * np.exp(-((x - x0) ** 2) / (2 * sigma**2)) + offset
@@ -0,0 +1,8 @@
1
+ from microEye.utils.hid.controller import hidController
2
+ from microEye.utils.hid.enums import Buttons, hidParams
3
+ from microEye.utils.hid.utils import (
4
+ dz_hybrid,
5
+ dz_scaled_radial,
6
+ dz_sloped_scaled_axial,
7
+ map_range,
8
+ )
@@ -0,0 +1,153 @@
1
+ import sys
2
+ from typing import Optional
3
+
4
+ import hid
5
+ import numpy as np
6
+ from pyqtgraph.parametertree import Parameter
7
+
8
+ from microEye.qt import QApplication, QtCore, QtWidgets, Signal
9
+ from microEye.utils.hid.device import hidDevice
10
+ from microEye.utils.hid.enums import Buttons, hidParams
11
+ from microEye.utils.hid.utils import dz_hybrid, dz_scaled_radial, dz_sloped_scaled_axial
12
+ from microEye.utils.parameter_tree import Tree
13
+
14
+
15
+ class hidController(Tree):
16
+ '''QWidget for handling HID controller input.'''
17
+ # Define signals with docstrings
18
+ reportEvent = Signal(Buttons)
19
+ '''Signal emitted when a controller button event occurs.
20
+
21
+ Parameters
22
+ ----------
23
+ Buttons: :class:`Buttons`
24
+ The enum member representing the button.
25
+ '''
26
+
27
+ reportLStickPosition = Signal(int, int)
28
+ '''Signal emitted when the left stick position changes.
29
+
30
+ Parameters
31
+ ----------
32
+ int: int
33
+ X-axis position of the left stick.
34
+ int: int
35
+ Y-axis position of the left stick.
36
+ '''
37
+
38
+ reportRStickPosition = Signal(int, int)
39
+ '''Signal emitted when the right stick position changes.
40
+
41
+ Parameters
42
+ ----------
43
+ int: int
44
+ X-axis position of the right stick.
45
+ int: int
46
+ Y-axis position of the right stick.
47
+ '''
48
+ PARAMS = hidParams
49
+
50
+ def __init__(self, parent: Optional['QtWidgets.QWidget'] = None):
51
+ '''Initialize the HID controller widget.'''
52
+ super().__init__(parent=parent)
53
+
54
+ self.refresh_list()
55
+
56
+ self.hid_device = None
57
+
58
+ self.last_btn = None
59
+ self.last_aux = None
60
+ self.left_analog = (128, 127)
61
+ self.right_analog = (128, 127)
62
+
63
+ self.timer = QtCore.QTimer()
64
+ self.timer.setInterval(1)
65
+ self.timer.timeout.connect(self.recurring_timer)
66
+ self.timer.start()
67
+
68
+ def create_parameters(self):
69
+ '''
70
+ Create the parameter tree structure.
71
+ '''
72
+ params = [
73
+ {'name': str(hidParams.TITLE), 'type': 'group',
74
+ 'children': []},
75
+ {'name': str(hidParams.DEVICE), 'type': 'list',
76
+ 'limits': []},
77
+ {'name': str(hidParams.REFRESH), 'type': 'action'},
78
+ {'name': str(hidParams.OPEN), 'type': 'action'},
79
+ {'name': str(hidParams.CLOSE), 'type': 'action'},
80
+ ]
81
+
82
+ self.param_tree = Parameter.create(name='', type='group', children=params)
83
+ self.param_tree.sigTreeStateChanged.connect(self.change)
84
+ self.header().setSectionResizeMode(
85
+ QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
86
+
87
+ self.get_param(
88
+ hidParams.REFRESH).sigActivated.connect(self.refresh_list)
89
+ self.get_param(
90
+ hidParams.OPEN).sigActivated.connect(self.open_HID)
91
+ self.get_param(
92
+ hidParams.CLOSE).sigActivated.connect(self.close_HID)
93
+
94
+ def recurring_timer(self):
95
+ '''Read and process controller input in a recurring timer.'''
96
+ if self.hid_device is not None:
97
+ report = self.hid_device.read(64)
98
+ if report:
99
+ # print(report)
100
+ if len(report) == 14:
101
+ res = Buttons.from_value(0, report[-4])
102
+ if res:
103
+ if res != self.last_btn:
104
+ self.reportEvent.emit(res)
105
+ self.last_btn = res
106
+ else:
107
+ self.last_btn = None
108
+ res = Buttons.from_value(1, report[-3])
109
+ if res:
110
+ if res != self.last_aux:
111
+ self.reportEvent.emit(res)
112
+ self.last_aux = res
113
+ else:
114
+ self.last_aux = None
115
+
116
+ self.left_analog = report[1], report[3]
117
+ self.right_analog = report[5], report[7]
118
+ self.reportLStickPosition.emit(
119
+ *self.left_analog)
120
+ self.reportRStickPosition.emit(
121
+ *self.right_analog)
122
+
123
+ def close_HID(self):
124
+ '''Close the HID device.'''
125
+ if self.hid_device is not None:
126
+ self.hid_device.close()
127
+ self.hid_device = None
128
+
129
+ def open_HID(self):
130
+ '''Open the selected HID device.'''
131
+ device: hidDevice = self.get_param_value(hidParams.DEVICE)
132
+ if device is not None:
133
+ if self.hid_device is not None:
134
+ self.hid_device.close()
135
+ self.hid_device = None
136
+
137
+ self.hid_device = device.getHID()
138
+
139
+ def refresh_list(self):
140
+ '''Refresh the list of available HID devices.'''
141
+ devicesParam = self.get_param(hidParams.DEVICE)
142
+
143
+ devices = [hidDevice(device) for device in hid.enumerate()]
144
+
145
+ devicesParam.setLimits(devices)
146
+
147
+
148
+ if __name__ == '__main__':
149
+ app = QApplication(sys.argv)
150
+ win = hidController()
151
+ win.show()
152
+
153
+ app.exec()
@@ -0,0 +1,63 @@
1
+ import hid
2
+
3
+
4
+ class hidDevice:
5
+ def __init__(self, device: dict) -> None:
6
+ '''
7
+ Initialize a new hidDevice object.
8
+
9
+ Parameters
10
+ ----------
11
+ device : dict
12
+ A dictionary containing information about the HID device.
13
+ '''
14
+ self.data = device
15
+
16
+ @property
17
+ def vendorID(self):
18
+ '''
19
+ Get the vendor ID of the HID device.
20
+
21
+ Returns
22
+ -------
23
+ int or None
24
+ The vendor ID of the HID device, or None if it is not available.
25
+ '''
26
+ return self.data.get('vendor_id', None)
27
+
28
+ @property
29
+ def productID(self):
30
+ '''
31
+ Get the product ID of the HID device.
32
+
33
+ Returns
34
+ -------
35
+ int or None
36
+ The product ID of the HID device, or None if it is not available.
37
+ '''
38
+ return self.data.get('product_id', None)
39
+
40
+ def getHID(self):
41
+ '''
42
+ Get a hid.device object for the HID device.
43
+
44
+ Returns
45
+ -------
46
+ hid.device
47
+ A hid.device object for the HID device.
48
+ '''
49
+ hid_device = hid.device()
50
+ hid_device.open(self.vendorID, self.productID)
51
+ hid_device.set_nonblocking(True)
52
+ return hid_device
53
+
54
+ def __str__(self) -> str:
55
+ '''
56
+ Get a string representation of the HID device.
57
+
58
+ Returns
59
+ -------
60
+ str
61
+ A string representation of the HID device.
62
+ '''
63
+ return self.data.get('product_string', 'N/A')