PaIRS-UniNa 0.2.7__cp311-cp311-win_amd64.whl → 0.2.11__cp311-cp311-win_amd64.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.
- PaIRS_UniNa/Calibration_Tab.py +40 -24
- PaIRS_UniNa/Changes.txt +50 -0
- PaIRS_UniNa/Explorer.py +257 -77
- PaIRS_UniNa/FolderLoop.py +196 -6
- PaIRS_UniNa/Input_Tab.py +160 -53
- PaIRS_UniNa/Input_Tab_CalVi.py +11 -12
- PaIRS_UniNa/Input_Tab_tools.py +30 -28
- PaIRS_UniNa/Output_Tab.py +1 -3
- PaIRS_UniNa/PaIRS_pypacks.py +171 -67
- PaIRS_UniNa/Process_Tab.py +19 -15
- PaIRS_UniNa/Process_Tab_Disp.py +8 -1
- PaIRS_UniNa/SPIVCalHelp.py +155 -0
- PaIRS_UniNa/Saving_tools.py +3 -0
- PaIRS_UniNa/TabTools.py +201 -9
- PaIRS_UniNa/Vis_Tab.py +221 -65
- PaIRS_UniNa/Vis_Tab_CalVi.py +139 -12
- PaIRS_UniNa/Whatsnew.py +4 -3
- PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
- PaIRS_UniNa/__init__.py +3 -3
- PaIRS_UniNa/addwidgets_ps.py +773 -97
- PaIRS_UniNa/calibView.py +5 -2
- PaIRS_UniNa/gPaIRS.py +307 -48
- PaIRS_UniNa/icons/closeAllFloat.png +0 -0
- PaIRS_UniNa/icons/defaultWinSize.png +0 -0
- PaIRS_UniNa/icons/dockVis.png +0 -0
- PaIRS_UniNa/icons/dockVis_disable.png +0 -0
- PaIRS_UniNa/icons/floatingVisSize.png +0 -0
- PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
- PaIRS_UniNa/icons/folder_loop_cleanup_off.png +0 -0
- PaIRS_UniNa/icons/fullWinsize.png +0 -0
- PaIRS_UniNa/icons/icon_PaIRS.ico +0 -0
- PaIRS_UniNa/icons/information.png +0 -0
- PaIRS_UniNa/icons/information2.png +0 -0
- PaIRS_UniNa/icons/scan_path_loop.png +0 -0
- PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
- PaIRS_UniNa/icons/smallWinSize.png +0 -0
- PaIRS_UniNa/icons/spiv_setup_no.png +0 -0
- PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
- PaIRS_UniNa/icons/undockVis.png +0 -0
- PaIRS_UniNa/procTools.py +46 -1
- PaIRS_UniNa/rqrdpckgs.txt +7 -7
- PaIRS_UniNa/tabSplitter.py +6 -1
- PaIRS_UniNa/ui_Calibration_Tab.py +92 -59
- PaIRS_UniNa/ui_gPairs.py +92 -50
- PaIRS_UniNa/ui_infoPaIRS.py +8 -8
- PaIRS_UniNa/whatsnew.txt +2 -3
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/METADATA +6 -8
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/RECORD +50 -33
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/WHEEL +1 -1
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from PySide6 import QtWidgets, QtGui, QtCore
|
|
2
|
+
import sys
|
|
3
|
+
from .PaIRS_pypacks import icons_path, fontPixelSize
|
|
4
|
+
|
|
5
|
+
def showSPIVCalHelp(parent=None,disable_callback=None):
|
|
6
|
+
"""
|
|
7
|
+
Shows an informational dialog explaining the correct calibration setup
|
|
8
|
+
for stereoscopic PIV in PaIRS, ensuring compatibility with disparity
|
|
9
|
+
correction and full stereoscopic reconstruction.
|
|
10
|
+
"""
|
|
11
|
+
dlg = QtWidgets.QDialog(parent)
|
|
12
|
+
dlg.setWindowTitle("Guidelines for stereoscopic PIV calibration")
|
|
13
|
+
#dlg.resize(900, 750)
|
|
14
|
+
dlg.setMinimumWidth(900)
|
|
15
|
+
dlg.setMinimumHeight(750)
|
|
16
|
+
|
|
17
|
+
main_layout = QtWidgets.QVBoxLayout(dlg)
|
|
18
|
+
|
|
19
|
+
# --- Explanatory text (English, corrected axes) ---
|
|
20
|
+
text = (
|
|
21
|
+
"For stereoscopic PIV, PaIRS assumes that:<br><br>"
|
|
22
|
+
|
|
23
|
+
" • the <b>calibration plate defines "
|
|
24
|
+
"the x–y plane</b> of the calibration coordinate system;<br>"
|
|
25
|
+
|
|
26
|
+
" • the <b>x-axis</b> is <b>aligned with the stereoscopic baseline</b>, i.e. "
|
|
27
|
+
"the direction along which the projections of the two camera viewing rays diverge "
|
|
28
|
+
"on the calibration plate (the dominant disparity direction);<br>"
|
|
29
|
+
|
|
30
|
+
" • the <b>y-axis</b> is then defined as the axis <b>perpendicular to the plane containing "
|
|
31
|
+
"the two cameras</b> (i.e. perpendicular to the triangulation plane formed by the two "
|
|
32
|
+
"optical axes);<br>"
|
|
33
|
+
|
|
34
|
+
" • the <b>z-axis is normal to the plate</b> (typically pointing towards the cameras).<br><br>"
|
|
35
|
+
|
|
36
|
+
"To ensure full compatibility with the operations performed in the disparity correction step and the stereoscopic reconstruction,"
|
|
37
|
+
" the calibration procedure must always adhere to the above coordinate convention.<br>"
|
|
38
|
+
" The example below shows a <b>correct</b> configuration (left) and an <b>incorrect</b> one (right).<br>"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
text_label = QtWidgets.QLabel()
|
|
42
|
+
text_label.setWordWrap(True)
|
|
43
|
+
text_label.setTextFormat(QtCore.Qt.RichText)
|
|
44
|
+
text_label.setText(f"<div>{text}</div>")
|
|
45
|
+
main_layout.addWidget(text_label)
|
|
46
|
+
font=dlg.font()
|
|
47
|
+
font.setPixelSize(fontPixelSize+4)
|
|
48
|
+
text_label.setFont(font)
|
|
49
|
+
|
|
50
|
+
# --- Side-by-side images ---
|
|
51
|
+
img_layout = QtWidgets.QHBoxLayout()
|
|
52
|
+
img_layout.setSpacing(10)
|
|
53
|
+
main_layout.addLayout(img_layout)
|
|
54
|
+
|
|
55
|
+
# Paths to images (adjust to match PaIRS resources folder)
|
|
56
|
+
img_ok_path = icons_path+"spiv_setup_ok.png"
|
|
57
|
+
img_no_path = icons_path+"spiv_setup_no.png"
|
|
58
|
+
|
|
59
|
+
# --- Correct configuration image ---
|
|
60
|
+
ok_widget = QtWidgets.QVBoxLayout()
|
|
61
|
+
ok_caption = QtWidgets.QLabel()
|
|
62
|
+
caption_text = "<b>Correct configuration (x–z stereo plane)</b>"
|
|
63
|
+
ok_caption.setText(f"<div>{caption_text}</div>")
|
|
64
|
+
ok_caption.setFont(font)
|
|
65
|
+
ok_caption.setTextFormat(QtCore.Qt.RichText)
|
|
66
|
+
ok_caption.setAlignment(QtCore.Qt.AlignCenter)
|
|
67
|
+
|
|
68
|
+
ok_label_img = QtWidgets.QLabel()
|
|
69
|
+
ok_label_img.setAlignment(QtCore.Qt.AlignCenter)
|
|
70
|
+
ok_label_img.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
71
|
+
ok_label_img.setScaledContents(True)
|
|
72
|
+
|
|
73
|
+
ok_pix = QtGui.QPixmap(img_ok_path)
|
|
74
|
+
if not ok_pix.isNull():
|
|
75
|
+
ok_pix = ok_pix.scaledToWidth(400, QtCore.Qt.SmoothTransformation)
|
|
76
|
+
ok_label_img.setPixmap(ok_pix)
|
|
77
|
+
ok_label_img.setFixedSize(ok_pix.width(),ok_pix.height())
|
|
78
|
+
|
|
79
|
+
ok_widget.addWidget(ok_caption)
|
|
80
|
+
ok_widget.addWidget(ok_label_img)
|
|
81
|
+
img_layout.addLayout(ok_widget)
|
|
82
|
+
|
|
83
|
+
# --- Incorrect configuration image ---
|
|
84
|
+
no_widget = QtWidgets.QVBoxLayout()
|
|
85
|
+
no_caption = QtWidgets.QLabel()
|
|
86
|
+
caption_text = "<b>Incorrect configuration</b>"
|
|
87
|
+
no_caption.setText(f"<div'>{caption_text}</div>")
|
|
88
|
+
no_caption.setFont(font)
|
|
89
|
+
no_caption.setTextFormat(QtCore.Qt.RichText)
|
|
90
|
+
no_caption.setAlignment(QtCore.Qt.AlignCenter)
|
|
91
|
+
|
|
92
|
+
no_label_img = QtWidgets.QLabel()
|
|
93
|
+
no_label_img.setAlignment(QtCore.Qt.AlignCenter)
|
|
94
|
+
no_label_img.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
95
|
+
no_label_img.setScaledContents(True)
|
|
96
|
+
|
|
97
|
+
no_pix = QtGui.QPixmap(img_no_path)
|
|
98
|
+
if not no_pix.isNull():
|
|
99
|
+
no_pix = no_pix.scaledToWidth(400, QtCore.Qt.SmoothTransformation)
|
|
100
|
+
no_label_img.setPixmap(no_pix)
|
|
101
|
+
no_label_img.setFixedSize(no_pix.width(),no_pix.height())
|
|
102
|
+
|
|
103
|
+
no_widget.addWidget(no_caption)
|
|
104
|
+
no_widget.addWidget(no_label_img)
|
|
105
|
+
img_layout.addLayout(no_widget)
|
|
106
|
+
|
|
107
|
+
# Prevent bottom clipping: allow images row to shrink/expand as needed
|
|
108
|
+
main_layout.setStretch(0, 1)
|
|
109
|
+
main_layout.setStretch(1, 0)
|
|
110
|
+
|
|
111
|
+
# Create a horizontal layout for buttons
|
|
112
|
+
button_layout = QtWidgets.QHBoxLayout()
|
|
113
|
+
|
|
114
|
+
# Spacer pushes OK to the right
|
|
115
|
+
button_layout.addStretch(1)
|
|
116
|
+
|
|
117
|
+
# Left button
|
|
118
|
+
if disable_callback is not None:
|
|
119
|
+
button_disable = QtWidgets.QPushButton("Don't show this message again")
|
|
120
|
+
def on_disable():
|
|
121
|
+
disable_callback()
|
|
122
|
+
dlg.accept()
|
|
123
|
+
button_disable.clicked.connect(on_disable)
|
|
124
|
+
button_layout.addWidget(button_disable)
|
|
125
|
+
|
|
126
|
+
# Right button (OK)
|
|
127
|
+
button_ok = QtWidgets.QPushButton("OK")
|
|
128
|
+
def on_ok():
|
|
129
|
+
dlg.accept()
|
|
130
|
+
button_ok.clicked.connect(on_ok)
|
|
131
|
+
button_layout.addWidget(button_ok)
|
|
132
|
+
|
|
133
|
+
# Add the layout to the dialog
|
|
134
|
+
main_layout.addSpacing(12)
|
|
135
|
+
main_layout.addLayout(button_layout)
|
|
136
|
+
|
|
137
|
+
button_ok.setDefault(True)
|
|
138
|
+
button_ok.setFocus()
|
|
139
|
+
|
|
140
|
+
main_layout.setContentsMargins(20, 25, 20, 25) # slightly larger bottom margin to avoid macOS clipping
|
|
141
|
+
|
|
142
|
+
dlg.exec()
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
# QApplication MUST be created before any QWidget
|
|
146
|
+
app = QtWidgets.QApplication(sys.argv)
|
|
147
|
+
|
|
148
|
+
# Parent window (optional)
|
|
149
|
+
main_window = QtWidgets.QMainWindow()
|
|
150
|
+
main_window.show()
|
|
151
|
+
|
|
152
|
+
# Show the SPIV calibration dialog
|
|
153
|
+
showSPIVCalHelp(parent=main_window)
|
|
154
|
+
|
|
155
|
+
sys.exit(app.exec())
|
PaIRS_UniNa/Saving_tools.py
CHANGED
|
@@ -51,6 +51,7 @@ class GPApar(TABpar):
|
|
|
51
51
|
self.WindowState = None
|
|
52
52
|
self.SplitterSizes = {}
|
|
53
53
|
self.ScrollAreaValues = {}
|
|
54
|
+
self.tabWinPar = {}
|
|
54
55
|
|
|
55
56
|
#legacy
|
|
56
57
|
self.FloatGeometry = []
|
|
@@ -64,6 +65,8 @@ class GPApar(TABpar):
|
|
|
64
65
|
|
|
65
66
|
self.printTypes = printTypes
|
|
66
67
|
self.NumCores = 0
|
|
68
|
+
self.globalVals = {}
|
|
69
|
+
self.globalExceptions = {'Calibration': ['FlagSPIVCal']}
|
|
67
70
|
|
|
68
71
|
self.stateFields=[f for f,_ in self.__dict__.items() if f not in self.infoFields]
|
|
69
72
|
|
PaIRS_UniNa/TabTools.py
CHANGED
|
@@ -468,6 +468,7 @@ class gPaIRS_Tab(QWidget):
|
|
|
468
468
|
FlagPreventAddPrev=False
|
|
469
469
|
if callback1: FlagPreventAddPrev=debugFun(callback1,f'Error callback1 ({tip}): ')
|
|
470
470
|
if callback2:
|
|
471
|
+
if FlagPreventAddPrev is None: FlagPreventAddPrev=False
|
|
471
472
|
self.FlagAsyncCallEvaluation=True
|
|
472
473
|
self.disableTab(True)
|
|
473
474
|
|
|
@@ -488,7 +489,7 @@ class gPaIRS_Tab(QWidget):
|
|
|
488
489
|
return
|
|
489
490
|
return callback
|
|
490
491
|
|
|
491
|
-
@Slot(str)
|
|
492
|
+
@Slot(str,bool,bool)
|
|
492
493
|
def callback2_end(self,tip,FlagSettingPar,FlagPreventAddPrev):
|
|
493
494
|
pri.Coding.green(f'{"*"*50}\nCallback <{self.TABname}>: {tip}')
|
|
494
495
|
if tip=='Null Callback':
|
|
@@ -523,6 +524,7 @@ class gPaIRS_Tab(QWidget):
|
|
|
523
524
|
Messagge='This process step is currently in execution. To modify it, you need to stop processing and then reset it and all the subsequent steps.'
|
|
524
525
|
warningDialog(self.gui,Messagge)
|
|
525
526
|
elif flagRun!=0:
|
|
527
|
+
self.flagGuiSplash=True
|
|
526
528
|
if self.gui.FlagRun:
|
|
527
529
|
Messagge='This process step has already been executed. To modify it, you need to stop processing and then reset it and all the subsequent steps.'
|
|
528
530
|
warningDialog(self.gui,Messagge)
|
|
@@ -531,11 +533,12 @@ class gPaIRS_Tab(QWidget):
|
|
|
531
533
|
def reset_step_online():
|
|
532
534
|
TABpar_ind.copyfrom(self.TABpar)
|
|
533
535
|
self.gui.reset_step(self.TABpar.ind)
|
|
536
|
+
self.flagGuiSplash=False
|
|
534
537
|
return
|
|
535
538
|
warningDialog(self.gui,Messagge,addButton={'Reset step!': reset_step_online})
|
|
536
539
|
|
|
537
540
|
|
|
538
|
-
if flagRun!=0 or len(self.TABpar.link)>0:
|
|
541
|
+
if (flagRun!=0 or len(self.TABpar.link)>0) and self.flagGuiSplash:
|
|
539
542
|
self.TABpar.copyfrom(TABpar_ind)
|
|
540
543
|
originalStyleSheet=self.gui.styleSheet()
|
|
541
544
|
self.gui.setStyleSheet(f'background: {self.palette().color(QPalette.ColorRole.Text).name()} ;') #dcdcdc
|
|
@@ -706,16 +709,130 @@ class gPaIRS_Tab(QWidget):
|
|
|
706
709
|
lab.setFont(font)
|
|
707
710
|
|
|
708
711
|
def setTABWarnLabel(self):
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
712
|
+
if hasattr(self.ui,'label_done'):
|
|
713
|
+
self.ui.name_tab.setFixedWidth(self.ui.name_tab.sizeHint().width())
|
|
714
|
+
self.ui.label_done.setPixmap(self.pixmap_done if self.TABpar.OptionDone==1 else self.pixmap_warnc)
|
|
715
|
+
self.ui.label_done.setToolTip(self.TABpar.warningMessage)
|
|
716
|
+
|
|
717
|
+
def syncPrevGlobalFields(self, ref_vals=None, include_bases=False, exceptions=[], FlagSync=True):
|
|
718
|
+
"""
|
|
719
|
+
Sync class-level fields (declared in class bodies, e.g. PROpar.mode = mode_init)
|
|
720
|
+
across all TABpar-like instances inside self.TABpar_prev (nested lists / None / TABpar).
|
|
721
|
+
|
|
722
|
+
Parameters
|
|
723
|
+
----------
|
|
724
|
+
ref : object | None
|
|
725
|
+
Reference TABpar instance whose values will be copied (default: self.TABpar).
|
|
726
|
+
include_bases : bool
|
|
727
|
+
If True, include class-level fields declared in base classes too.
|
|
728
|
+
If False, include ONLY fields declared in the concrete class (e.g., PROpar only).
|
|
729
|
+
"""
|
|
730
|
+
|
|
731
|
+
ref = getattr(self, "TABpar", None)
|
|
732
|
+
if ref is None:
|
|
733
|
+
return []
|
|
734
|
+
ref_cls = type(ref)
|
|
735
|
+
|
|
736
|
+
# Decide which class we consider as "TABpar-like"
|
|
737
|
+
# If your tabs store subclasses of a known ParClass, use that; otherwise fallback to TABpar.
|
|
738
|
+
par_base = getattr(self, "ParClass", None)
|
|
739
|
+
if par_base is None:
|
|
740
|
+
par_base = TABpar # assumes TABpar is in scope in TabTools.py
|
|
741
|
+
|
|
742
|
+
# Reference object
|
|
743
|
+
if ref_vals is None:
|
|
744
|
+
|
|
745
|
+
# Collect class-level fields declared in class bodies
|
|
746
|
+
def _class_fields(cls):
|
|
747
|
+
if include_bases:
|
|
748
|
+
classes = [C for C in cls.mro() if C not in (object,)]
|
|
749
|
+
else:
|
|
750
|
+
classes = [cls]
|
|
751
|
+
|
|
752
|
+
out = []
|
|
753
|
+
for C in classes:
|
|
754
|
+
for name, val in C.__dict__.items():
|
|
755
|
+
if name.startswith("__"):
|
|
756
|
+
continue
|
|
757
|
+
# Skip methods / descriptors
|
|
758
|
+
if callable(val) or isinstance(val, (staticmethod, classmethod, property)):
|
|
759
|
+
continue
|
|
760
|
+
out.append(name)
|
|
761
|
+
|
|
762
|
+
# Unique preserving order
|
|
763
|
+
seen = set()
|
|
764
|
+
fields = []
|
|
765
|
+
for n in out:
|
|
766
|
+
if n not in seen:
|
|
767
|
+
seen.add(n)
|
|
768
|
+
fields.append(n)
|
|
769
|
+
return fields
|
|
770
|
+
|
|
771
|
+
fields = _class_fields(ref_cls)
|
|
772
|
+
|
|
773
|
+
# Build reference values (prefer instance override, otherwise class default)
|
|
774
|
+
ref_vals = {}
|
|
775
|
+
#pri.Info.green(f'{self.TABname}:')
|
|
776
|
+
for f in fields:
|
|
777
|
+
try:
|
|
778
|
+
ref_vals[f] = getattr(ref, f)
|
|
779
|
+
#pri.Info.green(f'{f} = {ref_vals[f]}')
|
|
780
|
+
except Exception:
|
|
781
|
+
pass
|
|
782
|
+
#pri.Info.green('\n')
|
|
783
|
+
|
|
784
|
+
if not FlagSync: return ref_vals
|
|
785
|
+
|
|
786
|
+
# Exclude exception fields (if any)
|
|
787
|
+
if exceptions:
|
|
788
|
+
exc = set(exceptions)
|
|
789
|
+
ref_vals = {k: v for k, v in ref_vals.items() if k not in exc}
|
|
790
|
+
|
|
791
|
+
# Walk nested structure and patch instances
|
|
792
|
+
def _walk(node, ParBase=par_base): # <-- bind ParBase safely here
|
|
793
|
+
if node is None:
|
|
794
|
+
return
|
|
795
|
+
if isinstance(node, ParBase):
|
|
796
|
+
for f, v in ref_vals.items():
|
|
797
|
+
try:
|
|
798
|
+
setattr(node, f, v)
|
|
799
|
+
except Exception:
|
|
800
|
+
pass
|
|
801
|
+
return
|
|
802
|
+
if isinstance(node, (list, tuple)):
|
|
803
|
+
for it in node:
|
|
804
|
+
_walk(it, ParBase)
|
|
805
|
+
return
|
|
806
|
+
if isinstance(node, dict):
|
|
807
|
+
for it in node.values():
|
|
808
|
+
_walk(it, ParBase)
|
|
809
|
+
return
|
|
810
|
+
|
|
811
|
+
_walk(getattr(self, "TABpar_prev", None))
|
|
812
|
+
|
|
813
|
+
# Set class-level (global) fields ONCE
|
|
814
|
+
for C in (ref_cls, self.TABpar, self.TABpar_old):
|
|
815
|
+
if C is None:
|
|
816
|
+
continue
|
|
817
|
+
for f, v in ref_vals.items():
|
|
818
|
+
try:
|
|
819
|
+
setattr(C, f, v)
|
|
820
|
+
except Exception:
|
|
821
|
+
pass
|
|
822
|
+
return ref_vals
|
|
823
|
+
|
|
713
824
|
#*************************************************** Undo/redo
|
|
714
825
|
def adjustTABparInd(self):
|
|
715
826
|
TABpar_ind=self.TABpar_at(self.TABpar.ind)
|
|
716
827
|
if TABpar_ind:
|
|
717
828
|
TABpar_ind.copyfrom(self.TABpar)
|
|
718
829
|
|
|
830
|
+
def adjustFromTABparInd(self,ind=None):
|
|
831
|
+
if ind is None: ind=self.TABpar.ind
|
|
832
|
+
TABpar_ind=self.TABpar_at(ind)
|
|
833
|
+
if TABpar_ind:
|
|
834
|
+
self.TABpar.copyfrom(TABpar_ind)
|
|
835
|
+
|
|
719
836
|
def gen_TABpar(self,ind,FlagSet=True,FlagEmptyPrev=False,FlagNone=False,FlagInsert=-1,Process=None,Step=None):
|
|
720
837
|
Prev=prev=self.TABpar_prev if FlagSet else []
|
|
721
838
|
|
|
@@ -956,6 +1073,7 @@ class gPaIRS_Tab(QWidget):
|
|
|
956
1073
|
d=0
|
|
957
1074
|
|
|
958
1075
|
menu=QMenu(b)
|
|
1076
|
+
menu.setStyleSheet(gPaIRS_QMenu_style)
|
|
959
1077
|
act=[]
|
|
960
1078
|
nur=len(krange)
|
|
961
1079
|
flag=nur==Num_Prevs_back_forw
|
|
@@ -989,7 +1107,6 @@ class gPaIRS_Tab(QWidget):
|
|
|
989
1107
|
if self.TABpar.ind[:-1]==ind[:-1]:
|
|
990
1108
|
self.TABpar.ind[-1]=0
|
|
991
1109
|
|
|
992
|
-
|
|
993
1110
|
#*************************************************** Special spin boxes (x,y,w,h)
|
|
994
1111
|
def setMinMaxSpinxywh(self):
|
|
995
1112
|
self.ui.spin_x.setMinimum(0)
|
|
@@ -1062,9 +1179,16 @@ def setupWid(self:gPaIRS_Tab,FlagFontSize=True):
|
|
|
1062
1179
|
|
|
1063
1180
|
if hasattr(self,'widgets'): widgets=self.widgets
|
|
1064
1181
|
else: widgets=self.findChildren(QWidget)
|
|
1182
|
+
if isinstance(widgets[0],list):
|
|
1183
|
+
widgets=[w for wi in widgets for w in wi]
|
|
1065
1184
|
widgets+=self.findChildren(CollapsibleBox)
|
|
1185
|
+
widgets+=self.findChildren(QTextEdit)
|
|
1066
1186
|
for w in widgets:
|
|
1067
1187
|
w:QToolButton
|
|
1188
|
+
try:
|
|
1189
|
+
w.objectName()
|
|
1190
|
+
except:
|
|
1191
|
+
continue
|
|
1068
1192
|
if hasattr(w,'toolTip'):
|
|
1069
1193
|
tooltip=toPlainText(w.toolTip())
|
|
1070
1194
|
if hasattr(w,'shortcut'):
|
|
@@ -1076,15 +1200,58 @@ def setupWid(self:gPaIRS_Tab,FlagFontSize=True):
|
|
|
1076
1200
|
w.setToolTip(tooltip)
|
|
1077
1201
|
#if hasattr(w,'statusTip'):
|
|
1078
1202
|
w.setStatusTip(tooltip)
|
|
1079
|
-
|
|
1080
1203
|
if hasattr(w,'setup'):
|
|
1081
1204
|
w.setup()
|
|
1082
1205
|
if hasattr(w,'setup2'):
|
|
1083
1206
|
w.setup2()
|
|
1084
1207
|
|
|
1085
|
-
if isinstance(w,QToolButton) or isinstance(w,QPushButton):
|
|
1208
|
+
if isinstance(w,QToolButton) or isinstance(w,QPushButton) or isinstance(w,QCheckBox) or isinstance(w,QRadioButton) or isinstance(w,QComboBox):
|
|
1086
1209
|
if w.cursor().shape()==Qt.CursorShape.ArrowCursor:
|
|
1087
1210
|
w.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
|
1211
|
+
if isinstance(w,QComboBox):
|
|
1212
|
+
w.setView(QListView(w))
|
|
1213
|
+
w.setStyleSheet(gPaIRS_Completer_style.replace("QAbstractItemView","QComboBox QAbstractItemView"))
|
|
1214
|
+
if isinstance(w,QToolButton) or isinstance(w,QPushButton):
|
|
1215
|
+
if not w.icon().isNull():
|
|
1216
|
+
size = w.iconSize()
|
|
1217
|
+
new_size = QSize(
|
|
1218
|
+
max(1, size.width()),
|
|
1219
|
+
max(1, size.height())
|
|
1220
|
+
)
|
|
1221
|
+
w.setIconSize(new_size)
|
|
1222
|
+
if (isinstance(w,QToolButton) or isinstance(w,QPushButton) or w.objectName()=='logo') and not isinstance(w,HoverZoomToolButton) and w.metaObject().className() not in ('DraggableButton','RichTextPushButton') and w.objectName() not in ('binButton','CollapsibleBox_toggle','StartingPage_Button','button_dockVis'):
|
|
1223
|
+
if w.objectName() in ('logo','title_icon','workspace_icon'):
|
|
1224
|
+
apply_hover_glow_label(w)
|
|
1225
|
+
w.default_stylesheet=w.styleSheet()
|
|
1226
|
+
else:
|
|
1227
|
+
apply_native_hover_glow(w)
|
|
1228
|
+
if w.metaObject().className() == "RichTextPushButton" or isinstance(w,QComboBox):
|
|
1229
|
+
apply_native_hover_glow(w)
|
|
1230
|
+
if isinstance(w,QCheckBox) or isinstance(w,QRadioButton):
|
|
1231
|
+
style=f"{w.metaObject().className()}{f'::hover{{ background-color: {PaIRS_ghostblue}; border-radius: 6px;}}'}"
|
|
1232
|
+
w.setStyleSheet(style)
|
|
1233
|
+
if isinstance(w,QSlider):
|
|
1234
|
+
w.setMouseTracking(True)
|
|
1235
|
+
cursor_filter = SliderHandleCursorFilter(w)
|
|
1236
|
+
w.installEventFilter(cursor_filter)
|
|
1237
|
+
apply_native_hover_glow(w,borderRadius=6,glowSize=2)
|
|
1238
|
+
if w.objectName()=='log' and hasattr(self,'gui'):
|
|
1239
|
+
base=f"""
|
|
1240
|
+
QTextEdit {{
|
|
1241
|
+
background-color: #000000;
|
|
1242
|
+
color: #FFFFFF;
|
|
1243
|
+
border: 1px solid #2a2a2a;
|
|
1244
|
+
border-radius: 6px;
|
|
1245
|
+
|
|
1246
|
+
padding: 2px;
|
|
1247
|
+
|
|
1248
|
+
selection-background-color: {PaIRS_blue};
|
|
1249
|
+
selection-color: #FFFFFF;
|
|
1250
|
+
}}
|
|
1251
|
+
"""
|
|
1252
|
+
w.setStyleSheet(base + "\n" + gPaIRS_QMenu_style)
|
|
1253
|
+
if isinstance(w,MyQLineEdit) or isinstance(w,QSpinBox) or isinstance(w,QDoubleSpinBox):
|
|
1254
|
+
install_right_click_menu(w)
|
|
1088
1255
|
|
|
1089
1256
|
for sname in ('range_from','range_to','x','y','w','h'):
|
|
1090
1257
|
if hasattr(self.ui,"spin_"+sname):
|
|
@@ -1202,6 +1369,31 @@ def adjustFont(self:QLabel):
|
|
|
1202
1369
|
|
|
1203
1370
|
self.setFont(font)
|
|
1204
1371
|
|
|
1372
|
+
def mouseRightPressEvent(self, event):
|
|
1373
|
+
self.FlagRightButtonPress = event.type() == QEvent.MouseButtonPress and event.button() == Qt.RightButton
|
|
1374
|
+
return type(self).mousePressEvent(self, event)
|
|
1375
|
+
|
|
1376
|
+
def focusOutEvent_preserve_on_right_click(self, event):
|
|
1377
|
+
if getattr(self, "FlagRightButtonPress", True):
|
|
1378
|
+
event.accept()
|
|
1379
|
+
self.FlagRightButtonPress = False
|
|
1380
|
+
else:
|
|
1381
|
+
type(self).focusOutEvent(self, event)
|
|
1382
|
+
return
|
|
1383
|
+
|
|
1384
|
+
def mouseReleaseEvent_preserve_on_right_click(self, event):
|
|
1385
|
+
if getattr(self, "FlagRightButtonPress", True):
|
|
1386
|
+
event.accept()
|
|
1387
|
+
else:
|
|
1388
|
+
type(self).mouseReleaseEvent(self, event)
|
|
1389
|
+
return
|
|
1390
|
+
|
|
1391
|
+
def install_right_click_menu(w):
|
|
1392
|
+
w.FlagRightButtonPress = False
|
|
1393
|
+
w.mousePressEvent = types.MethodType(mouseRightPressEvent, w)
|
|
1394
|
+
w.focusOutEvent = types.MethodType(focusOutEvent_preserve_on_right_click, w)
|
|
1395
|
+
w.mouseReleaseEvent = types.MethodType(mouseReleaseEvent_preserve_on_right_click, w)
|
|
1396
|
+
|
|
1205
1397
|
#*************************************************** Other
|
|
1206
1398
|
def iterateList(l,value):
|
|
1207
1399
|
if type(l)==list:
|