setiastrosuitepro 1.6.2.post1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of setiastrosuitepro might be problematic. Click here for more details.

Files changed (367) hide show
  1. setiastro/__init__.py +2 -0
  2. setiastro/data/SASP_data.fits +0 -0
  3. setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
  4. setiastro/data/catalogs/astrobin_filters.csv +890 -0
  5. setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
  6. setiastro/data/catalogs/cali2.csv +63 -0
  7. setiastro/data/catalogs/cali2color.csv +65 -0
  8. setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
  9. setiastro/data/catalogs/celestial_catalog.csv +24031 -0
  10. setiastro/data/catalogs/detected_stars.csv +24784 -0
  11. setiastro/data/catalogs/fits_header_data.csv +46 -0
  12. setiastro/data/catalogs/test.csv +8 -0
  13. setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
  14. setiastro/images/Astro_Spikes.png +0 -0
  15. setiastro/images/Background_startup.jpg +0 -0
  16. setiastro/images/HRDiagram.png +0 -0
  17. setiastro/images/LExtract.png +0 -0
  18. setiastro/images/LInsert.png +0 -0
  19. setiastro/images/Oxygenation-atm-2.svg.png +0 -0
  20. setiastro/images/RGB080604.png +0 -0
  21. setiastro/images/abeicon.png +0 -0
  22. setiastro/images/aberration.png +0 -0
  23. setiastro/images/andromedatry.png +0 -0
  24. setiastro/images/andromedatry_satellited.png +0 -0
  25. setiastro/images/annotated.png +0 -0
  26. setiastro/images/aperture.png +0 -0
  27. setiastro/images/astrosuite.ico +0 -0
  28. setiastro/images/astrosuite.png +0 -0
  29. setiastro/images/astrosuitepro.icns +0 -0
  30. setiastro/images/astrosuitepro.ico +0 -0
  31. setiastro/images/astrosuitepro.png +0 -0
  32. setiastro/images/background.png +0 -0
  33. setiastro/images/background2.png +0 -0
  34. setiastro/images/benchmark.png +0 -0
  35. setiastro/images/big_moon_stabilizer_timeline.png +0 -0
  36. setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
  37. setiastro/images/blaster.png +0 -0
  38. setiastro/images/blink.png +0 -0
  39. setiastro/images/clahe.png +0 -0
  40. setiastro/images/collage.png +0 -0
  41. setiastro/images/colorwheel.png +0 -0
  42. setiastro/images/contsub.png +0 -0
  43. setiastro/images/convo.png +0 -0
  44. setiastro/images/copyslot.png +0 -0
  45. setiastro/images/cosmic.png +0 -0
  46. setiastro/images/cosmicsat.png +0 -0
  47. setiastro/images/crop1.png +0 -0
  48. setiastro/images/cropicon.png +0 -0
  49. setiastro/images/curves.png +0 -0
  50. setiastro/images/cvs.png +0 -0
  51. setiastro/images/debayer.png +0 -0
  52. setiastro/images/denoise_cnn_custom.png +0 -0
  53. setiastro/images/denoise_cnn_graph.png +0 -0
  54. setiastro/images/disk.png +0 -0
  55. setiastro/images/dse.png +0 -0
  56. setiastro/images/exoicon.png +0 -0
  57. setiastro/images/eye.png +0 -0
  58. setiastro/images/fliphorizontal.png +0 -0
  59. setiastro/images/flipvertical.png +0 -0
  60. setiastro/images/font.png +0 -0
  61. setiastro/images/freqsep.png +0 -0
  62. setiastro/images/functionbundle.png +0 -0
  63. setiastro/images/graxpert.png +0 -0
  64. setiastro/images/green.png +0 -0
  65. setiastro/images/gridicon.png +0 -0
  66. setiastro/images/halo.png +0 -0
  67. setiastro/images/hdr.png +0 -0
  68. setiastro/images/histogram.png +0 -0
  69. setiastro/images/hubble.png +0 -0
  70. setiastro/images/imagecombine.png +0 -0
  71. setiastro/images/invert.png +0 -0
  72. setiastro/images/isophote.png +0 -0
  73. setiastro/images/isophote_demo_figure.png +0 -0
  74. setiastro/images/isophote_demo_image.png +0 -0
  75. setiastro/images/isophote_demo_model.png +0 -0
  76. setiastro/images/isophote_demo_residual.png +0 -0
  77. setiastro/images/jwstpupil.png +0 -0
  78. setiastro/images/linearfit.png +0 -0
  79. setiastro/images/livestacking.png +0 -0
  80. setiastro/images/mask.png +0 -0
  81. setiastro/images/maskapply.png +0 -0
  82. setiastro/images/maskcreate.png +0 -0
  83. setiastro/images/maskremove.png +0 -0
  84. setiastro/images/morpho.png +0 -0
  85. setiastro/images/mosaic.png +0 -0
  86. setiastro/images/multiscale_decomp.png +0 -0
  87. setiastro/images/nbtorgb.png +0 -0
  88. setiastro/images/neutral.png +0 -0
  89. setiastro/images/nuke.png +0 -0
  90. setiastro/images/openfile.png +0 -0
  91. setiastro/images/pedestal.png +0 -0
  92. setiastro/images/pen.png +0 -0
  93. setiastro/images/pixelmath.png +0 -0
  94. setiastro/images/platesolve.png +0 -0
  95. setiastro/images/ppp.png +0 -0
  96. setiastro/images/pro.png +0 -0
  97. setiastro/images/project.png +0 -0
  98. setiastro/images/psf.png +0 -0
  99. setiastro/images/redo.png +0 -0
  100. setiastro/images/redoicon.png +0 -0
  101. setiastro/images/rescale.png +0 -0
  102. setiastro/images/rgbalign.png +0 -0
  103. setiastro/images/rgbcombo.png +0 -0
  104. setiastro/images/rgbextract.png +0 -0
  105. setiastro/images/rotate180.png +0 -0
  106. setiastro/images/rotateclockwise.png +0 -0
  107. setiastro/images/rotatecounterclockwise.png +0 -0
  108. setiastro/images/satellite.png +0 -0
  109. setiastro/images/script.png +0 -0
  110. setiastro/images/selectivecolor.png +0 -0
  111. setiastro/images/simbad.png +0 -0
  112. setiastro/images/slot0.png +0 -0
  113. setiastro/images/slot1.png +0 -0
  114. setiastro/images/slot2.png +0 -0
  115. setiastro/images/slot3.png +0 -0
  116. setiastro/images/slot4.png +0 -0
  117. setiastro/images/slot5.png +0 -0
  118. setiastro/images/slot6.png +0 -0
  119. setiastro/images/slot7.png +0 -0
  120. setiastro/images/slot8.png +0 -0
  121. setiastro/images/slot9.png +0 -0
  122. setiastro/images/spcc.png +0 -0
  123. setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
  124. setiastro/images/spinner.gif +0 -0
  125. setiastro/images/stacking.png +0 -0
  126. setiastro/images/staradd.png +0 -0
  127. setiastro/images/staralign.png +0 -0
  128. setiastro/images/starnet.png +0 -0
  129. setiastro/images/starregistration.png +0 -0
  130. setiastro/images/starspike.png +0 -0
  131. setiastro/images/starstretch.png +0 -0
  132. setiastro/images/statstretch.png +0 -0
  133. setiastro/images/supernova.png +0 -0
  134. setiastro/images/uhs.png +0 -0
  135. setiastro/images/undoicon.png +0 -0
  136. setiastro/images/upscale.png +0 -0
  137. setiastro/images/viewbundle.png +0 -0
  138. setiastro/images/whitebalance.png +0 -0
  139. setiastro/images/wimi_icon_256x256.png +0 -0
  140. setiastro/images/wimilogo.png +0 -0
  141. setiastro/images/wims.png +0 -0
  142. setiastro/images/wrench_icon.png +0 -0
  143. setiastro/images/xisfliberator.png +0 -0
  144. setiastro/qml/ResourceMonitor.qml +126 -0
  145. setiastro/saspro/__init__.py +20 -0
  146. setiastro/saspro/__main__.py +945 -0
  147. setiastro/saspro/_generated/__init__.py +7 -0
  148. setiastro/saspro/_generated/build_info.py +3 -0
  149. setiastro/saspro/abe.py +1346 -0
  150. setiastro/saspro/abe_preset.py +196 -0
  151. setiastro/saspro/aberration_ai.py +694 -0
  152. setiastro/saspro/aberration_ai_preset.py +224 -0
  153. setiastro/saspro/accel_installer.py +218 -0
  154. setiastro/saspro/accel_workers.py +30 -0
  155. setiastro/saspro/add_stars.py +624 -0
  156. setiastro/saspro/astrobin_exporter.py +1010 -0
  157. setiastro/saspro/astrospike.py +153 -0
  158. setiastro/saspro/astrospike_python.py +1841 -0
  159. setiastro/saspro/autostretch.py +198 -0
  160. setiastro/saspro/backgroundneutral.py +602 -0
  161. setiastro/saspro/batch_convert.py +328 -0
  162. setiastro/saspro/batch_renamer.py +522 -0
  163. setiastro/saspro/blemish_blaster.py +491 -0
  164. setiastro/saspro/blink_comparator_pro.py +2926 -0
  165. setiastro/saspro/bundles.py +61 -0
  166. setiastro/saspro/bundles_dock.py +114 -0
  167. setiastro/saspro/cheat_sheet.py +213 -0
  168. setiastro/saspro/clahe.py +368 -0
  169. setiastro/saspro/comet_stacking.py +1442 -0
  170. setiastro/saspro/common_tr.py +107 -0
  171. setiastro/saspro/config.py +38 -0
  172. setiastro/saspro/config_bootstrap.py +40 -0
  173. setiastro/saspro/config_manager.py +316 -0
  174. setiastro/saspro/continuum_subtract.py +1617 -0
  175. setiastro/saspro/convo.py +1400 -0
  176. setiastro/saspro/convo_preset.py +414 -0
  177. setiastro/saspro/copyastro.py +190 -0
  178. setiastro/saspro/cosmicclarity.py +1589 -0
  179. setiastro/saspro/cosmicclarity_preset.py +407 -0
  180. setiastro/saspro/crop_dialog_pro.py +973 -0
  181. setiastro/saspro/crop_preset.py +189 -0
  182. setiastro/saspro/curve_editor_pro.py +2562 -0
  183. setiastro/saspro/curves_preset.py +375 -0
  184. setiastro/saspro/debayer.py +673 -0
  185. setiastro/saspro/debug_utils.py +29 -0
  186. setiastro/saspro/dnd_mime.py +35 -0
  187. setiastro/saspro/doc_manager.py +2664 -0
  188. setiastro/saspro/exoplanet_detector.py +2166 -0
  189. setiastro/saspro/file_utils.py +284 -0
  190. setiastro/saspro/fitsmodifier.py +748 -0
  191. setiastro/saspro/fix_bom.py +32 -0
  192. setiastro/saspro/free_torch_memory.py +48 -0
  193. setiastro/saspro/frequency_separation.py +1349 -0
  194. setiastro/saspro/function_bundle.py +1596 -0
  195. setiastro/saspro/generate_translations.py +3092 -0
  196. setiastro/saspro/ghs_dialog_pro.py +663 -0
  197. setiastro/saspro/ghs_preset.py +284 -0
  198. setiastro/saspro/graxpert.py +637 -0
  199. setiastro/saspro/graxpert_preset.py +287 -0
  200. setiastro/saspro/gui/__init__.py +0 -0
  201. setiastro/saspro/gui/main_window.py +8810 -0
  202. setiastro/saspro/gui/mixins/__init__.py +33 -0
  203. setiastro/saspro/gui/mixins/dock_mixin.py +362 -0
  204. setiastro/saspro/gui/mixins/file_mixin.py +450 -0
  205. setiastro/saspro/gui/mixins/geometry_mixin.py +403 -0
  206. setiastro/saspro/gui/mixins/header_mixin.py +441 -0
  207. setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
  208. setiastro/saspro/gui/mixins/menu_mixin.py +389 -0
  209. setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
  210. setiastro/saspro/gui/mixins/toolbar_mixin.py +1457 -0
  211. setiastro/saspro/gui/mixins/update_mixin.py +309 -0
  212. setiastro/saspro/gui/mixins/view_mixin.py +435 -0
  213. setiastro/saspro/gui/statistics_dialog.py +47 -0
  214. setiastro/saspro/halobgon.py +488 -0
  215. setiastro/saspro/header_viewer.py +448 -0
  216. setiastro/saspro/headless_utils.py +88 -0
  217. setiastro/saspro/histogram.py +756 -0
  218. setiastro/saspro/history_explorer.py +941 -0
  219. setiastro/saspro/i18n.py +168 -0
  220. setiastro/saspro/image_combine.py +417 -0
  221. setiastro/saspro/image_peeker_pro.py +1604 -0
  222. setiastro/saspro/imageops/__init__.py +37 -0
  223. setiastro/saspro/imageops/mdi_snap.py +292 -0
  224. setiastro/saspro/imageops/scnr.py +36 -0
  225. setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
  226. setiastro/saspro/imageops/stretch.py +236 -0
  227. setiastro/saspro/isophote.py +1182 -0
  228. setiastro/saspro/layers.py +208 -0
  229. setiastro/saspro/layers_dock.py +714 -0
  230. setiastro/saspro/lazy_imports.py +193 -0
  231. setiastro/saspro/legacy/__init__.py +2 -0
  232. setiastro/saspro/legacy/image_manager.py +2226 -0
  233. setiastro/saspro/legacy/numba_utils.py +3676 -0
  234. setiastro/saspro/legacy/xisf.py +1071 -0
  235. setiastro/saspro/linear_fit.py +537 -0
  236. setiastro/saspro/live_stacking.py +1841 -0
  237. setiastro/saspro/log_bus.py +5 -0
  238. setiastro/saspro/logging_config.py +460 -0
  239. setiastro/saspro/luminancerecombine.py +309 -0
  240. setiastro/saspro/main_helpers.py +201 -0
  241. setiastro/saspro/mask_creation.py +931 -0
  242. setiastro/saspro/masks_core.py +56 -0
  243. setiastro/saspro/mdi_widgets.py +353 -0
  244. setiastro/saspro/memory_utils.py +666 -0
  245. setiastro/saspro/metadata_patcher.py +75 -0
  246. setiastro/saspro/mfdeconv.py +3831 -0
  247. setiastro/saspro/mfdeconv_earlystop.py +71 -0
  248. setiastro/saspro/mfdeconvcudnn.py +3263 -0
  249. setiastro/saspro/mfdeconvsport.py +2382 -0
  250. setiastro/saspro/minorbodycatalog.py +567 -0
  251. setiastro/saspro/morphology.py +407 -0
  252. setiastro/saspro/multiscale_decomp.py +1293 -0
  253. setiastro/saspro/nbtorgb_stars.py +541 -0
  254. setiastro/saspro/numba_utils.py +3145 -0
  255. setiastro/saspro/numba_warmup.py +141 -0
  256. setiastro/saspro/ops/__init__.py +9 -0
  257. setiastro/saspro/ops/command_help_dialog.py +623 -0
  258. setiastro/saspro/ops/command_runner.py +217 -0
  259. setiastro/saspro/ops/commands.py +1594 -0
  260. setiastro/saspro/ops/script_editor.py +1102 -0
  261. setiastro/saspro/ops/scripts.py +1473 -0
  262. setiastro/saspro/ops/settings.py +637 -0
  263. setiastro/saspro/parallel_utils.py +554 -0
  264. setiastro/saspro/pedestal.py +121 -0
  265. setiastro/saspro/perfect_palette_picker.py +1071 -0
  266. setiastro/saspro/pipeline.py +110 -0
  267. setiastro/saspro/pixelmath.py +1604 -0
  268. setiastro/saspro/plate_solver.py +2445 -0
  269. setiastro/saspro/project_io.py +797 -0
  270. setiastro/saspro/psf_utils.py +136 -0
  271. setiastro/saspro/psf_viewer.py +549 -0
  272. setiastro/saspro/pyi_rthook_astroquery.py +95 -0
  273. setiastro/saspro/remove_green.py +331 -0
  274. setiastro/saspro/remove_stars.py +1599 -0
  275. setiastro/saspro/remove_stars_preset.py +404 -0
  276. setiastro/saspro/resources.py +501 -0
  277. setiastro/saspro/rgb_combination.py +208 -0
  278. setiastro/saspro/rgb_extract.py +19 -0
  279. setiastro/saspro/rgbalign.py +723 -0
  280. setiastro/saspro/runtime_imports.py +7 -0
  281. setiastro/saspro/runtime_torch.py +754 -0
  282. setiastro/saspro/save_options.py +73 -0
  283. setiastro/saspro/selective_color.py +1552 -0
  284. setiastro/saspro/sfcc.py +1472 -0
  285. setiastro/saspro/shortcuts.py +3043 -0
  286. setiastro/saspro/signature_insert.py +1102 -0
  287. setiastro/saspro/stacking_suite.py +18470 -0
  288. setiastro/saspro/star_alignment.py +7435 -0
  289. setiastro/saspro/star_alignment_preset.py +329 -0
  290. setiastro/saspro/star_metrics.py +49 -0
  291. setiastro/saspro/star_spikes.py +765 -0
  292. setiastro/saspro/star_stretch.py +507 -0
  293. setiastro/saspro/stat_stretch.py +538 -0
  294. setiastro/saspro/status_log_dock.py +78 -0
  295. setiastro/saspro/subwindow.py +3328 -0
  296. setiastro/saspro/supernovaasteroidhunter.py +1719 -0
  297. setiastro/saspro/swap_manager.py +99 -0
  298. setiastro/saspro/torch_backend.py +89 -0
  299. setiastro/saspro/torch_rejection.py +434 -0
  300. setiastro/saspro/translations/all_source_strings.json +3654 -0
  301. setiastro/saspro/translations/ar_translations.py +3865 -0
  302. setiastro/saspro/translations/de_translations.py +3749 -0
  303. setiastro/saspro/translations/es_translations.py +3939 -0
  304. setiastro/saspro/translations/fr_translations.py +3858 -0
  305. setiastro/saspro/translations/hi_translations.py +3571 -0
  306. setiastro/saspro/translations/integrate_translations.py +270 -0
  307. setiastro/saspro/translations/it_translations.py +3678 -0
  308. setiastro/saspro/translations/ja_translations.py +3601 -0
  309. setiastro/saspro/translations/pt_translations.py +3869 -0
  310. setiastro/saspro/translations/ru_translations.py +2848 -0
  311. setiastro/saspro/translations/saspro_ar.qm +0 -0
  312. setiastro/saspro/translations/saspro_ar.ts +255 -0
  313. setiastro/saspro/translations/saspro_de.qm +0 -0
  314. setiastro/saspro/translations/saspro_de.ts +253 -0
  315. setiastro/saspro/translations/saspro_es.qm +0 -0
  316. setiastro/saspro/translations/saspro_es.ts +12520 -0
  317. setiastro/saspro/translations/saspro_fr.qm +0 -0
  318. setiastro/saspro/translations/saspro_fr.ts +12514 -0
  319. setiastro/saspro/translations/saspro_hi.qm +0 -0
  320. setiastro/saspro/translations/saspro_hi.ts +257 -0
  321. setiastro/saspro/translations/saspro_it.qm +0 -0
  322. setiastro/saspro/translations/saspro_it.ts +12520 -0
  323. setiastro/saspro/translations/saspro_ja.qm +0 -0
  324. setiastro/saspro/translations/saspro_ja.ts +257 -0
  325. setiastro/saspro/translations/saspro_pt.qm +0 -0
  326. setiastro/saspro/translations/saspro_pt.ts +257 -0
  327. setiastro/saspro/translations/saspro_ru.qm +0 -0
  328. setiastro/saspro/translations/saspro_ru.ts +237 -0
  329. setiastro/saspro/translations/saspro_sw.qm +0 -0
  330. setiastro/saspro/translations/saspro_sw.ts +257 -0
  331. setiastro/saspro/translations/saspro_uk.qm +0 -0
  332. setiastro/saspro/translations/saspro_uk.ts +10771 -0
  333. setiastro/saspro/translations/saspro_zh.qm +0 -0
  334. setiastro/saspro/translations/saspro_zh.ts +12520 -0
  335. setiastro/saspro/translations/sw_translations.py +3671 -0
  336. setiastro/saspro/translations/uk_translations.py +3700 -0
  337. setiastro/saspro/translations/zh_translations.py +3675 -0
  338. setiastro/saspro/versioning.py +77 -0
  339. setiastro/saspro/view_bundle.py +1558 -0
  340. setiastro/saspro/wavescale_hdr.py +645 -0
  341. setiastro/saspro/wavescale_hdr_preset.py +101 -0
  342. setiastro/saspro/wavescalede.py +680 -0
  343. setiastro/saspro/wavescalede_preset.py +230 -0
  344. setiastro/saspro/wcs_update.py +374 -0
  345. setiastro/saspro/whitebalance.py +492 -0
  346. setiastro/saspro/widgets/__init__.py +48 -0
  347. setiastro/saspro/widgets/common_utilities.py +306 -0
  348. setiastro/saspro/widgets/graphics_views.py +122 -0
  349. setiastro/saspro/widgets/image_utils.py +518 -0
  350. setiastro/saspro/widgets/minigame/game.js +986 -0
  351. setiastro/saspro/widgets/minigame/index.html +53 -0
  352. setiastro/saspro/widgets/minigame/style.css +241 -0
  353. setiastro/saspro/widgets/preview_dialogs.py +280 -0
  354. setiastro/saspro/widgets/resource_monitor.py +237 -0
  355. setiastro/saspro/widgets/spinboxes.py +275 -0
  356. setiastro/saspro/widgets/themed_buttons.py +13 -0
  357. setiastro/saspro/widgets/wavelet_utils.py +331 -0
  358. setiastro/saspro/wimi.py +7996 -0
  359. setiastro/saspro/wims.py +578 -0
  360. setiastro/saspro/window_shelf.py +185 -0
  361. setiastro/saspro/xisf.py +1123 -0
  362. setiastrosuitepro-1.6.2.post1.dist-info/METADATA +278 -0
  363. setiastrosuitepro-1.6.2.post1.dist-info/RECORD +367 -0
  364. setiastrosuitepro-1.6.2.post1.dist-info/WHEEL +4 -0
  365. setiastrosuitepro-1.6.2.post1.dist-info/entry_points.txt +6 -0
  366. setiastrosuitepro-1.6.2.post1.dist-info/licenses/LICENSE +674 -0
  367. setiastrosuitepro-1.6.2.post1.dist-info/licenses/license.txt +2580 -0
@@ -0,0 +1,33 @@
1
+ # pro/gui/mixins/__init__.py
2
+ """
3
+ GUI Mixins for AstroSuiteProMainWindow.
4
+
5
+ This package contains modular mixins that separate different aspects of the main window
6
+ into logical, maintainable components.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from .dock_mixin import DockMixin
11
+ from .menu_mixin import MenuMixin
12
+ from .toolbar_mixin import ToolbarMixin
13
+ from .file_mixin import FileMixin
14
+ from .theme_mixin import ThemeMixin
15
+ from .geometry_mixin import GeometryMixin
16
+ from .view_mixin import ViewMixin
17
+ from .header_mixin import HeaderMixin
18
+ from .mask_mixin import MaskMixin
19
+ from .update_mixin import UpdateMixin
20
+
21
+ __all__ = [
22
+ "DockMixin",
23
+ "MenuMixin",
24
+ "ToolbarMixin",
25
+ "FileMixin",
26
+ "ThemeMixin",
27
+ "GeometryMixin",
28
+ "ViewMixin",
29
+ "HeaderMixin",
30
+ "MaskMixin",
31
+ "UpdateMixin",
32
+ ]
33
+
@@ -0,0 +1,362 @@
1
+ # pro/gui/mixins/dock_mixin.py
2
+ """
3
+ Dock management mixin for AstroSuiteProMainWindow.
4
+
5
+ This mixin contains all dock-related functionality: initialization,
6
+ visibility management, and registration in menus.
7
+ """
8
+ from __future__ import annotations
9
+ from typing import TYPE_CHECKING
10
+
11
+ from PyQt6.QtCore import Qt, QTimer
12
+ from PyQt6.QtWidgets import (
13
+ QDockWidget, QPlainTextEdit, QTreeWidget, QTreeWidgetItem,
14
+ QVBoxLayout, QWidget, QTextEdit, QListWidget, QListWidgetItem,
15
+ QAbstractItemView, QApplication
16
+ )
17
+ from PyQt6.QtGui import QTextCursor, QAction
18
+
19
+ if TYPE_CHECKING:
20
+ from PyQt6.QtWidgets import QAction
21
+
22
+
23
+ class DockMixin:
24
+ """
25
+ Mixin for dock widget management.
26
+
27
+ Provides methods for creating, managing, and synchronizing dock widgets
28
+ in the main window.
29
+ """
30
+
31
+ def _init_log_dock(self):
32
+ """Initialize the system log dock widget."""
33
+ self.log_dock = QDockWidget(self.tr("System Log"), self)
34
+ self.log_dock.setObjectName("LogDock")
35
+ self.log_dock.setAllowedAreas(
36
+ Qt.DockWidgetArea.BottomDockWidgetArea
37
+ | Qt.DockWidgetArea.TopDockWidgetArea
38
+ )
39
+
40
+ self.log_text = QPlainTextEdit(self.log_dock)
41
+ self.log_text.setReadOnly(True)
42
+ self.log_text.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
43
+ self.log_dock.setWidget(self.log_text)
44
+
45
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_dock)
46
+
47
+ self.act_toggle_log = self.log_dock.toggleViewAction()
48
+ self.act_toggle_log.setText(self.tr("Show System Log Panel"))
49
+
50
+ def _append_log_text(self, text: str):
51
+ """Append text to the system log dock."""
52
+ if not text:
53
+ return
54
+ # Append to the bottom and keep view scrolled
55
+ cursor = self.log_text.textCursor()
56
+ cursor.movePosition(QTextCursor.MoveOperation.End)
57
+ cursor.insertText(text)
58
+ self.log_text.setTextCursor(cursor)
59
+ self.log_text.ensureCursorVisible()
60
+
61
+ def _hook_stdout_stderr(self):
62
+ """Hook stdout/stderr to redirect to the system log dock."""
63
+ import sys
64
+ from setiastro.saspro.mdi_widgets import QtLogStream
65
+
66
+ # Remember original streams so we still print to real console.
67
+ self._orig_stdout = sys.stdout
68
+ self._orig_stderr = sys.stderr
69
+
70
+ self._qt_stdout = QtLogStream(self._orig_stdout, self)
71
+ self._qt_stderr = QtLogStream(self._orig_stderr, self)
72
+
73
+ self._qt_stdout.text_emitted.connect(self._append_log_text)
74
+ self._qt_stderr.text_emitted.connect(self._append_log_text)
75
+
76
+ sys.stdout = self._qt_stdout
77
+ sys.stderr = self._qt_stderr
78
+
79
+ def _register_dock_in_view_menu(self, dock: QDockWidget, action: QAction | None = None):
80
+ """
81
+ Register a dock widget's toggle action in the View → Panels menu.
82
+
83
+ Args:
84
+ dock: The QDockWidget to register
85
+ action: Optional custom action (if None, uses dock.toggleViewAction())
86
+ """
87
+ if not hasattr(self, "_view_panels_menu"):
88
+ return
89
+
90
+ if action is None:
91
+ action = dock.toggleViewAction()
92
+
93
+ self._view_panels_menu.addAction(action)
94
+
95
+ def _remove_dock_from_view_menu(self, action: QAction):
96
+ """
97
+ Remove a dock's toggle action from the View → Panels menu.
98
+
99
+ Args:
100
+ action: The action to remove
101
+ """
102
+ if not hasattr(self, "_view_panels_menu"):
103
+ return
104
+
105
+ self._view_panels_menu.removeAction(action)
106
+
107
+ def _init_explorer_dock(self):
108
+ self.explorer = QListWidget()
109
+ # Enter/Return or single-activation: focus if open, else open
110
+ self.explorer.itemActivated.connect(self._activate_or_open_from_explorer)
111
+ # Double-click: same behavior
112
+ self.explorer.itemDoubleClicked.connect(self._activate_or_open_from_explorer)
113
+
114
+ dock = QDockWidget(self.tr("Explorer"), self)
115
+ dock.setWidget(self.explorer)
116
+ dock.setObjectName("ExplorerDock")
117
+ self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dock)
118
+
119
+ def _init_console_dock(self):
120
+ self.console = QListWidget()
121
+
122
+ # Allow multi-row selection so Select All actually highlights everything
123
+ self.console.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
124
+
125
+ # Right-click context menu
126
+ self.console.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
127
+ self.console.customContextMenuRequested.connect(self._on_console_context_menu)
128
+
129
+ dock = QDockWidget(self.tr("Console / Status"), self)
130
+ dock.setWidget(self.console)
131
+ dock.setObjectName("ConsoleDock")
132
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, dock)
133
+
134
+ def _init_status_log_dock(self):
135
+ from setiastro.saspro.status_log_dock import StatusLogDock
136
+ from setiastro.saspro.log_bus import LogBus
137
+
138
+ # Create the dock
139
+ self.status_log_dock = StatusLogDock(self) # your dock widget class
140
+ self.status_log_dock.setObjectName("StatusLogDock") # stable name for restoreState/menu
141
+ self.status_log_dock.setAllowedAreas(
142
+ Qt.DockWidgetArea.LeftDockWidgetArea
143
+ | Qt.DockWidgetArea.RightDockWidgetArea
144
+ | Qt.DockWidgetArea.BottomDockWidgetArea
145
+ | Qt.DockWidgetArea.TopDockWidgetArea
146
+ )
147
+ # Default area (will be overridden by restoreState if present)
148
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.status_log_dock)
149
+
150
+ # Expose the dock globally so dialogs can show/raise it
151
+ app = QApplication.instance()
152
+ app._sasd_status_console = self.status_log_dock
153
+
154
+ # Ensure a global log bus and wire bus -> dock (queued; thread-safe)
155
+ if not hasattr(app, "_sasd_log_bus"):
156
+ app._sasd_log_bus = LogBus()
157
+ app._sasd_log_bus.posted.connect(
158
+ self.status_log_dock.append_line,
159
+ type=Qt.ConnectionType.QueuedConnection
160
+ )
161
+
162
+ # First-run placement (only if no prior saved layout)
163
+ self._first_place_status_log_if_needed()
164
+
165
+ def _init_layers_dock(self):
166
+ from setiastro.saspro.layers_dock import LayersDock
167
+
168
+ self.layers_dock = LayersDock(self)
169
+ self.layers_dock.setObjectName("LayersDock")
170
+ # put it on the right, *below* header viewer if you dock that at right too
171
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.layers_dock)
172
+ # ensure the header viewer sits above, layers below
173
+ try:
174
+ self.splitDockWidget(self.header_dock, self.layers_dock, Qt.Orientation.Vertical)
175
+ except Exception:
176
+ pass
177
+
178
+ def _init_header_viewer_dock(self):
179
+ from setiastro.saspro.header_viewer import HeaderViewerDock
180
+
181
+ self.header_viewer = HeaderViewerDock(self)
182
+ self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.header_viewer)
183
+
184
+ # Bind the dock to DocManager so it tracks the ACTIVE subwindow only.
185
+ # Make sure self.doc_manager.set_mdi_area(mdi) was already called.
186
+ self.header_viewer.attach_doc_manager(self.doc_manager)
187
+
188
+ # Optional: keep it strictly active-only (default). Flip to True to restore hover-follow behavior.
189
+ # self.header_viewer.set_follow_hover(False)
190
+
191
+ # Seed once with whatever is currently active.
192
+ try:
193
+ self.header_viewer.set_document(self.doc_manager.get_active_document())
194
+ except Exception:
195
+ pass
196
+
197
+ def _init_resource_monitor_overlay(self):
198
+ """Initialize the QML System Resource Monitor as a floating overlay."""
199
+ try:
200
+ from setiastro.saspro.widgets.resource_monitor import SystemMonitorWidget
201
+
202
+ # Create as a child of the central widget or self to sit on top
203
+ # Using self (QMainWindow) allows it to float over everything including status bar if we want,
204
+ # but usually we want it over MDI area. Let's try self first for "floating" feel.
205
+ self.resource_monitor = SystemMonitorWidget(self)
206
+ self.resource_monitor.setObjectName("ResourceMonitorOverlay")
207
+
208
+ # Make it a proper independent window to allow true transparency (translucent background)
209
+ # without black artifacts from parent composition.
210
+ # Fixed: Removed WindowStaysOnTopHint to allow it to be obscured by other apps (Alt-Tab support)
211
+ self.resource_monitor.setWindowFlags(
212
+ Qt.WindowType.Window |
213
+ Qt.WindowType.FramelessWindowHint |
214
+ Qt.WindowType.Tool
215
+ )
216
+
217
+ # Sizing and Transparency
218
+ self.resource_monitor.setFixedSize(200, 60)
219
+ # self.resource_monitor.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True) # Optional: if we want click-through
220
+
221
+
222
+ # Initial placement (will be updated by resizeEvent)
223
+ self._update_monitor_position()
224
+
225
+ # Defer visibility to MainWindow.showEvent to prevent appearing before main window
226
+ # visible = self.settings.value("ui/resource_monitor_visible", True, type=bool)
227
+ # if visible:
228
+ # self.resource_monitor.show()
229
+ # else:
230
+ # self.resource_monitor.hide()
231
+ except Exception as e:
232
+ print(f"WARNING: Could not initialize System Monitor overlay: {e}")
233
+ self.resource_monitor = None
234
+
235
+ def _toggle_resource_monitor(self, checked: bool):
236
+ """Toggle floating monitor visibility."""
237
+ if hasattr(self, 'resource_monitor') and self.resource_monitor:
238
+ if checked:
239
+ self.resource_monitor.show()
240
+ self._update_monitor_position()
241
+ else:
242
+ self.resource_monitor.hide()
243
+ self.settings.setValue("ui/resource_monitor_visible", checked)
244
+
245
+ def _update_monitor_position(self):
246
+ """Snap monitor to bottom-right corner."""
247
+ if hasattr(self, 'resource_monitor') and self.resource_monitor:
248
+ from PyQt6.QtCore import QPoint
249
+ m = 5 # margin
250
+ # Position relative to the main window geometry
251
+ w = self.resource_monitor.width()
252
+ h = self.resource_monitor.height()
253
+
254
+ # Anchor to bottom-right of the window
255
+ x = self.width() - w - m
256
+ y = self.height() - h - m
257
+
258
+ # Map local MainWindow coordinates to Global Screen coordinates
259
+ # This is required because resource_monitor is a Top-Level Window (for transparency)
260
+ global_pos = self.mapToGlobal(QPoint(x, y))
261
+ self.resource_monitor.move(global_pos)
262
+ self.resource_monitor.raise_()
263
+
264
+ # We need to hook resizeEvent to call _update_monitor_position.
265
+ # Since this is a mixin, we can't easily override resizeEvent of the MainWindow without being careful.
266
+ # Best way: install an event filter on self, or since we are a mixin mixed into MainWindow,
267
+ # we can rely on MainWindow calling a specific method or we can patch it...
268
+ # Actually, MainWindow likely has resizeEvent.
269
+ # simpler: QTimer check? No.
270
+ # Correct way for Mixin: The MainWindow class should call something.
271
+ # BUT, I can just installEventFilter(self) ? No, infinite loop risk.
272
+ #
273
+ # Let's use the 'GeometryMixin' or just add a standard method `_on_resize_for_monitor`
274
+ # and assume I can hook it in MainWindow.py.
275
+
276
+
277
+ # ❌ Remove this old line; it let random mouse-over updates hijack the dock:
278
+ # self.currentDocumentChanged.disconnect(self.header_viewer.set_document) # if previously connected
279
+ # (If you prefer to keep the signal for explicit tab switches, it's fine to leave
280
+ # it connected--the dock's new guard will ignore non-active/hover docs.)
281
+
282
+ def _populate_view_panels_menu(self):
283
+ """Rebuild 'View Panels' with all current dock widgets (ordered nicely)."""
284
+ menu = self._ensure_view_panels_menu()
285
+ menu.clear()
286
+ self._view_panels_actions = {}
287
+
288
+ # Collect every QDockWidget that exists right now
289
+ docks: list[QDockWidget] = self.findChildren(QDockWidget)
290
+
291
+ # Friendly ordering for common ones; others follow alphabetically.
292
+ order_hint = {
293
+ "Explorer": 10,
294
+ "Console / Status": 20,
295
+ "Header Viewer": 30,
296
+ "Layers": 40,
297
+ "Window Shelf": 50,
298
+ "Command Search": 60,
299
+ }
300
+
301
+ # Add special action for overlay monitor
302
+ mon_act = QAction(self.tr("System Monitor"), self)
303
+ mon_act.setCheckable(True)
304
+ mon_act.setChecked(self.settings.value("ui/resource_monitor_visible", True, type=bool))
305
+ mon_act.triggered.connect(self._toggle_resource_monitor)
306
+
307
+ # We need to insert it into the logic that populates the menu.
308
+ # But 'dock_mixin' automates menu from self.findChildren(QDockWidget).
309
+ # So we have to manually inject this action into the "Panels" menu if possible
310
+ # or expose it such that main_window can add it.
311
+ #
312
+ # Easier: allow main_window to add it, or ...
313
+ # If I can't easily see where menu is built, I'll bind it to self.act_toggle_monitor = mon_act
314
+ self.act_toggle_monitor = mon_act
315
+
316
+ def key_fn(d: QDockWidget):
317
+ t = d.windowTitle()
318
+ return (order_hint.get(t, 1000), t.lower())
319
+
320
+ for dock in sorted(docks, key=key_fn):
321
+ self._register_dock_in_view_menu(dock)
322
+
323
+ if hasattr(self, "act_toggle_monitor"):
324
+ menu.addSeparator()
325
+ menu.addAction(self.act_toggle_monitor)
326
+
327
+ def _add_doc_to_explorer(self, doc):
328
+ base = self._normalize_base_doc(doc)
329
+
330
+ # de-dupe by identity on base
331
+ for i in range(self.explorer.count()):
332
+ it = self.explorer.item(i)
333
+ if it.data(Qt.ItemDataRole.UserRole) is base:
334
+ # refresh text in case dims/name changed
335
+ it.setText(self._format_explorer_title(base))
336
+ return
337
+
338
+ item = QListWidgetItem(self._format_explorer_title(base))
339
+ item.setData(Qt.ItemDataRole.UserRole, base)
340
+ fp = (base.metadata or {}).get("file_path")
341
+ if fp:
342
+ item.setToolTip(fp)
343
+ self.explorer.addItem(item)
344
+
345
+ # keep row label in sync with edits/resizes/renames
346
+ try:
347
+ base.changed.connect(lambda *_: self._update_explorer_item_for_doc(base))
348
+ except Exception:
349
+ pass
350
+
351
+ def _remove_doc_from_explorer(self, doc):
352
+ """
353
+ Remove either the exact doc or its base (handles ROI proxies).
354
+ """
355
+ base = self._normalize_base_doc(doc)
356
+ for i in range(self.explorer.count()):
357
+ it = self.explorer.item(i)
358
+ d = it.data(Qt.ItemDataRole.UserRole)
359
+ if d is doc or d is base:
360
+ self.explorer.takeItem(i)
361
+ break
362
+