setiastrosuitepro 1.6.4__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 (115) 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/waning_crescent_1.png +0 -0
  14. setiastro/images/waning_crescent_2.png +0 -0
  15. setiastro/images/waning_crescent_3.png +0 -0
  16. setiastro/images/waning_crescent_4.png +0 -0
  17. setiastro/images/waning_crescent_5.png +0 -0
  18. setiastro/images/waning_gibbous_1.png +0 -0
  19. setiastro/images/waning_gibbous_2.png +0 -0
  20. setiastro/images/waning_gibbous_3.png +0 -0
  21. setiastro/images/waning_gibbous_4.png +0 -0
  22. setiastro/images/waning_gibbous_5.png +0 -0
  23. setiastro/images/waxing_crescent_1.png +0 -0
  24. setiastro/images/waxing_crescent_2.png +0 -0
  25. setiastro/images/waxing_crescent_3.png +0 -0
  26. setiastro/images/waxing_crescent_4.png +0 -0
  27. setiastro/images/waxing_crescent_5.png +0 -0
  28. setiastro/images/waxing_gibbous_1.png +0 -0
  29. setiastro/images/waxing_gibbous_2.png +0 -0
  30. setiastro/images/waxing_gibbous_3.png +0 -0
  31. setiastro/images/waxing_gibbous_4.png +0 -0
  32. setiastro/images/waxing_gibbous_5.png +0 -0
  33. setiastro/qml/ResourceMonitor.qml +84 -82
  34. setiastro/saspro/__main__.py +20 -1
  35. setiastro/saspro/_generated/build_info.py +2 -2
  36. setiastro/saspro/abe.py +37 -4
  37. setiastro/saspro/aberration_ai.py +237 -21
  38. setiastro/saspro/acv_exporter.py +379 -0
  39. setiastro/saspro/add_stars.py +33 -6
  40. setiastro/saspro/backgroundneutral.py +108 -40
  41. setiastro/saspro/blemish_blaster.py +4 -1
  42. setiastro/saspro/blink_comparator_pro.py +74 -24
  43. setiastro/saspro/clahe.py +4 -1
  44. setiastro/saspro/continuum_subtract.py +4 -1
  45. setiastro/saspro/convo.py +13 -7
  46. setiastro/saspro/cosmicclarity.py +129 -18
  47. setiastro/saspro/crop_dialog_pro.py +123 -7
  48. setiastro/saspro/curve_editor_pro.py +109 -42
  49. setiastro/saspro/doc_manager.py +245 -15
  50. setiastro/saspro/exoplanet_detector.py +120 -28
  51. setiastro/saspro/frequency_separation.py +1158 -204
  52. setiastro/saspro/ghs_dialog_pro.py +81 -16
  53. setiastro/saspro/graxpert.py +1 -0
  54. setiastro/saspro/gui/main_window.py +429 -228
  55. setiastro/saspro/gui/mixins/dock_mixin.py +245 -24
  56. setiastro/saspro/gui/mixins/menu_mixin.py +27 -1
  57. setiastro/saspro/gui/mixins/theme_mixin.py +160 -14
  58. setiastro/saspro/gui/mixins/toolbar_mixin.py +384 -18
  59. setiastro/saspro/gui/mixins/update_mixin.py +138 -36
  60. setiastro/saspro/gui/mixins/view_mixin.py +42 -0
  61. setiastro/saspro/halobgon.py +4 -0
  62. setiastro/saspro/histogram.py +5 -1
  63. setiastro/saspro/image_combine.py +4 -0
  64. setiastro/saspro/image_peeker_pro.py +4 -0
  65. setiastro/saspro/imageops/starbasedwhitebalance.py +23 -52
  66. setiastro/saspro/imageops/stretch.py +582 -62
  67. setiastro/saspro/isophote.py +4 -0
  68. setiastro/saspro/layers.py +13 -9
  69. setiastro/saspro/layers_dock.py +183 -3
  70. setiastro/saspro/legacy/image_manager.py +154 -20
  71. setiastro/saspro/legacy/numba_utils.py +67 -47
  72. setiastro/saspro/legacy/xisf.py +240 -98
  73. setiastro/saspro/live_stacking.py +180 -79
  74. setiastro/saspro/luminancerecombine.py +228 -27
  75. setiastro/saspro/mask_creation.py +174 -15
  76. setiastro/saspro/mfdeconv.py +113 -35
  77. setiastro/saspro/mfdeconvcudnn.py +119 -70
  78. setiastro/saspro/mfdeconvsport.py +112 -35
  79. setiastro/saspro/morphology.py +4 -0
  80. setiastro/saspro/multiscale_decomp.py +51 -12
  81. setiastro/saspro/numba_utils.py +72 -57
  82. setiastro/saspro/ops/commands.py +18 -18
  83. setiastro/saspro/ops/script_editor.py +10 -2
  84. setiastro/saspro/ops/scripts.py +122 -0
  85. setiastro/saspro/perfect_palette_picker.py +37 -3
  86. setiastro/saspro/plate_solver.py +84 -49
  87. setiastro/saspro/psf_viewer.py +119 -37
  88. setiastro/saspro/resources.py +67 -0
  89. setiastro/saspro/rgbalign.py +4 -0
  90. setiastro/saspro/selective_color.py +4 -1
  91. setiastro/saspro/sfcc.py +364 -152
  92. setiastro/saspro/shortcuts.py +160 -29
  93. setiastro/saspro/signature_insert.py +692 -33
  94. setiastro/saspro/stacking_suite.py +1331 -484
  95. setiastro/saspro/star_alignment.py +247 -123
  96. setiastro/saspro/star_spikes.py +4 -0
  97. setiastro/saspro/star_stretch.py +38 -3
  98. setiastro/saspro/stat_stretch.py +743 -128
  99. setiastro/saspro/subwindow.py +786 -360
  100. setiastro/saspro/supernovaasteroidhunter.py +1 -1
  101. setiastro/saspro/wavescale_hdr.py +4 -1
  102. setiastro/saspro/wavescalede.py +4 -1
  103. setiastro/saspro/whitebalance.py +84 -12
  104. setiastro/saspro/widgets/common_utilities.py +28 -21
  105. setiastro/saspro/widgets/resource_monitor.py +109 -59
  106. setiastro/saspro/widgets/spinboxes.py +10 -13
  107. setiastro/saspro/wimi.py +27 -656
  108. setiastro/saspro/wims.py +13 -3
  109. setiastro/saspro/xisf.py +101 -11
  110. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/METADATA +2 -1
  111. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/RECORD +115 -82
  112. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/WHEEL +0 -0
  113. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/entry_points.txt +0 -0
  114. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/licenses/LICENSE +0 -0
  115. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.6.12.dist-info}/licenses/license.txt +0 -0
@@ -493,7 +493,8 @@ class DraggableToolBar(QToolBar):
493
493
  cid = self._action_id(act)
494
494
  if cid:
495
495
  m.addSeparator()
496
- m.addAction(self.tr("Hide this icon"), lambda: self._set_action_hidden(act, True))
496
+ m.addAction(self.tr("Hide this icon"), lambda: self.window()._hide_action_to_hidden_toolbar(act))
497
+
497
498
 
498
499
  # (Optional) teach users about Alt+Drag:
499
500
  m.addSeparator()
@@ -521,16 +522,19 @@ class DraggableToolBar(QToolBar):
521
522
  m.addSeparator()
522
523
 
523
524
  # Submenu listing hidden actions for this toolbar
524
- hidden = self._load_hidden_set()
525
525
  sub = m.addMenu(self.tr("Show hidden…"))
526
526
 
527
- # Build list from actions that are currently invisible
527
+ mw = self.window()
528
+ tb_hidden = getattr(mw, "_hidden_toolbar", lambda: None)()
528
529
  any_hidden = False
529
- for act in self.actions():
530
- cid = self._action_id(act)
531
- if cid and (cid in hidden) and (not act.isVisible()):
530
+ if tb_hidden:
531
+ for act in tb_hidden.actions():
532
+ # Skip separators
533
+ if act.isSeparator():
534
+ continue
532
535
  any_hidden = True
533
- sub.addAction(act.text() or cid, lambda a=act: self._set_action_hidden(a, False))
536
+ sub.addAction(act.text() or (act.property("command_id") or act.objectName() or "item"),
537
+ lambda a=act: mw._unhide_action_from_hidden_toolbar(a))
534
538
 
535
539
  if not any_hidden:
536
540
  sub.setEnabled(False)
@@ -541,10 +545,15 @@ class DraggableToolBar(QToolBar):
541
545
  m.exec(ev.globalPos())
542
546
 
543
547
  def _reset_hidden_icons(self):
544
- # Show everything and clear hidden list
545
- for act in self.actions():
546
- act.setVisible(True)
547
- self._save_hidden_set(set())
548
+ mw = self.window()
549
+ tb_hidden = getattr(mw, "_hidden_toolbar", lambda: None)()
550
+ if not tb_hidden:
551
+ return
552
+ # copy list because we'll mutate
553
+ acts = [a for a in tb_hidden.actions() if not a.isSeparator()]
554
+ for a in acts:
555
+ mw._unhide_action_from_hidden_toolbar(a)
556
+
548
557
 
549
558
 
550
559
  _PRESET_UI_IDS = {
@@ -1024,17 +1033,14 @@ class ShortcutCanvas(QWidget):
1024
1033
  return False
1025
1034
  sw = self._top_subwindow_at(e.position().toPoint())
1026
1035
  if sw is None:
1027
- print("[ShortcutCanvas] _forward_command_drop: no subwindow under cursor", flush=True)
1028
- QApplication.processEvents()
1036
+
1029
1037
  return False
1030
1038
  try:
1031
1039
  raw = bytes(md.data(MIME_CMD))
1032
1040
  payload = _unpack_cmd_payload(raw) # your existing helper
1033
- print(f"[ShortcutCanvas] _forward_command_drop → subwin={sw}, payload={payload!r}", flush=True)
1034
- QApplication.processEvents()
1041
+
1035
1042
  except Exception as ex:
1036
- print(f"[ShortcutCanvas] _forward_command_drop: failed to unpack payload: {ex!r}", flush=True)
1037
- QApplication.processEvents()
1043
+
1038
1044
  return False
1039
1045
  self._mgr.apply_command_to_subwindow(sw, payload)
1040
1046
  e.acceptProposedAction()
@@ -1536,6 +1542,7 @@ class ShortcutManager:
1536
1542
 
1537
1543
  # ---- persistence (QSettings JSON blob) ----
1538
1544
  def save_shortcuts(self):
1545
+
1539
1546
  data = []
1540
1547
  for sid, w in list(self.widgets.items()):
1541
1548
  if _is_dead(w):
@@ -1836,6 +1843,7 @@ class ShortcutManager:
1836
1843
 
1837
1844
 
1838
1845
  def clear(self):
1846
+
1839
1847
  for sid, w in list(self.widgets.items()):
1840
1848
  try:
1841
1849
  if not _is_dead(w):
@@ -1910,50 +1918,173 @@ class ShortcutManager:
1910
1918
  # legacy single-remove (kept for callers)
1911
1919
  self.delete_by_id(sid, persist=True)
1912
1920
 
1913
-
1914
1921
  class _StatStretchPresetDialog(QDialog):
1922
+ """
1923
+ Preset editor for headless replay: command_id="stat_stretch"
1924
+
1925
+ Keys supported:
1926
+ target_median: float
1927
+ linked: bool
1928
+ normalize: bool
1929
+ apply_curves: bool
1930
+ curves_boost: float # 0..1
1931
+ blackpoint_sigma: float # 0..1 (matches your slider/100)
1932
+ no_black_clip: bool
1933
+ hdr_compress: bool
1934
+ hdr_amount: float # 0..1
1935
+ hdr_knee: float # 0..1
1936
+ luma_only: bool
1937
+ luma_mode: str # e.g. "rec709"
1938
+ luma_blend: float #0..1 (0=normal linked, 1=pure luma-only)
1939
+ """
1915
1940
  def __init__(self, parent=None, initial: dict | None = None):
1916
1941
  super().__init__(parent)
1917
1942
  self.setWindowTitle("Statistical Stretch — Preset")
1918
1943
  init = dict(initial or {})
1919
1944
 
1945
+ # --- Target median ---
1920
1946
  self.spin_target = QDoubleSpinBox()
1921
- self.spin_target.setRange(0.0, 1.0); self.spin_target.setDecimals(3)
1947
+ self.spin_target.setRange(0.0, 1.0)
1948
+ self.spin_target.setDecimals(3)
1922
1949
  self.spin_target.setSingleStep(0.01)
1923
1950
  self.spin_target.setValue(float(init.get("target_median", 0.25)))
1924
1951
 
1952
+ # --- Linked / Normalize ---
1925
1953
  self.chk_linked = QCheckBox("Linked RGB channels")
1926
1954
  self.chk_linked.setChecked(bool(init.get("linked", False)))
1927
1955
 
1928
1956
  self.chk_normalize = QCheckBox("Normalize to [0..1]")
1929
1957
  self.chk_normalize.setChecked(bool(init.get("normalize", False)))
1930
1958
 
1959
+ # --- Curves ---
1960
+ self.chk_curves = QCheckBox("Apply Curves")
1961
+ self.chk_curves.setChecked(bool(init.get("apply_curves", False)))
1962
+
1931
1963
  self.spin_curves = QDoubleSpinBox()
1932
- self.spin_curves.setRange(0.0, 1.0); self.spin_curves.setDecimals(2)
1964
+ self.spin_curves.setRange(0.0, 1.0)
1965
+ self.spin_curves.setDecimals(2)
1933
1966
  self.spin_curves.setSingleStep(0.05)
1934
- self.spin_curves.setValue(float(init.get("curves_boost", 0.0 if not init.get("apply_curves") else 0.20)))
1967
+ self.spin_curves.setValue(float(init.get("curves_boost", 0.0)))
1968
+ self.spin_curves.setEnabled(self.chk_curves.isChecked())
1969
+ self.chk_curves.toggled.connect(self.spin_curves.setEnabled)
1970
+
1971
+ # --- Blackpoint sigma ---
1972
+ self.spin_bp = QDoubleSpinBox()
1973
+ self.spin_bp.setRange(0.0, 1.0)
1974
+ self.spin_bp.setDecimals(2)
1975
+ self.spin_bp.setSingleStep(0.05)
1976
+ self.spin_bp.setValue(float(init.get("blackpoint_sigma", 0.0)))
1977
+
1978
+ self.chk_no_black_clip = QCheckBox("No black clip")
1979
+ self.chk_no_black_clip.setChecked(bool(init.get("no_black_clip", False)))
1980
+
1981
+ # --- HDR compress ---
1982
+ self.chk_hdr = QCheckBox("HDR compression")
1983
+ self.chk_hdr.setChecked(bool(init.get("hdr_compress", False)))
1984
+
1985
+ self.spin_hdr_amt = QDoubleSpinBox()
1986
+ self.spin_hdr_amt.setRange(0.0, 1.0)
1987
+ self.spin_hdr_amt.setDecimals(2)
1988
+ self.spin_hdr_amt.setSingleStep(0.05)
1989
+ self.spin_hdr_amt.setValue(float(init.get("hdr_amount", 0.0)))
1990
+
1991
+ self.spin_hdr_knee = QDoubleSpinBox()
1992
+ self.spin_hdr_knee.setRange(0.0, 1.0)
1993
+ self.spin_hdr_knee.setDecimals(2)
1994
+ self.spin_hdr_knee.setSingleStep(0.05)
1995
+ self.spin_hdr_knee.setValue(float(init.get("hdr_knee", 0.5)))
1996
+
1997
+ def _set_hdr_enabled(on: bool):
1998
+ on = bool(on)
1999
+ self.spin_hdr_amt.setEnabled(on)
2000
+ self.spin_hdr_knee.setEnabled(on)
2001
+
2002
+ _set_hdr_enabled(self.chk_hdr.isChecked())
2003
+ self.chk_hdr.toggled.connect(_set_hdr_enabled)
2004
+
2005
+ # --- Luma only ---
2006
+ self.chk_luma_only = QCheckBox("Luma-only mode")
2007
+ self.chk_luma_only.setChecked(bool(init.get("luma_only", False)))
2008
+
2009
+ self.cmb_luma = QComboBox()
2010
+ # keep in sync with your tool’s supported modes
2011
+ self.cmb_luma.addItems(["rec709", "avg", "hsp", "max"])
2012
+ init_mode = str(init.get("luma_mode", "rec709") or "rec709")
2013
+ idx = self.cmb_luma.findText(init_mode)
2014
+ if idx >= 0:
2015
+ self.cmb_luma.setCurrentIndex(idx)
2016
+
2017
+ self.spin_luma_blend = QDoubleSpinBox()
2018
+ self.spin_luma_blend.setRange(0.0, 1.0)
2019
+ self.spin_luma_blend.setDecimals(2)
2020
+ self.spin_luma_blend.setSingleStep(0.05)
2021
+ self.spin_luma_blend.setValue(float(init.get("luma_blend", 0.70)))
2022
+
2023
+ def _set_luma_enabled(on: bool):
2024
+ on = bool(on)
2025
+ self.cmb_luma.setEnabled(on)
2026
+ self.spin_luma_blend.setEnabled(on)
2027
+
2028
+ _set_luma_enabled(self.chk_luma_only.isChecked())
2029
+ self.chk_luma_only.toggled.connect(_set_luma_enabled)
2030
+
2031
+ # --- Layout ---
2032
+ form = QFormLayout()
1935
2033
 
1936
- form = QFormLayout(self)
1937
2034
  form.addRow("Target median:", self.spin_target)
1938
2035
  form.addRow("", self.chk_linked)
1939
2036
  form.addRow("", self.chk_normalize)
2037
+
2038
+ form.addRow("", QLabel("— Tone shaping —"))
2039
+ form.addRow("", self.chk_curves)
1940
2040
  form.addRow("Curves boost (0–1):", self.spin_curves)
1941
- form.addRow(QLabel("Curves are applied only if boost > 0."))
1942
2041
 
1943
- btns = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, parent=self)
1944
- btns.accepted.connect(self.accept); btns.rejected.connect(self.reject)
2042
+ form.addRow("", QLabel("— Blackpoint / HDR —"))
2043
+ form.addRow("Blackpoint σ (0–1):", self.spin_bp)
2044
+ form.addRow("", self.chk_no_black_clip)
2045
+
2046
+ form.addRow("", self.chk_hdr)
2047
+ form.addRow("HDR amount (0–1):", self.spin_hdr_amt)
2048
+ form.addRow("HDR knee (0–1):", self.spin_hdr_knee)
2049
+
2050
+ form.addRow("", QLabel("— Luma mode —"))
2051
+ form.addRow("", self.chk_luma_only)
2052
+ form.addRow("Luma mode:", self.cmb_luma)
2053
+ form.addRow("Luma blend (0–1):", self.spin_luma_blend)
2054
+ btns = QDialogButtonBox(
2055
+ QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel,
2056
+ parent=self
2057
+ )
2058
+ btns.accepted.connect(self.accept)
2059
+ btns.rejected.connect(self.reject)
1945
2060
  form.addRow(btns)
1946
2061
 
2062
+ self.setLayout(form)
2063
+
1947
2064
  def result_dict(self) -> dict:
1948
- boost = float(self.spin_curves.value())
2065
+ hdr_on = bool(self.chk_hdr.isChecked())
2066
+ curves_on = bool(self.chk_curves.isChecked())
2067
+ luma_on = bool(self.chk_luma_only.isChecked())
2068
+
1949
2069
  return {
1950
2070
  "target_median": float(self.spin_target.value()),
1951
2071
  "linked": bool(self.chk_linked.isChecked()),
1952
2072
  "normalize": bool(self.chk_normalize.isChecked()),
1953
- "apply_curves": bool(boost > 0.0),
1954
- "curves_boost": boost,
2073
+
2074
+ "apply_curves": curves_on,
2075
+ "curves_boost": float(self.spin_curves.value()) if curves_on else 0.0,
2076
+
2077
+ "blackpoint_sigma": float(self.spin_bp.value()),
2078
+ "no_black_clip": bool(self.chk_no_black_clip.isChecked()),
2079
+
2080
+ "hdr_compress": hdr_on,
2081
+ "hdr_amount": float(self.spin_hdr_amt.value()) if hdr_on else 0.0,
2082
+ "hdr_knee": float(self.spin_hdr_knee.value()) if hdr_on else 0.0,
2083
+
2084
+ "luma_only": luma_on,
2085
+ "luma_mode": str(self.cmb_luma.currentText()) if luma_on else "rec709",
2086
+ "luma_blend": float(self.spin_luma_blend.value()) if luma_on else 0.0,
1955
2087
  }
1956
-
1957
2088
 
1958
2089
  class _StarStretchPresetDialog(QDialog):
1959
2090
  def __init__(self, parent=None, initial: dict | None = None):