PaIRS-UniNa 0.2.10__cp313-cp313-macosx_11_0_universal2.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 (333) hide show
  1. PaIRS_UniNa/Calibration_Tab.py +347 -0
  2. PaIRS_UniNa/Changes.txt +174 -0
  3. PaIRS_UniNa/Custom_Top.py +303 -0
  4. PaIRS_UniNa/Explorer.py +3322 -0
  5. PaIRS_UniNa/FolderLoop.py +562 -0
  6. PaIRS_UniNa/Input_Tab.py +829 -0
  7. PaIRS_UniNa/Input_Tab_CalVi.py +787 -0
  8. PaIRS_UniNa/Input_Tab_tools.py +3026 -0
  9. PaIRS_UniNa/Log_Tab.py +110 -0
  10. PaIRS_UniNa/Output_Tab.py +922 -0
  11. PaIRS_UniNa/PaIRS.py +18 -0
  12. PaIRS_UniNa/PaIRS_PIV.py +873 -0
  13. PaIRS_UniNa/PaIRS_pypacks.py +1374 -0
  14. PaIRS_UniNa/Process_Tab.py +1761 -0
  15. PaIRS_UniNa/Process_Tab_CalVi.py +313 -0
  16. PaIRS_UniNa/Process_Tab_Disp.py +170 -0
  17. PaIRS_UniNa/Process_Tab_Min.py +120 -0
  18. PaIRS_UniNa/ResizePopup.py +55 -0
  19. PaIRS_UniNa/SPIVCalHelp.py +155 -0
  20. PaIRS_UniNa/Saving_tools.py +298 -0
  21. PaIRS_UniNa/TabTools.py +1413 -0
  22. PaIRS_UniNa/Vis_Tab.py +2176 -0
  23. PaIRS_UniNa/Vis_Tab_CalVi.py +982 -0
  24. PaIRS_UniNa/Whatsnew.py +130 -0
  25. PaIRS_UniNa/_PaIRS_PIV.so +0 -0
  26. PaIRS_UniNa/__init__.py +6 -0
  27. PaIRS_UniNa/__main__.py +45 -0
  28. PaIRS_UniNa/addwidgets_ps.py +1633 -0
  29. PaIRS_UniNa/calib.py +1488 -0
  30. PaIRS_UniNa/calibView.py +833 -0
  31. PaIRS_UniNa/gPaIRS.py +3957 -0
  32. PaIRS_UniNa/gPalette.py +189 -0
  33. PaIRS_UniNa/icons/abort.png +0 -0
  34. PaIRS_UniNa/icons/about.png +0 -0
  35. PaIRS_UniNa/icons/align_all.png +0 -0
  36. PaIRS_UniNa/icons/announcement.png +0 -0
  37. PaIRS_UniNa/icons/automatic_levels_off.png +0 -0
  38. PaIRS_UniNa/icons/automatic_levels_on.png +0 -0
  39. PaIRS_UniNa/icons/automatic_off.png +0 -0
  40. PaIRS_UniNa/icons/automatic_on.png +0 -0
  41. PaIRS_UniNa/icons/automatic_size_off.png +0 -0
  42. PaIRS_UniNa/icons/automatic_size_on.png +0 -0
  43. PaIRS_UniNa/icons/axes.png +0 -0
  44. PaIRS_UniNa/icons/background.png +0 -0
  45. PaIRS_UniNa/icons/background_vectors.png +0 -0
  46. PaIRS_UniNa/icons/bin_off.png +0 -0
  47. PaIRS_UniNa/icons/bin_on.png +0 -0
  48. PaIRS_UniNa/icons/browse_file_c.png +0 -0
  49. PaIRS_UniNa/icons/browse_folder_c.png +0 -0
  50. PaIRS_UniNa/icons/brush_cursor.png +0 -0
  51. PaIRS_UniNa/icons/bugfix.png +0 -0
  52. PaIRS_UniNa/icons/cal_proc.png +0 -0
  53. PaIRS_UniNa/icons/cal_proc_off.png +0 -0
  54. PaIRS_UniNa/icons/cal_step.png +0 -0
  55. PaIRS_UniNa/icons/cal_step_off.png +0 -0
  56. PaIRS_UniNa/icons/calibrate.png +0 -0
  57. PaIRS_UniNa/icons/calibration_logo.png +0 -0
  58. PaIRS_UniNa/icons/change_folder.png +0 -0
  59. PaIRS_UniNa/icons/change_folder_off.png +0 -0
  60. PaIRS_UniNa/icons/checklist.png +0 -0
  61. PaIRS_UniNa/icons/clean.png +0 -0
  62. PaIRS_UniNa/icons/clean_run.png +0 -0
  63. PaIRS_UniNa/icons/close.png +0 -0
  64. PaIRS_UniNa/icons/close_all.png +0 -0
  65. PaIRS_UniNa/icons/close_project.png +0 -0
  66. PaIRS_UniNa/icons/close_workspace.png +0 -0
  67. PaIRS_UniNa/icons/colormap.png +0 -0
  68. PaIRS_UniNa/icons/colormaps/Accent.png +0 -0
  69. PaIRS_UniNa/icons/colormaps/BrBG.png +0 -0
  70. PaIRS_UniNa/icons/colormaps/Dark2.png +0 -0
  71. PaIRS_UniNa/icons/colormaps/PRGn.png +0 -0
  72. PaIRS_UniNa/icons/colormaps/Paired.png +0 -0
  73. PaIRS_UniNa/icons/colormaps/Pastel1.png +0 -0
  74. PaIRS_UniNa/icons/colormaps/Pastel2.png +0 -0
  75. PaIRS_UniNa/icons/colormaps/PiYG.png +0 -0
  76. PaIRS_UniNa/icons/colormaps/PuOr.png +0 -0
  77. PaIRS_UniNa/icons/colormaps/RdBu.png +0 -0
  78. PaIRS_UniNa/icons/colormaps/RdGy.png +0 -0
  79. PaIRS_UniNa/icons/colormaps/RdYlBu.png +0 -0
  80. PaIRS_UniNa/icons/colormaps/RdYlGn.png +0 -0
  81. PaIRS_UniNa/icons/colormaps/Set1.png +0 -0
  82. PaIRS_UniNa/icons/colormaps/Set2.png +0 -0
  83. PaIRS_UniNa/icons/colormaps/Set3.png +0 -0
  84. PaIRS_UniNa/icons/colormaps/Spectral.png +0 -0
  85. PaIRS_UniNa/icons/colormaps/Wistia.png +0 -0
  86. PaIRS_UniNa/icons/colormaps/afmhot.png +0 -0
  87. PaIRS_UniNa/icons/colormaps/autumn.png +0 -0
  88. PaIRS_UniNa/icons/colormaps/binary.png +0 -0
  89. PaIRS_UniNa/icons/colormaps/blackVector.png +0 -0
  90. PaIRS_UniNa/icons/colormaps/blueVector.png +0 -0
  91. PaIRS_UniNa/icons/colormaps/bone.png +0 -0
  92. PaIRS_UniNa/icons/colormaps/brg.png +0 -0
  93. PaIRS_UniNa/icons/colormaps/bwr.png +0 -0
  94. PaIRS_UniNa/icons/colormaps/cividis.png +0 -0
  95. PaIRS_UniNa/icons/colormaps/cool.png +0 -0
  96. PaIRS_UniNa/icons/colormaps/coolwarm.png +0 -0
  97. PaIRS_UniNa/icons/colormaps/copper.png +0 -0
  98. PaIRS_UniNa/icons/colormaps/cubehelix.png +0 -0
  99. PaIRS_UniNa/icons/colormaps/cyanVector.png +0 -0
  100. PaIRS_UniNa/icons/colormaps/flag.png +0 -0
  101. PaIRS_UniNa/icons/colormaps/gist_heat.png +0 -0
  102. PaIRS_UniNa/icons/colormaps/gray.png +0 -0
  103. PaIRS_UniNa/icons/colormaps/greenVector.png +0 -0
  104. PaIRS_UniNa/icons/colormaps/hot.png +0 -0
  105. PaIRS_UniNa/icons/colormaps/hsv.png +0 -0
  106. PaIRS_UniNa/icons/colormaps/inferno.png +0 -0
  107. PaIRS_UniNa/icons/colormaps/jet.png +0 -0
  108. PaIRS_UniNa/icons/colormaps/magentaVector.png +0 -0
  109. PaIRS_UniNa/icons/colormaps/magma.png +0 -0
  110. PaIRS_UniNa/icons/colormaps/ocean.png +0 -0
  111. PaIRS_UniNa/icons/colormaps/pink.png +0 -0
  112. PaIRS_UniNa/icons/colormaps/plasma.png +0 -0
  113. PaIRS_UniNa/icons/colormaps/prism.png +0 -0
  114. PaIRS_UniNa/icons/colormaps/rainbow.png +0 -0
  115. PaIRS_UniNa/icons/colormaps/redVector.png +0 -0
  116. PaIRS_UniNa/icons/colormaps/seismic.png +0 -0
  117. PaIRS_UniNa/icons/colormaps/spring.png +0 -0
  118. PaIRS_UniNa/icons/colormaps/summer.png +0 -0
  119. PaIRS_UniNa/icons/colormaps/tab10.png +0 -0
  120. PaIRS_UniNa/icons/colormaps/tab20.png +0 -0
  121. PaIRS_UniNa/icons/colormaps/tab20b.png +0 -0
  122. PaIRS_UniNa/icons/colormaps/tab20c.png +0 -0
  123. PaIRS_UniNa/icons/colormaps/terrain.png +0 -0
  124. PaIRS_UniNa/icons/colormaps/twilight.png +0 -0
  125. PaIRS_UniNa/icons/colormaps/viridis.png +0 -0
  126. PaIRS_UniNa/icons/colormaps/whiteVector.png +0 -0
  127. PaIRS_UniNa/icons/colormaps/winter.png +0 -0
  128. PaIRS_UniNa/icons/colormaps/yellowVector.png +0 -0
  129. PaIRS_UniNa/icons/common_region.png +0 -0
  130. PaIRS_UniNa/icons/common_region_off.png +0 -0
  131. PaIRS_UniNa/icons/completed.png +0 -0
  132. PaIRS_UniNa/icons/contourf_off.png +0 -0
  133. PaIRS_UniNa/icons/contourf_on.png +0 -0
  134. PaIRS_UniNa/icons/copy.png +0 -0
  135. PaIRS_UniNa/icons/copy_process.png +0 -0
  136. PaIRS_UniNa/icons/copy_process_off.png +0 -0
  137. PaIRS_UniNa/icons/copygrid.png +0 -0
  138. PaIRS_UniNa/icons/cursor_lamp.png +0 -0
  139. PaIRS_UniNa/icons/cut.png +0 -0
  140. PaIRS_UniNa/icons/cut_warnings.png +0 -0
  141. PaIRS_UniNa/icons/darkmode.png +0 -0
  142. PaIRS_UniNa/icons/debug_run.png +0 -0
  143. PaIRS_UniNa/icons/delete.png +0 -0
  144. PaIRS_UniNa/icons/deleteErr.png +0 -0
  145. PaIRS_UniNa/icons/disp_step.png +0 -0
  146. PaIRS_UniNa/icons/disp_step_off.png +0 -0
  147. PaIRS_UniNa/icons/down.png +0 -0
  148. PaIRS_UniNa/icons/edit_list.png +0 -0
  149. PaIRS_UniNa/icons/editing.png +0 -0
  150. PaIRS_UniNa/icons/example_list.png +0 -0
  151. PaIRS_UniNa/icons/find_all_planes.png +0 -0
  152. PaIRS_UniNa/icons/find_plane.png +0 -0
  153. PaIRS_UniNa/icons/flaticon_PaIRS.png +0 -0
  154. PaIRS_UniNa/icons/flaticon_PaIRS_beta.png +0 -0
  155. PaIRS_UniNa/icons/flaticon_PaIRS_download.png +0 -0
  156. PaIRS_UniNa/icons/flaticon_PaIRS_download_warning.png +0 -0
  157. PaIRS_UniNa/icons/flip_y_off.png +0 -0
  158. PaIRS_UniNa/icons/flip_y_on.png +0 -0
  159. PaIRS_UniNa/icons/focusErrr.png +0 -0
  160. PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
  161. PaIRS_UniNa/icons/folder_loop_cleanup_off.png +0 -0
  162. PaIRS_UniNa/icons/gear.gif +0 -0
  163. PaIRS_UniNa/icons/gear.png +0 -0
  164. PaIRS_UniNa/icons/ger.png +0 -0
  165. PaIRS_UniNa/icons/greenv.png +0 -0
  166. PaIRS_UniNa/icons/guide.png +0 -0
  167. PaIRS_UniNa/icons/icon_CalVi.png +0 -0
  168. PaIRS_UniNa/icons/icon_PaIRS.png +0 -0
  169. PaIRS_UniNa/icons/import.png +0 -0
  170. PaIRS_UniNa/icons/import_set.png +0 -0
  171. PaIRS_UniNa/icons/information.png +0 -0
  172. PaIRS_UniNa/icons/information2.png +0 -0
  173. PaIRS_UniNa/icons/input_logo.png +0 -0
  174. PaIRS_UniNa/icons/issue.png +0 -0
  175. PaIRS_UniNa/icons/laser_NTR.png +0 -0
  176. PaIRS_UniNa/icons/laser_TR_double.png +0 -0
  177. PaIRS_UniNa/icons/laser_TR_single.png +0 -0
  178. PaIRS_UniNa/icons/link.png +0 -0
  179. PaIRS_UniNa/icons/linked.png +0 -0
  180. PaIRS_UniNa/icons/loaded.png +0 -0
  181. PaIRS_UniNa/icons/loading_2.gif +0 -0
  182. PaIRS_UniNa/icons/log_logo.png +0 -0
  183. PaIRS_UniNa/icons/logo_CalVi.png +0 -0
  184. PaIRS_UniNa/icons/logo_CalVi_completo.png +0 -0
  185. PaIRS_UniNa/icons/logo_CalVi_party.png +0 -0
  186. PaIRS_UniNa/icons/logo_PaIRS.png +0 -0
  187. PaIRS_UniNa/icons/logo_PaIRS_completo.png +0 -0
  188. PaIRS_UniNa/icons/logo_PaIRS_download.png +0 -0
  189. PaIRS_UniNa/icons/logo_PaIRS_party_rect.png +0 -0
  190. PaIRS_UniNa/icons/logo_PaIRS_rect.png +0 -0
  191. PaIRS_UniNa/icons/logo_opaco.png +0 -0
  192. PaIRS_UniNa/icons/mask.png +0 -0
  193. PaIRS_UniNa/icons/measure.png +0 -0
  194. PaIRS_UniNa/icons/measure_off.png +0 -0
  195. PaIRS_UniNa/icons/min_proc.png +0 -0
  196. PaIRS_UniNa/icons/min_proc_off.png +0 -0
  197. PaIRS_UniNa/icons/min_step.png +0 -0
  198. PaIRS_UniNa/icons/min_step_off.png +0 -0
  199. PaIRS_UniNa/icons/minus.png +0 -0
  200. PaIRS_UniNa/icons/mirror_u.png +0 -0
  201. PaIRS_UniNa/icons/mirror_v.png +0 -0
  202. PaIRS_UniNa/icons/mirror_x.png +0 -0
  203. PaIRS_UniNa/icons/mirror_y.png +0 -0
  204. PaIRS_UniNa/icons/mtplt.png +0 -0
  205. PaIRS_UniNa/icons/new.png +0 -0
  206. PaIRS_UniNa/icons/new_workspace.png +0 -0
  207. PaIRS_UniNa/icons/news.png +0 -0
  208. PaIRS_UniNa/icons/normal_run.png +0 -0
  209. PaIRS_UniNa/icons/open.png +0 -0
  210. PaIRS_UniNa/icons/open_image.png +0 -0
  211. PaIRS_UniNa/icons/open_new_window.png +0 -0
  212. PaIRS_UniNa/icons/open_result.png +0 -0
  213. PaIRS_UniNa/icons/open_workspace.png +0 -0
  214. PaIRS_UniNa/icons/output_logo.png +0 -0
  215. PaIRS_UniNa/icons/paste_above.png +0 -0
  216. PaIRS_UniNa/icons/paste_below.png +0 -0
  217. PaIRS_UniNa/icons/pause.png +0 -0
  218. PaIRS_UniNa/icons/paused.png +0 -0
  219. PaIRS_UniNa/icons/pencil_bw.png +0 -0
  220. PaIRS_UniNa/icons/piv_proc.png +0 -0
  221. PaIRS_UniNa/icons/piv_proc_off.png +0 -0
  222. PaIRS_UniNa/icons/piv_step.png +0 -0
  223. PaIRS_UniNa/icons/piv_step_off.png +0 -0
  224. PaIRS_UniNa/icons/plane.png +0 -0
  225. PaIRS_UniNa/icons/play.png +0 -0
  226. PaIRS_UniNa/icons/plus.png +0 -0
  227. PaIRS_UniNa/icons/process_logo.png +0 -0
  228. PaIRS_UniNa/icons/process_loop.png +0 -0
  229. PaIRS_UniNa/icons/project.png +0 -0
  230. PaIRS_UniNa/icons/pylog.png +0 -0
  231. PaIRS_UniNa/icons/python_warning.png +0 -0
  232. PaIRS_UniNa/icons/queue.png +0 -0
  233. PaIRS_UniNa/icons/quit.png +0 -0
  234. PaIRS_UniNa/icons/read.png +0 -0
  235. PaIRS_UniNa/icons/read_list.png +0 -0
  236. PaIRS_UniNa/icons/redo.png +0 -0
  237. PaIRS_UniNa/icons/redx.png +0 -0
  238. PaIRS_UniNa/icons/reset.png +0 -0
  239. PaIRS_UniNa/icons/reset_levels.png +0 -0
  240. PaIRS_UniNa/icons/resize_icon.png +0 -0
  241. PaIRS_UniNa/icons/restore.png +0 -0
  242. PaIRS_UniNa/icons/restore_undo.png +0 -0
  243. PaIRS_UniNa/icons/rotate_clock.png +0 -0
  244. PaIRS_UniNa/icons/rotate_counter.png +0 -0
  245. PaIRS_UniNa/icons/rotate_v_clock.png +0 -0
  246. PaIRS_UniNa/icons/rotate_v_counter.png +0 -0
  247. PaIRS_UniNa/icons/running.gif +0 -0
  248. PaIRS_UniNa/icons/running.png +0 -0
  249. PaIRS_UniNa/icons/running_warn.png +0 -0
  250. PaIRS_UniNa/icons/sandglass.png +0 -0
  251. PaIRS_UniNa/icons/save.png +0 -0
  252. PaIRS_UniNa/icons/save_and_stop.png +0 -0
  253. PaIRS_UniNa/icons/save_cfg.png +0 -0
  254. PaIRS_UniNa/icons/saveas.png +0 -0
  255. PaIRS_UniNa/icons/saveas_workspace.png +0 -0
  256. PaIRS_UniNa/icons/scale_all.png +0 -0
  257. PaIRS_UniNa/icons/scale_down.png +0 -0
  258. PaIRS_UniNa/icons/scale_up.png +0 -0
  259. PaIRS_UniNa/icons/scan_list.png +0 -0
  260. PaIRS_UniNa/icons/scan_path.png +0 -0
  261. PaIRS_UniNa/icons/scan_path_loop.png +0 -0
  262. PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
  263. PaIRS_UniNa/icons/search.png +0 -0
  264. PaIRS_UniNa/icons/showIW_off.png +0 -0
  265. PaIRS_UniNa/icons/showIW_on.png +0 -0
  266. PaIRS_UniNa/icons/show_all.png +0 -0
  267. PaIRS_UniNa/icons/sort.png +0 -0
  268. PaIRS_UniNa/icons/sort_reversed.png +0 -0
  269. PaIRS_UniNa/icons/spiv_proc.png +0 -0
  270. PaIRS_UniNa/icons/spiv_proc_off.png +0 -0
  271. PaIRS_UniNa/icons/spiv_setup_no.png +0 -0
  272. PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
  273. PaIRS_UniNa/icons/star.png +0 -0
  274. PaIRS_UniNa/icons/step_inheritance.png +0 -0
  275. PaIRS_UniNa/icons/subMIN_off.png +0 -0
  276. PaIRS_UniNa/icons/subMIN_on.png +0 -0
  277. PaIRS_UniNa/icons/tom.png +0 -0
  278. PaIRS_UniNa/icons/trash.png +0 -0
  279. PaIRS_UniNa/icons/undo.png +0 -0
  280. PaIRS_UniNa/icons/unedited.png +0 -0
  281. PaIRS_UniNa/icons/unina_dii.png +0 -0
  282. PaIRS_UniNa/icons/uninitialized.png +0 -0
  283. PaIRS_UniNa/icons/unlink.png +0 -0
  284. PaIRS_UniNa/icons/unwrap_items.png +0 -0
  285. PaIRS_UniNa/icons/up.png +0 -0
  286. PaIRS_UniNa/icons/updating_import.gif +0 -0
  287. PaIRS_UniNa/icons/updating_pairs.gif +0 -0
  288. PaIRS_UniNa/icons/vectorColor.png +0 -0
  289. PaIRS_UniNa/icons/vettore.png +0 -0
  290. PaIRS_UniNa/icons/view.png +0 -0
  291. PaIRS_UniNa/icons/view_off.png +0 -0
  292. PaIRS_UniNa/icons/vis_logo.png +0 -0
  293. PaIRS_UniNa/icons/waiting_circle.png +0 -0
  294. PaIRS_UniNa/icons/warning.png +0 -0
  295. PaIRS_UniNa/icons/warning_circle.png +0 -0
  296. PaIRS_UniNa/icons/window.png +0 -0
  297. PaIRS_UniNa/icons/workspace.png +0 -0
  298. PaIRS_UniNa/icons/wrap_items.png +0 -0
  299. PaIRS_UniNa/icons/write_list.png +0 -0
  300. PaIRS_UniNa/listLib.py +303 -0
  301. PaIRS_UniNa/mtfPIV.py +256 -0
  302. PaIRS_UniNa/parForMulti.py +435 -0
  303. PaIRS_UniNa/parForWorkers.py +593 -0
  304. PaIRS_UniNa/pivParFor.py +235 -0
  305. PaIRS_UniNa/plt_util.py +141 -0
  306. PaIRS_UniNa/preProcParFor.py +155 -0
  307. PaIRS_UniNa/procTools.py +1439 -0
  308. PaIRS_UniNa/readcfg.py +52 -0
  309. PaIRS_UniNa/rqrdpckgs.txt +9 -0
  310. PaIRS_UniNa/stereoPivParFor.py +227 -0
  311. PaIRS_UniNa/tAVarie.py +215 -0
  312. PaIRS_UniNa/tabSplitter.py +612 -0
  313. PaIRS_UniNa/ui_Calibration_Tab.py +578 -0
  314. PaIRS_UniNa/ui_Custom_Top.py +296 -0
  315. PaIRS_UniNa/ui_Input_Tab.py +1101 -0
  316. PaIRS_UniNa/ui_Input_Tab_CalVi.py +1283 -0
  317. PaIRS_UniNa/ui_Log_Tab.py +263 -0
  318. PaIRS_UniNa/ui_Output_Tab.py +2362 -0
  319. PaIRS_UniNa/ui_Process_Tab.py +3810 -0
  320. PaIRS_UniNa/ui_Process_Tab_CalVi.py +1549 -0
  321. PaIRS_UniNa/ui_Process_Tab_Disp.py +1141 -0
  322. PaIRS_UniNa/ui_Process_Tab_Min.py +437 -0
  323. PaIRS_UniNa/ui_ResizePopup.py +204 -0
  324. PaIRS_UniNa/ui_Vis_Tab.py +1628 -0
  325. PaIRS_UniNa/ui_Vis_Tab_CalVi.py +1251 -0
  326. PaIRS_UniNa/ui_Whatsnew.py +132 -0
  327. PaIRS_UniNa/ui_gPairs.py +877 -0
  328. PaIRS_UniNa/ui_infoPaIRS.py +551 -0
  329. PaIRS_UniNa/whatsnew.txt +4 -0
  330. pairs_unina-0.2.10.dist-info/METADATA +159 -0
  331. pairs_unina-0.2.10.dist-info/RECORD +333 -0
  332. pairs_unina-0.2.10.dist-info/WHEEL +5 -0
  333. pairs_unina-0.2.10.dist-info/top_level.txt +2 -0
PaIRS_UniNa/gPaIRS.py ADDED
@@ -0,0 +1,3957 @@
1
+
2
+ from .ui_gPairs import *
3
+ from .ui_infoPaIRS import *
4
+ from .parForWorkers import *
5
+
6
+ from .TabTools import *
7
+ from .procTools import *
8
+ from .Explorer import *
9
+ from .Input_Tab import *
10
+ from .Output_Tab import *
11
+ from .Process_Tab import *
12
+ from .Log_Tab import *
13
+ from .Vis_Tab import *
14
+ from .Process_Tab_Min import *
15
+ from .Process_Tab_Disp import *
16
+ from .Calibration_Tab import *
17
+ from .Input_Tab_CalVi import *
18
+ from .Process_Tab_CalVi import *
19
+ from .Vis_Tab_CalVi import *
20
+ from .tabSplitter import *
21
+
22
+ from .ResizePopup import*
23
+ from .Whatsnew import*
24
+
25
+ from .gPalette import *
26
+
27
+ from .Saving_tools import*
28
+
29
+ import concurrent.futures
30
+
31
+ from .__init__ import __version__,__subversion__,__year__,__date__,__mail__,__website__
32
+
33
+ version=__version__
34
+ subversion=__subversion__
35
+ year=__year__
36
+ mail=__mail__
37
+ website=__website__
38
+ uicfg_version='0.2.0'
39
+ uicfg_version_to_load=uicfg_version
40
+ #uicfg_version_to_load='0.1.5'
41
+ Flag_fullDEBUG=False
42
+ FlagPrevPropagationTabSplitter=True
43
+
44
+ #********************************************* Additional windows (LEGACY)
45
+ class FloatingObject(QMainWindow):
46
+ def closeEvent(self, event):
47
+ self.hide()
48
+
49
+ def __init__(self,parent,tab):
50
+ super().__init__()
51
+ if parent is None:
52
+ self.gui=self.window()
53
+ else:
54
+ if hasattr(parent,'gui'):
55
+ self.gui:gPaIRS=parent.gui
56
+ else:
57
+ self.gui:gPaIRS=parent.window()
58
+
59
+ self.name=''
60
+ self.button=None
61
+ self.tab=tab
62
+ self.setup()
63
+
64
+ def setup(self):
65
+ tab=self.tab
66
+ if type(tab)==CollapsibleBox:
67
+ self.setWindowTitle(tab.toggle_button.text())
68
+ self.setWindowIcon(self.gui.windowIcon())
69
+ elif isinstance(tab,Calibration_Tab) or any([isinstance(tab,t) for t in self.gui.tabTypes[1:]]):
70
+ self.name=tab.ui.name_tab.text().replace(' ','')
71
+ self.setWindowTitle(tab.ui.name_tab.text())
72
+ self.setWindowIcon(tab.ui.icon.pixmap())
73
+ else:
74
+ self.setWindowTitle(self.gui.windowTitle())
75
+ self.setWindowIcon(self.gui.windowIcon())
76
+ if type(tab.parent()) in (QSplitter,QLayout,myQSplitter):
77
+ self.lay:QLayout=tab.parent()
78
+ else:
79
+ self.lay:QLayout=tab.parent().layout()
80
+ self.pa=tab
81
+ self.index=self.lay.indexOf(tab)
82
+ #self.setCentralWidget(tab)
83
+
84
+ self.setBaseSize(tab.baseSize())
85
+ self.setAutoFillBackground(False)
86
+ self.setMinimumSize(tab.minimumSize())
87
+ self.setMaximumSize(tab.maximumSize())
88
+
89
+ #if self.name:
90
+ # self.button=getattr(self.gui.ui,'button_'+self.name)
91
+
92
+ def setFloat(self):
93
+ self.setCentralWidget(self.pa)
94
+ self.centralWidget().setMinimumSize(self.pa.minimumSize())
95
+ self.centralWidget().setMaximumSize(self.pa.maximumSize())
96
+
97
+ class FloatingWidget(FloatingObject):
98
+ def closeEvent(self, event):
99
+ index=min([self.index,self.lay.count()-1])
100
+ self.lay.insertWidget(index,self.pa)
101
+ self.close()
102
+ i=self.gui.FloatingWindows.index(self)
103
+ self.gui.FloatingWindows.pop(i)
104
+ #self.gui.undockTabs()
105
+
106
+ def __init__(self,parent,tab):
107
+ super().__init__(parent,tab)
108
+
109
+ geo=self.pa.geometry()
110
+ geoP=self.gui.geometry()
111
+ x=geoP.x()+int(geoP.width()*0.5)-int(geo.width()*0.5)
112
+ y=geoP.y()+int(geoP.height()*0.5)-int(geo.height()*0.5)
113
+ self.setGeometry(x,y,geo.width(),geo.height())
114
+ self.setFloat()
115
+ self.show()
116
+
117
+ class infoPaIRS(QMainWindow):
118
+ def __init__(self,gui):
119
+ super().__init__()
120
+ ui=Ui_InfoPaiRS()
121
+ ui.setupUi(self)
122
+ self.ui=ui
123
+ setupWid(self)
124
+
125
+ subv=f"(.{subversion})" if int(subversion) else ""
126
+ infotext=self.ui.info.text().replace('#.#.#',version+subv)
127
+ infotext=infotext.replace('yyyy',year)
128
+ infotext=infotext.replace('dddd/dd/dd',__date__)
129
+ mailString=f'<a href="mailto:{mail}"><span style=" text-decoration: underline; color:#0000ff; font-size:11pt">{mail}</a>'
130
+ infotext=infotext.replace('mmmm',mailString)
131
+ websiteString=f'<a href="{website}"><span style=" text-decoration: underline; color:#0000ff; font-size:11pt">{website}</a>'
132
+ infotext=infotext.replace('wwww',websiteString)
133
+ self.ui.info.setText(infotext)
134
+ if Flag_ISEXE:
135
+ #self.ui.tabWidget.removeTab(3)
136
+ self.ui.tabWidget.setTabText(3,'Packages')
137
+ self.ui.req.setText(self.distPackages())
138
+ else:
139
+ self.ui.tabWidget.setTabText(3,'Requirements')
140
+ self.ui.req.setText(self.requirements())
141
+
142
+ self.fontPixelSize=gui.GPApar.fontPixelSize
143
+ self.setFontSizeText()
144
+
145
+ self.gui=gui
146
+ for w in self.findChildren(QObject):
147
+ if hasattr(w,'keyPressEvent'):
148
+ def createKeyPressFun(w):
149
+ def KeyPressFun(e):
150
+ if w.hasFocus():
151
+ #pri.Info.yellow(w)
152
+ type(w).keyPressEvent(w,e)
153
+ #if not e.key() in self.gui.blockedKeys:
154
+ # self.gui.keyPressEvent(e)
155
+ return KeyPressFun
156
+ w.keyPressEvent=createKeyPressFun(w)
157
+
158
+ def setFontSizeText(self):
159
+ fPixSize=self.fontPixelSize
160
+ setFontPixelSize(self,fPixSize)
161
+ setFontSizeText(self.ui.info,[fPixSize+6,fPixSize*2])
162
+ setFontSizeText(self.ui.info_uni,[fPixSize+4])
163
+ setFontSizeText(self.ui.ger_cv,[fPixSize+1])
164
+ setFontSizeText(self.ui.tom_cv,[fPixSize+1])
165
+ setFontSizeText(self.ui.list_ref,[fPixSize+1])
166
+
167
+ def distPackages(self):
168
+ # Read the contents of the file and split by lines
169
+ with open(rqrdpckgs_filename, 'r') as file:
170
+ lines = file.readlines()
171
+
172
+ # Introductory sentence
173
+ intro_text = """
174
+ <p style="font-size: 12pt; font-weight: normal; text-align: justify;">
175
+ Python packages included in the current executable:
176
+ </p>
177
+ <p>
178
+
179
+ </p>
180
+ """
181
+
182
+ # Start the HTML table with improved styling
183
+ html_table = intro_text + """
184
+ <table border="1" style="width: 100%; align-items: center;">
185
+ <thead>
186
+ <tr>
187
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Package</th>
188
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Version</th>
189
+ </tr>
190
+ </thead>
191
+ <tbody>
192
+ """
193
+
194
+ # Iterate over each line in the file
195
+ for line in lines:
196
+ # Split each line into package name, min vers11pt max version, and other info
197
+ package_info = line.strip().split()
198
+
199
+ # Ensure the line has the expected format
200
+ if len(package_info) >= 3:
201
+ package_name = package_info[0]
202
+ if package_name[0]=='#': continue
203
+ max_version = package_info[2]
204
+
205
+ # Append a row to the HTML table
206
+ html_table += f"""
207
+ <tr>
208
+ <td style="padding: 10px; font-size: 11pt">{package_name}</td>
209
+ <td style="padding: 10px; font-size: 11pt">{max_version}</td>
210
+ </tr>
211
+ """
212
+
213
+ # Close the table tags
214
+ html_table += """
215
+ </tbody>
216
+ </table>
217
+ """
218
+ return html_table
219
+
220
+ def requirements(self):
221
+ # Read the contents of the file and split by lines
222
+ with open(rqrdpckgs_filename, 'r') as file:
223
+ lines = file.readlines()
224
+
225
+ # Introductory sentence
226
+ intro_text = """
227
+ <p style="font-size: 12pt; font-weight: normal; text-align: justify;">
228
+ Required Python packages with their minimum and maximum supported versions:
229
+ </p>
230
+ <p>
231
+
232
+ </p>
233
+ """
234
+
235
+ # Start the HTML table with improved styling
236
+ html_table = intro_text + """
237
+ <table border="1" style="width: 100%; align-items: center;">
238
+ <thead>
239
+ <tr>
240
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Package</th>
241
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Minimum version</th>
242
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Maximum version</th>
243
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Installed version</th>
244
+ </tr>
245
+ </thead>
246
+ <tbody>
247
+ """
248
+
249
+ # Iterate over each line in the file
250
+ for line in lines:
251
+ # Split each line into package name, min vers11pt max version, and other info
252
+ package_info = line.strip().split()
253
+
254
+ # Ensure the line has the expected format
255
+ if len(package_info) >= 3:
256
+ package_name = package_info[0]
257
+ if package_name[0]=='#': continue
258
+ min_version = package_info[1]
259
+ max_version = package_info[2]
260
+ curr_version = package_info[3]
261
+
262
+ # Append a row to the HTML table
263
+ html_table += f"""
264
+ <tr>
265
+ <td style="padding: 10px; font-size: 11pt">{package_name}</td>
266
+ <td style="padding: 10px; font-size: 11pt">{min_version}</td>
267
+ <td style="padding: 10px; font-size: 11pt">{max_version}</td>
268
+ <td style="padding: 10px; font-size: 11pt">{curr_version}</td>
269
+ </tr>
270
+ """
271
+
272
+ # Close the table tags
273
+ html_table += """
274
+ </tbody>
275
+ </table>
276
+ """
277
+ return html_table
278
+
279
+ #********************************************* GPaIRS
280
+ class gPaIRS(QMainWindow):
281
+
282
+ def eventFilter(self, obj, event:QKeyEvent):
283
+ # Check if the event is a KeyPress event
284
+ if event.type() == QEvent.KeyPress:
285
+ if event.modifiers() & Qt.KeyboardModifier.ControlModifier:
286
+ if event.modifiers() & Qt.KeyboardModifier.ShiftModifier and event.key() == Qt.Key.Key_F:
287
+ self.setDefaultSizes()
288
+ return True
289
+ FlagSetFont=False
290
+ if event.key() == Qt.Key.Key_0:
291
+ FlagSetFont=self.GPApar.fontPixelSize!=fontPixelSize
292
+ self.GPApar.fontPixelSize=fontPixelSize
293
+ elif event.key() == Qt.Key.Key_1 or event.key() == Qt.Key.Key_Minus:
294
+ if event.modifiers() & Qt.KeyboardModifier.ShiftModifier:
295
+ FlagSetFont=self.GPApar.fontPixelSize!=fontPixelSize_lim[0]
296
+ self.GPApar.fontPixelSize=fontPixelSize_lim[0]
297
+ else:
298
+ FlagSetFont=self.GPApar.fontPixelSize>fontPixelSize_lim[0]
299
+ if FlagSetFont: self.GPApar.fontPixelSize-=1
300
+ elif event.key() == Qt.Key.Key_9 or event.key() == Qt.Key.Key_Plus:
301
+ if event.modifiers() & Qt.KeyboardModifier.ShiftModifier:
302
+ FlagSetFont=self.GPApar.fontPixelSize!=fontPixelSize_lim[1]
303
+ self.GPApar.fontPixelSize=fontPixelSize_lim[1]
304
+ else:
305
+ FlagSetFont=self.GPApar.fontPixelSize<fontPixelSize_lim[1]
306
+ if FlagSetFont: self.GPApar.fontPixelSize+=1
307
+ if FlagSetFont:
308
+ self.app.processEvents()
309
+ self.setFontPixelSize()
310
+ return True
311
+
312
+ # Pass the event on to the parent class
313
+ return super().eventFilter(obj, event)
314
+
315
+ def resizeEvent(self,event):
316
+ if self.FlagGeometryInit:
317
+ self.FlagGeometryInit=False
318
+ #self.setFontPixelSize()
319
+ super().resizeEvent(event)
320
+ #self.updateGPAparGeom()
321
+
322
+ def showEvent(self, event):
323
+ super().showEvent(event)
324
+ if event.type() == QEvent.Show:
325
+ QTimer.singleShot(0, lambda: self.ui.tabAreaWidget.setSPLlayout())
326
+ pass
327
+
328
+ def closeEvent(self,event):
329
+ if self.completingTask!=self.correctClose:
330
+ self.pauseQuestion('quitting',self.correctClose,FlagFirstQuestion=True)
331
+ event.ignore()
332
+ return
333
+
334
+ def correctClose(self):
335
+ if self.pfPool: self.pfPool.closeParPool()
336
+ print('\nClosing PaIRS...')
337
+ self.save_last_workspace()
338
+ self.closeAll()
339
+ if self.GPApar.FlagOutDated:
340
+ warningLatestVersion(self,self.app,flagExit=1,flagWarning=self.GPApar.FlagOutDated in (-1,1,-1000))
341
+ self.close()
342
+ self.app.processEvents()
343
+ self.app.SecondaryThreads=self.SecondaryThreads
344
+ self.app.quit()
345
+
346
+ def closeAll(self):
347
+ if hasattr(self,"FloatingTabs"):
348
+ for w in self.FloatingTabs:
349
+ w.close()
350
+ if hasattr(self,"FloatingWindows"):
351
+ for w in self.FloatingWindows:
352
+ w.close()
353
+
354
+ class gPaIRS_signals(QObject):
355
+ killOrResetParForWorker=Signal(bool)#used to kill or reset he parForWorker
356
+ progress=Signal(int)
357
+ indProc=Signal(int)
358
+ parPoolInit=Signal()
359
+ guiInit=Signal()
360
+ setMapVar=Signal()
361
+ pause_proc=Signal()
362
+ printOutDated=Signal()
363
+
364
+ def __init__(self,flagDebug=False,app=None, standardPalette=None):
365
+ self.app:QApplication=app
366
+ self.name='PaIRS'
367
+ self.flagSimpleFor=False # normally false, True only if you are checking the c library or the parpool therefore I have added a long print at the end of this function
368
+ #todo gerardo spostare la stampa alla fine di tutto anche se ripetuta
369
+ activateFlagDebug(flagDebug)
370
+ self.PIVvers=PaIRS_lib.Version(PaIRS_lib.MOD_PIV).split('\n')[0]
371
+ pri.Time.blue(2,f'gPaIRS init PaIRS-PIV {self.PIVvers}')
372
+ super().__init__()
373
+
374
+ #------------------------------------- Launching Parallel Pool
375
+ self.previousPlotTime=time() #previous time for plotting
376
+ self.FlagGeometryInit=True
377
+ self.FlagOpenedWorkspace=False
378
+
379
+ self.FlagGuiInit=False
380
+ self.signals=self.gPaIRS_signals()
381
+ #self.numUsedThreadsPIV=NUMTHREADS_MAX #now is called numMaxProcs
382
+
383
+ self.numMaxProcs=NUMTHREADS_MAX #number of cores that the user has selected should be larger than numUsedProcs*numPivOmpCores
384
+ self.numUsedProcs=NUMTHREADS_MAX #number of really used processor (Threads parfor)
385
+ self.numPivOmpCores=1 # number of PIV internal cores used by omp
386
+
387
+ self.FlagParPoolInit=False
388
+ self.launchParPool(NUMTHREADS_MAX)
389
+
390
+ self.procdata:dataTreePar=None
391
+ self.currind:list=None
392
+ #self.numProcOrErrTot=0 # at the end should be equal to the number of images to be processed
393
+ self.numCallBackTotOk=0 # Callbacks that are relative to a normal termination
394
+ self.SecondaryThreads=[]
395
+
396
+ self.FlagPackIssue=False
397
+
398
+ #------------------------------------- Graphical interface: widgets
399
+ ui=Ui_gPairs()
400
+ ui.setupUi(self)
401
+ self.ui=ui
402
+ self.ui.button_Run.setVisible(False)
403
+ self.ui.button_Run.setEnabled(False)
404
+
405
+ self.buttonSizeCallbacks=[]
406
+ def createCallback(k):
407
+ return lambda: self.setPresetSizes(k)
408
+ for k in range(6):
409
+ self.buttonSizeCallbacks.append(createCallback(k))
410
+ #self.ResizePopup=ResizePopup(self.buttonSizeCallbacks)
411
+ self.ResizePopup=None
412
+
413
+ self.cfgname=lastcfgname
414
+ self.FlagHappyLogo=False
415
+ self.setupLogo()
416
+ self.startHappyLogoWatcher()
417
+
418
+ self.GPApar_old=GPApar()
419
+ self.GPApar=GPApar()
420
+ self.GPApar.NumCores=self.numMaxProcs
421
+ self.TABpar=self.GPApar
422
+
423
+ pri.Time.blue(2,f'gPaIRS inizio generazione tabs')
424
+ self.defineTabs()
425
+ self.defineMenuActions()
426
+ self.ui.title_workspace.updateLabel=self.updateWorkspaceTitle
427
+
428
+ setupWid(self) #---------------- IMPORTANT
429
+ self.setFurtherFontPixelSizes(fontPixelSize)
430
+
431
+ pri.Time.blue(2,f'gPaIRS fine generazione tabs')
432
+
433
+ #for the keyboard shortcut
434
+ """
435
+ self.FlagKeyCallbackExec=False
436
+ self.blockedKeys=[Qt.Key.Key_Up,Qt.Key.Key_Down,Qt.Key.Key_Left,Qt.Key.Key_Right]
437
+ for w in self.findChildren(QObject):
438
+ if hasattr(w,'keyPressEvent'):
439
+ def createKeyPressFun(w):
440
+ def KeyPressFun(e):
441
+ if w.hasFocus():
442
+ #pri.Info.yellow(w)
443
+ if not self.FlagKeyCallbackExec:
444
+ self.FlagKeyCallbackExec=True
445
+ type(w).keyPressEvent(w,e)
446
+ if not e.key() in self.blockedKeys:
447
+ self.keyPressEvent(e)
448
+ self.FlagKeyCallbackExec=False
449
+ return KeyPressFun
450
+ w.keyPressEvent=createKeyPressFun(w)
451
+ """
452
+ self.ui.spin_nworkers.setValue(self.numMaxProcs)
453
+ self.ui.spin_nworkers.setMinimum(1)
454
+ self.ui.spin_nworkers.setMaximum(NUMTHREADS_MAX)
455
+ self.ui.spin_nworkers.valueChanged.connect(self.spin_nworkers_action)
456
+
457
+ self.ui.button_pause.hide()
458
+ self.ui.w_progress_Proc.hide()
459
+
460
+ #for positioning and resizing
461
+ #window=QWindow()
462
+ #window.showMaximized()
463
+ #self.maximumGeometry=window.geometry()
464
+ #window.close()
465
+ self.maximumGeometry=self.app.primaryScreen().geometry()
466
+
467
+ self.minW=self.minimumWidth()
468
+ self.maxW=self.maximumGeometry.width()
469
+ self.ui.Explorer.setMinimumWidth(0)
470
+ margins=self.ui.centralLayout.contentsMargins()
471
+ self.minW_ManTabs=self.minimumWidth()-margins.left()-margins.right()
472
+
473
+ self.splash=None
474
+
475
+ #------------------------------------- Graphical interface: miscellanea
476
+ self.flaticon_PaIRS_download=QIcon()
477
+ self.flaticon_PaIRS_download.addFile(icons_path+'flaticon_PaIRS_download.png')
478
+ self.flaticon_PaIRS_download_warning=QIcon()
479
+ self.flaticon_PaIRS_download_warning.addFile(icons_path+'flaticon_PaIRS_download_warning.png')
480
+ self.flaticon_PaIRS_beta=QIcon()
481
+ self.flaticon_PaIRS_beta.addFile(icons_path+'flaticon_PaIRS_beta.png')
482
+
483
+ self.icon_play=QIcon()
484
+ self.icon_play.addFile(u""+ icons_path +"play.png", QSize(), QIcon.Normal, QIcon.Off)
485
+ self.icon_pause=QIcon()
486
+ self.icon_pause.addFile(u""+ icons_path +"pause.png", QSize(), QIcon.Normal, QIcon.Off)
487
+ self.icon_save_and_stop=QIcon()
488
+ self.icon_save_and_stop.addFile(u""+ icons_path +"save_and_stop.png", QSize(), QIcon.Normal, QIcon.Off)
489
+
490
+ self.ui.tabAreaWidget.icon_link=QIcon()
491
+ self.ui.tabAreaWidget.icon_link.addFile(u""+ icons_path +"link.png", QSize(), QIcon.Normal, QIcon.Off)
492
+ self.ui.tabAreaWidget.icon_unlink=QIcon()
493
+ self.ui.tabAreaWidget.icon_unlink.addFile(u""+ icons_path +"unlink.png", QSize(), QIcon.Normal, QIcon.Off)
494
+
495
+ self.updating_import_gif = QMovie(u""+ icons_path +"updating_import.gif")
496
+ self.updating_import_gif.setScaledSize(self.ui.label_updating_import.size())
497
+ #self.ui.label_updating_import.setScaledContents(True)
498
+ self.updating_import_gif.start()
499
+ self.ui.label_updating_import.setMovie(self.updating_import_gif)
500
+ self.ui.label_updating_import.setVisible(False)
501
+
502
+ self.updating_pairs_gif = QMovie(u""+ icons_path +"updating_pairs.gif")
503
+ self.updating_pairs_gif.setScaledSize(self.ui.label_updating_pairs.size())
504
+ #self.ui.label_updating_pairs.setScaledContents(True)
505
+ self.updating_pairs_gif.start()
506
+ self.ui.label_updating_pairs.setMovie(self.updating_pairs_gif)
507
+ self.ui.label_updating_pairs.setVisible(False)
508
+
509
+ self.runningMovie = QMovie(icons_path+'running.gif')
510
+ self.runningMovie.setScaledSize(QSize(StepItemWidget.label_size,StepItemWidget.label_size))
511
+ self.runningMovie.start()
512
+
513
+ self.gearMovie = QMovie(icons_path+'gear.gif')
514
+ self.gearMovie.setScaledSize(QSize(StepItemWidget.label_size,StepItemWidget.label_size))
515
+ self.gearMovie.start()
516
+
517
+ self.palettes=[lightPalette(),darkPalette(),standardPalette]
518
+ self.paletteNames=['Light','Dark','System']
519
+ #self.ui.logo.contextMenuEvent=self.paletteContextMenuEvent
520
+ self.ui.button_colormode.mousePressEvent=self.paletteContextMenuEvent
521
+ self.ui.button_packissue.mousePressEvent=lambda e: checkRequiredPackages(self,FlagDisplay=True)
522
+ self.ui.logo.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
523
+ self.ui.logo.mousePressEvent=lambda e: self.about()
524
+ #self.ui.logo.mousePressEvent=self.paletteContextMenuEvent
525
+ #cursor_lamp_pixmap=QtGui.QPixmap(''+ icons_path +'cursor_lamp.png').scaled(QSize(24,24), Qt.KeepAspectRatio)
526
+ #cursor_lamp = QtGui.QCursor(cursor_lamp_pixmap,-1,-1)
527
+ #self.ui.logo.setCursor(cursor_lamp)
528
+
529
+ self.aboutDialog=None
530
+ self.logChanges:Log_Tab=None
531
+ self.whatsNew=lambda: whatsNew(self)
532
+
533
+ self.ui.button_PaIRS_download.setCursor(Qt.CursorShape.PointingHandCursor)
534
+ self.ui.button_PaIRS_download.setVisible(False)
535
+ self.signals.printOutDated.connect(self.setButtonDownload)
536
+
537
+ self.fontPixelSize=fontPixelSize
538
+ self.setDefaultSizes()
539
+
540
+ self.ui.title_workspace.bullet=GPApar().saveBullet()
541
+
542
+ #------------------------------------- Declaration of parameters
543
+ self.PaIRS_threadpool=QThreadPool()
544
+ if NUMTHREADS_gPaIRS:
545
+ self.PaIRS_threadpool.setMaxThreadCount(NUMTHREADS_gPaIRS)
546
+
547
+ self.FlagRun=0
548
+ self.procWorkers=[]
549
+ self.contProc=self.nProc=0
550
+ self.procdata=None
551
+ self.FlagResetPlot=False
552
+ self.FlagProcInit=False
553
+ self.FlagProcPlot=False
554
+ self.procFields=['numProcOrErrTot','Log','list_print','list_pim','numCallBackTotOk','numFinalized','flagRun','flagParForCompleted']
555
+ self.namesPIV=NamesPIV()
556
+
557
+ #self.defineFloatings()
558
+ self.FloatingTabs=[]
559
+ self.FloatingWindows=[]
560
+
561
+ self.menuDebug=None
562
+ self.completingTask=None
563
+ self.waitingDialog=None
564
+
565
+ #------------------------------------- Callbacks
566
+ self.ui.Explorer.adjustProcessSelection=self.adjustProcessSelection
567
+ self.ui.Explorer.projectTree.adjustSelection=self.adjustProjectSelection
568
+ self.projectTree.editingFinished=self.adjustProcessSelection
569
+ self.processTree.editingFinished=lambda: self.editingFinished(self.processTree)
570
+ self.binTree.editingFinished=lambda: self.editingFinished(self.binTree)
571
+
572
+ self.ui.button_Run.clicked.connect(self.button_run_pause_action)
573
+ self.ui.button_pause.clicked.connect(self.button_run_pause_action)
574
+
575
+ self.ui.workspace_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
576
+ self.ui.workspace_icon.pressed.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet("border: none; background: #dcdcdc;"))
577
+ self.ui.workspace_icon.released.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet(btn.default_stylesheet))
578
+ pixmap_workspace=QPixmap(icons_path+'workspace.png')
579
+ self.ui.workspace_icon.clicked.connect(lambda: self.warningDialog(self.GPApar.InfoMessage(),pixmap=pixmap_workspace,title='Workspace information'))
580
+
581
+ self.currITEpar=self.TREpar
582
+ self.ui.title_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
583
+ self.ui.title_icon.pressed.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet("border: none; background: #dcdcdc;"))
584
+ self.ui.title_icon.released.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet(btn.default_stylesheet))
585
+ pixmap_workspace=QPixmap(icons_path+'workspace.png')
586
+ self.ui.title_icon.clicked.connect(lambda: self.warningDialog(self.currITEpar.InfoMessage(),pixmap=TreeIcons.pixmaps[self.currITEpar.icon],title=f"{self.currITEpar.basename} information"))
587
+
588
+ setButtonHoverStyle(self.ui.logo,FlagBorder=False,borderRadius=int(self.ui.logo.height()/2))
589
+
590
+ class RCLbar:
591
+ buttons={0: self.ui.button_reset_step,
592
+ 1: self.ui.button_step_inherit,
593
+ 2: self.ui.button_copy_step,
594
+ 3: self.ui.button_link_step}
595
+ buttonData={0: {'name': 'Reset step'},
596
+ 1: {'name': 'Copy input/output data from...'},
597
+ 2: {'name': 'Copy step from...'},
598
+ 3: {'name': 'Link step to...'}}
599
+ self.RCLbar=RCLbar()
600
+ self.ui.Explorer.processActionBar.additionalButtonBars['items'].append(self.RCLbar)
601
+
602
+ self.installEventFilter(self)
603
+
604
+ #------------------------------------- Initialization
605
+ from .PaIRS_pypacks import basefold
606
+ basefold=myStandardPath(basefold)
607
+ self.initialize()
608
+
609
+ #------------------------------------- Debug
610
+ self.addDebugMenu()
611
+ self.setMenuStyle()
612
+ self.menuDebug.setFont(self.ui.menuFile.font())
613
+ self.menuDebug.menuAction().setVisible(Flag_DEBUG)
614
+ self.userDebugShortcut = QShortcut(QKeySequence('Shift+Alt+D'), self)
615
+ self.userDebugShortcut.activated.connect(self.userDebugMode)
616
+ self.developerDebugShortcut = QShortcut(QKeySequence('Alt+D, Alt+E, Alt+B, Alt+Return'), self)
617
+ self.developerDebugShortcut.activated.connect(lambda:self.setDebugMode(True))
618
+ #self.exitDebugShortcut = QShortcut(QKeySequence('Shift+Alt+D'), self)
619
+ #self.exitDebugShortcut.activated.connect(lambda:self.setDebugMode(False))
620
+ self.setDebugMode(flagDebug)# should be put not upper than here
621
+ pri.Time.blue(0,'dopo setupUi')
622
+ self.FlagClosing=[False]
623
+ #self.setupPathCompleter()
624
+
625
+ self.FlagGuiInit=True
626
+ self.load_gif = QMovie(u""+ icons_path +"loading_2.gif")
627
+ self.load_gif.start()
628
+ self.loaded_map=QPixmap(u""+ icons_path + "loaded.png")
629
+ self.parPoolInitSetup()
630
+ #todo gerardo spostare questa stampa alla fine di tutto anche se ripetuta
631
+ if self.flagSimpleFor:print('\n\n\n\n\n\nflagSimplefor=True \nAre you really working with the c library?\n\n\n\n\n\n\n\n')
632
+ pri.Time.blue(0,'fine di tutto init')
633
+
634
+ def initialize(self):
635
+ pri.Info.yellow('||| Initializing gPaIRS |||')
636
+ if os.path.exists(lastcfgname):
637
+ self.open_workspace(filename=lastcfgname,FlagSetGeometry=True)
638
+ self.GPApar_old.copyfrom(self.GPApar)
639
+ else:
640
+ self.adjustProjectSelection()
641
+ self.setGPaIRSPalette()
642
+ return
643
+
644
+ def disableDropping(self,FlagDisableed=True):
645
+ self.projectTree.setDragEnabled(not FlagDisableed)
646
+ self.processTree.setDragEnabled(not FlagDisableed)
647
+
648
+ def setSwitchEnabled(self,FlagEnabled=True):
649
+ for k in range(len(self.projectTree.itemList[0])):
650
+ topLevelItem=self.projectTree.topLevelItem(k)
651
+ itemWidget=self.projectTree.itemWidget(topLevelItem,1)
652
+ if itemWidget:
653
+ switch:ModernSwitch=itemWidget.findChildren(ModernSwitch)[0]
654
+ if switch:
655
+ switch.setEnabled(FlagEnabled)
656
+ for k in range(self.processTree.topLevelItemCount()):
657
+ topLevelItem=self.processTree.topLevelItem(k)
658
+ itemWidget=self.processTree.itemWidget(topLevelItem,1)
659
+ if itemWidget:
660
+ switch:ModernSwitch=itemWidget.findChildren(ModernSwitch)[0]
661
+ if switch:
662
+ switch.setEnabled(FlagEnabled)
663
+
664
+ def setButtonRunVisible(self):
665
+ FlagButtonRun=any([tre.FlagRunnable and tre.FlagQueue for tre in self.projectTree.itemList[0]])
666
+ if not FlagButtonRun:
667
+ self.ui.button_Run.setVisible(False)
668
+ self.ui.button_pause.setVisible(False)
669
+ self.ui.w_progress_Proc.setVisible(False)
670
+ self.ui.progress_Proc.setValue(0)
671
+ self.ui.time_stamp.setText('Initializing...')
672
+ else:
673
+ FlagButtonRun=self.ui.progress_Proc.value() in (0,self.ui.progress_Proc.maximum()) and self.FlagRun==0
674
+ self.ui.button_Run.setVisible(FlagButtonRun)
675
+ self.ui.button_pause.setVisible(not FlagButtonRun)
676
+ self.ui.w_progress_Proc.setVisible(not FlagButtonRun)
677
+ self.ui.tabAreaWidget.display_controls()
678
+
679
+ def editingFinished(self,tree):
680
+ self.ui.Explorer.arrangeCurrentProcess(tree)
681
+ self.adjustProcessSelection()
682
+
683
+ def defineFloatings(self):
684
+ self.FloatingTabs=[]
685
+ for wid in self.tabWidgets[:-1]:
686
+ self.FloatingTabs.append(FloatingObject(self,wid))
687
+ self.GPApar.FloatGeometry.append(self.geometry())
688
+ self.GPApar.FloatingsVis.append(self.isVisible())
689
+
690
+ #********************************************* TAB definitions
691
+ def defineTabs(self):
692
+ self.w_Input = Input_Tab(self,False)
693
+ pri.Time.magenta('Input')
694
+ self.w_Output = Output_Tab(self,False)
695
+ pri.Time.magenta('Output')
696
+ self.w_Process = Process_Tab(self,False)
697
+ pri.Time.magenta('Process')
698
+ self.w_Log = Log_Tab(self,False)
699
+ pri.Time.magenta('Log')
700
+ self.w_Vis = Vis_Tab(self,False)
701
+ pri.Time.magenta('Vis')
702
+ self.w_Process_Min = Process_Tab_Min(self,False)
703
+ pri.Time.magenta('Process_Min')
704
+ self.w_Process_Disp = Process_Tab_Disp(self,False)
705
+ pri.Time.magenta('Process_Disp')
706
+ self.w_Calibration = Calibration_Tab(self,False)
707
+ pri.Time.magenta('Calibration')
708
+ self.w_Input_CalVi = Input_Tab_CalVi(self,False)
709
+ pri.Time.magenta('Input_CalVi')
710
+ self.w_Process_CalVi = Process_Tab_CalVi(self,False)
711
+ pri.Time.magenta('Process_CalVi')
712
+ self.w_Vis_CalVi = Vis_Tab_CalVi(self,False)
713
+ pri.Time.magenta('Vis_CalVi')
714
+ self.tabWidgets=[ self.w_Calibration,
715
+ self.w_Input,self.w_Input_CalVi,
716
+ self.w_Output,
717
+ self.w_Process,self.w_Process_Min,self.w_Process_Disp,self.w_Process_CalVi,
718
+ self.w_Log,
719
+ self.w_Vis,self.w_Vis_CalVi ]
720
+ self.tabTypes=[type(w) for w in self.tabWidgets]
721
+ pri.Time.blue(2,f'gPaIRS generazione tabs')
722
+
723
+ icons=[w.TABname.split('_')[0].lower()+'_logo' for w in self.tabWidgets]
724
+ self.ui.tabAreaWidget.setupTabArea(self.tabWidgets,icons)
725
+ self.ui.tabAreaWidget.gui=self
726
+ self.tabWidgets=self.tabWidgets+[self.ui.tabAreaWidget]
727
+ self.tabNames=[tab.TABname for tab in self.tabWidgets]
728
+
729
+ self.w_Input.ui.imTreeWidget.disableTab=self.disableTab_ImTree
730
+
731
+ self.ui.projectPage.ITEM_HEIGHT=80
732
+ self.ui.projectPage.title.setText("Select a project")
733
+ self.ui.projectPage.setupPage(projectPageButtons,self.ui.Explorer.projectPageActions)
734
+ self.ui.processPage.title.setText("Select a process")
735
+ self.ui.processPage.setupPage(processData,self.ui.Explorer.processPageActions)
736
+ self.ui.stepPage.title.setText("Set up each step of the process")
737
+ self.ui.stepPage.setupPage(stepData,self.ui.Explorer.stepPageActions)
738
+ self.ui.Explorer.stepPage=self.ui.stepPage
739
+
740
+ self.projectTree=self.ui.Explorer.projectTree
741
+ self.processTree=self.ui.Explorer.processTree
742
+ self.binTree=self.ui.Explorer.binTree
743
+ self.TREpar=self.ui.Explorer.TREpar
744
+
745
+ self.ui.Explorer.gui=self
746
+ self.projectTree.gui=self
747
+ self.processTree.gui=self
748
+ self.binTree.gui=self
749
+
750
+ for w in self.tabWidgets:
751
+ w:gPaIRS_Tab
752
+ w.TABpar_prev=[]
753
+ self.processTree.itemList=[]
754
+ self.binTree.itemList=[]
755
+
756
+ self.ui.Explorer.widgets=self.tabWidgets
757
+ self.projectTree.setupWidgets(self.tabWidgets)
758
+ self.processTree.setupWidgets(self.tabWidgets)
759
+ self.binTree.setupWidgets(self.tabWidgets)
760
+
761
+ self.projectTree.modifyWorkspace=self.modifyWorkspace
762
+ self.projectTree.adjustSwitches=self.adjustSwitches
763
+ self.processTree.adjustSwitches=self.adjustSwitches
764
+ self.projectTree.signals.updateLists.connect(self.updateWorkspace)
765
+ self.processTree.signals.updateLists.connect(self.updateProjectItemWidget)
766
+
767
+ #self.ui.button_back.hide()
768
+ #self.ui.button_forward.hide()
769
+
770
+ self.ui.w_header.layout().removeWidget(self.ui.logo_CalVi)
771
+ self.ui.w_header.layout().removeWidget(self.ui.button_Run_CalVi)
772
+ self.ui.w_header.layout().removeWidget(self.ui.button_Abort_CalVi)
773
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.ui.logo_CalVi)
774
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.ui.button_Run_CalVi)
775
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.ui.button_Abort_CalVi)
776
+ self.ui.button_Run_CalVi.setFixedHeight(TabAreaWidget.buttonSize[1])
777
+ self.ui.button_Abort_CalVi.setFixedHeight(TabAreaWidget.buttonSize[1])
778
+ self.ui.tabAreaWidget.buttonBar.setMaximumHeight(TabAreaWidget.buttonSize[1])
779
+
780
+ self.ui.logo_CalVi.setVisible(False)
781
+ self.ui.button_Run_CalVi.setVisible(False)
782
+ self.ui.button_Abort_CalVi.setVisible(False)
783
+ self.ui.button_Run_CalVi.clicked.connect(self.runCalVi)
784
+ self.ui.button_Abort_CalVi.clicked.connect(self.abortCalVi)
785
+ self.w_Input_CalVi.setRunCalViButtonText=lambda: self.setRunCalViButtonText(False)
786
+ setattr(self.w_Calibration,'logo_CalVi',self.ui.logo_CalVi)
787
+ setattr(self.w_Calibration,'button_Run_CalVi',self.ui.button_Run_CalVi)
788
+
789
+ for w in self.tabWidgets:
790
+ w:gPaIRS_Tab
791
+ w.FlagDisplayControls=False
792
+ self.w_Input.ui.w_Mode.layout().removeWidget(self.w_Input.ui.button_back)
793
+ self.w_Input.ui.w_Mode.layout().removeWidget(self.w_Input.ui.button_forward)
794
+ self.w_Input.ui.button_back.clicked.disconnect()
795
+ self.w_Input.ui.button_forward.clicked.disconnect()
796
+ self.w_Input.display_controls=lambda:None
797
+
798
+ self.ui.w_header.layout().removeWidget(self.ui.button_restore_undo)
799
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.ui.button_restore_undo)
800
+ self.ui.button_restore_undo.setFixedWidth(TabAreaWidget.buttonSize[1])
801
+ self.ui.button_restore_undo.setFixedHeight(TabAreaWidget.buttonSize[1])
802
+ self.ui.button_restore_undo.clicked.connect(self.fullCallback)
803
+ self.ui.tabAreaWidget.ui.button_restore_undo=self.ui.button_restore_undo
804
+
805
+ self.ui.tabAreaWidget.FlagDisplayControls=True
806
+ self.ui.tabAreaWidget.ui.button_back=self.w_Input.ui.button_back
807
+ self.ui.tabAreaWidget.ui.button_back.clicked.connect(lambda: self.button_back_forward_action(-1))
808
+ self.ui.tabAreaWidget.ui.button_back.contextMenuEvent=lambda e: self.bfContextMenu(-1,e)
809
+
810
+ self.ui.tabAreaWidget.ui.button_forward=self.w_Input.ui.button_forward
811
+ self.ui.tabAreaWidget.ui.button_forward.clicked.connect(lambda: self.button_back_forward_action(+1))
812
+ self.ui.tabAreaWidget.ui.button_forward.contextMenuEvent=lambda e: self.bfContextMenu(+1,e)
813
+
814
+ self.onlyReadLabel=QLabel('Read-Only')
815
+ font=self.onlyReadLabel.font()
816
+ font.setBold(True)
817
+ font.setItalic(True)
818
+ font.setPixelSize(fontPixelSize)
819
+ self.onlyReadLabel.setFont(font)
820
+ self.onlyReadLabel.setStyleSheet('color: rgb(51, 102, 255)') #('color: rgb(255,51,51);')
821
+ #self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.onlyReadLabel)
822
+ self.ui.tabAreaWidget.onlyReadLabel=self.onlyReadLabel
823
+ self.ui.tabAreaWidget.button_reset_step=self.ui.button_reset_step
824
+ self.ui.tabAreaWidget.button_step_inherit=self.ui.button_step_inherit
825
+ self.ui.tabAreaWidget.button_copy_step=self.ui.button_copy_step
826
+ self.ui.tabAreaWidget.button_link_step=self.ui.button_link_step
827
+
828
+ self.w_RCL = QWidget(self) #CLR: copy, link, reset
829
+ self.RCL_layout = QHBoxLayout()
830
+ self.RCL_layout.setContentsMargins(0, 0, 0, 0)
831
+ self.RCL_layout.setSpacing(actionButtonSpacing*2)
832
+ self.w_RCL.setLayout(self.RCL_layout)
833
+
834
+ self.RCL_layout.addSpacerItem(QSpacerItem(projectActionButtonSize[1], projectActionButtonSize[1], QSizePolicy.Expanding, QSizePolicy.Minimum))
835
+ self.RCL_layout.addWidget(self.onlyReadLabel)
836
+ self.RCL_layout.addSpacerItem(QSpacerItem(5, projectActionButtonSize[1], QSizePolicy.Minimum, QSizePolicy.Minimum))
837
+ for b in [self.ui.button_reset_step,self.ui.button_step_inherit,self.ui.button_copy_step,self.ui.button_link_step]:
838
+ self.ui.w_header.layout().removeWidget(b)
839
+ #self.ui.tabAreaWidget.buttonBar_layout.addWidget(b)
840
+ #b.setFixedSize(TabAreaWidget.buttonSize[1],TabAreaWidget.buttonSize[1])
841
+ #b.setIconSize(QSize(TabAreaWidget.buttonSize[1]-8,TabAreaWidget.buttonSize[1]-8))
842
+ self.RCL_layout.addWidget(b)
843
+ b.setFixedSize(projectActionButtonSize[1],projectActionButtonSize[1])
844
+ b.setIconSize(QSize(projectActionButtonSize[0],projectActionButtonSize[0]))
845
+ if hasattr(self,b.objectName()+'_action'):
846
+ b.clicked.connect(getattr(self,b.objectName()+'_action'))
847
+ self.ui.Explorer.processTree_layout.addWidget(self.w_RCL)
848
+
849
+ self.w_Input.ui.button_back.setFixedSize(TabAreaWidget.buttonSize[1],TabAreaWidget.buttonSize[1])
850
+ self.w_Input.ui.button_back.setIconSize(QSize(TabAreaWidget.buttonSize[1]-2,TabAreaWidget.buttonSize[1]-2))
851
+ self.w_Input.ui.button_forward.setFixedSize(TabAreaWidget.buttonSize[1],TabAreaWidget.buttonSize[1])
852
+ self.w_Input.ui.button_forward.setIconSize(QSize(TabAreaWidget.buttonSize[1]-2,TabAreaWidget.buttonSize[1]-2))
853
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.w_Input.ui.button_back)
854
+ self.ui.tabAreaWidget.buttonBar_layout.addWidget(self.w_Input.ui.button_forward)
855
+
856
+ self.ui.tabAreaWidget.FlagPrevPropagation=FlagPrevPropagationTabSplitter
857
+ self.ui.Explorer.inheritance=self.inheritance
858
+
859
+ self.brush_icon=QIcon(icons_path+"brush_cursor.png")
860
+ self.w_Vis.ui.icon.addfuncclick['copy_VIS']=lambda: self.copy_link_action(self.w_Vis.ui.name_tab,lambda isl,ima: self.copy_VIS(isl,ima),menuTitle='Copy graphical settings from...',message='No other process of the same type is available!',icon=self.brush_icon)
861
+ self.w_Vis.ui.icon.setCustomCursor()
862
+
863
+ self.defineTABbridges()
864
+
865
+ for c in self.findChildren(PaIRSTree):
866
+ c:PaIRSTree
867
+ c.gui=self
868
+
869
+ def fullCallback(self):
870
+ for w in self.tabWidgets:
871
+ w:gPaIRS_Tab
872
+ TABpar_ind=w.TABpar_at(w.TABpar.ind[:-1]+[-1])
873
+ if TABpar_ind:
874
+ if w.TABpar.isDifferentFrom(TABpar_ind,exceptions=w.TABpar.unchecked_fields+['ind']):
875
+ w.TABpar.ind[-1]=-1
876
+ w.fullCallback('Restored configuration')
877
+ break
878
+ ind=[i for i in w.TABpar.ind]
879
+ ind[-1]=-1
880
+ self.setTABpars_at(ind)
881
+
882
+ def setMenuStyle(self):
883
+ menu_style = gPaIRS_QMenu_style
884
+ self.ui.menu.setStyleSheet(menu_style)
885
+ self.ui.menuFile.setStyleSheet(menu_style)
886
+ self.ui.menuHelp.setStyleSheet(menu_style)
887
+ self.menuDebug.setStyleSheet(menu_style)
888
+ self.ui.menubar.setStyleSheet(menu_style.replace("QMenu","QMenuBar"))
889
+
890
+ def defineMenuActions(self):
891
+ self.projectTree.button_open_action=self.open_project
892
+ self.projectTree.button_save_action=self.save_project
893
+ self.projectTree.button_saveas_action=self.saveas_project
894
+ self.projectTree.button_close_action=self.close_project
895
+ self.projectTree.button_clean_action=self.clean_projects
896
+
897
+ self.processTree.button_delete_action=self.delete_process
898
+ self.processTree.button_clean_action=self.clean_processes
899
+
900
+ self.ui.actionPaIRS_Run.triggered.connect(lambda: runPaIRS(self,))
901
+ self.ui.actionPaIRS_Clean_run.triggered.connect(lambda: runPaIRS(self,'-c'))
902
+ self.ui.actionPaIRS_Debug_run.triggered.connect(lambda: runPaIRS(self,'-d'))
903
+
904
+ actions=self.ui.menuFile.actions()
905
+ for a in actions:
906
+ aName=a.objectName().replace('action','').lower()
907
+ if hasattr(self,'menu_'+aName+'_action'):
908
+ a.triggered.connect(getattr(self,'menu_'+aName+'_action'))
909
+ self.ui.aExit.triggered.connect(lambda: self.close())
910
+
911
+ self.showChanges=lambda: changes(self,Log_Tab,fileChanges)
912
+ self.ui.actionChanges.triggered.connect(self.showChanges)
913
+ self.ui.actionGuide.triggered.connect(self.guide)
914
+ self.ui.actionDownload.setVisible(not Flag_ISEXE)
915
+ if not Flag_ISEXE:
916
+ self.ui.menuHelp.insertSeparator(self.ui.actionDownload)
917
+ self.ui.actionDownload.triggered.connect(self.downloadApp)
918
+ self.ui.actionAbout.triggered.connect(self.about)
919
+
920
+ self.ui.button_PaIRS_download.clicked.connect(lambda: button_download_PaIRS_action(self,self.app))
921
+
922
+ def disableTab_ImTree(self,Flag=True):
923
+ self.ui.w_Managing_Tabs.setEnabled(not Flag)
924
+ for w in self.tabWidgets:
925
+ w:gPaIRS_Tab
926
+ if w!=self.w_Input and w!=self.ui.tabAreaWidget:
927
+ w.setEnabled(not Flag)
928
+ self.w_Input.ui.CollapBox_ImSet.setEnabled(not Flag)
929
+ self.w_Input.ui.w_InputFold_Button.setEnabled(not Flag)
930
+ self.w_Input.ui.imTreeWidget.setEnabled(True)
931
+
932
+ self.w_Input.ui.button_back.setEnabled(not Flag)
933
+ self.w_Input.ui.button_forward.setEnabled(not Flag)
934
+
935
+ self.ui.menubar.setEnabled(not Flag)
936
+
937
+ #evita TABpar.FlagSettingPar=Flag così che sai dove FlagSettingPar è settato True o False
938
+ ImageTreeWidget.disableTab(self.w_Input.ui.imTreeWidget,Flag)
939
+
940
+ def button_back_forward_action(self,step):
941
+ self.w_Input.FlagSettingPar=True
942
+ self.setFocus()
943
+ self.w_Input.FlagSettingPar=False
944
+ for w in self.tabWidgets:
945
+ w:gPaIRS_Tab
946
+ if not w.TABpar.FlagNone:
947
+ ind=w.TABpar.ind
948
+ ind[-1]+=step
949
+ w.TABpar.copyfrom(w.TABpar_at(ind))
950
+ FlagAdjustPar=w.TABpar.FlagInit==False or w.TABpar.Process==ProcessTypes.cal #w.TABpar.ind[-1]==0
951
+ FlagBridge=w.TABpar.Process==ProcessTypes.cal #False
952
+ if FlagAdjustPar or FlagBridge:
953
+ for w in self.tabWidgets:
954
+ if not w.TABpar.FlagNone:
955
+ w:gPaIRS_Tab
956
+ if FlagAdjustPar:
957
+ FlagSettingPar=TABpar.FlagSettingPar
958
+ TABpar.FlagSettingPar=True
959
+ w.adjustTABpar()
960
+ TABpar.FlagSettingPar=FlagSettingPar
961
+ if FlagBridge: self.bridge(w.TABname)
962
+ FlagAdjustPar=False
963
+ FlagBridge=False
964
+ for w in self.tabWidgets:
965
+ w:gPaIRS_Tab
966
+ if not w.TABpar.FlagNone:
967
+ w.setTABpar(FlagAdjustPar,FlagBridge)
968
+ self.ui.Explorer.setITElayout()
969
+ return
970
+
971
+ def bfContextMenu(self,bf,event):
972
+ ind=self.ui.tabAreaWidget.TABpar.ind
973
+ i=ind[-1]
974
+ TABpar_prev=self.ui.tabAreaWidget.TABpar_prev_at(ind)
975
+
976
+ if bf==-1:
977
+ b=self.ui.tabAreaWidget.ui.button_back
978
+ kin=max([0,i-Num_Prevs_back_forw])
979
+ krange=[k for k in range(i-1,kin,-1)]+[0]
980
+ icon=self.ui.tabAreaWidget.undo_icon
981
+ d=1
982
+ elif bf==1:
983
+ b=self.ui.tabAreaWidget.ui.button_forward
984
+ kfin=min([len(TABpar_prev)-1,i+Num_Prevs_back_forw])
985
+ krange=[k for k in range(i+1,kfin)]+[len(TABpar_prev)-1]
986
+ icon=self.ui.tabAreaWidget.redo_icon
987
+ d=0
988
+
989
+ menu=QMenu(b)
990
+ act=[]
991
+ nur=len(krange)
992
+ flag=nur==Num_Prevs_back_forw
993
+ for j,k in enumerate(krange):
994
+ if j==nur-1:
995
+ if flag: menu.addSeparator()
996
+ if k==0: s=' (first)'
997
+ else: s=' (current)'
998
+ else:
999
+ if j==nur-2 and flag:
1000
+ s=' (...)'
1001
+ else:
1002
+ s=''
1003
+ n=f"{k-i:+d}: "
1004
+ name=n+TABpar_prev[k+d].tip+s
1005
+ act.append(QAction(icon,name,b))
1006
+ menu.addAction(act[-1])
1007
+
1008
+ action = menu.exec_(b.mapToGlobal(event.pos()))
1009
+ for k,a in zip(krange,act):
1010
+ if a==action:
1011
+ self.button_back_forward_action(-i+k)
1012
+
1013
+ def defineTABbridges(self):
1014
+ for w in self.tabWidgets: #[:-1] except tabArea
1015
+ w:gPaIRS_Tab
1016
+ self.define_add_TABpar_bridge(w)
1017
+ self.define_setTABpar_bridge(w)
1018
+
1019
+ def setTABpars_at(self,ind,FlagAdjustPar=False,FlagBridge=True,widget:gPaIRS_Tab=None):
1020
+ for w in self.tabWidgets:
1021
+ w:gPaIRS_Tab
1022
+ TABpar_ind:TABpar=w.TABpar_at(ind)
1023
+ if TABpar_ind:
1024
+ if not TABpar_ind.FlagNone:
1025
+ w.TABpar.copyfrom(TABpar_ind)
1026
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(ind)
1027
+ self.ui.Explorer.ITEpar.copyfrom(ITE_ind,exceptions=['procdata'])
1028
+ self.ui.Explorer.ITEpar.procdata=dataTreePar(ITE_ind.Process,ITE_ind.Step)
1029
+ self.ui.Explorer.ITEpar.procdata.ind=self.ui.Explorer.ITEpar.ind
1030
+ self.ui.Explorer.ITEpar.procdata.copyfrom(ITE_ind.procdata)
1031
+ if widget is None:
1032
+ self.ui.tabAreaWidget.setTABpar(FlagAdjustPar,FlagBridge)
1033
+ else:
1034
+ widget.setTABpar(FlagAdjustPar,FlagBridge)
1035
+ self.ui.tabAreaWidget.display_controls()
1036
+
1037
+ def define_add_TABpar_bridge(self,tab:gPaIRS_Tab):
1038
+ def add_TABpar_bridge(tip,ind):
1039
+ tab.TABpar.parentTab=tab.TABname
1040
+ for w in self.tabWidgets:
1041
+ w:gPaIRS_Tab
1042
+ if w!=tab:
1043
+ w:gPaIRS_Tab
1044
+ w.TABpar.ind=[i for i in ind]
1045
+ ind_new=w.add_TABpar_copy(tip,ind) #setting parameters without bridge
1046
+ ITE:ITEpar=self.ui.Explorer.ITEfromInd(ind)
1047
+ ITE.ind[-1]=ind_new[-1]
1048
+ self.ui.Explorer.ITEpar.ind[-1]=ind_new[-1]
1049
+ ITEs:ITEpar=self.ui.Explorer.ITEsfromInd(ind_new)
1050
+ ITEs[0].modifiedDate=currentTimeString()
1051
+ ITEs[0].date=f'Modified: {ITE.modifiedDate}'
1052
+
1053
+ TRE:TREpar=self.projectTree.itemList[0][ITE.ind[0]]
1054
+ TRE.modifiedDate=ITEs[0].modifiedDate
1055
+ TRE.date=ITEs[0].date
1056
+ TRE.FlagSaved=False
1057
+
1058
+ self.GPApar.modifiedDate=ITEs[0].modifiedDate
1059
+ self.GPApar.date=ITEs[0].date
1060
+ self.GPApar.FlagSaved=False
1061
+
1062
+ self.ui.Explorer.ITEpar.copyfrom(ITE)
1063
+ self.TREpar.copyfrom(TRE)
1064
+ self.adjustItemWidgets(ind)
1065
+
1066
+ self.inheritance(ind_new)
1067
+ self.IOVinheritance(ind_new)
1068
+ self.adjustDependencies(ITE)
1069
+
1070
+ for w in self.tabWidgets[:-1]:
1071
+ w:gPaIRS_Tab
1072
+ w.adjustFromTABparInd(ind_new)
1073
+ w.setTABWarnLabel()
1074
+ self.w_Log.setLogText()
1075
+ #self.checkFutureProc()
1076
+ tab.add_TABpar_bridge=add_TABpar_bridge
1077
+
1078
+ def define_setTABpar_bridge(self,tab:gPaIRS_Tab):
1079
+ def setTABpar_bridge(FlagAdjustPar,FlagCallback=False):
1080
+ focusWidget=self.focusWidget()
1081
+ TABname=tab.TABname
1082
+ self.bridge(TABname)
1083
+ if FlagAdjustPar:
1084
+ FlagSettingPar=TABpar.FlagSettingPar
1085
+ TABpar.FlagSettingPar=True
1086
+ for w in self.tabWidgets:
1087
+ if w.TABpar.FlagNone: continue
1088
+ w:gPaIRS_Tab
1089
+ if w!=tab:
1090
+ w.adjustTABpar()
1091
+ self.bridge(w.TABname)
1092
+ TABpar.FlagSettingPar=FlagSettingPar
1093
+ FlagAdjustPar=False
1094
+ FlagBridge=False
1095
+ FlagDisplayControls=False
1096
+ for w in self.tabWidgets:
1097
+ w:gPaIRS_Tab
1098
+ if not w.TABpar.FlagNone and w!=self.w_Log:
1099
+ if w.TABpar_old.isDifferentFrom(w.TABpar,exceptions=['ind'],FlagStrictDiff=True):
1100
+ w.setTABpar(FlagAdjustPar,FlagBridge,FlagCallback,FlagDisplayControls) #setting parameters without bridge
1101
+ else:
1102
+ if w==self.w_Vis_CalVi and w.TABpar.plane and w.TABpar.cam:
1103
+ self.w_Vis_CalVi.calibView.show()
1104
+ w.TABpar_old.copyfrom(w.TABpar,exceptions=['ind'])
1105
+ if not FlagCallback:
1106
+ w.adjustTABparInd()
1107
+ self.ui.Explorer.ITEpar.FlagInit=False
1108
+ self.ui.Explorer.setITElayout()
1109
+ if not self.w_Log.TABpar.FlagNone:
1110
+ if self.w_Log.LOGpar.flagRun!=-2:
1111
+ self.logBridge()
1112
+ if self.w_Log.TABpar_old.isDifferentFrom(self.w_Log.TABpar,FlagStrictDiff=True):
1113
+ self.w_Log.setTABpar(FlagAdjustPar,FlagBridge,FlagCallback)
1114
+ else:
1115
+ self.w_Log.TABpar_old.copyfrom(self.w_Log.TABpar,exceptions=['ind'])
1116
+ if not FlagCallback: self.w_Log.adjustTABparInd()
1117
+ else:
1118
+ self.w_Log.setTABpar(FlagAdjustPar=False,FlagBridge=False,FlagCallback=False)
1119
+ if not FlagCallback:
1120
+ self.inheritance(tab.TABpar.ind)
1121
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(tab.TABpar.ind)
1122
+ self.adjustDependencies(ITE_ind)
1123
+ self.ui.tabAreaWidget.display_controls()
1124
+
1125
+ if focusWidget:
1126
+ self.app.processEvents()
1127
+ focusWidget.setFocus()
1128
+ tab.setTABpar_bridge=setTABpar_bridge
1129
+
1130
+ def logBridge(self,ind=None):
1131
+ if ind is None:
1132
+ OUT:OUTpar = self.w_Output.TABpar
1133
+ LOG:LOGpar = self.w_Log.TABpar
1134
+ VIS:VISpar = self.w_Vis.TABpar
1135
+ ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1136
+ else:
1137
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1138
+ LOG:LOGpar = self.w_Log.TABpar_at(ind)
1139
+ VIS:VISpar = self.w_Vis.TABpar_at(ind)
1140
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1141
+
1142
+ if LOG is None or LOG.FlagNone: return
1143
+
1144
+ if ITE.flagRun==0:
1145
+ warningMessages=[]
1146
+ errorMessages=[]
1147
+ for w in self.tabWidgets[:-1]:
1148
+ w:gPaIRS_Tab
1149
+ if ind is None:
1150
+ par:TABpar= w.TABpar
1151
+ else:
1152
+ par:TABpar= w.TABpar_at(ind)
1153
+ if w!=self.w_Log and par is not None and not par.FlagNone:
1154
+ if par.OptionDone==0: errorMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1155
+ elif par.OptionDone!=1: warningMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1156
+
1157
+
1158
+ warnigText='\n\n'.join(warningMessages)
1159
+ if warnigText:
1160
+ warnigText='\n\n'+ITE.procdata.headerSection('WARNINGS',warnigText,'!')
1161
+ errorText='\n\n'.join(errorMessages)
1162
+ if errorText:
1163
+ errorText='\n\n'+ITE.procdata.headerSection('CRITICAL ISSUES',errorText,'X')
1164
+ LOG.text=PaIRS_Header+ITE.procdata.itemname+warnigText+errorText
1165
+ if VIS.FlagView:
1166
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1167
+ logfile=ITE.procdata.procOutName()+'.log'
1168
+ if ITE.procdata.outPathRoot=='': logfile=outPathRoot+logfile
1169
+ border='o' #·●⦁᛫
1170
+ headerWidth=54
1171
+ result_text = '\n\n\n\n\n'+ITE.procdata.eyeHeaderSection('EXISTING PROCESS LOG',width=headerWidth,border=border) +f"\nLog file: '{os.path.basename(logfile)}'\n\n"
1172
+ if os.path.isfile(logfile):
1173
+ try:
1174
+ with open(logfile, 'r', encoding='utf-8') as f:
1175
+ log_content = f.read()
1176
+ result_text += "\n" + log_content
1177
+ except Exception as e:
1178
+ result_text += f"\nError reading log file '{os.path.basename(logfile)}:'\n{e}"
1179
+ else:
1180
+ result_text += f"\nLog file '{os.path.basename(logfile)}' not found!"
1181
+ LOG.text+=result_text+'\n\n'+ITE.procdata.headerSection('END of EXISTING PROCESS LOG',' ',border,headerWidth)
1182
+ else:
1183
+ LOG.text=ITE.procdata.Log
1184
+
1185
+ def bridge(self,TABname:str,ind:list=None):
1186
+ if ind is None:
1187
+ INP:INPpar = self.w_Input.TABpar
1188
+ OUT:OUTpar = self.w_Output.TABpar
1189
+ PRO:PROpar = self.w_Process.TABpar
1190
+ VIS:VISpar = self.w_Vis.TABpar
1191
+
1192
+ PRO_Min:PROpar_Min = self.w_Process_Min.TABpar
1193
+ PRO_Disp:PROpar_Disp = self.w_Process_Disp.TABpar
1194
+
1195
+ CAL:CALpar = self.w_Calibration.TABpar
1196
+ INP_CalVi:INPpar_CalVi = self.w_Input_CalVi.TABpar
1197
+ PRO_CalVi:PROpar_CalVi = self.w_Process_CalVi.TABpar
1198
+ VIS_CalVi:VISpar_CalVi = self.w_Vis_CalVi.TABpar
1199
+
1200
+ ITE:ITEpar = self.ui.Explorer.TABpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1201
+ SPL:SPLpar = self.ui.tabAreaWidget.TABpar
1202
+ else:
1203
+ INP:INPpar = self.w_Input.TABpar_at(ind)
1204
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1205
+ PRO:PROpar = self.w_Process.TABpar_at(ind)
1206
+ VIS:VISpar = self.w_Vis.TABpar_at(ind)
1207
+
1208
+ PRO_Min:PROpar_Min = self.w_Process_Min.TABpar_at(ind)
1209
+ PRO_Disp:PROpar_Disp = self.w_Process_Disp.TABpar_at(ind)
1210
+
1211
+ CAL:CALpar = self.w_Calibration.TABpar_at(ind)
1212
+ INP_CalVi:INPpar_CalVi = self.w_Input_CalVi.TABpar_at(ind)
1213
+ PRO_CalVi:PROpar_CalVi = self.w_Process_CalVi.TABpar_at(ind)
1214
+ VIS_CalVi:VISpar_CalVi = self.w_Vis_CalVi.TABpar_at(ind)
1215
+
1216
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1217
+ SPL:SPLpar = self.ui.tabAreaWidget.TABpar_at(ind)
1218
+
1219
+ if ITE.Step in [StepTypes.min,StepTypes.piv,StepTypes.disp,StepTypes.spiv]:
1220
+ if TABname=='Input':
1221
+ OUT.inputPath=INP.path
1222
+ OUT.imageFile=None
1223
+ if INP.nimg:
1224
+ for c in range(len(INP.imList)):
1225
+ for f in range(len(INP.imList[c])):
1226
+ for k in range(len(INP.imList[c][f])):
1227
+ if INP.imEx[c][f][k]:
1228
+ OUT.imageFile=INP.imList[c][f][k]
1229
+ break
1230
+
1231
+ VIS.img=INP.selection[0]
1232
+ VIS.cam=INP.selection[1]
1233
+ VIS.frame=INP.selection[2]
1234
+ VIS.ncam=INP.ncam
1235
+ VIS.path=INP.path
1236
+ VIS.imList=copy.deepcopy(INP.imList)
1237
+ VIS.nimg=INP.nimg
1238
+ VIS.Out.copyfrom(OUT)
1239
+ elif TABname=='Output':
1240
+ if VIS.Out.isDifferentFrom(OUT):
1241
+ VIS.Out.copyfrom(OUT)
1242
+ self.w_Vis.FlagResetSizes=True
1243
+ if ITE.Step in [StepTypes.piv,StepTypes.disp,StepTypes.spiv]:
1244
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1245
+ ndig=len(str(VIS.nimg))
1246
+ outExt=list(outType_dict)[OUT.outType]
1247
+ VIS.outPathRoot=outPathRoot
1248
+ VIS.name_proc=ITE.procdata.name_proc
1249
+ VIS.fres=[outPathRoot+'_', ndig, outExt] #lambda i: f"{outPathRoot}_{i:0{ndig:d}d}{outExt}"
1250
+ elif ITE.Step == StepTypes.min:
1251
+ imListMin=[]
1252
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1253
+ for c in range(INP.ncam):
1254
+ imListMin.append([outPathRoot+f'_cam{c+1}_a_min.png',outPathRoot+f'_cam{c+1}_b_min.png'])
1255
+
1256
+ INP.FlagMIN = True
1257
+ INP.FlagTR = PRO_Min.FlagTR
1258
+ INP.LaserType = PRO_Min.LaserType
1259
+ INP.imListMin = deep_duplicate(imListMin)
1260
+
1261
+ VIS.FlagMIN = ITE.procdata.flagRun>0
1262
+ VIS.FlagTR = PRO_Min.FlagTR
1263
+ VIS.LaserType = PRO_Min.LaserType
1264
+ VIS.imListMin = deep_duplicate(imListMin)
1265
+ elif TABname=='Process_Min':
1266
+ INP.FlagTR=PRO_Min.FlagTR
1267
+ INP.LaserType=PRO_Min.LaserType
1268
+ VIS.FlagTR=PRO_Min.FlagTR
1269
+ VIS.LaserType=PRO_Min.LaserType
1270
+ elif TABname=='Process_Disp':
1271
+ if VIS.Pro.isDifferentFrom(PRO_Disp,exceptions=['FlagBordo']):
1272
+ VIS.Pro.copyfrom(PRO_Disp,exceptions=['FlagBordo'])
1273
+ VIS.Nit=PRO_Disp.Nit if VIS.flagRun!=-2 else ITE.procdata.numFinalized
1274
+ elif TABname=='Process':
1275
+ if VIS.Pro.isDifferentFrom(PRO):
1276
+ VIS.Pro.copyfrom(PRO)
1277
+ elif TABname=='Vis':
1278
+ INP.selection=[VIS.img,VIS.cam,VIS.frame]
1279
+ self.w_Input.InputAdjustSelection(INP)
1280
+ pass
1281
+ elif ITE.Step in [StepTypes.cal]:
1282
+ INP_CalVi.FlagReadCalib=PRO_CalVi.CalibProcType>=2
1283
+ INP_CalVi.CalibProcType=PRO_CalVi.CalibProcType
1284
+ if TABname=='Calibration':
1285
+ #FlagPrev=CAL.ind[-1]==len(self.w_Calibration.TABpar_prev_at(CAL.ind))-1
1286
+ self.ui.logo_CalVi.setVisible(CAL.FlagCalVi and CAL.flagRun==0 and not CAL.link) #and FlagPrev)
1287
+ self.ui.button_Run_CalVi.setVisible(CAL.FlagCalVi and CAL.flagRun==0 and not CAL.link) #and FlagPrev)
1288
+ if CAL.isDifferentFrom(self.w_Calibration.CALpar_old,fields=['FlagCalVi','flagRun']) or not INP_CalVi.FlagInit:
1289
+ for w in [self.w_Input_CalVi,self.w_Process_CalVi,self.w_Vis_CalVi]:
1290
+ k=self.ui.tabAreaWidget.widgets.index(w)
1291
+ SPL.FlagVisible[k]=CAL.FlagCalVi
1292
+ w.buttonTab.setVisible(CAL.FlagCalVi)
1293
+ self.ui.tabAreaWidget.splitterResize(FlagReleased=False)
1294
+ width=sum([s if f else 0 for s,f in zip(SPL.sizes,SPL.FlagVisible)])
1295
+ if width<self.ui.tabAreaWidget.width():
1296
+ SPL.sizes[-1]= self.ui.tabAreaWidget.width()-width
1297
+ else: SPL.sizes[-1]=0
1298
+ #ITE.ncam=CAL.ncam
1299
+ #ITE.progress=len(CAL.calList)
1300
+ elif TABname=='Input_CalVi':
1301
+ VIS_CalVi.plane=int(INP_CalVi.row)*(1+PRO_CalVi.TargetType)+1
1302
+ VIS_CalVi.FlagResetLevels=INP_CalVi.isDifferentFrom(self.w_Input_CalVi.INPpar_old,fields=['path']) or len(self.w_Input_CalVi.INPpar_old.filenames)==0
1303
+ VIS_CalVi.FlagResetZoom=INP_CalVi.isDifferentFrom(self.w_Input_CalVi.INPpar_old,fields=['x','y','w','h','W','H']) or len(self.w_Input_CalVi.INPpar_old.filenames)==0
1304
+ pass
1305
+ elif TABname=='Process_CalVi':
1306
+ INP_CalVi.FlagOptPlane=PRO_CalVi.CalibProcType>0
1307
+ if len(INP_CalVi.plapar):
1308
+ if INP_CalVi.FlagOptPlane:
1309
+ for k,p in enumerate(INP_CalVi.plapar):
1310
+ if len(p)==1:
1311
+ INP_CalVi.plapar[k]=[float(0)]*5+[p[0]]
1312
+ else:
1313
+ for k,p in enumerate(INP_CalVi.plapar):
1314
+ if len(p)>1:
1315
+ INP_CalVi.plapar[k]=[p[-1]]
1316
+ pass
1317
+ elif TABname=='Vis_CalVi':
1318
+ if VIS_CalVi.plane-1!=INP_CalVi.row:
1319
+ INP_CalVi.row=int( (VIS_CalVi.plane-1)/(1+PRO_CalVi.TargetType) )
1320
+ INP_CalVi.rows=[INP_CalVi.row]
1321
+ #INP_CalVi.col=0
1322
+ #INP_CalVi.cols=[INP_CalVi.col]
1323
+ pass
1324
+ else:
1325
+ pass
1326
+ return
1327
+
1328
+ def getInheritance(self, ind):
1329
+ indpar=[j for j in ind]
1330
+ for j in range(indpar[-2]):
1331
+ indpar[-2]=j
1332
+ self.inheritance(indpar)
1333
+
1334
+ def inheritance(self,indpar):
1335
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(indpar) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1336
+ if ITE.FlagNone: return
1337
+ ind=copy.deepcopy(ITE.ind)
1338
+ Process=ITE.Process
1339
+ Step=ITE.Step
1340
+
1341
+ if Process in (ProcessTypes.piv,ProcessTypes.spiv) and Step == StepTypes.min:
1342
+ if ITE.active:
1343
+ FlagMIN=True
1344
+ INP:INPpar = self.w_Input.TABpar_at(ind)
1345
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1346
+ PRO_Min:PROpar_Min = self.w_Process_Min.TABpar_at(ind)
1347
+ FlagTR=PRO_Min.FlagTR
1348
+ LaserType=PRO_Min.LaserType
1349
+ imListMin=[]
1350
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1351
+ for c in range(INP.ncam):
1352
+ imListMin.append([outPathRoot+f'_cam{c+1}_a_min.png',outPathRoot+f'_cam{c+1}_b_min.png'])
1353
+ imageFileMin=INP.path
1354
+ FlagImage=False
1355
+ for c in range(len(INP.imList)):
1356
+ for f in range(len(INP.imList[c])):
1357
+ if INP.imList[c][f]:
1358
+ imageFileMin+=INP.imList[c][f][0]
1359
+ FlagImage=True
1360
+ break
1361
+ if FlagImage: break
1362
+ else:
1363
+ FlagMIN=False
1364
+ FlagTR=False
1365
+ LaserType=0 #0 single, 1 double
1366
+ imListMin=[]
1367
+ imageFileMin=None
1368
+ if Process==ProcessTypes.piv:
1369
+ children=[+1] #piv step
1370
+ else:
1371
+ children=[+1,+2] #disparity, spiv steps
1372
+ for c in children:
1373
+ ind_child=copy.deepcopy(ind)
1374
+ ind_child[-2]+=c
1375
+ TABpar_prev=self.w_Input.TABpar_prev_at(ind_child)
1376
+
1377
+ for d in range(len(TABpar_prev)):
1378
+ ind_child[-1]=d
1379
+ INP_child:INPpar=self.w_Input.TABpar_at(ind_child)
1380
+ INP_child.FlagMIN = FlagMIN
1381
+ INP_child.FlagTR = FlagTR
1382
+ INP_child.LaserType = LaserType
1383
+ INP_child.imListMin = deep_duplicate(imListMin)
1384
+ #INP_child.FlagInit = False
1385
+
1386
+ OUT_child:OUTpar=self.w_Output.TABpar_at(ind_child)
1387
+ OUT_child.imageFileMin = imageFileMin
1388
+
1389
+ VIS_child:VISpar=self.w_Vis.TABpar_at(ind_child)
1390
+ VIS_child.FlagMIN = ITE.procdata.flagRun>0
1391
+ VIS_child.FlagTR = FlagTR
1392
+ VIS_child.LaserType = LaserType
1393
+ VIS_child.imListMin = deep_duplicate(imListMin)
1394
+ #VIS_child.FlagInit = False
1395
+
1396
+ elif Process == ProcessTypes.spiv and Step == StepTypes.cal:
1397
+ if ITE.active:
1398
+ CAL:CALpar = self.w_Calibration.TABpar_at(ind)
1399
+ FlagCAL=ITE.procdata.flagRun>0
1400
+
1401
+ calList=CAL.calList
1402
+ calEx=CAL.calEx
1403
+ else:
1404
+ FlagCAL=False
1405
+ calList=[]
1406
+ calEx=[]
1407
+ children=[+1,+2,+3] #disparity, spiv steps
1408
+ for c in children:
1409
+ ind_child=copy.deepcopy(ind)
1410
+ ind_child[-2]+=c
1411
+
1412
+ for d in range(len(self.w_Input.TABpar_prev_at(ind_child))):
1413
+ ind_child[-1]=d
1414
+
1415
+ INP_child:INPpar=self.w_Input.TABpar_at(ind_child)
1416
+ INP_child.FlagCAL = FlagCAL
1417
+ INP_child.calList = copy.deepcopy(calList)
1418
+ INP_child.calEx = copy.deepcopy(calEx)
1419
+ #INP_child.FlagInit = False
1420
+
1421
+ VIS_child:VISpar=self.w_Vis.TABpar_at(ind_child)
1422
+ VIS_child.FlagCAL = FlagCAL
1423
+ VIS_child.calList = copy.deepcopy(calList)
1424
+ VIS_child.calEx = copy.deepcopy(calEx)
1425
+ #VIS_child.FlagInit = False
1426
+
1427
+ elif Process == ProcessTypes.spiv and Step == StepTypes.disp:
1428
+ if ITE.active:
1429
+ FlagDISP=True
1430
+ else:
1431
+ FlagDISP=False
1432
+ children=[+1] #disparity, spiv steps
1433
+ for c in children:
1434
+ ind_child=copy.deepcopy(ind)
1435
+ ind_child[-2]+=c
1436
+ TABpar_prev=self.w_Input.TABpar_prev_at(ind_child)
1437
+
1438
+ for d in range(len(TABpar_prev)):
1439
+ ind_child[-1]=d
1440
+ OUT_child:OUTpar=self.w_Output.TABpar_at(ind_child)
1441
+ OUT_child.FlagDISP = FlagDISP
1442
+ """
1443
+ elif Process == ProcessTypes.spiv and Step == StepTypes.disp:
1444
+ if ITE.active:
1445
+ FlagDISP=True
1446
+ INP:INPpar = self.w_Input.TABpar_at(ind)
1447
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1448
+ zconst=OUT.zconst
1449
+ xterm=OUT.xterm
1450
+ yterm=OUT.yterm
1451
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1452
+ dispFile=outPathRoot+'.clz'
1453
+ else:
1454
+ FlagDISP=False
1455
+ zconst=0.0
1456
+ xterm=0.0
1457
+ yterm=0.0
1458
+ dispFile=''
1459
+ children=[+1] #disparity, spiv steps
1460
+ FlagInit=True
1461
+ for c in children:
1462
+ ind_child=copy.deepcopy(ind)
1463
+ ind_child[-2]+=c
1464
+ TABpar_prev=self.w_Input.TABpar_prev_at(ind_child)
1465
+
1466
+ for d in range(len(TABpar_prev)):
1467
+ ind_child[-1]=d
1468
+
1469
+ INP_child:INPpar=self.w_Input.TABpar_at(ind_child)
1470
+ INP_child.FlagDISP = FlagDISP
1471
+ INP_child.dispFile = dispFile
1472
+ #INP_child.FlagInit = False
1473
+
1474
+ OUT_child:OUTpar=self.w_Output.TABpar_at(ind_child)
1475
+ OUT_child.FlagDISP = FlagDISP
1476
+ OUT_child.zconst= zconst
1477
+ OUT_child.xterm = xterm
1478
+ OUT_child.yterm = yterm
1479
+
1480
+ VIS_child:VISpar=self.w_Vis.TABpar_at(ind_child)
1481
+ VIS_child.FlagDISP = FlagDISP
1482
+ VIS_child.dispFile = dispFile
1483
+ #VIS_child.FlagInit = False
1484
+
1485
+ pass
1486
+ """
1487
+
1488
+ ITEs=self.ui.Explorer.ITEsfromInd(indpar)
1489
+ #currInd=list(ITEs[0].children).index(ITE.Step)+1
1490
+ for c in range(len(ITEs)): #range(currInd+1,len(ITEs))
1491
+ ITE_ind:ITEpar=ITEs[c]
1492
+ self.checkProcesses(FlagInit=True,ind=ITE_ind.ind)
1493
+ #self.checkProcesses(FlagInit=False,ind=ITE_ind.ind)
1494
+ self.ui.Explorer.setITElayout(ITE_ind)
1495
+ return
1496
+
1497
+ def IOVinheritance(self,indpar):
1498
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(indpar) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1499
+ if ITE.FlagNone: return
1500
+ ind=copy.deepcopy(ITE.ind)
1501
+ Step=ITE.Step
1502
+ #inverse inheritance
1503
+ if Step not in (StepTypes.cal,) and ITE.active:
1504
+ INP:INPpar = self.w_Input.TABpar_at(ind)
1505
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1506
+ VIS:VISpar = self.w_Vis.TABpar_at(ind)
1507
+
1508
+ #children=[-2, -1] if Step==StepTypes.spiv else [-1] #disparity, spiv steps #*
1509
+ for c in range(len(processData[ITE.Process]['children'])): #in children: #*
1510
+ ind_child=copy.deepcopy(ind)
1511
+ #ind_child[-2]+=c #*
1512
+ ind_child[-2]=c
1513
+ TABpar_prev=self.w_Input.TABpar_prev_at(ind_child)
1514
+ if TABpar_prev[0] is None: continue
1515
+
1516
+ FlagInit=len(TABpar_prev)==1 and TABpar_prev[0].flagRun==0
1517
+ if FlagInit:
1518
+ ind_child[-1]=0
1519
+ INP_child:INPpar=self.w_Input.TABpar_at(ind_child)
1520
+ INP_child.copyfrom(INP,exceptions=['Process','Step']+INP_child.parFields)
1521
+
1522
+ OUT_child:OUTpar=self.w_Output.TABpar_at(ind_child)
1523
+ OUT_child.copyfrom(OUT,exceptions=['Process','Step']+OUT_child.parFields)
1524
+
1525
+ VIS_child:VISpar=self.w_Vis.TABpar_at(ind_child)
1526
+ VIS_child.copyfrom(VIS,exceptions=['Process','Step']+VIS_child.parFields)
1527
+
1528
+ self.checkProcesses(FlagInit=True,ind=ind_child)
1529
+ self.checkProcesses(FlagInit=False,ind=ind_child)
1530
+ ITE_ind:ITEpar = self.ui.Explorer.ITEfromInd(ind_child)
1531
+ self.ui.Explorer.setITElayout(ITE_ind)
1532
+ self.inheritance(ind_child)
1533
+
1534
+ def IOVcopy(self,ind_slave,ind_master):
1535
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind_master) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1536
+ if ITE.FlagNone: return
1537
+
1538
+ #Input/Output/Vis inheritance
1539
+ INP:INPpar = self.w_Input.TABpar_at(ind_master)
1540
+ OUT:OUTpar = self.w_Output.TABpar_at(ind_master)
1541
+ VIS:VISpar = self.w_Vis.TABpar_at(ind_master)
1542
+
1543
+ self.w_Input.INPpar.copyfrom(INP,exceptions=['Process','Step']+INP.parFields)
1544
+ self.w_Output.OUTpar.copyfrom(OUT,exceptions=['Process','Step']+OUT.parFields)
1545
+ self.w_Vis.VISpar.copyfrom(VIS,exceptions=['Process','Step']+VIS.parFields)
1546
+
1547
+ FlagNewPar=self.w_Input.isNewPar() or self.w_Output.isNewPar()
1548
+ ind_slave=self.w_Input.add_TABpar('Copy input/output data from step',FlagNewPar)
1549
+ self.setTABpars_at(ind_slave,FlagAdjustPar=True,FlagBridge=True,widget=self.w_Input)
1550
+
1551
+ ITE_slave:ITEpar = self.ui.Explorer.ITEfromInd(ind_slave) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1552
+ self.ui.Explorer.setITElayout(ITE_slave)
1553
+ return
1554
+
1555
+ #*************************************************** Update workspace and projects
1556
+ def updateWorkspace(self):
1557
+ self.GPApar.modifiedDate=currentTimeString()
1558
+ self.GPApar.date=f'Modified: {self.GPApar.modifiedDate}'
1559
+ self.GPApar.FlagSaved=False
1560
+
1561
+ self.adjustWorkspaceHeader()
1562
+
1563
+ def adjustWorkspaceHeader(self):
1564
+ if self.GPApar.outName and self.GPApar.outName!=lastcfgname:
1565
+ title=self.GPApar.name+self.GPApar.saveBullet()
1566
+ subtitle=self.GPApar.date
1567
+ icon=self.GPApar.icon
1568
+ FlagVisible=True
1569
+ else:
1570
+ title=''
1571
+ subtitle=''
1572
+ icon=None
1573
+ FlagVisible=False
1574
+ self.ui.title_workspace.setVisible(FlagVisible)
1575
+ self.ui.subtitle_workspace.setVisible(FlagVisible)
1576
+ self.ui.title_workspace.setText(title)
1577
+ self.ui.subtitle_workspace.setText(subtitle)
1578
+
1579
+ InfoMessage=self.GPApar.InfoMessage()
1580
+ self.ui.title_workspace.setToolTip(InfoMessage)
1581
+ self.ui.title_workspace.setStatusTip(InfoMessage)
1582
+ self.ui.subtitle_workspace.setToolTip(InfoMessage)
1583
+ self.ui.subtitle_workspace.setStatusTip(InfoMessage)
1584
+
1585
+ self.ui.workspace_icon.setVisible(icon is not None)
1586
+ self.adjustMenuFile()
1587
+
1588
+ self.setGPaIRSTitle()
1589
+
1590
+ def adjustMenuFile(self):
1591
+ self.ui.actionSave.setEnabled(not self.GPApar.FlagSaved)
1592
+ self.ui.actionClose.setEnabled(self.GPApar.outName not in ('',lastcfgname))
1593
+
1594
+ def updateProjectItemWidget(self):
1595
+ TRE:TREpar=self.projectTree.itemList[0][self.TREpar.project]
1596
+ TRE.modifiedDate=currentTimeString()
1597
+ TRE.date=f'Modified: {TRE.modifiedDate}'
1598
+ TRE.FlagSaved=False
1599
+ self.TREpar.copyfrom(TRE)
1600
+
1601
+ self.GPApar.modifiedDate=TRE.modifiedDate
1602
+ self.GPApar.date=TRE.date
1603
+ self.GPApar.FlagSaved=False
1604
+
1605
+ self.adjustItemWidgets()
1606
+
1607
+ def adjustItemWidgets(self,ind=None):
1608
+ if ind is None: ind=[self.TREpar.project, self.TREpar.tree, self.TREpar.process, self.TREpar.step, -1]
1609
+ TRE:TREpar=self.projectTree.itemList[0][ind[0]]
1610
+ topLevelItem=self.projectTree.topLevelItem(ind[0])
1611
+ itemWidget=self.projectTree.itemWidget(topLevelItem,1)
1612
+ if itemWidget:
1613
+ title:QLabel=itemWidget.findChildren(QLabel,'title_project')[0]
1614
+ title.setText(TRE.name+TRE.saveBullet())
1615
+ subtitle:QLabel=itemWidget.findChildren(QLabel,'subtitle_project')[0]
1616
+ subtitle.setText(TRE.date)
1617
+ InfoMessage=TRE.InfoMessage()
1618
+ title.setToolTip(InfoMessage)
1619
+ title.setStatusTip(InfoMessage)
1620
+ subtitle.setToolTip(InfoMessage)
1621
+ subtitle.setStatusTip(InfoMessage)
1622
+ if self.TREpar.project==ind[0] and self.TREpar.tree==ind[1] and self.TREpar.process is not None:
1623
+ self.adjustTitleHeader()
1624
+ self.projectTree.actionBar.button_save.setEnabled(not self.TREpar.FlagSaved)
1625
+ topLevelItem=self.processTree.topLevelItem(ind[2])
1626
+ itemWidget=self.processTree.itemWidget(topLevelItem,1)
1627
+ if itemWidget:
1628
+ title:QLabel=itemWidget.findChildren(QLabel,'title_process')[0]
1629
+ subtitle:QLabel=itemWidget.findChildren(QLabel,'subtitle_process')[0]
1630
+ subtitle.setText(TRE.date)
1631
+ ITE:ITEpar=self.ui.Explorer.ITEfromTRE(TRE)
1632
+ InfoMessage=ITE.InfoMessage()
1633
+ title.setToolTip(InfoMessage)
1634
+ title.setStatusTip(InfoMessage)
1635
+ subtitle.setToolTip(InfoMessage)
1636
+ subtitle.setStatusTip(InfoMessage)
1637
+ self.adjustTitleHeader()
1638
+ self.adjustWorkspaceHeader()
1639
+
1640
+ def adjustTitleHeader(self):
1641
+ if self.TREpar.project is None:
1642
+ title='Welcome to PaIRS'
1643
+ subtitle='Particle Image Reconstruction Software'
1644
+ icon=None
1645
+ self.currITEpar=None
1646
+ else:
1647
+ title=self.TREpar.name+self.TREpar.saveBullet()
1648
+ if self.TREpar.process is None or self.TREpar.step is None:
1649
+ subtitle=self.TREpar.date
1650
+ icon=self.TREpar.icon
1651
+ self.currITEpar=self.TREpar
1652
+ else:
1653
+ ITEs:ITEpar=self.ui.Explorer.ITEsfromTRE(self.TREpar)
1654
+ title+=': '+ITEs[0].name
1655
+ subtitle=self.TREpar.date
1656
+ icon=ITEs[self.TREpar.step].icon
1657
+ self.currITEpar=ITEs[self.TREpar.step]
1658
+ self.ui.title.setText(title)
1659
+ self.ui.subtitle.setText(subtitle)
1660
+
1661
+ if self.currITEpar:
1662
+ InfoMessage=self.currITEpar.InfoMessage()
1663
+ else:
1664
+ InfoMessage=''
1665
+ self.ui.title.setToolTip(InfoMessage)
1666
+ self.ui.title.setStatusTip(InfoMessage)
1667
+ self.ui.subtitle.setToolTip(InfoMessage)
1668
+ self.ui.subtitle.setStatusTip(InfoMessage)
1669
+
1670
+ self.ui.title_icon.setVisible(icon is not None)
1671
+ self.ui.title_icon.setIcon(TreeIcons.icons[icon])
1672
+
1673
+ def adjustProcessSelection(self):
1674
+ FlagVisible=[False,False,False,False]
1675
+ if self.TREpar.project is None:
1676
+ FlagVisible[0]=True
1677
+ self.ui.Explorer.hideStepButtons()
1678
+ else:
1679
+ if self.TREpar.process is None:
1680
+ FlagVisible[1]=True
1681
+ self.ui.Explorer.hideStepButtons()
1682
+ else:
1683
+ if self.TREpar.step is None or self.TREpar.step==0:
1684
+ FlagVisible[2]=True
1685
+ else:
1686
+ FlagVisible[3]=True
1687
+ self.ui.projectPage.setVisible(FlagVisible[0])
1688
+ self.ui.processPage.setVisible(FlagVisible[1])
1689
+ self.ui.stepPage.setVisible(FlagVisible[2])
1690
+ self.ui.tabAreaWidget.setVisible(FlagVisible[3])
1691
+ self.w_RCL.setVisible(FlagVisible[3])
1692
+ #if FlagVisible[3]:
1693
+ # self.ui.tabAreaWidget.scrollArea.splitter.splitterResize()
1694
+
1695
+ self.adjustWorkspaceHeader()
1696
+ self.adjustTitleHeader()
1697
+ self.adjustSwitches()
1698
+
1699
+ self.ui.Explorer.cancelUndo()
1700
+
1701
+ def adjustProjectSelection(self):
1702
+ self.adjustProcessSelection()
1703
+ self.ui.Explorer.adjustProjectSelection()
1704
+
1705
+ def adjustSwitches(self):
1706
+ for k in range(len(self.projectTree.itemList[0])):
1707
+ topLevelItem=self.projectTree.topLevelItem(k)
1708
+ itemWidget=self.projectTree.itemWidget(topLevelItem,1)
1709
+ if itemWidget:
1710
+ switch:ModernSwitch=itemWidget.findChildren(ModernSwitch)[0]
1711
+ if switch:
1712
+ FlagVisible=any([i[0].flagRun<=0 and i[0].Process!=ProcessTypes.cal for i in self.projectTree.itemList[1][k][0]])
1713
+ self.projectTree.itemList[0][k].FlagRunnable=FlagVisible
1714
+ if not self.FlagRun:
1715
+ FlagQueue=len(self.projectTree.itemList[1][k][0])==0 or not FlagVisible or any([i[0].flagRun<=0 and i[0].Process!=ProcessTypes.cal and i[0].FlagQueue for i in self.projectTree.itemList[1][k][0]])
1716
+ else:
1717
+ FlagQueue=switch._checked
1718
+
1719
+ switch.setVisible(FlagVisible)
1720
+ switch.setSwitch(FlagQueue)
1721
+ self.projectTree.itemList[0][k].FlagQueue=FlagQueue
1722
+ if self.TREpar.project==k:
1723
+ self.TREpar.FlagQueue=FlagQueue
1724
+ #switch.setEnabled(self.FlagRun==0)
1725
+ if len(self.processTree.itemList):
1726
+ for k,i in enumerate(self.processTree.itemList[0]):
1727
+ topLevelItem=self.processTree.topLevelItem(k)
1728
+ itemWidget=self.processTree.itemWidget(topLevelItem,1)
1729
+ if itemWidget:
1730
+ switch:ModernSwitch=itemWidget.findChildren(ModernSwitch)[0]
1731
+ if switch:
1732
+ ITE:ITEpar=i[0]
1733
+ switch.setVisible(ITE.flagRun<=0 and ITE.Process!=ProcessTypes.cal and any([j.active and len(j.link)==0 for j in i[1:]]))
1734
+ #self.swithcEnabled(self.FlagRun==0)
1735
+ self.setButtonRunVisible()
1736
+
1737
+ #*************************************************** Link and copy
1738
+ def adjustDependencies(self,ITE:ITEpar):
1739
+ for ind_slave in ITE.dependencies:
1740
+ self.copy_pars(ind_slave,ITE.ind)
1741
+ #self.inheritance(ind_slave) #useless, already performed in copy_pars
1742
+ self.setLinks(ind_slave,ITE.ind)
1743
+
1744
+ def button_reset_step_action(self):
1745
+ if self.questionDialog('Are you sure you want to reset the current process step? This operation will affect all the subsequent steps in the process and it is irreversible!'):
1746
+ self.reset_step(self.ui.Explorer.ITEpar.ind)
1747
+ return
1748
+
1749
+ def reset_step(self,ind):
1750
+ FlagSettingPar=TABpar.FlagSettingPar
1751
+ TABpar.FlagSettingPar=True
1752
+ ITEs_ind:ITEpar=self.ui.Explorer.ITEsfromInd(ind)
1753
+ ind_child=copy.deepcopy(ind)
1754
+ for j in range(ind[-2],0,-1):
1755
+ ind_child[-2]=j-1
1756
+ ITE_ind:ITEpar=ITEs_ind[j]
1757
+ if not ITE_ind.active and ITE_ind.flagRun<0:
1758
+ ITE_ind.procdata=data=dataTreePar(ITE_ind.Process,ITE_ind.Step)
1759
+ ITE_ind.procdata.ind=ITE_ind.ind
1760
+ ITE_ind.progress=0
1761
+ self.setFlagRun(data,0,flagPrev=True)
1762
+ else:
1763
+ break
1764
+ for j in range(len(ITEs_ind)-1,ind[-2],-1):
1765
+ ind_child[-2]=j-1
1766
+ ITE_ind:ITEpar=ITEs_ind[j]
1767
+ ITE_ind.procdata=data=dataTreePar(ITE_ind.Process,ITE_ind.Step)
1768
+ ITE_ind.procdata.ind=ITE_ind.ind
1769
+ ITE_ind.progress=0
1770
+ self.setFlagRun(data,0,flagPrev=True)
1771
+ self.adjustDependencies(ITE_ind)
1772
+ self.inheritance(ind_child)
1773
+ ind_child[-1]=-1
1774
+ LOG_ind:LOGpar=self.w_Log.TABpar_at(ind_child)
1775
+ if LOG_ind:
1776
+ LOG_ind.progress=0
1777
+ if self.w_Log.LOGpar.ind[:-1]==LOG_ind.ind[:-1]:
1778
+ self.w_Log.setLOGlayout()
1779
+ self.ui.progress_Proc.setValue(0)
1780
+ self.setTABpars_at(ITE_ind.ind,FlagAdjustPar=True,widget=self.w_Calibration if ITE_ind.Step==StepTypes.cal else self.w_Vis)
1781
+ if data.ind[:-2]==self.ui.tabAreaWidget.TABpar.ind[:-2]:
1782
+ self.ui.Explorer.arrangeCurrentProcess(self.processTree)
1783
+
1784
+ self.adjustSwitches()
1785
+
1786
+ TABpar.FlagSettingPar=FlagSettingPar
1787
+
1788
+ def IOVheritableSteps(self):
1789
+ ITE=self.ui.Explorer.ITEpar
1790
+ stepList={}
1791
+ if len(self.processTree.itemList) and ITE.ind[2]<len(self.processTree.itemList[0]):
1792
+ for step in self.processTree.itemList[0][ITE.ind[2]]:
1793
+ step:ITEpar
1794
+ if step.active and ITE.ind[:-1]!=step.ind[:-1]:
1795
+ INP:INPpar = self.w_Input.TABpar_at(step.ind)
1796
+ OUT:OUTpar = self.w_Output.TABpar_at(step.ind)
1797
+ VIS:VISpar = self.w_Vis.TABpar_at(step.ind)
1798
+ if INP is not None and OUT is not None and VIS is not None:
1799
+ stepList[step.name]={'ind': step.ind, 'icon': step.icon}
1800
+ return stepList
1801
+
1802
+ def linkableSteps(self,FlagExcludeLinked=False):
1803
+ ITE=self.ui.Explorer.ITEpar
1804
+ stepList={}
1805
+ if len(self.processTree.itemList):
1806
+ for process in self.processTree.itemList[0]:
1807
+ ITE0:ITEpar=process[0]
1808
+ for step in process[1:]:
1809
+ step:ITEpar
1810
+ FlagNoOverLink=True if not FlagExcludeLinked else len(step.link)==0
1811
+ if step.active and step.Step==ITE.Step and ITE.ind[:-2]!=ITE0.ind[:-2] and FlagNoOverLink:
1812
+ stepList[f'{step.ind[-3]+1}: '+ITE0.name]={'ind': step.ind, 'icon': ITE0.icon}
1813
+ return stepList
1814
+
1815
+ def copy_link_action(self,button:QPushButton, fun=lambda ind_slave, ind_master:None, FlagExcludeLinked=False, menuTitle='Copy step from...',icon=None,message='No process step available!', stepListType=0):
1816
+ if stepListType==1:
1817
+ stepList=self.IOVheritableSteps()
1818
+ else:
1819
+ stepList=self.linkableSteps(FlagExcludeLinked=FlagExcludeLinked)
1820
+ ITE=self.ui.Explorer.ITEpar
1821
+ if len(stepList)==0:
1822
+ show_mouse_tooltip(self,message)
1823
+ return None
1824
+
1825
+ style=button.styleSheet()
1826
+ button.setStyleSheet("")
1827
+ menu = QMenu(self)
1828
+ title_action = QAction(menuTitle, self)
1829
+ if icon: title_action.setIcon(icon)
1830
+ title_action.setDisabled(True) # Disabilita l'azione per evitare l'interazione
1831
+ menu.addAction(title_action)
1832
+ menu.addSeparator()
1833
+ for key, item in stepList.items():
1834
+ #for colormap in VIS_ColorMaps[colorMapClass]:
1835
+ nameItem=' '+key
1836
+ action:QAction = menu.addAction(TreeIcons.icons[item['icon']], nameItem)
1837
+ action.triggered.connect(lambda _, name=key: fun(ITE.ind,stepList[name]['ind']))
1838
+ menu.exec(QCursor.pos()) #menu.exec(button.mapToGlobal(button.rect().bottomLeft()))
1839
+ button.setStyleSheet(style)
1840
+ return
1841
+
1842
+ def button_step_inherit_action(self):
1843
+ self.copy_link_action(self.ui.button_step_inherit,lambda isl,ima: self.IOVcopy(isl,ima),menuTitle='Copy input/output data from...', message='No process step available!', stepListType=1)
1844
+
1845
+ def button_copy_step_action(self):
1846
+ self.copy_link_action(self.ui.button_copy_step,lambda isl,ima: self.copy_pars_proc(isl,ima,FlagNew=True))
1847
+
1848
+ def checkCamCompatibility(self,ind_slave,ind_master):
1849
+ ITE_slave:ITEpar=self.ui.Explorer.ITEfromInd(ind_slave)
1850
+ isCompatible=True
1851
+ if ITE_slave.Step==StepTypes.min:
1852
+ INP_slave:INPpar=self.w_Input.TABpar_at(ind_slave)
1853
+ ncam_slave=INP_slave.ncam
1854
+ INP_master:INPpar=self.w_Input.TABpar_at(ind_master)
1855
+ ncam_master=INP_master.ncam
1856
+ isCompatible=ncam_slave==ncam_master
1857
+ elif ITE_slave.Step==StepTypes.cal:
1858
+ CAL_slave:CALpar=self.w_Calibration.TABpar_at(ind_slave)
1859
+ ncam_slave=CAL_slave.ncam
1860
+ CAL_master:CALpar=self.w_Calibration.TABpar_at(ind_master)
1861
+ ncam_master=CAL_master.ncam
1862
+ isCompatible=ncam_slave==ncam_master
1863
+ if not isCompatible:
1864
+ warningMessage=f'The number of cameras in the current step (={ncam_slave}) is different from that in the selected step (={ncam_master}). Please, select a different step or modify the number of cameras in the selected step before proceeding!'
1865
+ self.warningDialog(warningMessage)
1866
+ return isCompatible
1867
+
1868
+ def copy_pars(self,ind_slave,ind_master,FlagNew=False):
1869
+ ind_new=[i for i in ind_slave]
1870
+ if FlagNew: ind_new[-1]+=1
1871
+ for w in self.tabWidgets:
1872
+ w:gPaIRS_Tab
1873
+ TAB_slave_curr:TABpar=w.TABpar_at(ind_slave)
1874
+ if TAB_slave_curr:
1875
+ if FlagNew: w.gen_TABpar(ind_new,Process=TAB_slave_curr.Process,Step=TAB_slave_curr.Step)
1876
+ TAB_slave:TABpar=w.TABpar_at(ind_new)
1877
+ TAB_slave.copyfrom(w.TABpar_at(ind_master),exceptions=['ind','link','Process'])
1878
+ ITE_master:ITEpar=self.ui.Explorer.ITEfromInd(ind_master)
1879
+ ITE_slave:ITEpar=self.ui.Explorer.ITEfromInd(ind_new)
1880
+ ITE_slave.ind=[i for i in ind_new]
1881
+ ITE_slave.copyfrom(ITE_master,exceptions=['procdata','ind','link','Process','dependencies'])
1882
+ ITE_slave.procdata.copyfrom(ITE_master.procdata,exceptions=['ind','link','Process'])
1883
+ self.getInheritance(ind_slave)
1884
+ self.ui.Explorer.undoInd=None
1885
+ self.inheritance(ind_slave)
1886
+ self.ui.Explorer.setITElayout(ITE_slave)
1887
+ self.adjustSwitches() #useless?
1888
+ return ind_new
1889
+
1890
+ def copy_pars_proc(self,ind_slave,ind_master,FlagNew=False,FlagSet=True):
1891
+ if not self.checkCamCompatibility(ind_slave,ind_master): return
1892
+ ITEs_slave=self.ui.Explorer.ITEsfromInd(ind_slave)
1893
+ ITEs_master=self.ui.Explorer.ITEsfromInd(ind_master)
1894
+ for c in range(ind_slave[-2]+1):
1895
+ ind_slave=ITEs_slave[c+1].ind
1896
+ ind_master=ITEs_master[c+1].ind
1897
+ ind_new=self.copy_pars(ind_slave,ind_master,FlagNew=True)
1898
+
1899
+ if FlagSet:
1900
+ self.ui.Explorer.arrangeCurrentProcess(self.ui.Explorer.processTree)
1901
+ self.ui.Explorer.selectStep()
1902
+ self.adjustSwitches()
1903
+ return ind_new
1904
+
1905
+ def copy_VIS(self,ind_slave,ind_master):
1906
+ ind_new=[i for i in ind_slave]
1907
+ w=self.w_Vis
1908
+ w:gPaIRS_Tab
1909
+ TAB_slave_curr:VISpar=w.TABpar_at(ind_slave)
1910
+ if TAB_slave_curr:
1911
+ TAB_slave:VISpar=w.TABpar_at(ind_new)
1912
+ TAB_slave.copyfromfields(w.TABpar_at(ind_master),fields=TAB_slave.graphics_fields)
1913
+ self.w_Vis.setTABpar_at(ind_new,FlagAdjustPar=True,FlagBridge=True)
1914
+ return ind_new
1915
+
1916
+ def button_link_step_action(self):
1917
+ if self.ui.button_link_step.isChecked():
1918
+ result=self.copy_link_action(self.ui.button_link_step,self.link_pars,FlagExcludeLinked=True,menuTitle='Link step to...')
1919
+ FlagUnlink=result is None
1920
+ else:
1921
+ FlagUnlink=True
1922
+ if FlagUnlink:
1923
+ ITE=self.ui.Explorer.ITEpar
1924
+ self.unlink_pars(ITE.ind)
1925
+ self.ui.button_link_step.setChecked(False)
1926
+
1927
+ def link_pars(self,ind_slave,ind_master,FlagSet=True):
1928
+ if not self.checkCamCompatibility(ind_slave,ind_master): return
1929
+ ITEs_slave=self.ui.Explorer.ITEsfromInd(ind_slave)
1930
+ ITEs_master=self.ui.Explorer.ITEsfromInd(ind_master)
1931
+ for c in range(ind_slave[-2]+1):
1932
+ ind_slave=ITEs_slave[c+1].ind
1933
+ ind_master=ITEs_master[c+1].ind
1934
+ ind_new=self.copy_pars(ind_slave,ind_master,FlagNew=True)
1935
+ self.setLinks(ind_new,ind_master)
1936
+ #item=self.processTree.topLevelItem(ind_new[2])
1937
+ #child=item.child(ind_new[3])
1938
+ #child.setIcon(0,self.processTree.linkedIcon)
1939
+
1940
+ #self.setTABpars_at(ind_new)
1941
+ if FlagSet:
1942
+ self.ui.Explorer.arrangeCurrentProcess(self.ui.Explorer.processTree)
1943
+ self.ui.Explorer.selectStep()
1944
+ self.adjustSwitches()
1945
+ return ind_new
1946
+
1947
+ def setLinks(self,ind_slave,ind_master,FlagUnlink=False,ind_slave_new=None,ind_master_new=None):
1948
+ if ind_slave_new is None: ind_slave_new=copy.deepcopy(ind_slave)
1949
+ if ind_master_new is None: ind_master_new=copy.deepcopy(ind_master)
1950
+ ITE_master:ITEpar=self.ui.Explorer.ITEfromInd(ind_master_new)
1951
+ if FlagUnlink and ind_slave in ITE_master.dependencies:
1952
+ ITE_master.dependencies.remove(ind_slave)
1953
+ elif not FlagUnlink and ind_slave not in ITE_master.dependencies:
1954
+ ITE_master.dependencies.append(copy.deepcopy(ind_slave))
1955
+ for w in self.tabWidgets:
1956
+ w:gPaIRS_Tab
1957
+ TABpar_ind:TABpar=w.TABpar_at(ind_slave_new)
1958
+ if TABpar_ind:
1959
+ if FlagUnlink:
1960
+ TABpar_ind.link=[]
1961
+ TABpar_ind.linkInfo=''
1962
+ else:
1963
+ TABpar_ind.link=copy.deepcopy(ind_master)
1964
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(ind_slave_new)
1965
+ if FlagUnlink:
1966
+ ITE_ind.link=[]
1967
+ ITE_ind.procdata.link=[]
1968
+ else:
1969
+ ITE_ind.link=copy.deepcopy(ind_master)
1970
+ ITE_ind.procdata.link=copy.deepcopy(ind_master)
1971
+
1972
+ def unlink_pars(self,ind_slave):
1973
+ ITE_slave:ITEpar=self.ui.Explorer.ITEfromInd(ind_slave)
1974
+ ind_master=ITE_slave.link
1975
+ if ind_master:
1976
+ self.setLinks(ind_slave,ind_master,FlagUnlink=True)
1977
+ #item=self.processTree.topLevelItem(ind_slave[2])
1978
+ #child=item.child(ind_slave[3])
1979
+ #child.setIcon(0,QIcon())
1980
+ self.setTABpars_at(ind_slave)
1981
+ self.adjustSwitches()
1982
+
1983
+ #*************************************************** PROCESS
1984
+ #********************************** Launching
1985
+ def button_run_pause_action(self):
1986
+ # FlagRun = 0 no procWorkers (all workers have been closed or never launched)
1987
+ # FlagRun = 1 procWorkers working
1988
+ # FlagRun = 2 pause pressed, waiting for procWorkers to be completed
1989
+ pri.Process.magenta(f'button_RunPause_callback self.FlagRun={self.FlagRun} ')
1990
+ self.ui.button_pause.setEnabled(False) #ta disabilitato sempre lo riabilita il worker prima di iniziare
1991
+
1992
+ if self.FlagRun==0:
1993
+ self.FlagRun=1
1994
+ self.setButtonPause(False)
1995
+ self.run()
1996
+ elif self.FlagRun==1:
1997
+ self.FlagRun=2
1998
+ self.signals.killOrResetParForWorker.emit(True)
1999
+ self.setButtonPause(True)
2000
+
2001
+ def setButtonPause(self,flagPlay):
2002
+ if flagPlay:
2003
+ self.ui.label_updating_pairs.setVisible(False)
2004
+ self.ui.button_pause.setIcon(self.icon_play)
2005
+ stringa='Restart'
2006
+ else:
2007
+ self.ui.label_updating_pairs.setVisible(True)
2008
+ self.ui.button_pause.setIcon(self.icon_pause)
2009
+ stringa='Pause'
2010
+ tip=f'{stringa} process queue'+' ('+self.ui.button_pause.shortcut().toString(QKeySequence.NativeText)+')'
2011
+ self.ui.button_pause.setToolTip(tip)
2012
+ self.ui.button_pause.setStatusTip(tip)
2013
+ self.setButtonRunVisible()
2014
+ self.processTree.setProcessActionButtonLayout()
2015
+ """
2016
+ FlagButtonRun=self.ui.progress_Proc.value()==0
2017
+ self.ui.button_Run.setVisible(FlagButtonRun)
2018
+ self.ui.button_pause.setVisible(not FlagButtonRun)
2019
+ self.ui.w_progress_Proc.setVisible(not FlagButtonRun)
2020
+ """
2021
+
2022
+ def run(self):
2023
+ self.setSwitchEnabled(False)
2024
+ self.disableDropping(True)
2025
+ if self.initializeWorkers():
2026
+ self.indProc=-1
2027
+ self.updateIndProc()
2028
+ else:
2029
+ self.FlagRun=0
2030
+ self.setButtonPause(True)
2031
+ #self.button_run_pause_action()
2032
+ self.stopProcs()
2033
+
2034
+ def updateIndProc(self):
2035
+ self.indWorker+=1
2036
+ data=self.dataQueue[self.indWorker]
2037
+ self.initialize_proc(data)
2038
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2039
+ self.ui.Explorer.setITElayout(ITE_ind)
2040
+
2041
+ self.indProc+=1
2042
+ data:dataTreePar
2043
+ self.ui.Explorer.updateSwitchMovies(self.currind,FlagStart=False)
2044
+ self.procdata=None
2045
+ self.procdata=data=self.dataQueue[self.indProc]
2046
+ self.currind=data.ind
2047
+ self.checkProcesses(FlagInit=True,ind=self.currind)
2048
+ ITE:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2049
+ self.ui.Explorer.setITElayout(ITE)
2050
+ if ITE.OptionDone==0:
2051
+ self.stopProcs()
2052
+ self.nextProc()
2053
+ return
2054
+
2055
+ self.procdata.uncopied_fields+=self.procFields
2056
+ self.ui.Explorer.updateSwitchMovies(self.currind,FlagStart=True)
2057
+
2058
+ self.resetProc(data)
2059
+ self.setProgressBar(data)
2060
+ data.resetLog()
2061
+ try:
2062
+ with open(data.stepOutName()+'.log', 'w') as file:
2063
+ file.write(data.Log)
2064
+ except:
2065
+ pri.Error.red(f'Error while trying to save the process log file: {data.stepOutName()}.log.\n{traceback.format_exc()}\n')
2066
+
2067
+ self.FlagResetPlot=True
2068
+ self.setFlagRun(data,-2)
2069
+ self.ui.Explorer.setITElayout(ITE)
2070
+ ITEs_ind:ITEpar=self.ui.Explorer.ITEsfromInd(self.currind)
2071
+ ind_child=copy.deepcopy(self.currind)
2072
+ for j in range(1,self.currind[-2]+1):
2073
+ ind_child[-2]=j-1
2074
+ ITE_child:ITEpar=ITEs_ind[j]
2075
+ data_child=ITE_child.procdata
2076
+ if data_child.flagRun==0:
2077
+ self.setFlagRun(data_child,-1)
2078
+ self.checkProcesses(FlagInit=True,ind=ind_child)
2079
+ self.ui.Explorer.setITElayout(ITE_child)
2080
+ if data_child.ind==self.ui.tabAreaWidget.TABpar.ind:
2081
+ self.w_Log.LOGpar.text=data_child.Log
2082
+ self.setTABpars_at(data_child.ind,FlagAdjustPar=True)
2083
+
2084
+ FlagCurrent=data.ind==self.ui.tabAreaWidget.TABpar.ind
2085
+ if FlagCurrent:
2086
+ self.w_Log.LOGpar.text=data.Log
2087
+ self.setTABpars_at(data.ind,FlagAdjustPar=True)
2088
+ self.w_Log.buttonAction()
2089
+ self.FlagProcInit=True
2090
+ self.signals.indProc.emit(self.indProc)
2091
+ if data.flagRun==0:#not launched
2092
+ data.resetTimeStat()
2093
+ data.onStartTimeStat()
2094
+
2095
+ def setFlagRun(self,data:dataTreePar,flagRun,flagPrev=False):
2096
+ data.flagRun=flagRun #come ultimo o comunque dopo resetProc
2097
+ for w in self.tabWidgets:
2098
+ w:gPaIRS_Tab
2099
+ if flagPrev:
2100
+ TABpar_prev=w.TABpar_prev_at(data.ind)
2101
+ for TABpar_ind in TABpar_prev:
2102
+ if TABpar_ind: TABpar_ind.flagRun=flagRun
2103
+ else:
2104
+ TABpar_ind:TABpar=w.TABpar_at(data.ind)
2105
+ if TABpar_ind: TABpar_ind.flagRun=flagRun
2106
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2107
+ ITE_ind.flagRun=flagRun
2108
+
2109
+ self.ui.Explorer.setProcessFlagRun(data.ind)
2110
+ return
2111
+
2112
+ def nextProc(self):
2113
+ self.UpdatingImage=True
2114
+
2115
+ if self.indProc<self.nProc-1 and self.FlagRun==1:
2116
+ try:
2117
+ self.updateIndProc()
2118
+ except:
2119
+ errMessage=f"{traceback.format_exc()}"
2120
+ self.procdata.warnings[0]+='\n\n'+self.procdata.headerSection('CRITICAL ERROR',errMessage,'X')
2121
+ self.store_proc(self.procdata)
2122
+ self.stopProcs()
2123
+ self.nextProc()
2124
+ else:
2125
+ self.ui.button_pause.setEnabled(False)
2126
+
2127
+ def resetProc(self,data:dataTreePar):
2128
+ data.warnings[0]=data.warnings[1]
2129
+ data.warnings[1]=''
2130
+ data.flagParForCompleted=False
2131
+ data.numCallBackTotOk=data.numFinalized
2132
+ self.signals.progress.emit(data.numFinalized)
2133
+ data.numProcOrErrTot=0
2134
+ self.procWorkers[self.indProc].data=data
2135
+ self.ui.time_stamp.hide()
2136
+ return
2137
+
2138
+ def setProgressBar(self,data:dataTreePar):
2139
+ self.ui.progress_Proc.setMinimum(0)
2140
+ self.ui.progress_Proc.setMaximum(data.nsteps)
2141
+ self.ui.progress_Proc.setValue(data.numFinalized)
2142
+ self.w_Log.TABpar_at(data.ind).nimg=data.nsteps
2143
+ #ITE:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2144
+ return
2145
+
2146
+ def setLogProgressBar(self,data:dataTreePar):
2147
+ self.w_Log.ui.progress_Proc.setMinimum(0)
2148
+ self.w_Log.ui.progress_Proc.setMaximum(data.nsteps)
2149
+ self.w_Log.ui.progress_Proc.setValue(data.numFinalized)
2150
+ return
2151
+
2152
+ #********************************** Initialization of workers
2153
+ def initializeWorkers(self):
2154
+ self.indWorker=-1
2155
+ self.indProc=-1
2156
+ while self.pfPool is None:
2157
+ #TBD serve lo sleep? Se non ci sono errori cancellare
2158
+ pri.Error.white('****************\n****************\n****************\nwhile self.pfPool is None\n****************\n****************\n******************\n')
2159
+ if Flag_DEBUG: 1/0
2160
+ sleep(0.5)
2161
+ self.procWorkers=[]
2162
+ self.nProc=0
2163
+ nError=0
2164
+ nValid=0
2165
+ nTot=0
2166
+ self.dataQueue=[]
2167
+ for project in self.projectTree.itemList[1]:
2168
+ for process in project[0]:
2169
+ for step in process[1:]:
2170
+ step:ITEpar
2171
+ self.ui.Explorer.setITElayout(step)
2172
+ nTot+=int(process[0].FlagQueue and step.active)
2173
+ nError+=int(process[0].FlagQueue and step.active and step.flagRun<=0 and step.Step!=StepTypes.cal and step.OptionDone==0)
2174
+ nValid+=int((process[0].FlagQueue and step.active and step.flagRun>0) or step.Step==StepTypes.cal)
2175
+ if process[0].FlagQueue and step.active and step.flagRun<=0 and step.Step!=StepTypes.cal and step.OptionDone!=0 and len(step.link)==0:
2176
+ self.nProc+=1
2177
+ data=step.procdata
2178
+ data.ind=step.ind
2179
+ self.dataQueue.append(data)
2180
+ elif step.Process!=ProcessTypes.cal and step.Step==StepTypes.cal and step.OptionDone==1:
2181
+ data=step.procdata
2182
+ data.ind=step.ind
2183
+ self.setFlagRun(data,2)
2184
+ CAL:CALpar=self.w_Calibration.TABpar_at(step.ind)
2185
+ CAL.FlagCalVi=False
2186
+ if self.nProc==0 and nValid==0:
2187
+ self.warningDialog('No valid process found in the present projects!\nPlease, check for critical issues related to each step of the defined processes.',pixmap=icons_path+'issue.png')
2188
+ elif self.nProc==0 and nError>0:
2189
+ self.warningDialog(f'{nError} process step{"s" if nError>1 else ""} present{"" if nError>1 else "s"} critical issues!\nNo further valid process found in the present projects.\nPlease, check before running again.',pixmap=icons_path+'issue.png')
2190
+ elif self.nProc>0 and nError>0:
2191
+ if not self.questionDialog(f'{nError} process step{"s" if nError>1 else ""} present{"" if nError>1 else "s"} critical issues!\n{"They" if nError>1 else "It"} will not be executed. Do you want to proceed with processing?'):
2192
+ self.contProc=self.nProc-1 #necessario per far funzionare stopProc in run quando il risultato di questa funzione è False
2193
+ return False
2194
+ elif self.nProc==0:
2195
+ self.warningDialog(f'All the processes found in the present projects have been already executed!',pixmap=icons_path+'completed.png')
2196
+ FlagQueue=len(self.dataQueue)!=0
2197
+ self.contProc=-1 if not FlagQueue else 0
2198
+ self.putStepsInQueue()
2199
+ """
2200
+ for data in self.dataQueue:
2201
+ data:dataTreePar
2202
+ self.indWorker+=1
2203
+ self.initialize_proc(data)
2204
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2205
+ self.ui.Explorer.setITElayout(ITE_ind)
2206
+ """
2207
+ return FlagQueue
2208
+
2209
+ def initialize_proc(self,data:dataTreePar):
2210
+ self.set_proc(data)
2211
+ self.setFlagRun(data,-1)
2212
+
2213
+ if data.ind[:-2]==self.ui.tabAreaWidget.TABpar.ind[:-2]:
2214
+ self.ui.Explorer.arrangeCurrentProcess(self.processTree)
2215
+
2216
+ currpath=data.outPath
2217
+ if not os.path.exists(currpath):
2218
+ try:
2219
+ os.mkdir(currpath)
2220
+ except Exception as inst:
2221
+ pri.Error.red(f'It was not possible to make the directory {currpath}:\n{traceback.format_exc()}\n\n{inst}')
2222
+ pfPool = None if self.flagSimpleFor else self.pfPool
2223
+ if data.Step==StepTypes.min:
2224
+ self.numUsedProcs=self.numMaxProcs
2225
+ data.numPivOmpCores=1
2226
+ data.numUsedProcs=self.numMaxProcs
2227
+ procWorker=MIN_ParFor_Worker(data,self.indWorker,self.indProc,self.numMaxProcs,pfPool,self.parForMul)
2228
+ elif data.Step ==StepTypes.piv or data.Step ==StepTypes.spiv:
2229
+ data.numPivOmpCores,data.numUsedProcs=optimalPivCores(self.numMaxProcs,data.nimg,penCore=0.95)
2230
+ #data.numUsedProcs=3 # data.numUsedProcs is used for output should be the number of parfor threads used
2231
+ #data.numPivOmpCores=7#self.numMaxProcs
2232
+ self.numUsedProcs=data.numUsedProcs
2233
+ procWorker=PIV_ParFor_Worker(data,self.indWorker,self.indProc,self.numMaxProcs,pfPool,self.parForMul)
2234
+ elif data.Step ==StepTypes.disp:
2235
+ data.numPivOmpCores=NUMTHREADS_MAX
2236
+ data.numUsedProcs=1
2237
+ procWorker=StereoDisparity_ParFor_Worker(data,self.indWorker,self.indProc,self.numMaxProcs,pfPool,self.parForMul)
2238
+
2239
+
2240
+ procWorker.signals.progress.connect(self.progress_proc)
2241
+ self.signals.progress.connect(procWorker.setNumCallBackTot)
2242
+ procWorker.signals.finished.connect(self.pause_proc)
2243
+ procWorker.signals.initialized.connect(self.buttonPauseHideShow)
2244
+ procWorker.signals.completed.connect(self.stopProcs)
2245
+ self.signals.pause_proc.connect(procWorker.storeCompleted)
2246
+ #self.ui.button_pause.clicked.connect(MIN_worker.die)
2247
+ self.signals.killOrResetParForWorker.connect(procWorker.killOrReset)
2248
+ self.signals.indProc.connect(procWorker.updateIndProc)
2249
+ self.FlagInitialized=True
2250
+ self.procWorkers.append(procWorker)
2251
+ self.PaIRS_threadpool.start(procWorker)
2252
+
2253
+ def set_proc(self,data:dataTreePar,ind=None,FlagLog=True):
2254
+ if ind is None: ind=data.ind
2255
+ k=self.dataQueue.index(data)
2256
+ if self.dataFlagRuns[k]==0:
2257
+ self.getInheritance(ind)
2258
+ data.namesPIV=NamesPIV(Process=data.Process,Step=data.Step)
2259
+ INP_ind=self.w_Input.TABpar_at(ind)
2260
+ OUT_ind=self.w_Output.TABpar_at(ind)
2261
+ PRO_ind=self.w_Process.TABpar_at(ind)
2262
+ PRO_Min_ind=self.w_Process_Min.TABpar_at(ind)
2263
+ PRO_Disp_ind=self.w_Process_Disp.TABpar_at(ind)
2264
+ data.setProc(INP_ind,OUT_ind,PRO_ind,PRO_Min_ind,PRO_Disp_ind)
2265
+ data.assignDataName()
2266
+
2267
+ if FlagLog:
2268
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(ind)
2269
+ data.warnings[1]=ITE_ind.warningMessage
2270
+ data.setCompleteLog()
2271
+
2272
+ LOG_ind=self.w_Log.TABpar_at(ind)
2273
+ if LOG_ind:
2274
+ LOG_ind.text=data.Log
2275
+
2276
+ #********************************** Progress
2277
+ @Slot(int,int,int,list,str)
2278
+ def progress_proc(self,procId,i,pim,Var,stampa):
2279
+ ''' E' la funzione chiamata alla fine di ogni elaborazione dai vari threads in parfor è chiamata wrapUp CallBack'''
2280
+ data=self.procdata
2281
+ pri.Info.yellow(f'[progress_proc] {data.ind} {self.procdata is self.dataQueue[self.indProc]} {self.currind}')
2282
+ #******************** Updating total number of tasks passed to the pool
2283
+ data.numProcOrErrTot+=1
2284
+ #pri.Time.blue(0,f'progress_proc start i={i} pim={hex(pim)} {"*"*25} {procId} FlagRun={self.FlagRun}')
2285
+
2286
+ if i<0: return #When restarting a process return immediately if the images have been already processed
2287
+ #******************** Updating Log
2288
+ data.Log+=stampa+'\n'
2289
+ self.w_Log.TABpar_at(data.ind).text=data.Log
2290
+
2291
+ data.list_print[i]=stampa
2292
+ data.list_pim[i]=pim
2293
+
2294
+ if not pim&FLAG_CALLBACK_INTERNAL: return #c'è un errore prima della fine di tutti i processi relativi ad i
2295
+ #******************** Updating Progress Bar
2296
+ data.numCallBackTotOk+=1 #Always at the end the progress bar will go back to the correct value
2297
+ self.signals.progress.emit(data.numCallBackTotOk) #fundamental in multithreading
2298
+
2299
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2300
+ LOG_ind:LOGpar=self.w_Log.TABpar_at(data.ind)
2301
+ if self.FlagRun==1:
2302
+ self.ui.progress_Proc.setValue(data.numProcOrErrTot)
2303
+ LOG_ind.progress=data.numProcOrErrTot
2304
+ ITE_ind.progress=data.numProcOrErrTot
2305
+ else:
2306
+ self.ui.progress_Proc.setValue(data.numFinalized)
2307
+ LOG_ind.progress=data.numFinalized
2308
+ ITE_ind.progress=data.numFinalized
2309
+ LOG_ind.nimg=data.nsteps
2310
+ self.ui.Explorer.updateItemWidget(ITE_ind)
2311
+ self.adjustDependencies(ITE_ind)
2312
+
2313
+ flagSelected=data.hasIndexOf(self.ui.Explorer.ITEpar)
2314
+ if flagSelected:
2315
+ self.w_Log.LOGpar.progress=LOG_ind.progress
2316
+ self.w_Log.LOGpar.nimg=data.nimg
2317
+ self.w_Log.setProgressProc()
2318
+
2319
+ if data.Step==StepTypes.min:
2320
+ flagFinalized=(pim&FLAG_FINALIZED[0]) and (pim&FLAG_FINALIZED[1])
2321
+ elif data.Step in (StepTypes.piv,StepTypes.disp,StepTypes.spiv):
2322
+ flagFinalized=pim&FLAG_FINALIZED[0]
2323
+
2324
+ if not flagFinalized: return
2325
+ #******************** Updating numFinalized
2326
+ data.numFinalized+=1
2327
+
2328
+ if data.flagParForCompleted: return
2329
+ #******************** updating log
2330
+ if flagSelected:
2331
+ self.w_Log.LOGpar.text=data.Log
2332
+ self.w_Log.setLogText(FlagMoveToBottom=True)
2333
+
2334
+ pri.Process.green(f'progress_proc {i} data.numProcOrErrTot={data.numProcOrErrTot} self.numFinalized={data.numFinalized}')
2335
+ # prLock ha smesso di funzionare perchè?
2336
+ #prLock(f'progress_proc {i} data.numProcOrErrTot={data.numProcOrErrTot} self.numCallBackTotOk={self.numCallBackTotOk}')
2337
+
2338
+ if self.FlagRun==0 or (procId%self.numUsedProcs and data.Step!=StepTypes.disp): return #evitare aggiornamento tempo
2339
+ #if self.FlagRun==0: return #evitare aggiornamento tempo
2340
+ #******************** Updating time counter and stats
2341
+ actualTime=time()
2342
+ self.showTimeToEnd(data,time=actualTime)
2343
+
2344
+ if not Flag_GRAPHICS and not self.w_Vis.VISpar.FlagVis: return
2345
+ if actualTime<self.previousPlotTime+deltaTimePlot: return
2346
+ if not flagSelected: return
2347
+ # fra l'altro mi sembra che queata funzione sia abbastanza onerosa
2348
+ #updating plot
2349
+ pri.Time.green(f'plotting the field {i} over {data.numProcOrErrTot} ')
2350
+
2351
+ self.plotCurrent(data,i,Var)
2352
+ self.previousPlotTime=time()
2353
+ return
2354
+ #pri.Time.green(0,f'progress_proc end i={i} pim={hex(pim)} {"-"*25} {procId} FlagRun={self.FlagRun}')
2355
+
2356
+ def plotCurrent(self,data=None,i=-1,Var=None,FlagBridge=False):
2357
+ if Var==[]: return
2358
+ if data is None:
2359
+ data=self.procdata
2360
+ try:
2361
+ FlagCurrent=data.hasIndexOf(self.ui.Explorer.ITEpar)
2362
+ VIS_ind:VISpar=self.w_Vis.TABpar_at(data.ind)
2363
+ if data.Step==StepTypes.min:
2364
+ if i>-1:
2365
+ VIS_ind.image_file_Current=data.inpPath+data.list_Image_Files[i]
2366
+ self.w_Vis.image_Current_raw=Var
2367
+ else:
2368
+ VIS_ind.FlagMIN = True
2369
+ VIS_ind.image_file_Current=''
2370
+ self.w_Vis.image_Current_raw=None
2371
+ #if Var: #todo GP: per i==-1 Var deve essere l'immagine giusta
2372
+ # self.w_Vis.getImageInfo(Var,data.ind)
2373
+ # self.w_Vis.resetAllLevels(data.ind)
2374
+ # self.w_Vis.resetAllXYLims(data.ind)
2375
+
2376
+ if self.FlagResetPlot:
2377
+ VIS_ind.img=0
2378
+ VIS_ind.type=0
2379
+ VIS_ind.variable=self.namesPIV.combo_dict[self.namesPIV.img]
2380
+ VIS_ind.variableKey=self.namesPIV.combo_dict_keys[VIS_ind.variable]
2381
+ VIS_ind.FlagResetLevels=VIS_ind.FlagResetSizes=True
2382
+ self.FlagResetPlot=False
2383
+ pass
2384
+ elif data.Step in (StepTypes.piv,StepTypes.disp,StepTypes.spiv):
2385
+ if i>-1:
2386
+ if data.Step==StepTypes.disp:
2387
+ VIS_ind.result_file_Current=VIS_ind.resF(f'it{i+1}')
2388
+ VIS_ind.Nit=i+1
2389
+ VIS_ind.it=i+1
2390
+ else:
2391
+ VIS_ind.result_file_Current=VIS_ind.resF(i)
2392
+ fields=data.namesPIV.instVel
2393
+ result={}
2394
+ for f,v in zip(fields,Var):
2395
+ result[f]=v
2396
+ result=self.w_Vis.calcMagnitude(result)
2397
+ FlagUnit=VIS_ind.Out.xres!=1.0 or VIS_ind.Out.pixAR!=1.0
2398
+ result=self.w_Vis.calcZVorticity(result,FlagUnit)
2399
+ self.w_Vis.result_Current=result
2400
+ else:
2401
+ VIS_ind.result_file_Current=''
2402
+ self.w_Vis.result_Current=None
2403
+ #if Var: #todo GP: per i==-1 Var deve essere result
2404
+ # self.w_Vis.getResultInfo(result,data.ind)
2405
+ # self.w_Vis.resetAllLevels(data.ind)
2406
+ # self.w_Vis.resetAllXYLims(data.ind)
2407
+
2408
+ if self.FlagResetPlot:
2409
+ VIS_ind.img=0
2410
+ VIS_ind.type=1
2411
+ if data.Step==StepTypes.disp:
2412
+ VIS_ind.variable=self.namesPIV.combo_dict[self.namesPIV.z]
2413
+ else:
2414
+ VIS_ind.variable=self.namesPIV.combo_dict[self.namesPIV.Mod]
2415
+ VIS_ind.variableKey=self.namesPIV.combo_dict_keys[VIS_ind.variable]
2416
+ VIS_ind.FlagResetLevels=VIS_ind.FlagResetSizes=True
2417
+ self.FlagResetPlot=False
2418
+ pass
2419
+ else:
2420
+ pri.Info.red(f'Current process type ({data.Step}) has no plot function available!')
2421
+ return
2422
+ if FlagCurrent:
2423
+ self.w_Vis.FlagReset=i==-1
2424
+ self.setTABpars_at(data.ind,FlagAdjustPar=True,widget=self.w_Vis)
2425
+ pri.Process.yellow(f'{"*"*50} Result plotted!')
2426
+ except Exception as inst:
2427
+ pri.Error.red('Error Plotting in progress_proc',color=PrintTA.red)
2428
+ traceback.print_exc()
2429
+ if Flag_fullDEBUG: pri.Error.red(f'\n{inst}')
2430
+
2431
+ def showTimeToEnd(self,data:dataTreePar,time=0):
2432
+ if data.numCallBackTotOk:
2433
+ eta=data.deltaTime2String(data.eta) if time==0 else data.calcTimeStat(time,data.numCallBackTotOk)
2434
+ else:
2435
+ eta='no info'
2436
+ self.ui.time_stamp.show()
2437
+ self.ui.time_stamp.setText(f'Time to the end: {eta}')
2438
+
2439
+ #********************************** Pause
2440
+ @Slot(dataTreePar)
2441
+ def pause_proc(self,data:dataTreePar,errMessage=''):
2442
+ ''' pause_proc also when ends '''
2443
+ pri.Time.red(f'pause_proc Begin ')
2444
+ if errMessage:
2445
+ self.procdata.warnings[0]+='\n\n'+data.headerSection('CRITICAL ERROR',errMessage,'X')
2446
+ self.store_proc(data)
2447
+
2448
+ if data.FlagFinished or errMessage!='': #save and continue
2449
+ if self.FlagRun==0: # bug noto se uno mette in pausa mentre sta finendo di salvare (al 100%) da errore, basta ripremere play oppure eliminare il check
2450
+ pri.Process.red('**************************** pause_proc Error ****************************')
2451
+ else:
2452
+ self.nextProc()
2453
+ else:
2454
+ """
2455
+ if data.hasIndexOf(self.w_Tree.TABpar):
2456
+ self.w_Tree.selectFuture(0)
2457
+ if data.flagRun==-1:
2458
+ i:QTreeWidgetItem=self.w_Tree.TREpar.future[0]
2459
+ data.icon_type=self.Tree_icons.icontype('paused')
2460
+ i.setIcon(0,self.Tree_icons.paused)
2461
+ self.setButtons(data)
2462
+ """
2463
+
2464
+ pri.Time.red(f'pause_proc END')
2465
+ self.signals.pause_proc.emit()
2466
+
2467
+ def store_proc(self,data_worker:dataTreePar):
2468
+ data=self.procdata #self.w_Tree.TABpar_prev[idata.indTree][idata.indItem][-1]
2469
+ for f in self.procFields:
2470
+ if f in self.procdata.uncopied_fields:
2471
+ i=self.procdata.uncopied_fields.index(f)
2472
+ self.procdata.uncopied_fields.pop(i)
2473
+ #Aggiusto ciò che deve essere aggiornato
2474
+ #if not data.numFinalized: return
2475
+ pri.Time.yellow(f'{"-"*100} store PROC')
2476
+
2477
+ data.onPauseTimeStat()
2478
+
2479
+ #Copio ciò che è stato modificato nel worker
2480
+ #siccome data_worker sarà distrutto non faccio una deepcopy con copyfrom
2481
+ data.compMin=data_worker.compMin
2482
+ data.mediaPIV=data_worker.mediaPIV
2483
+ data.FlagFinished=data_worker.FlagFinished
2484
+
2485
+ if data.Step == StepTypes.disp:
2486
+ data.res=data_worker.res
2487
+ data.laserConst=[const for const in data_worker.laserConst]
2488
+ indpar=[i for i in data.ind]
2489
+ OUT_ind:OUTpar=self.w_Output.TABpar_at(indpar)
2490
+ OUT_ind.res=data.res
2491
+ if OUT_ind.unit==0:
2492
+ OUT_ind.xres=data.res
2493
+ if 'zconst' in data.OUT_dict and 'xterm' in data.OUT_dict and 'yterm' in data.OUT_dict:
2494
+ OUT_ind.zconst=data.OUT_dict['zconst']
2495
+ OUT_ind.xterm=data.OUT_dict['xterm']
2496
+ OUT_ind.yterm=data.OUT_dict['yterm']
2497
+ indpar[-2]+=1
2498
+ indpar[-1]=-1
2499
+ OUT_ind:OUTpar=self.w_Output.TABpar_at(indpar)
2500
+ OUT_ind.res=data.res
2501
+ if OUT_ind.unit==0:
2502
+ OUT_ind.xres=data.res
2503
+ if 'zconst' in data.OUT_dict and 'xterm' in data.OUT_dict and 'yterm' in data.OUT_dict:
2504
+ OUT_ind.zconst=data.OUT_dict['zconst']
2505
+ OUT_ind.xterm=data.OUT_dict['xterm']
2506
+ OUT_ind.yterm=data.OUT_dict['yterm']
2507
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(indpar)
2508
+ ITE_ind.procdata.res=data.res
2509
+ ITE_ind.procdata.laserConst=[const for const in data_worker.laserConst]
2510
+ if 'zconst' in data.OUT_dict and 'xterm' in data.OUT_dict and 'yterm' in data.OUT_dict:
2511
+ ITE_ind.procdata.OUT_dict['zconst']=data.OUT_dict['zconst']
2512
+ ITE_ind.procdata.OUT_dict['xterm']=data.OUT_dict['xterm']
2513
+ ITE_ind.procdata.OUT_dict['yterm']=data.OUT_dict['yterm']
2514
+
2515
+ #Aggiusto ciò che deve essere aggiornato
2516
+ if data.nsteps==data.numCallBackTotOk: #data.FlagFinished: #todo TA da GP: secondo te è corretto?
2517
+ flagRun=int(data.numFinalized==data.nsteps)+1
2518
+ else:
2519
+ flagRun=-1
2520
+ self.setFlagRun(data,flagRun)
2521
+ data.warnings[1]=''
2522
+ data.setCompleteLog()
2523
+ self.adjustSwitches()
2524
+
2525
+ Process=[]
2526
+ for l in self.projectTree.itemList[1:]:
2527
+ Process.append([ l[data.ind[0]][data.ind[1]][data.ind[2]] ])
2528
+ filename=data.procOutName()
2529
+ try:
2530
+ saveList(Process,filename)
2531
+ except Exception as inst:
2532
+ #warningDialog(self,f'Error while saving the configuration file {filename}!')
2533
+ pri.Error.red(f'Error while saving the configuration file {filename}!\n{inst}')
2534
+
2535
+ try:
2536
+ with open(data.outPathRoot+'.log', 'a') as file:
2537
+ file.write(data.Log)
2538
+ except:
2539
+ pri.Error.red(f'Error while trying to save the process log file: {data.outPathRoot}.log.\n{traceback.format_exc()}\n')
2540
+ try:
2541
+ with open(data.stepOutName()+'.log', 'w') as file:
2542
+ file.write(data.Log)
2543
+ except:
2544
+ pri.Error.red(f'Error while trying to save the process log file: {data.stepOutName()}.log.\n{traceback.format_exc()}\n')
2545
+ if data.Step in (StepTypes.piv,StepTypes.spiv):
2546
+ data.writeCfgProcPiv()
2547
+
2548
+ LOG_ind:LOGpar=self.w_Log.TABpar_at(data.ind)
2549
+ LOG_ind.text=data.Log
2550
+ self.w_Log.setLogText(FlagMoveToBottom=True)
2551
+ self.plotCurrent(data,-1,None,FlagBridge=True)
2552
+
2553
+ #if not data.hasIndexOf(self.ui.Explorer.ITEpar):
2554
+ ITE:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2555
+ self.ui.Explorer.setITElayout(ITE)
2556
+ self.inheritance(data.ind)
2557
+ self.adjustDependencies(ITE)
2558
+ self.ui.time_stamp.setText('')
2559
+
2560
+ self.adjustSwitches()
2561
+
2562
+ pri.Time.yellow(f'{"-"*100} store PROC END')
2563
+
2564
+ @Slot()
2565
+ def buttonPauseHideShow(self):
2566
+ #pr ('buttonPauseHideShow')
2567
+ self.ui.button_pause.setEnabled(True) #.show()
2568
+
2569
+ @Slot()
2570
+ def stopProcs(self):
2571
+ self.contProc+=1
2572
+ if self.procdata:
2573
+ pri.Time.red(f'stopProcs self.contProc={self.contProc}/{self.nProc} self.numCallBackTotOk={self.numCallBackTotOk} numFinalized={self.procdata.numFinalized} {self.FlagRun}')
2574
+
2575
+ FlagEnd = self.contProc==self.indProc+1 if self.FlagRun==2 else self.contProc==self.nProc
2576
+ if FlagEnd:
2577
+ self.ui.Explorer.updateSwitchMovies(self.currind,FlagStart=False)
2578
+ self.setSwitchEnabled(True)
2579
+ self.disableDropping(False)
2580
+ self.procdata=None
2581
+ self.currind=None
2582
+
2583
+ self.setEnabled(True)
2584
+ self.procWorkers=[]
2585
+ self.FlagRun=0
2586
+ self.putStepsInQueue()
2587
+ self.ui.button_pause.setEnabled(True)
2588
+ self.ui.button_Run.setEnabled(True)
2589
+ self.setButtonPause(True)
2590
+
2591
+ self.closeIfRequested()
2592
+
2593
+ def putStepsInQueue(self):
2594
+ if self.FlagRun:
2595
+ self.dataFlagRuns=[]
2596
+ for k,data in enumerate(self.dataQueue):
2597
+ if self.FlagRun:
2598
+ self.dataFlagRuns.append(data.flagRun)
2599
+ self.setFlagRun(data,-10)
2600
+ elif data.flagRun==-10:
2601
+ self.setFlagRun(data,self.dataFlagRuns[k])
2602
+ else:
2603
+ continue
2604
+ ITE_ind:ITEpar=self.ui.Explorer.ITEfromInd(data.ind)
2605
+ self.ui.Explorer.setITElayout(ITE_ind)
2606
+ self.ui.Explorer.arrangeCurrentProcess(self.processTree)
2607
+
2608
+ def closeIfRequested(self):
2609
+ self.ui.label_updating_pairs.setVisible(False)
2610
+ if self.waitingDialog:
2611
+ self.waitingDialog.done(0)
2612
+ self.waitingDialog=None
2613
+ if self.completingTask:
2614
+ self.completingTask()
2615
+ self.completingTask=None
2616
+ """
2617
+ if self.FlagClosing[0]:
2618
+ self.correctClose()
2619
+ """
2620
+
2621
+ #********************************************* CalVi
2622
+ def runCalVi(self):
2623
+ self.w_Vis_CalVi.VISpar.FlagRunning=not self.w_Vis_CalVi.VISpar.FlagRunning
2624
+ if self.w_Vis_CalVi.VISpar.FlagRunning:
2625
+ """
2626
+ prev=self.w_Vis_CalVi.TABpar_prev_at(self.w_Vis_CalVi.TABpar.ind)
2627
+ step=len(prev)-1-self.w_Vis_CalVi.TABpar.ind[-1]
2628
+ self.button_back_forward_action(step)
2629
+ self.w_Vis_CalVi.VISpar.FlagRunning=True
2630
+ """
2631
+ self.w_Vis_CalVi.VISpar.FlagRunning=False
2632
+ self.w_Calibration.fullCallback()
2633
+ self.w_Vis_CalVi.VISpar.FlagRunning=True
2634
+
2635
+ self.disableTab_Vis(self.w_Vis_CalVi.VISpar.FlagRunning)
2636
+
2637
+ self.initDataAndSetImgFromGui(self.w_Input_CalVi.INPpar,self.w_Process_CalVi.PROpar)
2638
+ FlagResume=self.w_Vis_CalVi.FlagResume
2639
+ def removeQuestion():
2640
+ if FlagResume!=1: return
2641
+ camString=''
2642
+ cams=self.w_Input_CalVi.INPpar.cams
2643
+ if self.w_Input_CalVi.INPpar.FlagCam:
2644
+ if len(cams)==1: camString=f'_cam{cams[0]}'
2645
+ else:
2646
+ cams=[-1]
2647
+ data=self.w_Vis_CalVi.calibView.calib.cal.data
2648
+ varName=f'{data.percorsoOut}{data.NomeFileOut}{camString}{outExt.calvi}'
2649
+ questionMessage=f'The calibration result file:\n{varName}\nalready exists in the current output path. The above error could arise from the attempt of loading such a file.\n\nDo you want to remove the file from the disk?\n\n(Please, consider to choose a different output name root for your process)'
2650
+ if questionDialog(self,questionMessage):
2651
+ os.remove(varName)
2652
+ if self.w_Input_CalVi.INPpar.errorMessage:
2653
+ warningDialog(self,self.w_Input_CalVi.INPpar.errorMessage)
2654
+ self.abortCalVi()
2655
+ return removeQuestion()
2656
+ if self.w_Vis_CalVi.VISpar.errorMessage:
2657
+ warningDialog(self,self.w_Vis_CalVi.VISpar.errorMessage)
2658
+ self.abortCalVi()
2659
+ return removeQuestion()
2660
+ if not all([all(imExc) for imExc in self.w_Vis_CalVi.VISpar.imEx]):
2661
+ imageFile=''
2662
+ for k in range(len(self.w_Vis_CalVi.VISpar.imEx)):
2663
+ for j in range(len(self.w_Vis_CalVi.VISpar.imEx[k])):
2664
+ if not self.w_Vis_CalVi.VISpar.imEx[k][j]:
2665
+ imageFile=self.w_Vis_CalVi.VISpar.imList[k][j]
2666
+ break
2667
+ if imageFile: break
2668
+ Message=f'No valid image files found!\n[{imageFile},...]'
2669
+ warningDialog(self,Message)
2670
+ self.abortCalVi()
2671
+ return removeQuestion()
2672
+ self.w_Vis_CalVi.buttonAction()
2673
+ pri.Info.cyan(f'Running calibration FlagRestart={self.w_Vis_CalVi.FlagResume}')
2674
+ if self.w_Vis_CalVi.FlagResume>-1:
2675
+ self.w_Vis_CalVi.runCalVi(flagMod=bool(self.w_Vis_CalVi.FlagResume))
2676
+ else:
2677
+ flagYes=self.questionDialog('A calibration result file already exists in the current output path. Do you want to overwrite it?')
2678
+ if flagYes:
2679
+ self.w_Vis_CalVi.FlagResume=0
2680
+ self.w_Vis_CalVi.runCalVi(flagMod=False)
2681
+ else:
2682
+ self.runCalVi()
2683
+ else:
2684
+ self.disableTab_Vis(self.w_Vis_CalVi.VISpar.FlagRunning)
2685
+
2686
+ if self.w_Vis_CalVi.FlagResume>-1:
2687
+ self.saveCal()
2688
+ if self.w_Vis_CalVi.calibView.calib.FlagCalibration and ( (self.w_Process_CalVi.PROpar.FlagPlane and not self.w_Process_CalVi.PROpar.CalibProcType==0) or self.w_Process_CalVi.PROpar.CamMod==4 ):
2689
+ if self.w_Input_CalVi.INPpar.FlagOptPlane: self.savePlanePar()
2690
+ self.updateINPpar()
2691
+ self.saveCal('_Mod')
2692
+ if self.w_Vis_CalVi.calibView.calib.FlagCalibration:
2693
+ self.appendCalibration()
2694
+ #indTree,indItem,ind=self.w_Input_CalVi.INPpar.indexes()
2695
+ #self.actualBridge('Input_CalVi',indTree,indItem,ind)
2696
+ self.initDataAndSetImgFromGui(self.w_Input_CalVi.INPpar,self.w_Process_CalVi.PROpar)
2697
+ self.w_Vis_CalVi.stopCalVi()
2698
+
2699
+ self.closeIfRequested()
2700
+
2701
+ def abortCalVi(self):
2702
+ self.w_Vis_CalVi.FlagResume=-1
2703
+ self.runCalVi()
2704
+
2705
+ def updateINPpar(self):
2706
+ if self.w_Process_CalVi.PROpar.FlagPlane:
2707
+ costPlanes=self.w_Vis_CalVi.calibView.calib.cal.vect.costPlanes
2708
+ for i in range(len(self.w_Input_CalVi.INPpar.filenames)):
2709
+ self.w_Input_CalVi.INPpar.plapar[i]=[round(p,3) for p in costPlanes[i]]
2710
+ if self.w_Process_CalVi.PROpar.CamMod==4:
2711
+ cost=self.w_Vis_CalVi.calibView.calib.cal.vect.cost[0]
2712
+ self.w_Process_CalVi.PROpar.CylRad=cost[21]
2713
+ self.w_Process_CalVi.PROpar.CylThick=cost[22]
2714
+ self.w_Process_CalVi.PROpar.CylNRatio=cost[23]
2715
+ self.w_Input_CalVi.fullCallback()
2716
+
2717
+ def appendCalibration(self):
2718
+ INP=self.w_Input_CalVi.INPpar
2719
+ data=self.w_Vis_CalVi.calibView.calib.cal.data
2720
+ if INP.FlagCam:
2721
+ outFiles=[f'{data.percorsoOut}{data.NomeFileOut}{c}.cal' for c in INP.cams]
2722
+ else:
2723
+ outFiles=[f'{data.percorsoOut}{data.NomeFileOut}{1}.cal']
2724
+ appendedFiles=[f for f in outFiles if f not in self.w_Calibration.CALpar.calList]
2725
+ self.w_Calibration.buttonAction()
2726
+ if len(appendedFiles)==0: return
2727
+ if self.w_Calibration.CALpar.ncam==len(self.w_Calibration.CALpar.calList):
2728
+ warningDialog(self,f'The calibration file list already contains a number of files equal to the number of cameras specified ({self.w_Calibration.CALpar.ncam}). The results of the current CalVi process will not be appended to the list.')
2729
+ else:
2730
+ self.w_Calibration.ui.calTree.importLists(appendedFiles)
2731
+ self.w_Calibration.copyListsFromTree()
2732
+ #self.w_Calibration.nullCallback()
2733
+ self.w_Calibration.adjustTABparInd()
2734
+
2735
+ def saveCal(self,add_str=''):
2736
+ VIS=self.w_Vis_CalVi.VISpar
2737
+ data=self.w_Vis_CalVi.calibView.calib.cal.data
2738
+ calVect=self.w_Vis_CalVi.calibView.calib.cal.vect
2739
+ VIS.orPosAndShift=[]
2740
+ VIS.angAndMask=[]
2741
+ VIS.spotDistAndRemoval=[]
2742
+ for c in range(data.NCam):
2743
+ for p1 in range(data.Numpiani_PerCam):
2744
+ p=p1+c*data.Numpiani_PerCam
2745
+ VIS.orPosAndShift.append([])
2746
+ VIS.angAndMask.append([])
2747
+ VIS.spotDistAndRemoval.append([])
2748
+
2749
+ VIS.orPosAndShift[p].append(float(calVect.XOr[p] - data.ColPart))
2750
+ VIS.orPosAndShift[p].append(float(calVect.YOr[p] - data.RigaPart))
2751
+ VIS.orPosAndShift[p].append(float(calVect.xOrShift[p]))
2752
+ VIS.orPosAndShift[p].append(float(calVect.yOrShift[p]))
2753
+
2754
+ VIS.angAndMask[p].append(float(calVect.angCol[p]))
2755
+ VIS.angAndMask[p].append(float(calVect.angRow[p]))
2756
+ for i in self.w_Vis_CalVi.calibView.calib.cal.getPuTrovaCC(p):
2757
+ VIS.angAndMask[p].append(float(i))
2758
+
2759
+ VIS.spotDistAndRemoval[p].append(float(calVect.dColPix[p]))
2760
+ VIS.spotDistAndRemoval[p].append(float(calVect.dRigPix[p]))
2761
+ VIS.spotDistAndRemoval[p].append(float(calVect.remPointsUp[p]))
2762
+ VIS.spotDistAndRemoval[p].append(float(calVect.remPointsDo[p]))
2763
+ VIS.spotDistAndRemoval[p].append(float(calVect.remPointsLe[p]))
2764
+ VIS.spotDistAndRemoval[p].append(float(calVect.remPointsRi[p]))
2765
+
2766
+ INP=self.w_Input_CalVi.INPpar
2767
+ camString=''
2768
+ if INP.FlagCam:
2769
+ if len(INP.cams)==1: camString=f'_cam{INP.cams[0]}'
2770
+ varName=f'{data.percorsoOut}{data.NomeFileOut}{camString}{add_str}{outExt.calvi}'
2771
+ var=[INP,self.w_Process_CalVi.PROpar,VIS,myStandardPath(os.path.dirname(varName))]
2772
+ try:
2773
+ with open(varName,'wb') as file:
2774
+ pickle.dump(var,file)
2775
+ pri.Info.blue(f'>>> Saving calibration process file {varName}')
2776
+ except:
2777
+ pri.Error.red(f'Error while trying to save the calibration process file: {varName}.\n{traceback.format_exc()}\n')
2778
+
2779
+ self.w_Input_CalVi.adjustTABparInd()
2780
+ self.w_Process_CalVi.adjustTABparInd()
2781
+ self.w_Vis_CalVi.adjustTABparInd()
2782
+ Process=[]
2783
+ for l in self.projectTree.itemList[1:]:
2784
+ Process.append([ l[INP.ind[0]][INP.ind[1]][INP.ind[2]] ])
2785
+ filename=f'{data.percorsoOut}{data.NomeFileOut}{camString}{add_str}{outExt.cal}'
2786
+ try:
2787
+ saveList(Process,filename)
2788
+ except Exception as inst:
2789
+ #warningDialog(self,f'Error while saving the configuration file {filename}!')
2790
+ pri.Error.red(f'Error while saving the configuration file {filename}!\n{inst}')
2791
+ return
2792
+
2793
+ def savePlanePar(self):
2794
+ data=self.w_Vis_CalVi.calibView.calib.cal.data
2795
+ calVect=self.w_Vis_CalVi.calibView.calib.cal.vect
2796
+ INP=self.w_Input_CalVi.INPpar
2797
+ if len(INP.cams)==1: camString=f'_cam{INP.cams[0]}'
2798
+ else: camString=''
2799
+ plaparRad=f'{data.percorsoOut}{data.NomeFileOut}{camString}_plane'
2800
+ plapar_names=['beta (°)','alpha (°)','gamma (°)','x (mm)','y (mm)','z (mm)']
2801
+ for i,c in enumerate(calVect.costPlanes):
2802
+ dp={}
2803
+ for p,v in zip(plapar_names,c):
2804
+ dp[p]=v
2805
+ plaparName=plaparRad+f"{i+1:d}_z{dp['z (mm)']:.2f}{outExt.pla}"
2806
+ try:
2807
+ with open(plaparName,'w') as file:
2808
+ file.write(str(dp).replace('{','{\n ').replace(',',',\n').replace('}','\n}'))
2809
+ except:
2810
+ pri.Error.red(f'Error while trying to save the plane parameter file: {plaparName}.\n{traceback.format_exc()}\n')
2811
+ pri.Info.blue(f' Saving plane data file {plaparName}')
2812
+
2813
+ def setRunCalViButtonText(self,FlagRunning=True):
2814
+ button=self.ui.button_Run_CalVi
2815
+ if not FlagRunning:
2816
+ flag=bool(self.w_Vis_CalVi.VISpar.errorMessage) or bool(self.w_Input_CalVi.INPpar.errorMessage)
2817
+ if flag:
2818
+ fPixSize=button.font().pixelSize()
2819
+ s=f'<sup><span style=" font-size:{fPixSize-2}px"> ⚠</span></sup>'
2820
+ else:
2821
+ s=''
2822
+ text='Run'
2823
+ button.setIcon(self.icon_play)
2824
+ tooltip=f'Run CalVi{" (some issues detected!)" if flag else ""}'
2825
+ else:
2826
+ s=''
2827
+ text='Save'
2828
+ button.setIcon(self.icon_save_and_stop)
2829
+ tooltip='Quit CalVi and save results'
2830
+ button.setText(text+s)
2831
+ tooltip+=' ('+button.shortcut().toString(QKeySequence.NativeText)+')'
2832
+ button.setToolTip(tooltip)
2833
+ button.setStatusTip(tooltip)
2834
+
2835
+ def disableTab_Vis(self,Flag=True):
2836
+ self.ui.w_Managing_Tabs.setEnabled(not Flag)
2837
+ for w in self.tabWidgets:
2838
+ w:gPaIRS_Tab
2839
+ if w!=self.w_Vis_CalVi and w!=self.ui.tabAreaWidget:
2840
+ w.setEnabled(not Flag)
2841
+ self.w_Input.ui.button_back.setEnabled(not Flag)
2842
+ self.w_Input.ui.button_forward.setEnabled(not Flag)
2843
+ self.ui.button_Run_CalVi.setVisible(not Flag)
2844
+ self.ui.button_Abort_CalVi.setVisible(Flag)
2845
+ self.setRunCalViButtonText(FlagRunning=Flag)
2846
+
2847
+ self.ui.tabAreaWidget.FlagDisplayControls=not Flag
2848
+ self.ui.tabAreaWidget.ui.button_restore_undo.setVisible(not Flag)
2849
+ self.ui.tabAreaWidget.ui.button_back.setVisible(not Flag)
2850
+ self.ui.tabAreaWidget.ui.button_forward.setVisible(not Flag)
2851
+ self.ui.tabAreaWidget.display_controls()
2852
+
2853
+ self.ui.label_updating_pairs.setVisible(Flag)
2854
+
2855
+ def initDataAndSetImgFromGui(self,INP,PRO):
2856
+ self.w_Vis_CalVi.initDataFromGui(INP,PRO)
2857
+ inddel=self.w_Vis_CalVi.setImgFromGui()
2858
+ if len(inddel): #todo GP: migliorare? (setto due volte le immagini e faccio in calib il check)
2859
+ Message=f'The following image files encountered issues while importing (they may have incompatible sizes with the first image file of the list "{self.w_Input_CalVi.INPpar.filenames[0]}" or be not in grayscale format):\n'
2860
+ for k in inddel:
2861
+ if k==inddel[-1]: colon='.'
2862
+ else: colon=';'
2863
+ Message+=f'- {self.w_Input_CalVi.INPpar.filenames[k]}{colon}\n'
2864
+ Message+='They will not be added to the list.'
2865
+ self.warningDialog(Message)
2866
+ for i in range(len(inddel)-1,-1,-1):
2867
+ k=inddel[i]
2868
+ self.w_Input_CalVi.INPpar.filenames.pop(k)
2869
+ self.w_Input_CalVi.INPpar.plapar.pop(k)
2870
+ self.w_Input_CalVi.adjust_list_images()
2871
+ #self.w_Input_CalVi.nullCallback()
2872
+ self.w_Input_CalVi.adjustTABparInd()
2873
+ self.w_Vis_CalVi.initDataFromGui(INP,PRO)
2874
+ self.w_Vis_CalVi.setImgFromGui()
2875
+
2876
+ #********************************************* LEGACY
2877
+ def setUpdatingState(self,flagUpdating):
2878
+ if Flag_DISABLE_onUpdate:
2879
+ for tname in self.TABnames:
2880
+ w: gPaIRS_Tab
2881
+ wname='w_'+tname
2882
+ w=getattr(self,wname)
2883
+ if tname=='Vis':
2884
+ w.ui.w_plot.setEnabled(not flagUpdating)
2885
+ else:
2886
+ w.ui.scrollArea.setEnabled(not flagUpdating)
2887
+ #w.setVisible(not flag)
2888
+ self.ui.label_updating_import.setVisible(flagUpdating)
2889
+ pass
2890
+
2891
+ #*************************************************** Parallel Pool
2892
+ def launchParPool(self,nworkers):
2893
+ # TA ho deciso di utilizzare concurrent.futures per lanciare il processo in parallelo perchè non ho capito bene come usare
2894
+ # quello di QT
2895
+ # Avevo provato anche Thread ma non sono stato capace di capire come lanciare
2896
+ # Ho provato a lanciare le due operazioni all'interno di initParForAsync in parallelo ma mi sembra che sia molto lento
2897
+ # Alla fine ho adottato una configurazione mista con initParForAsync scritta in mod asincrono
2898
+ # Quando initParForAsync termina chiama initParForComplete che effettua le ultime cose
2899
+
2900
+ if hasattr(self, 'pfPool'):#this function should be called only once but just in case we check and close the parPool
2901
+ self.pfPool.closeParPool()
2902
+ else:
2903
+ self.pfPool=None
2904
+ self.parForMul=None
2905
+ self.FlagParPoolInit=False
2906
+ self.signals.parPoolInit.connect(self.parPoolInitSetup)
2907
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
2908
+ f3=executor.submit(asyncio.run,initParForAsync(nworkers))
2909
+ def initParForComplete(_f3):
2910
+ pri.Time.blue(0,'fine initParFor1')
2911
+ (pfPool,parForMul)=f3.result()
2912
+ #timesleep(5)
2913
+ pri.Time.blue(0,'PIV_ParFor_Worker dopo ParForMul')
2914
+ parForMul.sleepTime=ParFor_sleepTime #time between calls of callBack
2915
+ self.pfPool=pfPool
2916
+ self.parForMul=parForMul
2917
+ self.parForMul.numUsedCores=self.numMaxProcs # =NUMTHREADS_MAX#potrebbe essere minore di NUMTHREADS_PIV_MAX con cui è stato impostato
2918
+ self.FlagParPoolInit=True
2919
+ self.signals.parPoolInit.emit()
2920
+ f3.add_done_callback(initParForComplete)
2921
+
2922
+ @Slot(int)
2923
+ def parPoolInitSetup(self):
2924
+ if self.FlagGuiInit:
2925
+ if not self.FlagParPoolInit:
2926
+ self.FlagParPoolInit=False
2927
+
2928
+ self.ui.label_gif.setPixmap(QPixmap())
2929
+ self.ui.label_gif.setMovie(self.load_gif)
2930
+
2931
+ self.ui.label_loading.setText('Starting parallel pool with')
2932
+ self.ui.spin_nworkers.setEnabled(False)
2933
+ self.ui.label_loading_2.setText('workers...')
2934
+ else:
2935
+ self.ui.button_Run.setEnabled(True)
2936
+
2937
+ self.ui.label_gif.setMovie(QMovie())
2938
+ self.ui.label_gif.setPixmap(self.loaded_map)
2939
+
2940
+ self.ui.label_loading.setText('Parallel pool with')
2941
+ self.ui.spin_nworkers.setEnabled(True)
2942
+ self.ui.label_loading_2.setText('workers started!')
2943
+ #self.repaint()
2944
+
2945
+ def spin_nworkers_action(self):
2946
+ val=self.ui.spin_nworkers.value()
2947
+ self.GPApar.NumCores=val
2948
+ if val <=NUMTHREADS_MAX:
2949
+ self.numMaxProcs=val
2950
+
2951
+ #*************************************************** Warnings
2952
+ def warningDialog(self,Message,time_milliseconds=0,flagScreenCenter=False,icon=QIcon(),palette=None,pixmap=None,title='Warning!',flagRichText=False,flagNoButtons=False,addButton:dict=None):
2953
+ return warningDialog(self,Message,time_milliseconds,flagScreenCenter,icon,palette,pixmap,title,flagRichText,flagNoButtons,addButton)
2954
+
2955
+ def questionDialog(self,Message):
2956
+ flagYes=questionDialog(self,Message)
2957
+ return flagYes
2958
+
2959
+ #*************************************************** Checking
2960
+ def checkProcesses(self,FlagInit=False,ind=None):
2961
+ FlagCheck=ind is None
2962
+ if ind is not None: projects=self.projectTree.itemList[1][ind[0]:ind[0]+1]
2963
+ else: projects=self.projectTree.itemList[1]
2964
+ for ITEs_project in projects:
2965
+ if ind is not None: ITEs_project_ind=ITEs_project[ind[1]:ind[1]+1]
2966
+ else: ITEs_project_ind=ITEs_project
2967
+ for ITEs_tree in ITEs_project_ind:
2968
+ if ind is not None: ITEs_tree_ind=ITEs_tree[ind[2]:ind[2]+1]
2969
+ else: ITEs_tree_ind=ITEs_tree
2970
+ for ITEs in ITEs_tree_ind:
2971
+ if ind is not None: ITEs_ind=ITEs[ind[3]+1:ind[3]+2]
2972
+ else: ITEs_ind=ITEs
2973
+ for ITE in ITEs_ind:
2974
+ ITE:ITEpar
2975
+ ITE.FlagInit=FlagInit
2976
+ indITE=ITE.ind
2977
+ if ind is not None: FlagCheck=True
2978
+ for w in self.tabWidgets:
2979
+ w:gPaIRS_Tab
2980
+ TABpar_ind:TABpar=w.TABpar_at(indITE)
2981
+ if TABpar_ind:
2982
+ if FlagInit:
2983
+ w.checkTABpar(indITE)
2984
+ w.setTABwarn(indITE)
2985
+ TABpar_ind.FlagInit=True
2986
+ else:
2987
+ TABpar_ind.FlagInit=False
2988
+ self.logBridge(indITE)
2989
+ return FlagCheck
2990
+
2991
+ #*************************************************** Projects
2992
+ def pauseQuestion(self,taskDescription='continuing',task=lambda:None,FlagFirstQuestion=False):
2993
+ if FlagFirstQuestion:
2994
+ if not self.questionDialog(f'Are you sure you want to proceed with {taskDescription}?'):
2995
+ return
2996
+ if self.FlagRun or self.w_Vis_CalVi.VISpar.FlagRunning:
2997
+ if self.FlagRun: currentTaskDescription='PaIRS is currently executing the processes in the current workspace. '
2998
+ elif self.w_Vis_CalVi.VISpar.FlagRunning: currentTaskDescription='CalVi is currently running. '
2999
+ if self.questionDialog(f'{currentTaskDescription}Do you want to pause them before {taskDescription}?'):
3000
+ if self.FlagRun: self.button_run_pause_action()
3001
+ self.setEnabled(False)
3002
+ self.completingTask=task
3003
+ self.waitingDialog=self.warningDialog('Please, wait while stopping the running processes!',pixmap=''+ icons_path +'sandglass.png',flagNoButtons=True)
3004
+ if self.w_Vis_CalVi.VISpar.FlagRunning: self.abortCalVi()
3005
+ else:
3006
+ task()
3007
+ return
3008
+
3009
+ def open_project(self):
3010
+ filename, _ = QFileDialog.getOpenFileName(self,\
3011
+ "Select a PaIRS project file", filter=f'*{outExt.proj}',\
3012
+ #dir=self.w_Input.INPpar.path,\
3013
+ options=optionNativeDialog)
3014
+ if not filename: return
3015
+ errorString=''
3016
+ try:
3017
+ data, errorMessage=loadList(filename)
3018
+ errorString+=errorMessage
3019
+ except:
3020
+ errorString+=traceback.format_exc()
3021
+ if errorString:
3022
+ WarningMessage=f'Error with loading the file: {filename}\n'
3023
+ warningDialog(self,WarningMessage)
3024
+ pri.Error.red(f'{WarningMessage}\n{errorString}\n')
3025
+ try:
3026
+ ind=self.projectTree.topLevelItemCount()
3027
+ insert_at_depth(self.projectTree.itemList,self.projectTree.listDepth,ind,data)
3028
+ self.modifyWorkspace()
3029
+ TRE:TREpar=self.projectTree.itemList[0][ind]
3030
+ TRE.project=ind
3031
+ self.projectTree.createProjectItem(ind,FlagNewItem=False)
3032
+ item=self.projectTree.topLevelItem(ind)
3033
+ self.projectTree.setCurrentItem(item)
3034
+ item.setSelected(True)
3035
+ self.adjustItemWidgets()
3036
+ except Exception as inst:
3037
+ WarningMessage=f'Error while retrieving the project "{data[0][0].name}" from the file: {filename}\n'
3038
+ warningDialog(self,WarningMessage)
3039
+ pri.Error.red(f'{WarningMessage}\n{traceback.format_exc()}\n')
3040
+ return
3041
+
3042
+ def saveas_current_structure(self,name:str='',ext='',saveList=lambda f:None,par:TABpar=None,FlagSave=True):
3043
+ Title=f"Select location and name of the {name} file to save"
3044
+ filename, _ = QFileDialog.getSaveFileName(self,Title,
3045
+ dir=par.name.replace(' ','_'), #self.w_Input.INPpar.path+par.name.replace(' ','_'),
3046
+ filter=f'*{ext}',\
3047
+ options=optionNativeDialog)
3048
+ if not filename: return
3049
+ if len(filename)>=len(ext):
3050
+ if filename[-len(ext):]==ext: filename=filename[:-len(ext)] #per adattarlo al mac
3051
+ filename=myStandardRoot('{}'.format(str(filename)))
3052
+ if not outExt.cfg in filename:
3053
+ filename=filename+ext
3054
+ if FlagSave:saveList(filename)
3055
+ return filename
3056
+
3057
+ def updateWorkspaceTitle(self):
3058
+ self.GPApar.name=self.ui.title_workspace.label.text().replace(self.GPApar.saveBullet(),'')
3059
+ self.GPApar.FlagSaved=False
3060
+ self.adjustWorkspaceHeader()
3061
+
3062
+ def save_current_project(self,filename):
3063
+ Project=[]
3064
+ FlagSaved=False
3065
+ for l in self.projectTree.itemList:
3066
+ Project.append([l[self.TREpar.project]])
3067
+ try:
3068
+ TRE:TREpar=self.projectTree.itemList[0][self.TREpar.project]
3069
+ TRE.outName=filename
3070
+ TRE.savedDate=currentTimeString()
3071
+ TRE.FlagSaved=True
3072
+ saveList(Project,filename)
3073
+ except Exception as inst:
3074
+ warningDialog(self,f'Error while saving the file {filename}!\nPlease, retry.')
3075
+ pri.Error.red(f'Error while saving the file {filename}!\n{inst}')
3076
+ else:
3077
+ self.TREpar.copyfrom(TRE)
3078
+ self.adjustItemWidgets()
3079
+ FlagSaved=True
3080
+ return FlagSaved
3081
+
3082
+ def saveas_current_project(self):
3083
+ self.saveas_current_structure(name='project',ext=outExt.proj,saveList=lambda f: self.save_current_project(f),par=self.TREpar)
3084
+
3085
+ def save_project(self):
3086
+ FlagSaved=False
3087
+ if self.TREpar.outName:
3088
+ filename=self.TREpar.outName
3089
+ if self.TREpar.FlagRunnable and self.TREpar.FlagQueue:
3090
+ self.pauseQuestion('saving the selected project',lambda: self.save_current_project(filename),FlagFirstQuestion=self.FlagRun!=0)
3091
+ else:
3092
+ FlagSaved=self.save_current_project(filename)
3093
+ else:
3094
+ FlagSaved=self.saveas_project()
3095
+ return FlagSaved
3096
+
3097
+ def saveas_project(self):
3098
+ FlagSaved=False
3099
+ if self.TREpar.FlagRunnable and self.TREpar.FlagQueue:
3100
+ self.pauseQuestion('saving the selected project',self.saveas_current_project)
3101
+ else:
3102
+ FlagSaved=self.saveas_current_project()
3103
+ return FlagSaved
3104
+
3105
+ def close_project(self):
3106
+ self.pauseQuestion('closing the selected project',lambda: ProjectTree.button_close_action(self.projectTree))
3107
+
3108
+ def clean_projects(self):
3109
+ self.pauseQuestion('closing all the projects',lambda: ProjectTree.button_clean_action(self.projectTree))
3110
+
3111
+ def copy_process(self):
3112
+ if self.ui.Explorer.ITEpar.FlagQueue and self.ui.Explorer.currentTree==self.processTree:
3113
+ self.pauseQuestion('copying the selected process',lambda: ProcessTree.button_copy_action(self.processTree))
3114
+
3115
+ def delete_process(self):
3116
+ if self.ui.Explorer.currentTree==self.processTree:
3117
+ #if self.ui.Explorer.ITEpar.FlagQueue: self.ui.Explorer.ITEpar.FlagQueue=False
3118
+ self.pauseQuestion('deleting the selected process',lambda: ProcessTree.button_delete_action(self.processTree))
3119
+
3120
+ def clean_processes(self):
3121
+ if self.ui.Explorer.currentTree==self.processTree:
3122
+ self.pauseQuestion('cleaning the whole process list',lambda: ProcessTree.button_clean_action(self.processTree))
3123
+
3124
+ #*************************************************** Sizes, font & layout
3125
+ def updateGPAparGeometry(self):
3126
+ self.GPApar.Geometry=self.saveGeometry().toBase64().data().decode()
3127
+ self.GPApar.WindowState=self.saveState().toBase64().data().decode()
3128
+ #g=self.geometry()
3129
+ #self.GPApar.Geometry=[g.x(), g.y(), g.width(), g.height()]
3130
+ #self.GPApar.WindowState=[self.windowState().value,self.windowState().name]
3131
+ splitterSizes={}
3132
+ for s in self.ui.Explorer.findChildren(QSplitter)+[self.ui.main_splitter,self.ui.Operating_Tabs_splitter]:
3133
+ s:QSplitter
3134
+ pri.Coding.green(f'splitterSizes: {s.objectName()}')
3135
+ splitterSizes[s.objectName()]=s.sizes()
3136
+ self.GPApar.SplitterSizes=splitterSizes
3137
+ scrollAreaValues={}
3138
+ for a in self.ui.Explorer.findChildren(QScrollArea):
3139
+ a:QScrollArea
3140
+ pri.Coding.blue(f'scrollArea: {a.objectName()}')
3141
+ scrollAreaValues[a.objectName()]=[a.horizontalScrollBar().value(),a.verticalScrollBar().value()]
3142
+ self.GPApar.ScrollAreaValues=scrollAreaValues
3143
+ for w in self.tabWidgets[:-1]:
3144
+ w:gPaIRS_Tab
3145
+ self.GPApar.globalVals[w.TABname]=w.syncPrevGlobalFields(FlagSync=False)
3146
+ return
3147
+
3148
+ def setFontPixelSize(self):
3149
+ if self.fontPixelSize==self.GPApar.fontPixelSize: return
3150
+ fPixSize=self.GPApar.fontPixelSize
3151
+ font=QFont()
3152
+ font.setFamily(fontName)
3153
+ font.setPixelSize(fPixSize)
3154
+ if self.app: self.app.setFont(font)
3155
+ setFontPixelSize(self,fPixSize)
3156
+ self.setFurtherFontPixelSizes(fPixSize)
3157
+ if self.aboutDialog:
3158
+ self.aboutDialog.fontPixelSize=self.GPApar.fontPixelSize
3159
+ self.aboutDialog.setFontSizeText()
3160
+ if self.logChanges: self.logChanges.setFontPixelSize(fPixSize)
3161
+ if self.menuDebug: self.menuDebug.setFont(self.ui.menuFile.font())
3162
+ self.fontPixelSize=fPixSize
3163
+
3164
+ def setFurtherFontPixelSizes(self,fPixSize):
3165
+ self.setTabFontPixelSize(fPixSize)
3166
+
3167
+ lab:QLabel=self.ui.title
3168
+ fPixSize_TabNames=min([fPixSize*2,30])
3169
+ font=lab.font()
3170
+ font.setFamily(fontName)
3171
+ font.setPixelSize(fPixSize_TabNames)
3172
+ lab.setFont(font)
3173
+ self.ui.title_workspace.setFont(font)
3174
+
3175
+ lab:QLabel=self.ui.subtitle
3176
+ font=lab.font()
3177
+ font.setFamily(fontName)
3178
+ font.setPixelSize(fPixSize+4)
3179
+ lab.setFont(font)
3180
+ self.ui.subtitle_workspace.setFont(font)
3181
+
3182
+ lab:QLabel=self.onlyReadLabel
3183
+ font=lab.font()
3184
+ font.setFamily(fontName)
3185
+ font.setPixelSize(fPixSize+1)
3186
+ lab.setFont(font)
3187
+
3188
+ self.ui.projectPage.setFontPixelSize(fPixSize)
3189
+ self.ui.processPage.setFontPixelSize(fPixSize)
3190
+ self.ui.stepPage.setFontPixelSize(fPixSize)
3191
+
3192
+ self.w_Log.setLogFont(fontPixelSize-dfontLog)
3193
+ self.w_Vis_CalVi.setLogFont(fontPixelSize-dfontLog)
3194
+
3195
+ def setTabFontPixelSize(self,fPixSize):
3196
+ fPixSize_TabNames=min([fPixSize*2,30])
3197
+ for w in self.ui.tabAreaWidget.widgets:
3198
+ setFontPixelSize(w,fPixSize)
3199
+ w:gPaIRS_Tab
3200
+ for lab in w.findChildren(QLabel):
3201
+ lab:QLabel
3202
+ if 'name_tab' in lab.objectName():
3203
+ #lab:QLabel=w.ui.name_tab
3204
+ font=lab.font()
3205
+ font.setPixelSize(fPixSize_TabNames)
3206
+ lab.setFont(font)
3207
+
3208
+ def falseShow(self):
3209
+ FlagHidden=not self.isVisible()
3210
+ total_rect = QGuiApplication.primaryScreen().geometry()
3211
+ for screen in QGuiApplication.screens():
3212
+ total_rect = total_rect.united(screen.geometry())
3213
+ self.move(total_rect.right() + 100, total_rect.bottom() + 100)
3214
+ self.updateGeometry()
3215
+ self.show()
3216
+ self.repaint()
3217
+ return FlagHidden
3218
+
3219
+ def setDefaultSizes(self):
3220
+ margins=self.ui.centralLayout.contentsMargins()
3221
+ main_splitter_sizes=[self.ui.w_Managing_Tabs.baseSize().width(),self.ui.tabAreaWidget.widgetMinimumWidth*2+self.ui.tabAreaWidget.margin*2+self.ui.tabAreaWidget.handleWidth*2] #processTree, main_sep, tabAreaWidget
3222
+ w=margins.left()+self.ui.main_splitter.handleWidth()*2+sum(main_splitter_sizes)+margins.right()
3223
+ h=margins.top()+self.ui.w_header.minimumHeight()+self.ui.tabAreaWidget.tabAreaHeight+self.ui.tabAreaWidget.buttonSize[1]+self.ui.tabAreaWidget.buttonSpacing+self.ui.tabAreaWidget.margin*2+self.ui.w_Operating_Tabs.layout().spacing()+self.ui.statusbar.minimumHeight()+margins.bottom()
3224
+ self.resize(w,h)
3225
+ self.ui.main_splitter.setSizes(main_splitter_sizes)
3226
+ self.updateGeometry()
3227
+ x=(self.maximumGeometry.width()-w)*0.5
3228
+ y=(self.maximumGeometry.height()-h)*0.5
3229
+ if self.falseShow(): self.hide()
3230
+ self.move(x,y)
3231
+ self.app.processEvents()
3232
+ self.updateGPAparGeometry()
3233
+
3234
+ def setGPaIRSTitle(self):
3235
+ cfgString=f': {self.GPApar.outName}' if self.GPApar.outName and self.GPApar.outName!=lastcfgname else ''
3236
+ if not self.GPApar.FlagSaved: cfgString+='*'
3237
+ if Flag_DEBUG:#TA per non incasinarmi
3238
+ windowTitle=f'PaIRS (v{version}.{__subversion__} - {__date__}) -- cfg v{uicfg_version} -- PIV {self.PIVvers} -- {platform.system()} -- Python {platform.python_version()}'
3239
+ else:
3240
+ windowTitle=f'PaIRS (v{version})'
3241
+ windowTitle+=cfgString
3242
+ self.setWindowTitle(windowTitle)
3243
+
3244
+ #*************************************************** Menus
3245
+ #********************* File
3246
+ def setGPAlayout(self):
3247
+ self.setFontPixelSize()
3248
+ self.setGPaIRSPalette()
3249
+
3250
+ geometry=QByteArray.fromBase64(self.GPApar.Geometry.encode())
3251
+ self.restoreGeometry(geometry)
3252
+ #if isinstance(self.GPApar.Geometry,list) and len(self.GPApar.Geometry)==4:
3253
+ # g=self.GPApar.Geometry
3254
+ # try:
3255
+ # self.setGeometry(g[0],g[1],g[2],g[3])
3256
+ # except:
3257
+ # pri.Info.yellow(f'Error while restoring geometry:\n{traceback.format_exc()}\n\nDefault sizes will be set!\n\n')
3258
+ # self.setDefaultSizes()
3259
+ #else:
3260
+ # self.setDefaultSizes()
3261
+
3262
+ windowState = QByteArray.fromBase64(self.GPApar.WindowState.encode())
3263
+ self.restoreState(windowState)
3264
+ #try:
3265
+ # s=self.GPApar.WindowState
3266
+ # self.setWindowState(Qt.WindowState(s[0]))
3267
+ #except:
3268
+ # pri.Info.yellow(f'Error while restoring window state:\n{traceback.format_exc()}\n\nDefault window state will be set!\n\n')
3269
+
3270
+ for s in self.ui.Explorer.findChildren(QSplitter)+[self.ui.main_splitter,self.ui.Operating_Tabs_splitter]:
3271
+ s:QSplitter
3272
+ if s.objectName() in self.GPApar.SplitterSizes:
3273
+ s.setSizes(self.GPApar.SplitterSizes[s.objectName()])
3274
+ for a in self.ui.Explorer.findChildren(QScrollArea):
3275
+ a:QScrollArea
3276
+ if a.objectName() in self.GPApar.ScrollAreaValues:
3277
+ scrollAreaValues=self.GPApar.ScrollAreaValues[a.objectName()]
3278
+ a.horizontalScrollBar().setValue(scrollAreaValues[0])
3279
+ a.verticalScrollBar().setValue(scrollAreaValues[1])
3280
+ self.setNumCores()
3281
+ for w in self.tabWidgets[:-1]:
3282
+ w:gPaIRS_Tab
3283
+ if w.TABname in self.GPApar.globalVals:
3284
+ exceptions=self.GPApar.globalExceptions[w.TABname] if w.TABname in self.GPApar.globalExceptions else []
3285
+ w.syncPrevGlobalFields(ref_vals=self.GPApar.globalVals[w.TABname],exceptions=exceptions)
3286
+
3287
+ def setNumCores(self):
3288
+ if self.GPApar.NumCores >NUMTHREADS_MAX:
3289
+ self.GPApar.NumCores=NUMTHREADS_MAX
3290
+ self.numTotUsedThreads=self.GPApar.NumCores
3291
+ self.ui.spin_nworkers.setValue(self.GPApar.NumCores)
3292
+
3293
+ def modifyWorkspace(self):
3294
+ self.GPApar.modifiedDate=currentTimeString()
3295
+ self.GPApar.date=f'Modified : {self.GPApar.modifiedDate}'
3296
+ self.GPApar.FlagSaved=False
3297
+
3298
+ def new_workspace(self):
3299
+ filename=self.saveas_current_structure(name='workspace',ext=outExt.wksp,saveList=lambda f: self.save_current_workspace(f),par=self.GPApar,FlagSave=False)
3300
+ self.GPApar.copyfrom(GPApar(),exceptions=self.GPApar.stateFields)
3301
+ self.GPApar.outName=filename
3302
+ self.GPApar.createdDate=currentTimeString()
3303
+ self.GPApar.modifiedDate=self.GPApar.createdDate
3304
+ self.GPApar.date=f'Modified : {self.GPApar.modifiedDate}'
3305
+ self.projectTree.clean_workspace()
3306
+ self.adjustProjectSelection()
3307
+
3308
+ def new_workspace_debug(self):
3309
+ self.GPApar.copyfrom(GPApar(),exceptions=self.GPApar.stateFields)
3310
+ self.projectTree.clean_workspace()
3311
+ self.adjustProjectSelection()
3312
+
3313
+ def menu_new_action(self):
3314
+ taskDescription='creating a new workspace'
3315
+ if not self.GPApar.FlagSaved:
3316
+ if self.questionDialog(f'The current workspace is unsaved. Do you want to save it before {taskDescription}?'):
3317
+ self.menu_save_action()
3318
+ self.pauseQuestion(taskDescription,self.new_workspace,FlagFirstQuestion=True)
3319
+
3320
+ def open_workspace(self,filename='',FlagSetGeometry=False):
3321
+ pri.Time.cyan('Open workspace: init')
3322
+ if filename=='':
3323
+ filename, _ = QFileDialog.getOpenFileName(self,\
3324
+ "Select a PaIRS workspace file", filter=f'*{outExt.wksp}',\
3325
+ #dir=self.w_Input.INPpar.path,\
3326
+ options=optionNativeDialog)
3327
+ if not filename: return
3328
+ waitingWindow=warningDialog(self,'Please, wait while retrieving previous workspace!\n(If this action takes too much time, please consider to close the workspace before quitting PaIRS next time.)',pixmap=''+ icons_path +'sandglass.png',flagNoButtons=True,flagScreenCenter=True)
3329
+ self.app.processEvents()
3330
+ errorString=''
3331
+ try:
3332
+ data, errorMessage=loadList(filename)
3333
+ errorString+=errorMessage
3334
+ pri.Time.cyan('Open workspace: load')
3335
+ except:
3336
+ errorString+=traceback.format_exc()
3337
+ if errorString:
3338
+ WarningMessage=f'Error with loading the file: {filename}\n'
3339
+ warningDialog(self,WarningMessage)
3340
+ pri.Error.red(f'{WarningMessage}\n{errorString}\n')
3341
+ try:
3342
+ self.projectTree.clean_action()
3343
+ #all_indexes=[i for i in range(len(data[2]))]
3344
+ insert_at_depth(self.projectTree.itemList,self.projectTree.listDepth,0,data[2])
3345
+ self.checkProcesses()
3346
+ self.ui.Explorer.ITEpar.FlagInit=False
3347
+ for _ in range(len(self.projectTree.itemList[0])):
3348
+ self.projectTree.createProjectItem(FlagNewItem=False)
3349
+ """
3350
+ item=self.projectTree.topLevelItem(0)
3351
+ self.projectTree.setCurrentItem(item)
3352
+ item.setSelected(True)
3353
+ """
3354
+ self.GPApar.copyfrom(data[0])
3355
+ self.TREpar.copyfrom(data[1])
3356
+
3357
+ #FlagHidden=not self.isVisible()
3358
+ #if FlagHidden:
3359
+ # self.move(0, -1e6) #todo: capire come aggiornare la geometria senza lo show
3360
+ # self.show()
3361
+ pri.Time.cyan('Open workspace: set data')
3362
+ #self.TREpar.step=None
3363
+ #FlagShown=self.falseShow()
3364
+ if FlagSetGeometry: self.setGPAlayout()
3365
+ self.adjustProjectSelection()
3366
+ #if FlagShown: self.hide()
3367
+ pri.Time.cyan('Open workspace: selection')
3368
+ pri.Time.cyan('Open workspace: geometry (end)')
3369
+ except Exception as inst:
3370
+ if filename==lastcfgname:
3371
+ WarningMessage='Error with loading the last configuration file.\n'
3372
+ os.remove(lastcfgname)
3373
+ else:
3374
+ WarningMessage=f'Error while retrieving the workspace "{data[0].name}" from the file: {filename}\n'
3375
+ warningDialog(self,WarningMessage)
3376
+ pri.Error.red(f'{WarningMessage}\n{traceback.format_exc()}\n')
3377
+ self.new_workspace_debug()
3378
+ self.setGPAlayout()
3379
+ return waitingWindow.done(0)
3380
+
3381
+ def menu_open_action(self):
3382
+ taskDescription='loading a previous workspace'
3383
+ if not self.GPApar.FlagSaved:
3384
+ if self.questionDialog(f'The current workspace is unsaved. Do you want to save it before {taskDescription}?'):
3385
+ self.menu_save_action()
3386
+ self.pauseQuestion(taskDescription,self.open_workspace,FlagFirstQuestion=True)
3387
+
3388
+ def save_current_workspace(self,filename,FlagAdjustHeader=True):
3389
+ self.updateGPAparGeometry()
3390
+ if filename!=lastcfgname:
3391
+ if not self.GPApar.outName:
3392
+ self.GPApar.name=os.path.splitext(os.path.basename(filename))[0]
3393
+ self.GPApar.outName=filename
3394
+ self.GPApar.savedDate=currentTimeString()
3395
+ self.GPApar.FlagSaved=True
3396
+ Workspace=[self.GPApar.duplicate(),self.TREpar.duplicate(),self.projectTree.itemList]
3397
+ try:
3398
+ saveList(Workspace,filename)
3399
+ except Exception as inst:
3400
+ warningDialog(self,f'Error while saving the file {filename}!\nPlease, retry.')
3401
+ pri.Error.red(f'Error while saving the file {filename}!\n{inst}')
3402
+ else:
3403
+ if FlagAdjustHeader: self.adjustWorkspaceHeader()
3404
+ FlagSaved=True
3405
+ return FlagSaved
3406
+
3407
+ def save_last_workspace(self):
3408
+ self.save_current_workspace(lastcfgname,FlagAdjustHeader=False)
3409
+ pri.Info.white(f' >>>>> Saving last ui configuration to file:\t{lastcfgname}')
3410
+
3411
+ def saveas_current_workspace(self):
3412
+ self.saveas_current_structure(name='workspace',ext=outExt.wksp,saveList=lambda f: self.save_current_workspace(f),par=self.GPApar)
3413
+
3414
+ def menu_save_action(self):
3415
+ if self.GPApar.outName:
3416
+ filename=self.GPApar.outName
3417
+ self.pauseQuestion('saving the current workspace',lambda: self.save_current_workspace(filename),FlagFirstQuestion=False)
3418
+ else:
3419
+ self.menu_saveas_action()
3420
+ return False
3421
+
3422
+ def menu_saveas_action(self):
3423
+ self.pauseQuestion('saving the current workspace',self.saveas_current_workspace,FlagFirstQuestion=False)
3424
+ return False
3425
+
3426
+ def close_workspace(self):
3427
+ self.GPApar.copyfrom(GPApar(),exceptions=self.GPApar.stateFields)
3428
+ self.projectTree.clean_workspace()
3429
+
3430
+ def menu_close_action(self):
3431
+ taskDescription='closing the current workspace'
3432
+ if not self.GPApar.FlagSaved:
3433
+ if self.questionDialog(f'The current workspace is unsaved. Do you want to save it before {taskDescription}?'):
3434
+ self.menu_save_action()
3435
+ self.pauseQuestion(taskDescription,self.close_workspace,FlagFirstQuestion=True)
3436
+
3437
+ #********************* Help
3438
+ def guide(self):
3439
+ #url = QUrl("http://wpage.unina.it/etfd/PaIRS/PaIRS-UniNa-Guide.pdf")
3440
+ url = QUrl("https://www.pairs.unina.it/web/PaIRS-UniNa-v020-Guide.pdf")
3441
+ QDesktopServices.openUrl(url)
3442
+
3443
+ def downloadApp(self):
3444
+ #url = QUrl("http://wpage.unina.it/etfd/PaIRS/PaIRS-UniNa-Guide.pdf")
3445
+ url = QUrl(EXEurl)
3446
+ QDesktopServices.openUrl(url)
3447
+
3448
+ def about(self):
3449
+ if self.aboutDialog:
3450
+ self.aboutDialog.hide()
3451
+ self.aboutDialog.show()
3452
+ else:
3453
+ self.aboutDialog=infoPaIRS(self)
3454
+ self.aboutDialog.show()
3455
+
3456
+ #********************* Debug
3457
+ def addDebugMenu(self):
3458
+ global Flag_fullDEBUG, pri
3459
+ menubar=self.ui.menubar
3460
+ self.menuDebug=menubar.addMenu("Debug")
3461
+
3462
+ #--------------------------- new ui cfg
3463
+ self.menuDebug.addSeparator()
3464
+ self.ui.aNew = self.menuDebug.addAction("New")
3465
+ self.ui.aNew.triggered.connect(self.new_workspace_debug)
3466
+
3467
+ #--------------------------- last ui cfg
3468
+ self.menuDebug.addSeparator()
3469
+ self.ui.aSaveLastCfg = self.menuDebug.addAction("Save lastWorkspace"+outExt.cfg)
3470
+ self.ui.aSaveLastCfg.triggered.connect(self.save_last_workspace)
3471
+
3472
+ self.ui.aDeleteLastCfg = self.menuDebug.addAction("Delete lastWorkspace"+outExt.cfg)
3473
+ def delete_lastcfg():
3474
+ if os.path.exists(lastcfgname):
3475
+ os.remove(lastcfgname)
3476
+ pri.Info.white(f' xxxxx Deleting last ui configuration file:\t{lastcfgname}')
3477
+ else:
3478
+ pri.Info.white(f' xxxxx Last ui configuration file:\t{lastcfgname}\t already deleted!')
3479
+ self.delete_lastcfg=delete_lastcfg
3480
+ self.ui.aDeleteLastCfg.triggered.connect(delete_lastcfg)
3481
+
3482
+ self.ui.aReloadLastCfg = self.menuDebug.addAction("Reload lastWorkspace"+outExt.cfg)
3483
+ def reloadLastCfg():
3484
+ if os.path.exists(lastcfgname): self.initialize()
3485
+ else: self.new_workspace_debug()
3486
+ self.ui.aReloadLastCfg.triggered.connect(reloadLastCfg)
3487
+
3488
+ #--------------------------- printings
3489
+ self.menuDebug.addSeparator()
3490
+ self.ui.printMenu=self.menuDebug.addMenu('Print')
3491
+ printTypes_list=list(self.GPApar.printTypes)
3492
+ printActions=[]
3493
+ printCallbacks=[]
3494
+ def setPrint(name,act,k):
3495
+ flag=act.isChecked()
3496
+ self.GPApar.printTypes[name]=flag
3497
+ flagTime=getattr(getattr(pri,name),'flagTime')
3498
+ faceStd=getattr(getattr(pri,name),'faceStd')
3499
+ if flag:
3500
+ setattr(pri,name,ColorPrint(flagTime=flagTime,prio=PrintTAPriority.medium,faceStd=faceStd))
3501
+ else:
3502
+ setattr(pri,name,ColorPrint(flagTime=flagTime,prio=PrintTAPriority.never,faceStd=faceStd))
3503
+ #print(f'{name} {flag}')
3504
+ #pri.Callback.white(f'pri.Callback.white(): setPrint')
3505
+ return
3506
+ def genCallback(name,act,k):
3507
+ n=name
3508
+ a=act
3509
+ j=k
3510
+ def callback():
3511
+ setPrint(n,a,j)
3512
+ self.menuDebug.popup(self.menuDebug.pos())
3513
+ self.ui.printMenu.exec_()
3514
+ return callback
3515
+ for k,name in enumerate(printTypes_list):
3516
+ if not hasattr(pri,name): continue
3517
+ flagFullDebug=getattr(getattr(pri,name),'flagFullDebug')
3518
+ if flagFullDebug and not Flag_fullDEBUG: continue
3519
+ act=self.ui.printMenu.addAction(name)
3520
+ printActions.append(act)
3521
+ act.setCheckable(True)
3522
+ flag=self.GPApar.printTypes[name]
3523
+ act.setChecked(flag)
3524
+ setPrint(name,act,k)
3525
+ printCallbacks.append(genCallback(name,act,k))
3526
+ act.triggered.connect(printCallbacks[-1])
3527
+ self.ui.printMenu.addSeparator()
3528
+ allPrintsAct=self.ui.printMenu.addAction('All printings')
3529
+ allPrintsAct.setCheckable(True)
3530
+ def setAllPrints():
3531
+ flag=allPrintsAct.isChecked()
3532
+ for a in printActions:
3533
+ a:QAction
3534
+ a.setChecked(flag)
3535
+ setPrint(a.text(),a,None)
3536
+ self.menuDebug.popup(self.menuDebug.pos())
3537
+ self.ui.printMenu.exec_()
3538
+ return
3539
+ allPrintsAct.triggered.connect(setAllPrints)
3540
+
3541
+ #--------------------------- operation
3542
+ if Flag_fullDEBUG:
3543
+ self.menuDebug.addSeparator()
3544
+ self.ui.simpleFor = self.menuDebug.addAction("Dummy it will be change after")
3545
+ def changeFlagSingleFor():
3546
+ self.flagSimpleFor=not self.flagSimpleFor
3547
+ if self.flagSimpleFor:
3548
+ self.ui.simpleFor.setText("reactivate multi processor")
3549
+ else:
3550
+ self.ui.simpleFor.setText("Simple For (no Multi processor usefull to debug c code)")
3551
+ self.flagSimpleFor=not self.flagSimpleFor
3552
+ changeFlagSingleFor()
3553
+ self.ui.simpleFor.triggered.connect(changeFlagSingleFor)
3554
+
3555
+ self.menuDebug.addSeparator()
3556
+ self.ui.aShowDownload = self.menuDebug.addAction("Show/hide download button")
3557
+ def aShowDownload():
3558
+ self.ui.button_PaIRS_download.setVisible(not self.ui.button_PaIRS_download.isVisible())
3559
+ self.ui.aShowDownload.triggered.connect(aShowDownload)
3560
+
3561
+ self.ui.aBetaDownload = self.menuDebug.addAction("Change download button icon")
3562
+ def aBetaDownload():
3563
+ b=self.ui.button_PaIRS_download
3564
+ if b.icon().pixmap(b.size()).toImage()==self.flaticon_PaIRS_download.pixmap(b.size()).toImage():
3565
+ b.setIcon(self.flaticon_PaIRS_beta)
3566
+ else:
3567
+ b.setIcon(self.flaticon_PaIRS_download)
3568
+ self.ui.aBetaDownload.triggered.connect(aBetaDownload)
3569
+
3570
+ self.ui.aResetFlagOutDated = self.menuDebug.addAction("Reset FlagOutDated")
3571
+ def aResetFlagOutDated():
3572
+ self.GPApar.FlagOutDated=0 if self.GPApar.currentVersion==self.GPApar.latestVersion else 1 if self.GPApar.FlagOutDated>0 else -1
3573
+ packageName='PaIRS-UniNa'
3574
+ currentVersion=self.GPApar.currentVersion
3575
+ latestVersion=self.GPApar.latestVersion
3576
+ if self.GPApar.FlagOutDated==1:
3577
+ sOut=f'{packageName} the current version ({currentVersion}) of {packageName} is obsolete! Please, install the latest version: {latestVersion} by using:\npython -m pip install --upgrade {packageName}'
3578
+ elif self.GPApar.FlagOutDated==1:
3579
+ sOut=f'The version of the current instance of {packageName} ({currentVersion}) is newer than the latest official releas ({latestVersion})!\nYou should contact Tommaso and Gerardo if you are a developer and some relevant change is made by yourself!\nIf you are a user, enjoy this beta version and please report any issue!'
3580
+ else:
3581
+ sOut=f'{packageName} The current version ({currentVersion}) of {packageName} is up-to-date! Enjoy it!'
3582
+ pri.Info.yellow(f'[{self.GPApar.FlagOutDated}] '+sOut)
3583
+ self.ui.aResetFlagOutDated.triggered.connect(aResetFlagOutDated)
3584
+
3585
+ self.ui.aCheckOutDated = self.menuDebug.addAction("Check for new packages")
3586
+ def aCheckOutDated():
3587
+ self.GPApar.FlagOutDated=0
3588
+ self.ui.button_PaIRS_download.hide()
3589
+ checkLatestVersion(self,__version__,self.app,splash=None)
3590
+ self.ui.aCheckOutDated.triggered.connect(aCheckOutDated)
3591
+
3592
+ self.menuDebug.addSeparator()
3593
+ self.ui.aResetWhatsNew = self.menuDebug.addAction("Reset whatsnew.txt")
3594
+ def aResetWhatsNew():
3595
+ if os.path.exists(fileWhatsNew[1]):
3596
+ try:
3597
+ os.rename(fileWhatsNew[1],fileWhatsNew[0])
3598
+ except Exception as inst:
3599
+ pri.Error.red(f'There was a problem while renaming the file {fileWhatsNew[1]}:\n{inst}')
3600
+ self.ui.aResetWhatsNew.triggered.connect(aResetWhatsNew)
3601
+
3602
+ self.ui.aShowWhatsNew = self.menuDebug.addAction("Show What's new window")
3603
+ def aShowWhatsNew():
3604
+ self.whatsNew()
3605
+ self.ui.aShowWhatsNew.triggered.connect(aShowWhatsNew)
3606
+
3607
+ self.menuDebug.addSeparator()
3608
+ self.ui.aKill = self.menuDebug.addAction("Stop processes and close")
3609
+ def aKill():
3610
+ self.FlagClosing[0]=True
3611
+ self.signals.killOrResetParForWorker.emit(True)
3612
+ self.aKill=aKill
3613
+ self.ui.aKill.triggered.connect(aKill)
3614
+
3615
+ self.ui.aFocusWid = self.menuDebug.addAction("Print widget with focus")
3616
+ def aFocusWid():
3617
+ pri.Info.yellow(f"The widget with focus is: {self.focusWidget()}")
3618
+ self.aCheckConnections=aFocusWid
3619
+ self.ui.aFocusWid.triggered.connect(aFocusWid)
3620
+
3621
+ if not Flag_ISEXE:
3622
+ self.menuDebug.addSeparator()
3623
+ self.ui.aResetRequiredPackagesFile = self.menuDebug.addAction("Reset rqrdpckgs.txt file")
3624
+ def aResetRequiredPackagesFile():
3625
+ resetRequiredPackagesFile()
3626
+ self.ui.aResetRequiredPackagesFile.triggered.connect(aResetRequiredPackagesFile)
3627
+
3628
+ self.ui.aCheckRequiredPackages = self.menuDebug.addAction("Requirements' version check")
3629
+ def aCheckRequiredPackages():
3630
+ checkRequiredPackages(self,FlagDisplay=True)
3631
+ self.ui.aCheckRequiredPackages.triggered.connect(aCheckRequiredPackages)
3632
+
3633
+ self.ui.aShowPackIssue = self.menuDebug.addAction("Show/hide version check button")
3634
+ def aShowPackIssue():
3635
+ self.FlagPackIssue=not self.FlagPackIssue
3636
+ self.ui.button_packissue.setVisible(self.FlagPackIssue)
3637
+ self.ui.aShowPackIssue.triggered.connect(aShowPackIssue)
3638
+
3639
+ self.ui.aTryCheckRequiredPackages = self.menuDebug.addAction("Try requirements' version check")
3640
+ def aTryCheckRequiredPackages():
3641
+ checkRequiredPackages(self,FlagDisplay=True,FlagForcePrint=True)
3642
+ self.ui.aTryCheckRequiredPackages.triggered.connect(aTryCheckRequiredPackages)
3643
+
3644
+ #--------------------------- graphics
3645
+ if Flag_fullDEBUG:
3646
+ self.menuDebug.addSeparator()
3647
+
3648
+ self.ui.aDefSizes = self.menuDebug.addAction("Set default sizes")
3649
+ self.ui.aDefSizes.triggered.connect(self.setDefaultSizes)
3650
+
3651
+ self.ui.aUndock = self.menuDebug.addAction("Undock a widget")
3652
+ self.ui.aUndock.triggered.connect(self.extractWidget)
3653
+
3654
+ self.ui.aLogo = self.menuDebug.addAction("Change PaIRS logo")
3655
+ self.ui.aLogo.triggered.connect(self.happyLogo)
3656
+
3657
+ self.ui.aGifs = self.menuDebug.addAction("Show/hide gifs")
3658
+ def showGifs():
3659
+ flag=not self.ui.label_updating_import.isVisible()
3660
+ self.ui.label_updating_import.setVisible(flag)
3661
+ self.ui.label_updating_pairs.setVisible(flag)
3662
+ self.ui.aGifs.triggered.connect(showGifs)
3663
+
3664
+ #--------------------------- exit
3665
+ self.menuDebug.addSeparator()
3666
+
3667
+ self.ui.aExitDebug = self.menuDebug.addAction("Exit debug mode")
3668
+ self.ui.aExitDebug.triggered.connect(lambda:self.setDebugMode(False))
3669
+
3670
+ def extractWidget(self):
3671
+ title="Undock a widget"
3672
+ label="Enter the widget name:"
3673
+ words = ["self.w_Input",
3674
+ "self.w_Input.ui.CollapBox_ImSet",
3675
+ "self.w_Output",
3676
+ "self.w_Process",
3677
+ "self.w_Process.ui.CollapBox_IntWind",
3678
+ "self.w_Process.ui.CollapBox_FinIt",
3679
+ "self.w_Process.ui.CollapBox_top",
3680
+ "self.w_Process.ui.CollapBox_Interp",
3681
+ "self.w_Process.ui.CollapBox_Validation",
3682
+ "self.w_Process.ui.CollapBox_Windowing",
3683
+ "self.w_Vis", "self.w_Vis.ui.CollapBox_PlotTools",
3684
+ "self.w_Process", "self.w_Log",
3685
+ "self.w_Process_Min","self.w_Process_Disp",
3686
+ "self.w_Calibration",
3687
+ "self.w_Input_CalVi", "self.w_Process_CalVi", "self.w_Vis_CalVi",
3688
+ "self.ui.w_Managing_Tabs",
3689
+ ]
3690
+
3691
+ ok,text=inputDialog(self,title,label,completer_list=words,width=500)
3692
+ if ok:
3693
+ try:
3694
+ ts=text.split('.')
3695
+ parent=".".join(ts[:-1])
3696
+ child=ts[-1]
3697
+ tab=getattr(eval(parent),child)
3698
+ self.FloatingWindows.append(FloatingWidget(self,tab))
3699
+ pass
3700
+ except Exception as inst:
3701
+ pri.Error.red(f'Error while undocking the widget <{tab}>\n{inst}')
3702
+ pass
3703
+
3704
+ def userDebugMode(self):
3705
+ if not Flag_DEBUG:
3706
+ self.inputDebugMode()
3707
+ else:
3708
+ self.setDebugMode(False)
3709
+
3710
+ def inputDebugMode(self):
3711
+ _,text=inputDialog(self,'Debug','Insert password for debug mode:',width=300,flagScreenCenter=not self.isVisible())
3712
+ if text==pwddbg:
3713
+ self.setDebugMode(True)
3714
+ else:
3715
+ warningDialog(self,'Password for debug mode is wrong!\nPaIRS will stay in normal mode.',time_milliseconds=5000)
3716
+ self.setDebugMode(False)
3717
+
3718
+ def setDebugMode(self,Flag):
3719
+ global Flag_DEBUG
3720
+ Flag_DEBUG=Flag
3721
+ activateFlagDebug(Flag_DEBUG)
3722
+ self.setGPaIRSTitle()
3723
+ self.menuDebug.menuAction().setVisible(Flag)
3724
+
3725
+ def setButtonDownload(self,):
3726
+ self.ui.button_PaIRS_download.setVisible(self.GPApar.FlagOutDated!=0)
3727
+ if self.GPApar.FlagOutDated>0:
3728
+ self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_download)
3729
+ self.ui.button_PaIRS_download.setToolTip("Download the latest version of PaIRS-UniNa.")
3730
+ elif self.GPApar.FlagOutDated==-1000:
3731
+ self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_download_warning)
3732
+ self.ui.button_PaIRS_download.setToolTip("Issue with verifying the latest release!")
3733
+ else:
3734
+ self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_beta)
3735
+ self.ui.button_PaIRS_download.setToolTip("A beta version is currently used!")
3736
+ self.ui.button_PaIRS_download.setStatusTip(self.ui.button_PaIRS_download.toolTip())
3737
+
3738
+ #*************************************************** Greetings
3739
+ def setupLogo(self):
3740
+ today = datetime.date.today()
3741
+ d=today.strftime("%d/%m/%Y")
3742
+ happy_days=[
3743
+ #[d, 'Happy birthday to PaIRS! 🎈🎂🍾'], #to test
3744
+ ['20/12/1991', 'Happy birthday to Gerardo! 🎈🎂🍾'],
3745
+ ['05/02/1969', 'Happy birthday to Tommaso! 🎈🎂🍾'],
3746
+ ['11/07/1987', 'Happy birthday to Carlo! 🎈🎂🍾'],
3747
+ ['19/09/1963', 'Happy birthday to Gennaro! 🎈🎂🍾'],
3748
+ ['27/11/1940', 'Happy birthday to prof. Carlomagno! 🎈🎂🍾'],
3749
+ ['01/12/1969', 'Happy birthday to Giuseppe S.! 🎈🎂🍾'],
3750
+ ['28/02/1981', 'Happy birthday to Rosaria! 🎈🎂🍾'],
3751
+ ['18/10/1985', 'Happy birthday to Stefano! 🎈🎂🍾'],
3752
+ ['13/08/1985', 'Happy birthday to Andrea! 🎈🎂🍾'],
3753
+ ['22/12/1988', 'Happy birthday to Jack! 🎈🎂🍾'],
3754
+ ['03/09/1991', 'Happy birthday to Giusy! 🎈🎂🍾'],
3755
+ ['03/11/1989', 'Happy birthday to Massimo! 🎈🎂🍾'],
3756
+ ['15/06/1991', 'Happy birthday to Mattia! 🎈🎂🍾'],
3757
+ ['14/07/1993', 'Happy birthday to Mirko! 🎈🎂🍾'],
3758
+ ['13/03/1997', 'Happy birthday to Giosuè! 🎈🎂🍾'],
3759
+ ['24/09/1998', 'Happy birthday to Piergiorgio! 🎈🎂🍾'],
3760
+ ['15/01/1999', 'Happy birthday to Alessandro! 🎈🎂🍾'],
3761
+ ['20/02/1999', 'Happy birthday to Cristina! 🎈🎂🍾'],
3762
+ ['20/09/2000', 'Happy birthday to Antonio M.! 🎈🎂🍾'],
3763
+ ['21/09/2000', 'Happy birthday to Gabriele! 🎈🎂🍾'],
3764
+ ['16/11/2000', 'Happy birthday to Antonio D.! 🎈🎂🍾'],
3765
+ ['01/01', 'Happy New Year! 🎊🧨'],
3766
+ ['25/12', 'Merry Christmas! 🎄✨'],
3767
+ ['31/10', 'Happy Halloween! 🎃👻'],
3768
+ ['22/06', 'Hello, Summer! 🌞🌊'],
3769
+ ]
3770
+
3771
+ i=-1
3772
+ for j,l in enumerate(happy_days):
3773
+ if l[0][:6]==d[:6]:
3774
+ i=j
3775
+ break
3776
+
3777
+ if i>-1:
3778
+ self.FlagHappyLogo=True
3779
+ self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_party_rect.png"))
3780
+ self.ui.lab_happy_days.show()
3781
+ self.ui.lab_happy_days.setText(happy_days[i][1])
3782
+ else:
3783
+ self.FlagHappyLogo=False
3784
+ self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_rect.png"))
3785
+ self.ui.lab_happy_days.hide()
3786
+
3787
+ def startHappyLogoWatcher(self):
3788
+ """Re-check date at next midnight and periodically as keep-alive."""
3789
+ # one-shot timer to just-after-midnight (00:01)
3790
+ def _schedule_midnight():
3791
+ now=QDateTime.currentDateTime()
3792
+ next_day = now.date().addDays(1)
3793
+ next_midnight = QDateTime(next_day, QTime(0, 0))
3794
+ msec=now.msecsTo(next_midnight.addSecs(60)) # 00:01
3795
+ if msec<60_000: msec=60_000 # safety minimum
3796
+ self._happy_midnight=QTimer(self)
3797
+ self._happy_midnight.setSingleShot(True)
3798
+ self._happy_midnight.timeout.connect(_on_tick)
3799
+ self._happy_midnight.start(msec)
3800
+
3801
+ def _on_tick():
3802
+ # Re-apply logo state and reschedule
3803
+ self.setupLogo()
3804
+ _schedule_midnight()
3805
+
3806
+ # keep-alive each few hours (handles sleep/wake or clock drift)
3807
+ self._happy_keepalive=QTimer(self)
3808
+ self._happy_keepalive.setInterval(3*60*60*1000) # 3h
3809
+ self._happy_keepalive.timeout.connect(self.setupLogo)
3810
+ self._happy_keepalive.start()
3811
+
3812
+ # initial schedule
3813
+ _schedule_midnight()
3814
+
3815
+ def happyLogo(self):
3816
+ self.FlagHappyLogo=not self.FlagHappyLogo
3817
+ if self.FlagHappyLogo:
3818
+ self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_party_rect.png"))
3819
+ self.ui.lab_happy_days.show()
3820
+ self.ui.lab_happy_days.setText('Greetings! Today is a great day! 🎈🎉')
3821
+ else:
3822
+ self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_rect.png"))
3823
+ self.ui.lab_happy_days.hide()
3824
+
3825
+ #*************************************************** Palette
3826
+ def setGPaIRSPalette(self):
3827
+ setAppGuiPalette(self,self.palettes[self.GPApar.paletteType])
3828
+
3829
+ def paletteContextMenuEvent(self, event):
3830
+ contextMenu = QMenu(self)
3831
+ act=[]
3832
+ for n in self.paletteNames:
3833
+ act.append(contextMenu.addAction(f"{n} mode"))
3834
+ act[self.GPApar.paletteType].setCheckable(True)
3835
+ act[self.GPApar.paletteType].setChecked(True)
3836
+ #userAct = contextMenu.exec(self.mapToGlobal(event.pos()))
3837
+ userAct = contextMenu.exec(self.ui.button_colormode.mapToGlobal(self.ui.button_colormode.rect().center()))
3838
+ for k,a in enumerate(act):
3839
+ if a==userAct:
3840
+ self.GPApar.paletteType=k
3841
+ self.setGPaIRSPalette()
3842
+
3843
+ def launchPaIRS(flagDebug=False,flagInputDebug=False):
3844
+ print('\n'+PaIRS_Header+'Starting the interface...')
3845
+ #QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True)
3846
+ app=PaIRSApp.instance()
3847
+ if not app:app = QApplication(sys.argv)
3848
+ app.setStyle('Fusion')
3849
+ font=QFont()
3850
+ font.setFamily(fontName)
3851
+ font.setPixelSize(fontPixelSize)
3852
+ app.setFont(font)
3853
+ app.pyicon=app.windowIcon()
3854
+ icon=QIcon()
3855
+ icon.addFile(''+ icons_path +'icon_PaIRS.png',QSize(), QIcon.Normal, QIcon.Off)
3856
+ app.setWindowIcon(icon)
3857
+ try:
3858
+ if (platform.system() == "Windows"):
3859
+ import ctypes
3860
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('PaIRS')
3861
+ except:
3862
+ pri.Info.red('It was not possible to set the application icon')
3863
+
3864
+ if not flagDebug or Flag_SHOWSPLASH:
3865
+ splash=showSplash()
3866
+ app.processEvents()
3867
+ else:
3868
+ splash=None
3869
+
3870
+ standardPalette=app.style().standardPalette()
3871
+ global Flag_fullDEBUG
3872
+ Flag_fullDEBUG=flagDebug
3873
+ for n in printTypes:
3874
+ p:ColorPrint=getattr(pri,n)
3875
+ if p.flagFullDebug and not Flag_fullDEBUG:
3876
+ p.prio=PrintTAPriority.never
3877
+ p.setPrints()
3878
+
3879
+ if FlagAddMotherBoard and Flag_fullDEBUG:
3880
+ pri.Info.yellow(f"{'-'*50}\nHi, developer!\nMaybe it could be useful for you to add the current computer identifier:\n{currentID}\nto the 'developerIDs' dictionary in PaIRS_pypacks.py!\n{'-'*50}\n")
3881
+
3882
+ if flagInputDebug:
3883
+ _,text=inputDialog(None,'Debug','Insert password for debug mode:',icon=icon,palette=standardPalette,width=300)
3884
+ flagDebug=text==pwddbg
3885
+ if not flagDebug:
3886
+ warningDialog(None,'Password for debug mode is wrong!\nPaIRS will be started in normal mode.',icon=icon,time_milliseconds=5000)
3887
+ gui=gPaIRS(flagDebug,app, standardPalette)
3888
+
3889
+ currentVersion=__version__ #if __subversion__=='0' else __version__+'.'+__subversion__
3890
+ flagStopAndDownload=checkLatestVersion(gui,currentVersion,app,splash)
3891
+ if flagStopAndDownload:
3892
+ gui.correctClose()
3893
+ runPaIRS(gui,flagQuestion=False)
3894
+ return [app,gui,False]
3895
+
3896
+ gui.splash=splash
3897
+ #warningDlg.setModal(True)
3898
+ if splash:
3899
+ splash.setWindowFlags(splash.windowFlags()|Qt.WindowStaysOnTopHint)
3900
+ splash.show()
3901
+ app.processEvents()
3902
+
3903
+ if splash:
3904
+ gui.ui.logo.hide()
3905
+ #gui.adjustGeometry()
3906
+ gui.show()
3907
+ gui.setFontPixelSize()
3908
+ if splash:
3909
+ splashAnimation(splash,gui.ui.logo)
3910
+ #QTimer.singleShot(time_showSplashOnTop,splash.hide)
3911
+ print('\nWelcome to PaIRS!\nEnjoy it!')
3912
+ if not getattr(sys, 'frozen', False): #made by pyInstaller
3913
+ checkRequiredPackages(gui)
3914
+ else:
3915
+ gui.FlagPackIssue=False
3916
+ gui.ui.button_packissue.setVisible(gui.FlagPackIssue)
3917
+ if os.path.exists(fileWhatsNew[0]): gui.whatsNew()
3918
+ app.exec()
3919
+ return [app,gui,True]
3920
+
3921
+ def splashAnimation(self:QLabel,logo:QLabel):
3922
+ margin=23
3923
+ ml=logo.width()/self.width()*margin
3924
+ wl=logo.width()+2*ml
3925
+ hl=wl/self.width()*self.height()
3926
+
3927
+ self.anim = QPropertyAnimation(self, b"pos")
3928
+ pos=logo.mapToGlobal(logo.geometry().topLeft())
3929
+ pos.setX(pos.x()-ml)
3930
+ self.anim.setEndValue(pos)
3931
+ self.anim.setDuration(time_showSplashOnTop)
3932
+ self.anim_2 = QPropertyAnimation(self, b"size")
3933
+
3934
+ self.anim_2.setEndValue(QSize(wl, hl))
3935
+ self.anim_2.setDuration(time_showSplashOnTop)
3936
+ self.anim_group = QParallelAnimationGroup()
3937
+ self.anim_group.addAnimation(self.anim)
3938
+ self.anim_group.addAnimation(self.anim_2)
3939
+ self.anim_group.finished.connect(self.hide)
3940
+ self.anim_group.finished.connect(logo.show)
3941
+ self.anim_group.start()
3942
+
3943
+ def quitPaIRS(app:QApplication,flagPrint=True):
3944
+ app.setWindowIcon(app.pyicon)
3945
+ app.quit()
3946
+ if flagPrint: print('\nPaIRS closed.\nSee you soon!')
3947
+ if hasattr(app,'SecondaryThreads'):
3948
+ if len(app.SecondaryThreads):
3949
+ while any([s.isRunning for s in app.SecondaryThreads]):
3950
+ timesleep(.1)
3951
+ pass
3952
+ app=None
3953
+ return
3954
+
3955
+ if __name__ == "__main__":
3956
+ app,gui,flagPrint=launchPaIRS(True)
3957
+ quitPaIRS(app,flagPrint)