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/subwindow.py
CHANGED
|
@@ -83,12 +83,12 @@ class _DragTab(QLabel):
|
|
|
83
83
|
self.owner = owner
|
|
84
84
|
self._press_pos = None
|
|
85
85
|
self.setText("⧉")
|
|
86
|
-
self.setToolTip(
|
|
86
|
+
self.setToolTip(self.tr(
|
|
87
87
|
"Drag to duplicate/copy view.\n"
|
|
88
88
|
"Hold Alt while dragging to LINK this view with another (live pan/zoom sync).\n"
|
|
89
89
|
"Hold Shift while dragging to drop this image as a mask onto another view.\n"
|
|
90
90
|
"Hold Ctrl while dragging to copy the astrometric solution (WCS) to another view."
|
|
91
|
-
)
|
|
91
|
+
))
|
|
92
92
|
|
|
93
93
|
self.setFixedSize(22, 18)
|
|
94
94
|
self.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
@@ -371,7 +371,8 @@ class ImageSubWindow(QWidget):
|
|
|
371
371
|
# pixel readout live-probe state
|
|
372
372
|
self._space_down = False
|
|
373
373
|
self._readout_dragging = False
|
|
374
|
-
|
|
374
|
+
# Pinch gesture state (macOS trackpad)
|
|
375
|
+
self._gesture_zoom_start = None
|
|
375
376
|
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
|
376
377
|
|
|
377
378
|
# Title (doc/view) sync
|
|
@@ -414,31 +415,31 @@ class ImageSubWindow(QWidget):
|
|
|
414
415
|
|
|
415
416
|
self._preview_btn = QToolButton(self)
|
|
416
417
|
self._preview_btn.setText("⟂") # crosshair glyph
|
|
417
|
-
self._preview_btn.setToolTip("Create Preview: click, then drag on the image to define a preview rectangle.")
|
|
418
|
+
self._preview_btn.setToolTip(self.tr("Create Preview: click, then drag on the image to define a preview rectangle."))
|
|
418
419
|
self._preview_btn.setCheckable(True)
|
|
419
420
|
self._preview_btn.clicked.connect(self._toggle_preview_select_mode)
|
|
420
421
|
row.addWidget(self._preview_btn, 0, Qt.AlignmentFlag.AlignLeft)
|
|
421
422
|
# — Undo / Redo just for this subwindow —
|
|
422
423
|
self._btn_undo = QToolButton(self)
|
|
423
424
|
self._btn_undo.setText("↶") # or use an icon
|
|
424
|
-
self._btn_undo.setToolTip("Undo (this view)")
|
|
425
|
+
self._btn_undo.setToolTip(self.tr("Undo (this view)"))
|
|
425
426
|
self._btn_undo.setEnabled(False)
|
|
426
427
|
self._btn_undo.clicked.connect(self._on_local_undo)
|
|
427
428
|
row.addWidget(self._btn_undo, 0, Qt.AlignmentFlag.AlignLeft)
|
|
428
429
|
|
|
429
430
|
self._btn_redo = QToolButton(self)
|
|
430
431
|
self._btn_redo.setText("↷")
|
|
431
|
-
self._btn_redo.setToolTip("Redo (this view)")
|
|
432
|
+
self._btn_redo.setToolTip(self.tr("Redo (this view)"))
|
|
432
433
|
self._btn_redo.setEnabled(False)
|
|
433
434
|
self._btn_redo.clicked.connect(self._on_local_redo)
|
|
434
435
|
row.addWidget(self._btn_redo, 0, Qt.AlignmentFlag.AlignLeft)
|
|
435
436
|
|
|
436
437
|
self._btn_replay_main = QToolButton(self)
|
|
437
438
|
self._btn_replay_main.setText("⟳") # pick any glyph you like
|
|
438
|
-
self._btn_replay_main.setToolTip(
|
|
439
|
+
self._btn_replay_main.setToolTip(self.tr(
|
|
439
440
|
"Click: replay the last action on the base image.\n"
|
|
440
441
|
"Arrow: pick a specific past action to replay on the base image."
|
|
441
|
-
)
|
|
442
|
+
))
|
|
442
443
|
self._btn_replay_main.setEnabled(False) # enabled only when preview + history
|
|
443
444
|
|
|
444
445
|
# Left-click = your existing 'replay last on base'
|
|
@@ -457,7 +458,7 @@ class ImageSubWindow(QWidget):
|
|
|
457
458
|
# ── NEW: WCS grid toggle ─────────────────────────────────────────
|
|
458
459
|
self._btn_wcs = QToolButton(self)
|
|
459
460
|
self._btn_wcs.setText("⌗")
|
|
460
|
-
self._btn_wcs.setToolTip("Toggle WCS grid overlay (if WCS exists)")
|
|
461
|
+
self._btn_wcs.setToolTip(self.tr("Toggle WCS grid overlay (if WCS exists)"))
|
|
461
462
|
self._btn_wcs.setCheckable(True)
|
|
462
463
|
|
|
463
464
|
# Start OFF on every new view, regardless of WCS presence or past sessions
|
|
@@ -484,6 +485,7 @@ class ImageSubWindow(QWidget):
|
|
|
484
485
|
|
|
485
486
|
self.scroll = QScrollArea(full_host)
|
|
486
487
|
self.scroll.setWidgetResizable(False)
|
|
488
|
+
self.scroll.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
487
489
|
self.label = QLabel(alignment=Qt.AlignmentFlag.AlignCenter)
|
|
488
490
|
self.scroll.setWidget(self.label)
|
|
489
491
|
self.scroll.viewport().setMouseTracking(True)
|
|
@@ -498,7 +500,7 @@ class ImageSubWindow(QWidget):
|
|
|
498
500
|
bar.actionTriggered.connect(self._on_scroll_changed)
|
|
499
501
|
|
|
500
502
|
# IMPORTANT: add the tab BEFORE connecting signals so currentChanged can't fire early
|
|
501
|
-
self._full_tab_idx = self._tabs.addTab(full_host, "Full")
|
|
503
|
+
self._full_tab_idx = self._tabs.addTab(full_host, self.tr("Full"))
|
|
502
504
|
self._full_host = full_host
|
|
503
505
|
self._tabs.tabBar().setVisible(False) # hidden until a preview exists
|
|
504
506
|
lyt.addWidget(self._tabs)
|
|
@@ -1029,7 +1031,7 @@ class ImageSubWindow(QWidget):
|
|
|
1029
1031
|
self.label = QLabel(alignment=Qt.AlignmentFlag.AlignCenter)
|
|
1030
1032
|
self.scroll.setWidget(self.label)
|
|
1031
1033
|
v.addWidget(self.scroll)
|
|
1032
|
-
self._full_tab_idx = self._tabs.addTab(full_host, "Full")
|
|
1034
|
+
self._full_tab_idx = self._tabs.addTab(full_host, self.tr("Full"))
|
|
1033
1035
|
self._full_host = full_host
|
|
1034
1036
|
self._tabs.tabBar().setVisible(False) # hidden until a first preview exists
|
|
1035
1037
|
|
|
@@ -1090,7 +1092,7 @@ class ImageSubWindow(QWidget):
|
|
|
1090
1092
|
if self._preview_select_mode:
|
|
1091
1093
|
mw = self._find_main_window()
|
|
1092
1094
|
if mw and hasattr(mw, "statusBar"):
|
|
1093
|
-
mw.statusBar().showMessage("Preview mode: drag a rectangle on the image to create a preview.", 6000)
|
|
1095
|
+
mw.statusBar().showMessage(self.tr("Preview mode: drag a rectangle on the image to create a preview."), 6000)
|
|
1094
1096
|
else:
|
|
1095
1097
|
self._cancel_rubber()
|
|
1096
1098
|
|
|
@@ -1165,7 +1167,7 @@ class ImageSubWindow(QWidget):
|
|
|
1165
1167
|
if mw and hasattr(mw, "statusBar"):
|
|
1166
1168
|
sb = mw.statusBar()
|
|
1167
1169
|
if sb:
|
|
1168
|
-
sb.showMessage("Press Space + Click/Drag to probe pixels (WCS shown if available)", 8000)
|
|
1170
|
+
sb.showMessage(self.tr("Press Space + Click/Drag to probe pixels (WCS shown if available)"), 8000)
|
|
1169
1171
|
|
|
1170
1172
|
|
|
1171
1173
|
|
|
@@ -1344,7 +1346,7 @@ class ImageSubWindow(QWidget):
|
|
|
1344
1346
|
sub = self._mdi_subwindow()
|
|
1345
1347
|
if not sub: return
|
|
1346
1348
|
if base is None:
|
|
1347
|
-
base = self._effective_title() or "Untitled"
|
|
1349
|
+
base = self._effective_title() or self.tr("Untitled")
|
|
1348
1350
|
|
|
1349
1351
|
# ✅ strip any carried-over glyphs (🔗, ■, “Active View: ”) from overrides/doc names
|
|
1350
1352
|
core, _ = self._strip_decorations(base)
|
|
@@ -1420,7 +1422,7 @@ class ImageSubWindow(QWidget):
|
|
|
1420
1422
|
|
|
1421
1423
|
def base_doc_title(self) -> str:
|
|
1422
1424
|
"""The clean, base title (document display name), no prefixes/suffixes."""
|
|
1423
|
-
return self.document.display_name() or "Untitled"
|
|
1425
|
+
return self.document.display_name() or self.tr("Untitled")
|
|
1424
1426
|
|
|
1425
1427
|
def _active_mask_array(self):
|
|
1426
1428
|
"""Return the active mask ndarray (H,W) or None."""
|
|
@@ -1526,17 +1528,17 @@ class ImageSubWindow(QWidget):
|
|
|
1526
1528
|
|
|
1527
1529
|
def _show_ctx_menu(self, pos):
|
|
1528
1530
|
menu = QMenu(self)
|
|
1529
|
-
a_view = menu.addAction("Rename View… (F2)")
|
|
1530
|
-
a_doc = menu.addAction("Rename Document…")
|
|
1531
|
+
a_view = menu.addAction(self.tr("Rename View… (F2)"))
|
|
1532
|
+
a_doc = menu.addAction(self.tr("Rename Document…"))
|
|
1531
1533
|
menu.addSeparator()
|
|
1532
|
-
a_min = menu.addAction("Send to Shelf")
|
|
1533
|
-
a_clear = menu.addAction("Clear View Name (use doc name)")
|
|
1534
|
+
a_min = menu.addAction(self.tr("Send to Shelf"))
|
|
1535
|
+
a_clear = menu.addAction(self.tr("Clear View Name (use doc name)"))
|
|
1534
1536
|
menu.addSeparator()
|
|
1535
|
-
a_unlink = menu.addAction("Unlink from Linked Views") # ← NEW
|
|
1537
|
+
a_unlink = menu.addAction(self.tr("Unlink from Linked Views")) # ← NEW
|
|
1536
1538
|
menu.addSeparator()
|
|
1537
|
-
a_help = menu.addAction("Show pixel/WCS readout hint")
|
|
1539
|
+
a_help = menu.addAction(self.tr("Show pixel/WCS readout hint"))
|
|
1538
1540
|
menu.addSeparator()
|
|
1539
|
-
a_prev = menu.addAction("Create Preview (drag rectangle)")
|
|
1541
|
+
a_prev = menu.addAction(self.tr("Create Preview (drag rectangle)"))
|
|
1540
1542
|
|
|
1541
1543
|
act = menu.exec(self.mapToGlobal(pos))
|
|
1542
1544
|
|
|
@@ -1569,7 +1571,7 @@ class ImageSubWindow(QWidget):
|
|
|
1569
1571
|
|
|
1570
1572
|
def _rename_view(self):
|
|
1571
1573
|
current = self._view_title_override or self.document.display_name()
|
|
1572
|
-
new, ok = QInputDialog.getText(self, "Rename View", "New view name:", text=current)
|
|
1574
|
+
new, ok = QInputDialog.getText(self, self.tr("Rename View"), self.tr("New view name:"), text=current)
|
|
1573
1575
|
if ok and new.strip():
|
|
1574
1576
|
self._view_title_override = new.strip()
|
|
1575
1577
|
self._sync_host_title() # calls _rebuild_title → emits viewTitleChanged
|
|
@@ -1584,7 +1586,7 @@ class ImageSubWindow(QWidget):
|
|
|
1584
1586
|
|
|
1585
1587
|
def _rename_document(self):
|
|
1586
1588
|
current = self.document.display_name()
|
|
1587
|
-
new, ok = QInputDialog.getText(self, "Rename Document", "New document name:", text=current)
|
|
1589
|
+
new, ok = QInputDialog.getText(self, self.tr("Rename Document"), self.tr("New document name:"), text=current)
|
|
1588
1590
|
if ok and new.strip():
|
|
1589
1591
|
# store on the doc so Explorer + other views update too
|
|
1590
1592
|
self.document.metadata["display_name"] = new.strip()
|
|
@@ -1775,9 +1777,9 @@ class ImageSubWindow(QWidget):
|
|
|
1775
1777
|
# ---- DnD 'view tab' -------------------------------------------------
|
|
1776
1778
|
def _install_view_tab(self):
|
|
1777
1779
|
self._view_tab = QToolButton(self)
|
|
1778
|
-
self._view_tab.setText("View")
|
|
1779
|
-
self._view_tab.setToolTip("Drag onto another window to copy zoom/pan.\n"
|
|
1780
|
-
"Double-click to duplicate this view.")
|
|
1780
|
+
self._view_tab.setText(self.tr("View"))
|
|
1781
|
+
self._view_tab.setToolTip(self.tr("Drag onto another window to copy zoom/pan.\n"
|
|
1782
|
+
"Double-click to duplicate this view."))
|
|
1781
1783
|
self._view_tab.setCursor(Qt.CursorShape.OpenHandCursor)
|
|
1782
1784
|
self._view_tab.setAutoRaise(True)
|
|
1783
1785
|
self._view_tab.move(8, 8) # pinned near top-left of the subwindow
|
|
@@ -2526,6 +2528,43 @@ class ImageSubWindow(QWidget):
|
|
|
2526
2528
|
p = p.parent()
|
|
2527
2529
|
return p
|
|
2528
2530
|
|
|
2531
|
+
def event(self, e):
|
|
2532
|
+
"""Override event() to handle native macOS gestures (pinch zoom)."""
|
|
2533
|
+
# Handle native gestures (macOS trackpad pinch zoom)
|
|
2534
|
+
if e.type() == QEvent.Type.NativeGesture:
|
|
2535
|
+
gesture_type = e.gestureType()
|
|
2536
|
+
|
|
2537
|
+
if gesture_type == Qt.NativeGestureType.BeginNativeGesture:
|
|
2538
|
+
# Start of pinch gesture - store initial scale
|
|
2539
|
+
self._gesture_zoom_start = self.scale
|
|
2540
|
+
e.accept()
|
|
2541
|
+
return True
|
|
2542
|
+
|
|
2543
|
+
elif gesture_type == Qt.NativeGestureType.ZoomNativeGesture:
|
|
2544
|
+
# Ongoing pinch zoom - value() is cumulative scale factor
|
|
2545
|
+
# Typical values: -0.5 to +0.5 for moderate pinches
|
|
2546
|
+
zoom_delta = e.value()
|
|
2547
|
+
|
|
2548
|
+
# Convert delta to zoom factor
|
|
2549
|
+
# Use smaller multiplier for smoother feel (0.5x damping)
|
|
2550
|
+
factor = 1.0 + (zoom_delta * 0.5)
|
|
2551
|
+
|
|
2552
|
+
# Apply incremental zoom
|
|
2553
|
+
self._zoom_at_anchor(factor)
|
|
2554
|
+
e.accept()
|
|
2555
|
+
return True
|
|
2556
|
+
|
|
2557
|
+
elif gesture_type == Qt.NativeGestureType.EndNativeGesture:
|
|
2558
|
+
# End of pinch gesture - cleanup
|
|
2559
|
+
self._gesture_zoom_start = None
|
|
2560
|
+
e.accept()
|
|
2561
|
+
return True
|
|
2562
|
+
|
|
2563
|
+
# Let parent handle all other events
|
|
2564
|
+
return super().event(e)
|
|
2565
|
+
|
|
2566
|
+
|
|
2567
|
+
|
|
2529
2568
|
def eventFilter(self, obj, ev):
|
|
2530
2569
|
is_on_view = (obj is self.label) or (obj is self.scroll.viewport())
|
|
2531
2570
|
|
|
@@ -2557,7 +2596,29 @@ class ImageSubWindow(QWidget):
|
|
|
2557
2596
|
# 1) Ctrl + wheel → zoom
|
|
2558
2597
|
if ev.type() == QEvent.Type.Wheel:
|
|
2559
2598
|
if ev.modifiers() & Qt.KeyboardModifier.ControlModifier:
|
|
2560
|
-
|
|
2599
|
+
# Try pixelDelta first (macOS trackpad gives smooth values)
|
|
2600
|
+
dy = ev.pixelDelta().y()
|
|
2601
|
+
|
|
2602
|
+
if dy != 0:
|
|
2603
|
+
# Smooth trackpad scrolling: use smaller base factor
|
|
2604
|
+
# Scale proportionally to delta magnitude for natural feel
|
|
2605
|
+
# Typical trackpad deltas are 1-10 pixels per event
|
|
2606
|
+
abs_dy = abs(dy)
|
|
2607
|
+
if abs_dy <= 3:
|
|
2608
|
+
base_factor = 1.01 # Very gentle for tiny movements
|
|
2609
|
+
elif abs_dy <= 10:
|
|
2610
|
+
base_factor = 1.02 # Gentle for small movements
|
|
2611
|
+
else:
|
|
2612
|
+
base_factor = 1.03 # Moderate for larger gestures
|
|
2613
|
+
|
|
2614
|
+
factor = base_factor if dy > 0 else 1/base_factor
|
|
2615
|
+
else:
|
|
2616
|
+
# Traditional mouse wheel: use angleDelta with moderate factor
|
|
2617
|
+
dy = ev.angleDelta().y()
|
|
2618
|
+
if dy == 0:
|
|
2619
|
+
return True
|
|
2620
|
+
# Use 1.15 for mouse wheel (gentler than original 1.25)
|
|
2621
|
+
factor = 1.15 if dy > 0 else 1/1.15
|
|
2561
2622
|
self._zoom_at_anchor(factor)
|
|
2562
2623
|
return True
|
|
2563
2624
|
return False
|
|
@@ -2642,7 +2703,7 @@ class ImageSubWindow(QWidget):
|
|
|
2642
2703
|
|
|
2643
2704
|
pid = self._next_preview_id
|
|
2644
2705
|
self._next_preview_id += 1
|
|
2645
|
-
name =
|
|
2706
|
+
name = self.tr("Preview {0} ({1}×{2})").format(pid, w, h)
|
|
2646
2707
|
|
|
2647
2708
|
self._previews.append({"id": pid, "name": name, "roi": (x, y, w, h), "arr": crop})
|
|
2648
2709
|
|
|
@@ -3062,8 +3123,8 @@ class ImageSubWindow(QWidget):
|
|
|
3062
3123
|
|
|
3063
3124
|
if should_warn:
|
|
3064
3125
|
r = QMessageBox.question(
|
|
3065
|
-
self, "Close Image?",
|
|
3066
|
-
"This image has edits that aren’t applied/saved.\nClose anyway?",
|
|
3126
|
+
self, self.tr("Close Image?"),
|
|
3127
|
+
self.tr("This image has edits that aren’t applied/saved.\nClose anyway?"),
|
|
3067
3128
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
3068
3129
|
QMessageBox.StandardButton.No
|
|
3069
3130
|
)
|
|
@@ -3180,7 +3241,7 @@ class TableSubWindow(QWidget):
|
|
|
3180
3241
|
title_row.addWidget(self.title_lbl)
|
|
3181
3242
|
title_row.addStretch(1)
|
|
3182
3243
|
|
|
3183
|
-
self.export_btn = QPushButton("Export CSV…")
|
|
3244
|
+
self.export_btn = QPushButton(self.tr("Export CSV…"))
|
|
3184
3245
|
self.export_btn.clicked.connect(self._export_csv)
|
|
3185
3246
|
title_row.addWidget(self.export_btn)
|
|
3186
3247
|
lyt.addLayout(title_row)
|
|
@@ -3238,17 +3299,17 @@ class TableSubWindow(QWidget):
|
|
|
3238
3299
|
existing = self.document.metadata.get("table_csv")
|
|
3239
3300
|
if existing and os.path.exists(existing):
|
|
3240
3301
|
# Offer to open/save-as that CSV
|
|
3241
|
-
dst, ok = QFileDialog.getSaveFileName(self, "Save CSV As…", os.path.basename(existing), "CSV Files (*.csv)")
|
|
3302
|
+
dst, ok = QFileDialog.getSaveFileName(self, self.tr("Save CSV As…"), os.path.basename(existing), self.tr("CSV Files (*.csv)"))
|
|
3242
3303
|
if ok and dst:
|
|
3243
3304
|
try:
|
|
3244
3305
|
import shutil
|
|
3245
3306
|
shutil.copyfile(existing, dst)
|
|
3246
3307
|
except Exception as e:
|
|
3247
|
-
QMessageBox.warning(self, "Export CSV",
|
|
3308
|
+
QMessageBox.warning(self, self.tr("Export CSV"), self.tr("Failed to copy CSV:\n{0}").format(e))
|
|
3248
3309
|
return
|
|
3249
3310
|
|
|
3250
3311
|
# No pre-export → write one from the model
|
|
3251
|
-
dst, ok = QFileDialog.getSaveFileName(self, "Export CSV…", "table.csv", "CSV Files (*.csv)")
|
|
3312
|
+
dst, ok = QFileDialog.getSaveFileName(self, self.tr("Export CSV…"), "table.csv", self.tr("CSV Files (*.csv)"))
|
|
3252
3313
|
if not ok or not dst:
|
|
3253
3314
|
return
|
|
3254
3315
|
try:
|
|
@@ -3264,4 +3325,4 @@ class TableSubWindow(QWidget):
|
|
|
3264
3325
|
for r in range(rows):
|
|
3265
3326
|
w.writerow([self._model.data(self._model.index(r, c), Qt.ItemDataRole.DisplayRole) for c in range(cols)])
|
|
3266
3327
|
except Exception as e:
|
|
3267
|
-
QMessageBox.warning(self, "Export CSV",
|
|
3328
|
+
QMessageBox.warning(self, self.tr("Export CSV"), self.tr("Failed to export CSV:\n{0}").format(e))
|