setiastrosuitepro 1.6.0__py3-none-any.whl → 1.6.4.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 (293) hide show
  1. setiastro/data/SASP_data.fits +0 -0
  2. setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
  3. setiastro/data/catalogs/astrobin_filters.csv +890 -0
  4. setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
  5. setiastro/data/catalogs/cali2.csv +63 -0
  6. setiastro/data/catalogs/cali2color.csv +65 -0
  7. setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
  8. setiastro/data/catalogs/celestial_catalog.csv +24031 -0
  9. setiastro/data/catalogs/detected_stars.csv +24784 -0
  10. setiastro/data/catalogs/fits_header_data.csv +46 -0
  11. setiastro/data/catalogs/test.csv +8 -0
  12. setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
  13. setiastro/images/Astro_Spikes.png +0 -0
  14. setiastro/images/Background_startup.jpg +0 -0
  15. setiastro/images/HRDiagram.png +0 -0
  16. setiastro/images/LExtract.png +0 -0
  17. setiastro/images/LInsert.png +0 -0
  18. setiastro/images/Oxygenation-atm-2.svg.png +0 -0
  19. setiastro/images/RGB080604.png +0 -0
  20. setiastro/images/abeicon.png +0 -0
  21. setiastro/images/aberration.png +0 -0
  22. setiastro/images/andromedatry.png +0 -0
  23. setiastro/images/andromedatry_satellited.png +0 -0
  24. setiastro/images/annotated.png +0 -0
  25. setiastro/images/aperture.png +0 -0
  26. setiastro/images/astrosuite.ico +0 -0
  27. setiastro/images/astrosuite.png +0 -0
  28. setiastro/images/astrosuitepro.icns +0 -0
  29. setiastro/images/astrosuitepro.ico +0 -0
  30. setiastro/images/astrosuitepro.png +0 -0
  31. setiastro/images/background.png +0 -0
  32. setiastro/images/background2.png +0 -0
  33. setiastro/images/benchmark.png +0 -0
  34. setiastro/images/big_moon_stabilizer_timeline.png +0 -0
  35. setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
  36. setiastro/images/blaster.png +0 -0
  37. setiastro/images/blink.png +0 -0
  38. setiastro/images/clahe.png +0 -0
  39. setiastro/images/collage.png +0 -0
  40. setiastro/images/colorwheel.png +0 -0
  41. setiastro/images/contsub.png +0 -0
  42. setiastro/images/convo.png +0 -0
  43. setiastro/images/copyslot.png +0 -0
  44. setiastro/images/cosmic.png +0 -0
  45. setiastro/images/cosmicsat.png +0 -0
  46. setiastro/images/crop1.png +0 -0
  47. setiastro/images/cropicon.png +0 -0
  48. setiastro/images/curves.png +0 -0
  49. setiastro/images/cvs.png +0 -0
  50. setiastro/images/debayer.png +0 -0
  51. setiastro/images/denoise_cnn_custom.png +0 -0
  52. setiastro/images/denoise_cnn_graph.png +0 -0
  53. setiastro/images/disk.png +0 -0
  54. setiastro/images/dse.png +0 -0
  55. setiastro/images/exoicon.png +0 -0
  56. setiastro/images/eye.png +0 -0
  57. setiastro/images/fliphorizontal.png +0 -0
  58. setiastro/images/flipvertical.png +0 -0
  59. setiastro/images/font.png +0 -0
  60. setiastro/images/freqsep.png +0 -0
  61. setiastro/images/functionbundle.png +0 -0
  62. setiastro/images/graxpert.png +0 -0
  63. setiastro/images/green.png +0 -0
  64. setiastro/images/gridicon.png +0 -0
  65. setiastro/images/halo.png +0 -0
  66. setiastro/images/hdr.png +0 -0
  67. setiastro/images/histogram.png +0 -0
  68. setiastro/images/hubble.png +0 -0
  69. setiastro/images/imagecombine.png +0 -0
  70. setiastro/images/invert.png +0 -0
  71. setiastro/images/isophote.png +0 -0
  72. setiastro/images/isophote_demo_figure.png +0 -0
  73. setiastro/images/isophote_demo_image.png +0 -0
  74. setiastro/images/isophote_demo_model.png +0 -0
  75. setiastro/images/isophote_demo_residual.png +0 -0
  76. setiastro/images/jwstpupil.png +0 -0
  77. setiastro/images/linearfit.png +0 -0
  78. setiastro/images/livestacking.png +0 -0
  79. setiastro/images/mask.png +0 -0
  80. setiastro/images/maskapply.png +0 -0
  81. setiastro/images/maskcreate.png +0 -0
  82. setiastro/images/maskremove.png +0 -0
  83. setiastro/images/morpho.png +0 -0
  84. setiastro/images/mosaic.png +0 -0
  85. setiastro/images/multiscale_decomp.png +0 -0
  86. setiastro/images/nbtorgb.png +0 -0
  87. setiastro/images/neutral.png +0 -0
  88. setiastro/images/nuke.png +0 -0
  89. setiastro/images/openfile.png +0 -0
  90. setiastro/images/pedestal.png +0 -0
  91. setiastro/images/pen.png +0 -0
  92. setiastro/images/pixelmath.png +0 -0
  93. setiastro/images/platesolve.png +0 -0
  94. setiastro/images/ppp.png +0 -0
  95. setiastro/images/pro.png +0 -0
  96. setiastro/images/project.png +0 -0
  97. setiastro/images/psf.png +0 -0
  98. setiastro/images/redo.png +0 -0
  99. setiastro/images/redoicon.png +0 -0
  100. setiastro/images/rescale.png +0 -0
  101. setiastro/images/rgbalign.png +0 -0
  102. setiastro/images/rgbcombo.png +0 -0
  103. setiastro/images/rgbextract.png +0 -0
  104. setiastro/images/rotate180.png +0 -0
  105. setiastro/images/rotatearbitrary.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/__main__.py +228 -67
  146. setiastro/saspro/_generated/build_info.py +2 -1
  147. setiastro/saspro/abe.py +76 -25
  148. setiastro/saspro/aberration_ai.py +14 -14
  149. setiastro/saspro/add_stars.py +15 -12
  150. setiastro/saspro/astrobin_exporter.py +61 -58
  151. setiastro/saspro/astrospike_python.py +3 -1
  152. setiastro/saspro/autostretch.py +4 -2
  153. setiastro/saspro/backgroundneutral.py +65 -14
  154. setiastro/saspro/batch_convert.py +8 -5
  155. setiastro/saspro/batch_renamer.py +39 -36
  156. setiastro/saspro/blemish_blaster.py +15 -12
  157. setiastro/saspro/blink_comparator_pro.py +605 -379
  158. setiastro/saspro/cheat_sheet.py +62 -17
  159. setiastro/saspro/clahe.py +34 -8
  160. setiastro/saspro/comet_stacking.py +103 -38
  161. setiastro/saspro/common_tr.py +107 -0
  162. setiastro/saspro/continuum_subtract.py +7 -7
  163. setiastro/saspro/convo.py +12 -9
  164. setiastro/saspro/copyastro.py +3 -0
  165. setiastro/saspro/cosmicclarity.py +77 -52
  166. setiastro/saspro/crop_dialog_pro.py +80 -45
  167. setiastro/saspro/curve_editor_pro.py +51 -33
  168. setiastro/saspro/debayer.py +6 -3
  169. setiastro/saspro/doc_manager.py +49 -19
  170. setiastro/saspro/exoplanet_detector.py +11 -11
  171. setiastro/saspro/fitsmodifier.py +48 -44
  172. setiastro/saspro/fix_bom.py +32 -0
  173. setiastro/saspro/frequency_separation.py +18 -12
  174. setiastro/saspro/function_bundle.py +18 -16
  175. setiastro/saspro/generate_translations.py +3092 -0
  176. setiastro/saspro/ghs_dialog_pro.py +19 -16
  177. setiastro/saspro/graxpert.py +3 -0
  178. setiastro/saspro/gui/main_window.py +471 -126
  179. setiastro/saspro/gui/mixins/dock_mixin.py +123 -11
  180. setiastro/saspro/gui/mixins/file_mixin.py +25 -20
  181. setiastro/saspro/gui/mixins/geometry_mixin.py +115 -15
  182. setiastro/saspro/gui/mixins/header_mixin.py +6 -6
  183. setiastro/saspro/gui/mixins/mask_mixin.py +8 -8
  184. setiastro/saspro/gui/mixins/menu_mixin.py +62 -33
  185. setiastro/saspro/gui/mixins/toolbar_mixin.py +382 -226
  186. setiastro/saspro/gui/mixins/update_mixin.py +26 -26
  187. setiastro/saspro/gui/statistics_dialog.py +47 -0
  188. setiastro/saspro/halobgon.py +29 -3
  189. setiastro/saspro/header_viewer.py +21 -18
  190. setiastro/saspro/histogram.py +29 -26
  191. setiastro/saspro/history_explorer.py +2 -0
  192. setiastro/saspro/i18n.py +168 -0
  193. setiastro/saspro/image_combine.py +3 -0
  194. setiastro/saspro/image_peeker_pro.py +52 -44
  195. setiastro/saspro/imageops/stretch.py +5 -13
  196. setiastro/saspro/isophote.py +3 -0
  197. setiastro/saspro/legacy/numba_utils.py +64 -47
  198. setiastro/saspro/linear_fit.py +3 -0
  199. setiastro/saspro/live_stacking.py +13 -2
  200. setiastro/saspro/mask_creation.py +180 -22
  201. setiastro/saspro/mfdeconv.py +5 -0
  202. setiastro/saspro/morphology.py +38 -13
  203. setiastro/saspro/multiscale_decomp.py +713 -256
  204. setiastro/saspro/nbtorgb_stars.py +12 -2
  205. setiastro/saspro/numba_utils.py +149 -48
  206. setiastro/saspro/ops/scripts.py +77 -17
  207. setiastro/saspro/ops/settings.py +177 -100
  208. setiastro/saspro/perfect_palette_picker.py +25 -7
  209. setiastro/saspro/pixelmath.py +114 -110
  210. setiastro/saspro/plate_solver.py +118 -108
  211. setiastro/saspro/remove_green.py +24 -7
  212. setiastro/saspro/remove_stars.py +136 -162
  213. setiastro/saspro/remove_stars_preset.py +55 -13
  214. setiastro/saspro/resources.py +46 -15
  215. setiastro/saspro/rgb_combination.py +19 -18
  216. setiastro/saspro/rgbalign.py +11 -11
  217. setiastro/saspro/save_options.py +5 -4
  218. setiastro/saspro/selective_color.py +84 -25
  219. setiastro/saspro/sfcc.py +119 -72
  220. setiastro/saspro/shortcuts.py +345 -36
  221. setiastro/saspro/signature_insert.py +4 -1
  222. setiastro/saspro/stacking_suite.py +2066 -1119
  223. setiastro/saspro/star_alignment.py +291 -331
  224. setiastro/saspro/star_spikes.py +137 -53
  225. setiastro/saspro/star_stretch.py +47 -10
  226. setiastro/saspro/stat_stretch.py +52 -16
  227. setiastro/saspro/status_log_dock.py +1 -1
  228. setiastro/saspro/subwindow.py +97 -36
  229. setiastro/saspro/supernovaasteroidhunter.py +68 -61
  230. setiastro/saspro/swap_manager.py +77 -42
  231. setiastro/saspro/translations/all_source_strings.json +4726 -0
  232. setiastro/saspro/translations/ar_translations.py +4096 -0
  233. setiastro/saspro/translations/de_translations.py +3728 -0
  234. setiastro/saspro/translations/es_translations.py +4169 -0
  235. setiastro/saspro/translations/fr_translations.py +4090 -0
  236. setiastro/saspro/translations/hi_translations.py +3803 -0
  237. setiastro/saspro/translations/integrate_translations.py +271 -0
  238. setiastro/saspro/translations/it_translations.py +4728 -0
  239. setiastro/saspro/translations/ja_translations.py +3834 -0
  240. setiastro/saspro/translations/pt_translations.py +3847 -0
  241. setiastro/saspro/translations/ru_translations.py +3082 -0
  242. setiastro/saspro/translations/saspro_ar.qm +0 -0
  243. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  244. setiastro/saspro/translations/saspro_de.qm +0 -0
  245. setiastro/saspro/translations/saspro_de.ts +14548 -0
  246. setiastro/saspro/translations/saspro_es.qm +0 -0
  247. setiastro/saspro/translations/saspro_es.ts +16202 -0
  248. setiastro/saspro/translations/saspro_fr.qm +0 -0
  249. setiastro/saspro/translations/saspro_fr.ts +15870 -0
  250. setiastro/saspro/translations/saspro_hi.qm +0 -0
  251. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  252. setiastro/saspro/translations/saspro_it.qm +0 -0
  253. setiastro/saspro/translations/saspro_it.ts +19046 -0
  254. setiastro/saspro/translations/saspro_ja.qm +0 -0
  255. setiastro/saspro/translations/saspro_ja.ts +14980 -0
  256. setiastro/saspro/translations/saspro_pt.qm +0 -0
  257. setiastro/saspro/translations/saspro_pt.ts +15024 -0
  258. setiastro/saspro/translations/saspro_ru.qm +0 -0
  259. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  260. setiastro/saspro/translations/saspro_sw.qm +0 -0
  261. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  262. setiastro/saspro/translations/saspro_uk.qm +0 -0
  263. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  264. setiastro/saspro/translations/saspro_zh.qm +0 -0
  265. setiastro/saspro/translations/saspro_zh.ts +15289 -0
  266. setiastro/saspro/translations/sw_translations.py +3897 -0
  267. setiastro/saspro/translations/uk_translations.py +3929 -0
  268. setiastro/saspro/translations/zh_translations.py +3910 -0
  269. setiastro/saspro/versioning.py +77 -0
  270. setiastro/saspro/view_bundle.py +20 -17
  271. setiastro/saspro/wavescale_hdr.py +54 -33
  272. setiastro/saspro/wavescale_hdr_preset.py +6 -5
  273. setiastro/saspro/wavescalede.py +54 -31
  274. setiastro/saspro/wavescalede_preset.py +9 -7
  275. setiastro/saspro/whitebalance.py +58 -22
  276. setiastro/saspro/widgets/common_utilities.py +12 -11
  277. setiastro/saspro/widgets/minigame/game.js +991 -0
  278. setiastro/saspro/widgets/minigame/index.html +53 -0
  279. setiastro/saspro/widgets/minigame/style.css +241 -0
  280. setiastro/saspro/widgets/preview_dialogs.py +8 -8
  281. setiastro/saspro/widgets/resource_monitor.py +263 -0
  282. setiastro/saspro/widgets/spinboxes.py +18 -0
  283. setiastro/saspro/widgets/wavelet_utils.py +52 -20
  284. setiastro/saspro/wimi.py +7996 -0
  285. setiastro/saspro/wims.py +578 -0
  286. setiastro/saspro/window_shelf.py +2 -2
  287. {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/METADATA +15 -3
  288. setiastrosuitepro-1.6.4.post1.dist-info/RECORD +368 -0
  289. setiastrosuitepro-1.6.0.dist-info/RECORD +0 -174
  290. {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/WHEEL +0 -0
  291. {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/entry_points.txt +0 -0
  292. {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/LICENSE +0 -0
  293. {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/license.txt +0 -0
@@ -11,6 +11,7 @@ called via the `main()` function when invoked as an entry point.
11
11
 
12
12
  import sys
13
13
  import os
14
+ from PyQt6.QtCore import QCoreApplication
14
15
 
15
16
  # ---- Linux Qt stability guard (must run BEFORE any PyQt6 import) ----
16
17
  # Default behavior: DO NOT override Wayland.
@@ -34,6 +35,11 @@ _app = None
34
35
  # Flag to track if splash was initialized
35
36
  _splash_initialized = False
36
37
 
38
+ from setiastro.saspro.versioning import get_app_version
39
+ _EARLY_VERSION = get_app_version("setiastrosuitepro")
40
+
41
+ VERSION = _EARLY_VERSION
42
+
37
43
  def _init_splash():
38
44
  """Initialize the splash screen. Safe to call multiple times."""
39
45
  global _splash, _app, _splash_initialized
@@ -43,7 +49,8 @@ def _init_splash():
43
49
 
44
50
  # Minimal imports for splash screen
45
51
  from PyQt6.QtWidgets import QApplication, QWidget
46
- from PyQt6.QtCore import Qt, QCoreApplication, QRect
52
+ from PyQt6.QtCore import Qt, QCoreApplication, QRect, QPropertyAnimation, QEasingCurve
53
+ import time
47
54
  from PyQt6.QtGui import QGuiApplication, QIcon, QPixmap, QColor, QPainter, QFont, QLinearGradient
48
55
 
49
56
 
@@ -81,28 +88,37 @@ def _init_splash():
81
88
  except Exception:
82
89
  pass
83
90
 
91
+ # Determine icon paths early
84
92
  # Determine icon paths early
85
93
  def _find_icon_path():
86
- """Find the best available icon path."""
94
+ """Legacy fallback if resources import fails."""
87
95
  if hasattr(sys, '_MEIPASS'):
88
96
  base = sys._MEIPASS
89
97
  else:
90
- # When running from package, try to find images directory
91
98
  try:
92
99
  import setiastro
93
100
  package_dir = os.path.dirname(os.path.abspath(setiastro.__file__))
94
- # Check if images/ exists at package root level (for pip-installed packages)
95
101
  package_parent = os.path.dirname(package_dir)
96
102
  images_dir_installed = os.path.join(package_parent, 'images')
97
103
  if os.path.exists(images_dir_installed):
98
104
  base = package_parent
99
105
  else:
100
- # Try project root (for development)
101
- base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
106
+ base = os.path.dirname(
107
+ os.path.dirname(
108
+ os.path.dirname(
109
+ os.path.dirname(os.path.abspath(__file__))
110
+ )
111
+ )
112
+ )
102
113
  except (ImportError, AttributeError):
103
- # Fallback to project root relative to this file
104
- base = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
105
-
114
+ base = os.path.dirname(
115
+ os.path.dirname(
116
+ os.path.dirname(
117
+ os.path.dirname(os.path.abspath(__file__))
118
+ )
119
+ )
120
+ )
121
+
106
122
  candidates = [
107
123
  os.path.join(base, "images", "astrosuitepro.png"),
108
124
  os.path.join(base, "images", "astrosuitepro.ico"),
@@ -112,9 +128,25 @@ def _init_splash():
112
128
  for p in candidates:
113
129
  if os.path.exists(p):
114
130
  return p
115
- return candidates[0] # fallback
116
-
117
- _early_icon_path = _find_icon_path()
131
+ return "" # nothing found
132
+
133
+ # NEW: Prefer centralized resources resolver
134
+ try:
135
+ from setiastro.saspro.resources import icon_path, background_startup_path
136
+ _early_icon_path = icon_path
137
+ if not os.path.exists(_early_icon_path):
138
+ # fall back to legacy search if for some reason this is missing
139
+ _early_icon_path = _find_icon_path()
140
+
141
+ # Load startup background path
142
+ _startup_bg_path = background_startup_path
143
+ if not os.path.exists(_startup_bg_path):
144
+ _startup_bg_path = None
145
+
146
+ except Exception:
147
+ _early_icon_path = _find_icon_path()
148
+ _startup_bg_path = None
149
+
118
150
 
119
151
  # =========================================================================
120
152
  # PhotoshopStyleSplash - Custom splash screen widget
@@ -125,9 +157,9 @@ def _init_splash():
125
157
  """
126
158
  def __init__(self, logo_path: str):
127
159
  super().__init__()
128
- self._version = "1.6.0" # Hardcoded for early display
160
+ self._version = _EARLY_VERSION
129
161
  self._build = ""
130
- self.current_message = "Starting..."
162
+ self.current_message = QCoreApplication.translate("Splash", "Starting...")
131
163
  self.progress_value = 0
132
164
 
133
165
  # Window setup
@@ -155,6 +187,11 @@ def _init_splash():
155
187
  # Load and scale logo
156
188
  self.logo_pixmap = self._load_logo(logo_path)
157
189
 
190
+ # Load background image
191
+ self.bg_image_pixmap = QPixmap()
192
+ if _startup_bg_path:
193
+ self.bg_image_pixmap = QPixmap(_startup_bg_path)
194
+
158
195
  # Fonts
159
196
  self.title_font = QFont("Segoe UI", 28, QFont.Weight.Bold)
160
197
  self.subtitle_font = QFont("Segoe UI", 11)
@@ -193,15 +230,42 @@ def _init_splash():
193
230
  _app.processEvents()
194
231
 
195
232
  def setProgress(self, value: int):
196
- """Update progress (0-100)."""
197
- self.progress_value = max(0, min(100, value))
233
+ """Update progress (0-100) with smooth animation."""
234
+ target = max(0, min(100, value))
235
+ start = self.progress_value
236
+
237
+ # If jumping backwards or small change, just set it
238
+ if target <= start or (target - start) < 1:
239
+ self.progress_value = target
240
+ self.repaint()
241
+ if _app: _app.processEvents()
242
+ return
243
+
244
+ # Animate forward
245
+ steps = 15 # number of frames for the slide
246
+ # We want the total slide to take ~100-150ms max to feel responsive but smooth
247
+ dt = 0.005 # 5ms per frame
248
+
249
+ for i in range(1, steps + 1):
250
+ # Ease out interpolator
251
+ t = i / steps
252
+ # Quadratic ease out: f(t) = -t*(t-2)
253
+ factor = -t * (t - 2)
254
+
255
+ cur = start + (target - start) * factor
256
+ self.progress_value = cur
257
+ self.repaint()
258
+ if _app: _app.processEvents()
259
+ time.sleep(dt)
260
+
261
+ self.progress_value = target
198
262
  self.repaint()
199
263
  if _app:
200
264
  _app.processEvents()
201
265
 
202
266
  def setBuildInfo(self, version: str, build: str):
203
267
  """Update version and build info once available."""
204
- self._version = version
268
+ self._version = _EARLY_VERSION
205
269
  self._build = build
206
270
  self.repaint()
207
271
 
@@ -220,6 +284,45 @@ def _init_splash():
220
284
  gradient.setColorAt(1.0, QColor(10, 10, 20))
221
285
  painter.fillRect(0, 0, w, h, gradient)
222
286
 
287
+ # --- Background Image (Centered with Fade Out) ---
288
+ if not self.bg_image_pixmap.isNull():
289
+ # Create a temporary pixmap to handle the masking
290
+ temp = QPixmap(w, h)
291
+ temp.fill(Qt.GlobalColor.transparent)
292
+
293
+ ptmp = QPainter(temp)
294
+ ptmp.setRenderHint(QPainter.RenderHint.Antialiasing)
295
+ ptmp.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
296
+
297
+ # Scale image to cover the entire splash screen
298
+ scaled = self.bg_image_pixmap.scaled(
299
+ w, h,
300
+ Qt.AspectRatioMode.KeepAspectRatioByExpanding,
301
+ Qt.TransformationMode.SmoothTransformation
302
+ )
303
+
304
+ # Center the image
305
+ sx = (w - scaled.width()) // 2
306
+ sy = (h - scaled.height()) // 2
307
+ ptmp.drawPixmap(sx, sy, scaled)
308
+
309
+ # Apply Fade Out Mask (Gradient Alpha)
310
+ ptmp.setCompositionMode(QPainter.CompositionMode.CompositionMode_DestinationIn)
311
+ fade_gradient = QLinearGradient(0, 0, 0, h)
312
+ # Keep top half fully visible (subject to global opacity)
313
+ fade_gradient.setColorAt(0.0, QColor(0, 0, 0, 255))
314
+ fade_gradient.setColorAt(0.5, QColor(0, 0, 0, 255))
315
+ # Fade out completely at the bottom
316
+ fade_gradient.setColorAt(1.0, QColor(0, 0, 0, 0))
317
+ ptmp.fillRect(0, 0, w, h, fade_gradient)
318
+ ptmp.end()
319
+
320
+ # Draw combined result with 50% opacity
321
+ painter.save()
322
+ painter.setOpacity(0.25)
323
+ painter.drawPixmap(0, 0, temp)
324
+ painter.restore()
325
+
223
326
  # --- Subtle border ---
224
327
  painter.setPen(QColor(60, 60, 80))
225
328
  painter.drawRect(0, 0, w - 1, h - 1)
@@ -239,14 +342,14 @@ def _init_splash():
239
342
  # --- Subtitle with version ---
240
343
  painter.setFont(self.subtitle_font)
241
344
  painter.setPen(QColor(180, 180, 200))
242
- subtitle_text = f"Version {self._version}"
345
+ subtitle_text = QCoreApplication.translate("Splash", "Version {0}").format(self._version)
243
346
 
244
347
  if self._build:
245
348
  if self._build == "dev":
246
349
  # No build_info → running from source checkout
247
- subtitle_text += " • Running locally from source code"
350
+ subtitle_text += QCoreApplication.translate("Splash", " • Running locally from source code")
248
351
  else:
249
- subtitle_text += f" • Build {self._build}"
352
+ subtitle_text += QCoreApplication.translate("Splash", " • Build {0}").format(self._build)
250
353
 
251
354
  subtitle_rect = QRect(0, 270, w, 25)
252
355
  painter.drawText(subtitle_rect, Qt.AlignmentFlag.AlignCenter, subtitle_text)
@@ -290,20 +393,59 @@ def _init_splash():
290
393
  self.hide()
291
394
  self.close()
292
395
  self.deleteLater()
396
+
397
+ def start_fade_out(self):
398
+ """Smoothly fade out the splash screen."""
399
+ self._anim = QPropertyAnimation(self, b"windowOpacity")
400
+ self._anim.setDuration(1000)
401
+ self._anim.setStartValue(1.0)
402
+ self._anim.setEndValue(0.0)
403
+ self._anim.setEasingCurve(QEasingCurve.Type.OutQuad)
404
+ self._anim.finished.connect(self.finish)
405
+ self._anim.start()
293
406
 
407
+ def start_fade_in(self):
408
+ """Smoothly fade in the splash screen."""
409
+ self.setWindowOpacity(0.0)
410
+ self._anim = QPropertyAnimation(self, b"windowOpacity")
411
+ self._anim.setDuration(800)
412
+ self._anim.setStartValue(0.0)
413
+ self._anim.setEndValue(1.0)
414
+ self._anim.setEasingCurve(QEasingCurve.Type.InQuad)
415
+ self._anim.start()
416
+
294
417
  # --- Show splash IMMEDIATELY ---
295
418
  _splash = _EarlySplash(_early_icon_path)
419
+ _splash.start_fade_in()
296
420
  _splash.show()
297
- _splash.setMessage("Initializing Python runtime...")
421
+
422
+ # Block briefly to allow fade-in to progress smoothly before heavy imports start
423
+ # We use a busy loop with processEvents to keep the UI responsive during fade
424
+ t_start = time.time()
425
+ while time.time() - t_start < 0.85: # slightly longer than animation
426
+ _app.processEvents()
427
+ if _splash.windowOpacity() >= 0.99:
428
+ break
429
+ time.sleep(0.01)
430
+
431
+ _splash.setMessage(QCoreApplication.translate("Splash", "Initializing Python runtime..."))
298
432
  _splash.setProgress(2)
299
433
  _app.processEvents()
300
434
 
435
+ # Load translation BEFORE any other widgets are created
436
+ try:
437
+ from setiastro.saspro.i18n import load_language, get_translations_dir
438
+ ok = load_language(app=_app)
439
+ except Exception as e:
440
+ print("i18n load failed:", repr(e))
441
+
442
+
301
443
  _splash_initialized = True
302
444
 
303
445
 
304
- # Initialize splash if running as main module
305
- if __name__ == "__main__":
306
- _init_splash()
446
+ # Initialize splash immediately before any heavy imports
447
+ # This ensures the splash is visible while PyTorch, NumPy, etc. are loading
448
+ _init_splash()
307
449
 
308
450
 
309
451
  # =============================================================================
@@ -317,7 +459,7 @@ def _update_splash(msg: str, progress: int):
317
459
  _splash.setMessage(msg)
318
460
  _splash.setProgress(progress)
319
461
 
320
- _update_splash("Loading PyTorch runtime...", 5)
462
+ _update_splash(QCoreApplication.translate("Splash", "Loading PyTorch runtime..."), 5)
321
463
 
322
464
  from setiastro.saspro.runtime_torch import (
323
465
  add_runtime_to_sys_path,
@@ -329,7 +471,7 @@ add_runtime_to_sys_path(status_cb=lambda *_: None)
329
471
  _ban_shadow_torch_paths(status_cb=lambda *_: None)
330
472
  _purge_bad_torch_from_sysmodules(status_cb=lambda *_: None)
331
473
 
332
- _update_splash("Loading standard libraries...", 10)
474
+ _update_splash(QCoreApplication.translate("Splash", "Loading standard libraries..."), 10)
333
475
 
334
476
  # ----------------------------------------
335
477
  # Standard library imports (consolidated)
@@ -358,18 +500,18 @@ from pathlib import Path
358
500
  from typing import Dict, List, Optional, Set, Tuple
359
501
  from urllib.parse import quote, quote_plus
360
502
 
361
- _update_splash("Loading NumPy...", 15)
503
+ _update_splash(QCoreApplication.translate("Splash", "Loading NumPy..."), 15)
362
504
 
363
505
  # ----------------------------------------
364
506
  # Third-party imports
365
507
  # ----------------------------------------
366
508
  import numpy as np
367
509
 
368
- _update_splash("Loading image libraries...", 20)
510
+ _update_splash(QCoreApplication.translate("Splash", "Loading image libraries..."), 20)
369
511
  from tifffile import imwrite
370
512
  from setiastro.saspro.xisf import XISF
371
513
 
372
- _update_splash("Configuring matplotlib...", 25)
514
+ _update_splash(QCoreApplication.translate("Splash", "Configuring matplotlib..."), 25)
373
515
  from setiastro.saspro.config_bootstrap import ensure_mpl_config_dir
374
516
  _MPL_CFG_DIR = ensure_mpl_config_dir()
375
517
 
@@ -440,7 +582,7 @@ def get_lightkurve():
440
582
  return _lightkurve_module if _lightkurve_module else None
441
583
  # --- End lazy imports ---
442
584
 
443
- _update_splash("Loading UI utilities...", 30)
585
+ _update_splash(QCoreApplication.translate("Splash", "Loading UI utilities..."), 30)
444
586
 
445
587
  # Shared UI utilities (avoiding code duplication)
446
588
  from setiastro.saspro.widgets.common_utilities import (
@@ -451,7 +593,7 @@ from setiastro.saspro.widgets.common_utilities import (
451
593
  install_crash_handlers,
452
594
  )
453
595
 
454
- _update_splash("Loading reproject library...", 35)
596
+ _update_splash(QCoreApplication.translate("Splash", "Loading reproject library..."), 35)
455
597
 
456
598
  # Reproject for WCS-based alignment
457
599
  try:
@@ -459,7 +601,7 @@ try:
459
601
  except ImportError:
460
602
  reproject_interp = None # fallback if not installed
461
603
 
462
- _update_splash("Loading OpenCV...", 40)
604
+ _update_splash(QCoreApplication.translate("Splash", "Loading OpenCV..."), 40)
463
605
 
464
606
  # OpenCV for transform estimation & warping
465
607
  try:
@@ -469,7 +611,7 @@ except ImportError:
469
611
  OPENCV_AVAILABLE = False
470
612
 
471
613
 
472
- _update_splash("Loading PyQt6 components...", 45)
614
+ _update_splash(QCoreApplication.translate("Splash", "Loading PyQt6 components..."), 45)
473
615
 
474
616
  #################################
475
617
  # PyQt6 Imports
@@ -487,7 +629,8 @@ from PyQt6.QtGui import (QPixmap, QColor, QIcon, QKeySequence, QShortcut, QGuiAp
487
629
  )
488
630
 
489
631
  # ----- QtCore -----
490
- from PyQt6.QtCore import (Qt, pyqtSignal, QCoreApplication, QTimer, QSize, QSignalBlocker, QModelIndex, QThread, QUrl, QSettings, QEvent, QByteArray, QObject
632
+ from PyQt6.QtCore import (Qt, pyqtSignal, QCoreApplication, QTimer, QSize, QSignalBlocker, QModelIndex, QThread, QUrl, QSettings, QEvent, QByteArray, QObject,
633
+ QPropertyAnimation, QEasingCurve
491
634
  )
492
635
 
493
636
  from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
@@ -500,14 +643,8 @@ except Exception:
500
643
  BUILD_TIMESTAMP = "dev"
501
644
 
502
645
 
503
- try:
504
- from importlib.metadata import version as _get_version
505
- VERSION = _get_version("setiastrosuitepro")
506
- except Exception:
507
- # Fallback if package not installed (e.g. running from source without install)
508
- VERSION = "1.6.0-dev"
509
646
 
510
- _update_splash("Loading resources...", 50)
647
+ _update_splash(QCoreApplication.translate("Splash", "Loading resources..."), 50)
511
648
 
512
649
  # Icon paths are now centralized in setiastro.saspro.resources module
513
650
  from setiastro.saspro.resources import (
@@ -536,7 +673,7 @@ from setiastro.saspro.resources import (
536
673
  )
537
674
 
538
675
 
539
- _update_splash("Configuring Qt message handler...", 55)
676
+ _update_splash(QCoreApplication.translate("Splash", "Configuring Qt message handler..."), 55)
540
677
 
541
678
  from PyQt6.QtCore import qInstallMessageHandler, QtMsgType
542
679
 
@@ -552,7 +689,7 @@ def _qt_msg_handler(mode, ctx, msg):
552
689
 
553
690
  qInstallMessageHandler(_qt_msg_handler)
554
691
 
555
- _update_splash("Loading MDI widgets...", 60)
692
+ _update_splash(QCoreApplication.translate("Splash", "Loading MDI widgets..."), 60)
556
693
 
557
694
  # MDI widgets imported from setiastro.saspro.mdi_widgets
558
695
  from setiastro.saspro.mdi_widgets import (
@@ -582,11 +719,11 @@ from setiastro.saspro.file_utils import (
582
719
  WIN_RESERVED_NAMES as _WIN_RESERVED,
583
720
  )
584
721
 
585
- _update_splash("Loading main window module...", 65)
722
+ _update_splash(QCoreApplication.translate("Splash", "Loading main window module..."), 65)
586
723
 
587
724
  from setiastro.saspro.gui.main_window import AstroSuiteProMainWindow
588
725
 
589
- _update_splash("Modules loaded, finalizing...", 70)
726
+ _update_splash(QCoreApplication.translate("Splash", "Modules loaded, finalizing..."), 70)
590
727
 
591
728
 
592
729
  def main():
@@ -607,7 +744,7 @@ def main():
607
744
  # Update splash with build info now that we have VERSION and BUILD_TIMESTAMP
608
745
  if _splash:
609
746
  _splash.setBuildInfo(VERSION, BUILD_TIMESTAMP)
610
- _splash.setMessage("Setting up logging...")
747
+ _splash.setMessage(QCoreApplication.translate("Splash", "Setting up logging..."))
611
748
  _splash.setProgress(72)
612
749
 
613
750
  # --- Logging (catch unhandled exceptions to a file) ---
@@ -674,14 +811,14 @@ def main():
674
811
 
675
812
  # Setup crash handlers and app icon
676
813
  if _splash:
677
- _splash.setMessage("Installing crash handlers...")
814
+ _splash.setMessage(QCoreApplication.translate("Splash", "Installing crash handlers..."))
678
815
  _splash.setProgress(75)
679
816
  install_crash_handlers(_app)
680
817
  _app.setWindowIcon(QIcon(windowslogo_path if os.path.exists(windowslogo_path) else icon_path))
681
818
 
682
819
  # --- Windows exe / multiprocessing friendly ---
683
820
  if _splash:
684
- _splash.setMessage("Configuring multiprocessing...")
821
+ _splash.setMessage(QCoreApplication.translate("Splash", "Configuring multiprocessing..."))
685
822
  _splash.setProgress(78)
686
823
  try:
687
824
  multiprocessing.freeze_support()
@@ -695,23 +832,23 @@ def main():
695
832
 
696
833
  try:
697
834
  if _splash:
698
- _splash.setMessage("Loading image manager...")
835
+ _splash.setMessage(QCoreApplication.translate("Splash", "Loading image manager..."))
699
836
  _splash.setProgress(80)
700
837
  from setiastro.saspro.legacy.image_manager import ImageManager
701
838
 
702
839
  if _splash:
703
- _splash.setMessage("Suppressing warnings...")
840
+ _splash.setMessage(QCoreApplication.translate("Splash", "Suppressing warnings..."))
704
841
  _splash.setProgress(82)
705
842
  from matplotlib import MatplotlibDeprecationWarning
706
843
  warnings.filterwarnings("ignore", category=MatplotlibDeprecationWarning)
707
844
 
708
845
  if _splash:
709
- _splash.setMessage("Creating image manager...")
846
+ _splash.setMessage(QCoreApplication.translate("Splash", "Creating image manager..."))
710
847
  _splash.setProgress(85)
711
848
  imgr = ImageManager(max_slots=100)
712
849
 
713
850
  if _splash:
714
- _splash.setMessage("Building main window...")
851
+ _splash.setMessage(QCoreApplication.translate("Splash", "Building main window..."))
715
852
  _splash.setProgress(90)
716
853
  win = AstroSuiteProMainWindow(
717
854
  image_manager=imgr,
@@ -720,9 +857,35 @@ def main():
720
857
  )
721
858
 
722
859
  if _splash:
723
- _splash.setMessage("Showing main window...")
860
+ _splash.setMessage(QCoreApplication.translate("Splash", "Showing main window..."))
724
861
  _splash.setProgress(95)
862
+
863
+ # --- Smooth Transition: App Fade In + Splash Fade Out ---
864
+ # MITIGATION: Prevent "White Flash" on startup
865
+ # 1. Force a dark background immediately so if opacity lags, it's dark not white
866
+ win.setStyleSheet("QMainWindow { background-color: #0F0F19; }")
867
+ # 2. Ensure native window handle exists so setWindowOpacity works immediately
868
+ win.winId()
869
+ # 3. Set opacity to 0
870
+ win.setWindowOpacity(0.0)
871
+
725
872
  win.show()
873
+
874
+ # 1. Animate Main Window Fade In
875
+ anim_app = QPropertyAnimation(win, b"windowOpacity")
876
+ anim_app.setDuration(1200)
877
+ anim_app.setStartValue(0.0)
878
+ anim_app.setEndValue(1.0)
879
+ anim_app.setEasingCurve(QEasingCurve.Type.OutQuad)
880
+
881
+ # Cleanup temp stylesheet upon completion to avoid interfering with ThemeMixin
882
+ def _on_fade_in_finished():
883
+ win.setStyleSheet("")
884
+ if hasattr(win, "on_fade_in_complete"):
885
+ win.on_fade_in_complete()
886
+
887
+ anim_app.finished.connect(_on_fade_in_finished)
888
+ anim_app.start()
726
889
 
727
890
  # Start background Numba warmup after UI is visible
728
891
  try:
@@ -732,22 +895,20 @@ def main():
732
895
  pass # Non-critical if warmup fails
733
896
 
734
897
  if _splash:
735
- _splash.setMessage("Ready!")
898
+ _splash.setMessage(QCoreApplication.translate("Splash", "Ready!"))
736
899
  _splash.setProgress(100)
737
900
  _app.processEvents()
738
901
 
739
- # Small delay to show "Ready!" before closing
902
+ # Small delay to ensure "Ready!" is seen briefly before fade starts
740
903
  import time
741
- time.sleep(0.3)
742
- _app.processEvents()
743
-
744
- # Ensure the splash cannot resurrect later:
745
- try:
746
- _splash.finish()
747
- finally:
748
- _splash.hide()
749
- _splash.close()
750
- _splash.deleteLater()
904
+ time.sleep(0.1)
905
+
906
+ # 2. Animate Splash Fade Out
907
+ # Note: We do NOT use finish() directly here. The animation calls it when done.
908
+ _splash.start_fade_out()
909
+
910
+ # NOTE: We keep a reference to _splash (global) so it doesn't get GC'd during animation.
911
+ # It will deleteLater() itself.
751
912
 
752
913
  if BUILD_TIMESTAMP == "dev":
753
914
  build_label = "running from local source code"
@@ -770,8 +931,8 @@ def main():
770
931
  logging.error("Unhandled exception occurred\n%s", tb)
771
932
  msg = QMessageBox(None)
772
933
  msg.setIcon(QMessageBox.Icon.Critical)
773
- msg.setWindowTitle("Application Error")
774
- msg.setText("An unexpected error occurred.")
934
+ msg.setWindowTitle(QCoreApplication.translate("Main", "Application Error"))
935
+ msg.setText(QCoreApplication.translate("Main", "An unexpected error occurred."))
775
936
  msg.setInformativeText(tb.splitlines()[-1] if tb else "See details.")
776
937
  msg.setDetailedText(tb)
777
938
  msg.setStandardButtons(QMessageBox.StandardButton.Ok)
@@ -1,2 +1,3 @@
1
1
  # Auto-generated at build time. Do not edit.
2
- BUILD_TIMESTAMP = "2025-12-17T02:57:36Z"
2
+ BUILD_TIMESTAMP = "2025-12-27T21:45:37Z"
3
+ APP_VERSION = "1.6.4.post1"