datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.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 (496) hide show
  1. datalab/__init__.py +35 -2
  2. datalab/adapters_metadata/__init__.py +31 -0
  3. datalab/adapters_metadata/base_adapter.py +316 -0
  4. datalab/adapters_metadata/common.py +422 -0
  5. datalab/adapters_metadata/geometry_adapter.py +98 -0
  6. datalab/adapters_metadata/table_adapter.py +84 -0
  7. datalab/adapters_plotpy/__init__.py +54 -0
  8. datalab/adapters_plotpy/annotations.py +124 -0
  9. datalab/adapters_plotpy/base.py +110 -0
  10. datalab/adapters_plotpy/converters.py +86 -0
  11. datalab/adapters_plotpy/factories.py +80 -0
  12. datalab/adapters_plotpy/objects/__init__.py +0 -0
  13. datalab/adapters_plotpy/objects/base.py +197 -0
  14. datalab/adapters_plotpy/objects/image.py +157 -0
  15. datalab/adapters_plotpy/objects/scalar.py +565 -0
  16. datalab/adapters_plotpy/objects/signal.py +264 -0
  17. datalab/adapters_plotpy/roi/__init__.py +0 -0
  18. datalab/adapters_plotpy/roi/base.py +146 -0
  19. datalab/adapters_plotpy/roi/factory.py +93 -0
  20. datalab/adapters_plotpy/roi/image.py +207 -0
  21. datalab/adapters_plotpy/roi/signal.py +72 -0
  22. datalab/app.py +98 -0
  23. datalab/config.py +817 -0
  24. datalab/control/__init__.py +0 -0
  25. datalab/control/baseproxy.py +776 -0
  26. datalab/control/proxy.py +343 -0
  27. datalab/control/remote.py +1005 -0
  28. datalab/data/doc/DataLab_en.pdf +0 -0
  29. datalab/data/doc/DataLab_fr.pdf +0 -0
  30. datalab/data/icons/analysis/delete_results.svg +109 -0
  31. datalab/data/icons/analysis/fw1e2.svg +156 -0
  32. datalab/data/icons/analysis/fwhm.svg +156 -0
  33. datalab/data/icons/analysis/histogram.svg +49 -0
  34. datalab/data/icons/analysis/peak_detect.svg +160 -0
  35. datalab/data/icons/analysis/plot_results.svg +151 -0
  36. datalab/data/icons/analysis/show_results.svg +83 -0
  37. datalab/data/icons/analysis/stats.svg +49 -0
  38. datalab/data/icons/analysis.svg +120 -0
  39. datalab/data/icons/apply.svg +3 -0
  40. datalab/data/icons/check_all.svg +15 -0
  41. datalab/data/icons/collapse.svg +44 -0
  42. datalab/data/icons/collapse_selection.svg +63 -0
  43. datalab/data/icons/console.svg +101 -0
  44. datalab/data/icons/create/1d-normal.svg +8 -0
  45. datalab/data/icons/create/1d-poisson.svg +9 -0
  46. datalab/data/icons/create/1d-uniform.svg +8 -0
  47. datalab/data/icons/create/1d-zero.svg +57 -0
  48. datalab/data/icons/create/2d-gaussian.svg +56 -0
  49. datalab/data/icons/create/2d-normal.svg +38 -0
  50. datalab/data/icons/create/2d-poisson.svg +38 -0
  51. datalab/data/icons/create/2d-ramp.svg +90 -0
  52. datalab/data/icons/create/2d-sinc.svg +62 -0
  53. datalab/data/icons/create/2d-uniform.svg +38 -0
  54. datalab/data/icons/create/2d-zero.svg +13 -0
  55. datalab/data/icons/create/checkerboard.svg +39 -0
  56. datalab/data/icons/create/cosine.svg +12 -0
  57. datalab/data/icons/create/exponential.svg +55 -0
  58. datalab/data/icons/create/gaussian.svg +12 -0
  59. datalab/data/icons/create/grating.svg +29 -0
  60. datalab/data/icons/create/linear_chirp.svg +7 -0
  61. datalab/data/icons/create/logistic.svg +7 -0
  62. datalab/data/icons/create/lorentzian.svg +12 -0
  63. datalab/data/icons/create/planck.svg +12 -0
  64. datalab/data/icons/create/polynomial.svg +7 -0
  65. datalab/data/icons/create/pulse.svg +12 -0
  66. datalab/data/icons/create/ring.svg +18 -0
  67. datalab/data/icons/create/sawtooth.svg +7 -0
  68. datalab/data/icons/create/siemens.svg +35 -0
  69. datalab/data/icons/create/sinc.svg +12 -0
  70. datalab/data/icons/create/sine.svg +7 -0
  71. datalab/data/icons/create/square.svg +7 -0
  72. datalab/data/icons/create/square_pulse.svg +7 -0
  73. datalab/data/icons/create/step.svg +7 -0
  74. datalab/data/icons/create/step_pulse.svg +12 -0
  75. datalab/data/icons/create/triangle.svg +7 -0
  76. datalab/data/icons/create/voigt.svg +12 -0
  77. datalab/data/icons/edit/annotations.svg +72 -0
  78. datalab/data/icons/edit/annotations_copy.svg +114 -0
  79. datalab/data/icons/edit/annotations_delete.svg +83 -0
  80. datalab/data/icons/edit/annotations_edit.svg +98 -0
  81. datalab/data/icons/edit/annotations_export.svg +85 -0
  82. datalab/data/icons/edit/annotations_import.svg +85 -0
  83. datalab/data/icons/edit/annotations_paste.svg +100 -0
  84. datalab/data/icons/edit/copy_titles.svg +109 -0
  85. datalab/data/icons/edit/delete.svg +84 -0
  86. datalab/data/icons/edit/delete_all.svg +214 -0
  87. datalab/data/icons/edit/duplicate.svg +64 -0
  88. datalab/data/icons/edit/goto_source.svg +60 -0
  89. datalab/data/icons/edit/metadata.svg +60 -0
  90. datalab/data/icons/edit/metadata_add.svg +80 -0
  91. datalab/data/icons/edit/metadata_copy.svg +96 -0
  92. datalab/data/icons/edit/metadata_delete.svg +62 -0
  93. datalab/data/icons/edit/metadata_export.svg +68 -0
  94. datalab/data/icons/edit/metadata_import.svg +68 -0
  95. datalab/data/icons/edit/metadata_paste.svg +79 -0
  96. datalab/data/icons/edit/move_down.svg +55 -0
  97. datalab/data/icons/edit/move_up.svg +54 -0
  98. datalab/data/icons/edit/new_group.svg +76 -0
  99. datalab/data/icons/edit/recompute.svg +60 -0
  100. datalab/data/icons/edit/rename.svg +49 -0
  101. datalab/data/icons/edit.svg +16 -0
  102. datalab/data/icons/expand.svg +44 -0
  103. datalab/data/icons/expand_selection.svg +63 -0
  104. datalab/data/icons/fit/cdf_fit.svg +56 -0
  105. datalab/data/icons/fit/exponential_fit.svg +55 -0
  106. datalab/data/icons/fit/gaussian_fit.svg +62 -0
  107. datalab/data/icons/fit/interactive_fit.svg +101 -0
  108. datalab/data/icons/fit/linear_fit.svg +57 -0
  109. datalab/data/icons/fit/lorentzian_fit.svg +209 -0
  110. datalab/data/icons/fit/multigaussian_fit.svg +85 -0
  111. datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
  112. datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
  113. datalab/data/icons/fit/planckian_fit.svg +62 -0
  114. datalab/data/icons/fit/polynomial_fit.svg +59 -0
  115. datalab/data/icons/fit/sigmoid_fit.svg +56 -0
  116. datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
  117. datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
  118. datalab/data/icons/fit/voigt_fit.svg +57 -0
  119. datalab/data/icons/group.svg +56 -0
  120. datalab/data/icons/h5/h5array.svg +59 -0
  121. datalab/data/icons/h5/h5attrs.svg +75 -0
  122. datalab/data/icons/h5/h5browser.svg +133 -0
  123. datalab/data/icons/h5/h5file.svg +69 -0
  124. datalab/data/icons/h5/h5group.svg +49 -0
  125. datalab/data/icons/h5/h5scalar.svg +1 -0
  126. datalab/data/icons/help_pdf.svg +46 -0
  127. datalab/data/icons/history.svg +7 -0
  128. datalab/data/icons/image.svg +135 -0
  129. datalab/data/icons/io/fileopen_directory.svg +60 -0
  130. datalab/data/icons/io/fileopen_h5.svg +84 -0
  131. datalab/data/icons/io/fileopen_ima.svg +187 -0
  132. datalab/data/icons/io/fileopen_py.svg +123 -0
  133. datalab/data/icons/io/fileopen_sig.svg +138 -0
  134. datalab/data/icons/io/filesave_h5.svg +97 -0
  135. datalab/data/icons/io/filesave_ima.svg +200 -0
  136. datalab/data/icons/io/filesave_py.svg +136 -0
  137. datalab/data/icons/io/filesave_sig.svg +151 -0
  138. datalab/data/icons/io/import_text.svg +144 -0
  139. datalab/data/icons/io/save_to_directory.svg +134 -0
  140. datalab/data/icons/io.svg +84 -0
  141. datalab/data/icons/libre-camera-flash-off.svg +1 -0
  142. datalab/data/icons/libre-camera-flash-on.svg +1 -0
  143. datalab/data/icons/libre-gui-about.svg +1 -0
  144. datalab/data/icons/libre-gui-action-delete.svg +1 -0
  145. datalab/data/icons/libre-gui-add.svg +1 -0
  146. datalab/data/icons/libre-gui-arrow-down.svg +1 -0
  147. datalab/data/icons/libre-gui-arrow-left.svg +1 -0
  148. datalab/data/icons/libre-gui-arrow-right.svg +1 -0
  149. datalab/data/icons/libre-gui-arrow-up.svg +1 -0
  150. datalab/data/icons/libre-gui-close.svg +40 -0
  151. datalab/data/icons/libre-gui-cogs.svg +1 -0
  152. datalab/data/icons/libre-gui-globe.svg +1 -0
  153. datalab/data/icons/libre-gui-help.svg +1 -0
  154. datalab/data/icons/libre-gui-link.svg +1 -0
  155. datalab/data/icons/libre-gui-menu.svg +1 -0
  156. datalab/data/icons/libre-gui-pencil.svg +1 -0
  157. datalab/data/icons/libre-gui-plugin.svg +1 -0
  158. datalab/data/icons/libre-gui-questions.svg +1 -0
  159. datalab/data/icons/libre-gui-settings.svg +1 -0
  160. datalab/data/icons/libre-gui-unlink.svg +1 -0
  161. datalab/data/icons/libre-tech-ram.svg +1 -0
  162. datalab/data/icons/libre-toolbox.svg +1 -0
  163. datalab/data/icons/logs.svg +1 -0
  164. datalab/data/icons/markers.svg +74 -0
  165. datalab/data/icons/menu.svg +13 -0
  166. datalab/data/icons/new_ima.svg +148 -0
  167. datalab/data/icons/new_sig.svg +123 -0
  168. datalab/data/icons/operations/abs.svg +116 -0
  169. datalab/data/icons/operations/arithmetic.svg +123 -0
  170. datalab/data/icons/operations/average.svg +124 -0
  171. datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
  172. datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
  173. datalab/data/icons/operations/constant.svg +116 -0
  174. datalab/data/icons/operations/constant_add.svg +109 -0
  175. datalab/data/icons/operations/constant_divide.svg +109 -0
  176. datalab/data/icons/operations/constant_multiply.svg +109 -0
  177. datalab/data/icons/operations/constant_subtract.svg +109 -0
  178. datalab/data/icons/operations/convert_dtype.svg +117 -0
  179. datalab/data/icons/operations/convolution.svg +46 -0
  180. datalab/data/icons/operations/deconvolution.svg +57 -0
  181. datalab/data/icons/operations/derivative.svg +127 -0
  182. datalab/data/icons/operations/difference.svg +52 -0
  183. datalab/data/icons/operations/division.svg +139 -0
  184. datalab/data/icons/operations/exp.svg +116 -0
  185. datalab/data/icons/operations/flip_horizontally.svg +69 -0
  186. datalab/data/icons/operations/flip_vertically.svg +74 -0
  187. datalab/data/icons/operations/im.svg +124 -0
  188. datalab/data/icons/operations/integral.svg +50 -0
  189. datalab/data/icons/operations/inverse.svg +143 -0
  190. datalab/data/icons/operations/log10.svg +109 -0
  191. datalab/data/icons/operations/phase.svg +116 -0
  192. datalab/data/icons/operations/power.svg +118 -0
  193. datalab/data/icons/operations/product.svg +124 -0
  194. datalab/data/icons/operations/profile.svg +379 -0
  195. datalab/data/icons/operations/profile_average.svg +399 -0
  196. datalab/data/icons/operations/profile_radial.svg +261 -0
  197. datalab/data/icons/operations/profile_segment.svg +262 -0
  198. datalab/data/icons/operations/quadratic_difference.svg +84 -0
  199. datalab/data/icons/operations/re.svg +124 -0
  200. datalab/data/icons/operations/rotate_left.svg +72 -0
  201. datalab/data/icons/operations/rotate_right.svg +72 -0
  202. datalab/data/icons/operations/signals_to_image.svg +314 -0
  203. datalab/data/icons/operations/sqrt.svg +110 -0
  204. datalab/data/icons/operations/std.svg +124 -0
  205. datalab/data/icons/operations/sum.svg +102 -0
  206. datalab/data/icons/play_demo.svg +9 -0
  207. datalab/data/icons/processing/axis_transform.svg +62 -0
  208. datalab/data/icons/processing/bandpass.svg +79 -0
  209. datalab/data/icons/processing/bandstop.svg +71 -0
  210. datalab/data/icons/processing/binning.svg +126 -0
  211. datalab/data/icons/processing/clip.svg +119 -0
  212. datalab/data/icons/processing/detrending.svg +173 -0
  213. datalab/data/icons/processing/distribute_on_grid.svg +769 -0
  214. datalab/data/icons/processing/edge_detection.svg +46 -0
  215. datalab/data/icons/processing/erase.svg +1 -0
  216. datalab/data/icons/processing/exposure.svg +143 -0
  217. datalab/data/icons/processing/fourier.svg +104 -0
  218. datalab/data/icons/processing/highpass.svg +59 -0
  219. datalab/data/icons/processing/interpolation.svg +71 -0
  220. datalab/data/icons/processing/level_adjustment.svg +70 -0
  221. datalab/data/icons/processing/lowpass.svg +60 -0
  222. datalab/data/icons/processing/morphology.svg +49 -0
  223. datalab/data/icons/processing/noise_addition.svg +114 -0
  224. datalab/data/icons/processing/noise_reduction.svg +38 -0
  225. datalab/data/icons/processing/normalize.svg +84 -0
  226. datalab/data/icons/processing/offset_correction.svg +131 -0
  227. datalab/data/icons/processing/resampling1d.svg +101 -0
  228. datalab/data/icons/processing/resampling2d.svg +240 -0
  229. datalab/data/icons/processing/reset_positions.svg +185 -0
  230. datalab/data/icons/processing/resize.svg +9 -0
  231. datalab/data/icons/processing/reverse_signal_x.svg +171 -0
  232. datalab/data/icons/processing/stability.svg +11 -0
  233. datalab/data/icons/processing/swap_x_y.svg +65 -0
  234. datalab/data/icons/processing/thresholding.svg +63 -0
  235. datalab/data/icons/processing/windowing.svg +45 -0
  236. datalab/data/icons/properties.svg +26 -0
  237. datalab/data/icons/reset.svg +9 -0
  238. datalab/data/icons/restore.svg +40 -0
  239. datalab/data/icons/roi/roi.svg +76 -0
  240. datalab/data/icons/roi/roi_coordinate.svg +78 -0
  241. datalab/data/icons/roi/roi_copy.svg +112 -0
  242. datalab/data/icons/roi/roi_delete.svg +81 -0
  243. datalab/data/icons/roi/roi_export.svg +87 -0
  244. datalab/data/icons/roi/roi_graphical.svg +78 -0
  245. datalab/data/icons/roi/roi_grid.svg +67 -0
  246. datalab/data/icons/roi/roi_ima.svg +188 -0
  247. datalab/data/icons/roi/roi_import.svg +87 -0
  248. datalab/data/icons/roi/roi_new.svg +81 -0
  249. datalab/data/icons/roi/roi_new_circle.svg +95 -0
  250. datalab/data/icons/roi/roi_new_polygon.svg +110 -0
  251. datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
  252. datalab/data/icons/roi/roi_paste.svg +98 -0
  253. datalab/data/icons/roi/roi_sig.svg +124 -0
  254. datalab/data/icons/shapes.svg +134 -0
  255. datalab/data/icons/signal.svg +103 -0
  256. datalab/data/icons/table.svg +85 -0
  257. datalab/data/icons/table_unavailable.svg +102 -0
  258. datalab/data/icons/to_signal.svg +124 -0
  259. datalab/data/icons/tour/next.svg +44 -0
  260. datalab/data/icons/tour/previous.svg +44 -0
  261. datalab/data/icons/tour/rewind.svg +51 -0
  262. datalab/data/icons/tour/stop.svg +47 -0
  263. datalab/data/icons/tour/tour.svg +16 -0
  264. datalab/data/icons/uncheck_all.svg +78 -0
  265. datalab/data/icons/view/curve_antialiasing.svg +50 -0
  266. datalab/data/icons/view/new_window.svg +98 -0
  267. datalab/data/icons/view/refresh-auto.svg +57 -0
  268. datalab/data/icons/view/refresh-manual.svg +51 -0
  269. datalab/data/icons/view/reset_curve_styles.svg +96 -0
  270. datalab/data/icons/view/show_first.svg +55 -0
  271. datalab/data/icons/view/show_titles.svg +46 -0
  272. datalab/data/icons/visualization.svg +51 -0
  273. datalab/data/logo/DataLab-Banner-150.png +0 -0
  274. datalab/data/logo/DataLab-Banner-200.png +0 -0
  275. datalab/data/logo/DataLab-Banner2-100.png +0 -0
  276. datalab/data/logo/DataLab-Splash.png +0 -0
  277. datalab/data/logo/DataLab-watermark.png +0 -0
  278. datalab/data/logo/DataLab.svg +83 -0
  279. datalab/data/tests/reordering_test.h5 +0 -0
  280. datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
  281. datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
  282. datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
  283. datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
  284. datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
  285. datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
  286. datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
  287. datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
  288. datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
  289. datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
  290. datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
  291. datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
  292. datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
  293. datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
  294. datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
  295. datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
  296. datalab/env.py +542 -0
  297. datalab/gui/__init__.py +89 -0
  298. datalab/gui/actionhandler.py +1701 -0
  299. datalab/gui/docks.py +473 -0
  300. datalab/gui/h5io.py +150 -0
  301. datalab/gui/macroeditor.py +310 -0
  302. datalab/gui/main.py +2081 -0
  303. datalab/gui/newobject.py +217 -0
  304. datalab/gui/objectview.py +766 -0
  305. datalab/gui/panel/__init__.py +48 -0
  306. datalab/gui/panel/base.py +3254 -0
  307. datalab/gui/panel/image.py +157 -0
  308. datalab/gui/panel/macro.py +607 -0
  309. datalab/gui/panel/signal.py +164 -0
  310. datalab/gui/plothandler.py +800 -0
  311. datalab/gui/processor/__init__.py +84 -0
  312. datalab/gui/processor/base.py +2456 -0
  313. datalab/gui/processor/catcher.py +75 -0
  314. datalab/gui/processor/image.py +1214 -0
  315. datalab/gui/processor/signal.py +755 -0
  316. datalab/gui/profiledialog.py +333 -0
  317. datalab/gui/roieditor.py +633 -0
  318. datalab/gui/roigrideditor.py +208 -0
  319. datalab/gui/settings.py +612 -0
  320. datalab/gui/tour.py +908 -0
  321. datalab/h5/__init__.py +12 -0
  322. datalab/h5/common.py +314 -0
  323. datalab/h5/generic.py +580 -0
  324. datalab/h5/native.py +39 -0
  325. datalab/h5/utils.py +95 -0
  326. datalab/objectmodel.py +640 -0
  327. datalab/plugins/_readme_.txt +9 -0
  328. datalab/plugins/datalab_imageformats.py +175 -0
  329. datalab/plugins/datalab_testdata.py +190 -0
  330. datalab/plugins.py +355 -0
  331. datalab/tests/__init__.py +199 -0
  332. datalab/tests/backbone/__init__.py +1 -0
  333. datalab/tests/backbone/config_unit_test.py +170 -0
  334. datalab/tests/backbone/config_versioning_unit_test.py +34 -0
  335. datalab/tests/backbone/dictlistserial_app_test.py +38 -0
  336. datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
  337. datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
  338. datalab/tests/backbone/execenv_unit.py +262 -0
  339. datalab/tests/backbone/loadtest_gdi.py +147 -0
  340. datalab/tests/backbone/long_callback.py +96 -0
  341. datalab/tests/backbone/main_app_test.py +137 -0
  342. datalab/tests/backbone/memory_leak.py +43 -0
  343. datalab/tests/backbone/procisolation1_unit.py +128 -0
  344. datalab/tests/backbone/procisolation2_unit.py +171 -0
  345. datalab/tests/backbone/procisolation_unit_test.py +22 -0
  346. datalab/tests/backbone/profiling_app.py +27 -0
  347. datalab/tests/backbone/strings_unit_test.py +65 -0
  348. datalab/tests/backbone/title_formatting_unit_test.py +82 -0
  349. datalab/tests/conftest.py +131 -0
  350. datalab/tests/features/__init__.py +1 -0
  351. datalab/tests/features/applauncher/__init__.py +1 -0
  352. datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
  353. datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
  354. datalab/tests/features/common/__init__.py +1 -0
  355. datalab/tests/features/common/add_metadata_app_test.py +134 -0
  356. datalab/tests/features/common/add_metadata_unit_test.py +267 -0
  357. datalab/tests/features/common/annotations_management_unit_test.py +152 -0
  358. datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
  359. datalab/tests/features/common/createobject_unit_test.py +50 -0
  360. datalab/tests/features/common/geometry_results_app_test.py +135 -0
  361. datalab/tests/features/common/interactive_processing_test.py +1109 -0
  362. datalab/tests/features/common/io_app_test.py +75 -0
  363. datalab/tests/features/common/large_results_app_test.py +187 -0
  364. datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
  365. datalab/tests/features/common/metadata_app_test.py +139 -0
  366. datalab/tests/features/common/metadata_io_unit_test.py +60 -0
  367. datalab/tests/features/common/misc_app_test.py +236 -0
  368. datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
  369. datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
  370. datalab/tests/features/common/operation_modes_app_test.py +392 -0
  371. datalab/tests/features/common/plot_results_app_test.py +278 -0
  372. datalab/tests/features/common/reorder_app_test.py +75 -0
  373. datalab/tests/features/common/result_deletion_unit_test.py +96 -0
  374. datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
  375. datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
  376. datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
  377. datalab/tests/features/common/roieditor_unit_test.py +102 -0
  378. datalab/tests/features/common/save_to_dir_app_test.py +163 -0
  379. datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
  380. datalab/tests/features/common/stat_app_test.py +40 -0
  381. datalab/tests/features/common/stats_tools_unit_test.py +77 -0
  382. datalab/tests/features/common/table_results_app_test.py +52 -0
  383. datalab/tests/features/common/textimport_unit_test.py +131 -0
  384. datalab/tests/features/common/uuid_preservation_test.py +281 -0
  385. datalab/tests/features/common/worker_unit_test.py +402 -0
  386. datalab/tests/features/control/__init__.py +1 -0
  387. datalab/tests/features/control/connect_dialog.py +28 -0
  388. datalab/tests/features/control/embedded1_unit_test.py +304 -0
  389. datalab/tests/features/control/embedded2_unit_test.py +52 -0
  390. datalab/tests/features/control/remoteclient_app_test.py +219 -0
  391. datalab/tests/features/control/remoteclient_unit.py +75 -0
  392. datalab/tests/features/control/simpleclient_unit_test.py +321 -0
  393. datalab/tests/features/hdf5/__init__.py +1 -0
  394. datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
  395. datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
  396. datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
  397. datalab/tests/features/hdf5/h5import_app_test.py +25 -0
  398. datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
  399. datalab/tests/features/image/__init__.py +1 -0
  400. datalab/tests/features/image/annotations_app_test.py +28 -0
  401. datalab/tests/features/image/annotations_unit_test.py +80 -0
  402. datalab/tests/features/image/average_app_test.py +46 -0
  403. datalab/tests/features/image/background_dialog_test.py +70 -0
  404. datalab/tests/features/image/blobs_app_test.py +50 -0
  405. datalab/tests/features/image/contour_app_test.py +42 -0
  406. datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
  407. datalab/tests/features/image/denoise_app_test.py +31 -0
  408. datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
  409. datalab/tests/features/image/edges_app_test.py +31 -0
  410. datalab/tests/features/image/erase_app_test.py +21 -0
  411. datalab/tests/features/image/fft2d_app_test.py +27 -0
  412. datalab/tests/features/image/flatfield_app_test.py +40 -0
  413. datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
  414. datalab/tests/features/image/imagetools_app_test.py +51 -0
  415. datalab/tests/features/image/imagetools_unit_test.py +27 -0
  416. datalab/tests/features/image/load_app_test.py +73 -0
  417. datalab/tests/features/image/morph_app_test.py +32 -0
  418. datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
  419. datalab/tests/features/image/peak2d_app_test.py +53 -0
  420. datalab/tests/features/image/profile_app_test.py +73 -0
  421. datalab/tests/features/image/profile_dialog_test.py +56 -0
  422. datalab/tests/features/image/roi_app_test.py +98 -0
  423. datalab/tests/features/image/roi_circ_app_test.py +62 -0
  424. datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
  425. datalab/tests/features/image/roigrid_unit_test.py +60 -0
  426. datalab/tests/features/image/side_by_side_app_test.py +52 -0
  427. datalab/tests/features/macro/__init__.py +1 -0
  428. datalab/tests/features/macro/macro_app_test.py +28 -0
  429. datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
  430. datalab/tests/features/signal/__init__.py +1 -0
  431. datalab/tests/features/signal/baseline_dialog_test.py +53 -0
  432. datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
  433. datalab/tests/features/signal/fft1d_app_test.py +26 -0
  434. datalab/tests/features/signal/filter_app_test.py +44 -0
  435. datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
  436. datalab/tests/features/signal/interpolation_app_test.py +110 -0
  437. datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
  438. datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
  439. datalab/tests/features/signal/pulse_features_app_test.py +118 -0
  440. datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
  441. datalab/tests/features/signal/roi_app_test.py +78 -0
  442. datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
  443. datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
  444. datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
  445. datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
  446. datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
  447. datalab/tests/features/tour_unit_test.py +22 -0
  448. datalab/tests/features/utilities/__init__.py +1 -0
  449. datalab/tests/features/utilities/installconf_unit_test.py +21 -0
  450. datalab/tests/features/utilities/logview_app_test.py +21 -0
  451. datalab/tests/features/utilities/logview_error.py +24 -0
  452. datalab/tests/features/utilities/logview_unit_test.py +21 -0
  453. datalab/tests/features/utilities/memstatus_app_test.py +42 -0
  454. datalab/tests/features/utilities/settings_unit_test.py +88 -0
  455. datalab/tests/scenarios/__init__.py +1 -0
  456. datalab/tests/scenarios/beautiful_app.py +121 -0
  457. datalab/tests/scenarios/common.py +463 -0
  458. datalab/tests/scenarios/demo.py +212 -0
  459. datalab/tests/scenarios/example_app_test.py +47 -0
  460. datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
  461. datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
  462. datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
  463. datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
  464. datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
  465. datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
  466. datalab/utils/__init__.py +1 -0
  467. datalab/utils/conf.py +304 -0
  468. datalab/utils/dephash.py +105 -0
  469. datalab/utils/qthelpers.py +633 -0
  470. datalab/utils/strings.py +34 -0
  471. datalab/utils/tests.py +0 -0
  472. datalab/widgets/__init__.py +1 -0
  473. datalab/widgets/connection.py +138 -0
  474. datalab/widgets/filedialog.py +91 -0
  475. datalab/widgets/fileviewer.py +84 -0
  476. datalab/widgets/fitdialog.py +788 -0
  477. datalab/widgets/h5browser.py +1048 -0
  478. datalab/widgets/imagebackground.py +111 -0
  479. datalab/widgets/instconfviewer.py +175 -0
  480. datalab/widgets/logviewer.py +80 -0
  481. datalab/widgets/signalbaseline.py +90 -0
  482. datalab/widgets/signalcursor.py +208 -0
  483. datalab/widgets/signaldeltax.py +151 -0
  484. datalab/widgets/signalpeak.py +199 -0
  485. datalab/widgets/status.py +249 -0
  486. datalab/widgets/textimport.py +786 -0
  487. datalab/widgets/warningerror.py +223 -0
  488. datalab/widgets/wizard.py +286 -0
  489. datalab_platform-1.0.0.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.0.dist-info/RECORD +494 -0
  491. datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
  492. datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
  493. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/top_level.txt +0 -0
datalab/gui/tour.py ADDED
@@ -0,0 +1,908 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
4
+
5
+ """
6
+ Tour
7
+ ====
8
+
9
+ The :mod:`datalab.gui.tour` module implements a tour of DataLab features.
10
+
11
+ A dialog box is displayed when the user launches DataLab for the first time or
12
+ when the user clicks on the "Show tour" entry in the "?" menu.
13
+
14
+ The tour user experience is the following:
15
+
16
+ - First, the DataLab main window is maximized, and it is grayed out (the whole window
17
+ is covered with a gray area with an opacity of 50%). The user can not interact with
18
+ the DataLab main window while the tour is running.
19
+
20
+ - A first modal dialog box is displayed with a short description of DataLab, and two
21
+ buttons: "Start" and "Close". If the user clicks on "Start", the tour
22
+ starts. If the user clicks on "Close", the tour is not started and the dialog box
23
+ is closed.
24
+
25
+ - The tour is composed of several steps. Each step is a modal dialog box with a short
26
+ description of a DataLab feature, and three buttons: "Previous", "Next" and "Close".
27
+ If the user clicks on "Previous", the previous step is displayed. If the user clicks
28
+ on "Next", the next step is displayed. If the user clicks on "Close", the tour is
29
+ stopped and the dialog box is closed.
30
+
31
+ - At each step, the dialog box is moved to the center of the DataLab main window (i.e.
32
+ the center of the screen), and the feature described in the step is highlighted in
33
+ the DataLab main window. The highlight is a red rectangle around the feature, and
34
+ the feature is the only part of the DataLab main window that is not grayed out.
35
+
36
+ - The last step of the tour is a modal dialog box with a conclusion message and two
37
+ buttons: "Show tour again", "Close", and "Show demo". If the user clicks on "Show
38
+ tour again", the tour starts again. If the user clicks on "Close", the tour is
39
+ stopped and the dialog box is closed. If the user clicks on "Show demo", the demo
40
+ is started.
41
+
42
+ .. autoclass:: Tour
43
+ :members:
44
+ :inherited-members:
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ import abc
50
+ import enum
51
+ import os
52
+ from collections.abc import Callable
53
+ from typing import TYPE_CHECKING
54
+
55
+ import numpy as np
56
+ from guidata.configtools import get_icon, get_image_file_path
57
+ from guidata.qthelpers import is_dark_theme
58
+ from qtpy import QtCore as QC
59
+ from qtpy import QtGui as QG
60
+ from qtpy import QtWidgets as QW
61
+ from sigima.objects import create_image, create_signal
62
+
63
+ from datalab.config import _
64
+ from datalab.env import execenv
65
+
66
+ if TYPE_CHECKING:
67
+ from datalab.gui.main import DLMainWindow
68
+
69
+
70
+ class Cover(QW.QWidget):
71
+ """
72
+ Widget that covers the main window with a gray area with an opacity of 50%.
73
+ """
74
+
75
+ def __init__(self, parent: DLMainWindow) -> None:
76
+ super().__init__(parent)
77
+ self.setWindowFlags(QC.Qt.Tool | QC.Qt.FramelessWindowHint)
78
+ self.setAttribute(QC.Qt.WA_TranslucentBackground)
79
+ self.__opacity_factor = 1.0
80
+ # Widgets to be excluded from the grayed out area:
81
+ self.__excluded_widgets: list[QW.QWidget] | None = None
82
+ # Path to be grayed out:
83
+ self.__path: QG.QPainterPath = QG.QPainterPath()
84
+
85
+ def set_opacity_factor(self, opacity_factor: float) -> None:
86
+ """
87
+ Set the opacity factor of the grayed out area.
88
+
89
+ Args:
90
+ opacity_factor: Opacity factor.
91
+ """
92
+ self.__opacity_factor = opacity_factor
93
+
94
+ def exclude(self, widgets: list[QW.QWidget]) -> None:
95
+ """
96
+ Exclude widgets from the grayed out area.
97
+
98
+ Args:
99
+ widgets: Widgets to be excluded.
100
+ """
101
+ self.__excluded_widgets = widgets
102
+
103
+ def update_geometry(self) -> None:
104
+ """
105
+ Update the geometry of the widget.
106
+ """
107
+ if os.name == "nt":
108
+ QW.QApplication.processEvents()
109
+ self.setGeometry(self.parentWidget().geometry())
110
+ self.__path = QG.QPainterPath()
111
+ # Path is defined as the rectangle of the main window minus the rectangles of
112
+ # the excluded widgets:
113
+ self.__path.addRect(QC.QRectF(self.parentWidget().rect()))
114
+ if self.__excluded_widgets is not None:
115
+ for widget in self.__excluded_widgets:
116
+ widget.raise_()
117
+ widget.show()
118
+ geometry = widget.frameGeometry()
119
+ width, height = geometry.width(), geometry.height()
120
+ point = widget.mapTo(self.parentWidget(), QC.QPoint(0, 0))
121
+ x, y = point.x(), point.y()
122
+ widget_path = QG.QPainterPath()
123
+ widget_path.addRect(QC.QRectF(x, y, width, height))
124
+ self.__path -= QG.QPainterPath(widget_path)
125
+ self.repaint()
126
+
127
+ def showEvent(self, a0: QG.QShowEvent | None) -> None:
128
+ """
129
+ Event handler for the "show" event.
130
+
131
+ Args:
132
+ a0: Show event.
133
+ """
134
+ super().showEvent(a0)
135
+ self.setGeometry(self.parentWidget().geometry())
136
+
137
+ def paintEvent(self, event: QG.QPaintEvent) -> None:
138
+ """
139
+ Event handler for the "paint" event.
140
+
141
+ Args:
142
+ event: Paint event.
143
+ """
144
+ super().paintEvent(event)
145
+ painter = QG.QPainter(self)
146
+ painter.setOpacity((0.75 if is_dark_theme() else 0.5) * self.__opacity_factor)
147
+ painter.setBrush(QG.QBrush(QC.Qt.black))
148
+ painter.setPen(QC.Qt.NoPen)
149
+ painter.drawPath(self.__path)
150
+
151
+
152
+ class StepResult(enum.Enum):
153
+ """
154
+ Result of a step.
155
+ """
156
+
157
+ PREVIOUS = enum.auto()
158
+ NEXT = enum.auto()
159
+ CLOSE = enum.auto()
160
+ DEMO = enum.auto()
161
+ RESTART = enum.auto()
162
+
163
+
164
+ class StepDialog(QW.QDialog):
165
+ """
166
+ Base class for tour dialog boxes.
167
+
168
+ Args:
169
+ parent: Parent widget.
170
+ step: Tour step.
171
+ """
172
+
173
+ def __init__(
174
+ self,
175
+ parent: QW.QWidget,
176
+ step: TourStep,
177
+ ) -> None:
178
+ super().__init__(parent)
179
+ self.setWindowTitle(step.title)
180
+ self.setWindowFlags(QC.Qt.Popup)
181
+ self.setModal(True)
182
+ self.step = step
183
+ self.result: StepResult | None = None
184
+ self.__btnmap: dict[QW.QPushButton, StepResult] = {}
185
+ self.__btnlayout = QW.QHBoxLayout()
186
+ self._setup_ui()
187
+
188
+ def __btn(self, text: str, result: StepResult, default: bool = False) -> None:
189
+ """
190
+ Create a button.
191
+
192
+ Args:
193
+ text: Button text.
194
+ result: Result of the button.
195
+ default: Default button. Defaults to False.
196
+ """
197
+ btn = QW.QPushButton(text)
198
+ btn.setAutoDefault(default)
199
+ btn.setDefault(default)
200
+ icon = {
201
+ "<<": "rewind.svg",
202
+ "<": "previous.svg",
203
+ ">": "next.svg",
204
+ "X": "stop.svg",
205
+ }.get(text)
206
+ if icon is not None:
207
+ btn.setIcon(get_icon(icon))
208
+ btn.setText("")
209
+ btn.setMinimumWidth(100)
210
+ btn.clicked.connect(lambda: self.button_clicked(btn))
211
+ self.__btnmap[btn] = result
212
+ self.__btnlayout.addWidget(btn)
213
+
214
+ def __btn_spacing(self, spacing: int) -> None:
215
+ """
216
+ Add spacing between buttons.
217
+
218
+ Args:
219
+ spacing: Spacing.
220
+ """
221
+ self.__btnlayout.addSpacing(spacing)
222
+
223
+ def __create_label(
224
+ self,
225
+ text: str,
226
+ delta_fontsize: int,
227
+ color: QC.Qt.GlobalColor,
228
+ bold: bool = False,
229
+ ) -> QW.QLabel:
230
+ """
231
+ Create a label.
232
+
233
+ Args:
234
+ text: Label text.
235
+ delta_fontsize: Delta font size.
236
+ color: Text color.
237
+ bold: Bold text.
238
+
239
+ Returns:
240
+ Label.
241
+ """
242
+ label = QW.QLabel(text)
243
+ label.setWordWrap(True)
244
+ label.setAlignment(QC.Qt.AlignCenter)
245
+ # Change font size for something bigger:
246
+ font = label.font()
247
+ font.setPointSize(font.pointSize() + delta_fontsize)
248
+ label.setFont(font)
249
+ # Set text color:
250
+ palette = label.palette()
251
+ palette.setColor(QG.QPalette.WindowText, color)
252
+ label.setPalette(palette)
253
+ # Set bold text:
254
+ font = label.font()
255
+ font.setBold(bold)
256
+ return label
257
+
258
+ def __create_horizontal_line(self) -> QW.QFrame:
259
+ """
260
+ Create a horizontal line.
261
+
262
+ Returns:
263
+ Horizontal line.
264
+ """
265
+ line = QW.QFrame()
266
+ line.setFrameShape(QW.QFrame.HLine)
267
+ line.setFrameShadow(QW.QFrame.Sunken)
268
+ line.setLineWidth(1)
269
+ line.setMidLineWidth(0)
270
+ palette = line.palette()
271
+ palette.setColor(QG.QPalette.WindowText, QC.Qt.lightGray)
272
+ line.setPalette(palette)
273
+ return line
274
+
275
+ def _setup_ui(self) -> None:
276
+ """
277
+ Setup the user interface.
278
+ """
279
+ if self.step.step_type == "introduction":
280
+ self.__btn_spacing(50)
281
+ self.__btn(_("Start"), StepResult.NEXT, True)
282
+ self.__btn(_("Close"), StepResult.CLOSE)
283
+ self.__btn_spacing(50)
284
+ elif self.step.step_type == "conclusion":
285
+ self.__btn("<<", StepResult.RESTART)
286
+ self.__btn("<", StepResult.PREVIOUS)
287
+ self.__btn(_("Demo"), StepResult.DEMO)
288
+ self.__btn("X", StepResult.CLOSE, True)
289
+ else:
290
+ self.__btn("<<", StepResult.RESTART)
291
+ self.__btn("<", StepResult.PREVIOUS)
292
+ self.__btn(">", StepResult.NEXT, True)
293
+ self.__btn("X", StepResult.CLOSE)
294
+ self._layout = QW.QVBoxLayout()
295
+ if self.step.step_type in ("introduction", "conclusion"):
296
+ logo = QW.QLabel()
297
+ logo.setPixmap(QG.QPixmap(get_image_file_path("DataLab-Banner2-100.png")))
298
+ logo.setAlignment(QC.Qt.AlignCenter)
299
+ self._layout.addWidget(logo)
300
+ title_color = QC.Qt.lightGray if is_dark_theme() else QC.Qt.darkGray
301
+ title = self.__create_label(self.step.title, 1, title_color, True)
302
+ self._layout.addWidget(title)
303
+ self._layout.addWidget(self.__create_horizontal_line())
304
+ label_color = QC.Qt.cyan if is_dark_theme() else QC.Qt.darkBlue
305
+ label_dsize = 3 if self.step.step_type == "regular" else 4
306
+ label = self.__create_label(self.step.text, label_dsize, label_color)
307
+ if self.step.step_type == "regular":
308
+ label.setAlignment(QC.Qt.AlignLeft)
309
+ self._layout.addWidget(label)
310
+ self._layout.addSpacing(5)
311
+ self._layout.addLayout(self.__btnlayout)
312
+ if self.step.step_type == "introduction":
313
+ self._layout.addSpacing(5)
314
+ help_text = _(
315
+ "Hit <b>Enter</b> to continue to the next step, or "
316
+ "<b>Esc</b> to close the tour."
317
+ )
318
+ help_label = self.__create_label(help_text, -1, title_color)
319
+ help_label.setAlignment(QC.Qt.AlignLeft)
320
+ self._layout.addWidget(help_label)
321
+ self.setLayout(self._layout)
322
+
323
+ def button_clicked(self, button: QW.QPushButton) -> None:
324
+ """
325
+ Event handler for the "clicked" event on the buttons.
326
+
327
+ Args:
328
+ button: Button that was clicked.
329
+ """
330
+ self.result = self.__btnmap[button]
331
+ if self.result is StepResult.CLOSE:
332
+ self.reject()
333
+ else:
334
+ self.accept()
335
+
336
+ def reject(self) -> None:
337
+ """
338
+ Event handler for the "reject" event.
339
+ """
340
+ self.result = StepResult.CLOSE
341
+ super().reject()
342
+
343
+ def paintEvent(self, event: QG.QPaintEvent) -> None:
344
+ """
345
+ Event handler for the "paint" event.
346
+
347
+ Args:
348
+ event: Paint event.
349
+ """
350
+ super().paintEvent(event)
351
+ painter = QG.QPainter(self)
352
+ painter.setOpacity(0.5)
353
+ painter.setBrush(QG.QBrush(QC.Qt.black))
354
+ painter.setPen(QC.Qt.NoPen)
355
+
356
+
357
+ class TourStep:
358
+ """
359
+ Tour step.
360
+
361
+ Args:
362
+ tour: Tour.
363
+ title: Step title.
364
+ text: Step text.
365
+ widgets: Widgets to be highlighted. If None, no widget is highlighted, meaning
366
+ that the step is probably an introduction or a conclusion.
367
+ setup_callback: Callback function to be called before the step is displayed,
368
+ which takes a single argument, the `DLMainWindow` instance.
369
+ teardown_callback: Callback function to be called after the step is displayed,
370
+ which takes a single argument, the `DLMainWindow` instance.
371
+ step_type: Step type. Can be "regular", "introduction" or "conclusion".
372
+ """
373
+
374
+ def __init__(
375
+ self,
376
+ tour: BaseTour,
377
+ title: str,
378
+ text: str,
379
+ widgets: list[QW.QWidget] | None = None,
380
+ setup_callback: Callable | None = None,
381
+ teardown_callback: Callable | None = None,
382
+ step_type: str = "regular",
383
+ ) -> None:
384
+ self.tour = tour
385
+ self.title = title
386
+ self.text = text
387
+ self.widgets = widgets
388
+ self.setup_callback = setup_callback
389
+ self.teardown_callback = teardown_callback
390
+ self.step_type = step_type
391
+ assert step_type in ["regular", "introduction", "conclusion"]
392
+
393
+ def show(self) -> StepResult:
394
+ """
395
+ Show the step.
396
+
397
+ Returns:
398
+ Result of the step.
399
+ """
400
+ if self.setup_callback is not None:
401
+ self.setup_callback(self.tour.win)
402
+ self.update_cover(self.tour.cover)
403
+ dialog = StepDialog(self.tour.win, self)
404
+ if not execenv.unattended:
405
+ dialog.exec()
406
+ elif self.step_type != "conclusion":
407
+ dialog.result = StepResult.NEXT
408
+ dialog.accept()
409
+ else:
410
+ dialog.result = StepResult.CLOSE
411
+ dialog.reject()
412
+ if self.teardown_callback is not None:
413
+ self.teardown_callback(self.tour.win)
414
+ return dialog.result
415
+
416
+ def update_cover(self, cover: Cover) -> None:
417
+ """
418
+ Update the cover widget.
419
+
420
+ Args:
421
+ cover: Cover widget.
422
+ """
423
+ cover.set_opacity_factor(1.0 if self.step_type == "regular" else 0.7)
424
+ cover.exclude(self.widgets)
425
+ cover.update_geometry()
426
+
427
+
428
+ class BaseTourMeta(type(QW.QWidget), abc.ABCMeta):
429
+ """Mixed metaclass to avoid conflicts"""
430
+
431
+
432
+ class BaseTour(QW.QWidget, metaclass=BaseTourMeta):
433
+ """
434
+ Base class for the tour of DataLab features.
435
+
436
+ Args:
437
+ win: DataLab main window.
438
+ """
439
+
440
+ def __init__(self, win: DLMainWindow) -> None:
441
+ super().__init__(win)
442
+ self.win = win
443
+ self._steps: list[TourStep] = []
444
+ self._current_step = 0
445
+ self.cover = Cover(win)
446
+ self.cover.show()
447
+ self.__window_geometry: tuple[tuple[int, int], tuple[int, int]] | None = None
448
+ self.__window_prepared = False
449
+ self.setup_tour(win)
450
+
451
+ def __resize_window(self, factor: float) -> None:
452
+ """
453
+ Resize the window so that it is centered on the screen and its size is
454
+ `factor` times the size of the screen.
455
+
456
+ Args:
457
+ factor: Factor by which the size of the window is multiplied.
458
+ """
459
+ desktop = QW.QApplication.desktop()
460
+ screen = desktop.screenNumber(desktop.cursor().pos())
461
+ screen_geometry = desktop.screenGeometry(screen)
462
+ width = int(screen_geometry.width() * factor)
463
+ height = int(screen_geometry.height() * factor)
464
+ self.win.resize(width, height)
465
+ self.win.move(screen_geometry.center() - QC.QPoint(width // 2, height // 2))
466
+
467
+ def __save_window_geometry(self) -> None:
468
+ """Save the window geometry (size and position)."""
469
+ self.__window_geometry = self.win.saveGeometry()
470
+
471
+ def __restore_window_geometry(self) -> None:
472
+ """Restore the window geometry (size and position)."""
473
+ if self.__window_geometry is not None:
474
+ self.win.restoreGeometry(self.__window_geometry)
475
+
476
+ @abc.abstractmethod
477
+ def setup_tour(self, win: DLMainWindow) -> None:
478
+ """
479
+ Setup the tour: add steps to the tour.
480
+ """
481
+
482
+ @abc.abstractmethod
483
+ def cleanup_tour(self, win: DLMainWindow) -> None:
484
+ """
485
+ Cleanup the tour.
486
+ """
487
+
488
+ def add_step(
489
+ self,
490
+ title: str,
491
+ text: str,
492
+ widgets: list[QW.QWidget] | None = None,
493
+ setup_callback: Callable | None = None,
494
+ teardown_callback: Callable | None = None,
495
+ step_type: str | None = None,
496
+ ) -> None:
497
+ """
498
+ Add a step to the tour.
499
+
500
+ Args:
501
+ title: Step title.
502
+ text: Step text.
503
+ widgets: Widgets to be highlighted. If None, no widget is highlighted,
504
+ meaning that the step is probably an introduction or a conclusion.
505
+ setup_callback: Callback function to be called before the step is displayed,
506
+ which takes a single argument, the `DLMainWindow` instance.
507
+ teardown_callback: Callback function to be called after the step is
508
+ displayed, which takes a single argument, the `DLMainWindow` instance.
509
+ step_type: Step type. Can be "regular", "introduction" or "conclusion".
510
+ Defaults to None.
511
+ """
512
+ if step_type is None:
513
+ if self._steps:
514
+ step_type = "regular"
515
+ else:
516
+ step_type = "introduction"
517
+ step = TourStep(
518
+ self, title, text, widgets, setup_callback, teardown_callback, step_type
519
+ )
520
+ self._steps.append(step)
521
+
522
+ def show_current_step(self) -> None:
523
+ """
524
+ Show the current step.
525
+ """
526
+ step = self._steps[self._current_step]
527
+ result = step.show()
528
+ if result is StepResult.PREVIOUS:
529
+ self.previous_step()
530
+ elif result is StepResult.NEXT:
531
+ self.next_step()
532
+ elif result is StepResult.CLOSE:
533
+ self.end()
534
+ elif result is StepResult.DEMO:
535
+ self.end()
536
+ # pylint: disable=import-outside-toplevel
537
+ from datalab.tests.scenarios import demo
538
+
539
+ demo.play_demo(self.win)
540
+ elif result is StepResult.RESTART:
541
+ self.start()
542
+ else:
543
+ raise RuntimeError(f"Unknown result: {result}")
544
+
545
+ def start(self) -> None:
546
+ """
547
+ Start the tour.
548
+ """
549
+ self._current_step = 0
550
+ self.show_current_step()
551
+
552
+ def end(self) -> None:
553
+ """
554
+ End the tour.
555
+ """
556
+ self.cover.close()
557
+ self.cleanup_tour(self.win)
558
+ self.__restore_window_geometry()
559
+
560
+ def next_step(self) -> None:
561
+ """
562
+ Go to the next step.
563
+ """
564
+ if self._current_step == 0 and not self.__window_prepared:
565
+ self.__save_window_geometry()
566
+ self.__resize_window(0.7)
567
+ self.cover.update_geometry()
568
+ self.__window_prepared = True
569
+ self._current_step += 1
570
+ self.show_current_step()
571
+
572
+ def previous_step(self) -> None:
573
+ """
574
+ Go to the previous step.
575
+ """
576
+ self._current_step -= 1
577
+ self.show_current_step()
578
+
579
+
580
+ class Tour(BaseTour):
581
+ """
582
+ Tour of DataLab features.
583
+
584
+ Args:
585
+ win: DataLab main window.
586
+ """
587
+
588
+ def prepare_signalpanel(self, win: DLMainWindow) -> None:
589
+ """
590
+ Prepare the signal panel.
591
+
592
+ Args:
593
+ win: DataLab main window.
594
+ """
595
+ # Create a signal:
596
+ x = np.linspace(0, 10, 100)
597
+ y = np.sin(x)
598
+ sig = create_signal(_("Test signal, for the tour"), x, y)
599
+ win.add_object(sig)
600
+ win.set_current_panel("signal")
601
+
602
+ def prepare_imagepanel(self, win: DLMainWindow) -> None:
603
+ """
604
+ Prepare the image panel.
605
+
606
+ Args:
607
+ win: DataLab main window.
608
+ """
609
+ # Create an image:
610
+ x = np.linspace(0, 10, 100)
611
+ y = np.linspace(0, 10, 100)
612
+ xx, yy = np.meshgrid(x, y)
613
+ zz = np.sin(xx) * np.cos(yy)
614
+ img = create_image(_("Test image, for the tour"), zz)
615
+ win.add_object(img)
616
+ win.set_current_panel("image")
617
+
618
+ def popup_menu(self, win: DLMainWindow, menu: QW.QMenu) -> None:
619
+ """
620
+ Popup a menu.
621
+
622
+ Args:
623
+ win: DataLab main window.
624
+ menu_name: Name of the menu to popup.
625
+ """
626
+ menu.popup(win.mapToGlobal(QC.QPoint(50, 50)))
627
+
628
+ def cleanup_tour(self, win: DLMainWindow) -> None:
629
+ """
630
+ Cleanup the tour.
631
+
632
+ Args:
633
+ win: DataLab main window.
634
+ """
635
+ if len(win.signalpanel.objmodel) == 1:
636
+ win.signalpanel.remove_all_objects()
637
+ else:
638
+ win.signalpanel.remove_object()
639
+ if len(win.imagepanel.objmodel) == 1:
640
+ win.imagepanel.remove_all_objects()
641
+ else:
642
+ win.imagepanel.remove_object()
643
+
644
+ def setup_tour(self, win: DLMainWindow) -> None:
645
+ """
646
+ Setup the tour: add steps to the tour.
647
+ """
648
+ self.add_step(
649
+ _("Welcome to DataLab!"),
650
+ _("This tour will guide you through the main features of DataLab."),
651
+ )
652
+ self.add_step(
653
+ _("DataLab main window"),
654
+ _(
655
+ "This is the main window of DataLab. It is composed of several parts "
656
+ "that we will describe in the following steps."
657
+ ),
658
+ )
659
+ self.add_step(
660
+ _("DataLab main window"),
661
+ _(
662
+ "Menus and toolbars regroup the main actions that can be performed "
663
+ "in DataLab. Their content is adapted to the current panel, as we "
664
+ "will see in the following steps."
665
+ ),
666
+ [
667
+ win.menuBar(),
668
+ win.main_toolbar,
669
+ win.signalpanel_toolbar,
670
+ win.imagepanel_toolbar,
671
+ win.signalpanel.acthandler.view_toolbar,
672
+ win.imagepanel.acthandler.view_toolbar,
673
+ ],
674
+ )
675
+ self.add_step(
676
+ _("DataLab main window"),
677
+ _(
678
+ "The main window is composed of two main panels: the Signal Panel, "
679
+ "and the Image Panel.<br>"
680
+ "Switching between panels is done using the highlighted tabs."
681
+ ),
682
+ [win.tabwidget.tabBar()],
683
+ )
684
+ self.add_step(
685
+ _("Signal Panel"),
686
+ _(
687
+ "The <b>Signal Panel</b> is used to manage 1D signals."
688
+ "It is composed of the elements shown in the following steps."
689
+ ),
690
+ )
691
+ self.add_step(
692
+ _("Signal Panel") + " – " + _("List and properties"),
693
+ _(
694
+ "In the highlighted area, signals are listed at the top, and their "
695
+ "properties may be displayed and edited at the bottom.<br><br>"
696
+ "Signals are numbered (but may be reorganized) and put together in "
697
+ "numbered groups."
698
+ ),
699
+ [win.tabwidget.tabBar(), win.signalpanel],
700
+ self.prepare_signalpanel,
701
+ )
702
+ self.add_step(
703
+ _("Signal Panel") + " – " + _("View"),
704
+ _(
705
+ "Signals are plotted in the <b>Signal View</b>.<br><br>"
706
+ "Curves may be customized using context menus or the vertical "
707
+ "toolbar on the left (appearance settings are saved in the "
708
+ "signal metadata)."
709
+ ),
710
+ [win.docks[win.signalpanel]],
711
+ )
712
+ self.add_step(
713
+ _("Signal Panel") + " – " + _("File menu"),
714
+ _(
715
+ "The <b>File</b> menu contains actions to "
716
+ "import and export signals individually (various formats) or "
717
+ "to save or restore the whole workspace (HDF5 files)."
718
+ ),
719
+ [win.menuBar()],
720
+ lambda win: self.popup_menu(win, win.file_menu),
721
+ lambda win: win.file_menu.hide(),
722
+ )
723
+ self.add_step(
724
+ _("Signal Panel") + " – " + _("Create menu"),
725
+ _(
726
+ "The <b>Create</b> menu contains actions to create new signals "
727
+ "from various models (Gaussian, sine, etc.)."
728
+ ),
729
+ [win.menuBar()],
730
+ lambda win: self.popup_menu(win, win.create_menu),
731
+ lambda win: win.create_menu.hide(),
732
+ )
733
+ self.add_step(
734
+ _("Signal Panel") + " – " + _("Edit menu"),
735
+ _(
736
+ "The <b>Edit</b> menu contains actions to edit signals individually "
737
+ "or in groups."
738
+ ),
739
+ [win.menuBar()],
740
+ lambda win: self.popup_menu(win, win.edit_menu),
741
+ lambda win: win.edit_menu.hide(),
742
+ )
743
+ self.add_step(
744
+ _("Signal Panel") + " – " + _("Operations menu"),
745
+ _(
746
+ "The <b>Operations</b> menu is focused on arithmetic operations, "
747
+ "basic mathematical functions or data type conversions."
748
+ ),
749
+ [win.menuBar()],
750
+ lambda win: self.popup_menu(win, win.operation_menu),
751
+ lambda win: win.operation_menu.hide(),
752
+ )
753
+ self.add_step(
754
+ _("Signal Panel") + " – " + _("Processing menu"),
755
+ _("The <b>Processing</b> menu regroups 1->1 signal processing actions."),
756
+ [win.menuBar()],
757
+ lambda win: self.popup_menu(win, win.processing_menu),
758
+ lambda win: win.processing_menu.hide(),
759
+ )
760
+ self.add_step(
761
+ _("Signal Panel") + " – " + _("Analysis menu"),
762
+ _(
763
+ "The <b>Analysis</b> menu regroups 1->0 signal computing actions "
764
+ "(that is, actions that do not modify the signals, but compute "
765
+ "a result, e.g. scalar values), with optional ROI selection."
766
+ ),
767
+ [win.menuBar()],
768
+ lambda win: self.popup_menu(win, win.analysis_menu),
769
+ lambda win: win.analysis_menu.hide(),
770
+ )
771
+ self.add_step(
772
+ _("Image Panel"),
773
+ _(
774
+ "The <b>Image Panel</b> is used to manage 2D images. It is composed "
775
+ "of the elements shown in the following steps."
776
+ ),
777
+ [],
778
+ lambda win: win.set_current_panel("image"),
779
+ )
780
+ self.add_step(
781
+ _("Image Panel") + " – " + _("List and properties"),
782
+ _(
783
+ "In the highlighted area, images are listed at the top, and their "
784
+ "properties may be displayed and edited at the bottom.<br><br>"
785
+ "Images are numbered (but may be reorganized) and put together in "
786
+ "numbered groups."
787
+ ),
788
+ [win.tabwidget.tabBar(), win.imagepanel],
789
+ self.prepare_imagepanel,
790
+ )
791
+ self.add_step(
792
+ _("Image Panel") + " – " + _("View"),
793
+ _(
794
+ "Images are shown in the <b>Image View</b>.<br><br>"
795
+ "The displayed images may be customized using context menus "
796
+ "or the vertical toolbar on the left (appearance settings "
797
+ "are saved in the image metadata)."
798
+ ),
799
+ [win.docks[win.imagepanel]],
800
+ )
801
+ self.add_step(
802
+ _("Image Panel") + " – " + _("File menu"),
803
+ _(
804
+ "The <b>File</b> menu contains actions to "
805
+ "import and export images individually (various formats) or "
806
+ "to save or restore the whole workspace (HDF5 files)."
807
+ ),
808
+ [win.menuBar()],
809
+ lambda win: self.popup_menu(win, win.file_menu),
810
+ lambda win: win.file_menu.hide(),
811
+ )
812
+ self.add_step(
813
+ _("Image Panel") + " – " + _("Create menu"),
814
+ _(
815
+ "The <b>Create</b> menu contains actions to create new images "
816
+ "from various models (Gaussian, checkerboard, etc.)."
817
+ ),
818
+ [win.menuBar()],
819
+ lambda win: self.popup_menu(win, win.create_menu),
820
+ lambda win: win.create_menu.hide(),
821
+ )
822
+ self.add_step(
823
+ _("Image Panel") + " – " + _("Edit menu"),
824
+ _(
825
+ "The <b>Edit</b> menu contains actions to edit images individually "
826
+ "or in groups."
827
+ ),
828
+ [win.menuBar()],
829
+ lambda win: self.popup_menu(win, win.edit_menu),
830
+ lambda win: win.edit_menu.hide(),
831
+ )
832
+ self.add_step(
833
+ _("Image Panel") + " – " + _("Operations menu"),
834
+ _(
835
+ "The <b>Operations</b> menu is focused on arithmetic operations, "
836
+ "data type conversions, pixel binning resize, intensity profiles..."
837
+ ),
838
+ [win.menuBar()],
839
+ lambda win: self.popup_menu(win, win.operation_menu),
840
+ lambda win: win.operation_menu.hide(),
841
+ )
842
+ self.add_step(
843
+ _("Image Panel") + " – " + _("Processing menu"),
844
+ _(
845
+ "The <b>Processing</b> menu regroups 1->1 image processing actions "
846
+ "(that is, actions that modify the images)."
847
+ ),
848
+ [win.menuBar()],
849
+ lambda win: self.popup_menu(win, win.processing_menu),
850
+ lambda win: win.processing_menu.hide(),
851
+ )
852
+ self.add_step(
853
+ _("Image Panel") + " – " + _("Analysis menu"),
854
+ _(
855
+ "The <b>Analysis</b> menu regroups 1->0 image computing actions "
856
+ "(that is, actions that do not modify the images, but compute "
857
+ "a result, e.g. circle coordinates), with optional ROI selection."
858
+ ),
859
+ [win.menuBar()],
860
+ lambda win: self.popup_menu(win, win.analysis_menu),
861
+ lambda win: win.analysis_menu.hide(),
862
+ )
863
+ self.add_step(
864
+ _("Extensions"),
865
+ _(
866
+ "DataLab is designed to be easily extended with new features, "
867
+ "by using <b>Macros</b>, <b>Plugins</b> or <b>Remote Control</b>."
868
+ "<br><br>The common point between these mechanisms is that "
869
+ "they are all relying on Python scripts and the <i>DataLab API</i>."
870
+ ),
871
+ )
872
+ self.add_step(
873
+ _("Extensions") + " – " + _("Macros"),
874
+ _(
875
+ "The <b>Macro Panel</b> allows to create, edit and run macros.<br>"
876
+ "Macros are saved together with the DataLab workspace (HDF5 file)."
877
+ ),
878
+ [win.docks[win.macropanel]],
879
+ lambda win: win.set_current_panel("macro"),
880
+ lambda win: win.set_current_panel("signal"),
881
+ )
882
+ self.add_step(
883
+ _("Extensions") + " – " + _("Plugins"),
884
+ _(
885
+ "The <b>Plugins</b> menu regroups features that are not part of "
886
+ "the core of DataLab, but that are provided as plugins.<br>"
887
+ "(See the documentation for more information about plugins.)"
888
+ ),
889
+ [win.menuBar()],
890
+ lambda win: self.popup_menu(win, win.plugins_menu),
891
+ lambda win: win.plugins_menu.hide(),
892
+ )
893
+ self.add_step(
894
+ _("This is the end of the tour!"),
895
+ _("You can show the tour again, or close this dialog box."),
896
+ step_type="conclusion",
897
+ )
898
+
899
+
900
+ def start(win: DLMainWindow) -> None:
901
+ """
902
+ Start the tour of DataLab features.
903
+
904
+ Args:
905
+ win: DataLab main window.
906
+ """
907
+ tour = Tour(win)
908
+ tour.start()