setiastrosuitepro 1.6.1__py3-none-any.whl → 1.6.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. setiastro/images/Background_startup.jpg +0 -0
  2. setiastro/qml/ResourceMonitor.qml +126 -0
  3. setiastro/saspro/__main__.py +159 -23
  4. setiastro/saspro/_generated/build_info.py +2 -1
  5. setiastro/saspro/abe.py +62 -11
  6. setiastro/saspro/aberration_ai.py +3 -3
  7. setiastro/saspro/add_stars.py +5 -2
  8. setiastro/saspro/astrobin_exporter.py +3 -0
  9. setiastro/saspro/astrospike_python.py +3 -1
  10. setiastro/saspro/autostretch.py +4 -2
  11. setiastro/saspro/backgroundneutral.py +52 -10
  12. setiastro/saspro/batch_convert.py +3 -0
  13. setiastro/saspro/batch_renamer.py +3 -0
  14. setiastro/saspro/blemish_blaster.py +3 -0
  15. setiastro/saspro/cheat_sheet.py +50 -15
  16. setiastro/saspro/clahe.py +27 -1
  17. setiastro/saspro/comet_stacking.py +103 -38
  18. setiastro/saspro/convo.py +3 -0
  19. setiastro/saspro/copyastro.py +3 -0
  20. setiastro/saspro/cosmicclarity.py +70 -45
  21. setiastro/saspro/crop_dialog_pro.py +17 -0
  22. setiastro/saspro/curve_editor_pro.py +18 -0
  23. setiastro/saspro/debayer.py +3 -0
  24. setiastro/saspro/doc_manager.py +39 -16
  25. setiastro/saspro/fitsmodifier.py +3 -0
  26. setiastro/saspro/frequency_separation.py +8 -2
  27. setiastro/saspro/function_bundle.py +2 -0
  28. setiastro/saspro/generate_translations.py +715 -1
  29. setiastro/saspro/ghs_dialog_pro.py +3 -0
  30. setiastro/saspro/graxpert.py +3 -0
  31. setiastro/saspro/gui/main_window.py +275 -32
  32. setiastro/saspro/gui/mixins/dock_mixin.py +100 -1
  33. setiastro/saspro/gui/mixins/file_mixin.py +7 -0
  34. setiastro/saspro/gui/mixins/menu_mixin.py +28 -0
  35. setiastro/saspro/gui/statistics_dialog.py +47 -0
  36. setiastro/saspro/halobgon.py +29 -3
  37. setiastro/saspro/histogram.py +3 -0
  38. setiastro/saspro/history_explorer.py +2 -0
  39. setiastro/saspro/i18n.py +22 -10
  40. setiastro/saspro/image_combine.py +3 -0
  41. setiastro/saspro/image_peeker_pro.py +3 -0
  42. setiastro/saspro/imageops/stretch.py +5 -13
  43. setiastro/saspro/isophote.py +3 -0
  44. setiastro/saspro/legacy/numba_utils.py +64 -47
  45. setiastro/saspro/linear_fit.py +3 -0
  46. setiastro/saspro/live_stacking.py +13 -2
  47. setiastro/saspro/mask_creation.py +3 -0
  48. setiastro/saspro/mfdeconv.py +5 -0
  49. setiastro/saspro/morphology.py +30 -5
  50. setiastro/saspro/multiscale_decomp.py +3 -0
  51. setiastro/saspro/nbtorgb_stars.py +12 -2
  52. setiastro/saspro/numba_utils.py +148 -47
  53. setiastro/saspro/ops/scripts.py +77 -17
  54. setiastro/saspro/ops/settings.py +1 -43
  55. setiastro/saspro/perfect_palette_picker.py +1 -0
  56. setiastro/saspro/pixelmath.py +6 -2
  57. setiastro/saspro/plate_solver.py +2 -1
  58. setiastro/saspro/remove_green.py +18 -1
  59. setiastro/saspro/remove_stars.py +136 -162
  60. setiastro/saspro/resources.py +7 -0
  61. setiastro/saspro/rgb_combination.py +1 -0
  62. setiastro/saspro/rgbalign.py +4 -4
  63. setiastro/saspro/save_options.py +1 -0
  64. setiastro/saspro/sfcc.py +50 -8
  65. setiastro/saspro/signature_insert.py +3 -0
  66. setiastro/saspro/stacking_suite.py +630 -341
  67. setiastro/saspro/star_alignment.py +16 -1
  68. setiastro/saspro/star_spikes.py +116 -32
  69. setiastro/saspro/star_stretch.py +38 -1
  70. setiastro/saspro/stat_stretch.py +35 -3
  71. setiastro/saspro/subwindow.py +63 -2
  72. setiastro/saspro/supernovaasteroidhunter.py +3 -0
  73. setiastro/saspro/translations/all_source_strings.json +3654 -0
  74. setiastro/saspro/translations/ar_translations.py +3865 -0
  75. setiastro/saspro/translations/de_translations.py +16 -0
  76. setiastro/saspro/translations/es_translations.py +16 -0
  77. setiastro/saspro/translations/fr_translations.py +16 -0
  78. setiastro/saspro/translations/hi_translations.py +3571 -0
  79. setiastro/saspro/translations/integrate_translations.py +36 -0
  80. setiastro/saspro/translations/it_translations.py +16 -0
  81. setiastro/saspro/translations/ja_translations.py +16 -0
  82. setiastro/saspro/translations/pt_translations.py +16 -0
  83. setiastro/saspro/translations/ru_translations.py +2848 -0
  84. setiastro/saspro/translations/saspro_ar.qm +0 -0
  85. setiastro/saspro/translations/saspro_ar.ts +255 -0
  86. setiastro/saspro/translations/saspro_de.qm +0 -0
  87. setiastro/saspro/translations/saspro_de.ts +3 -3
  88. setiastro/saspro/translations/saspro_es.qm +0 -0
  89. setiastro/saspro/translations/saspro_es.ts +3 -3
  90. setiastro/saspro/translations/saspro_fr.qm +0 -0
  91. setiastro/saspro/translations/saspro_fr.ts +3 -3
  92. setiastro/saspro/translations/saspro_hi.qm +0 -0
  93. setiastro/saspro/translations/saspro_hi.ts +257 -0
  94. setiastro/saspro/translations/saspro_it.qm +0 -0
  95. setiastro/saspro/translations/saspro_it.ts +3 -3
  96. setiastro/saspro/translations/saspro_ja.qm +0 -0
  97. setiastro/saspro/translations/saspro_ja.ts +4 -4
  98. setiastro/saspro/translations/saspro_pt.qm +0 -0
  99. setiastro/saspro/translations/saspro_pt.ts +3 -3
  100. setiastro/saspro/translations/saspro_ru.qm +0 -0
  101. setiastro/saspro/translations/saspro_ru.ts +237 -0
  102. setiastro/saspro/translations/saspro_sw.qm +0 -0
  103. setiastro/saspro/translations/saspro_sw.ts +257 -0
  104. setiastro/saspro/translations/saspro_uk.qm +0 -0
  105. setiastro/saspro/translations/saspro_uk.ts +10771 -0
  106. setiastro/saspro/translations/saspro_zh.qm +0 -0
  107. setiastro/saspro/translations/saspro_zh.ts +3 -3
  108. setiastro/saspro/translations/sw_translations.py +3671 -0
  109. setiastro/saspro/translations/uk_translations.py +3700 -0
  110. setiastro/saspro/translations/zh_translations.py +16 -0
  111. setiastro/saspro/versioning.py +12 -6
  112. setiastro/saspro/view_bundle.py +3 -0
  113. setiastro/saspro/wavescale_hdr.py +22 -1
  114. setiastro/saspro/wavescalede.py +23 -1
  115. setiastro/saspro/whitebalance.py +39 -3
  116. setiastro/saspro/widgets/minigame/game.js +986 -0
  117. setiastro/saspro/widgets/minigame/index.html +53 -0
  118. setiastro/saspro/widgets/minigame/style.css +241 -0
  119. setiastro/saspro/widgets/resource_monitor.py +237 -0
  120. setiastro/saspro/widgets/wavelet_utils.py +52 -20
  121. setiastro/saspro/wimi.py +7996 -0
  122. setiastro/saspro/wims.py +578 -0
  123. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/METADATA +15 -4
  124. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/RECORD +128 -103
  125. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/WHEEL +0 -0
  126. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/entry_points.txt +0 -0
  127. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/licenses/LICENSE +0 -0
  128. {setiastrosuitepro-1.6.1.dist-info → setiastrosuitepro-1.6.2.dist-info}/licenses/license.txt +0 -0
@@ -59,7 +59,9 @@ TRANSLATIONS_ZH = {
59
59
  "Post-alignment failed: {0}": "后对齐失败:{0}",
60
60
  },
61
61
  "AstroSuiteProMainWindow": {
62
+ "Start a new project? This closes all views and clears desktop shortcuts.": "开始新项目?这将关闭所有视图并清除桌面快捷方式。",
62
63
  "&About": "关于(&A)",
64
+ "Statistics...": "统计...",
63
65
  "&Edit": "编辑(&E)",
64
66
  "&File": "文件(&F)",
65
67
  "&Functions": "功能(&U)",
@@ -1135,6 +1137,7 @@ TRANSLATIONS_ZH = {
1135
1137
  "Value": "值",
1136
1138
  },
1137
1139
  "FileMixin": {
1140
+ "Start a new project? This closes all views and clears desktop shortcuts.": "开始新项目?这将关闭所有视图并清除桌面快捷方式。",
1138
1141
  "Failed to save:\n{e}": "保存失败:\n{e}",
1139
1142
  "Failed to save:\n{msg}": "保存失败:\n{msg}",
1140
1143
  "File not found": "未找到文件",
@@ -1698,6 +1701,8 @@ TRANSLATIONS_ZH = {
1698
1701
  "Selective Color Correction": "选择性颜色校正",
1699
1702
  },
1700
1703
  "SettingsDialog": {
1704
+ "Restart required": "需要重启",
1705
+ "Language changed. Please manually restart the application to apply the new language.": "语言已更改。请手动重启应用以应用新语言。",
1701
1706
  "ASTAP executable:": "ASTAP 可执行文件:",
1702
1707
  "Astrometry.net API key:": "Astrometry.net API 密钥:",
1703
1708
  "Check Now…": "立即检查…",
@@ -3656,4 +3661,15 @@ TRANSLATIONS_ZH = {
3656
3661
  "Success": "成功",
3657
3662
  "View in Aladin": "在 Aladin 中查看",
3658
3663
  },
3664
+
3665
+ "StatisticsDialog": {
3666
+ "App Statistics": "应用统计",
3667
+ "Time Spent:": "花费时间:",
3668
+ "Images Opened:": "打开的图像:",
3669
+ "Tools Opened:": "打开的工具:",
3670
+ "Days": "天",
3671
+ "Hours": "小时",
3672
+ "Minutes": "分钟",
3673
+ "Close": "关闭",
3674
+ },
3659
3675
  }
@@ -46,26 +46,32 @@ def get_app_version(dist_name: str = "setiastrosuitepro") -> str:
46
46
  Single source of truth for SASpro version.
47
47
 
48
48
  Order:
49
- 1) installed distribution metadata (best for packaged installs)
49
+ 0) build_info.py (best for PyInstaller frozen builds)
50
+ 1) installed distribution metadata (best for pip installs)
50
51
  2) pyproject.toml (best for running from source checkout)
51
52
  3) safe fallback
52
53
  """
53
- # 1) Installed package metadata (when it matches)
54
+ # 0) build_info (PyInstaller-friendly)
55
+ try:
56
+ from ._generated.build_info import APP_VERSION
57
+ if isinstance(APP_VERSION, str) and APP_VERSION.strip() and APP_VERSION.strip() != "0.0.0":
58
+ return APP_VERSION.strip()
59
+ except Exception:
60
+ pass
61
+
62
+ # 1) Installed package metadata
54
63
  try:
55
64
  from importlib.metadata import version as _dist_version
56
65
  v = _dist_version(dist_name)
57
- # If you want to *avoid* accidentally picking up a stale installed 0.1.0,
58
- # you can reject that known-bad default:
59
66
  if v and v != "0.1.0":
60
67
  return v
61
68
  except Exception:
62
69
  pass
63
70
 
64
- # 2) Source tree pyproject.toml (walk from this file upward)
71
+ # 2) Source tree pyproject.toml
65
72
  here = Path(__file__).resolve()
66
73
  v2 = _read_pyproject_version(here.parent)
67
74
  if v2:
68
75
  return v2
69
76
 
70
- # 3) Frozen / unknown: fallback
71
77
  return "0.0.0"
@@ -378,6 +378,7 @@ class SelectViewsDialog(QDialog):
378
378
  super().__init__(parent)
379
379
  self.setWindowTitle("Add Views to Bundle")
380
380
  self.setWindowFlag(Qt.WindowType.Window, True)
381
+ self.setWindowModality(Qt.WindowModality.NonModal)
381
382
  self.setModal(False)
382
383
  #self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
383
384
  self._boxes: list[QCheckBox] = []
@@ -510,6 +511,8 @@ class ViewBundleDialog(QDialog):
510
511
  super().__init__(parent)
511
512
  _pin_on_top_mac(self)
512
513
  self.setWindowTitle("View Bundles")
514
+ self.setWindowFlag(Qt.WindowType.Window, True)
515
+ self.setWindowModality(Qt.WindowModality.NonModal)
513
516
  self.setModal(False)
514
517
  self.resize(900, 540)
515
518
  self.setAcceptDrops(True)
@@ -199,6 +199,9 @@ class WaveScaleHDRDialogPro(QDialog):
199
199
  import logging
200
200
  logging.debug(f"Exception suppressed: {type(e).__name__}: {e}")
201
201
  self.resize(980, 700)
202
+ self.setWindowFlag(Qt.WindowType.Window, True)
203
+ self.setWindowModality(Qt.WindowModality.NonModal)
204
+ self.setModal(False)
202
205
 
203
206
  self._doc = doc
204
207
  base = getattr(doc, "image", None)
@@ -606,8 +609,26 @@ class WaveScaleHDRDialogPro(QDialog):
606
609
  except Exception:
607
610
  pass
608
611
 
609
- self.accept()
612
+ # Dialog stays open so user can apply to other images
613
+ # Refresh document reference for next operation
614
+ self._refresh_document_from_active()
610
615
 
616
+ def _refresh_document_from_active(self):
617
+ """
618
+ Refresh the dialog's document reference to the currently active document.
619
+ This allows reusing the same dialog on different images.
620
+ """
621
+ try:
622
+ main = self.parent()
623
+ if main and hasattr(main, "_active_doc"):
624
+ new_doc = main._active_doc()
625
+ if new_doc is not None and new_doc is not self._doc:
626
+ self._doc = new_doc
627
+ # Reset L channel and refresh preview for new document
628
+ self._L_original = None
629
+ self._last_preview = None
630
+ except Exception:
631
+ pass
611
632
 
612
633
 
613
634
  def _schedule_mask_refresh(self, _value):
@@ -201,6 +201,9 @@ class WaveScaleDarkEnhancerDialogPro(QDialog):
201
201
  import logging
202
202
  logging.debug(f"Exception suppressed: {type(e).__name__}: {e}")
203
203
  self.resize(980, 700)
204
+ self.setWindowFlag(Qt.WindowType.Window, True)
205
+ self.setWindowModality(Qt.WindowModality.NonModal)
206
+ self.setModal(False)
204
207
 
205
208
  self._doc = doc
206
209
  base = getattr(doc, "image", None)
@@ -581,7 +584,26 @@ class WaveScaleDarkEnhancerDialogPro(QDialog):
581
584
  # Never let replay wiring break the apply
582
585
  pass
583
586
 
584
- self.accept()
587
+ # Dialog stays open so user can apply to other images
588
+ # Refresh document reference for next operation
589
+ self._refresh_document_from_active()
590
+
591
+ def _refresh_document_from_active(self):
592
+ """
593
+ Refresh the dialog's document reference to the currently active document.
594
+ This allows reusing the same dialog on different images.
595
+ """
596
+ try:
597
+ main = self.parent()
598
+ if main and hasattr(main, "_active_doc"):
599
+ new_doc = main._active_doc()
600
+ if new_doc is not None and new_doc is not self._doc:
601
+ self._doc = new_doc
602
+ # Reset state and refresh for new document
603
+ self._L_original = None
604
+ self._last_preview = None
605
+ except Exception:
606
+ pass
585
607
 
586
608
 
587
609
  # ─────────────────────────────────────────────────────────────────────────────
@@ -191,10 +191,18 @@ def apply_white_balance_to_doc(doc, preset: Optional[Dict] = None):
191
191
  class WhiteBalanceDialog(QDialog):
192
192
  def __init__(self, parent, doc, icon: QIcon | None = None):
193
193
  super().__init__(parent)
194
+ self._main = parent
194
195
  self.doc = doc
196
+
197
+ # Connect to active document change signal
198
+ if hasattr(self._main, "currentDocumentChanged"):
199
+ self._main.currentDocumentChanged.connect(self._on_active_doc_changed)
195
200
  if icon:
196
201
  self.setWindowIcon(icon)
197
202
  self.setWindowTitle(self.tr("White Balance"))
203
+ self.setWindowFlag(Qt.WindowType.Window, True)
204
+ self.setWindowModality(Qt.WindowModality.NonModal)
205
+ self.setModal(False)
198
206
  self.resize(900, 600)
199
207
 
200
208
  self._build_ui()
@@ -291,6 +299,18 @@ class WhiteBalanceDialog(QDialog):
291
299
  self.manual_group.setVisible(t == "Manual")
292
300
  self.star_group.setVisible(t == "Star-Based")
293
301
 
302
+ # ---- active document change ------------------------------------
303
+ def _on_active_doc_changed(self, doc):
304
+ """Called when user clicks a different image window."""
305
+ if doc is None or getattr(doc, "image", None) is None:
306
+ return
307
+ self.doc = doc
308
+ # Force fresh star detection by temporarily disabling cache
309
+ old_reuse = self.chk_reuse.isChecked()
310
+ self.chk_reuse.setChecked(False)
311
+ self._update_star_preview()
312
+ self.chk_reuse.setChecked(old_reuse)
313
+
294
314
  # ---- preview --------------------------------------------------------
295
315
  def _update_star_preview(self):
296
316
  if self.type_combo.currentText() != "Star-Based":
@@ -373,7 +393,8 @@ class WhiteBalanceDialog(QDialog):
373
393
 
374
394
  # Use the headless helper so doc metadata is consistent
375
395
  apply_white_balance_to_doc(self.doc, preset)
376
- self.accept()
396
+ # Dialog stays open - refresh document for next operation
397
+ self._refresh_document_from_active()
377
398
 
378
399
  elif mode == "Auto":
379
400
  preset = {"mode": "auto"}
@@ -382,7 +403,8 @@ class WhiteBalanceDialog(QDialog):
382
403
  _record_preset_for_replay(preset)
383
404
 
384
405
  apply_white_balance_to_doc(self.doc, preset)
385
- self.accept()
406
+ # Dialog stays open - refresh document for next operation
407
+ self._refresh_document_from_active()
386
408
 
387
409
  else: # --- Star-Based: compute here so we can plot like SASv2 ---
388
410
  thr = float(self.thr_slider.value())
@@ -449,8 +471,22 @@ class WhiteBalanceDialog(QDialog):
449
471
  self.tr("White Balance"),
450
472
  self.tr("Star-Based WB applied.\nDetected {0} stars.").format(int(star_count)),
451
473
  )
452
- self.accept()
474
+ # Dialog stays open - refresh document for next operation
475
+ self._refresh_document_from_active()
453
476
 
454
477
  except Exception as e:
455
478
  QMessageBox.critical(self, self.tr("White Balance"), self.tr("Failed to apply White Balance:\n{0}").format(e))
456
479
 
480
+ def _refresh_document_from_active(self):
481
+ """
482
+ Refresh the dialog's document reference to the currently active document.
483
+ This allows reusing the same dialog on different images.
484
+ """
485
+ try:
486
+ main = self.parent()
487
+ if main and hasattr(main, "_active_doc"):
488
+ new_doc = main._active_doc()
489
+ if new_doc is not None and new_doc is not self.doc:
490
+ self.doc = new_doc
491
+ except Exception:
492
+ pass