setiastrosuitepro 1.6.5.post3__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.
- setiastro/__init__.py +2 -0
- 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/__init__.py +20 -0
- setiastro/saspro/__main__.py +958 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +3 -0
- setiastro/saspro/abe.py +1346 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +698 -0
- setiastro/saspro/aberration_ai_preset.py +224 -0
- setiastro/saspro/accel_installer.py +218 -0
- setiastro/saspro/accel_workers.py +30 -0
- setiastro/saspro/add_stars.py +624 -0
- setiastro/saspro/astrobin_exporter.py +1010 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1841 -0
- setiastro/saspro/autostretch.py +198 -0
- setiastro/saspro/backgroundneutral.py +611 -0
- setiastro/saspro/batch_convert.py +328 -0
- setiastro/saspro/batch_renamer.py +522 -0
- setiastro/saspro/blemish_blaster.py +491 -0
- setiastro/saspro/blink_comparator_pro.py +3149 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +213 -0
- setiastro/saspro/clahe.py +368 -0
- setiastro/saspro/comet_stacking.py +1442 -0
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/config.py +38 -0
- setiastro/saspro/config_bootstrap.py +40 -0
- setiastro/saspro/config_manager.py +316 -0
- setiastro/saspro/continuum_subtract.py +1617 -0
- setiastro/saspro/convo.py +1400 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +190 -0
- setiastro/saspro/cosmicclarity.py +1589 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +983 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2562 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +673 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2664 -0
- setiastro/saspro/exoplanet_detector.py +2166 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +748 -0
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1349 -0
- setiastro/saspro/function_bundle.py +1596 -0
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +663 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +637 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8792 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
- setiastro/saspro/gui/mixins/file_mixin.py +450 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
- setiastro/saspro/gui/mixins/header_mixin.py +441 -0
- setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
- setiastro/saspro/gui/mixins/menu_mixin.py +390 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1619 -0
- setiastro/saspro/gui/mixins/update_mixin.py +323 -0
- setiastro/saspro/gui/mixins/view_mixin.py +435 -0
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +488 -0
- setiastro/saspro/header_viewer.py +448 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +756 -0
- setiastro/saspro/history_explorer.py +941 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +417 -0
- setiastro/saspro/image_peeker_pro.py +1604 -0
- setiastro/saspro/imageops/__init__.py +37 -0
- setiastro/saspro/imageops/mdi_snap.py +292 -0
- setiastro/saspro/imageops/scnr.py +36 -0
- setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
- setiastro/saspro/imageops/stretch.py +236 -0
- setiastro/saspro/isophote.py +1182 -0
- setiastro/saspro/layers.py +208 -0
- setiastro/saspro/layers_dock.py +714 -0
- setiastro/saspro/lazy_imports.py +193 -0
- setiastro/saspro/legacy/__init__.py +2 -0
- setiastro/saspro/legacy/image_manager.py +2360 -0
- setiastro/saspro/legacy/numba_utils.py +3676 -0
- setiastro/saspro/legacy/xisf.py +1213 -0
- setiastro/saspro/linear_fit.py +537 -0
- setiastro/saspro/live_stacking.py +1854 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +510 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +1086 -0
- setiastro/saspro/masks_core.py +56 -0
- setiastro/saspro/mdi_widgets.py +353 -0
- setiastro/saspro/memory_utils.py +666 -0
- setiastro/saspro/metadata_patcher.py +75 -0
- setiastro/saspro/mfdeconv.py +3909 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3312 -0
- setiastro/saspro/mfdeconvsport.py +2459 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +407 -0
- setiastro/saspro/multiscale_decomp.py +1747 -0
- setiastro/saspro/nbtorgb_stars.py +541 -0
- setiastro/saspro/numba_utils.py +3145 -0
- setiastro/saspro/numba_warmup.py +141 -0
- setiastro/saspro/ops/__init__.py +9 -0
- setiastro/saspro/ops/command_help_dialog.py +623 -0
- setiastro/saspro/ops/command_runner.py +217 -0
- setiastro/saspro/ops/commands.py +1594 -0
- setiastro/saspro/ops/script_editor.py +1105 -0
- setiastro/saspro/ops/scripts.py +1476 -0
- setiastro/saspro/ops/settings.py +637 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1105 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1604 -0
- setiastro/saspro/plate_solver.py +2445 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +549 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +331 -0
- setiastro/saspro/remove_stars.py +1599 -0
- setiastro/saspro/remove_stars_preset.py +446 -0
- setiastro/saspro/resources.py +503 -0
- setiastro/saspro/rgb_combination.py +208 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +723 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +73 -0
- setiastro/saspro/selective_color.py +1611 -0
- setiastro/saspro/sfcc.py +1472 -0
- setiastro/saspro/shortcuts.py +3116 -0
- setiastro/saspro/signature_insert.py +1102 -0
- setiastro/saspro/stacking_suite.py +19066 -0
- setiastro/saspro/star_alignment.py +7380 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +765 -0
- setiastro/saspro/star_stretch.py +507 -0
- setiastro/saspro/stat_stretch.py +538 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3407 -0
- setiastro/saspro/supernovaasteroidhunter.py +1719 -0
- setiastro/saspro/swap_manager.py +134 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- 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 +1558 -0
- setiastro/saspro/wavescale_hdr.py +645 -0
- setiastro/saspro/wavescale_hdr_preset.py +101 -0
- setiastro/saspro/wavescalede.py +680 -0
- setiastro/saspro/wavescalede_preset.py +230 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +513 -0
- setiastro/saspro/widgets/__init__.py +48 -0
- setiastro/saspro/widgets/common_utilities.py +306 -0
- setiastro/saspro/widgets/graphics_views.py +122 -0
- setiastro/saspro/widgets/image_utils.py +518 -0
- 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 +280 -0
- setiastro/saspro/widgets/resource_monitor.py +263 -0
- setiastro/saspro/widgets/spinboxes.py +290 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +331 -0
- setiastro/saspro/wimi.py +7996 -0
- setiastro/saspro/wims.py +578 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1213 -0
- setiastrosuitepro-1.6.5.post3.dist-info/METADATA +278 -0
- setiastrosuitepro-1.6.5.post3.dist-info/RECORD +368 -0
- setiastrosuitepro-1.6.5.post3.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.5.post3.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.5.post3.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.5.post3.dist-info/licenses/license.txt +2580 -0
|
@@ -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?")
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# pro/config.py
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from PyQt6.QtCore import QStandardPaths
|
|
5
|
+
|
|
6
|
+
class Config:
|
|
7
|
+
"""Central configuration for Seti Astro Suite Pro."""
|
|
8
|
+
|
|
9
|
+
# GitHub Repos
|
|
10
|
+
GITHUB_ABERRATION_REPO = "riccardoalberghi/abberation_models"
|
|
11
|
+
|
|
12
|
+
# Paths
|
|
13
|
+
@staticmethod
|
|
14
|
+
def get_app_data_dir() -> str:
|
|
15
|
+
"""Returns the application data directory."""
|
|
16
|
+
base = QStandardPaths.writableLocation(QStandardPaths.StandardLocation.AppDataLocation)
|
|
17
|
+
if not base:
|
|
18
|
+
base = os.path.expanduser("~/.local/share/SetiAstro")
|
|
19
|
+
return base
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def get_models_dir() -> str:
|
|
23
|
+
"""Returns the directory for storing AI models."""
|
|
24
|
+
return os.path.join(Config.get_app_data_dir(), "Models")
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def get_aberration_models_dir() -> str:
|
|
28
|
+
"""Returns the directory for Aberration AI models."""
|
|
29
|
+
return os.path.join(Config.get_models_dir(), "aberration_ai")
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def get_graxpert_default_path() -> str | None:
|
|
33
|
+
"""Returns the default GraXpert executable path based on OS."""
|
|
34
|
+
if sys.platform == "darwin":
|
|
35
|
+
return "/Applications/GraXpert.app/Contents/MacOS/GraXpert"
|
|
36
|
+
elif sys.platform == "win32":
|
|
37
|
+
return "GraXpert.exe"
|
|
38
|
+
return None
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized matplotlib configuration bootstrap.
|
|
3
|
+
|
|
4
|
+
This module provides a single source of truth for setting up matplotlib's
|
|
5
|
+
configuration directory, used by both the main application entry point and
|
|
6
|
+
the GUI main window.
|
|
7
|
+
"""
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def ensure_mpl_config_dir() -> str:
|
|
13
|
+
"""
|
|
14
|
+
Make matplotlib use a known, writable folder.
|
|
15
|
+
|
|
16
|
+
Frozen (PyInstaller): <folder-with-exe>/mpl_config
|
|
17
|
+
Dev / IDE: <repo-folder>/mpl_config
|
|
18
|
+
|
|
19
|
+
This matches the pre-warm script that will build the font cache there.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: Path to the matplotlib configuration directory
|
|
23
|
+
"""
|
|
24
|
+
if getattr(sys, "frozen", False):
|
|
25
|
+
base = os.path.dirname(sys.executable)
|
|
26
|
+
else:
|
|
27
|
+
base = os.path.dirname(os.path.abspath(__file__))
|
|
28
|
+
# We're in pro/ directory, go up one level to project root
|
|
29
|
+
base = os.path.dirname(base)
|
|
30
|
+
|
|
31
|
+
mpl_cfg = os.path.join(base, "mpl_config")
|
|
32
|
+
try:
|
|
33
|
+
os.makedirs(mpl_cfg, exist_ok=True)
|
|
34
|
+
except OSError:
|
|
35
|
+
# worst case: let matplotlib pick its default
|
|
36
|
+
return mpl_cfg
|
|
37
|
+
|
|
38
|
+
# only set if user / env didn't force something else
|
|
39
|
+
os.environ.setdefault("MPLCONFIGDIR", mpl_cfg)
|
|
40
|
+
return mpl_cfg
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# pro/config_manager.py
|
|
2
|
+
"""
|
|
3
|
+
Centralized configuration manager for Seti Astro Suite Pro.
|
|
4
|
+
|
|
5
|
+
Provides type-safe access to application settings with validation,
|
|
6
|
+
defaults, and change notifications.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, Optional, TypeVar, Generic, Callable, List
|
|
11
|
+
from PyQt6.QtCore import QSettings, QObject, pyqtSignal
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
T = TypeVar('T')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ConfigValue(Generic[T]):
|
|
19
|
+
"""
|
|
20
|
+
Descriptor for a typed configuration value.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
class MyConfig(ConfigManager):
|
|
24
|
+
my_setting = ConfigValue("my_setting", default=10, type_=int)
|
|
25
|
+
"""
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
key: str,
|
|
29
|
+
default: T,
|
|
30
|
+
type_: type = str,
|
|
31
|
+
validator: Callable[[T], bool] | None = None,
|
|
32
|
+
description: str = ""
|
|
33
|
+
):
|
|
34
|
+
self.key = key
|
|
35
|
+
self.default = default
|
|
36
|
+
self.type_ = type_
|
|
37
|
+
self.validator = validator
|
|
38
|
+
self.description = description
|
|
39
|
+
|
|
40
|
+
def __set_name__(self, owner, name):
|
|
41
|
+
self.name = name
|
|
42
|
+
|
|
43
|
+
def __get__(self, obj, objtype=None) -> T:
|
|
44
|
+
if obj is None:
|
|
45
|
+
return self # type: ignore
|
|
46
|
+
return obj.get(self.key, self.default, self.type_)
|
|
47
|
+
|
|
48
|
+
def __set__(self, obj, value: T):
|
|
49
|
+
if self.validator and not self.validator(value):
|
|
50
|
+
raise ValueError(f"Invalid value for {self.key}: {value}")
|
|
51
|
+
obj.set(self.key, value)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ConfigManager(QObject):
|
|
55
|
+
"""
|
|
56
|
+
Centralized configuration manager with type safety.
|
|
57
|
+
|
|
58
|
+
Wraps QSettings with:
|
|
59
|
+
- Type-safe get/set
|
|
60
|
+
- Default values
|
|
61
|
+
- Change notifications
|
|
62
|
+
- Validation
|
|
63
|
+
|
|
64
|
+
Usage:
|
|
65
|
+
config = ConfigManager.instance()
|
|
66
|
+
config.set("my_key", 42)
|
|
67
|
+
value = config.get("my_key", default=0, type_=int)
|
|
68
|
+
|
|
69
|
+
Or with descriptors:
|
|
70
|
+
class AppConfig(ConfigManager):
|
|
71
|
+
chunk_height = ConfigValue("stacking/chunk_height", default=512, type_=int)
|
|
72
|
+
|
|
73
|
+
config = AppConfig.instance()
|
|
74
|
+
print(config.chunk_height)
|
|
75
|
+
config.chunk_height = 1024
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
# Singleton instance
|
|
79
|
+
_instance: Optional['ConfigManager'] = None
|
|
80
|
+
|
|
81
|
+
# Signal emitted when any setting changes
|
|
82
|
+
settingChanged = pyqtSignal(str, object) # key, new_value
|
|
83
|
+
|
|
84
|
+
def __init__(self, organization: str = "SetiAstro", application: str = "SetiAstroSuitePro"):
|
|
85
|
+
super().__init__()
|
|
86
|
+
self._settings = QSettings(organization, application)
|
|
87
|
+
self._cache: Dict[str, Any] = {}
|
|
88
|
+
self._listeners: Dict[str, List[Callable]] = {}
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def instance(cls) -> 'ConfigManager':
|
|
92
|
+
"""Get the singleton instance."""
|
|
93
|
+
if cls._instance is None:
|
|
94
|
+
cls._instance = cls()
|
|
95
|
+
return cls._instance
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def reset_instance(cls):
|
|
99
|
+
"""Reset the singleton (mainly for testing)."""
|
|
100
|
+
cls._instance = None
|
|
101
|
+
|
|
102
|
+
def get(self, key: str, default: T = None, type_: type = str) -> T:
|
|
103
|
+
"""
|
|
104
|
+
Get a configuration value with type conversion.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
key: The setting key (can use "/" for groups, e.g., "stacking/chunk_size")
|
|
108
|
+
default: Default value if key doesn't exist
|
|
109
|
+
type_: Expected type (int, float, bool, str, list, dict)
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
The value converted to the specified type
|
|
113
|
+
"""
|
|
114
|
+
# Check cache first
|
|
115
|
+
cache_key = f"{key}:{type_.__name__}"
|
|
116
|
+
if cache_key in self._cache:
|
|
117
|
+
return self._cache[cache_key]
|
|
118
|
+
|
|
119
|
+
value = self._settings.value(key, default)
|
|
120
|
+
|
|
121
|
+
# Convert to requested type
|
|
122
|
+
if value is None:
|
|
123
|
+
return default
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
if type_ == bool:
|
|
127
|
+
# QSettings stores bools as strings sometimes
|
|
128
|
+
if isinstance(value, str):
|
|
129
|
+
value = value.lower() in ('true', '1', 'yes')
|
|
130
|
+
else:
|
|
131
|
+
value = bool(value)
|
|
132
|
+
elif type_ == int:
|
|
133
|
+
value = int(value)
|
|
134
|
+
elif type_ == float:
|
|
135
|
+
value = float(value)
|
|
136
|
+
elif type_ == list:
|
|
137
|
+
if isinstance(value, str):
|
|
138
|
+
value = json.loads(value) if value else []
|
|
139
|
+
elif not isinstance(value, list):
|
|
140
|
+
value = list(value) if value else []
|
|
141
|
+
elif type_ == dict:
|
|
142
|
+
if isinstance(value, str):
|
|
143
|
+
value = json.loads(value) if value else {}
|
|
144
|
+
elif not isinstance(value, dict):
|
|
145
|
+
value = {}
|
|
146
|
+
else:
|
|
147
|
+
value = type_(value)
|
|
148
|
+
except (ValueError, TypeError, json.JSONDecodeError):
|
|
149
|
+
value = default
|
|
150
|
+
|
|
151
|
+
# Cache the result
|
|
152
|
+
self._cache[cache_key] = value
|
|
153
|
+
return value
|
|
154
|
+
|
|
155
|
+
def set(self, key: str, value: Any) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Set a configuration value.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
key: The setting key
|
|
161
|
+
value: The value to store
|
|
162
|
+
"""
|
|
163
|
+
# Invalidate cache for this key
|
|
164
|
+
for cache_key in list(self._cache.keys()):
|
|
165
|
+
if cache_key.startswith(f"{key}:"):
|
|
166
|
+
del self._cache[cache_key]
|
|
167
|
+
|
|
168
|
+
# Convert complex types to JSON for storage
|
|
169
|
+
if isinstance(value, (list, dict)):
|
|
170
|
+
value = json.dumps(value)
|
|
171
|
+
|
|
172
|
+
self._settings.setValue(key, value)
|
|
173
|
+
|
|
174
|
+
# Emit signal
|
|
175
|
+
self.settingChanged.emit(key, value)
|
|
176
|
+
|
|
177
|
+
# Notify listeners
|
|
178
|
+
if key in self._listeners:
|
|
179
|
+
for callback in self._listeners[key]:
|
|
180
|
+
try:
|
|
181
|
+
callback(value)
|
|
182
|
+
except Exception:
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
def remove(self, key: str) -> None:
|
|
186
|
+
"""Remove a setting."""
|
|
187
|
+
# Invalidate cache
|
|
188
|
+
for cache_key in list(self._cache.keys()):
|
|
189
|
+
if cache_key.startswith(f"{key}:"):
|
|
190
|
+
del self._cache[cache_key]
|
|
191
|
+
|
|
192
|
+
self._settings.remove(key)
|
|
193
|
+
|
|
194
|
+
def contains(self, key: str) -> bool:
|
|
195
|
+
"""Check if a setting exists."""
|
|
196
|
+
return self._settings.contains(key)
|
|
197
|
+
|
|
198
|
+
def all_keys(self) -> List[str]:
|
|
199
|
+
"""Get all setting keys."""
|
|
200
|
+
return self._settings.allKeys()
|
|
201
|
+
|
|
202
|
+
def clear(self) -> None:
|
|
203
|
+
"""Clear all settings."""
|
|
204
|
+
self._cache.clear()
|
|
205
|
+
self._settings.clear()
|
|
206
|
+
|
|
207
|
+
def sync(self) -> None:
|
|
208
|
+
"""Force sync to disk."""
|
|
209
|
+
self._settings.sync()
|
|
210
|
+
|
|
211
|
+
def add_listener(self, key: str, callback: Callable[[Any], None]) -> None:
|
|
212
|
+
"""
|
|
213
|
+
Add a listener for changes to a specific key.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
key: The setting key to watch
|
|
217
|
+
callback: Function to call when value changes
|
|
218
|
+
"""
|
|
219
|
+
if key not in self._listeners:
|
|
220
|
+
self._listeners[key] = []
|
|
221
|
+
self._listeners[key].append(callback)
|
|
222
|
+
|
|
223
|
+
def remove_listener(self, key: str, callback: Callable[[Any], None]) -> None:
|
|
224
|
+
"""Remove a listener."""
|
|
225
|
+
if key in self._listeners and callback in self._listeners[key]:
|
|
226
|
+
self._listeners[key].remove(callback)
|
|
227
|
+
|
|
228
|
+
def begin_group(self, prefix: str) -> None:
|
|
229
|
+
"""Begin a settings group (for hierarchical settings)."""
|
|
230
|
+
self._settings.beginGroup(prefix)
|
|
231
|
+
|
|
232
|
+
def end_group(self) -> None:
|
|
233
|
+
"""End the current settings group."""
|
|
234
|
+
self._settings.endGroup()
|
|
235
|
+
|
|
236
|
+
def get_group(self, prefix: str) -> Dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
Get all settings in a group as a dictionary.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
prefix: The group prefix
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Dictionary of key -> value for all settings in the group
|
|
245
|
+
"""
|
|
246
|
+
result = {}
|
|
247
|
+
self._settings.beginGroup(prefix)
|
|
248
|
+
for key in self._settings.childKeys():
|
|
249
|
+
result[key] = self._settings.value(key)
|
|
250
|
+
self._settings.endGroup()
|
|
251
|
+
return result
|
|
252
|
+
|
|
253
|
+
def set_group(self, prefix: str, values: Dict[str, Any]) -> None:
|
|
254
|
+
"""
|
|
255
|
+
Set multiple settings in a group.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
prefix: The group prefix
|
|
259
|
+
values: Dictionary of key -> value to set
|
|
260
|
+
"""
|
|
261
|
+
self._settings.beginGroup(prefix)
|
|
262
|
+
for key, value in values.items():
|
|
263
|
+
if isinstance(value, (list, dict)):
|
|
264
|
+
value = json.dumps(value)
|
|
265
|
+
self._settings.setValue(key, value)
|
|
266
|
+
self._settings.endGroup()
|
|
267
|
+
self._cache.clear() # Invalidate all cache
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
# Convenience function
|
|
271
|
+
def get_config() -> ConfigManager:
|
|
272
|
+
"""Get the global configuration manager."""
|
|
273
|
+
return ConfigManager.instance()
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# ============================================================================
|
|
277
|
+
# Application-specific configuration class with typed properties
|
|
278
|
+
# ============================================================================
|
|
279
|
+
|
|
280
|
+
class AppConfig(ConfigManager):
|
|
281
|
+
"""
|
|
282
|
+
Application configuration with typed properties.
|
|
283
|
+
|
|
284
|
+
Usage:
|
|
285
|
+
config = AppConfig.instance()
|
|
286
|
+
print(config.chunk_height)
|
|
287
|
+
config.chunk_height = 1024
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
# Stacking settings
|
|
291
|
+
chunk_height = ConfigValue("stacking/chunk_height", default=512, type_=int)
|
|
292
|
+
chunk_width = ConfigValue("stacking/chunk_width", default=512, type_=int)
|
|
293
|
+
use_gpu = ConfigValue("stacking/use_gpu", default=True, type_=bool)
|
|
294
|
+
rejection_algorithm = ConfigValue("stacking/rejection_algorithm", default="sigma_clip", type_=str)
|
|
295
|
+
|
|
296
|
+
# UI settings
|
|
297
|
+
theme = ConfigValue("ui/theme", default="dark", type_=str)
|
|
298
|
+
show_toolbar = ConfigValue("ui/show_toolbar", default=True, type_=bool)
|
|
299
|
+
recent_files_max = ConfigValue("ui/recent_files_max", default=10, type_=int)
|
|
300
|
+
|
|
301
|
+
# Performance settings
|
|
302
|
+
max_threads = ConfigValue("performance/max_threads", default=0, type_=int) # 0 = auto
|
|
303
|
+
memory_limit_mb = ConfigValue("performance/memory_limit_mb", default=0, type_=int) # 0 = no limit
|
|
304
|
+
use_memmap = ConfigValue("performance/use_memmap", default=True, type_=bool)
|
|
305
|
+
|
|
306
|
+
# Paths
|
|
307
|
+
last_open_dir = ConfigValue("paths/last_open_dir", default="", type_=str)
|
|
308
|
+
last_save_dir = ConfigValue("paths/last_save_dir", default="", type_=str)
|
|
309
|
+
output_dir = ConfigValue("paths/output_dir", default="", type_=str)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def get_app_config() -> AppConfig:
|
|
313
|
+
"""Get the application configuration with typed properties."""
|
|
314
|
+
if AppConfig._instance is None:
|
|
315
|
+
AppConfig._instance = AppConfig()
|
|
316
|
+
return AppConfig._instance # type: ignore
|