setiastrosuitepro 1.6.12__py3-none-any.whl → 1.7.3__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/images/3dplanet.png +0 -0
- setiastro/images/TextureClarity.svg +56 -0
- setiastro/images/narrowbandnormalization.png +0 -0
- setiastro/images/planetarystacker.png +0 -0
- setiastro/saspro/__init__.py +9 -8
- setiastro/saspro/__main__.py +326 -285
- setiastro/saspro/_generated/build_info.py +2 -2
- setiastro/saspro/aberration_ai.py +128 -13
- setiastro/saspro/aberration_ai_preset.py +29 -3
- setiastro/saspro/astrospike_python.py +45 -3
- setiastro/saspro/blink_comparator_pro.py +116 -71
- setiastro/saspro/curve_editor_pro.py +72 -22
- setiastro/saspro/curves_preset.py +249 -47
- setiastro/saspro/doc_manager.py +4 -1
- setiastro/saspro/gui/main_window.py +326 -46
- setiastro/saspro/gui/mixins/file_mixin.py +41 -18
- setiastro/saspro/gui/mixins/menu_mixin.py +9 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +123 -7
- setiastro/saspro/histogram.py +179 -7
- setiastro/saspro/imageops/narrowband_normalization.py +816 -0
- setiastro/saspro/imageops/serloader.py +1429 -0
- setiastro/saspro/layers.py +186 -10
- setiastro/saspro/layers_dock.py +198 -5
- setiastro/saspro/legacy/image_manager.py +10 -4
- setiastro/saspro/legacy/numba_utils.py +1 -1
- setiastro/saspro/live_stacking.py +24 -4
- setiastro/saspro/multiscale_decomp.py +30 -17
- setiastro/saspro/narrowband_normalization.py +1618 -0
- setiastro/saspro/planetprojection.py +3854 -0
- setiastro/saspro/remove_green.py +1 -1
- setiastro/saspro/resources.py +8 -0
- setiastro/saspro/rgbalign.py +456 -12
- setiastro/saspro/save_options.py +45 -13
- setiastro/saspro/ser_stack_config.py +102 -0
- setiastro/saspro/ser_stacker.py +2327 -0
- setiastro/saspro/ser_stacker_dialog.py +1865 -0
- setiastro/saspro/ser_tracking.py +228 -0
- setiastro/saspro/serviewer.py +1773 -0
- setiastro/saspro/sfcc.py +298 -64
- setiastro/saspro/shortcuts.py +14 -7
- setiastro/saspro/stacking_suite.py +21 -6
- setiastro/saspro/stat_stretch.py +179 -31
- setiastro/saspro/subwindow.py +38 -5
- setiastro/saspro/texture_clarity.py +593 -0
- setiastro/saspro/widgets/resource_monitor.py +122 -74
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/METADATA +3 -2
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/RECORD +51 -37
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/WHEEL +0 -0
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/entry_points.txt +0 -0
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/licenses/LICENSE +0 -0
- {setiastrosuitepro-1.6.12.dist-info → setiastrosuitepro-1.7.3.dist-info}/licenses/license.txt +0 -0
setiastro/saspro/__main__.py
CHANGED
|
@@ -12,6 +12,27 @@ called via the `main()` function when invoked as an entry point.
|
|
|
12
12
|
import sys
|
|
13
13
|
import os
|
|
14
14
|
|
|
15
|
+
_STARTUP_PROFILE = os.environ.get("SASPRO_STARTUP_PROFILE", "").strip().lower() in ("1","true","yes","on")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _is_wayland_session() -> bool:
|
|
19
|
+
# Best-effort detection that does NOT require a QApplication instance
|
|
20
|
+
xdg = (os.environ.get("XDG_SESSION_TYPE") or "").lower()
|
|
21
|
+
if xdg == "wayland":
|
|
22
|
+
return True
|
|
23
|
+
# QT can still run wayland even if XDG_SESSION_TYPE isn't set
|
|
24
|
+
if os.environ.get("WAYLAND_DISPLAY"):
|
|
25
|
+
return True
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
def _allow_window_opacity_effects() -> bool:
|
|
29
|
+
# User override: allow opacity effects even on Wayland if they want
|
|
30
|
+
if os.environ.get("SASPRO_ALLOW_OPACITY", "").strip().lower() in ("1","true","yes","on"):
|
|
31
|
+
return True
|
|
32
|
+
# Default: disable opacity effects on Wayland
|
|
33
|
+
return not _is_wayland_session()
|
|
34
|
+
|
|
35
|
+
|
|
15
36
|
from pathlib import Path
|
|
16
37
|
|
|
17
38
|
if sys.platform.startswith("win"):
|
|
@@ -24,7 +45,7 @@ if sys.platform.startswith("win"):
|
|
|
24
45
|
pass
|
|
25
46
|
os.environ["PATH"] = str(internal) + os.pathsep + os.environ.get("PATH", "")
|
|
26
47
|
|
|
27
|
-
|
|
48
|
+
|
|
28
49
|
|
|
29
50
|
# ---- Linux Qt stability guard (must run BEFORE any PyQt6 import) ----
|
|
30
51
|
# Default behavior: DO NOT override Wayland.
|
|
@@ -41,6 +62,8 @@ if sys.platform.startswith("linux"):
|
|
|
41
62
|
os.environ.setdefault("QT_OPENGL", "software")
|
|
42
63
|
os.environ.setdefault("LIBGL_ALWAYS_SOFTWARE", "1")
|
|
43
64
|
|
|
65
|
+
from PyQt6.QtCore import QCoreApplication
|
|
66
|
+
|
|
44
67
|
# Global variables for splash screen and app
|
|
45
68
|
_splash = None
|
|
46
69
|
_app = None
|
|
@@ -48,6 +71,10 @@ _app = None
|
|
|
48
71
|
# Flag to track if splash was initialized
|
|
49
72
|
_splash_initialized = False
|
|
50
73
|
|
|
74
|
+
# Flag to ensure heavy imports/bootstrap happens only once
|
|
75
|
+
_imports_bootstrapped = False
|
|
76
|
+
|
|
77
|
+
|
|
51
78
|
from setiastro.saspro.versioning import get_app_version
|
|
52
79
|
_EARLY_VERSION = get_app_version("setiastrosuitepro")
|
|
53
80
|
|
|
@@ -414,6 +441,9 @@ def _init_splash():
|
|
|
414
441
|
self.deleteLater()
|
|
415
442
|
|
|
416
443
|
def start_fade_out(self):
|
|
444
|
+
if not _allow_window_opacity_effects():
|
|
445
|
+
self.finish()
|
|
446
|
+
return
|
|
417
447
|
"""Smoothly fade out the splash screen."""
|
|
418
448
|
self._anim = QPropertyAnimation(self, b"windowOpacity")
|
|
419
449
|
self._anim.setDuration(1000)
|
|
@@ -424,7 +454,9 @@ def _init_splash():
|
|
|
424
454
|
self._anim.start()
|
|
425
455
|
|
|
426
456
|
def start_fade_in(self):
|
|
427
|
-
|
|
457
|
+
if not _allow_window_opacity_effects():
|
|
458
|
+
self.setWindowOpacity(1.0)
|
|
459
|
+
return
|
|
428
460
|
self.setWindowOpacity(0.0)
|
|
429
461
|
self._anim = QPropertyAnimation(self, b"windowOpacity")
|
|
430
462
|
self._anim.setDuration(800)
|
|
@@ -462,11 +494,6 @@ def _init_splash():
|
|
|
462
494
|
_splash_initialized = True
|
|
463
495
|
|
|
464
496
|
|
|
465
|
-
# Initialize splash immediately before any heavy imports
|
|
466
|
-
# This ensures the splash is visible while PyTorch, NumPy, etc. are loading
|
|
467
|
-
_init_splash()
|
|
468
|
-
|
|
469
|
-
|
|
470
497
|
# =============================================================================
|
|
471
498
|
# Now proceed with all the heavy imports (splash is visible)
|
|
472
499
|
# =============================================================================
|
|
@@ -478,271 +505,279 @@ def _update_splash(msg: str, progress: int):
|
|
|
478
505
|
_splash.setMessage(msg)
|
|
479
506
|
_splash.setProgress(progress)
|
|
480
507
|
|
|
481
|
-
|
|
508
|
+
def _bootstrap_imports():
|
|
509
|
+
"""
|
|
510
|
+
Heavy imports + runtime bootstrap.
|
|
511
|
+
This must NOT run at module import time, only when main() is called.
|
|
512
|
+
"""
|
|
513
|
+
global _imports_bootstrapped
|
|
514
|
+
if _imports_bootstrapped:
|
|
515
|
+
return
|
|
516
|
+
_imports_bootstrapped = True
|
|
517
|
+
|
|
518
|
+
# Make sure splash exists before we start doing heavy work
|
|
519
|
+
if not _splash_initialized:
|
|
520
|
+
_init_splash()
|
|
521
|
+
|
|
522
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading PyTorch runtime..."), 5)
|
|
523
|
+
|
|
524
|
+
from setiastro.saspro.runtime_torch import (
|
|
525
|
+
add_runtime_to_sys_path,
|
|
526
|
+
_ban_shadow_torch_paths,
|
|
527
|
+
_purge_bad_torch_from_sysmodules,
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
add_runtime_to_sys_path(status_cb=lambda *_: None)
|
|
531
|
+
_ban_shadow_torch_paths(status_cb=lambda *_: None)
|
|
532
|
+
_purge_bad_torch_from_sysmodules(status_cb=lambda *_: None)
|
|
533
|
+
|
|
534
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading standard libraries..."), 10)
|
|
535
|
+
|
|
536
|
+
# ----------------------------------------
|
|
537
|
+
# Standard library imports (consolidated)
|
|
538
|
+
# ----------------------------------------
|
|
539
|
+
import importlib
|
|
540
|
+
import json
|
|
541
|
+
import logging
|
|
542
|
+
import math
|
|
543
|
+
import multiprocessing
|
|
544
|
+
import os
|
|
545
|
+
import re
|
|
546
|
+
import sys
|
|
547
|
+
import threading
|
|
548
|
+
import time
|
|
549
|
+
import traceback
|
|
550
|
+
import warnings
|
|
551
|
+
import webbrowser
|
|
552
|
+
|
|
553
|
+
from collections import defaultdict
|
|
554
|
+
from datetime import datetime
|
|
555
|
+
from decimal import getcontext
|
|
556
|
+
from io import BytesIO
|
|
557
|
+
from itertools import combinations
|
|
558
|
+
from math import isnan
|
|
559
|
+
from pathlib import Path
|
|
560
|
+
from typing import Dict, List, Optional, Set, Tuple
|
|
561
|
+
from urllib.parse import quote, quote_plus
|
|
482
562
|
|
|
483
|
-
|
|
484
|
-
add_runtime_to_sys_path,
|
|
485
|
-
_ban_shadow_torch_paths,
|
|
486
|
-
_purge_bad_torch_from_sysmodules,
|
|
487
|
-
)
|
|
563
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading NumPy..."), 15)
|
|
488
564
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
565
|
+
# ----------------------------------------
|
|
566
|
+
# Third-party imports
|
|
567
|
+
# ----------------------------------------
|
|
568
|
+
import numpy as np
|
|
492
569
|
|
|
493
|
-
_update_splash(QCoreApplication.translate("Splash", "Loading
|
|
570
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading image libraries..."), 20)
|
|
571
|
+
from tifffile import imwrite
|
|
572
|
+
from setiastro.saspro.xisf import XISF
|
|
494
573
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
import
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
# ----------------------------------------
|
|
525
|
-
# Third-party imports
|
|
526
|
-
# ----------------------------------------
|
|
527
|
-
import numpy as np
|
|
528
|
-
|
|
529
|
-
_update_splash(QCoreApplication.translate("Splash", "Loading image libraries..."), 20)
|
|
530
|
-
from tifffile import imwrite
|
|
531
|
-
from setiastro.saspro.xisf import XISF
|
|
532
|
-
|
|
533
|
-
_update_splash(QCoreApplication.translate("Splash", "Configuring matplotlib..."), 25)
|
|
534
|
-
from setiastro.saspro.config_bootstrap import ensure_mpl_config_dir
|
|
535
|
-
_MPL_CFG_DIR = ensure_mpl_config_dir()
|
|
536
|
-
|
|
537
|
-
# Apply metadata patches for frozen builds
|
|
538
|
-
from setiastro.saspro.metadata_patcher import apply_metadata_patches
|
|
539
|
-
apply_metadata_patches()
|
|
540
|
-
# ----------------------------------------
|
|
541
|
-
|
|
542
|
-
warnings.filterwarnings(
|
|
543
|
-
"ignore",
|
|
544
|
-
message=r"Call to deprecated function \(or staticmethod\) _destroy\.",
|
|
545
|
-
category=DeprecationWarning,
|
|
546
|
-
)
|
|
547
|
-
|
|
548
|
-
os.environ['LIGHTKURVE_STYLE'] = 'default'
|
|
549
|
-
|
|
550
|
-
# ----------------------------------------
|
|
551
|
-
# Matplotlib configuration
|
|
552
|
-
# ----------------------------------------
|
|
553
|
-
import matplotlib
|
|
554
|
-
matplotlib.use("QtAgg")
|
|
555
|
-
|
|
556
|
-
# Configure stdout encoding
|
|
557
|
-
if (sys.stdout is not None) and (hasattr(sys.stdout, "reconfigure")):
|
|
558
|
-
sys.stdout.reconfigure(encoding='utf-8')
|
|
559
|
-
|
|
560
|
-
# --- Lazy imports for heavy dependencies (performance optimization) ---
|
|
561
|
-
# photutils: loaded on first use
|
|
562
|
-
_photutils_isophote = None
|
|
563
|
-
def _get_photutils_isophote():
|
|
564
|
-
"""Lazy loader for photutils.isophote module."""
|
|
574
|
+
_update_splash(QCoreApplication.translate("Splash", "Configuring matplotlib..."), 25)
|
|
575
|
+
from setiastro.saspro.config_bootstrap import ensure_mpl_config_dir
|
|
576
|
+
_MPL_CFG_DIR = ensure_mpl_config_dir()
|
|
577
|
+
|
|
578
|
+
# Apply metadata patches for frozen builds
|
|
579
|
+
from setiastro.saspro.metadata_patcher import apply_metadata_patches
|
|
580
|
+
apply_metadata_patches()
|
|
581
|
+
|
|
582
|
+
warnings.filterwarnings(
|
|
583
|
+
"ignore",
|
|
584
|
+
message=r"Call to deprecated function \(or staticmethod\) _destroy\.",
|
|
585
|
+
category=DeprecationWarning,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
os.environ['LIGHTKURVE_STYLE'] = 'default'
|
|
589
|
+
|
|
590
|
+
# ----------------------------------------
|
|
591
|
+
# Matplotlib configuration
|
|
592
|
+
# ----------------------------------------
|
|
593
|
+
import matplotlib
|
|
594
|
+
matplotlib.use("QtAgg")
|
|
595
|
+
|
|
596
|
+
# Configure stdout encoding
|
|
597
|
+
if (sys.stdout is not None) and (hasattr(sys.stdout, "reconfigure")):
|
|
598
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
599
|
+
|
|
600
|
+
# --- Lazy imports for heavy dependencies (performance optimization) ---
|
|
601
|
+
# photutils: loaded on first use
|
|
565
602
|
global _photutils_isophote
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
_lightkurve_module = None
|
|
591
|
-
def get_lightkurve():
|
|
592
|
-
"""Lazy loader for lightkurve module."""
|
|
603
|
+
_photutils_isophote = None
|
|
604
|
+
|
|
605
|
+
def _get_photutils_isophote():
|
|
606
|
+
global _photutils_isophote
|
|
607
|
+
if _photutils_isophote is None:
|
|
608
|
+
try:
|
|
609
|
+
from photutils import isophote as _isophote_module
|
|
610
|
+
_photutils_isophote = _isophote_module
|
|
611
|
+
except Exception:
|
|
612
|
+
_photutils_isophote = False
|
|
613
|
+
return _photutils_isophote if _photutils_isophote else None
|
|
614
|
+
|
|
615
|
+
def get_Ellipse():
|
|
616
|
+
mod = _get_photutils_isophote()
|
|
617
|
+
return mod.Ellipse if mod else None
|
|
618
|
+
|
|
619
|
+
def get_EllipseGeometry():
|
|
620
|
+
mod = _get_photutils_isophote()
|
|
621
|
+
return mod.EllipseGeometry if mod else None
|
|
622
|
+
|
|
623
|
+
def get_build_ellipse_model():
|
|
624
|
+
mod = _get_photutils_isophote()
|
|
625
|
+
return mod.build_ellipse_model if mod else None
|
|
626
|
+
|
|
593
627
|
global _lightkurve_module
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
try:
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
except ImportError:
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
from PyQt6.
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
from setiastro.saspro.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
628
|
+
_lightkurve_module = None
|
|
629
|
+
|
|
630
|
+
def get_lightkurve():
|
|
631
|
+
global _lightkurve_module
|
|
632
|
+
if _lightkurve_module is None:
|
|
633
|
+
try:
|
|
634
|
+
import lightkurve as _lk
|
|
635
|
+
_lk.MPLSTYLE = None
|
|
636
|
+
_lightkurve_module = _lk
|
|
637
|
+
except Exception:
|
|
638
|
+
_lightkurve_module = False
|
|
639
|
+
return _lightkurve_module if _lightkurve_module else None
|
|
640
|
+
|
|
641
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading UI utilities..."), 30)
|
|
642
|
+
|
|
643
|
+
from setiastro.saspro.widgets.common_utilities import (
|
|
644
|
+
AboutDialog,
|
|
645
|
+
ProjectSaveWorker as _ProjectSaveWorker,
|
|
646
|
+
DECOR_GLYPHS,
|
|
647
|
+
_strip_ui_decorations,
|
|
648
|
+
install_crash_handlers,
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading reproject library..."), 35)
|
|
652
|
+
|
|
653
|
+
try:
|
|
654
|
+
from reproject import reproject_interp
|
|
655
|
+
except ImportError:
|
|
656
|
+
reproject_interp = None
|
|
657
|
+
|
|
658
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading OpenCV..."), 40)
|
|
659
|
+
|
|
660
|
+
try:
|
|
661
|
+
import cv2
|
|
662
|
+
OPENCV_AVAILABLE = True
|
|
663
|
+
except ImportError:
|
|
664
|
+
OPENCV_AVAILABLE = False
|
|
665
|
+
|
|
666
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading PyQt6 components..."), 45)
|
|
667
|
+
|
|
668
|
+
from PyQt6 import sip
|
|
669
|
+
|
|
670
|
+
from PyQt6.QtWidgets import (QDialog, QApplication, QMainWindow, QWidget, QHBoxLayout, QFileDialog, QMessageBox, QSizePolicy, QToolBar, QPushButton, QAbstractItemDelegate,
|
|
671
|
+
QLineEdit, QMenu, QListWidget, QListWidgetItem, QSplashScreen, QDockWidget, QListView, QCompleter, QMdiArea, QMdiSubWindow, QWidgetAction, QAbstractItemView,
|
|
672
|
+
QInputDialog, QVBoxLayout, QLabel, QCheckBox, QProgressBar, QProgressDialog, QGraphicsItem, QTabWidget, QTableWidget, QHeaderView, QTableWidgetItem, QToolButton, QPlainTextEdit
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
from PyQt6.QtGui import (QPixmap, QColor, QIcon, QKeySequence, QShortcut, QGuiApplication, QStandardItemModel, QStandardItem, QAction, QPalette, QBrush, QActionGroup, QDesktopServices, QFont, QTextCursor
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
from PyQt6.QtCore import (Qt, pyqtSignal, QTimer, QSize, QSignalBlocker, QModelIndex, QThread, QUrl, QSettings, QEvent, QByteArray, QObject,
|
|
679
|
+
QPropertyAnimation, QEasingCurve
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
|
684
|
+
|
|
685
|
+
global BUILD_TIMESTAMP
|
|
686
|
+
try:
|
|
687
|
+
from setiastro.saspro._generated.build_info import BUILD_TIMESTAMP
|
|
688
|
+
except Exception:
|
|
689
|
+
BUILD_TIMESTAMP = "dev"
|
|
690
|
+
|
|
691
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading resources..."), 50)
|
|
692
|
+
|
|
693
|
+
from setiastro.saspro.resources import (
|
|
694
|
+
icon_path, windowslogo_path, green_path, neutral_path, whitebalance_path,
|
|
695
|
+
morpho_path, clahe_path, starnet_path, staradd_path, LExtract_path,
|
|
696
|
+
LInsert_path, slot0_path, slot1_path, slot2_path, slot3_path, slot4_path,
|
|
697
|
+
rgbcombo_path, rgbextract_path, copyslot_path, graxperticon_path,
|
|
698
|
+
cropicon_path, openfile_path, abeicon_path, undoicon_path, redoicon_path,
|
|
699
|
+
blastericon_path, hdr_path, invert_path, fliphorizontal_path,
|
|
700
|
+
flipvertical_path, rotateclockwise_path, rotatecounterclockwise_path,
|
|
701
|
+
rotate180_path, maskcreate_path, maskapply_path, maskremove_path,
|
|
702
|
+
slot5_path, slot6_path, slot7_path, slot8_path, slot9_path, pixelmath_path,
|
|
703
|
+
histogram_path, mosaic_path, rescale_path, staralign_path, mask_path,
|
|
704
|
+
platesolve_path, psf_path, supernova_path, starregistration_path,
|
|
705
|
+
stacking_path, pedestal_icon_path, starspike_path, aperture_path,
|
|
706
|
+
jwstpupil_path, signature_icon_path, livestacking_path, hrdiagram_path,
|
|
707
|
+
convoicon_path, spcc_icon_path, sasp_data_path, exoicon_path, peeker_icon,
|
|
708
|
+
dse_icon_path, astrobin_filters_csv_path, isophote_path, statstretch_path,
|
|
709
|
+
starstretch_path, curves_path, disk_path, uhs_path, blink_path, ppp_path,
|
|
710
|
+
nbtorgb_path, freqsep_path, contsub_path, halo_path, cosmic_path,
|
|
711
|
+
satellite_path, imagecombine_path, wrench_path, eye_icon_path,
|
|
712
|
+
disk_icon_path, nuke_path, hubble_path, collage_path, annotated_path,
|
|
713
|
+
colorwheel_path, font_path, csv_icon_path, spinner_path, wims_path,
|
|
714
|
+
wimi_path, linearfit_path, debayer_path, aberration_path,
|
|
715
|
+
functionbundles_path, viewbundles_path, selectivecolor_path, rgbalign_path,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
_update_splash(QCoreApplication.translate("Splash", "Configuring Qt message handler..."), 55)
|
|
719
|
+
|
|
720
|
+
from PyQt6.QtCore import qInstallMessageHandler, QtMsgType
|
|
721
|
+
|
|
722
|
+
def _qt_msg_handler(mode, ctx, msg):
|
|
723
|
+
lvl = {
|
|
724
|
+
QtMsgType.QtDebugMsg: logging.DEBUG,
|
|
725
|
+
QtMsgType.QtInfoMsg: logging.INFO,
|
|
726
|
+
QtMsgType.QtWarningMsg: logging.WARNING,
|
|
727
|
+
QtMsgType.QtCriticalMsg: logging.ERROR,
|
|
728
|
+
QtMsgType.QtFatalMsg: logging.CRITICAL,
|
|
729
|
+
}.get(mode, logging.ERROR)
|
|
730
|
+
logging.log(lvl, "Qt: %s (%s:%s)", msg, getattr(ctx, "file", "?"), getattr(ctx, "line", -1))
|
|
731
|
+
|
|
732
|
+
qInstallMessageHandler(_qt_msg_handler)
|
|
733
|
+
|
|
734
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading MDI widgets..."), 60)
|
|
735
|
+
|
|
736
|
+
from setiastro.saspro.mdi_widgets import (
|
|
737
|
+
MdiArea, ViewLinkController, ConsoleListWidget, QtLogStream, _DocProxy,
|
|
738
|
+
ROLE_ACTION as _ROLE_ACTION,
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
from setiastro.saspro.main_helpers import (
|
|
742
|
+
safe_join_dir_and_name as _safe_join_dir_and_name,
|
|
743
|
+
normalize_save_path_chosen_filter as _normalize_save_path_chosen_filter,
|
|
744
|
+
display_name as _display_name,
|
|
745
|
+
best_doc_name as _best_doc_name,
|
|
746
|
+
doc_looks_like_table as _doc_looks_like_table,
|
|
747
|
+
is_alive as _is_alive,
|
|
748
|
+
safe_widget as _safe_widget,
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
from setiastro.saspro.file_utils import (
|
|
752
|
+
_normalize_ext,
|
|
753
|
+
_sanitize_filename,
|
|
754
|
+
_exts_from_filter,
|
|
755
|
+
REPLACE_SPACES_WITH_UNDERSCORES as _REPLACE_SPACES_WITH_UNDERSCORES,
|
|
756
|
+
WIN_RESERVED_NAMES as _WIN_RESERVED,
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
_update_splash(QCoreApplication.translate("Splash", "Loading main window module..."), 65)
|
|
760
|
+
|
|
761
|
+
from setiastro.saspro.gui.main_window import AstroSuiteProMainWindow
|
|
762
|
+
|
|
763
|
+
_update_splash(QCoreApplication.translate("Splash", "Modules loaded, finalizing..."), 70)
|
|
764
|
+
|
|
765
|
+
# Export things main() already relies on as globals (min disruption)
|
|
766
|
+
globals().update({
|
|
767
|
+
"logging": logging,
|
|
768
|
+
"multiprocessing": multiprocessing,
|
|
769
|
+
"warnings": warnings,
|
|
770
|
+
"QIcon": QIcon,
|
|
771
|
+
"QMessageBox": QMessageBox,
|
|
772
|
+
"QPropertyAnimation": QPropertyAnimation,
|
|
773
|
+
"QEasingCurve": QEasingCurve,
|
|
774
|
+
"windowslogo_path": windowslogo_path,
|
|
775
|
+
"icon_path": icon_path,
|
|
776
|
+
"install_crash_handlers": install_crash_handlers,
|
|
777
|
+
"AstroSuiteProMainWindow": AstroSuiteProMainWindow,
|
|
778
|
+
"BUILD_TIMESTAMP": BUILD_TIMESTAMP,
|
|
779
|
+
})
|
|
780
|
+
|
|
746
781
|
|
|
747
782
|
|
|
748
783
|
def main():
|
|
@@ -759,7 +794,8 @@ def main():
|
|
|
759
794
|
# Initialize splash if not already done
|
|
760
795
|
if not _splash_initialized:
|
|
761
796
|
_init_splash()
|
|
762
|
-
|
|
797
|
+
|
|
798
|
+
_bootstrap_imports()
|
|
763
799
|
# Update splash with build info now that we have VERSION and BUILD_TIMESTAMP
|
|
764
800
|
if _splash:
|
|
765
801
|
_splash.setBuildInfo(VERSION, BUILD_TIMESTAMP)
|
|
@@ -882,29 +918,34 @@ def main():
|
|
|
882
918
|
# --- Smooth Transition: App Fade In + Splash Fade Out ---
|
|
883
919
|
# MITIGATION: Prevent "White Flash" on startup
|
|
884
920
|
# 1. Force a dark background immediately so if opacity lags, it's dark not white
|
|
885
|
-
win.setStyleSheet("QMainWindow { background-color: #0F0F19; }")
|
|
886
|
-
# 2. Ensure native window handle exists so setWindowOpacity works immediately
|
|
921
|
+
win.setStyleSheet("QMainWindow { background-color: #0F0F19; }")
|
|
887
922
|
win.winId()
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
923
|
+
|
|
924
|
+
if _allow_window_opacity_effects():
|
|
925
|
+
win.setWindowOpacity(0.0)
|
|
926
|
+
|
|
891
927
|
win.show()
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
928
|
+
|
|
929
|
+
if _allow_window_opacity_effects():
|
|
930
|
+
anim_app = QPropertyAnimation(win, b"windowOpacity")
|
|
931
|
+
anim_app.setDuration(1200)
|
|
932
|
+
anim_app.setStartValue(0.0)
|
|
933
|
+
anim_app.setEndValue(1.0)
|
|
934
|
+
anim_app.setEasingCurve(QEasingCurve.Type.OutQuad)
|
|
935
|
+
|
|
936
|
+
def _on_fade_in_finished():
|
|
937
|
+
win.setStyleSheet("")
|
|
938
|
+
if hasattr(win, "on_fade_in_complete"):
|
|
939
|
+
win.on_fade_in_complete()
|
|
940
|
+
|
|
941
|
+
anim_app.finished.connect(_on_fade_in_finished)
|
|
942
|
+
anim_app.start()
|
|
943
|
+
else:
|
|
944
|
+
# No opacity animation on Wayland: just show immediately and clear the temp stylesheet
|
|
902
945
|
win.setStyleSheet("")
|
|
903
946
|
if hasattr(win, "on_fade_in_complete"):
|
|
904
947
|
win.on_fade_in_complete()
|
|
905
|
-
|
|
906
|
-
anim_app.finished.connect(_on_fade_in_finished)
|
|
907
|
-
anim_app.start()
|
|
948
|
+
|
|
908
949
|
|
|
909
950
|
# Start background Numba warmup after UI is visible
|
|
910
951
|
try:
|