setiastrosuitepro 1.6.2__py3-none-any.whl → 1.6.12__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 (162) hide show
  1. setiastro/images/abeicon.svg +16 -0
  2. setiastro/images/acv_icon.png +0 -0
  3. setiastro/images/colorwheel.svg +97 -0
  4. setiastro/images/cosmic.svg +40 -0
  5. setiastro/images/cosmicsat.svg +24 -0
  6. setiastro/images/first_quarter.png +0 -0
  7. setiastro/images/full_moon.png +0 -0
  8. setiastro/images/graxpert.svg +19 -0
  9. setiastro/images/last_quarter.png +0 -0
  10. setiastro/images/linearfit.svg +32 -0
  11. setiastro/images/new_moon.png +0 -0
  12. setiastro/images/pixelmath.svg +42 -0
  13. setiastro/images/rotatearbitrary.png +0 -0
  14. setiastro/images/waning_crescent_1.png +0 -0
  15. setiastro/images/waning_crescent_2.png +0 -0
  16. setiastro/images/waning_crescent_3.png +0 -0
  17. setiastro/images/waning_crescent_4.png +0 -0
  18. setiastro/images/waning_crescent_5.png +0 -0
  19. setiastro/images/waning_gibbous_1.png +0 -0
  20. setiastro/images/waning_gibbous_2.png +0 -0
  21. setiastro/images/waning_gibbous_3.png +0 -0
  22. setiastro/images/waning_gibbous_4.png +0 -0
  23. setiastro/images/waning_gibbous_5.png +0 -0
  24. setiastro/images/waxing_crescent_1.png +0 -0
  25. setiastro/images/waxing_crescent_2.png +0 -0
  26. setiastro/images/waxing_crescent_3.png +0 -0
  27. setiastro/images/waxing_crescent_4.png +0 -0
  28. setiastro/images/waxing_crescent_5.png +0 -0
  29. setiastro/images/waxing_gibbous_1.png +0 -0
  30. setiastro/images/waxing_gibbous_2.png +0 -0
  31. setiastro/images/waxing_gibbous_3.png +0 -0
  32. setiastro/images/waxing_gibbous_4.png +0 -0
  33. setiastro/images/waxing_gibbous_5.png +0 -0
  34. setiastro/qml/ResourceMonitor.qml +84 -82
  35. setiastro/saspro/__main__.py +20 -1
  36. setiastro/saspro/_generated/build_info.py +2 -2
  37. setiastro/saspro/abe.py +37 -4
  38. setiastro/saspro/aberration_ai.py +237 -21
  39. setiastro/saspro/acv_exporter.py +379 -0
  40. setiastro/saspro/add_stars.py +33 -6
  41. setiastro/saspro/backgroundneutral.py +114 -37
  42. setiastro/saspro/blemish_blaster.py +4 -1
  43. setiastro/saspro/blink_comparator_pro.py +548 -275
  44. setiastro/saspro/clahe.py +4 -1
  45. setiastro/saspro/continuum_subtract.py +4 -1
  46. setiastro/saspro/convo.py +13 -7
  47. setiastro/saspro/cosmicclarity.py +129 -18
  48. setiastro/saspro/crop_dialog_pro.py +134 -8
  49. setiastro/saspro/curve_editor_pro.py +109 -42
  50. setiastro/saspro/doc_manager.py +246 -16
  51. setiastro/saspro/exoplanet_detector.py +120 -28
  52. setiastro/saspro/frequency_separation.py +1158 -204
  53. setiastro/saspro/function_bundle.py +16 -16
  54. setiastro/saspro/ghs_dialog_pro.py +81 -16
  55. setiastro/saspro/graxpert.py +1 -0
  56. setiastro/saspro/gui/main_window.py +519 -289
  57. setiastro/saspro/gui/mixins/dock_mixin.py +276 -42
  58. setiastro/saspro/gui/mixins/geometry_mixin.py +105 -5
  59. setiastro/saspro/gui/mixins/menu_mixin.py +28 -1
  60. setiastro/saspro/gui/mixins/theme_mixin.py +160 -14
  61. setiastro/saspro/gui/mixins/toolbar_mixin.py +416 -27
  62. setiastro/saspro/gui/mixins/update_mixin.py +138 -36
  63. setiastro/saspro/gui/mixins/view_mixin.py +42 -0
  64. setiastro/saspro/halobgon.py +4 -0
  65. setiastro/saspro/histogram.py +5 -1
  66. setiastro/saspro/image_combine.py +4 -0
  67. setiastro/saspro/image_peeker_pro.py +4 -0
  68. setiastro/saspro/imageops/starbasedwhitebalance.py +23 -52
  69. setiastro/saspro/imageops/stretch.py +582 -62
  70. setiastro/saspro/isophote.py +4 -0
  71. setiastro/saspro/layers.py +13 -9
  72. setiastro/saspro/layers_dock.py +183 -3
  73. setiastro/saspro/legacy/image_manager.py +154 -20
  74. setiastro/saspro/legacy/numba_utils.py +67 -47
  75. setiastro/saspro/legacy/xisf.py +240 -98
  76. setiastro/saspro/live_stacking.py +180 -79
  77. setiastro/saspro/luminancerecombine.py +228 -27
  78. setiastro/saspro/mask_creation.py +174 -15
  79. setiastro/saspro/mfdeconv.py +113 -35
  80. setiastro/saspro/mfdeconvcudnn.py +119 -70
  81. setiastro/saspro/mfdeconvsport.py +112 -35
  82. setiastro/saspro/morphology.py +4 -0
  83. setiastro/saspro/multiscale_decomp.py +748 -255
  84. setiastro/saspro/numba_utils.py +72 -57
  85. setiastro/saspro/ops/commands.py +18 -18
  86. setiastro/saspro/ops/script_editor.py +10 -2
  87. setiastro/saspro/ops/scripts.py +122 -0
  88. setiastro/saspro/perfect_palette_picker.py +37 -3
  89. setiastro/saspro/plate_solver.py +84 -49
  90. setiastro/saspro/psf_viewer.py +119 -37
  91. setiastro/saspro/remove_stars_preset.py +55 -13
  92. setiastro/saspro/resources.py +97 -11
  93. setiastro/saspro/rgbalign.py +4 -0
  94. setiastro/saspro/selective_color.py +83 -21
  95. setiastro/saspro/sfcc.py +364 -152
  96. setiastro/saspro/shortcuts.py +253 -49
  97. setiastro/saspro/signature_insert.py +692 -33
  98. setiastro/saspro/stacking_suite.py +1610 -574
  99. setiastro/saspro/star_alignment.py +522 -453
  100. setiastro/saspro/star_spikes.py +4 -0
  101. setiastro/saspro/star_stretch.py +38 -3
  102. setiastro/saspro/stat_stretch.py +743 -128
  103. setiastro/saspro/status_log_dock.py +1 -1
  104. setiastro/saspro/subwindow.py +786 -360
  105. setiastro/saspro/supernovaasteroidhunter.py +1 -1
  106. setiastro/saspro/swap_manager.py +77 -42
  107. setiastro/saspro/translations/all_source_strings.json +1588 -516
  108. setiastro/saspro/translations/ar_translations.py +915 -684
  109. setiastro/saspro/translations/de_translations.py +442 -463
  110. setiastro/saspro/translations/es_translations.py +277 -47
  111. setiastro/saspro/translations/fr_translations.py +279 -47
  112. setiastro/saspro/translations/hi_translations.py +253 -21
  113. setiastro/saspro/translations/integrate_translations.py +3 -2
  114. setiastro/saspro/translations/it_translations.py +1211 -161
  115. setiastro/saspro/translations/ja_translations.py +3340 -3107
  116. setiastro/saspro/translations/pt_translations.py +3315 -3337
  117. setiastro/saspro/translations/ru_translations.py +351 -117
  118. setiastro/saspro/translations/saspro_ar.qm +0 -0
  119. setiastro/saspro/translations/saspro_ar.ts +15902 -138
  120. setiastro/saspro/translations/saspro_de.qm +0 -0
  121. setiastro/saspro/translations/saspro_de.ts +14428 -133
  122. setiastro/saspro/translations/saspro_es.qm +0 -0
  123. setiastro/saspro/translations/saspro_es.ts +11503 -7821
  124. setiastro/saspro/translations/saspro_fr.qm +0 -0
  125. setiastro/saspro/translations/saspro_fr.ts +11168 -7812
  126. setiastro/saspro/translations/saspro_hi.qm +0 -0
  127. setiastro/saspro/translations/saspro_hi.ts +14733 -135
  128. setiastro/saspro/translations/saspro_it.qm +0 -0
  129. setiastro/saspro/translations/saspro_it.ts +14347 -7821
  130. setiastro/saspro/translations/saspro_ja.qm +0 -0
  131. setiastro/saspro/translations/saspro_ja.ts +14860 -137
  132. setiastro/saspro/translations/saspro_pt.qm +0 -0
  133. setiastro/saspro/translations/saspro_pt.ts +14904 -137
  134. setiastro/saspro/translations/saspro_ru.qm +0 -0
  135. setiastro/saspro/translations/saspro_ru.ts +11766 -168
  136. setiastro/saspro/translations/saspro_sw.qm +0 -0
  137. setiastro/saspro/translations/saspro_sw.ts +15115 -135
  138. setiastro/saspro/translations/saspro_uk.qm +0 -0
  139. setiastro/saspro/translations/saspro_uk.ts +11206 -6729
  140. setiastro/saspro/translations/saspro_zh.qm +0 -0
  141. setiastro/saspro/translations/saspro_zh.ts +10581 -7812
  142. setiastro/saspro/translations/sw_translations.py +282 -56
  143. setiastro/saspro/translations/uk_translations.py +264 -35
  144. setiastro/saspro/translations/zh_translations.py +282 -47
  145. setiastro/saspro/view_bundle.py +17 -17
  146. setiastro/saspro/wavescale_hdr.py +4 -1
  147. setiastro/saspro/wavescalede.py +4 -1
  148. setiastro/saspro/whitebalance.py +84 -12
  149. setiastro/saspro/widgets/common_utilities.py +28 -21
  150. setiastro/saspro/widgets/minigame/game.js +11 -6
  151. setiastro/saspro/widgets/resource_monitor.py +133 -57
  152. setiastro/saspro/widgets/spinboxes.py +28 -13
  153. setiastro/saspro/wimi.py +92 -721
  154. setiastro/saspro/wims.py +46 -36
  155. setiastro/saspro/window_shelf.py +2 -2
  156. setiastro/saspro/xisf.py +101 -11
  157. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/METADATA +8 -7
  158. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/RECORD +162 -128
  159. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/WHEEL +0 -0
  160. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/entry_points.txt +0 -0
  161. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/licenses/LICENSE +0 -0
  162. {setiastrosuitepro-1.6.2.dist-info → setiastrosuitepro-1.6.12.dist-info}/licenses/license.txt +0 -0
@@ -350,6 +350,10 @@ class RGBAlignDialog(QDialog):
350
350
  self.setWindowFlag(Qt.WindowType.Window, True)
351
351
  self.setWindowModality(Qt.WindowModality.NonModal)
352
352
  self.setModal(False)
353
+ try:
354
+ self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
355
+ except Exception:
356
+ pass # older PyQt6 versions
353
357
  self.parent = parent
354
358
  # document could be a view; try to unwrap
355
359
  self.doc_view = document
@@ -458,7 +458,10 @@ class SelectiveColorCorrection(QDialog):
458
458
  self.setWindowTitle(self.tr("Selective Color Correction"))
459
459
  if window_icon:
460
460
  self.setWindowIcon(window_icon)
461
-
461
+ try:
462
+ self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
463
+ except Exception:
464
+ pass # older PyQt6 versions
462
465
  self.docman = doc_manager
463
466
  self.document = document
464
467
  if self.document is None or getattr(self.document, "image", None) is None:
@@ -467,7 +470,7 @@ class SelectiveColorCorrection(QDialog):
467
470
 
468
471
  self.img = np.clip(self.document.image.astype(np.float32), 0.0, 1.0)
469
472
  self.preview_img = self.img.copy()
470
-
473
+ self._syncing_hue = False
471
474
  self._imported_mask_full = None # full-res mask (H x W) float32 0..1
472
475
  self._imported_mask_name = None # nice label to show in UI
473
476
  self._use_imported_mask = False # checkbox state mirror
@@ -555,6 +558,36 @@ class SelectiveColorCorrection(QDialog):
555
558
  self.hue_wheel.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
556
559
  gl.addWidget(self.hue_wheel, 1, 0, 7, 2)
557
560
 
561
+ # Wheel -> sliders/spins (so dragging wheel updates UI and mask)
562
+ def _wheel_to_sliders(s: int, e: int):
563
+ # If user is dragging the wheel, we’re now custom
564
+ if not self._setting_preset and self.dd_preset.currentText() != "Custom":
565
+ self.dd_preset.blockSignals(True)
566
+ self.dd_preset.setCurrentText("Custom")
567
+ self.dd_preset.blockSignals(False)
568
+
569
+ # Update BOTH sliders and spins, without ping-pong
570
+ self._syncing_hue = True
571
+ try:
572
+ s = int(s) % 360
573
+ e = int(e) % 360
574
+
575
+ for w, val in (
576
+ (self.sl_h1, s), (self.sp_h1, s),
577
+ (self.sl_h2, e), (self.sp_h2, e),
578
+ ):
579
+ w.blockSignals(True)
580
+ w.setValue(val)
581
+ w.blockSignals(False)
582
+ finally:
583
+ self._syncing_hue = False
584
+
585
+ self._schedule_mask()
586
+
587
+ self.hue_wheel.rangeChanged.connect(_wheel_to_sliders)
588
+
589
+
590
+
558
591
  # Helper: integer slider + spin (0..360)
559
592
  def _deg_pair(grid: QGridLayout, label: str, row: int):
560
593
  grid.addWidget(QLabel(label), row, 2)
@@ -574,7 +607,8 @@ class SelectiveColorCorrection(QDialog):
574
607
 
575
608
  # Row 3: chroma + lightness
576
609
  gl.addWidget(QLabel("Min chroma:"), 3, 2)
577
- self.ds_minC = QDoubleSpinBox(); self.ds_minC.setRange(0,1); self.ds_minC.setSingleStep(0.05); self.ds_minC.setValue(0.0)
610
+ self.ds_minC = QDoubleSpinBox(); self.ds_minC.setRange(0,1); self.ds_minC.setSingleStep(0.05); self.ds_minC.setValue(0.05)
611
+
578
612
  self.ds_minC.valueChanged.connect(self._recompute_mask_and_preview)
579
613
  gl.addWidget(self.ds_minC, 3, 3)
580
614
 
@@ -741,10 +775,12 @@ class SelectiveColorCorrection(QDialog):
741
775
  right.addLayout(zoom_row)
742
776
 
743
777
  self.lbl_help = QLabel(
744
- "🖱️ <b>Click</b>: pick hue &nbsp;•&nbsp; "
778
+ "🖱️ <b>Click</b>: show hue &nbsp;•&nbsp; "
779
+ "<b>Shift + Click</b>: select that color &nbsp;•&nbsp; "
745
780
  "<b>Ctrl + Click & Drag</b>: pan &nbsp;•&nbsp; "
746
781
  "<b>Ctrl + Wheel</b>: zoom"
747
782
  )
783
+
748
784
  self.lbl_help.setWordWrap(True)
749
785
  self.lbl_help.setTextFormat(Qt.TextFormat.RichText)
750
786
  self.lbl_help.setStyleSheet("color: #888; font-size: 11px;")
@@ -797,12 +833,20 @@ class SelectiveColorCorrection(QDialog):
797
833
  w.valueChanged.connect(self._schedule_adjustments)
798
834
 
799
835
  def _sliders_to_wheel(_=None):
836
+ if getattr(self, "_syncing_hue", False):
837
+ return
838
+
800
839
  if not self._setting_preset and self.dd_preset.currentText() != "Custom":
840
+ self.dd_preset.blockSignals(True)
801
841
  self.dd_preset.setCurrentText("Custom")
802
- s = int(self.sp_h1.value()); e = int(self.sp_h2.value())
842
+ self.dd_preset.blockSignals(False)
843
+
844
+ s = int(self.sp_h1.value())
845
+ e = int(self.sp_h2.value())
803
846
  self.hue_wheel.setRange(s, e, notify=False)
804
847
  self._schedule_mask()
805
848
 
849
+
806
850
  self.sp_h1.valueChanged.connect(_sliders_to_wheel)
807
851
  self.sp_h2.valueChanged.connect(_sliders_to_wheel)
808
852
  self.sl_h1.valueChanged.connect(_sliders_to_wheel)
@@ -973,7 +1017,7 @@ class SelectiveColorCorrection(QDialog):
973
1017
  w.setValue(int(val))
974
1018
  w.blockSignals(False)
975
1019
 
976
- setv(self.ds_minC, 0.0)
1020
+ setv(self.ds_minC, 0.05)
977
1021
  setv(self.ds_minL, 0.0)
978
1022
  setv(self.ds_maxL, 1.0)
979
1023
  setv(self.ds_smooth, 10.0)
@@ -1018,23 +1062,27 @@ class SelectiveColorCorrection(QDialog):
1018
1062
  self._recompute_mask_and_preview()
1019
1063
 
1020
1064
 
1021
- def _schedule_adjustments(self, delay_ms: int | None = None):
1065
+ def _schedule_adjustments(self, *_, delay_ms: int | None = None):
1022
1066
  if delay_ms is None:
1023
1067
  delay_ms = getattr(self, "_adj_delay_ms", 200)
1024
- # if called very early, just no-op safely
1068
+
1025
1069
  if not hasattr(self, "_adj_timer"):
1026
1070
  return
1027
- self._adj_timer.stop()
1028
- self._adj_timer.start(int(delay_ms))
1029
1071
 
1072
+ ms = max(1, int(delay_ms)) # never allow 0/negative
1073
+ self._adj_timer.stop()
1074
+ self._adj_timer.start(ms)
1030
1075
 
1031
- def _schedule_mask(self, delay_ms: int | None = None):
1032
- """Debounce mask recomputation for hue changes."""
1076
+ def _schedule_mask(self, *_, delay_ms: int | None = None):
1033
1077
  if delay_ms is None:
1034
- delay_ms = self._mask_delay_ms
1035
- # restart the timer on every change
1078
+ delay_ms = getattr(self, "_mask_delay_ms", 200)
1079
+
1080
+ if not hasattr(self, "_mask_timer"):
1081
+ return
1082
+
1083
+ ms = max(1, int(delay_ms))
1036
1084
  self._mask_timer.stop()
1037
- self._mask_timer.start(int(delay_ms))
1085
+ self._mask_timer.start(ms)
1038
1086
 
1039
1087
 
1040
1088
  def _sample_hue_deg_from_base(self, x: int, y: int) -> float | None:
@@ -1190,16 +1238,30 @@ class SelectiveColorCorrection(QDialog):
1190
1238
  intervals = _PRESETS.get(txt, [])
1191
1239
  if intervals:
1192
1240
  lo, hi = (intervals[0][0], intervals[-1][1]) if len(intervals) > 1 else intervals[0]
1193
- self.hue_wheel.setRange(int(lo), int(hi), notify=False) # update wheel silently
1194
- self.hue_wheel.update() # ensure repaint
1195
- self.sp_h1.blockSignals(True); self.sp_h2.blockSignals(True)
1196
- self.sp_h1.setValue(int(lo)); self.sp_h2.setValue(int(hi))
1197
- self.sp_h1.blockSignals(False); self.sp_h2.blockSignals(False)
1241
+
1242
+ # --- NEW: keep wheel + sliders + spins all in sync ---
1243
+ self._syncing_hue = True
1244
+ try:
1245
+ # update wheel silently
1246
+ self.hue_wheel.setRange(int(lo), int(hi), notify=False)
1247
+
1248
+ # update both sliders and spins (no ping-pong)
1249
+ for w, val in (
1250
+ (self.sl_h1, int(lo)), (self.sp_h1, int(lo)),
1251
+ (self.sl_h2, int(hi)), (self.sp_h2, int(hi)),
1252
+ ):
1253
+ w.blockSignals(True)
1254
+ w.setValue(val)
1255
+ w.blockSignals(False)
1256
+
1257
+ self.hue_wheel.update() # ensure repaint
1258
+ finally:
1259
+ self._syncing_hue = False
1260
+
1198
1261
  self._recompute_mask_and_preview()
1199
1262
  finally:
1200
1263
  self._setting_preset = False
1201
1264
 
1202
-
1203
1265
  def _downsample(self, img, max_dim=1024):
1204
1266
  h, w = img.shape[:2]
1205
1267
  s = max(h, w)