PaIRS-UniNa 0.2.7__cp312-cp312-macosx_11_0_universal2.whl → 0.2.10__cp312-cp312-macosx_11_0_universal2.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 +16 -0
- PaIRS_UniNa/Changes.txt +39 -0
- PaIRS_UniNa/Explorer.py +311 -75
- 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 +17 -15
- PaIRS_UniNa/Output_Tab.py +1 -3
- PaIRS_UniNa/PaIRS_pypacks.py +63 -65
- 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 +2 -0
- PaIRS_UniNa/TabTools.py +165 -6
- PaIRS_UniNa/Vis_Tab.py +50 -22
- PaIRS_UniNa/Vis_Tab_CalVi.py +1 -2
- PaIRS_UniNa/Whatsnew.py +4 -3
- PaIRS_UniNa/_PaIRS_PIV.so +0 -0
- PaIRS_UniNa/__init__.py +3 -3
- PaIRS_UniNa/addwidgets_ps.py +570 -70
- PaIRS_UniNa/gPaIRS.py +118 -17
- PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
- PaIRS_UniNa/icons/folder_loop_cleanup_off.png +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/spiv_setup_no.png +0 -0
- PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
- PaIRS_UniNa/procTools.py +46 -1
- PaIRS_UniNa/rqrdpckgs.txt +7 -7
- PaIRS_UniNa/ui_Calibration_Tab.py +92 -59
- PaIRS_UniNa/ui_gPairs.py +8 -8
- PaIRS_UniNa/whatsnew.txt +2 -3
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/METADATA +7 -8
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/RECORD +38 -30
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/WHEEL +0 -0
- {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/top_level.txt +0 -0
PaIRS_UniNa/Explorer.py
CHANGED
|
@@ -14,11 +14,11 @@ MONTH_ABBREVIATIONS = {
|
|
|
14
14
|
1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun",
|
|
15
15
|
7: "Jul", 8: "Aug", 9: "Sep", StepTypes.cal: "Oct", 11: "Nov", 12: "Dec"
|
|
16
16
|
}
|
|
17
|
-
projectActionButtonSize=[20,
|
|
18
|
-
processActionButtonSize=[20,
|
|
17
|
+
projectActionButtonSize=[20,25]
|
|
18
|
+
processActionButtonSize=[20,25]
|
|
19
19
|
actionButtonSpacing=3
|
|
20
|
-
processButtonSize=[40,
|
|
21
|
-
stepButtonSize=[32,
|
|
20
|
+
processButtonSize=[40,50] #icon, button
|
|
21
|
+
stepButtonSize=[32,40]
|
|
22
22
|
headerHeight=24
|
|
23
23
|
titleHeight=22
|
|
24
24
|
subtitleHeight=14
|
|
@@ -323,12 +323,28 @@ class ModernSwitch(QWidget):
|
|
|
323
323
|
self._checked = True
|
|
324
324
|
par.FlagQueue=self._checked
|
|
325
325
|
|
|
326
|
+
# --- HOVER SETUP ---
|
|
327
|
+
self.setAttribute(Qt.WA_Hover, True)
|
|
328
|
+
self.setMouseTracking(True)
|
|
329
|
+
self._hovered = False
|
|
330
|
+
self._border_width = 1
|
|
331
|
+
self._border_width_hover = 2
|
|
332
|
+
self._border_color = QColor(0, 0, 0)
|
|
333
|
+
self._border_color_hover = QColor(240, 116, 35) # highlight
|
|
334
|
+
|
|
326
335
|
# Load image for the handle and scale it to fit the ellipse
|
|
327
336
|
self.handle_image = QPixmap(icons_path+"gear.png") # Replace with your image path
|
|
328
337
|
self.handle_image = self.handle_image.scaledToHeight(self.height() - self.handleMargin*2, Qt.SmoothTransformation)
|
|
329
338
|
|
|
330
339
|
self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
|
|
331
340
|
self.FlagAnimation=False
|
|
341
|
+
|
|
342
|
+
self.FlagRunning = False
|
|
343
|
+
self.gearMovie: QMovie = None
|
|
344
|
+
|
|
345
|
+
self._bg_color = QColor(46, 204, 113) if self._checked else QColor(175, 175, 175, 128)
|
|
346
|
+
self._handle_position = 0 # inizializzato in setSwitchLayout()
|
|
347
|
+
|
|
332
348
|
self.setSwitchLayout()
|
|
333
349
|
|
|
334
350
|
self.animation = QPropertyAnimation(self, b"handle_position", self)
|
|
@@ -357,20 +373,35 @@ class ModernSwitch(QWidget):
|
|
|
357
373
|
if par and self.gui.procdata:
|
|
358
374
|
if self.gui.procdata.ind[:-2]==par.ind[:-2]:
|
|
359
375
|
self.startTimer()
|
|
360
|
-
#self.timer.start(50) # Aggiorna ogni 50 ms
|
|
361
376
|
|
|
377
|
+
# ----------------- Hover events -----------------
|
|
378
|
+
def enterEvent(self, event):
|
|
379
|
+
self._hovered = True
|
|
380
|
+
self.update()
|
|
381
|
+
super().enterEvent(event)
|
|
382
|
+
|
|
383
|
+
def leaveEvent(self, event):
|
|
384
|
+
self._hovered = False
|
|
385
|
+
self.update()
|
|
386
|
+
super().leaveEvent(event)
|
|
387
|
+
|
|
388
|
+
# ----------------- Timer control -----------------
|
|
362
389
|
def startTimer(self):
|
|
363
390
|
if not self.FlagRunning and hasattr(self.gui,'gearMovie'):
|
|
364
391
|
self.FlagRunning=True
|
|
365
392
|
self.gearMovie=self.gui.gearMovie
|
|
366
393
|
self.timer.start(self.timerTime)
|
|
367
|
-
|
|
394
|
+
try:
|
|
395
|
+
pri.Coding.yellow('Start switch timer')
|
|
396
|
+
except Exception:
|
|
397
|
+
pass
|
|
368
398
|
|
|
369
399
|
def stopTimer(self):
|
|
370
400
|
if self.FlagRunning:
|
|
371
401
|
self.FlagRunning=False
|
|
372
402
|
self.timer.stop()
|
|
373
403
|
|
|
404
|
+
# ----------------- Property animation -----------------
|
|
374
405
|
def set_handle_position(self, pos):
|
|
375
406
|
self._handle_position = pos
|
|
376
407
|
self.update()
|
|
@@ -380,90 +411,98 @@ class ModernSwitch(QWidget):
|
|
|
380
411
|
|
|
381
412
|
handle_position = Property(int, fget=get_handle_position, fset=set_handle_position)
|
|
382
413
|
|
|
414
|
+
# ----------------- Painting -----------------
|
|
383
415
|
def paintEvent(self, event):
|
|
384
416
|
painter = QPainter(self)
|
|
385
417
|
painter.setRenderHint(QPainter.Antialiasing)
|
|
386
418
|
|
|
387
|
-
#
|
|
388
|
-
bg_rect = QRect(0, 0, self.width(), self.height())
|
|
389
|
-
|
|
390
|
-
#
|
|
419
|
+
# Background rect (rounded)
|
|
420
|
+
bg_rect = QRect(0, 0, self.width(), self.height()).adjusted(1, 1, -1, -1)
|
|
421
|
+
|
|
422
|
+
# Border pen (changes on hover)
|
|
423
|
+
if not self.isEnabled():
|
|
424
|
+
pen = QPen(self._border_color)
|
|
425
|
+
pen.setWidth(self._border_width)
|
|
426
|
+
else:
|
|
427
|
+
pen = QPen(self._border_color_hover if self._hovered else self._border_color)
|
|
428
|
+
pen.setWidth(self._border_width_hover if self._hovered else self._border_width)
|
|
429
|
+
|
|
430
|
+
painter.setPen(pen)
|
|
391
431
|
painter.setBrush(self._bg_color)
|
|
392
|
-
painter.drawRoundedRect(bg_rect
|
|
432
|
+
painter.drawRoundedRect(bg_rect, self.height() / 2, self.height() / 2)
|
|
393
433
|
|
|
394
|
-
#
|
|
434
|
+
# Handle position and size
|
|
395
435
|
handle_x = self._handle_position
|
|
396
436
|
handle_y = self.handleMargin
|
|
397
|
-
|
|
398
|
-
|
|
437
|
+
handle_w = self.handle_image.width()
|
|
438
|
+
handle_h = self.handle_image.height()
|
|
439
|
+
handle_rect = QRect(handle_x, handle_y, handle_w, handle_h)
|
|
399
440
|
|
|
400
|
-
|
|
401
|
-
if self.
|
|
402
|
-
|
|
403
|
-
handle_rect = QRect(handle_x, handle_y, handle_width, handle_height)
|
|
404
|
-
painter.drawPixmap(handle_rect, self.handle_image)
|
|
405
|
-
else:
|
|
406
|
-
# Draw handle circle
|
|
407
|
-
handle_radius = self.height() - self.handleMargin*2
|
|
408
|
-
handle_rect = QRect(self._handle_position, self.handleMargin, handle_radius, handle_radius)
|
|
409
|
-
painter.setBrush(Qt.white)
|
|
410
|
-
painter.drawEllipse(handle_rect)
|
|
411
|
-
"""
|
|
412
|
-
handle_rect = QRect(handle_x, handle_y, handle_width, handle_height)
|
|
413
|
-
#painter.drawPixmap(handle_rect, self.handle_image)
|
|
414
|
-
if self.FlagRunning:
|
|
415
|
-
painter.drawImage(handle_rect,self.gearMovie.currentImage())
|
|
441
|
+
# Draw gear (static or animated)
|
|
442
|
+
if self.FlagRunning and self.gearMovie is not None:
|
|
443
|
+
painter.drawImage(handle_rect, self.gearMovie.currentImage())
|
|
416
444
|
else:
|
|
417
|
-
painter.drawImage(handle_rect,self.handle_image.toImage())
|
|
418
|
-
|
|
445
|
+
painter.drawImage(handle_rect, self.handle_image.toImage())
|
|
446
|
+
|
|
447
|
+
# Draw label text
|
|
419
448
|
if self.FlagAnimation:
|
|
420
449
|
self.text_label.setText("")
|
|
421
450
|
else:
|
|
422
451
|
if self._checked:
|
|
423
452
|
self.text_label.setText("run ")
|
|
424
|
-
self.text_label.
|
|
453
|
+
self.text_label.adjustSize()
|
|
454
|
+
self.text_label.move(self.handleMargin * 2, (self.height() - self.text_label.height()) // 2)
|
|
425
455
|
else:
|
|
426
456
|
self.text_label.setText("skip")
|
|
427
|
-
self.text_label.
|
|
457
|
+
self.text_label.adjustSize()
|
|
458
|
+
self.text_label.move(self.width() - self.height() - self.handleMargin * 2,
|
|
459
|
+
(self.height() - self.text_label.height()) // 2)
|
|
428
460
|
|
|
461
|
+
# ----------------- Interaction -----------------
|
|
429
462
|
def mousePressEvent(self, event):
|
|
430
|
-
if event.button() == Qt.LeftButton and not self.FlagAnimation:
|
|
463
|
+
if event.button() == Qt.LeftButton and not self.FlagAnimation and self.isEnabled():
|
|
431
464
|
self.toggle()
|
|
432
465
|
|
|
433
466
|
def toggle(self):
|
|
434
467
|
self._checked = not self._checked
|
|
435
|
-
if self.par:
|
|
468
|
+
if self.par:
|
|
469
|
+
self.par.FlagQueue = self._checked
|
|
470
|
+
|
|
436
471
|
self.toggled.emit(self._checked)
|
|
472
|
+
|
|
473
|
+
self.animation.stop()
|
|
474
|
+
self.animation.setStartValue(self._handle_position)
|
|
437
475
|
self.animation.setEndValue(self.switchHandlePosition())
|
|
438
|
-
self.FlagAnimation=True
|
|
476
|
+
self.FlagAnimation = True
|
|
439
477
|
self.animation.start()
|
|
440
|
-
|
|
478
|
+
|
|
479
|
+
# ----------------- Layout helpers -----------------
|
|
441
480
|
def switchHandlePosition(self):
|
|
442
481
|
if self._checked:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
handle_position = self.handleMargin
|
|
446
|
-
return handle_position
|
|
482
|
+
return self.width() - self.height() + self.handleMargin
|
|
483
|
+
return self.handleMargin
|
|
447
484
|
|
|
448
485
|
def setSwitchLayout(self):
|
|
449
|
-
self.FlagAnimation=False
|
|
486
|
+
self.FlagAnimation = False
|
|
450
487
|
if self._checked:
|
|
451
|
-
self._bg_color = QColor(46, 204, 113)
|
|
452
|
-
tip=f'{self.name if self.name else "Item"} added to run queue.'
|
|
488
|
+
self._bg_color = QColor(46, 204, 113)
|
|
489
|
+
tip = f'{self.name if self.name else "Item"} added to run queue.'
|
|
453
490
|
else:
|
|
454
|
-
tip=f'{self.name if self.name else "Item"} excluded from run queue.'
|
|
455
|
-
#text_color = self.palette().color(QPalette.WindowText)
|
|
456
491
|
self._bg_color = QColor(175, 175, 175)
|
|
457
|
-
self._bg_color.setAlpha(
|
|
492
|
+
self._bg_color.setAlpha(64)
|
|
493
|
+
tip = f'{self.name if self.name else "Item"} excluded from run queue.'
|
|
494
|
+
|
|
458
495
|
self.setToolTip(tip)
|
|
459
496
|
self.setStatusTip(tip)
|
|
460
497
|
self.set_handle_position(self.switchHandlePosition())
|
|
461
498
|
|
|
462
|
-
def setSwitch(self,FlagChecked):
|
|
463
|
-
if FlagChecked!=self._checked:
|
|
464
|
-
self._checked=FlagChecked
|
|
499
|
+
def setSwitch(self, FlagChecked: bool):
|
|
500
|
+
if FlagChecked != self._checked:
|
|
501
|
+
self._checked = FlagChecked
|
|
502
|
+
if self.par:
|
|
503
|
+
self.par.FlagQueue = self._checked
|
|
465
504
|
self.setSwitchLayout()
|
|
466
|
-
|
|
505
|
+
|
|
467
506
|
class ActionButtonBar(QWidget):
|
|
468
507
|
FlagShortCuts = True
|
|
469
508
|
|
|
@@ -495,7 +534,7 @@ class ActionButtonBar(QWidget):
|
|
|
495
534
|
setattr(self,'sep_'+icon_name[1:],separator)
|
|
496
535
|
self.buttonLayout.addWidget(separator)
|
|
497
536
|
else:
|
|
498
|
-
b =
|
|
537
|
+
b = HoverZoomToolButton(self)
|
|
499
538
|
b.setObjectName('button_'+icon_name)
|
|
500
539
|
b.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
501
540
|
if FlagInvisible:
|
|
@@ -560,6 +599,7 @@ class ActionButtonBar(QWidget):
|
|
|
560
599
|
tree.FlagContexMenu=True
|
|
561
600
|
|
|
562
601
|
menu=QMenu(tree)
|
|
602
|
+
menu.setStyleSheet(self.window().ui.menu.styleSheet())
|
|
563
603
|
name=[]
|
|
564
604
|
act=[]
|
|
565
605
|
fun=[]
|
|
@@ -578,7 +618,7 @@ class ActionButtonBar(QWidget):
|
|
|
578
618
|
if FlagNamedBar and 'class' in bar.buttonData[type]:
|
|
579
619
|
if 'PIV'!=nameAction[:3]: nameAction=nameAction[:1].lower()+nameAction[1:]
|
|
580
620
|
if b.isCheckable():
|
|
581
|
-
nameAction=
|
|
621
|
+
nameAction=b.toolTip()
|
|
582
622
|
else:
|
|
583
623
|
nameAction='Add '+nameAction
|
|
584
624
|
act.append(QAction(b.icon(),nameAction,self))
|
|
@@ -1039,7 +1079,63 @@ class ProjectTree(PaIRSTree):
|
|
|
1039
1079
|
self.actionBar.button_close.setEnabled(FlagEnabled)
|
|
1040
1080
|
self.actionBar.button_clean.setEnabled(self.topLevelItemCount()>0)
|
|
1041
1081
|
|
|
1042
|
-
class
|
|
1082
|
+
class HoverZoomToolButton(QToolButton):
|
|
1083
|
+
def __init__(self, parent=None, base_icon=24, zoom=1.25):
|
|
1084
|
+
super().__init__(parent)
|
|
1085
|
+
|
|
1086
|
+
self.zoom_factor = zoom
|
|
1087
|
+
self.base_size = QSize(base_icon, base_icon)
|
|
1088
|
+
self.zoom_size = QSize(
|
|
1089
|
+
int(base_icon * zoom),
|
|
1090
|
+
int(base_icon * zoom)
|
|
1091
|
+
)
|
|
1092
|
+
|
|
1093
|
+
self.setIconSize(self.base_size)
|
|
1094
|
+
|
|
1095
|
+
self.anim = QPropertyAnimation(self, b"iconSize", self)
|
|
1096
|
+
self.anim.setDuration(120)
|
|
1097
|
+
self.anim.setEasingCurve(QEasingCurve.OutCubic)
|
|
1098
|
+
|
|
1099
|
+
# --- OVERRIDE ---
|
|
1100
|
+
def setIconSize(self, size: QSize):
|
|
1101
|
+
"""
|
|
1102
|
+
Override setIconSize to automatically update base and zoom sizes.
|
|
1103
|
+
"""
|
|
1104
|
+
super().setIconSize(size)
|
|
1105
|
+
self.updateFromCurrentIconSize()
|
|
1106
|
+
|
|
1107
|
+
def updateFromCurrentIconSize(self, zoom: float | None = None):
|
|
1108
|
+
"""
|
|
1109
|
+
Recompute base_size and zoom_size starting from the current iconSize().
|
|
1110
|
+
Optionally updates the zoom factor.
|
|
1111
|
+
"""
|
|
1112
|
+
if zoom is not None:
|
|
1113
|
+
self.zoom_factor = zoom
|
|
1114
|
+
|
|
1115
|
+
current = self.iconSize()
|
|
1116
|
+
self.base_size = QSize(current.width(), current.height())
|
|
1117
|
+
self.zoom_size = QSize(
|
|
1118
|
+
int(current.width() * self.zoom_factor),
|
|
1119
|
+
int(current.height() * self.zoom_factor)
|
|
1120
|
+
)
|
|
1121
|
+
|
|
1122
|
+
def enterEvent(self, event):
|
|
1123
|
+
if self.isEnabled():
|
|
1124
|
+
self.anim.stop()
|
|
1125
|
+
self.anim.setStartValue(self.iconSize())
|
|
1126
|
+
self.anim.setEndValue(self.zoom_size)
|
|
1127
|
+
self.anim.start()
|
|
1128
|
+
super().enterEvent(event)
|
|
1129
|
+
|
|
1130
|
+
def leaveEvent(self, event):
|
|
1131
|
+
if self.isEnabled():
|
|
1132
|
+
self.anim.stop()
|
|
1133
|
+
self.anim.setStartValue(self.iconSize())
|
|
1134
|
+
self.anim.setEndValue(self.base_size)
|
|
1135
|
+
self.anim.start()
|
|
1136
|
+
super().leaveEvent(event)
|
|
1137
|
+
|
|
1138
|
+
class DraggableButton(HoverZoomToolButton):
|
|
1043
1139
|
def __init__(self, data: dict = {}, buttonSize: list = processButtonSize, FlagInvisible=True, parent=None):
|
|
1044
1140
|
super().__init__(parent)
|
|
1045
1141
|
self.buttonData = data
|
|
@@ -1052,6 +1148,7 @@ class DraggableButton(QToolButton):
|
|
|
1052
1148
|
self.setIconSize(QSize(self.buttonSize[0], self.buttonSize[0]))
|
|
1053
1149
|
self.setIcon(self.buttonIcon)
|
|
1054
1150
|
self.setFixedSize(self.buttonSize[1], self.buttonSize[1])
|
|
1151
|
+
|
|
1055
1152
|
if FlagInvisible:
|
|
1056
1153
|
self.setCursor(Qt.CursorShape.OpenHandCursor)
|
|
1057
1154
|
self.setStyleSheet("QToolButton { border: none; background: none;} QToolButton::menu-indicator { image: none; }")
|
|
@@ -1103,7 +1200,7 @@ class ProcessButtonBar(QWidget):
|
|
|
1103
1200
|
super().__init__()
|
|
1104
1201
|
self.buttonLayout = QHBoxLayout()
|
|
1105
1202
|
self.buttonLayout.setContentsMargins(0, 0, 0, 0)
|
|
1106
|
-
self.buttonLayout.setSpacing(int(buttonSize[0]
|
|
1203
|
+
self.buttonLayout.setSpacing(int(buttonSize[0]/4))
|
|
1107
1204
|
self.setLayout(self.buttonLayout)
|
|
1108
1205
|
self.buttonData=buttonData
|
|
1109
1206
|
self.buttonSize = buttonSize
|
|
@@ -1123,7 +1220,7 @@ class StepButtonBar(QWidget):
|
|
|
1123
1220
|
super().__init__()
|
|
1124
1221
|
self.buttonLayout = QVBoxLayout()
|
|
1125
1222
|
self.buttonLayout.setContentsMargins(10, headerHeight+5, 0, 10)
|
|
1126
|
-
self.buttonLayout.setSpacing(int(buttonSize[0]/
|
|
1223
|
+
self.buttonLayout.setSpacing(int(buttonSize[0]/4))
|
|
1127
1224
|
self.setLayout(self.buttonLayout)
|
|
1128
1225
|
self.buttonData=buttonData
|
|
1129
1226
|
self.buttonSize = buttonSize
|
|
@@ -1135,8 +1232,7 @@ class StepButtonBar(QWidget):
|
|
|
1135
1232
|
data=buttonData[type]
|
|
1136
1233
|
|
|
1137
1234
|
if all([f in list(data) for f in ('icon', 'name', 'type')]):
|
|
1138
|
-
button =
|
|
1139
|
-
button.setIconSize(QSize(self.buttonSize[0], self.buttonSize[0]))
|
|
1235
|
+
button = HoverZoomToolButton(self, base_icon=self.buttonSize[0], zoom=1.25)
|
|
1140
1236
|
button.setFixedSize(self.buttonSize[1], self.buttonSize[1])
|
|
1141
1237
|
|
|
1142
1238
|
if FlagInvisible:
|
|
@@ -1223,7 +1319,7 @@ class ProcessTree(PaIRSTree):
|
|
|
1223
1319
|
|
|
1224
1320
|
if self.FlagBin:
|
|
1225
1321
|
columns=["#","Deleted processes"]
|
|
1226
|
-
self.setStyleSheet("""
|
|
1322
|
+
self.setStyleSheet(self.styleSheet() + """
|
|
1227
1323
|
QHeaderView::section {
|
|
1228
1324
|
color: red;
|
|
1229
1325
|
}
|
|
@@ -1452,8 +1548,8 @@ class ProcessTree(PaIRSTree):
|
|
|
1452
1548
|
ITE.FlagQueue=self.TREpar.FlagQueue
|
|
1453
1549
|
ITE.ind=[self.TREpar.project,int(self.FlagBin),ind,0,0]
|
|
1454
1550
|
|
|
1551
|
+
processNames=[item[0].name for item in self.itemList[0]]+[item[0].name for item in self.restoreTree.itemList[0]]
|
|
1455
1552
|
if name is None:
|
|
1456
|
-
processNames=[item[0].name for item in self.itemList[0]]+[item[0].name for item in self.restoreTree.itemList[0]]
|
|
1457
1553
|
nameInd=1
|
|
1458
1554
|
ITE.name=f'{ITE.basename} {nameInd}'
|
|
1459
1555
|
while ITE.name in processNames:
|
|
@@ -1461,6 +1557,10 @@ class ProcessTree(PaIRSTree):
|
|
|
1461
1557
|
ITE.name=f'{ITE.basename} {nameInd}'
|
|
1462
1558
|
else:
|
|
1463
1559
|
ITE.name=name
|
|
1560
|
+
nameInd=1
|
|
1561
|
+
while ITE.name in processNames:
|
|
1562
|
+
nameInd+=1
|
|
1563
|
+
ITE.name=f'{name} ({nameInd})'
|
|
1464
1564
|
self.createParPrevs(ITE)
|
|
1465
1565
|
self.itemList[0].insert(ind,[ITE])
|
|
1466
1566
|
else:
|
|
@@ -1917,12 +2017,12 @@ class ProcessTree(PaIRSTree):
|
|
|
1917
2017
|
pixmap_list.append(icons_path+ITE.icon)
|
|
1918
2018
|
name_list.append(ITE.name)
|
|
1919
2019
|
flag_list.append(ITE.Step!=StepTypes.cal)
|
|
1920
|
-
func=lambda i, opts: self.process_loop(paths,processType,ind,ITEs[0].name,i,opts)
|
|
2020
|
+
func=lambda i, opts, cleanup_flag, rescan_flag: self.process_loop(paths,processType,ind,ITEs[0].name,i,opts,cleanup_flag,rescan_flag)
|
|
1921
2021
|
dialog = FolderLoopDialog(pixmap_list, name_list, flag_list, parent=self, paths=paths, func=func, process_name=ITEs[0].name)
|
|
1922
2022
|
dialog.exec()
|
|
1923
2023
|
return
|
|
1924
2024
|
|
|
1925
|
-
def process_loop(self,paths,processType,ind,name0,i,opts):
|
|
2025
|
+
def process_loop(self,paths,processType,ind,name0,i,opts,cleanup_flag,rescan_flag):
|
|
1926
2026
|
nProcess=self.topLevelItemCount()
|
|
1927
2027
|
path=paths[i]
|
|
1928
2028
|
name=name0+f" (.../{os.path.basename(path)}/)"
|
|
@@ -1933,6 +2033,7 @@ class ProcessTree(PaIRSTree):
|
|
|
1933
2033
|
ind_slave[2]=nProcess
|
|
1934
2034
|
ind_slave[-1]=0
|
|
1935
2035
|
|
|
2036
|
+
FlagWarning=False
|
|
1936
2037
|
for j in range(len(opts)):
|
|
1937
2038
|
ind_master[3]=j
|
|
1938
2039
|
ind_slave[3]=j
|
|
@@ -1944,10 +2045,17 @@ class ProcessTree(PaIRSTree):
|
|
|
1944
2045
|
if opts[j]==2:
|
|
1945
2046
|
INP: INPpar=self.gui.w_Input.TABpar_at(ind_new)
|
|
1946
2047
|
INP.path=myStandardPath(path)
|
|
1947
|
-
|
|
2048
|
+
if rescan_flag:
|
|
2049
|
+
flagWarning=self.rescanInputPath(ind_master,ind_new,cleanup_flag)
|
|
2050
|
+
else:
|
|
2051
|
+
flagWarning=self.gui.w_Input.scanImList(ind_new)
|
|
2052
|
+
if cleanup_flag: self.gui.w_Input.purgeImList(ind_new)
|
|
2053
|
+
INP.nimg=0
|
|
2054
|
+
if len(INP.imList[0]):
|
|
2055
|
+
if len(INP.imList[0][0]):
|
|
2056
|
+
INP.nimg=len(INP.imList[0][0])
|
|
1948
2057
|
self.gui.w_Input.checkINPpar(ind_new)
|
|
1949
2058
|
self.gui.w_Input.setINPwarn(ind_new)
|
|
1950
|
-
self.Explorer.setITElayout(ITE)
|
|
1951
2059
|
|
|
1952
2060
|
TABname=self.gui.w_Input.TABname
|
|
1953
2061
|
self.gui.bridge(TABname,ind_new)
|
|
@@ -1966,12 +2074,54 @@ class ProcessTree(PaIRSTree):
|
|
|
1966
2074
|
w.TABpar.copyfrom(currpar)
|
|
1967
2075
|
self.gui.bridge(w.TABname,ind_new)
|
|
1968
2076
|
TABpar.FlagSettingPar=FlagSettingPar
|
|
2077
|
+
self.Explorer.setITElayout(ITE)
|
|
2078
|
+
FlagWarning=FlagWarning or flagWarning or ITE.OptionDone==0
|
|
2079
|
+
|
|
1969
2080
|
#item_child=item.child(j)
|
|
1970
2081
|
#item_child.setSelected(True)
|
|
1971
2082
|
#self.setCurrentItem(item_child)
|
|
1972
2083
|
else:
|
|
1973
2084
|
self.gui.link_pars(ind_slave,ind_master,FlagSet=False)
|
|
1974
|
-
return
|
|
2085
|
+
return FlagWarning
|
|
2086
|
+
|
|
2087
|
+
def rescanInputPath(self, ind_master, ind_new, FlagNoWarning):
|
|
2088
|
+
"""Rescan input on slave using master patterns, then rebuild imList/imEx."""
|
|
2089
|
+
INP: INPpar = self.gui.w_Input.TABpar_at(ind_new) # slave
|
|
2090
|
+
INPm: INPpar = self.gui.w_Input.TABpar_at(ind_master) # master
|
|
2091
|
+
|
|
2092
|
+
# Build A (for frame_1) and B (for frame_2) from master's pattern at master's frames
|
|
2093
|
+
patm = getattr(INPm.imSet, "pattern", [])
|
|
2094
|
+
ncam = INP.inp_ncam
|
|
2095
|
+
def _pat_list(frames,ind0=0):
|
|
2096
|
+
out=[];
|
|
2097
|
+
for k in range(ncam):
|
|
2098
|
+
f = frames[k]-ind0 if k < len(frames) else -1
|
|
2099
|
+
out.append(patm[f] if isinstance(f,int) and 0 <= f < len(patm) else None)
|
|
2100
|
+
return out
|
|
2101
|
+
A = _pat_list(INPm.frame_1)
|
|
2102
|
+
B = _pat_list(INPm.frame_2,1)
|
|
2103
|
+
|
|
2104
|
+
# Rescan slave input path with patterns=A,B (maps patterns -> frame indices on slave)
|
|
2105
|
+
self.gui.w_Input.scanInputPath(ind_new, patterns=[A, B], FlagNoWarning=FlagNoWarning)
|
|
2106
|
+
|
|
2107
|
+
# Rebuild imList/imEx from frames computed on slave
|
|
2108
|
+
INP.imList, INP.imEx = INP.imSet.genListsFromFrame(
|
|
2109
|
+
INP.frame_1, INP.frame_2, INP.ind_in, INP.npairs, INP.step, INP.FlagTR_Import
|
|
2110
|
+
)
|
|
2111
|
+
# Compare slave vs master lists
|
|
2112
|
+
def _lists_differ(a, b):
|
|
2113
|
+
if len(a) != len(b): return True
|
|
2114
|
+
for x, y in zip(a, b):
|
|
2115
|
+
if x != y: return True
|
|
2116
|
+
return False
|
|
2117
|
+
|
|
2118
|
+
FlagWarning = (
|
|
2119
|
+
_lists_differ(INP.imList, INPm.imList) or
|
|
2120
|
+
_lists_differ(INP.imEx, INPm.imEx)
|
|
2121
|
+
)
|
|
2122
|
+
|
|
2123
|
+
return FlagWarning
|
|
2124
|
+
|
|
1975
2125
|
|
|
1976
2126
|
def button_delete_action(self):
|
|
1977
2127
|
self.blockSignals(True)
|
|
@@ -2296,7 +2446,8 @@ class PaIRS_Explorer(gPaIRS_Tab):
|
|
|
2296
2446
|
self.main_layout.addWidget(self.Explorer_main_splitter)
|
|
2297
2447
|
|
|
2298
2448
|
# Creazione del pulsante checkable
|
|
2299
|
-
self.binButton =
|
|
2449
|
+
self.binButton = HoverZoomToolButton(self.processButtonBar)
|
|
2450
|
+
self.binButton.setObjectName('binButton')
|
|
2300
2451
|
self.binButton.setIconSize(QSize(self.processButtonBar.buttonSize[0], self.processButtonBar.buttonSize[0]))
|
|
2301
2452
|
self.binButton.setFixedSize(self.processButtonBar.buttonSize[1], self.processButtonBar.buttonSize[1])
|
|
2302
2453
|
if self.processButtonBar.FlagInvisible:
|
|
@@ -2377,7 +2528,7 @@ class PaIRS_Explorer(gPaIRS_Tab):
|
|
|
2377
2528
|
tree.setCurrentItem(child)
|
|
2378
2529
|
self.processTree_item_selection(tree)
|
|
2379
2530
|
else:
|
|
2380
|
-
|
|
2531
|
+
show_mouse_tooltip(self,'Current step is disabled! Please, reset the subsequemt step in the process to access it.')
|
|
2381
2532
|
for t,b in self.stepButtonBar.buttons.items():
|
|
2382
2533
|
b:QToolButton
|
|
2383
2534
|
b.clicked.connect(lambda flag, butt=b, type=t: stepButtonAction(butt, type))
|
|
@@ -2492,13 +2643,22 @@ class PaIRS_Explorer(gPaIRS_Tab):
|
|
|
2492
2643
|
if item.childCount()>ind:
|
|
2493
2644
|
item_child=item.child(ind)
|
|
2494
2645
|
item_child.setHidden(not ITEs[ind+1].active)
|
|
2495
|
-
b.setVisible(
|
|
2496
|
-
|
|
2646
|
+
b.setVisible(True)
|
|
2647
|
+
#b.setVisible(c not in ITEs[0].mandatory) #b.setVisible(True)
|
|
2648
|
+
#lab.setVisible(c in ITEs[0].mandatory)
|
|
2497
2649
|
flagRunnable=all([ITEs[j].flagRun==0 for j in range(ind+2,nsteps+1)]) if ind<nsteps else True
|
|
2498
2650
|
flagRunnable=flagRunnable and ITEs[ind+1].flagRun==0 and ITEs[0].flagRun!=-2 #and len(ITEs[ind+1].link)==0
|
|
2499
2651
|
b.setEnabled(flagRunnable)
|
|
2500
|
-
lab.setEnabled(flagRunnable)
|
|
2652
|
+
#lab.setEnabled(flagRunnable)
|
|
2501
2653
|
b.setChecked(ITEs[ind+1].active)
|
|
2654
|
+
nameAction=ITEs[ind+1].name
|
|
2655
|
+
if 'PIV'!=nameAction[:3]: nameAction=nameAction[:1].lower()+nameAction[1:]
|
|
2656
|
+
if c not in ITEs[0].mandatory:
|
|
2657
|
+
nameAction=f"{'De-activate' if b.isChecked() else 'Activate'} {nameAction}"
|
|
2658
|
+
else:
|
|
2659
|
+
nameAction=f"{'Go to and edit'} {nameAction}"
|
|
2660
|
+
b.setToolTip(nameAction)
|
|
2661
|
+
b.setStatusTip(nameAction)
|
|
2502
2662
|
else:
|
|
2503
2663
|
flagRunnable=False
|
|
2504
2664
|
b.setVisible(False)
|
|
@@ -2508,10 +2668,27 @@ class PaIRS_Explorer(gPaIRS_Tab):
|
|
|
2508
2668
|
b.setChecked(False)
|
|
2509
2669
|
b.setButtonIcon()
|
|
2510
2670
|
if self.stepPage:
|
|
2511
|
-
|
|
2671
|
+
FlagChild=c in ITEs[0].children
|
|
2672
|
+
self.stepPage.items[c].setVisible(FlagChild) #and b.isChecked())
|
|
2673
|
+
FlagEnabled=b.isEnabled() or b.isChecked()
|
|
2674
|
+
self.stepPage.items[c].setEnabled(FlagEnabled)
|
|
2512
2675
|
pageButton:QPushButton=self.stepPage.items[c].findChildren(QPushButton)[0]
|
|
2676
|
+
|
|
2677
|
+
if FlagChild:
|
|
2678
|
+
ind=list(ITEs[0].children).index(c)
|
|
2679
|
+
nameAction=ITEs[ind+1].name
|
|
2680
|
+
nameAction_lowerCase=nameAction[:1].lower()+nameAction[1:] if 'PIV'!=nameAction[:3] else nameAction
|
|
2681
|
+
if b.isEnabled():
|
|
2682
|
+
toolTip="Go to and edit " + nameAction_lowerCase if b.isChecked() else b.toolTip()
|
|
2683
|
+
else:
|
|
2684
|
+
toolTip="Go to and view " + nameAction_lowerCase if b.isChecked() else nameAction+" step was excluded from the process!"
|
|
2685
|
+
self.stepPage.items[c].setToolTip(toolTip)
|
|
2686
|
+
self.stepPage.items[c].setStatusTip(toolTip)
|
|
2687
|
+
|
|
2688
|
+
self.stepPage.setProcessTextActive(not (b.isEnabled() and not b.isChecked()),c)
|
|
2689
|
+
|
|
2513
2690
|
if flagRunnable:
|
|
2514
|
-
pageButton.setIcon(b.icon())
|
|
2691
|
+
pageButton.setIcon(b.icon())
|
|
2515
2692
|
else:
|
|
2516
2693
|
pageButton.setIcon(b.iconOn)
|
|
2517
2694
|
else:
|
|
@@ -2953,13 +3130,21 @@ class StartingPage(QFrame):
|
|
|
2953
3130
|
button_margin=self.ITEM_HEIGHT-self.ICON_SIZE-self.BUTTON_LAYOUT_TOP_MARGIN
|
|
2954
3131
|
CAPTION_HEIGHT=self.ITEM_HEIGHT-self.NAME_LABEL_HEIGHT-self.TEXT_LAYOUT_SPACING
|
|
2955
3132
|
self.items={}
|
|
3133
|
+
self.textItems={}
|
|
2956
3134
|
# Itera sui dizionari nella lista
|
|
2957
3135
|
for n, process in processes.items():
|
|
2958
3136
|
# Layout orizzontale per ogni processo
|
|
2959
3137
|
widget=QWidget()
|
|
3138
|
+
widget.setObjectName("process_item")
|
|
3139
|
+
widget.setStyleSheet("""
|
|
3140
|
+
QWidget#process_item:hover {
|
|
3141
|
+
background-color: rgba(0, 116, 255, 0.1);
|
|
3142
|
+
border-radius: 10px;
|
|
3143
|
+
}
|
|
3144
|
+
""")
|
|
2960
3145
|
process_layout = QHBoxLayout(widget)
|
|
2961
3146
|
process_layout.setSpacing(self.LAYOUT_SPACING)
|
|
2962
|
-
process_layout.setContentsMargins(
|
|
3147
|
+
process_layout.setContentsMargins(10, 10, 10, 0)
|
|
2963
3148
|
|
|
2964
3149
|
# Pulsante con icona
|
|
2965
3150
|
button_layout = QHBoxLayout()
|
|
@@ -2967,6 +3152,7 @@ class StartingPage(QFrame):
|
|
|
2967
3152
|
button_layout.setContentsMargins(0, self.BUTTON_LAYOUT_TOP_MARGIN, 0, button_margin)
|
|
2968
3153
|
|
|
2969
3154
|
icon_button = QPushButton()
|
|
3155
|
+
icon_button.setObjectName("StartingPage_Button")
|
|
2970
3156
|
pixmap = QPixmap(icons_path+process['icon']).scaled(self.ICON_SIZE, self.ICON_SIZE, mode=Qt.TransformationMode.SmoothTransformation)
|
|
2971
3157
|
icon_button.setIcon(pixmap)
|
|
2972
3158
|
icon_button.setIconSize(pixmap.size())
|
|
@@ -3007,13 +3193,15 @@ class StartingPage(QFrame):
|
|
|
3007
3193
|
caption_text_edit.setFont(caption_font)
|
|
3008
3194
|
caption_text_edit.setAlignment(Qt.AlignmentFlag.AlignJustify)
|
|
3009
3195
|
caption_text_edit.setReadOnly(True)
|
|
3196
|
+
caption_text_edit.setTextInteractionFlags(Qt.NoTextInteraction)
|
|
3197
|
+
caption_text_edit.viewport().setCursor(Qt.PointingHandCursor)
|
|
3010
3198
|
caption_text_edit.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
3011
3199
|
caption_text_edit.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
3012
3200
|
caption_text_edit.setFrameStyle(QFrame.NoFrame)
|
|
3013
3201
|
#caption_text_edit.setFixedWidth(self.CAPTION_WIDTH)
|
|
3014
3202
|
caption_text_edit.setStyleSheet("background: transparent;")
|
|
3015
3203
|
caption_text_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
|
3016
|
-
|
|
3204
|
+
|
|
3017
3205
|
# Adjust height to content
|
|
3018
3206
|
caption_text_edit.document().setTextWidth(caption_text_edit.viewport().width())
|
|
3019
3207
|
caption_text_edit.setFixedHeight(CAPTION_HEIGHT)#caption_text_edit.document().size().height())
|
|
@@ -3029,7 +3217,30 @@ class StartingPage(QFrame):
|
|
|
3029
3217
|
# Aggiungi il layout orizzontale al layout principale
|
|
3030
3218
|
self.main_layout.addWidget(widget)
|
|
3031
3219
|
|
|
3220
|
+
# --- Make the whole row clickable (icon + labels + background) ---
|
|
3221
|
+
if buttonBar:
|
|
3222
|
+
|
|
3223
|
+
def make_clickable(w, callback):
|
|
3224
|
+
w.setCursor(Qt.PointingHandCursor)
|
|
3225
|
+
|
|
3226
|
+
def mouseReleaseEvent(event, cb=callback, ww=w):
|
|
3227
|
+
if event.button() == Qt.LeftButton:
|
|
3228
|
+
cb()
|
|
3229
|
+
# call base implementation to keep default behaviour
|
|
3230
|
+
QWidget.mouseReleaseEvent(ww, event)
|
|
3231
|
+
|
|
3232
|
+
w.mouseReleaseEvent = mouseReleaseEvent
|
|
3233
|
+
|
|
3234
|
+
# entire row + title + caption all trigger the same action
|
|
3235
|
+
make_clickable(widget, action(n))
|
|
3236
|
+
#make_clickable(name_label, click_callback)
|
|
3237
|
+
#make_clickable(caption_text_edit, click_callback)
|
|
3238
|
+
|
|
3032
3239
|
self.items[n]=widget
|
|
3240
|
+
self.textItems[n]={
|
|
3241
|
+
"name_label": name_label,
|
|
3242
|
+
"caption": caption_text_edit,
|
|
3243
|
+
}
|
|
3033
3244
|
|
|
3034
3245
|
self.main_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding))
|
|
3035
3246
|
|
|
@@ -3054,6 +3265,31 @@ class StartingPage(QFrame):
|
|
|
3054
3265
|
caption_font.setPixelSize(CAPTION_FONT_SIZE)
|
|
3055
3266
|
c.setFont(caption_font)
|
|
3056
3267
|
|
|
3268
|
+
def setProcessTextActive(self, active: bool, key=None):
|
|
3269
|
+
"""
|
|
3270
|
+
If active=True -> black text (active)
|
|
3271
|
+
If active=False -> light bluish text (inactive)
|
|
3272
|
+
If key is None -> apply to all items
|
|
3273
|
+
If key is provided -> apply only to that process key
|
|
3274
|
+
"""
|
|
3275
|
+
active_color = "none"
|
|
3276
|
+
inactive_color = "rgb(150, 150, 255)"
|
|
3277
|
+
|
|
3278
|
+
color = active_color if active else inactive_color
|
|
3279
|
+
|
|
3280
|
+
def apply_to(item):
|
|
3281
|
+
item["name_label"].setStyleSheet(f"color: {color};")
|
|
3282
|
+
# QTextEdit draws text in its viewport -> set color on QTextEdit itself is fine
|
|
3283
|
+
item["caption"].setStyleSheet(f"color: {color}; background: transparent;")
|
|
3284
|
+
|
|
3285
|
+
if key is None:
|
|
3286
|
+
for item in self.textItems.values():
|
|
3287
|
+
apply_to(item)
|
|
3288
|
+
else:
|
|
3289
|
+
if key in self.textItems:
|
|
3290
|
+
apply_to(self.textItems[key])
|
|
3291
|
+
|
|
3292
|
+
|
|
3057
3293
|
if __name__ == "__main__":
|
|
3058
3294
|
app = QApplication([])
|
|
3059
3295
|
app.setStyle('Fusion')
|