setiastrosuitepro 1.6.1.post1__py3-none-any.whl → 1.6.4__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 (139) hide show
  1. setiastro/images/Background_startup.jpg +0 -0
  2. setiastro/images/rotatearbitrary.png +0 -0
  3. setiastro/qml/ResourceMonitor.qml +126 -0
  4. setiastro/saspro/__main__.py +162 -25
  5. setiastro/saspro/_generated/build_info.py +2 -1
  6. setiastro/saspro/abe.py +62 -11
  7. setiastro/saspro/aberration_ai.py +3 -3
  8. setiastro/saspro/add_stars.py +5 -2
  9. setiastro/saspro/astrobin_exporter.py +3 -0
  10. setiastro/saspro/astrospike_python.py +3 -1
  11. setiastro/saspro/autostretch.py +4 -2
  12. setiastro/saspro/backgroundneutral.py +60 -9
  13. setiastro/saspro/batch_convert.py +3 -0
  14. setiastro/saspro/batch_renamer.py +3 -0
  15. setiastro/saspro/blemish_blaster.py +3 -0
  16. setiastro/saspro/blink_comparator_pro.py +474 -251
  17. setiastro/saspro/cheat_sheet.py +50 -15
  18. setiastro/saspro/clahe.py +27 -1
  19. setiastro/saspro/comet_stacking.py +103 -38
  20. setiastro/saspro/convo.py +3 -0
  21. setiastro/saspro/copyastro.py +3 -0
  22. setiastro/saspro/cosmicclarity.py +70 -45
  23. setiastro/saspro/crop_dialog_pro.py +28 -1
  24. setiastro/saspro/curve_editor_pro.py +18 -0
  25. setiastro/saspro/debayer.py +3 -0
  26. setiastro/saspro/doc_manager.py +40 -17
  27. setiastro/saspro/fitsmodifier.py +3 -0
  28. setiastro/saspro/frequency_separation.py +8 -2
  29. setiastro/saspro/function_bundle.py +18 -16
  30. setiastro/saspro/generate_translations.py +715 -1
  31. setiastro/saspro/ghs_dialog_pro.py +3 -0
  32. setiastro/saspro/graxpert.py +3 -0
  33. setiastro/saspro/gui/main_window.py +364 -92
  34. setiastro/saspro/gui/mixins/dock_mixin.py +119 -7
  35. setiastro/saspro/gui/mixins/file_mixin.py +7 -0
  36. setiastro/saspro/gui/mixins/geometry_mixin.py +105 -5
  37. setiastro/saspro/gui/mixins/menu_mixin.py +29 -0
  38. setiastro/saspro/gui/mixins/toolbar_mixin.py +33 -10
  39. setiastro/saspro/gui/statistics_dialog.py +47 -0
  40. setiastro/saspro/halobgon.py +29 -3
  41. setiastro/saspro/histogram.py +3 -0
  42. setiastro/saspro/history_explorer.py +2 -0
  43. setiastro/saspro/i18n.py +22 -10
  44. setiastro/saspro/image_combine.py +3 -0
  45. setiastro/saspro/image_peeker_pro.py +3 -0
  46. setiastro/saspro/imageops/stretch.py +5 -13
  47. setiastro/saspro/isophote.py +3 -0
  48. setiastro/saspro/legacy/numba_utils.py +64 -47
  49. setiastro/saspro/linear_fit.py +3 -0
  50. setiastro/saspro/live_stacking.py +13 -2
  51. setiastro/saspro/mask_creation.py +3 -0
  52. setiastro/saspro/mfdeconv.py +5 -0
  53. setiastro/saspro/morphology.py +30 -5
  54. setiastro/saspro/multiscale_decomp.py +713 -256
  55. setiastro/saspro/nbtorgb_stars.py +12 -2
  56. setiastro/saspro/numba_utils.py +148 -47
  57. setiastro/saspro/ops/scripts.py +77 -17
  58. setiastro/saspro/ops/settings.py +1 -43
  59. setiastro/saspro/perfect_palette_picker.py +1 -0
  60. setiastro/saspro/pixelmath.py +6 -2
  61. setiastro/saspro/plate_solver.py +1 -0
  62. setiastro/saspro/remove_green.py +18 -1
  63. setiastro/saspro/remove_stars.py +136 -162
  64. setiastro/saspro/remove_stars_preset.py +55 -13
  65. setiastro/saspro/resources.py +36 -10
  66. setiastro/saspro/rgb_combination.py +1 -0
  67. setiastro/saspro/rgbalign.py +4 -4
  68. setiastro/saspro/save_options.py +1 -0
  69. setiastro/saspro/selective_color.py +79 -20
  70. setiastro/saspro/sfcc.py +50 -8
  71. setiastro/saspro/shortcuts.py +94 -21
  72. setiastro/saspro/signature_insert.py +3 -0
  73. setiastro/saspro/stacking_suite.py +924 -446
  74. setiastro/saspro/star_alignment.py +291 -331
  75. setiastro/saspro/star_spikes.py +116 -32
  76. setiastro/saspro/star_stretch.py +38 -1
  77. setiastro/saspro/stat_stretch.py +35 -3
  78. setiastro/saspro/status_log_dock.py +1 -1
  79. setiastro/saspro/subwindow.py +63 -2
  80. setiastro/saspro/supernovaasteroidhunter.py +3 -0
  81. setiastro/saspro/swap_manager.py +77 -42
  82. setiastro/saspro/translations/all_source_strings.json +4726 -0
  83. setiastro/saspro/translations/ar_translations.py +4096 -0
  84. setiastro/saspro/translations/de_translations.py +441 -446
  85. setiastro/saspro/translations/es_translations.py +278 -32
  86. setiastro/saspro/translations/fr_translations.py +280 -32
  87. setiastro/saspro/translations/hi_translations.py +3803 -0
  88. setiastro/saspro/translations/integrate_translations.py +38 -1
  89. setiastro/saspro/translations/it_translations.py +1211 -145
  90. setiastro/saspro/translations/ja_translations.py +556 -307
  91. setiastro/saspro/translations/pt_translations.py +3316 -3322
  92. setiastro/saspro/translations/ru_translations.py +3082 -0
  93. setiastro/saspro/translations/saspro_ar.qm +0 -0
  94. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  95. setiastro/saspro/translations/saspro_de.qm +0 -0
  96. setiastro/saspro/translations/saspro_de.ts +14428 -133
  97. setiastro/saspro/translations/saspro_es.qm +0 -0
  98. setiastro/saspro/translations/saspro_es.ts +11503 -7821
  99. setiastro/saspro/translations/saspro_fr.qm +0 -0
  100. setiastro/saspro/translations/saspro_fr.ts +11168 -7812
  101. setiastro/saspro/translations/saspro_hi.qm +0 -0
  102. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  103. setiastro/saspro/translations/saspro_it.qm +0 -0
  104. setiastro/saspro/translations/saspro_it.ts +14347 -7821
  105. setiastro/saspro/translations/saspro_ja.qm +0 -0
  106. setiastro/saspro/translations/saspro_ja.ts +14860 -137
  107. setiastro/saspro/translations/saspro_pt.qm +0 -0
  108. setiastro/saspro/translations/saspro_pt.ts +14904 -137
  109. setiastro/saspro/translations/saspro_ru.qm +0 -0
  110. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  111. setiastro/saspro/translations/saspro_sw.qm +0 -0
  112. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  113. setiastro/saspro/translations/saspro_uk.qm +0 -0
  114. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  115. setiastro/saspro/translations/saspro_zh.qm +0 -0
  116. setiastro/saspro/translations/saspro_zh.ts +10581 -7812
  117. setiastro/saspro/translations/sw_translations.py +3897 -0
  118. setiastro/saspro/translations/uk_translations.py +3929 -0
  119. setiastro/saspro/translations/zh_translations.py +283 -32
  120. setiastro/saspro/versioning.py +36 -5
  121. setiastro/saspro/view_bundle.py +20 -17
  122. setiastro/saspro/wavescale_hdr.py +22 -1
  123. setiastro/saspro/wavescalede.py +23 -1
  124. setiastro/saspro/whitebalance.py +39 -3
  125. setiastro/saspro/widgets/minigame/game.js +991 -0
  126. setiastro/saspro/widgets/minigame/index.html +53 -0
  127. setiastro/saspro/widgets/minigame/style.css +241 -0
  128. setiastro/saspro/widgets/resource_monitor.py +263 -0
  129. setiastro/saspro/widgets/spinboxes.py +18 -0
  130. setiastro/saspro/widgets/wavelet_utils.py +52 -20
  131. setiastro/saspro/wimi.py +100 -80
  132. setiastro/saspro/wims.py +33 -33
  133. setiastro/saspro/window_shelf.py +2 -2
  134. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/METADATA +15 -4
  135. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/RECORD +139 -115
  136. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/WHEEL +0 -0
  137. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/entry_points.txt +0 -0
  138. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/licenses/LICENSE +0 -0
  139. {setiastrosuitepro-1.6.1.post1.dist-info → setiastrosuitepro-1.6.4.dist-info}/licenses/license.txt +0 -0
@@ -1,4 +1,4 @@
1
- # pro/doc_manager.py
1
+ # saspro/doc_manager.py
2
2
  from __future__ import annotations
3
3
  from PyQt6.QtCore import QObject, pyqtSignal, Qt, QTimer
4
4
  from PyQt6.QtWidgets import QApplication, QMessageBox
@@ -2472,23 +2472,29 @@ class DocManager(QObject):
2472
2472
  If a Preview tab is selected on the active ImageSubWindow, return a cached
2473
2473
  _RoiViewDocument so tools and the Preview tab share the same instance.
2474
2474
  Otherwise return the real ImageDocument.
2475
+
2476
+ IMPORTANT: Always check the currently active MDI subwindow first,
2477
+ as that's what the user expects to be the "active" document.
2475
2478
  """
2476
- # Prefer cached (if set and still valid)
2477
- if self._active_doc is not None and self._active_doc in self._docs:
2478
- base_doc = self._active_doc
2479
- else:
2480
- base_doc = None
2481
- try:
2482
- if self._mdi is not None:
2483
- sw = self._mdi.activeSubWindow()
2484
- if sw is not None:
2485
- w = sw.widget()
2486
- base_doc = getattr(w, "document", None) or getattr(sw, "document", None)
2487
- if base_doc is not None:
2488
- self._active_doc = base_doc
2489
- except Exception:
2490
- pass
2491
- if base_doc is None:
2479
+ base_doc = None
2480
+
2481
+ # ALWAYS check the MDI active subwindow first - this is the source of truth
2482
+ try:
2483
+ if self._mdi is not None:
2484
+ sw = self._mdi.activeSubWindow()
2485
+ if sw is not None:
2486
+ w = sw.widget()
2487
+ base_doc = getattr(w, "document", None) or getattr(sw, "document", None)
2488
+ if base_doc is not None:
2489
+ self._active_doc = base_doc
2490
+ except Exception:
2491
+ pass
2492
+
2493
+ # Fallback to cached value only if MDI lookup failed
2494
+ if base_doc is None:
2495
+ if self._active_doc is not None and self._active_doc in self._docs:
2496
+ base_doc = self._active_doc
2497
+ else:
2492
2498
  base_doc = self._docs[-1] if self._docs else None
2493
2499
 
2494
2500
  # Non-image docs just pass through
@@ -2524,6 +2530,23 @@ class DocManager(QObject):
2524
2530
 
2525
2531
  # Prefer explicit doc if given; otherwise fall back to "active"
2526
2532
  view_doc = doc or self.get_active_document()
2533
+
2534
+ # DEBUG: Trace why LinearFit might fail
2535
+ # print(f"[DocManager] update_active_document target: {view_doc}, type: {type(view_doc).__name__}")
2536
+
2537
+ # NEW: Unwrap proxy objects (_DocProxy / LiveViewDocument)
2538
+ tname = type(view_doc).__name__
2539
+ if "LiveViewDocument" in tname:
2540
+ try:
2541
+ view_doc = view_doc._current()
2542
+ except Exception:
2543
+ pass
2544
+ elif "_DocProxy" in tname:
2545
+ try:
2546
+ view_doc = view_doc._target()
2547
+ except Exception:
2548
+ pass
2549
+
2527
2550
  if view_doc is None:
2528
2551
  raise RuntimeError("No active document")
2529
2552
 
@@ -606,6 +606,9 @@ class BatchFITSHeaderDialog(QDialog):
606
606
  def __init__(self, parent=None, preset_keyword: str = "", preset_value: str = "", preset_comment: str = ""):
607
607
  super().__init__(parent)
608
608
  self.setWindowTitle(self.tr("Batch Modify FITS Headers"))
609
+ self.setWindowFlag(Qt.WindowType.Window, True)
610
+ self.setWindowModality(Qt.WindowModality.NonModal)
611
+ self.setModal(False)
609
612
  self.resize(520, 220)
610
613
 
611
614
  v = QVBoxLayout(self)
@@ -708,10 +708,16 @@ class FrequencySeperationTab(QWidget):
708
708
 
709
709
  # channel reconcile
710
710
  if rch == 1 and ch == 3:
711
- # convert RGB→mono (luma or average; we’ll use average)
711
+ # convert RGB→mono (use weighted luma for consistency, or mean if desired. Original was mean)
712
712
  a = a.mean(axis=2).astype(np.float32)
713
713
  elif rch == 3 and ch == 1:
714
- a = np.repeat(a[..., None], 3, axis=2).astype(np.float32)
714
+ # Broadcast mono to 3 channels without copying
715
+ # (H,W,1) -> (H,W,3) via broadcasted view if consumer allows,
716
+ # but usually downstream (like subtraction) handles broadcasting fine.
717
+ # If explicit physical layout is needed, we must check usage.
718
+ # Here: used for subtraction (OK) and preview (OK).
719
+ # We return a view using broadcast_to or striding tricks.
720
+ a = np.broadcast_to(a, (ah, aw, 3))
715
721
 
716
722
  return a
717
723
 
@@ -202,7 +202,7 @@ class FunctionBundleChip(QWidget):
202
202
  from PyQt6.QtWidgets import QMenu # already imported at top, but safe
203
203
 
204
204
  m = QMenu(self)
205
- act_del = m.addAction("Delete Chip")
205
+ act_del = m.addAction(self._panel.tr("Delete Chip"))
206
206
  act = m.exec(ev.globalPos())
207
207
  if act is act_del:
208
208
  try:
@@ -333,7 +333,9 @@ class FunctionBundleDialog(QDialog):
333
333
  def __init__(self, parent: QWidget | None = None):
334
334
  super().__init__(parent)
335
335
  _pin_on_top_mac(self)
336
- self.setWindowTitle("Function Bundles")
336
+ self.setWindowTitle(self.tr("Function Bundles"))
337
+ self.setWindowFlag(Qt.WindowType.Window, True)
338
+ self.setWindowModality(Qt.WindowModality.NonModal)
337
339
  self.setModal(False)
338
340
  self.resize(920, 560)
339
341
  self.setAcceptDrops(True)
@@ -348,9 +350,9 @@ class FunctionBundleDialog(QDialog):
348
350
  self.list.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
349
351
  self.list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
350
352
 
351
- self.btn_new = QPushButton("New")
352
- self.btn_dup = QPushButton("Duplicate")
353
- self.btn_del = QPushButton("Delete")
353
+ self.btn_new = QPushButton(self.tr("New"))
354
+ self.btn_dup = QPushButton(self.tr("Duplicate"))
355
+ self.btn_del = QPushButton(self.tr("Delete"))
354
356
 
355
357
  # right: steps
356
358
  self.steps = QListWidget()
@@ -366,26 +368,26 @@ class FunctionBundleDialog(QDialog):
366
368
  self.steps.setResizeMode(QListView.ResizeMode.Adjust) # recompute item layout on width change
367
369
  self.steps.setUniformItemSizes(False)
368
370
 
369
- self.add_hint = QLabel("Drop shortcuts here to add steps")
371
+ self.add_hint = QLabel(self.tr("Drop shortcuts here to add steps"))
370
372
  self.add_hint.setAlignment(Qt.AlignmentFlag.AlignCenter)
371
373
  self.add_hint.setStyleSheet("color:#aaa; padding:6px; border:1px dashed #666; border-radius:6px;")
372
374
 
373
- self.btn_edit_preset = QPushButton("Edit Preset…")
375
+ self.btn_edit_preset = QPushButton(self.tr("Edit Preset…"))
374
376
  self.btn_edit_preset.setEnabled(False) # enabled when exactly one step is selected
375
377
 
376
- self.btn_remove = QPushButton("Remove Selected")
377
- self.btn_clear = QPushButton("Clear Steps")
378
- self.btn_up = QPushButton("▲ Move Up")
379
- self.btn_down = QPushButton("▼ Move Down")
378
+ self.btn_remove = QPushButton(self.tr("Remove Selected"))
379
+ self.btn_clear = QPushButton(self.tr("Clear Steps"))
380
+ self.btn_up = QPushButton(self.tr("▲ Move Up"))
381
+ self.btn_down = QPushButton(self.tr("▼ Move Down"))
380
382
 
381
- self.btn_drag_bundle = QPushButton("Drag Bundle")
382
- self.btn_run_active = QPushButton("Apply to Active View")
383
- self.btn_apply_to_vbundle = QPushButton("Apply to View Bundle…")
384
- self.btn_chip = QPushButton("Compress to Chip")
383
+ self.btn_drag_bundle = QPushButton(self.tr("Drag Bundle"))
384
+ self.btn_run_active = QPushButton(self.tr("Apply to Active View"))
385
+ self.btn_apply_to_vbundle = QPushButton(self.tr("Apply to View Bundle…"))
386
+ self.btn_chip = QPushButton(self.tr("Compress to Chip"))
385
387
 
386
388
  # layout
387
389
  left = QVBoxLayout()
388
- left.addWidget(QLabel("Function Bundles"))
390
+ left.addWidget(QLabel(self.tr("Function Bundles")))
389
391
  left.addWidget(self.list, 1)
390
392
  row = QHBoxLayout()
391
393
  row.addWidget(self.btn_new); row.addWidget(self.btn_dup); row.addWidget(self.btn_del)