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.
- setiastro/data/SASP_data.fits +0 -0
- setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
- setiastro/data/catalogs/astrobin_filters.csv +890 -0
- setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
- setiastro/data/catalogs/cali2.csv +63 -0
- setiastro/data/catalogs/cali2color.csv +65 -0
- setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
- setiastro/data/catalogs/celestial_catalog.csv +24031 -0
- setiastro/data/catalogs/detected_stars.csv +24784 -0
- setiastro/data/catalogs/fits_header_data.csv +46 -0
- setiastro/data/catalogs/test.csv +8 -0
- setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
- setiastro/images/Astro_Spikes.png +0 -0
- setiastro/images/Background_startup.jpg +0 -0
- setiastro/images/HRDiagram.png +0 -0
- setiastro/images/LExtract.png +0 -0
- setiastro/images/LInsert.png +0 -0
- setiastro/images/Oxygenation-atm-2.svg.png +0 -0
- setiastro/images/RGB080604.png +0 -0
- setiastro/images/abeicon.png +0 -0
- setiastro/images/aberration.png +0 -0
- setiastro/images/andromedatry.png +0 -0
- setiastro/images/andromedatry_satellited.png +0 -0
- setiastro/images/annotated.png +0 -0
- setiastro/images/aperture.png +0 -0
- setiastro/images/astrosuite.ico +0 -0
- setiastro/images/astrosuite.png +0 -0
- setiastro/images/astrosuitepro.icns +0 -0
- setiastro/images/astrosuitepro.ico +0 -0
- setiastro/images/astrosuitepro.png +0 -0
- setiastro/images/background.png +0 -0
- setiastro/images/background2.png +0 -0
- setiastro/images/benchmark.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
- setiastro/images/blaster.png +0 -0
- setiastro/images/blink.png +0 -0
- setiastro/images/clahe.png +0 -0
- setiastro/images/collage.png +0 -0
- setiastro/images/colorwheel.png +0 -0
- setiastro/images/contsub.png +0 -0
- setiastro/images/convo.png +0 -0
- setiastro/images/copyslot.png +0 -0
- setiastro/images/cosmic.png +0 -0
- setiastro/images/cosmicsat.png +0 -0
- setiastro/images/crop1.png +0 -0
- setiastro/images/cropicon.png +0 -0
- setiastro/images/curves.png +0 -0
- setiastro/images/cvs.png +0 -0
- setiastro/images/debayer.png +0 -0
- setiastro/images/denoise_cnn_custom.png +0 -0
- setiastro/images/denoise_cnn_graph.png +0 -0
- setiastro/images/disk.png +0 -0
- setiastro/images/dse.png +0 -0
- setiastro/images/exoicon.png +0 -0
- setiastro/images/eye.png +0 -0
- setiastro/images/fliphorizontal.png +0 -0
- setiastro/images/flipvertical.png +0 -0
- setiastro/images/font.png +0 -0
- setiastro/images/freqsep.png +0 -0
- setiastro/images/functionbundle.png +0 -0
- setiastro/images/graxpert.png +0 -0
- setiastro/images/green.png +0 -0
- setiastro/images/gridicon.png +0 -0
- setiastro/images/halo.png +0 -0
- setiastro/images/hdr.png +0 -0
- setiastro/images/histogram.png +0 -0
- setiastro/images/hubble.png +0 -0
- setiastro/images/imagecombine.png +0 -0
- setiastro/images/invert.png +0 -0
- setiastro/images/isophote.png +0 -0
- setiastro/images/isophote_demo_figure.png +0 -0
- setiastro/images/isophote_demo_image.png +0 -0
- setiastro/images/isophote_demo_model.png +0 -0
- setiastro/images/isophote_demo_residual.png +0 -0
- setiastro/images/jwstpupil.png +0 -0
- setiastro/images/linearfit.png +0 -0
- setiastro/images/livestacking.png +0 -0
- setiastro/images/mask.png +0 -0
- setiastro/images/maskapply.png +0 -0
- setiastro/images/maskcreate.png +0 -0
- setiastro/images/maskremove.png +0 -0
- setiastro/images/morpho.png +0 -0
- setiastro/images/mosaic.png +0 -0
- setiastro/images/multiscale_decomp.png +0 -0
- setiastro/images/nbtorgb.png +0 -0
- setiastro/images/neutral.png +0 -0
- setiastro/images/nuke.png +0 -0
- setiastro/images/openfile.png +0 -0
- setiastro/images/pedestal.png +0 -0
- setiastro/images/pen.png +0 -0
- setiastro/images/pixelmath.png +0 -0
- setiastro/images/platesolve.png +0 -0
- setiastro/images/ppp.png +0 -0
- setiastro/images/pro.png +0 -0
- setiastro/images/project.png +0 -0
- setiastro/images/psf.png +0 -0
- setiastro/images/redo.png +0 -0
- setiastro/images/redoicon.png +0 -0
- setiastro/images/rescale.png +0 -0
- setiastro/images/rgbalign.png +0 -0
- setiastro/images/rgbcombo.png +0 -0
- setiastro/images/rgbextract.png +0 -0
- setiastro/images/rotate180.png +0 -0
- setiastro/images/rotatearbitrary.png +0 -0
- setiastro/images/rotateclockwise.png +0 -0
- setiastro/images/rotatecounterclockwise.png +0 -0
- setiastro/images/satellite.png +0 -0
- setiastro/images/script.png +0 -0
- setiastro/images/selectivecolor.png +0 -0
- setiastro/images/simbad.png +0 -0
- setiastro/images/slot0.png +0 -0
- setiastro/images/slot1.png +0 -0
- setiastro/images/slot2.png +0 -0
- setiastro/images/slot3.png +0 -0
- setiastro/images/slot4.png +0 -0
- setiastro/images/slot5.png +0 -0
- setiastro/images/slot6.png +0 -0
- setiastro/images/slot7.png +0 -0
- setiastro/images/slot8.png +0 -0
- setiastro/images/slot9.png +0 -0
- setiastro/images/spcc.png +0 -0
- setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
- setiastro/images/spinner.gif +0 -0
- setiastro/images/stacking.png +0 -0
- setiastro/images/staradd.png +0 -0
- setiastro/images/staralign.png +0 -0
- setiastro/images/starnet.png +0 -0
- setiastro/images/starregistration.png +0 -0
- setiastro/images/starspike.png +0 -0
- setiastro/images/starstretch.png +0 -0
- setiastro/images/statstretch.png +0 -0
- setiastro/images/supernova.png +0 -0
- setiastro/images/uhs.png +0 -0
- setiastro/images/undoicon.png +0 -0
- setiastro/images/upscale.png +0 -0
- setiastro/images/viewbundle.png +0 -0
- setiastro/images/whitebalance.png +0 -0
- setiastro/images/wimi_icon_256x256.png +0 -0
- setiastro/images/wimilogo.png +0 -0
- setiastro/images/wims.png +0 -0
- setiastro/images/wrench_icon.png +0 -0
- setiastro/images/xisfliberator.png +0 -0
- setiastro/qml/ResourceMonitor.qml +126 -0
- setiastro/saspro/__main__.py +228 -67
- setiastro/saspro/_generated/build_info.py +2 -1
- setiastro/saspro/abe.py +76 -25
- setiastro/saspro/aberration_ai.py +14 -14
- setiastro/saspro/add_stars.py +15 -12
- setiastro/saspro/astrobin_exporter.py +61 -58
- setiastro/saspro/astrospike_python.py +3 -1
- setiastro/saspro/autostretch.py +4 -2
- setiastro/saspro/backgroundneutral.py +65 -14
- setiastro/saspro/batch_convert.py +8 -5
- setiastro/saspro/batch_renamer.py +39 -36
- setiastro/saspro/blemish_blaster.py +15 -12
- setiastro/saspro/blink_comparator_pro.py +605 -379
- setiastro/saspro/cheat_sheet.py +62 -17
- setiastro/saspro/clahe.py +34 -8
- setiastro/saspro/comet_stacking.py +103 -38
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/continuum_subtract.py +7 -7
- setiastro/saspro/convo.py +12 -9
- setiastro/saspro/copyastro.py +3 -0
- setiastro/saspro/cosmicclarity.py +77 -52
- setiastro/saspro/crop_dialog_pro.py +80 -45
- setiastro/saspro/curve_editor_pro.py +51 -33
- setiastro/saspro/debayer.py +6 -3
- setiastro/saspro/doc_manager.py +49 -19
- setiastro/saspro/exoplanet_detector.py +11 -11
- setiastro/saspro/fitsmodifier.py +48 -44
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/frequency_separation.py +18 -12
- setiastro/saspro/function_bundle.py +18 -16
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +19 -16
- setiastro/saspro/graxpert.py +3 -0
- setiastro/saspro/gui/main_window.py +471 -126
- setiastro/saspro/gui/mixins/dock_mixin.py +123 -11
- setiastro/saspro/gui/mixins/file_mixin.py +25 -20
- setiastro/saspro/gui/mixins/geometry_mixin.py +115 -15
- setiastro/saspro/gui/mixins/header_mixin.py +6 -6
- setiastro/saspro/gui/mixins/mask_mixin.py +8 -8
- setiastro/saspro/gui/mixins/menu_mixin.py +62 -33
- setiastro/saspro/gui/mixins/toolbar_mixin.py +382 -226
- setiastro/saspro/gui/mixins/update_mixin.py +26 -26
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +29 -3
- setiastro/saspro/header_viewer.py +21 -18
- setiastro/saspro/histogram.py +29 -26
- setiastro/saspro/history_explorer.py +2 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +3 -0
- setiastro/saspro/image_peeker_pro.py +52 -44
- setiastro/saspro/imageops/stretch.py +5 -13
- setiastro/saspro/isophote.py +3 -0
- setiastro/saspro/legacy/numba_utils.py +64 -47
- setiastro/saspro/linear_fit.py +3 -0
- setiastro/saspro/live_stacking.py +13 -2
- setiastro/saspro/mask_creation.py +180 -22
- setiastro/saspro/mfdeconv.py +5 -0
- setiastro/saspro/morphology.py +38 -13
- setiastro/saspro/multiscale_decomp.py +713 -256
- setiastro/saspro/nbtorgb_stars.py +12 -2
- setiastro/saspro/numba_utils.py +149 -48
- setiastro/saspro/ops/scripts.py +77 -17
- setiastro/saspro/ops/settings.py +177 -100
- setiastro/saspro/perfect_palette_picker.py +25 -7
- setiastro/saspro/pixelmath.py +114 -110
- setiastro/saspro/plate_solver.py +118 -108
- setiastro/saspro/remove_green.py +24 -7
- setiastro/saspro/remove_stars.py +136 -162
- setiastro/saspro/remove_stars_preset.py +55 -13
- setiastro/saspro/resources.py +46 -15
- setiastro/saspro/rgb_combination.py +19 -18
- setiastro/saspro/rgbalign.py +11 -11
- setiastro/saspro/save_options.py +5 -4
- setiastro/saspro/selective_color.py +84 -25
- setiastro/saspro/sfcc.py +119 -72
- setiastro/saspro/shortcuts.py +345 -36
- setiastro/saspro/signature_insert.py +4 -1
- setiastro/saspro/stacking_suite.py +2066 -1119
- setiastro/saspro/star_alignment.py +291 -331
- setiastro/saspro/star_spikes.py +137 -53
- setiastro/saspro/star_stretch.py +47 -10
- setiastro/saspro/stat_stretch.py +52 -16
- setiastro/saspro/status_log_dock.py +1 -1
- setiastro/saspro/subwindow.py +97 -36
- setiastro/saspro/supernovaasteroidhunter.py +68 -61
- setiastro/saspro/swap_manager.py +77 -42
- setiastro/saspro/translations/all_source_strings.json +4726 -0
- setiastro/saspro/translations/ar_translations.py +4096 -0
- setiastro/saspro/translations/de_translations.py +3728 -0
- setiastro/saspro/translations/es_translations.py +4169 -0
- setiastro/saspro/translations/fr_translations.py +4090 -0
- setiastro/saspro/translations/hi_translations.py +3803 -0
- setiastro/saspro/translations/integrate_translations.py +271 -0
- setiastro/saspro/translations/it_translations.py +4728 -0
- setiastro/saspro/translations/ja_translations.py +3834 -0
- setiastro/saspro/translations/pt_translations.py +3847 -0
- setiastro/saspro/translations/ru_translations.py +3082 -0
- setiastro/saspro/translations/saspro_ar.qm +0 -0
- setiastro/saspro/translations/saspro_ar.ts +16019 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +14548 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +16202 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +15870 -0
- setiastro/saspro/translations/saspro_hi.qm +0 -0
- setiastro/saspro/translations/saspro_hi.ts +14855 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +19046 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +14980 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +15024 -0
- setiastro/saspro/translations/saspro_ru.qm +0 -0
- setiastro/saspro/translations/saspro_ru.ts +11835 -0
- setiastro/saspro/translations/saspro_sw.qm +0 -0
- setiastro/saspro/translations/saspro_sw.ts +15237 -0
- setiastro/saspro/translations/saspro_uk.qm +0 -0
- setiastro/saspro/translations/saspro_uk.ts +15248 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +15289 -0
- setiastro/saspro/translations/sw_translations.py +3897 -0
- setiastro/saspro/translations/uk_translations.py +3929 -0
- setiastro/saspro/translations/zh_translations.py +3910 -0
- setiastro/saspro/versioning.py +77 -0
- setiastro/saspro/view_bundle.py +20 -17
- setiastro/saspro/wavescale_hdr.py +54 -33
- setiastro/saspro/wavescale_hdr_preset.py +6 -5
- setiastro/saspro/wavescalede.py +54 -31
- setiastro/saspro/wavescalede_preset.py +9 -7
- setiastro/saspro/whitebalance.py +58 -22
- setiastro/saspro/widgets/common_utilities.py +12 -11
- setiastro/saspro/widgets/minigame/game.js +991 -0
- setiastro/saspro/widgets/minigame/index.html +53 -0
- setiastro/saspro/widgets/minigame/style.css +241 -0
- setiastro/saspro/widgets/preview_dialogs.py +8 -8
- setiastro/saspro/widgets/resource_monitor.py +263 -0
- setiastro/saspro/widgets/spinboxes.py +18 -0
- setiastro/saspro/widgets/wavelet_utils.py +52 -20
- setiastro/saspro/wimi.py +7996 -0
- setiastro/saspro/wims.py +578 -0
- setiastro/saspro/window_shelf.py +2 -2
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/METADATA +15 -3
- setiastrosuitepro-1.6.4.post1.dist-info/RECORD +368 -0
- setiastrosuitepro-1.6.0.dist-info/RECORD +0 -174
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/WHEEL +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/entry_points.txt +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/LICENSE +0 -0
- {setiastrosuitepro-1.6.0.dist-info → setiastrosuitepro-1.6.4.post1.dist-info}/licenses/license.txt +0 -0
setiastro/saspro/cheat_sheet.py
CHANGED
|
@@ -11,6 +11,7 @@ from PyQt6.QtWidgets import (
|
|
|
11
11
|
QApplication, QMessageBox
|
|
12
12
|
)
|
|
13
13
|
from PyQt6.QtGui import QAction, QShortcut, QKeySequence
|
|
14
|
+
from PyQt6.QtCore import Qt, QCoreApplication
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def _qs_to_str(seq: QKeySequence) -> str:
|
|
@@ -46,27 +47,68 @@ def _seqs_for_action(act: QAction):
|
|
|
46
47
|
|
|
47
48
|
def _where_for_action(act: QAction) -> str:
|
|
48
49
|
"""Determine where an action is available (Menus/Toolbar or Window)."""
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
try:
|
|
51
|
+
parent = act.parent()
|
|
52
|
+
if parent is not None:
|
|
53
|
+
pn = parent.__class__.__name__
|
|
54
|
+
if pn.startswith("QMenu") or pn.startswith("QToolBar"):
|
|
55
|
+
return QCoreApplication.translate("CheatSheet", "Menus/Toolbar")
|
|
56
|
+
except Exception:
|
|
57
|
+
pass
|
|
58
|
+
return QCoreApplication.translate("CheatSheet", "Window")
|
|
54
59
|
|
|
55
60
|
|
|
56
61
|
def _describe_action(act: QAction) -> str:
|
|
57
62
|
"""Get a human-readable description for an action."""
|
|
58
|
-
|
|
63
|
+
try:
|
|
64
|
+
desc = _clean_text(
|
|
65
|
+
act.statusTip() or act.toolTip() or act.text() or act.objectName() or ""
|
|
66
|
+
)
|
|
67
|
+
except Exception:
|
|
68
|
+
desc = ""
|
|
69
|
+
|
|
70
|
+
if not desc:
|
|
71
|
+
desc = QCoreApplication.translate("CheatSheet", "Action")
|
|
72
|
+
return desc
|
|
59
73
|
|
|
60
74
|
|
|
61
75
|
def _describe_shortcut(sc: QShortcut) -> str:
|
|
62
76
|
"""Get a human-readable description for a shortcut."""
|
|
63
|
-
|
|
77
|
+
try:
|
|
78
|
+
hint = sc.property("hint")
|
|
79
|
+
desc = _clean_text(hint or sc.whatsThis() or sc.objectName() or "")
|
|
80
|
+
except Exception:
|
|
81
|
+
desc = ""
|
|
64
82
|
|
|
83
|
+
if not desc:
|
|
84
|
+
desc = QCoreApplication.translate("CheatSheet", "Shortcut")
|
|
85
|
+
return desc
|
|
65
86
|
|
|
87
|
+
def add_extra_shortcuts(rows):
|
|
88
|
+
"""
|
|
89
|
+
Add app-level shortcuts that aren't represented by QActions/QShortcuts.
|
|
90
|
+
rows: list of (shortcut_str, action_str, where_str)
|
|
91
|
+
"""
|
|
92
|
+
rows.append((
|
|
93
|
+
_clean_text("Ctrl+K"),
|
|
94
|
+
_clean_text("Toggle Show/Hide Mask"),
|
|
95
|
+
QCoreApplication.translate("CheatSheet", "Window"),
|
|
96
|
+
))
|
|
97
|
+
rows.append((
|
|
98
|
+
_clean_text("Ctrl+Alt+M"),
|
|
99
|
+
_clean_text("SASpro Neon Invaders (Easter Egg)"),
|
|
100
|
+
QCoreApplication.translate("CheatSheet", "Window"),
|
|
101
|
+
))
|
|
102
|
+
|
|
66
103
|
def _where_for_shortcut(sc: QShortcut) -> str:
|
|
67
104
|
"""Determine where a shortcut is available."""
|
|
68
|
-
|
|
69
|
-
|
|
105
|
+
try:
|
|
106
|
+
par = sc.parent()
|
|
107
|
+
if par is not None:
|
|
108
|
+
return par.__class__.__name__
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
return QCoreApplication.translate("CheatSheet", "Window")
|
|
70
112
|
|
|
71
113
|
|
|
72
114
|
class CheatSheetDialog(QDialog):
|
|
@@ -80,7 +122,10 @@ class CheatSheetDialog(QDialog):
|
|
|
80
122
|
|
|
81
123
|
def __init__(self, parent, keyboard_rows, gesture_rows):
|
|
82
124
|
super().__init__(parent)
|
|
83
|
-
self.setWindowTitle("Keyboard Shortcut Cheat Sheet")
|
|
125
|
+
self.setWindowTitle(self.tr("Keyboard Shortcut Cheat Sheet"))
|
|
126
|
+
self.setWindowFlag(Qt.WindowType.Window, True)
|
|
127
|
+
self.setWindowModality(Qt.WindowModality.NonModal)
|
|
128
|
+
self.setModal(False)
|
|
84
129
|
self.resize(780, 520)
|
|
85
130
|
|
|
86
131
|
self._keyboard_rows = keyboard_rows
|
|
@@ -92,7 +137,7 @@ class CheatSheetDialog(QDialog):
|
|
|
92
137
|
pg_keys = QWidget(tabs)
|
|
93
138
|
v1 = QVBoxLayout(pg_keys)
|
|
94
139
|
tbl_keys = QTableWidget(0, 3, pg_keys)
|
|
95
|
-
tbl_keys.setHorizontalHeaderLabels(["Shortcut", "Action", "Where"])
|
|
140
|
+
tbl_keys.setHorizontalHeaderLabels([self.tr("Shortcut"), self.tr("Action"), self.tr("Where")])
|
|
96
141
|
tbl_keys.verticalHeader().setVisible(False)
|
|
97
142
|
tbl_keys.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
|
|
98
143
|
tbl_keys.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
|
@@ -114,7 +159,7 @@ class CheatSheetDialog(QDialog):
|
|
|
114
159
|
pg_mouse = QWidget(tabs)
|
|
115
160
|
v2 = QVBoxLayout(pg_mouse)
|
|
116
161
|
tbl_mouse = QTableWidget(0, 3, pg_mouse)
|
|
117
|
-
tbl_mouse.setHorizontalHeaderLabels(["Gesture", "Context", "Effect"])
|
|
162
|
+
tbl_mouse.setHorizontalHeaderLabels([self.tr("Gesture"), self.tr("Context"), self.tr("Effect")])
|
|
118
163
|
tbl_mouse.verticalHeader().setVisible(False)
|
|
119
164
|
tbl_mouse.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
|
|
120
165
|
tbl_mouse.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
|
@@ -132,16 +177,16 @@ class CheatSheetDialog(QDialog):
|
|
|
132
177
|
tbl_mouse.setItem(r, 1, QTableWidgetItem(context))
|
|
133
178
|
tbl_mouse.setItem(r, 2, QTableWidgetItem(effect))
|
|
134
179
|
|
|
135
|
-
tabs.addTab(pg_keys, "Base Keyboard")
|
|
136
|
-
tabs.addTab(pg_mouse, "Additional & Mouse & Drag")
|
|
180
|
+
tabs.addTab(pg_keys, self.tr("Base Keyboard"))
|
|
181
|
+
tabs.addTab(pg_mouse, self.tr("Additional & Mouse & Drag"))
|
|
137
182
|
|
|
138
183
|
# Buttons
|
|
139
184
|
btns = QHBoxLayout()
|
|
140
185
|
btns.addStretch(1)
|
|
141
186
|
|
|
142
|
-
b_copy = QPushButton("Copy")
|
|
187
|
+
b_copy = QPushButton(self.tr("Copy"))
|
|
143
188
|
b_copy.clicked.connect(self._copy_all)
|
|
144
|
-
b_close = QPushButton("Close")
|
|
189
|
+
b_close = QPushButton(self.tr("Close"))
|
|
145
190
|
b_close.clicked.connect(self.accept)
|
|
146
191
|
btns.addWidget(b_copy)
|
|
147
192
|
btns.addWidget(b_close)
|
|
@@ -161,7 +206,7 @@ class CheatSheetDialog(QDialog):
|
|
|
161
206
|
for g, c, e in self._gesture_rows:
|
|
162
207
|
lines.append(f"{g:24} {c:18} {e}")
|
|
163
208
|
QApplication.clipboard().setText("\n".join(lines))
|
|
164
|
-
QMessageBox.information(self, "Copied", "Cheat sheet copied to clipboard.")
|
|
209
|
+
QMessageBox.information(self, self.tr("Copied"), self.tr("Cheat sheet copied to clipboard."))
|
|
165
210
|
|
|
166
211
|
|
|
167
212
|
# Legacy alias for backward compatibility
|
setiastro/saspro/clahe.py
CHANGED
|
@@ -113,7 +113,10 @@ def apply_clahe_to_doc(doc, preset: dict | None):
|
|
|
113
113
|
class CLAHEDialogPro(QDialog):
|
|
114
114
|
def __init__(self, parent, doc, icon: QIcon | None = None):
|
|
115
115
|
super().__init__(parent)
|
|
116
|
-
self.setWindowTitle("CLAHE")
|
|
116
|
+
self.setWindowTitle(self.tr("CLAHE"))
|
|
117
|
+
self.setWindowFlag(Qt.WindowType.Window, True)
|
|
118
|
+
self.setWindowModality(Qt.WindowModality.NonModal)
|
|
119
|
+
self.setModal(False)
|
|
117
120
|
if icon:
|
|
118
121
|
try: self.setWindowIcon(icon)
|
|
119
122
|
except Exception as e:
|
|
@@ -130,7 +133,7 @@ class CLAHEDialogPro(QDialog):
|
|
|
130
133
|
v = QVBoxLayout(self)
|
|
131
134
|
|
|
132
135
|
# ---- Params (unchanged) ----
|
|
133
|
-
grp = QGroupBox("CLAHE Parameters"); grid = QGridLayout(grp)
|
|
136
|
+
grp = QGroupBox(self.tr("CLAHE Parameters")); grid = QGridLayout(grp)
|
|
134
137
|
self.s_clip = QSlider(Qt.Orientation.Horizontal); self.s_clip.setRange(1, 40); self.s_clip.setValue(20)
|
|
135
138
|
self.lbl_clip = QLabel("2.0")
|
|
136
139
|
self.s_clip.valueChanged.connect(lambda val: self.lbl_clip.setText(f"{val/10.0:.1f}"))
|
|
@@ -150,13 +153,13 @@ class CLAHEDialogPro(QDialog):
|
|
|
150
153
|
self.s_tile.valueChanged.connect(lambda v: self.lbl_tile.setText(f"{v} px"))
|
|
151
154
|
self.s_tile.valueChanged.connect(self._debounce_preview)
|
|
152
155
|
|
|
153
|
-
grid.addWidget(QLabel("Tile Size (px):"), 1, 0)
|
|
156
|
+
grid.addWidget(QLabel(self.tr("Tile Size (px):")), 1, 0)
|
|
154
157
|
grid.addWidget(self.s_tile, 1, 1)
|
|
155
158
|
grid.addWidget(self.lbl_tile, 1, 2)
|
|
156
159
|
|
|
157
160
|
|
|
158
161
|
|
|
159
|
-
grid.addWidget(QLabel("Clip Limit:"), 0, 0); grid.addWidget(self.s_clip, 0, 1); grid.addWidget(self.lbl_clip, 0, 2)
|
|
162
|
+
grid.addWidget(QLabel(self.tr("Clip Limit:")), 0, 0); grid.addWidget(self.s_clip, 0, 1); grid.addWidget(self.lbl_clip, 0, 2)
|
|
160
163
|
|
|
161
164
|
v.addWidget(grp)
|
|
162
165
|
|
|
@@ -190,9 +193,9 @@ class CLAHEDialogPro(QDialog):
|
|
|
190
193
|
|
|
191
194
|
# ---- Buttons (unchanged) ----
|
|
192
195
|
row = QHBoxLayout()
|
|
193
|
-
self.btn_apply = QPushButton("Apply"); self.btn_apply.clicked.connect(self._apply)
|
|
194
|
-
self.btn_reset = QPushButton("Reset"); self.btn_reset.clicked.connect(self._reset)
|
|
195
|
-
self.btn_close = QPushButton("Cancel"); self.btn_close.clicked.connect(self.reject)
|
|
196
|
+
self.btn_apply = QPushButton(self.tr("Apply")); self.btn_apply.clicked.connect(self._apply)
|
|
197
|
+
self.btn_reset = QPushButton(self.tr("Reset")); self.btn_reset.clicked.connect(self._reset)
|
|
198
|
+
self.btn_close = QPushButton(self.tr("Cancel")); self.btn_close.clicked.connect(self.reject)
|
|
196
199
|
row.addStretch(1); row.addWidget(self.btn_apply); row.addWidget(self.btn_reset); row.addWidget(self.btn_close)
|
|
197
200
|
v.addLayout(row)
|
|
198
201
|
|
|
@@ -319,11 +322,34 @@ class CLAHEDialogPro(QDialog):
|
|
|
319
322
|
pass
|
|
320
323
|
# ─────────────────────────────────────────────────────────────
|
|
321
324
|
|
|
322
|
-
|
|
325
|
+
# Dialog stays open so user can apply to other images
|
|
326
|
+
# Refresh document reference for next operation
|
|
327
|
+
self._refresh_document_from_active()
|
|
323
328
|
|
|
324
329
|
except Exception as e:
|
|
325
330
|
QMessageBox.critical(self, "CLAHE", f"Failed to apply:\n{e}")
|
|
326
331
|
|
|
332
|
+
def _refresh_document_from_active(self):
|
|
333
|
+
"""
|
|
334
|
+
Refresh the dialog's document reference to the currently active document.
|
|
335
|
+
This allows reusing the same dialog on different images.
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
main = self.parent()
|
|
339
|
+
if main and hasattr(main, "_active_doc"):
|
|
340
|
+
new_doc = main._active_doc()
|
|
341
|
+
if new_doc is not None and new_doc is not self.doc:
|
|
342
|
+
self.doc = new_doc
|
|
343
|
+
# Refresh original image and preview for new document
|
|
344
|
+
self.orig = np.clip(np.asarray(new_doc.image, dtype=np.float32), 0.0, 1.0)
|
|
345
|
+
disp = self.orig
|
|
346
|
+
if disp.ndim == 2: disp = disp[..., None].repeat(3, axis=2)
|
|
347
|
+
elif disp.ndim == 3 and disp.shape[2] == 1: disp = disp.repeat(3, axis=2)
|
|
348
|
+
self._disp_base = disp
|
|
349
|
+
self._update_preview()
|
|
350
|
+
except Exception:
|
|
351
|
+
pass
|
|
352
|
+
|
|
327
353
|
def _tile_grid_from_px(self, tile_px: int, hw: tuple[int, int]) -> tuple[int, int]:
|
|
328
354
|
"""
|
|
329
355
|
Convert desired tile size (pixels) into OpenCV tileGridSize=(n,n)
|
|
@@ -90,28 +90,48 @@ def starnet_starless_pair_from_array(
|
|
|
90
90
|
# -------- normalize & shape: float32 [0..1], keep note if mono ----------
|
|
91
91
|
x = np.asarray(src_rgb01, dtype=np.float32)
|
|
92
92
|
was_mono = (x.ndim == 2) or (x.ndim == 3 and x.shape[2] == 1)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
#
|
|
93
|
+
|
|
94
|
+
# DELAY expansion: work with 'x' (mono or rgb) directly where possible
|
|
95
|
+
x_input = x
|
|
96
|
+
if x_input.ndim == 3 and x_input.shape[2] == 1:
|
|
97
|
+
x_input = x_input[..., 0] # collapse to 2D for processing if needed, or keep 2D
|
|
98
|
+
|
|
99
|
+
# For StarNet save, we need 3 channels usually, but check if we can save mono?
|
|
100
|
+
# Actually StarNet usually expects RGB Tiff. So we might need to expand just for saving.
|
|
101
|
+
# But let's avoid `x3 = np.repeat` globally.
|
|
102
|
+
|
|
103
|
+
# Optimization: Create x3 ON DEMAND or virtually using broadcasting only when needed.
|
|
104
|
+
# But `save_image` might handle mono TIFs. If StarNet accepts Mono TIF, we save huge RAM.
|
|
105
|
+
# Standard StarNet typically wants RGB. We will enable "is_mono" flag in `save_image` if it is mono,
|
|
106
|
+
# but StarNet is finicky. Let's stick to RGB for StarNet input but avoid `np.repeat` for the WHOLE array
|
|
107
|
+
# if we can just broadcast or slice.
|
|
108
|
+
# Actually, `stretch_color_image` handles broadcasting? No.
|
|
109
|
+
# Let's simple optimize:
|
|
110
|
+
|
|
102
111
|
if is_linear:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
# stretch; if mono use mono stretch
|
|
113
|
+
if was_mono:
|
|
114
|
+
if x.ndim == 3: x = x[..., 0]
|
|
115
|
+
pre = stretch_mono_image(x, 0.25, False, False)
|
|
116
|
+
# expand ONLY for save
|
|
117
|
+
pre_to_save = np.dstack([pre, pre, pre])
|
|
118
|
+
else:
|
|
119
|
+
pre = stretch_color_image(x, 0.25, False, False, False)
|
|
120
|
+
pre_to_save = pre
|
|
106
121
|
else:
|
|
107
|
-
pre =
|
|
122
|
+
pre = x # floating point 0..1
|
|
123
|
+
if was_mono:
|
|
124
|
+
if pre.ndim == 3: pre = pre[..., 0]
|
|
125
|
+
pre_to_save = np.dstack([pre, pre, pre])
|
|
126
|
+
else:
|
|
127
|
+
pre_to_save = pre
|
|
108
128
|
|
|
109
129
|
# -------- StarNet I/O (write float->16b TIFF; read back float) ----------
|
|
110
130
|
starnet_dir = os.path.dirname(exe) or os.getcwd()
|
|
111
131
|
in_path = os.path.join(starnet_dir, "imagetoremovestars.tif")
|
|
112
132
|
out_path = os.path.join(starnet_dir, "starless.tif")
|
|
113
133
|
|
|
114
|
-
save_image(
|
|
134
|
+
save_image(pre_to_save, in_path, original_format="tif", bit_depth="16-bit",
|
|
115
135
|
original_header=None, is_mono=False, image_meta=None, file_meta=None)
|
|
116
136
|
|
|
117
137
|
exe_name = os.path.basename(exe).lower()
|
|
@@ -134,32 +154,61 @@ def starnet_starless_pair_from_array(
|
|
|
134
154
|
except Exception:
|
|
135
155
|
pass
|
|
136
156
|
|
|
137
|
-
|
|
138
|
-
starless_pre = np.stack([starless_pre]*3, axis=-1)
|
|
139
|
-
elif starless_pre.ndim == 3 and starless_pre.shape[2] == 1:
|
|
140
|
-
starless_pre = np.repeat(starless_pre, 3, axis=2)
|
|
157
|
+
# Don't expand starless_pre yet if we don't need to.
|
|
141
158
|
starless_pre = starless_pre.astype(np.float32, copy=False)
|
|
142
|
-
|
|
159
|
+
if was_mono and starless_pre.ndim == 3:
|
|
160
|
+
# StarNet output is usually RGB even for mono input. Convert back to mono?
|
|
161
|
+
# Or just use one channel.
|
|
162
|
+
starless_pre = starless_pre[..., 0]
|
|
163
|
+
|
|
164
|
+
# Maintain `pre` as the stretched input (mono or rgb)
|
|
165
|
+
|
|
143
166
|
# ---- mask-protect in the SAME (stretched) domain as pre/starless_pre ----
|
|
144
167
|
if core_mask is not None:
|
|
145
168
|
m = np.clip(core_mask.astype(np.float32), 0.0, 1.0)
|
|
146
|
-
|
|
147
|
-
|
|
169
|
+
# broadcast mask
|
|
170
|
+
if not was_mono:
|
|
171
|
+
if m.ndim == 2: m = m[..., None]
|
|
172
|
+
|
|
173
|
+
protected_stretched = starless_pre * (1.0 - m) + pre * m
|
|
148
174
|
else:
|
|
149
175
|
protected_stretched = starless_pre
|
|
176
|
+
|
|
177
|
+
# Return to 3-channel ONLY if requested by the caller's context?
|
|
178
|
+
# The signature `starnet_starless_pair_from_array` implies it might return what it got.
|
|
179
|
+
# The original returned `protected_unstretch`.
|
|
180
|
+
pass # logic flow continues below...
|
|
150
181
|
|
|
151
182
|
# -------- “unstretch” → shared pseudo-linear space (once, after blend) ----------
|
|
152
183
|
if is_linear:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
184
|
+
# choose stretcher based on channels
|
|
185
|
+
if was_mono:
|
|
186
|
+
# ensure 2d
|
|
187
|
+
if protected_stretched.ndim == 3 and protected_stretched.shape[2] == 1:
|
|
188
|
+
protected_stretched = protected_stretched[..., 0]
|
|
189
|
+
elif protected_stretched.ndim == 3:
|
|
190
|
+
# collapse rgb to mono if needed? likely StarNet gave RGB.
|
|
191
|
+
# Keep RGB if StarNet created color artifacts we want to keep?
|
|
192
|
+
# Usually for mono data we want to kill color.
|
|
193
|
+
protected_stretched = protected_stretched.mean(axis=2)
|
|
194
|
+
|
|
195
|
+
protected_unstretch = stretch_mono_image(
|
|
196
|
+
protected_stretched, 0.05, False, False
|
|
197
|
+
)
|
|
198
|
+
# Expand finally for return constraint?
|
|
199
|
+
# The older function returned RGB-like.
|
|
200
|
+
# Let's expand here at the VERY END.
|
|
201
|
+
protected_unstretch = np.dstack([protected_unstretch]*3)
|
|
202
|
+
else:
|
|
203
|
+
protected_unstretch = stretch_color_image(
|
|
204
|
+
protected_stretched, 0.05, False, False, False
|
|
205
|
+
)
|
|
156
206
|
else:
|
|
157
207
|
protected_unstretch = protected_stretched
|
|
208
|
+
if was_mono and protected_unstretch.ndim == 2:
|
|
209
|
+
protected_unstretch = np.dstack([protected_unstretch]*3)
|
|
158
210
|
|
|
159
|
-
protected_unstretch
|
|
160
|
-
protected_unstretch.astype(np.float32, copy=False), 0.0, 1.0
|
|
161
|
-
)
|
|
162
|
-
return protected_unstretch, protected_unstretch
|
|
211
|
+
return np.clip(protected_unstretch, 0.0, 1.0), np.clip(protected_unstretch, 0.0, 1.0)
|
|
163
212
|
|
|
164
213
|
|
|
165
214
|
|
|
@@ -170,8 +219,17 @@ def darkstar_starless_from_array(src_rgb01: np.ndarray, settings, **_ignored) ->
|
|
|
170
219
|
"""
|
|
171
220
|
# normalize channels
|
|
172
221
|
img = src_rgb01.astype(np.float32, copy=False)
|
|
173
|
-
if
|
|
174
|
-
|
|
222
|
+
# Delay expansion: if it's 2D/Mono, send it as-is if DarkStar supports it,
|
|
223
|
+
# but DarkStar expects 3-channel TIF usually.
|
|
224
|
+
# We'll just expand for the save call, not "in place" if possible.
|
|
225
|
+
# Actually DarkStar runner saves `img` directly.
|
|
226
|
+
# So we'll expand just for that save to avoid holding 2 copies in memory.
|
|
227
|
+
if img.ndim == 2:
|
|
228
|
+
img_to_save = np.stack([img]*3, axis=-1)
|
|
229
|
+
elif img.ndim == 3 and img.shape[2] == 1:
|
|
230
|
+
img_to_save = np.repeat(img, 3, axis=2)
|
|
231
|
+
else:
|
|
232
|
+
img_to_save = img
|
|
175
233
|
|
|
176
234
|
# resolve exe and base folder
|
|
177
235
|
exe, base = _resolve_darkstar_exe(type("Dummy", (), {"settings": settings})())
|
|
@@ -192,7 +250,8 @@ def darkstar_starless_from_array(src_rgb01: np.ndarray, settings, **_ignored) ->
|
|
|
192
250
|
out_path = os.path.join(output_dir, "imagetoremovestars_starless.tif")
|
|
193
251
|
|
|
194
252
|
# save input as float32 TIFF
|
|
195
|
-
|
|
253
|
+
# save input as float32 TIFF
|
|
254
|
+
save_image(img_to_save, in_path, original_format="tif", bit_depth="32-bit floating point",
|
|
196
255
|
original_header=None, is_mono=False, image_meta=None, file_meta=None)
|
|
197
256
|
|
|
198
257
|
# build command (SASv2 parity): default unscreen, show extracted stars off, stride 512
|
|
@@ -218,8 +277,12 @@ def darkstar_starless_from_array(src_rgb01: np.ndarray, settings, **_ignored) ->
|
|
|
218
277
|
if starless is None:
|
|
219
278
|
raise RuntimeError("DarkStar produced no output.")
|
|
220
279
|
|
|
221
|
-
|
|
222
|
-
if starless.
|
|
280
|
+
# Delayed expansion
|
|
281
|
+
if starless.ndim == 2:
|
|
282
|
+
starless = np.stack([starless]*3, axis=-1)
|
|
283
|
+
elif starless.ndim == 3 and starless.shape[2] == 1:
|
|
284
|
+
starless = np.repeat(starless, 3, axis=2)
|
|
285
|
+
|
|
223
286
|
return np.clip(starless.astype(np.float32, copy=False), 0.0, 1.0)
|
|
224
287
|
|
|
225
288
|
# ---------- small helpers ----------
|
|
@@ -239,6 +302,10 @@ def _inv_affine_2x3(M: np.ndarray) -> np.ndarray:
|
|
|
239
302
|
def _to_luma(img: np.ndarray) -> np.ndarray:
|
|
240
303
|
if img.ndim == 2: return img.astype(np.float32, copy=False)
|
|
241
304
|
if img.ndim == 3 and img.shape[-1] == 3:
|
|
305
|
+
try:
|
|
306
|
+
return cv2.cvtColor(img, cv2.COLOR_RGB2GRAY).astype(np.float32, copy=False)
|
|
307
|
+
except Exception:
|
|
308
|
+
pass
|
|
242
309
|
r,g,b = img[...,0], img[...,1], img[...,2]
|
|
243
310
|
return (0.2126*r + 0.7152*g + 0.0722*b).astype(np.float32, copy=False)
|
|
244
311
|
if img.ndim == 3 and img.shape[-1] == 1:
|
|
@@ -748,11 +815,9 @@ def _shift_to_comet(img: np.ndarray, xy: Tuple[float,float], ref_xy: Tuple[float
|
|
|
748
815
|
M = np.array([[1.0, 0.0, dx], [0.0, 1.0, dy]], dtype=np.float32)
|
|
749
816
|
H, W = img.shape[:2]
|
|
750
817
|
interp = cv2.INTER_LANCZOS4
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
ch = [cv2.warpAffine(img[...,c], M, (W, H), flags=interp, borderMode=cv2.BORDER_REFLECT) for c in range(img.shape[-1])]
|
|
755
|
-
return np.stack(ch, axis=-1)
|
|
818
|
+
|
|
819
|
+
# Vectorized warp for both 2D (mono) and 3D (RGB)
|
|
820
|
+
return cv2.warpAffine(img, M, (W, H), flags=interp, borderMode=cv2.BORDER_REFLECT)
|
|
756
821
|
|
|
757
822
|
def stack_comet_aligned(file_list: List[str],
|
|
758
823
|
comet_xy: Dict[str, Tuple[float,float]],
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Common UI strings translation module.
|
|
4
|
+
|
|
5
|
+
This module provides centralized translation for common button labels,
|
|
6
|
+
dialog titles, and messages used throughout the application.
|
|
7
|
+
"""
|
|
8
|
+
from PyQt6.QtCore import QCoreApplication
|
|
9
|
+
|
|
10
|
+
def _tr(text: str, context: str = "Common") -> str:
|
|
11
|
+
"""Translate common UI strings."""
|
|
12
|
+
return QCoreApplication.translate(context, text)
|
|
13
|
+
|
|
14
|
+
# ============================================================================
|
|
15
|
+
# Common Button Labels
|
|
16
|
+
# ============================================================================
|
|
17
|
+
class Buttons:
|
|
18
|
+
@staticmethod
|
|
19
|
+
def apply(): return _tr("Apply")
|
|
20
|
+
@staticmethod
|
|
21
|
+
def cancel(): return _tr("Cancel")
|
|
22
|
+
@staticmethod
|
|
23
|
+
def close(): return _tr("Close")
|
|
24
|
+
@staticmethod
|
|
25
|
+
def ok(): return _tr("OK")
|
|
26
|
+
@staticmethod
|
|
27
|
+
def yes(): return _tr("Yes")
|
|
28
|
+
@staticmethod
|
|
29
|
+
def no(): return _tr("No")
|
|
30
|
+
@staticmethod
|
|
31
|
+
def save(): return _tr("Save")
|
|
32
|
+
@staticmethod
|
|
33
|
+
def save_as(): return _tr("Save As...")
|
|
34
|
+
@staticmethod
|
|
35
|
+
def open(): return _tr("Open...")
|
|
36
|
+
@staticmethod
|
|
37
|
+
def browse(): return _tr("Browse...")
|
|
38
|
+
@staticmethod
|
|
39
|
+
def reset(): return _tr("Reset")
|
|
40
|
+
@staticmethod
|
|
41
|
+
def clear(): return _tr("Clear")
|
|
42
|
+
@staticmethod
|
|
43
|
+
def delete(): return _tr("Delete")
|
|
44
|
+
@staticmethod
|
|
45
|
+
def add(): return _tr("Add")
|
|
46
|
+
@staticmethod
|
|
47
|
+
def remove(): return _tr("Remove")
|
|
48
|
+
@staticmethod
|
|
49
|
+
def preview(): return _tr("Preview")
|
|
50
|
+
@staticmethod
|
|
51
|
+
def apply_to_document(): return _tr("Apply to Document")
|
|
52
|
+
@staticmethod
|
|
53
|
+
def zoom_in(): return _tr("Zoom In")
|
|
54
|
+
@staticmethod
|
|
55
|
+
def zoom_out(): return _tr("Zoom Out")
|
|
56
|
+
@staticmethod
|
|
57
|
+
def fit_to_preview(): return _tr("Fit to Preview")
|
|
58
|
+
@staticmethod
|
|
59
|
+
def show_original(): return _tr("Show Original")
|
|
60
|
+
@staticmethod
|
|
61
|
+
def run(): return _tr("Run")
|
|
62
|
+
@staticmethod
|
|
63
|
+
def stop(): return _tr("Stop")
|
|
64
|
+
@staticmethod
|
|
65
|
+
def export(): return _tr("Export")
|
|
66
|
+
@staticmethod
|
|
67
|
+
def import_(): return _tr("Import")
|
|
68
|
+
|
|
69
|
+
# ============================================================================
|
|
70
|
+
# Common Dialog Titles
|
|
71
|
+
# ============================================================================
|
|
72
|
+
class Titles:
|
|
73
|
+
@staticmethod
|
|
74
|
+
def error(): return _tr("Error")
|
|
75
|
+
@staticmethod
|
|
76
|
+
def warning(): return _tr("Warning")
|
|
77
|
+
@staticmethod
|
|
78
|
+
def info(): return _tr("Information")
|
|
79
|
+
@staticmethod
|
|
80
|
+
def confirm(): return _tr("Confirm")
|
|
81
|
+
@staticmethod
|
|
82
|
+
def success(): return _tr("Success")
|
|
83
|
+
@staticmethod
|
|
84
|
+
def processing(): return _tr("Processing...")
|
|
85
|
+
@staticmethod
|
|
86
|
+
def please_wait(): return _tr("Please wait")
|
|
87
|
+
|
|
88
|
+
# ============================================================================
|
|
89
|
+
# Common Messages
|
|
90
|
+
# ============================================================================
|
|
91
|
+
class Messages:
|
|
92
|
+
@staticmethod
|
|
93
|
+
def no_image(): return _tr("No image loaded.")
|
|
94
|
+
@staticmethod
|
|
95
|
+
def no_active_image(): return _tr("No active image.")
|
|
96
|
+
@staticmethod
|
|
97
|
+
def load_image_first(): return _tr("Load an image first.")
|
|
98
|
+
@staticmethod
|
|
99
|
+
def processing_failed(): return _tr("Processing failed.")
|
|
100
|
+
@staticmethod
|
|
101
|
+
def operation_complete(): return _tr("Operation complete.")
|
|
102
|
+
@staticmethod
|
|
103
|
+
def are_you_sure(): return _tr("Are you sure?")
|
|
104
|
+
@staticmethod
|
|
105
|
+
def unsaved_changes(): return _tr("You have unsaved changes.")
|
|
106
|
+
@staticmethod
|
|
107
|
+
def exit_confirm(): return _tr("Do you really want to exit?")
|
|
@@ -129,7 +129,7 @@ class ContinuumSubtractTab(QWidget):
|
|
|
129
129
|
columns_layout = QHBoxLayout() # holds the three groups
|
|
130
130
|
|
|
131
131
|
# — NB group —
|
|
132
|
-
nb_group = QGroupBox("Narrowband Filters")
|
|
132
|
+
nb_group = QGroupBox(self.tr("Narrowband Filters"))
|
|
133
133
|
nb_l = QVBoxLayout()
|
|
134
134
|
for name, attr in [("Ha","ha"), ("SII","sii"), ("OIII","oiii")]:
|
|
135
135
|
# starry
|
|
@@ -166,9 +166,9 @@ class ContinuumSubtractTab(QWidget):
|
|
|
166
166
|
nb_l.addWidget(btn_sl); nb_l.addWidget(lbl_sl)
|
|
167
167
|
|
|
168
168
|
# user controls
|
|
169
|
-
self.linear_output_checkbox = QCheckBox("Output Linear Image Only")
|
|
169
|
+
self.linear_output_checkbox = QCheckBox(self.tr("Output Linear Image Only"))
|
|
170
170
|
nb_l.addWidget(self.linear_output_checkbox)
|
|
171
|
-
self.denoise_checkbox = QCheckBox("Denoise continuum result with Cosmic Clarity (0.9)") # NEW
|
|
171
|
+
self.denoise_checkbox = QCheckBox(self.tr("Denoise continuum result with Cosmic Clarity (0.9)")) # NEW
|
|
172
172
|
self.denoise_checkbox.setToolTip(
|
|
173
173
|
"Runs Cosmic Clarity denoise on the linear continuum-subtracted image "
|
|
174
174
|
"before any non-linear stretch."
|
|
@@ -221,13 +221,13 @@ class ContinuumSubtractTab(QWidget):
|
|
|
221
221
|
|
|
222
222
|
nb_l.addStretch(1)
|
|
223
223
|
|
|
224
|
-
self.clear_button = QPushButton("Clear Loaded Images")
|
|
224
|
+
self.clear_button = QPushButton(self.tr("Clear Loaded Images"))
|
|
225
225
|
self.clear_button.clicked.connect(self.clear_loaded_images)
|
|
226
226
|
nb_l.addWidget(self.clear_button)
|
|
227
227
|
nb_group.setLayout(nb_l)
|
|
228
228
|
|
|
229
229
|
# — Continuum group —
|
|
230
|
-
cont_group = QGroupBox("Continuum Sources")
|
|
230
|
+
cont_group = QGroupBox(self.tr("Continuum Sources"))
|
|
231
231
|
cont_l = QVBoxLayout()
|
|
232
232
|
for name, attr in [("Red","red"), ("Green","green"), ("OSC","osc")]:
|
|
233
233
|
btn = QPushButton(f"Load {name}")
|
|
@@ -248,7 +248,7 @@ class ContinuumSubtractTab(QWidget):
|
|
|
248
248
|
cont_group.setLayout(cont_l)
|
|
249
249
|
|
|
250
250
|
# — White balance diagnostics —
|
|
251
|
-
wb_group = QGroupBox("Star-Based WB")
|
|
251
|
+
wb_group = QGroupBox(self.tr("Star-Based WB"))
|
|
252
252
|
self.wb_l = QVBoxLayout()
|
|
253
253
|
self.wb_l.setAlignment(Qt.AlignmentFlag.AlignTop)
|
|
254
254
|
wb_group.setLayout(self.wb_l)
|
|
@@ -267,7 +267,7 @@ class ContinuumSubtractTab(QWidget):
|
|
|
267
267
|
|
|
268
268
|
# — Bottom row: Execute & status —
|
|
269
269
|
bottom_layout = QHBoxLayout()
|
|
270
|
-
self.execute_button = QPushButton("Execute")
|
|
270
|
+
self.execute_button = QPushButton(self.tr("Execute"))
|
|
271
271
|
self.execute_button.clicked.connect(self.startContinuumSubtraction)
|
|
272
272
|
bottom_layout.addWidget(self.execute_button, stretch=1)
|
|
273
273
|
bottom_layout.addWidget(self.spinnerLabel, stretch=1)
|
setiastro/saspro/convo.py
CHANGED
|
@@ -152,7 +152,10 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
152
152
|
if hasattr(self._main, "currentDocumentChanged") and self._doc_override is None:
|
|
153
153
|
self._main.currentDocumentChanged.connect(self._on_active_doc_changed)
|
|
154
154
|
|
|
155
|
-
self.setWindowTitle("Convolution / Deconvolution")
|
|
155
|
+
self.setWindowTitle(self.tr("Convolution / Deconvolution"))
|
|
156
|
+
self.setWindowFlag(Qt.WindowType.Window, True)
|
|
157
|
+
self.setWindowModality(Qt.WindowModality.NonModal)
|
|
158
|
+
self.setModal(False)
|
|
156
159
|
self.resize(1000, 650)
|
|
157
160
|
self._use_custom_psf = False
|
|
158
161
|
self._custom_psf: Optional[np.ndarray] = None
|
|
@@ -190,14 +193,14 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
190
193
|
|
|
191
194
|
# Buttons
|
|
192
195
|
row1 = QHBoxLayout()
|
|
193
|
-
self.preview_btn = QPushButton("Preview")
|
|
194
|
-
self.undo_btn = QPushButton("Undo")
|
|
195
|
-
self.close_btn = QPushButton("Close")
|
|
196
|
+
self.preview_btn = QPushButton(self.tr("Preview"))
|
|
197
|
+
self.undo_btn = QPushButton(self.tr("Undo"))
|
|
198
|
+
self.close_btn = QPushButton(self.tr("Close"))
|
|
196
199
|
row1.addWidget(self.preview_btn); row1.addWidget(self.undo_btn)
|
|
197
200
|
left_layout.addLayout(row1)
|
|
198
201
|
|
|
199
202
|
row2 = QHBoxLayout()
|
|
200
|
-
self.push_btn = QPushButton("Push")
|
|
203
|
+
self.push_btn = QPushButton(self.tr("Push"))
|
|
201
204
|
row2.addWidget(self.push_btn); row2.addWidget(self.close_btn)
|
|
202
205
|
left_layout.addLayout(row2)
|
|
203
206
|
|
|
@@ -333,7 +336,7 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
333
336
|
form.addRow("Rotation:", self.conv_rotation_slider)
|
|
334
337
|
|
|
335
338
|
layout.addLayout(form); layout.addStretch()
|
|
336
|
-
self.tabs.addTab(conv_tab, "Convolution")
|
|
339
|
+
self.tabs.addTab(conv_tab, self.tr("Convolution"))
|
|
337
340
|
|
|
338
341
|
def _build_deconvolution_tab(self):
|
|
339
342
|
deconv_tab = QWidget()
|
|
@@ -445,7 +448,7 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
445
448
|
|
|
446
449
|
outer_layout.addWidget(self.deconv_stack_container)
|
|
447
450
|
outer_layout.addStretch()
|
|
448
|
-
self.tabs.addTab(deconv_tab, "Deconvolution")
|
|
451
|
+
self.tabs.addTab(deconv_tab, self.tr("Deconvolution"))
|
|
449
452
|
|
|
450
453
|
# Clear “custom PSF” if sliders change
|
|
451
454
|
for s in (self.rl_psf_radius_slider, self.rl_psf_shape_slider, self.rl_psf_aspect_slider, self.rl_psf_rotation_slider):
|
|
@@ -486,7 +489,7 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
486
489
|
layout.addWidget(self.sep_psf_preview, alignment=Qt.AlignmentFlag.AlignHCenter)
|
|
487
490
|
|
|
488
491
|
layout.addStretch()
|
|
489
|
-
self.tabs.addTab(psf_tab, "PSF Estimator")
|
|
492
|
+
self.tabs.addTab(psf_tab, self.tr("PSF Estimator"))
|
|
490
493
|
|
|
491
494
|
def _build_tv_denoise_tab(self):
|
|
492
495
|
tvd_tab = QWidget(); layout = QVBoxLayout(tvd_tab)
|
|
@@ -499,7 +502,7 @@ class ConvoDeconvoDialog(QDialog):
|
|
|
499
502
|
self.tv_multichannel_checkbox.setToolTip("If checked and the image is color, run TV on all channels jointly")
|
|
500
503
|
form.addRow("", self.tv_multichannel_checkbox)
|
|
501
504
|
layout.addLayout(form); layout.addStretch()
|
|
502
|
-
self.tabs.addTab(tvd_tab, "TV Denoise")
|
|
505
|
+
self.tabs.addTab(tvd_tab, self.tr("TV Denoise"))
|
|
503
506
|
|
|
504
507
|
# ---------------- UI reactions ----------------
|
|
505
508
|
def _on_deconv_algo_changed(self, selected: str):
|