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.
Files changed (50) hide show
  1. PaIRS_UniNa/Calibration_Tab.py +40 -24
  2. PaIRS_UniNa/Changes.txt +50 -0
  3. PaIRS_UniNa/Explorer.py +257 -77
  4. PaIRS_UniNa/FolderLoop.py +196 -6
  5. PaIRS_UniNa/Input_Tab.py +160 -53
  6. PaIRS_UniNa/Input_Tab_CalVi.py +11 -12
  7. PaIRS_UniNa/Input_Tab_tools.py +30 -28
  8. PaIRS_UniNa/Output_Tab.py +1 -3
  9. PaIRS_UniNa/PaIRS_pypacks.py +171 -67
  10. PaIRS_UniNa/Process_Tab.py +19 -15
  11. PaIRS_UniNa/Process_Tab_Disp.py +8 -1
  12. PaIRS_UniNa/SPIVCalHelp.py +155 -0
  13. PaIRS_UniNa/Saving_tools.py +3 -0
  14. PaIRS_UniNa/TabTools.py +201 -9
  15. PaIRS_UniNa/Vis_Tab.py +221 -65
  16. PaIRS_UniNa/Vis_Tab_CalVi.py +139 -12
  17. PaIRS_UniNa/Whatsnew.py +4 -3
  18. PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
  19. PaIRS_UniNa/__init__.py +3 -3
  20. PaIRS_UniNa/addwidgets_ps.py +773 -97
  21. PaIRS_UniNa/calibView.py +5 -2
  22. PaIRS_UniNa/gPaIRS.py +307 -48
  23. PaIRS_UniNa/icons/closeAllFloat.png +0 -0
  24. PaIRS_UniNa/icons/defaultWinSize.png +0 -0
  25. PaIRS_UniNa/icons/dockVis.png +0 -0
  26. PaIRS_UniNa/icons/dockVis_disable.png +0 -0
  27. PaIRS_UniNa/icons/floatingVisSize.png +0 -0
  28. PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
  29. PaIRS_UniNa/icons/folder_loop_cleanup_off.png +0 -0
  30. PaIRS_UniNa/icons/fullWinsize.png +0 -0
  31. PaIRS_UniNa/icons/icon_PaIRS.ico +0 -0
  32. PaIRS_UniNa/icons/information.png +0 -0
  33. PaIRS_UniNa/icons/information2.png +0 -0
  34. PaIRS_UniNa/icons/scan_path_loop.png +0 -0
  35. PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
  36. PaIRS_UniNa/icons/smallWinSize.png +0 -0
  37. PaIRS_UniNa/icons/spiv_setup_no.png +0 -0
  38. PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
  39. PaIRS_UniNa/icons/undockVis.png +0 -0
  40. PaIRS_UniNa/procTools.py +46 -1
  41. PaIRS_UniNa/rqrdpckgs.txt +7 -7
  42. PaIRS_UniNa/tabSplitter.py +6 -1
  43. PaIRS_UniNa/ui_Calibration_Tab.py +92 -59
  44. PaIRS_UniNa/ui_gPairs.py +92 -50
  45. PaIRS_UniNa/ui_infoPaIRS.py +8 -8
  46. PaIRS_UniNa/whatsnew.txt +2 -3
  47. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/METADATA +6 -8
  48. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/RECORD +50 -33
  49. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/WHEEL +1 -1
  50. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.11.dist-info}/top_level.txt +0 -0
PaIRS_UniNa/Vis_Tab.py CHANGED
@@ -234,8 +234,7 @@ class NamesPIV(TABpar):
234
234
 
235
235
  class VISpar(TABpar):
236
236
  FlagVis=True
237
- FlagAutoLevels=True
238
- FlagAutoSizes=True
237
+
239
238
  class OUT(TABpar):
240
239
  def __init__(self):
241
240
  self.x = 0
@@ -269,7 +268,7 @@ class VISpar(TABpar):
269
268
  def __init__(self,Process=ProcessTypes.null,Step=StepTypes.null):
270
269
  self.setup(Process,Step)
271
270
  super().__init__('VISpar','Vis')
272
- self.unchecked_fields+=['FlagAutomaticLevels','FlagAutomaticSizes','setPage']
271
+ self.unchecked_fields+=['setPage']
273
272
  self.uncopied_fields+=['graphics_fields']
274
273
 
275
274
  def setup(self,Process,Step):
@@ -314,6 +313,8 @@ class VISpar(TABpar):
314
313
  self.variableKey=''
315
314
  self.field_rep=0
316
315
 
316
+ self.FlagAutoLevels=True
317
+ self.FlagAutoSizes=True
317
318
  self.FlagYInvert=[False,False]
318
319
  self.FlagResetLevels=True
319
320
  self.FlagResetSizes=True
@@ -389,7 +390,7 @@ class VISpar(TABpar):
389
390
  class Vis_Tab(gPaIRS_Tab):
390
391
  class VIS_Tab_Signals(gPaIRS_Tab.Tab_Signals):
391
392
  pass
392
-
393
+
393
394
  def __init__(self,parent: QWidget =None, flagInit= __name__ == "__main__"):
394
395
  super().__init__(parent,Ui_VisTab,VISpar)
395
396
  self.signals=self.VIS_Tab_Signals(self)
@@ -397,9 +398,23 @@ class Vis_Tab(gPaIRS_Tab):
397
398
  #------------------------------------- Graphical interface: widgets
398
399
  self.TABname='Vis'
399
400
  self.ui: Ui_VisTab
401
+
402
+ # Create a container widget that will hold toolbar + plot
403
+ self.w_plot_container = QWidget(self)
404
+ self.vlay_plot_container = vlay = QVBoxLayout(self.w_plot_container)
405
+ vlay.setContentsMargins(0, 0, 0, 0)
406
+ vlay.setSpacing(0)
407
+ parent_layout = self.ui.lay_w_Plot
408
+ parent_layout.removeWidget(self.ui.plot)
409
+ vlay.addWidget(self.ui.plot)
410
+ parent_layout.insertWidget(-1, self.w_plot_container)
411
+ parent_layout.setStretchFactor(self.w_plot_container,1)
400
412
  self.Ptoolbar=None
401
413
  self.addPlotToolBar()
402
414
  self.ui.plot.axes.format_coord=lambda x,y: self.custom_format_coord(x,y)
415
+ self.w_plot_container.contextMenuEvent = lambda ev: plotContextMenuEvent(self.w_plot_container, self, ev)
416
+ self.addButtonDockVis()
417
+ self.tabWin=None
403
418
 
404
419
  self.ui.sliders=self.findChildren(QSlider)
405
420
  for slider in (self.ui.slider_min,self.ui.slider_max,self.ui.slider_mean,self.ui.slider_range):
@@ -442,6 +457,7 @@ class Vis_Tab(gPaIRS_Tab):
442
457
  pri.Time.magenta('Colormap generation: start')
443
458
  # Create the popup menu
444
459
  self.colorMapMenu = QMenu(self)
460
+ self.colorMapMenu.setStyleSheet(gPaIRS_QMenu_style)
445
461
  # Add the colormap thumbnails to the menu
446
462
  def on_colormap_selected(name):
447
463
  self.VISpar.vcolorMap[self.VISpar.variableKey]=self.VISpar.colorMap=name
@@ -462,6 +478,7 @@ class Vis_Tab(gPaIRS_Tab):
462
478
  pri.Time.magenta('Vector color generation: start')
463
479
  # Create the popup menu
464
480
  self.vectorColorMenu = QMenu(self)
481
+ self.vectorColorMenu.setStyleSheet(gPaIRS_QMenu_style)
465
482
  # Add the colormap thumbnails to the menu
466
483
  def on_vectorcolor_selected(name):
467
484
  self.VISpar.vvectorColor[self.VISpar.variableKey]=self.VISpar.vectorColor=name
@@ -476,7 +493,9 @@ class Vis_Tab(gPaIRS_Tab):
476
493
  action = menu.addAction(QIcon(pixmap), ' '+colorName.lower())
477
494
  action.triggered.connect(lambda _, name=colorName: on_vectorcolor_selected(name))
478
495
  pri.Time.magenta('Vector color generation: end')
479
-
496
+
497
+ apply_hover_glow_label(self.ui.icon)
498
+
480
499
  #------------------------------------- Declaration of parameters
481
500
  self.VISpar_base=VISpar()
482
501
  self.VISpar:VISpar=self.TABpar
@@ -504,14 +523,15 @@ class Vis_Tab(gPaIRS_Tab):
504
523
 
505
524
  slider.valueChanged.connect(callback)
506
525
 
526
+ """
507
527
  if n in ('nclev','streamdens'):
508
528
  def sliderMessage(s:QSlider):
509
529
  if self.VISpar.field_rep==2:
510
530
  tip = f"Release to repaint"
511
- else: tip=""
512
- QToolTip.showText(s.mapToGlobal(s.rect().topLeft()), tip)
531
+ show_mouse_tooltip(s,tip)
513
532
  slider.sliderPressed.connect(lambda: sliderMessage(slider))
514
-
533
+ """
534
+
515
535
  setattr(self,'slider_'+n+'_callbcak',callback)
516
536
  setattr(self,'spin_'+n+'_action',action)
517
537
  setattr(self,'spin_'+n+'_set',setting)
@@ -536,6 +556,8 @@ class Vis_Tab(gPaIRS_Tab):
536
556
  self.QS_copy2clipboard.activated.connect(self.ui.plot.copy2clipboard)
537
557
  self.QS_copy2newfig=QShortcut(QKeySequence('Ctrl+D'), self.ui.plot)
538
558
  self.QS_copy2newfig.activated.connect(lambda: self.ui.plot.copy2newfig(self.ui.name_var.toolTip()))
559
+ self.QS_undockfig=QShortcut(QKeySequence('Ctrl+U'), self.ui.plot)
560
+ self.QS_undockfig.activated.connect(self.undockfig)
539
561
  self.load_Img_callback=self.wrappedCallback('Loading image',self.loadImg)
540
562
  self.load_Res_callback=self.wrappedCallback('Loading result',self.loadRes)
541
563
 
@@ -550,8 +572,8 @@ class Vis_Tab(gPaIRS_Tab):
550
572
  self.setTABlayout=self.setVISlayout
551
573
 
552
574
  self.FlagReset=True
553
- self.FlagResetLevels=True
554
- self.FlagResetSizes =True
575
+ self.FlagResetLevels=False
576
+ self.FlagResetSizes =False
555
577
 
556
578
  self.image_file=''
557
579
  self.image_raw=None
@@ -591,7 +613,7 @@ class Vis_Tab(gPaIRS_Tab):
591
613
  for x in self.Ptoolbar.actions():
592
614
  if x.text() in unwanted_buttons:
593
615
  self.Ptoolbar.removeAction(x)
594
- self.ui.lay_w_Plot.addWidget(self.Ptoolbar)
616
+ self.vlay_plot_container.addWidget(self.Ptoolbar)
595
617
 
596
618
  def initialize(self):
597
619
  pri.Info.yellow(f'{"*"*20} VIS initialization {"*"*20}')
@@ -623,6 +645,103 @@ class Vis_Tab(gPaIRS_Tab):
623
645
  self.VISpar.Out.FlagNone=True
624
646
  return
625
647
 
648
+ def addButtonDockVis(self):
649
+ # Container widget that will expand inside w_plot
650
+ self.dockWidget = QWidget(self.ui.w_plot)
651
+ self.dockWidget.setSizePolicy(
652
+ QSizePolicy.Expanding,
653
+ QSizePolicy.Expanding
654
+ )
655
+
656
+ # Center layout
657
+ vlay = QVBoxLayout(self.dockWidget)
658
+ vlay.setContentsMargins(0, 0, 0, 0)
659
+ vlay.setSpacing(15)
660
+
661
+ self.label_dockVis = QLabel(self)
662
+ self.label_dockVis.setText('Plot area detached and moved to a separate window.')
663
+ self.label_dockVis.setAlignment(Qt.AlignmentFlag.AlignCenter)
664
+ font=self.label_dockVis.font()
665
+ font.setItalic(True)
666
+ self.label_dockVis.setFont(font)
667
+ self.label_dockVis.setStyleSheet(
668
+ "QLabel { color: rgb(128,128,128) }"
669
+ )
670
+
671
+ # Central push button (icon only, no border)
672
+ self.button_dockVis = QPushButton(self)
673
+ self.button_dockVis.setObjectName('button_dockVis')
674
+ self.button_dockVis.setFlat(True) # no raised frame
675
+ self.button_dockVis.setCheckable(False)
676
+ self.button_dockVis.setText("") # icon only
677
+ self.button_dockVis.setIcon(QIcon(icons_path+"dockVis_disable.png"))
678
+ self.button_dockVis.setIconSize(QSize(64, 64))
679
+ self.button_dockVis.setStyleSheet(
680
+ "QPushButton { border: none; background: transparent; }"
681
+ "QPushButton:hover { background: rgba(0,0,0,20); border-radius: 4px; }"
682
+ "QPushButton:hover {"
683
+ "border: none;"
684
+ "background: transparent;"
685
+ "image: url("+icons_path+"dockVis.png);"
686
+ "}"
687
+ )
688
+ self.button_dockVis.setToolTip('Dock plot area')
689
+ self.button_dockVis.setStatusTip('Dock plot area')
690
+
691
+ # Center the button inside the expanding widget
692
+ vlay.addStretch()
693
+ vlay.addWidget(self.label_dockVis)
694
+ vlay.addWidget(self.button_dockVis, 0, Qt.AlignCenter)
695
+ vlay.addSpacerItem(QSpacerItem(10,self.button_dockVis.height()*2,QSizePolicy.Policy.Expanding,QSizePolicy.Policy.Fixed))
696
+ vlay.addStretch()
697
+
698
+ # Add the widget to w_plot layout
699
+ # assuming w_plot has a layout called lay_w_Plot
700
+ self.dockWidget.setVisible(False)
701
+ self.ui.verticalLayout.addWidget(self.dockWidget)
702
+ self.ui.verticalLayout.setStretchFactor(self.dockWidget,1)
703
+
704
+ # Optional: connect button signal
705
+ # self.btDock.clicked.connect(self.onDockClicked)
706
+
707
+ def undockfig(self):
708
+ wid=self.ui.w_plot #self.ui.w_plot_container
709
+ def btDock_callback():
710
+ self.gui.GPApar.tabWinPar[self.TABname]={
711
+ 'active' : False,
712
+ 'geometry' : save_frame_geometry_to_param(self.tabWin),
713
+ 'windowState' : self.tabWin.saveState().toBase64().data().decode(),
714
+ 'visible' : False,
715
+ }
716
+
717
+ self.tabWin=None
718
+ parent_layout = self.ui.lay_w_Plot
719
+ parent_layout.setStretchFactor(wid,1)
720
+ self.dockWidget.setVisible(False)
721
+ self.button_dockVis.clicked.disconnect(f.close)
722
+ self.QS_undockfig.activated.disconnect()
723
+ self.QS_undockfig.activated.connect(self.undockfig)
724
+ self.dockWidget.setVisible(True)
725
+ self.tabWin=f=self.gui.FloatingWidget(self,wid,btDock_callback)
726
+ f.setWindowTitle('Vis')
727
+ f.setWindowIcon(QIcon(icons_path+"vis_logo.png"))
728
+ if self.TABname in self.gui.GPApar.tabWinPar and 'geometry' in self.gui.GPApar.tabWinPar[self.TABname]:
729
+ restore_frame_geometry_from_param(f,self.gui.GPApar.tabWinPar[self.TABname]['geometry'])
730
+ else:
731
+ screen_geom = self.gui.app.primaryScreen().availableGeometry()
732
+ new_w = int(screen_geom.width() * 0.5)
733
+ new_h = int(screen_geom.height() * 0.8)
734
+ f.resize(new_w,new_h)
735
+ frame = f.frameGeometry()
736
+ frame.moveCenter(screen_geom.center())
737
+ f.move(frame.topLeft())
738
+ f.setContentsMargins(self.gui.w_Vis.layout().contentsMargins())
739
+ f.setMinimumSize(QSize(480,480))
740
+ self.gui.FloatingWindows.append(f)
741
+ self.button_dockVis.clicked.connect(f.close)
742
+ self.QS_undockfig.activated.disconnect()
743
+ self.QS_undockfig.activated.connect(self.button_dockVis.click)
744
+
626
745
  #*************************************************** Adjusting parameters
627
746
  def adjustVISpar(self):
628
747
  self.VISpar.ncam=len(self.VISpar.imList)
@@ -637,7 +756,7 @@ class Vis_Tab(gPaIRS_Tab):
637
756
  FlagNew=(not self.VISpar.type and FlagNewImage) or (self.VISpar.type==1 and FlagNewResult)
638
757
  FlagDiff=self.VISpar.isDifferentFrom(self.VISpar_old,fields=['img','cam','frame']) or FlagNew
639
758
 
640
- if (VISpar.FlagAutoLevels and (FlagNewImage or FlagNewResult)):
759
+ if (self.VISpar.FlagAutoLevels and (FlagNewImage or FlagNewResult)):
641
760
  self.resetAllLevels()
642
761
  if FlagDiff or self.FlagResetLevels:
643
762
  self.FlagResetLevels=False
@@ -646,7 +765,7 @@ class Vis_Tab(gPaIRS_Tab):
646
765
  self.FlagResetLevels=False
647
766
  self.resetLevels()
648
767
 
649
- if (VISpar.FlagAutoSizes and (FlagNewImage or FlagNewResult)):
768
+ if (self.VISpar.FlagAutoSizes and (FlagNewImage or FlagNewResult)):
650
769
  self.resetAllXYLims()
651
770
  if FlagDiff or self.FlagResetSizes:
652
771
  self.FlagResetSizes=False
@@ -654,8 +773,8 @@ class Vis_Tab(gPaIRS_Tab):
654
773
  elif self.FlagResetSizes:
655
774
  self.FlagResetSizes=False
656
775
  self.resetXYLims()
657
-
658
- self.adjustFieldRep()
776
+
777
+ self.adjustFieldRep()
659
778
 
660
779
  def adjustImport(self):
661
780
  self.VISpar.image_file=self.VISpar.image_file_Min=self.VISpar.image_file_Disp=''
@@ -702,7 +821,13 @@ class Vis_Tab(gPaIRS_Tab):
702
821
  else:
703
822
  self.VISpar.result_file=self.VISpar.resF(self.VISpar.img)
704
823
  elif self.VISpar.img==0:
705
- self.VISpar.result_file=self.VISpar.result_file_Mean
824
+ self.VISpar.result_file=self.VISpar.result_file_Mean
825
+ if not self.VISpar.FlagView:
826
+ ITE=self.gui.ui.Explorer.ITEfromInd(self.VISpar.ind)
827
+ id=ITE.procdata.name_proc
828
+ self.VISpar.FlagResult=fileIdenitifierCheck(id,self.VISpar.result_file)
829
+ if not self.VISpar.FlagResult: self.VISpar.result_file=''
830
+
706
831
 
707
832
  FlagNewImage, FlagNewResult, _=self.importFiles()
708
833
  return FlagNewImage, FlagNewResult
@@ -1063,7 +1188,8 @@ class Vis_Tab(gPaIRS_Tab):
1063
1188
  res[n]=tres[0][:,:,j]
1064
1189
  if self.namesPIV.u in res and self.namesPIV.v in res:
1065
1190
  res=self.calcMagnitude(res)
1066
- res=self.calcZVorticity(res)
1191
+ FlagUnit=self.VISpar.Out.xres!=1.0 or self.VISpar.Out.pixAR!=1.0
1192
+ res=self.calcZVorticity(res,FlagUnit)
1067
1193
  for f in list(res):
1068
1194
  if not f in self.namesPIV.allFields: del res[f]
1069
1195
  except Exception as inst:
@@ -1079,9 +1205,10 @@ class Vis_Tab(gPaIRS_Tab):
1079
1205
  res[self.namesPIV.Mod]=np.sqrt(res[self.namesPIV.u]**2+res[self.namesPIV.v]**2)
1080
1206
  return res
1081
1207
 
1082
- def calcZVorticity(self,res):
1208
+ def calcZVorticity(self,res,FlagUnit=False):
1083
1209
  if self.namesPIV.x in res and self.namesPIV.y in res and self.namesPIV.u in res and self.namesPIV.v in res:
1084
- xres,yres=self.getXYRes(type=1)
1210
+ if FlagUnit: xres=yres=1/1000
1211
+ else: xres=yres=1.0
1085
1212
  try:
1086
1213
  du_dy, _=np.gradient(res[self.namesPIV.u],res[self.namesPIV.y][:,0]*yres,res[self.namesPIV.x][0,:]*xres) # Derivate di u rispetto a y e x
1087
1214
  _, dv_dx=np.gradient(res[self.namesPIV.v],res[self.namesPIV.y][:,0]*yres,res[self.namesPIV.x][0,:]*xres) # Derivate di v rispetto a y e x
@@ -1182,11 +1309,21 @@ class Vis_Tab(gPaIRS_Tab):
1182
1309
  self.setLevels()
1183
1310
 
1184
1311
  def button_automatic_levels_action(self):
1185
- VISpar.FlagAutoLevels=self.ui.button_automatic_levels.isChecked()
1312
+ self.VISpar.FlagAutoLevels=self.ui.button_automatic_levels.isChecked()
1186
1313
  return True
1187
1314
 
1188
1315
  def button_automatic_sizes_action(self):
1189
- VISpar.FlagAutoSizes=self.ui.button_automatic_sizes.isChecked()
1316
+ self.VISpar.FlagAutoSizes=self.ui.button_automatic_sizes.isChecked()
1317
+ if self.VISpar.FlagAutoSizes is False and self.VISpar.Process==ProcessTypes.piv:
1318
+ type2=0 if self.VISpar.type==1 else 1
1319
+ if self.VISpar.unit[self.VISpar.type]!=self.VISpar.unit[type2]:
1320
+ xres,yres=self.getXYRes(type=self.VISpar.unit[self.VISpar.type])
1321
+ else: xres=yres=1.0
1322
+ if (type2==0 and self.VISpar.unit[type2]) or (type2==1 and not self.VISpar.unit[type2]):
1323
+ xres2,yres2=self.getXYRes(type=type2)
1324
+ else: xres2=yres2=1.0
1325
+ self.VISpar.size[type2][0:2]=[s*xres/xres2 for s in [self.VISpar.xmin, self.VISpar.xmax]]
1326
+ self.VISpar.size[type2][2:4]=[s*yres/yres2 for s in [self.VISpar.ymin, self.VISpar.ymax]]
1190
1327
  return True
1191
1328
 
1192
1329
  def button_restore_action(self):
@@ -1327,6 +1464,7 @@ class Vis_Tab(gPaIRS_Tab):
1327
1464
 
1328
1465
  # Create a context menu and populate it with the available sizes
1329
1466
  menu = QMenu(self)
1467
+ menu.setStyleSheet(gPaIRS_QMenu_style)
1330
1468
  for i in range(n):
1331
1469
  label = f"{Vect[2][i]} x {Vect[0][i]}"
1332
1470
  act = menu.addAction(label)
@@ -1389,10 +1527,10 @@ class Vis_Tab(gPaIRS_Tab):
1389
1527
  self.ui.button_Contourf.setChecked(self.VISpar.FlagContourf)
1390
1528
 
1391
1529
  def button_automatic_levels_set(self):
1392
- self.ui.button_automatic_levels.setChecked(VISpar.FlagAutoLevels)
1530
+ self.ui.button_automatic_levels.setChecked(self.VISpar.FlagAutoLevels)
1393
1531
 
1394
1532
  def button_automatic_sizes_set(self):
1395
- self.ui.button_automatic_sizes.setChecked(VISpar.FlagAutoSizes)
1533
+ self.ui.button_automatic_sizes.setChecked(self.VISpar.FlagAutoSizes)
1396
1534
 
1397
1535
  def button_invert_y_set(self):
1398
1536
  self.ui.button_invert_y.setChecked(self.VISpar.FlagYInvert[self.VISpar.type])
@@ -1480,6 +1618,7 @@ class Vis_Tab(gPaIRS_Tab):
1480
1618
  FlagVecField=self.VISpar.isDifferentFrom(self.VISpar_old,fields=fields)
1481
1619
  if FlagVecField and self.result:
1482
1620
  self.showVecField()
1621
+ elif self.result is None: self.cleanVecField()
1483
1622
  FlagDraw=FlagDraw or FlagVecField
1484
1623
 
1485
1624
  if FlagDraw:
@@ -1520,7 +1659,7 @@ class Vis_Tab(gPaIRS_Tab):
1520
1659
  FlagXLim=True
1521
1660
  else:
1522
1661
  self.imgshow.set_data(img)
1523
- extent=self.imgExtent()
1662
+ extent=self.imgExtent(size)
1524
1663
  if extent!=self.imgshow.get_extent():
1525
1664
  self.imgshow.set_extent(extent)
1526
1665
  FlagExtent=True
@@ -1560,7 +1699,7 @@ class Vis_Tab(gPaIRS_Tab):
1560
1699
  return cmap, levs
1561
1700
 
1562
1701
  def getXYRes(self,type=None):
1563
- if not type: type=self.VISpar.type
1702
+ if type is None: type=self.VISpar.type
1564
1703
  xres=yres=1.0
1565
1704
  if self.VISpar.Process==ProcessTypes.piv and not self.VISpar.Out.FlagNone:
1566
1705
  if type==0: #mm/pixels
@@ -2001,46 +2140,6 @@ class Vis_Tab(gPaIRS_Tab):
2001
2140
  """
2002
2141
 
2003
2142
  #*************************************************** Menus
2004
- def contextMenuEvent(self, event):
2005
- contextMenu = QMenu(self)
2006
- copy2clipboard = contextMenu.addAction("Copy to clipboard ("+self.QS_copy2clipboard.key().toString(QKeySequence.NativeText)+")")
2007
- copy2clipboard.setIcon(self.ui.plot.copyIcon)
2008
- copy2newfig = contextMenu.addAction("Open in new figure ("+self.QS_copy2newfig.key().toString(QKeySequence.NativeText)+")")
2009
- copy2newfig.setIcon(self.ui.plot.openNewWindowIcon)
2010
- contextMenu.addSeparator()
2011
- if len(self.ui.plot.fig2)>0:
2012
- showAll = contextMenu.addAction("Show all")
2013
- showAll.setIcon(self.ui.plot.showAllIcon)
2014
- alignAll = contextMenu.addAction("Align all")
2015
- alignAll.setIcon(self.ui.plot.alignAllIcon)
2016
- closeAll = contextMenu.addAction("Close all")
2017
- closeAll.setIcon(self.ui.plot.closeAllIcon)
2018
- contextMenu.addSeparator()
2019
- else:
2020
- showAll = None
2021
- closeAll= None
2022
- alignAll= None
2023
- loadImg = contextMenu.addAction("Load image")
2024
- loadImg.setIcon(self.ui.plot.loadImageIcon)
2025
- loadRes = contextMenu.addAction("Load result")
2026
- loadRes.setIcon(self.ui.plot.loadResultIcon)
2027
-
2028
- action = contextMenu.exec(self.mapToGlobal(event.pos()))
2029
- if action == copy2clipboard:
2030
- self.ui.plot.copy2clipboard()
2031
- elif action == copy2newfig:
2032
- self.ui.plot.copy2newfig(self.ui.name_var.toolTip())
2033
- elif action == showAll:
2034
- self.ui.plot.showAll()
2035
- elif action == closeAll:
2036
- self.ui.plot.closeAll()
2037
- elif action == alignAll:
2038
- self.ui.plot.alignAll()
2039
- elif action == loadImg:
2040
- self.load_Img_callback()
2041
- elif action == loadRes:
2042
- self.load_Res_callback()
2043
-
2044
2143
  def loadImg(self,filename=None):
2045
2144
  if filename is None:
2046
2145
  filename, _ = QFileDialog.getOpenFileName(self,\
@@ -2079,6 +2178,63 @@ class Vis_Tab(gPaIRS_Tab):
2079
2178
  self.VISpar.type=1
2080
2179
  self.cleanAxes()
2081
2180
 
2181
+ def plotContextMenuEvent(obj, self:Vis_Tab, event):
2182
+ contextMenu = QMenu(obj)
2183
+ contextMenu.setStyleSheet(gPaIRS_QMenu_style)
2184
+ copyGraphicalSetting = contextMenu.addAction("Copy graphical settings from...")
2185
+ copyGraphicalSetting.setIcon(self.gui.brush_icon)
2186
+ contextMenu.addSeparator()
2187
+ copy2clipboard = contextMenu.addAction("Copy to clipboard ("+self.QS_copy2clipboard.key().toString(QKeySequence.NativeText)+")")
2188
+ copy2clipboard.setIcon(self.ui.plot.copyIcon)
2189
+ copy2newfig = contextMenu.addAction("Open in new figure ("+self.QS_copy2newfig.key().toString(QKeySequence.NativeText)+")")
2190
+ copy2newfig.setIcon(self.ui.plot.openNewWindowIcon)
2191
+ contextMenu.addSeparator()
2192
+ if len(self.ui.plot.fig2)>0:
2193
+ showAll = contextMenu.addAction("Show all")
2194
+ showAll.setIcon(self.ui.plot.showAllIcon)
2195
+ alignAll = contextMenu.addAction("Align all")
2196
+ alignAll.setIcon(self.ui.plot.alignAllIcon)
2197
+ closeAll = contextMenu.addAction("Close all")
2198
+ closeAll.setIcon(self.ui.plot.closeAllIcon)
2199
+ contextMenu.addSeparator()
2200
+ else:
2201
+ showAll = None
2202
+ closeAll= None
2203
+ alignAll= None
2204
+ loadImg = contextMenu.addAction("Load image")
2205
+ loadImg.setIcon(self.ui.plot.loadImageIcon)
2206
+ loadRes = contextMenu.addAction("Load result")
2207
+ loadRes.setIcon(self.ui.plot.loadResultIcon)
2208
+ contextMenu.addSeparator()
2209
+ if self.button_dockVis.isVisible():
2210
+ undockfig = contextMenu.addAction("Dock plot aera ("+self.QS_undockfig.key().toString(QKeySequence.NativeText)+")")
2211
+ undockfig.setIcon(QIcon(icons_path+"dockVis.png"))
2212
+ undock_fun = self.button_dockVis.click
2213
+ else:
2214
+ undockfig = contextMenu.addAction("Undock plot aera ("+self.QS_undockfig.key().toString(QKeySequence.NativeText)+")")
2215
+ undockfig.setIcon(QIcon(icons_path+"undockVis.png"))
2216
+ undock_fun = self.undockfig
2217
+
2218
+ action = contextMenu.exec(obj.mapToGlobal(event.pos()))
2219
+ if action == copyGraphicalSetting:
2220
+ self.ui.icon.addfuncclick['copy_VIS']()
2221
+ elif action == copy2clipboard:
2222
+ self.ui.plot.copy2clipboard()
2223
+ elif action == copy2newfig:
2224
+ self.ui.plot.copy2newfig(self.ui.name_var.toolTip())
2225
+ elif action == showAll:
2226
+ self.ui.plot.showAll()
2227
+ elif action == closeAll:
2228
+ self.ui.plot.closeAll()
2229
+ elif action == alignAll:
2230
+ self.ui.plot.alignAll()
2231
+ elif action == loadImg:
2232
+ self.load_Img_callback()
2233
+ elif action == loadRes:
2234
+ self.load_Res_callback()
2235
+ elif action == undockfig:
2236
+ undock_fun()
2237
+
2082
2238
  def create_colormap_image(colormap, width, height, FlagVerticalColormap, imgMapPath):
2083
2239
  # Create an empty image
2084
2240
  img = np.zeros((height, width, 3), dtype=np.uint8)
@@ -151,6 +151,11 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
151
151
  if __name__ == "__main__":
152
152
  self.app=app
153
153
  setAppGuiPalette(self)
154
+
155
+ self.addButtonDockVis()
156
+ self.tabWin = None
157
+ self.QS_undockfig=QShortcut(QKeySequence('Ctrl+U'), self.calibView)
158
+ self.QS_undockfig.activated.connect(self.undockfig)
154
159
 
155
160
  #------------------------------------- Graphical interface: miscellanea
156
161
  self.ui.status_L.setText('')
@@ -275,13 +280,16 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
275
280
  self.buttonsToDisableNotCalibrated.append(self.functionButtons[k])
276
281
 
277
282
  functionButtons_insert=[0,0,0]
283
+ self.action_undock=QAction(QIcon(icons_path+"undockVis.png"),'Undock plot area',self)
284
+ self.action_undock.triggered.connect(self.undockfig)
285
+ self.action_dock=QAction(QIcon(icons_path+"dockVis.png"),'Dock plot area',self)
286
+ self.action_dock.triggered.connect(self.button_dockVis.click)
278
287
  for k,ind in enumerate([f.value for f in CalibFunctions]):
279
288
  action=QAction(self.functionButtons[k].icn,calibFunctionsText[abs(ind)],self)
280
289
  self.calibView.contextMenuActions.insert(functionButtons_insert[k],action)
281
290
  action.triggered.connect(create_functionButton_action(ind))
282
291
  if ind>0:
283
292
  self.buttonsToDisableNotCalibrated.append(action)
284
-
285
293
  self.originOffbox=self.ui.g_OriOff
286
294
  self.remPoinsBox=self.ui.g_GriLim
287
295
  self.buttonsToDisable=[
@@ -296,6 +304,106 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
296
304
  logfont.setPixelSize(fPixSize)
297
305
  self.ui.log.setFont(logfont)
298
306
 
307
+ def addButtonDockVis(self):
308
+ # Container widget that will expand inside w_plot
309
+ self.dockWidget = QWidget(self.ui.w_plot)
310
+ self.dockWidget.setSizePolicy(
311
+ QSizePolicy.Expanding,
312
+ QSizePolicy.Expanding
313
+ )
314
+
315
+ # Center layout
316
+ vlay = QVBoxLayout(self.dockWidget)
317
+ vlay.setContentsMargins(0, 0, 0, 0)
318
+ vlay.setSpacing(15)
319
+
320
+ self.label_dockVis = QLabel(self)
321
+ self.label_dockVis.setText('Plot area detached and moved to a separate window.')
322
+ self.label_dockVis.setAlignment(Qt.AlignmentFlag.AlignCenter)
323
+ font=self.label_dockVis.font()
324
+ font.setItalic(True)
325
+ self.label_dockVis.setFont(font)
326
+ self.label_dockVis.setStyleSheet(
327
+ "QLabel { color: rgb(128,128,128) }"
328
+ )
329
+
330
+ # Central push button (icon only, no border)
331
+ self.button_dockVis = QPushButton(self)
332
+ self.button_dockVis.setObjectName('button_dockVis')
333
+ self.button_dockVis.setFlat(True) # no raised frame
334
+ self.button_dockVis.setCheckable(False)
335
+ self.button_dockVis.setText("") # icon only
336
+ self.button_dockVis.setIcon(QIcon(icons_path+"dockVis_disable.png"))
337
+ self.button_dockVis.setIconSize(QSize(64, 64))
338
+ self.button_dockVis.setStyleSheet(
339
+ "QPushButton { border: none; background: transparent; }"
340
+ "QPushButton:hover { background: rgba(0,0,0,20); border-radius: 4px; }"
341
+ "QPushButton:hover {"
342
+ "border: none;"
343
+ "background: transparent;"
344
+ "image: url("+icons_path+"dockVis.png);"
345
+ "}"
346
+ )
347
+ self.button_dockVis.setToolTip('Dock plot area')
348
+ self.button_dockVis.setStatusTip('Dock plot area')
349
+
350
+ # Center the button inside the expanding widget
351
+ vlay.addStretch()
352
+ vlay.addWidget(self.label_dockVis)
353
+ vlay.addWidget(self.button_dockVis, 0, Qt.AlignCenter)
354
+ vlay.addSpacerItem(QSpacerItem(10,self.button_dockVis.height()*2,QSizePolicy.Policy.Expanding,QSizePolicy.Policy.Fixed))
355
+ vlay.addStretch()
356
+
357
+ # Add the widget to w_plot layout
358
+ # assuming w_plot has a layout called lay_w_Plot
359
+ self.dockWidget.setVisible(False)
360
+ self.ui.verticalLayout.addWidget(self.dockWidget)
361
+ self.ui.verticalLayout.setStretchFactor(self.dockWidget,1)
362
+
363
+ # Optional: connect button signal
364
+ # self.btDock.clicked.connect(self.onDockClicked)
365
+
366
+ def undockfig(self):
367
+ wid=self.ui.w_plot #self.ui.w_plot_container
368
+ def btDock_callback():
369
+ self.gui.GPApar.tabWinPar[self.TABname]={
370
+ 'active' : False,
371
+ 'geometry' : save_frame_geometry_to_param(self.tabWin),
372
+ 'windowState' : self.tabWin.saveState().toBase64().data().decode(),
373
+ 'visible' : False,
374
+ }
375
+
376
+ self.tabWin=None
377
+ parent_layout = self.ui.verticalLayout
378
+ parent_layout.setStretchFactor(wid,1)
379
+ self.dockWidget.setVisible(False)
380
+ self.button_dockVis.clicked.disconnect(f.close)
381
+ self.QS_undockfig.activated.disconnect()
382
+ self.QS_undockfig.activated.connect(self.undockfig)
383
+ self.setContextMenuLayout()
384
+ self.gui.updateGPAparGeometry()
385
+ self.dockWidget.setVisible(True)
386
+ self.tabWin=f=self.gui.FloatingWidget(self,wid,btDock_callback)
387
+ f.setWindowTitle('Vis (CalVi)')
388
+ f.setWindowIcon(QIcon(icons_path+"vis_logo.png"))
389
+ if self.TABname in self.gui.GPApar.tabWinPar and 'geometry' in self.gui.GPApar.tabWinPar[self.TABname]:
390
+ restore_frame_geometry_from_param(f,self.gui.GPApar.tabWinPar[self.TABname]['geometry'])
391
+ else:
392
+ screen_geom = QGuiApplication.primaryScreen().availableGeometry()
393
+ new_w = int(screen_geom.width() * 0.8)
394
+ new_h = int(screen_geom.height() * 0.8)
395
+ f.resize(new_w,new_h)
396
+ frame = f.frameGeometry()
397
+ frame.moveCenter(screen_geom.center())
398
+ f.move(frame.topLeft())
399
+ f.setContentsMargins(self.gui.w_Vis.layout().contentsMargins())
400
+ f.setMinimumSize(QSize(480,480))
401
+ self.gui.FloatingWindows.append(f)
402
+ self.button_dockVis.clicked.connect(f.close)
403
+ self.QS_undockfig.activated.disconnect()
404
+ self.QS_undockfig.activated.connect(self.button_dockVis.click)
405
+ self.setContextMenuLayout()
406
+
299
407
  #********************************************* Adjusting parameters
300
408
  def adjustVISpar(self):
301
409
  self.calibView.hide()
@@ -383,17 +491,10 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
383
491
  self.ui.button_PlotMask.setEnabled(self.VISpar.MaskType not in (2,3))
384
492
 
385
493
  self.ui.w_Commands.setVisible(self.VISpar.FlagRunning)
386
- if self.VISpar.FlagRunning:
387
- self.calibView.contextMenu = QtWidgets.QMenu(self)
388
- for a in self.calibView.contextMenuActions:
389
- self.calibView.contextMenu.addAction(a)
390
- self.calibView.contextMenu.insertSeparator(self.calibView.contextMenuActions[1])
391
- else:
392
- self.calibView.contextMenu =None
393
-
494
+ self.setContextMenuLayout()
495
+
394
496
  self.setSpinMaxMin()
395
497
  self.ui.Vis_CalVi_splitter.setSizes(self.VISpar.splitterSizes)
396
-
397
498
  self.calibView.scaleFactor=self.VISpar.scaleFactor
398
499
  self.calibView.calib.LMin=self.VISpar.LMin
399
500
  self.calibView.calib.LMax=self.VISpar.LMax
@@ -425,6 +526,34 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
425
526
  self.setRunButtonText()
426
527
  return
427
528
 
529
+ def setContextMenuLayout(self):
530
+ self.calibView.contextMenu = QtWidgets.QMenu(self)
531
+ self.calibView.contextMenu.setStyleSheet(gPaIRS_QMenu_style)
532
+
533
+ text=self.gui.ui.button_Run_CalVi.lbl.text()
534
+ text=text if 'Run' not in text else 'Run'
535
+ action_run=QAction(self.gui.ui.button_Run_CalVi.icn,text+' CalVi',self)
536
+ action_run.triggered.connect(self.gui.ui.button_Run_CalVi.click)
537
+ self.calibView.contextMenu.addAction(action_run)
538
+ if self.VISpar.FlagRunning:
539
+ action_abort=QAction(self.gui.ui.button_Abort_CalVi.icn,self.gui.ui.button_Abort_CalVi.lbl.text()+' CalVi',self)
540
+ action_abort.triggered.connect(self.gui.ui.button_Abort_CalVi.click)
541
+ self.calibView.contextMenu.addAction(action_abort)
542
+ self.calibView.contextMenu.addSeparator()
543
+
544
+ FlagSeparator=False
545
+ if self.VISpar.FlagRunning:
546
+ for a in self.calibView.contextMenuActions:
547
+ self.calibView.contextMenu.addAction(a)
548
+ FlagSeparator=True
549
+ self.calibView.contextMenu.insertSeparator(self.calibView.contextMenuActions[1])
550
+ if FlagSeparator: self.calibView.contextMenu.addSeparator()
551
+
552
+ if self.tabWin:
553
+ self.calibView.contextMenu.addAction(self.action_dock)
554
+ else:
555
+ self.calibView.contextMenu.addAction(self.action_undock)
556
+
428
557
  def setSpinMaxMin(self):
429
558
  self.ui.spin_plane.setMinimum(1*bool(self.VISpar.nPlane))
430
559
  self.ui.spin_plane.setMaximum(self.VISpar.nPlane)
@@ -968,8 +1097,6 @@ class Vis_Tab_CalVi(gPaIRS_Tab):
968
1097
  FlagVisible=all([not bool(p) for p in calVect.flagPlane[:-1]])
969
1098
  self.gui.ui.button_Run_CalVi.setVisible(FlagVisible)
970
1099
 
971
-
972
-
973
1100
 
974
1101
  if __name__ == "__main__":
975
1102
  import sys