setiastrosuitepro 1.6.7__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 (394) 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/acv_icon.png +0 -0
  24. setiastro/images/andromedatry.png +0 -0
  25. setiastro/images/andromedatry_satellited.png +0 -0
  26. setiastro/images/annotated.png +0 -0
  27. setiastro/images/aperture.png +0 -0
  28. setiastro/images/astrosuite.ico +0 -0
  29. setiastro/images/astrosuite.png +0 -0
  30. setiastro/images/astrosuitepro.icns +0 -0
  31. setiastro/images/astrosuitepro.ico +0 -0
  32. setiastro/images/astrosuitepro.png +0 -0
  33. setiastro/images/background.png +0 -0
  34. setiastro/images/background2.png +0 -0
  35. setiastro/images/benchmark.png +0 -0
  36. setiastro/images/big_moon_stabilizer_timeline.png +0 -0
  37. setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
  38. setiastro/images/blaster.png +0 -0
  39. setiastro/images/blink.png +0 -0
  40. setiastro/images/clahe.png +0 -0
  41. setiastro/images/collage.png +0 -0
  42. setiastro/images/colorwheel.png +0 -0
  43. setiastro/images/contsub.png +0 -0
  44. setiastro/images/convo.png +0 -0
  45. setiastro/images/copyslot.png +0 -0
  46. setiastro/images/cosmic.png +0 -0
  47. setiastro/images/cosmicsat.png +0 -0
  48. setiastro/images/crop1.png +0 -0
  49. setiastro/images/cropicon.png +0 -0
  50. setiastro/images/curves.png +0 -0
  51. setiastro/images/cvs.png +0 -0
  52. setiastro/images/debayer.png +0 -0
  53. setiastro/images/denoise_cnn_custom.png +0 -0
  54. setiastro/images/denoise_cnn_graph.png +0 -0
  55. setiastro/images/disk.png +0 -0
  56. setiastro/images/dse.png +0 -0
  57. setiastro/images/exoicon.png +0 -0
  58. setiastro/images/eye.png +0 -0
  59. setiastro/images/first_quarter.png +0 -0
  60. setiastro/images/fliphorizontal.png +0 -0
  61. setiastro/images/flipvertical.png +0 -0
  62. setiastro/images/font.png +0 -0
  63. setiastro/images/freqsep.png +0 -0
  64. setiastro/images/full_moon.png +0 -0
  65. setiastro/images/functionbundle.png +0 -0
  66. setiastro/images/graxpert.png +0 -0
  67. setiastro/images/green.png +0 -0
  68. setiastro/images/gridicon.png +0 -0
  69. setiastro/images/halo.png +0 -0
  70. setiastro/images/hdr.png +0 -0
  71. setiastro/images/histogram.png +0 -0
  72. setiastro/images/hubble.png +0 -0
  73. setiastro/images/imagecombine.png +0 -0
  74. setiastro/images/invert.png +0 -0
  75. setiastro/images/isophote.png +0 -0
  76. setiastro/images/isophote_demo_figure.png +0 -0
  77. setiastro/images/isophote_demo_image.png +0 -0
  78. setiastro/images/isophote_demo_model.png +0 -0
  79. setiastro/images/isophote_demo_residual.png +0 -0
  80. setiastro/images/jwstpupil.png +0 -0
  81. setiastro/images/last_quarter.png +0 -0
  82. setiastro/images/linearfit.png +0 -0
  83. setiastro/images/livestacking.png +0 -0
  84. setiastro/images/mask.png +0 -0
  85. setiastro/images/maskapply.png +0 -0
  86. setiastro/images/maskcreate.png +0 -0
  87. setiastro/images/maskremove.png +0 -0
  88. setiastro/images/morpho.png +0 -0
  89. setiastro/images/mosaic.png +0 -0
  90. setiastro/images/multiscale_decomp.png +0 -0
  91. setiastro/images/nbtorgb.png +0 -0
  92. setiastro/images/neutral.png +0 -0
  93. setiastro/images/new_moon.png +0 -0
  94. setiastro/images/nuke.png +0 -0
  95. setiastro/images/openfile.png +0 -0
  96. setiastro/images/pedestal.png +0 -0
  97. setiastro/images/pen.png +0 -0
  98. setiastro/images/pixelmath.png +0 -0
  99. setiastro/images/platesolve.png +0 -0
  100. setiastro/images/ppp.png +0 -0
  101. setiastro/images/pro.png +0 -0
  102. setiastro/images/project.png +0 -0
  103. setiastro/images/psf.png +0 -0
  104. setiastro/images/redo.png +0 -0
  105. setiastro/images/redoicon.png +0 -0
  106. setiastro/images/rescale.png +0 -0
  107. setiastro/images/rgbalign.png +0 -0
  108. setiastro/images/rgbcombo.png +0 -0
  109. setiastro/images/rgbextract.png +0 -0
  110. setiastro/images/rotate180.png +0 -0
  111. setiastro/images/rotatearbitrary.png +0 -0
  112. setiastro/images/rotateclockwise.png +0 -0
  113. setiastro/images/rotatecounterclockwise.png +0 -0
  114. setiastro/images/satellite.png +0 -0
  115. setiastro/images/script.png +0 -0
  116. setiastro/images/selectivecolor.png +0 -0
  117. setiastro/images/simbad.png +0 -0
  118. setiastro/images/slot0.png +0 -0
  119. setiastro/images/slot1.png +0 -0
  120. setiastro/images/slot2.png +0 -0
  121. setiastro/images/slot3.png +0 -0
  122. setiastro/images/slot4.png +0 -0
  123. setiastro/images/slot5.png +0 -0
  124. setiastro/images/slot6.png +0 -0
  125. setiastro/images/slot7.png +0 -0
  126. setiastro/images/slot8.png +0 -0
  127. setiastro/images/slot9.png +0 -0
  128. setiastro/images/spcc.png +0 -0
  129. setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
  130. setiastro/images/spinner.gif +0 -0
  131. setiastro/images/stacking.png +0 -0
  132. setiastro/images/staradd.png +0 -0
  133. setiastro/images/staralign.png +0 -0
  134. setiastro/images/starnet.png +0 -0
  135. setiastro/images/starregistration.png +0 -0
  136. setiastro/images/starspike.png +0 -0
  137. setiastro/images/starstretch.png +0 -0
  138. setiastro/images/statstretch.png +0 -0
  139. setiastro/images/supernova.png +0 -0
  140. setiastro/images/uhs.png +0 -0
  141. setiastro/images/undoicon.png +0 -0
  142. setiastro/images/upscale.png +0 -0
  143. setiastro/images/viewbundle.png +0 -0
  144. setiastro/images/waning_crescent_1.png +0 -0
  145. setiastro/images/waning_crescent_2.png +0 -0
  146. setiastro/images/waning_crescent_3.png +0 -0
  147. setiastro/images/waning_crescent_4.png +0 -0
  148. setiastro/images/waning_crescent_5.png +0 -0
  149. setiastro/images/waning_gibbous_1.png +0 -0
  150. setiastro/images/waning_gibbous_2.png +0 -0
  151. setiastro/images/waning_gibbous_3.png +0 -0
  152. setiastro/images/waning_gibbous_4.png +0 -0
  153. setiastro/images/waning_gibbous_5.png +0 -0
  154. setiastro/images/waxing_crescent_1.png +0 -0
  155. setiastro/images/waxing_crescent_2.png +0 -0
  156. setiastro/images/waxing_crescent_3.png +0 -0
  157. setiastro/images/waxing_crescent_4.png +0 -0
  158. setiastro/images/waxing_crescent_5.png +0 -0
  159. setiastro/images/waxing_gibbous_1.png +0 -0
  160. setiastro/images/waxing_gibbous_2.png +0 -0
  161. setiastro/images/waxing_gibbous_3.png +0 -0
  162. setiastro/images/waxing_gibbous_4.png +0 -0
  163. setiastro/images/waxing_gibbous_5.png +0 -0
  164. setiastro/images/whitebalance.png +0 -0
  165. setiastro/images/wimi_icon_256x256.png +0 -0
  166. setiastro/images/wimilogo.png +0 -0
  167. setiastro/images/wims.png +0 -0
  168. setiastro/images/wrench_icon.png +0 -0
  169. setiastro/images/xisfliberator.png +0 -0
  170. setiastro/qml/ResourceMonitor.qml +128 -0
  171. setiastro/saspro/__init__.py +20 -0
  172. setiastro/saspro/__main__.py +964 -0
  173. setiastro/saspro/_generated/__init__.py +7 -0
  174. setiastro/saspro/_generated/build_info.py +3 -0
  175. setiastro/saspro/abe.py +1379 -0
  176. setiastro/saspro/abe_preset.py +196 -0
  177. setiastro/saspro/aberration_ai.py +910 -0
  178. setiastro/saspro/aberration_ai_preset.py +224 -0
  179. setiastro/saspro/accel_installer.py +218 -0
  180. setiastro/saspro/accel_workers.py +30 -0
  181. setiastro/saspro/acv_exporter.py +379 -0
  182. setiastro/saspro/add_stars.py +627 -0
  183. setiastro/saspro/astrobin_exporter.py +1010 -0
  184. setiastro/saspro/astrospike.py +153 -0
  185. setiastro/saspro/astrospike_python.py +1841 -0
  186. setiastro/saspro/autostretch.py +198 -0
  187. setiastro/saspro/backgroundneutral.py +639 -0
  188. setiastro/saspro/batch_convert.py +328 -0
  189. setiastro/saspro/batch_renamer.py +522 -0
  190. setiastro/saspro/blemish_blaster.py +494 -0
  191. setiastro/saspro/blink_comparator_pro.py +3149 -0
  192. setiastro/saspro/bundles.py +61 -0
  193. setiastro/saspro/bundles_dock.py +114 -0
  194. setiastro/saspro/cheat_sheet.py +213 -0
  195. setiastro/saspro/clahe.py +371 -0
  196. setiastro/saspro/comet_stacking.py +1442 -0
  197. setiastro/saspro/common_tr.py +107 -0
  198. setiastro/saspro/config.py +38 -0
  199. setiastro/saspro/config_bootstrap.py +40 -0
  200. setiastro/saspro/config_manager.py +316 -0
  201. setiastro/saspro/continuum_subtract.py +1620 -0
  202. setiastro/saspro/convo.py +1403 -0
  203. setiastro/saspro/convo_preset.py +414 -0
  204. setiastro/saspro/copyastro.py +190 -0
  205. setiastro/saspro/cosmicclarity.py +1593 -0
  206. setiastro/saspro/cosmicclarity_preset.py +407 -0
  207. setiastro/saspro/crop_dialog_pro.py +1005 -0
  208. setiastro/saspro/crop_preset.py +189 -0
  209. setiastro/saspro/curve_editor_pro.py +2608 -0
  210. setiastro/saspro/curves_preset.py +375 -0
  211. setiastro/saspro/debayer.py +673 -0
  212. setiastro/saspro/debug_utils.py +29 -0
  213. setiastro/saspro/dnd_mime.py +35 -0
  214. setiastro/saspro/doc_manager.py +2727 -0
  215. setiastro/saspro/exoplanet_detector.py +2258 -0
  216. setiastro/saspro/file_utils.py +284 -0
  217. setiastro/saspro/fitsmodifier.py +748 -0
  218. setiastro/saspro/fix_bom.py +32 -0
  219. setiastro/saspro/free_torch_memory.py +48 -0
  220. setiastro/saspro/frequency_separation.py +1352 -0
  221. setiastro/saspro/function_bundle.py +1596 -0
  222. setiastro/saspro/generate_translations.py +3092 -0
  223. setiastro/saspro/ghs_dialog_pro.py +728 -0
  224. setiastro/saspro/ghs_preset.py +284 -0
  225. setiastro/saspro/graxpert.py +638 -0
  226. setiastro/saspro/graxpert_preset.py +287 -0
  227. setiastro/saspro/gui/__init__.py +0 -0
  228. setiastro/saspro/gui/main_window.py +8928 -0
  229. setiastro/saspro/gui/mixins/__init__.py +33 -0
  230. setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
  231. setiastro/saspro/gui/mixins/file_mixin.py +450 -0
  232. setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
  233. setiastro/saspro/gui/mixins/header_mixin.py +441 -0
  234. setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
  235. setiastro/saspro/gui/mixins/menu_mixin.py +391 -0
  236. setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
  237. setiastro/saspro/gui/mixins/toolbar_mixin.py +1824 -0
  238. setiastro/saspro/gui/mixins/update_mixin.py +323 -0
  239. setiastro/saspro/gui/mixins/view_mixin.py +477 -0
  240. setiastro/saspro/gui/statistics_dialog.py +47 -0
  241. setiastro/saspro/halobgon.py +492 -0
  242. setiastro/saspro/header_viewer.py +448 -0
  243. setiastro/saspro/headless_utils.py +88 -0
  244. setiastro/saspro/histogram.py +760 -0
  245. setiastro/saspro/history_explorer.py +941 -0
  246. setiastro/saspro/i18n.py +168 -0
  247. setiastro/saspro/image_combine.py +421 -0
  248. setiastro/saspro/image_peeker_pro.py +1608 -0
  249. setiastro/saspro/imageops/__init__.py +37 -0
  250. setiastro/saspro/imageops/mdi_snap.py +292 -0
  251. setiastro/saspro/imageops/scnr.py +36 -0
  252. setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
  253. setiastro/saspro/imageops/stretch.py +236 -0
  254. setiastro/saspro/isophote.py +1186 -0
  255. setiastro/saspro/layers.py +208 -0
  256. setiastro/saspro/layers_dock.py +714 -0
  257. setiastro/saspro/lazy_imports.py +193 -0
  258. setiastro/saspro/legacy/__init__.py +2 -0
  259. setiastro/saspro/legacy/image_manager.py +2360 -0
  260. setiastro/saspro/legacy/numba_utils.py +3676 -0
  261. setiastro/saspro/legacy/xisf.py +1213 -0
  262. setiastro/saspro/linear_fit.py +537 -0
  263. setiastro/saspro/live_stacking.py +1854 -0
  264. setiastro/saspro/log_bus.py +5 -0
  265. setiastro/saspro/logging_config.py +460 -0
  266. setiastro/saspro/luminancerecombine.py +510 -0
  267. setiastro/saspro/main_helpers.py +201 -0
  268. setiastro/saspro/mask_creation.py +1090 -0
  269. setiastro/saspro/masks_core.py +56 -0
  270. setiastro/saspro/mdi_widgets.py +353 -0
  271. setiastro/saspro/memory_utils.py +666 -0
  272. setiastro/saspro/metadata_patcher.py +75 -0
  273. setiastro/saspro/mfdeconv.py +3909 -0
  274. setiastro/saspro/mfdeconv_earlystop.py +71 -0
  275. setiastro/saspro/mfdeconvcudnn.py +3312 -0
  276. setiastro/saspro/mfdeconvsport.py +2459 -0
  277. setiastro/saspro/minorbodycatalog.py +567 -0
  278. setiastro/saspro/morphology.py +411 -0
  279. setiastro/saspro/multiscale_decomp.py +1751 -0
  280. setiastro/saspro/nbtorgb_stars.py +541 -0
  281. setiastro/saspro/numba_utils.py +3145 -0
  282. setiastro/saspro/numba_warmup.py +141 -0
  283. setiastro/saspro/ops/__init__.py +9 -0
  284. setiastro/saspro/ops/command_help_dialog.py +623 -0
  285. setiastro/saspro/ops/command_runner.py +217 -0
  286. setiastro/saspro/ops/commands.py +1594 -0
  287. setiastro/saspro/ops/script_editor.py +1105 -0
  288. setiastro/saspro/ops/scripts.py +1476 -0
  289. setiastro/saspro/ops/settings.py +637 -0
  290. setiastro/saspro/parallel_utils.py +554 -0
  291. setiastro/saspro/pedestal.py +121 -0
  292. setiastro/saspro/perfect_palette_picker.py +1105 -0
  293. setiastro/saspro/pipeline.py +110 -0
  294. setiastro/saspro/pixelmath.py +1604 -0
  295. setiastro/saspro/plate_solver.py +2480 -0
  296. setiastro/saspro/project_io.py +797 -0
  297. setiastro/saspro/psf_utils.py +136 -0
  298. setiastro/saspro/psf_viewer.py +631 -0
  299. setiastro/saspro/pyi_rthook_astroquery.py +95 -0
  300. setiastro/saspro/remove_green.py +331 -0
  301. setiastro/saspro/remove_stars.py +1599 -0
  302. setiastro/saspro/remove_stars_preset.py +446 -0
  303. setiastro/saspro/resources.py +570 -0
  304. setiastro/saspro/rgb_combination.py +208 -0
  305. setiastro/saspro/rgb_extract.py +19 -0
  306. setiastro/saspro/rgbalign.py +727 -0
  307. setiastro/saspro/runtime_imports.py +7 -0
  308. setiastro/saspro/runtime_torch.py +754 -0
  309. setiastro/saspro/save_options.py +73 -0
  310. setiastro/saspro/selective_color.py +1614 -0
  311. setiastro/saspro/sfcc.py +1530 -0
  312. setiastro/saspro/shortcuts.py +3125 -0
  313. setiastro/saspro/signature_insert.py +1106 -0
  314. setiastro/saspro/stacking_suite.py +19069 -0
  315. setiastro/saspro/star_alignment.py +7383 -0
  316. setiastro/saspro/star_alignment_preset.py +329 -0
  317. setiastro/saspro/star_metrics.py +49 -0
  318. setiastro/saspro/star_spikes.py +769 -0
  319. setiastro/saspro/star_stretch.py +542 -0
  320. setiastro/saspro/stat_stretch.py +554 -0
  321. setiastro/saspro/status_log_dock.py +78 -0
  322. setiastro/saspro/subwindow.py +3523 -0
  323. setiastro/saspro/supernovaasteroidhunter.py +1719 -0
  324. setiastro/saspro/swap_manager.py +134 -0
  325. setiastro/saspro/torch_backend.py +89 -0
  326. setiastro/saspro/torch_rejection.py +434 -0
  327. setiastro/saspro/translations/all_source_strings.json +4726 -0
  328. setiastro/saspro/translations/ar_translations.py +4096 -0
  329. setiastro/saspro/translations/de_translations.py +3728 -0
  330. setiastro/saspro/translations/es_translations.py +4169 -0
  331. setiastro/saspro/translations/fr_translations.py +4090 -0
  332. setiastro/saspro/translations/hi_translations.py +3803 -0
  333. setiastro/saspro/translations/integrate_translations.py +271 -0
  334. setiastro/saspro/translations/it_translations.py +4728 -0
  335. setiastro/saspro/translations/ja_translations.py +3834 -0
  336. setiastro/saspro/translations/pt_translations.py +3847 -0
  337. setiastro/saspro/translations/ru_translations.py +3082 -0
  338. setiastro/saspro/translations/saspro_ar.qm +0 -0
  339. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  340. setiastro/saspro/translations/saspro_de.qm +0 -0
  341. setiastro/saspro/translations/saspro_de.ts +14548 -0
  342. setiastro/saspro/translations/saspro_es.qm +0 -0
  343. setiastro/saspro/translations/saspro_es.ts +16202 -0
  344. setiastro/saspro/translations/saspro_fr.qm +0 -0
  345. setiastro/saspro/translations/saspro_fr.ts +15870 -0
  346. setiastro/saspro/translations/saspro_hi.qm +0 -0
  347. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  348. setiastro/saspro/translations/saspro_it.qm +0 -0
  349. setiastro/saspro/translations/saspro_it.ts +19046 -0
  350. setiastro/saspro/translations/saspro_ja.qm +0 -0
  351. setiastro/saspro/translations/saspro_ja.ts +14980 -0
  352. setiastro/saspro/translations/saspro_pt.qm +0 -0
  353. setiastro/saspro/translations/saspro_pt.ts +15024 -0
  354. setiastro/saspro/translations/saspro_ru.qm +0 -0
  355. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  356. setiastro/saspro/translations/saspro_sw.qm +0 -0
  357. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  358. setiastro/saspro/translations/saspro_uk.qm +0 -0
  359. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  360. setiastro/saspro/translations/saspro_zh.qm +0 -0
  361. setiastro/saspro/translations/saspro_zh.ts +15289 -0
  362. setiastro/saspro/translations/sw_translations.py +3897 -0
  363. setiastro/saspro/translations/uk_translations.py +3929 -0
  364. setiastro/saspro/translations/zh_translations.py +3910 -0
  365. setiastro/saspro/versioning.py +77 -0
  366. setiastro/saspro/view_bundle.py +1558 -0
  367. setiastro/saspro/wavescale_hdr.py +648 -0
  368. setiastro/saspro/wavescale_hdr_preset.py +101 -0
  369. setiastro/saspro/wavescalede.py +683 -0
  370. setiastro/saspro/wavescalede_preset.py +230 -0
  371. setiastro/saspro/wcs_update.py +374 -0
  372. setiastro/saspro/whitebalance.py +540 -0
  373. setiastro/saspro/widgets/__init__.py +48 -0
  374. setiastro/saspro/widgets/common_utilities.py +306 -0
  375. setiastro/saspro/widgets/graphics_views.py +122 -0
  376. setiastro/saspro/widgets/image_utils.py +518 -0
  377. setiastro/saspro/widgets/minigame/game.js +991 -0
  378. setiastro/saspro/widgets/minigame/index.html +53 -0
  379. setiastro/saspro/widgets/minigame/style.css +241 -0
  380. setiastro/saspro/widgets/preview_dialogs.py +280 -0
  381. setiastro/saspro/widgets/resource_monitor.py +313 -0
  382. setiastro/saspro/widgets/spinboxes.py +290 -0
  383. setiastro/saspro/widgets/themed_buttons.py +13 -0
  384. setiastro/saspro/widgets/wavelet_utils.py +331 -0
  385. setiastro/saspro/wimi.py +7367 -0
  386. setiastro/saspro/wims.py +588 -0
  387. setiastro/saspro/window_shelf.py +185 -0
  388. setiastro/saspro/xisf.py +1213 -0
  389. setiastrosuitepro-1.6.7.dist-info/METADATA +279 -0
  390. setiastrosuitepro-1.6.7.dist-info/RECORD +394 -0
  391. setiastrosuitepro-1.6.7.dist-info/WHEEL +4 -0
  392. setiastrosuitepro-1.6.7.dist-info/entry_points.txt +6 -0
  393. setiastrosuitepro-1.6.7.dist-info/licenses/LICENSE +674 -0
  394. setiastrosuitepro-1.6.7.dist-info/licenses/license.txt +2580 -0
@@ -0,0 +1,477 @@
1
+ # pro/gui/mixins/view_mixin.py
2
+ """
3
+ View management mixin for AstroSuiteProMainWindow.
4
+
5
+ This mixin contains all view-related functionality: tiling, cascading,
6
+ zooming, autostretch, and view layout management.
7
+ """
8
+ from __future__ import annotations
9
+ import math
10
+ from typing import TYPE_CHECKING
11
+
12
+ from PyQt6.QtCore import Qt
13
+ from PyQt6.QtGui import QIcon
14
+
15
+ if TYPE_CHECKING:
16
+ pass
17
+
18
+
19
+ class ViewMixin:
20
+ """
21
+ Mixin for view management.
22
+
23
+ Provides methods for arranging, zooming, and managing MDI subwindows.
24
+ """
25
+
26
+ def _auto_fit_all_subwindows(self):
27
+ """Apply auto-fit to every visible subwindow when the mode is enabled."""
28
+ if not getattr(self, "_auto_fit_on_resize", False):
29
+ return
30
+
31
+ subs = self._visible_subwindows()
32
+ if not subs:
33
+ return
34
+
35
+ # Remember current active so we can restore it
36
+ prev_active = self.mdi.activeSubWindow()
37
+
38
+ for sw in subs:
39
+ # Make this subwindow active so _zoom_active_fit() works on it
40
+ self.mdi.setActiveSubWindow(sw)
41
+ self._zoom_active_fit()
42
+
43
+ # Restore previously active subwindow if still around
44
+ if prev_active and prev_active in subs:
45
+ self.mdi.setActiveSubWindow(prev_active)
46
+
47
+ def _visible_subwindows(self):
48
+ """Return list of visible, non-minimized subwindows."""
49
+ subs = [sw for sw in self.mdi.subWindowList()
50
+ if sw.isVisible() and not (sw.windowState() & Qt.WindowState.WindowMinimized)]
51
+ return subs
52
+
53
+
54
+ def _tile_views(self):
55
+ """Tile all subwindows."""
56
+ self.mdi.tileSubWindows()
57
+ self._auto_fit_all_subwindows()
58
+
59
+ def _tile_views_direction(self, direction: str):
60
+ """
61
+ Tile views in a specific direction.
62
+
63
+ Args:
64
+ direction: 'v' for vertical columns, 'h' for horizontal rows
65
+ """
66
+ subs = self._visible_subwindows()
67
+ if not subs:
68
+ return
69
+ area = self.mdi.viewport().rect()
70
+ # account for MDI viewport origin in global coords
71
+ off = self.mdi.viewport().mapTo(self.mdi, area.topLeft())
72
+ origin_x, origin_y = off.x(), off.y()
73
+
74
+ n = len(subs)
75
+ if direction == "v": # columns
76
+ col_w = max(1, area.width() // n)
77
+ for i, sw in enumerate(subs):
78
+ sw.setGeometry(origin_x + i*col_w, origin_y, col_w, area.height())
79
+ else: # rows
80
+ row_h = max(1, area.height() // n)
81
+ for i, sw in enumerate(subs):
82
+ sw.setGeometry(origin_x, origin_y + i*row_h, area.width(), row_h)
83
+
84
+ self._auto_fit_all_subwindows()
85
+
86
+ def _tile_views_grid(self):
87
+ """Arrange subwindows in a near-square grid across the MDI area."""
88
+ subs = self._visible_subwindows()
89
+ if not subs:
90
+ return
91
+ area = self.mdi.viewport().rect()
92
+ off = self.mdi.viewport().mapTo(self.mdi, area.topLeft())
93
+ origin_x, origin_y = off.x(), off.y()
94
+
95
+ n = len(subs)
96
+ # rows x cols ~ square
97
+ cols = int(max(1, math.ceil(math.sqrt(n))))
98
+ rows = int(max(1, math.ceil(n / cols)))
99
+
100
+ cell_w = max(1, area.width() // cols)
101
+ cell_h = max(1, area.height() // rows)
102
+
103
+ for idx, sw in enumerate(subs):
104
+ r = idx // cols
105
+ c = idx % cols
106
+ sw.setGeometry(origin_x + c*cell_w, origin_y + r*cell_h, cell_w, cell_h)
107
+
108
+ self._auto_fit_all_subwindows()
109
+
110
+ def _zoom_step_active(self, direction: int):
111
+ """
112
+ Zoom the active view in or out by a fixed factor.
113
+
114
+ Args:
115
+ direction: > 0 for zoom in, < 0 for zoom out
116
+ """
117
+ sw = self.mdi.activeSubWindow()
118
+ if not sw:
119
+ return
120
+
121
+ view = sw.widget()
122
+ try:
123
+ cur_scale = float(getattr(view, "scale", 1.0))
124
+ except Exception:
125
+ cur_scale = 1.0
126
+
127
+ # Reasonable step factor
128
+ step = 1.25
129
+ factor = step if direction > 0 else 1.0 / step
130
+
131
+ new_scale = cur_scale * factor
132
+ # Clamp to sane bounds
133
+ new_scale = max(1e-4, min(32.0, new_scale))
134
+
135
+ # Manual zoom -> we are no longer in a "perfect fit" state
136
+ try:
137
+ self.act_zoom_fit.setChecked(False)
138
+ except Exception:
139
+ pass
140
+
141
+ # Prefer anchor-based zoom so we keep the current scroll-center stable
142
+ if hasattr(view, "_zoom_at_anchor") and callable(view._zoom_at_anchor):
143
+ try:
144
+ rel = float(new_scale) / max(cur_scale, 1e-12)
145
+ view._zoom_at_anchor(rel)
146
+ return
147
+ except Exception:
148
+ pass
149
+
150
+ # Fallback: absolute set_scale without forcing recentering
151
+ if hasattr(view, "set_scale") and callable(view.set_scale):
152
+ try:
153
+ view.set_scale(float(new_scale))
154
+ return
155
+ except Exception:
156
+ pass
157
+
158
+ def _zoom_active_1_1(self):
159
+ """Zoom active view to 100% (1:1 pixel scale)."""
160
+ sw = self.mdi.activeSubWindow()
161
+ if not sw:
162
+ return
163
+ view = sw.widget()
164
+ if hasattr(view, "set_scale") and callable(view.set_scale):
165
+ try:
166
+ view.set_scale(1.0)
167
+ except Exception:
168
+ pass
169
+
170
+ def _zoom_active_fit(self):
171
+ """Fit the active view's image to its viewport."""
172
+ sw = self.mdi.activeSubWindow()
173
+ if not sw:
174
+ return
175
+ view = sw.widget()
176
+ self._zoom_active_1_1()
177
+
178
+ # Get sizes
179
+ img_w, img_h = self._infer_image_size(view)
180
+ if not img_w or not img_h:
181
+ return
182
+
183
+ vp = self._viewport_widget(view)
184
+ vw, vh = max(1, vp.width()), max(1, vp.height())
185
+
186
+ # Compute uniform scale (minus a hair to avoid scrollbars fighting)
187
+ scale = min((vw - 2) / img_w, (vh - 2) / img_h)
188
+ # Clamp to sane bounds
189
+ scale = max(1e-4, min(32.0, scale))
190
+ self._sync_fit_auto_visual()
191
+
192
+ # Apply using view API if available
193
+ if hasattr(view, "set_scale") and callable(view.set_scale):
194
+ try:
195
+ view.set_scale(float(scale))
196
+ self._ensure_smooth_resample(view)
197
+ self._center_view(view)
198
+ return
199
+ except Exception:
200
+ pass
201
+
202
+ # Fallback: relative zoom using _zoom_at_anchor
203
+ try:
204
+ cur = float(getattr(view, "scale", 1.0))
205
+ factor = scale / max(cur, 1e-12)
206
+ if hasattr(view, "_zoom_at_anchor") and callable(view._zoom_at_anchor):
207
+ view._zoom_at_anchor(float(factor))
208
+ self._center_view(view)
209
+ return
210
+ except Exception:
211
+ pass
212
+
213
+ def _ensure_smooth_resample(self, view):
214
+ """
215
+ Make sure the view is using smooth interpolation for the current scale.
216
+ Different view widgets in SASpro may implement this differently, so we
217
+ try a few known hooks safely.
218
+ """
219
+ # 1) Best case: explicit API
220
+ for name in ("set_smooth_scaling", "set_interpolation", "set_smooth", "enable_smooth_scaling"):
221
+ fn = getattr(view, name, None)
222
+ if callable(fn):
223
+ try:
224
+ fn(True)
225
+ return
226
+ except Exception:
227
+ pass
228
+
229
+ # 2) Some views store a mode flag
230
+ for attr in ("smooth_scaling", "_smooth_scaling", "_use_smooth_scaling", "use_smooth_scaling"):
231
+ if hasattr(view, attr):
232
+ try:
233
+ setattr(view, attr, True)
234
+ # kick a repaint/update if available
235
+ try:
236
+ view.update()
237
+ except Exception:
238
+ pass
239
+ return
240
+ except Exception:
241
+ pass
242
+
243
+ # 3) QLabel pixmap scaling: if you have a custom "rebuild pixmap" method, call it
244
+ for name in ("_rebuild_pixmap", "_update_pixmap", "_render_scaled", "rebuild_pixmap"):
245
+ fn = getattr(view, name, None)
246
+ if callable(fn):
247
+ try:
248
+ fn()
249
+ return
250
+ except Exception:
251
+ pass
252
+
253
+
254
+ def _infer_image_size(self, view):
255
+ """Return (img_w, img_h) in device-independent pixels (ints), best-effort."""
256
+ # Preferred: from the label's pixmap
257
+ try:
258
+ pm = getattr(view, "label", None).pixmap() if hasattr(view, "label") else None
259
+ if pm and not pm.isNull():
260
+ dpr = max(1.0, float(pm.devicePixelRatio()))
261
+ return int(round(pm.width() / dpr)), int(round(pm.height() / dpr))
262
+ except Exception:
263
+ pass
264
+
265
+ # Next: from the document image
266
+ try:
267
+ doc = getattr(view, "document", None)
268
+ if doc and getattr(doc, "image", None) is not None:
269
+ import numpy as np
270
+ h, w = np.asarray(doc.image).shape[:2]
271
+ return int(w), int(h)
272
+ except Exception:
273
+ pass
274
+
275
+ # Fallback: from attributes some views keep
276
+ for w_key, h_key in (("image_width", "image_height"), ("_img_w", "_img_h")):
277
+ w = getattr(view, w_key, None)
278
+ h = getattr(view, h_key, None)
279
+ if isinstance(w, (int, float)) and isinstance(h, (int, float)) and w > 0 and h > 0:
280
+ return int(w), int(h)
281
+
282
+ return None, None
283
+
284
+ def _viewport_widget(self, view):
285
+ """Return the viewport widget used to display the image."""
286
+ try:
287
+ if hasattr(view, "scroll") and hasattr(view.scroll, "viewport"):
288
+ return view.scroll.viewport()
289
+ # Some views are QGraphicsView/QAbstractScrollArea-like
290
+ if hasattr(view, "viewport"):
291
+ return view.viewport()
292
+ except Exception:
293
+ pass
294
+ # Worst case: the view itself
295
+ return view
296
+
297
+ def _center_view(self, view):
298
+ """Center the content after a zoom change, if possible."""
299
+ try:
300
+ vp = self._viewport_widget(view)
301
+ hbar = view.scroll.horizontalScrollBar() if hasattr(view, "scroll") else None
302
+ vbar = view.scroll.verticalScrollBar() if hasattr(view, "scroll") else None
303
+ lbl = getattr(view, "label", None)
304
+ if vp and hbar and vbar and lbl:
305
+ cx = max(0, lbl.width() // 2 - vp.width() // 2)
306
+ cy = max(0, lbl.height() // 2 - vp.height() // 2)
307
+ hbar.setValue(min(hbar.maximum(), cx))
308
+ vbar.setValue(min(vbar.maximum(), cy))
309
+ except Exception:
310
+ pass
311
+
312
+ def _sync_fit_auto_visual(self):
313
+ """Sync the Fit button's checked state with auto-fit mode."""
314
+ on = bool(getattr(self, "_auto_fit_on_resize", False))
315
+ if hasattr(self, "act_zoom_fit"):
316
+ self.act_zoom_fit.blockSignals(True)
317
+ try:
318
+ self.act_zoom_fit.setChecked(on)
319
+ finally:
320
+ self.act_zoom_fit.blockSignals(False)
321
+
322
+ def _toggle_auto_fit_on_resize(self, checked: bool):
323
+ """Toggle auto-fit on resize mode."""
324
+ self._auto_fit_on_resize = bool(checked)
325
+ self.settings.setValue("view/auto_fit_on_resize", self._auto_fit_on_resize)
326
+ self._sync_fit_auto_visual()
327
+ if checked:
328
+ self._zoom_active_fit()
329
+
330
+ def _on_view_resized(self):
331
+ """Called whenever an ImageSubWindow emits resized(). Debounced."""
332
+ if not getattr(self, "_auto_fit_on_resize", False):
333
+ return
334
+ if hasattr(self, "_auto_fit_timer") and self._auto_fit_timer is not None:
335
+ if self._auto_fit_timer.isActive():
336
+ self._auto_fit_timer.stop()
337
+ self._auto_fit_timer.start()
338
+
339
+ def _apply_auto_fit_resize(self):
340
+ """Run the actual Fit after the resize settles."""
341
+ if not getattr(self, "_auto_fit_on_resize", False):
342
+ return
343
+ self._zoom_active_fit()
344
+
345
+ def _toggle_autostretch(self, on: bool):
346
+ """Toggle autostretch for the active view."""
347
+ sw = self.mdi.activeSubWindow()
348
+ if sw:
349
+ sw.widget().set_autostretch(on)
350
+ self._log(f"Display-Stretch {'ON' if on else 'OFF'} -> {sw.windowTitle()}")
351
+
352
+ def _set_hard_autostretch_from_action(self, checked: bool):
353
+ """Set hard autostretch profile from toolbar action."""
354
+ from PyQt6.QtCore import QSignalBlocker
355
+
356
+ sw = self.mdi.activeSubWindow()
357
+ if not sw:
358
+ return
359
+ view = sw.widget()
360
+
361
+ # mirror the action's check to the view profile
362
+ if hasattr(view, "set_autostretch_profile"):
363
+ view.set_autostretch_profile("hard" if checked else "normal")
364
+
365
+ # ensure it's visible
366
+ if not getattr(view, "autostretch_enabled", False):
367
+ view.set_autostretch(True)
368
+ self._sync_autostretch_action(True)
369
+
370
+ self._log(f"Display-Stretch profile -> {'HARD' if checked else 'NORMAL'} ({sw.windowTitle()})")
371
+
372
+ def _toggle_hard_autostretch(self):
373
+ """Toggle between hard and normal autostretch profiles."""
374
+ from PyQt6.QtCore import QSignalBlocker
375
+
376
+ sw = self.mdi.activeSubWindow()
377
+ if not sw:
378
+ return
379
+ view = sw.widget()
380
+
381
+ # flip profile
382
+ new_profile = "hard" if not getattr(view, "is_hard_autostretch", lambda: False)() else "normal"
383
+ if hasattr(view, "set_autostretch_profile"):
384
+ view.set_autostretch_profile(new_profile)
385
+
386
+ # ensure autostretch is ON so the change is visible immediately
387
+ if not getattr(view, "autostretch_enabled", False):
388
+ view.set_autostretch(True)
389
+ self._sync_autostretch_action(True)
390
+
391
+ # reflect in toolbar button
392
+ with QSignalBlocker(self.act_hardstretch):
393
+ self.act_hardstretch.setChecked(new_profile == "hard")
394
+
395
+ self._log(f"Display-Stretch profile -> {new_profile.upper()} ({sw.windowTitle()})")
396
+
397
+ def _sync_autostretch_action(self, on: bool):
398
+ """Sync the autostretch action's checked state."""
399
+ from PyQt6.QtCore import QSignalBlocker
400
+
401
+ if hasattr(self, "act_autostretch"):
402
+ block = QSignalBlocker(self.act_autostretch)
403
+ self.act_autostretch.setChecked(bool(on))
404
+
405
+ def _edit_display_target(self):
406
+ """Open dialog to edit display stretch target median."""
407
+ from PyQt6.QtWidgets import QInputDialog
408
+
409
+ cur = float(self.settings.value("display/target", 0.30, type=float))
410
+ val, ok = QInputDialog.getDouble(
411
+ self, "Target Median", "Target (0.01 - 0.90):", cur, 0.01, 0.90, 3
412
+ )
413
+ if not ok:
414
+ return
415
+ self.settings.setValue("display/target", float(val))
416
+ sw = self.mdi.activeSubWindow()
417
+ if not sw:
418
+ return
419
+ view = sw.widget()
420
+ if hasattr(view, "set_autostretch_target"):
421
+ view.set_autostretch_target(float(val))
422
+ if not getattr(view, "autostretch_enabled", False):
423
+ if hasattr(view, "set_autostretch"):
424
+ view.set_autostretch(True)
425
+ self._sync_autostretch_action(True)
426
+
427
+ def _edit_display_sigma(self):
428
+ """Open dialog to edit display stretch sigma."""
429
+ from PyQt6.QtWidgets import QInputDialog
430
+
431
+ cur = float(self.settings.value("display/sigma", 5.0, type=float))
432
+ val, ok = QInputDialog.getDouble(
433
+ self, "Sigma", "Sigma (0.5 - 10.0):", cur, 0.5, 10.0, 2
434
+ )
435
+ if not ok:
436
+ return
437
+ self.settings.setValue("display/sigma", float(val))
438
+ sw = self.mdi.activeSubWindow()
439
+ if not sw:
440
+ return
441
+ view = sw.widget()
442
+ if hasattr(view, "set_autostretch_sigma"):
443
+ view.set_autostretch_sigma(float(val))
444
+ if not getattr(view, "autostretch_enabled", False):
445
+ if hasattr(view, "set_autostretch"):
446
+ view.set_autostretch(True)
447
+ self._sync_autostretch_action(True)
448
+
449
+ def _copy_active_view(self):
450
+ """Copy the current view state (zoom/pan) for pasting to other views."""
451
+ sw = self.mdi.activeSubWindow()
452
+ if not sw:
453
+ return
454
+ view = sw.widget()
455
+ self._copied_view_state = {
456
+ "scale": getattr(view, "scale", 1.0),
457
+ "hbar": view.scroll.horizontalScrollBar().value() if hasattr(view, "scroll") else 0,
458
+ "vbar": view.scroll.verticalScrollBar().value() if hasattr(view, "scroll") else 0,
459
+ }
460
+ self._log("View state copied")
461
+
462
+ def _paste_active_view(self):
463
+ """Paste a previously copied view state to the active view."""
464
+ if not getattr(self, "_copied_view_state", None):
465
+ return
466
+ sw = self.mdi.activeSubWindow()
467
+ if not sw:
468
+ return
469
+ view = sw.widget()
470
+ state = self._copied_view_state
471
+
472
+ if hasattr(view, "set_scale"):
473
+ view.set_scale(state.get("scale", 1.0))
474
+ if hasattr(view, "scroll"):
475
+ view.scroll.horizontalScrollBar().setValue(state.get("hbar", 0))
476
+ view.scroll.verticalScrollBar().setValue(state.get("vbar", 0))
477
+ self._log("View state pasted")
@@ -0,0 +1,47 @@
1
+ from PyQt6.QtWidgets import QDialog, QVBoxLayout, QLabel, QFormLayout, QPushButton
2
+ from PyQt6.QtCore import Qt, QSettings
3
+ from PyQt6.QtGui import QIcon
4
+
5
+ class StatisticsDialog(QDialog):
6
+ def __init__(self, parent=None):
7
+ super().__init__(parent)
8
+ self.setWindowTitle(self.tr("App Statistics"))
9
+ self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)
10
+ self.resize(300, 200)
11
+
12
+ # Settings to read stats
13
+ self.settings = QSettings("SetiAstro", "SetiAstroSuitePro")
14
+
15
+ layout = QVBoxLayout(self)
16
+
17
+ form_layout = QFormLayout()
18
+
19
+ # Time Spent
20
+ total_seconds = self.settings.value("stats/total_time_seconds", 0, type=float)
21
+ days = int(total_seconds // 86400)
22
+ hours = int((total_seconds % 86400) // 3600)
23
+ minutes = int((total_seconds % 3600) // 60)
24
+
25
+ time_str = f"{days} {self.tr('Days')}, {hours} {self.tr('Hours')}, {minutes} {self.tr('Minutes')}"
26
+ if days == 0:
27
+ time_str = f"{hours} {self.tr('Hours')}, {minutes} {self.tr('Minutes')}"
28
+
29
+ self.lbl_time = QLabel(time_str)
30
+ form_layout.addRow(self.tr("Time Spent:"), self.lbl_time)
31
+
32
+ # Images Opened
33
+ images_count = self.settings.value("stats/opened_images_count", 0, type=int)
34
+ self.lbl_images = QLabel(str(images_count))
35
+ form_layout.addRow(self.tr("Images Opened:"), self.lbl_images)
36
+
37
+ # Tools Opened
38
+ tools_count = self.settings.value("stats/opened_tools_count", 0, type=int)
39
+ self.lbl_tools = QLabel(str(tools_count))
40
+ form_layout.addRow(self.tr("Tools Opened:"), self.lbl_tools)
41
+
42
+ layout.addLayout(form_layout)
43
+
44
+ # Close button
45
+ btn_close = QPushButton(self.tr("Close"))
46
+ btn_close.clicked.connect(self.accept)
47
+ layout.addWidget(btn_close, alignment=Qt.AlignmentFlag.AlignRight)