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/calibView.py CHANGED
@@ -376,8 +376,11 @@ class CalibView(QLabel):
376
376
  def contextMenuEvent(self, event):
377
377
  # Show the context menu
378
378
  if self.contextMenu:
379
- self.contextMenuPos=event.position()
380
- self.contextMenu.exec(event.globalPosition().toPoint())
379
+ try:
380
+ self.contextMenuPos=event.position()
381
+ self.contextMenu.exec(event.globalPosition().toPoint())
382
+ except:
383
+ pass
381
384
 
382
385
  def mouseMoveEvent(self, mouseEv):
383
386
  ''' mouse move'''
PaIRS_UniNa/gPaIRS.py CHANGED
@@ -95,16 +95,19 @@ class FloatingObject(QMainWindow):
95
95
  self.centralWidget().setMaximumSize(self.pa.maximumSize())
96
96
 
97
97
  class FloatingWidget(FloatingObject):
98
+ closedWin=Signal()
98
99
  def closeEvent(self, event):
99
- index=min([self.index,self.lay.count()-1])
100
+ index=min([self.index,self.lay.count()])
100
101
  self.lay.insertWidget(index,self.pa)
101
102
  self.close()
102
103
  i=self.gui.FloatingWindows.index(self)
103
104
  self.gui.FloatingWindows.pop(i)
105
+ self.closedWin.emit()
104
106
  #self.gui.undockTabs()
105
107
 
106
- def __init__(self,parent,tab):
108
+ def __init__(self,parent,tab,funClose=lambda:None):
107
109
  super().__init__(parent,tab)
110
+ self.closedWin.connect(funClose)
108
111
 
109
112
  geo=self.pa.geometry()
110
113
  geoP=self.gui.geometry()
@@ -124,7 +127,7 @@ class infoPaIRS(QMainWindow):
124
127
 
125
128
  subv=f"(.{subversion})" if int(subversion) else ""
126
129
  infotext=self.ui.info.text().replace('#.#.#',version+subv)
127
- infotext=infotext.replace('yyyy',year)
130
+ infotext=infotext.replace('yyyy','2023-'+year)
128
131
  infotext=infotext.replace('dddd/dd/dd',__date__)
129
132
  mailString=f'<a href="mailto:{mail}"><span style=" text-decoration: underline; color:#0000ff; font-size:11pt">{mail}</a>'
130
133
  infotext=infotext.replace('mmmm',mailString)
@@ -317,7 +320,7 @@ class gPaIRS(QMainWindow):
317
320
  self.FlagGeometryInit=False
318
321
  #self.setFontPixelSize()
319
322
  super().resizeEvent(event)
320
- #self.updateGPAparGeom()
323
+ #self.updateGPAparGeometry()
321
324
 
322
325
  def showEvent(self, event):
323
326
  super().showEvent(event)
@@ -413,6 +416,7 @@ class gPaIRS(QMainWindow):
413
416
  self.cfgname=lastcfgname
414
417
  self.FlagHappyLogo=False
415
418
  self.setupLogo()
419
+ self.startHappyLogoWatcher()
416
420
 
417
421
  self.GPApar_old=GPApar()
418
422
  self.GPApar=GPApar()
@@ -461,7 +465,7 @@ class gPaIRS(QMainWindow):
461
465
  #window.showMaximized()
462
466
  #self.maximumGeometry=window.geometry()
463
467
  #window.close()
464
- self.maximumGeometry=self.app.primaryScreen().geometry()
468
+ self.maximumGeometry=self.app.primaryScreen().availableGeometry()
465
469
 
466
470
  self.minW=self.minimumWidth()
467
471
  self.maxW=self.maximumGeometry.width()
@@ -556,6 +560,7 @@ class gPaIRS(QMainWindow):
556
560
  #self.defineFloatings()
557
561
  self.FloatingTabs=[]
558
562
  self.FloatingWindows=[]
563
+ self.FloatingWidget=FloatingWidget
559
564
 
560
565
  self.menuDebug=None
561
566
  self.completingTask=None
@@ -573,17 +578,17 @@ class gPaIRS(QMainWindow):
573
578
 
574
579
  self.ui.workspace_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
575
580
  self.ui.workspace_icon.pressed.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet("border: none; background: #dcdcdc;"))
576
- self.ui.workspace_icon.released.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet("border: none; background: none;"))
581
+ self.ui.workspace_icon.released.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet(btn.default_stylesheet))
577
582
  pixmap_workspace=QPixmap(icons_path+'workspace.png')
578
583
  self.ui.workspace_icon.clicked.connect(lambda: self.warningDialog(self.GPApar.InfoMessage(),pixmap=pixmap_workspace,title='Workspace information'))
579
584
 
580
585
  self.currITEpar=self.TREpar
581
586
  self.ui.title_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
582
587
  self.ui.title_icon.pressed.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet("border: none; background: #dcdcdc;"))
583
- self.ui.title_icon.released.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet("border: none; background: none;"))
588
+ self.ui.title_icon.released.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet(btn.default_stylesheet))
584
589
  pixmap_workspace=QPixmap(icons_path+'workspace.png')
585
590
  self.ui.title_icon.clicked.connect(lambda: self.warningDialog(self.currITEpar.InfoMessage(),pixmap=TreeIcons.pixmaps[self.currITEpar.icon],title=f"{self.currITEpar.basename} information"))
586
-
591
+
587
592
  class RCLbar:
588
593
  buttons={0: self.ui.button_reset_step,
589
594
  1: self.ui.button_step_inherit,
@@ -605,6 +610,7 @@ class gPaIRS(QMainWindow):
605
610
 
606
611
  #------------------------------------- Debug
607
612
  self.addDebugMenu()
613
+ self.setMenuStyle()
608
614
  self.menuDebug.setFont(self.ui.menuFile.font())
609
615
  self.menuDebug.menuAction().setVisible(Flag_DEBUG)
610
616
  self.userDebugShortcut = QShortcut(QKeySequence('Shift+Alt+D'), self)
@@ -720,6 +726,7 @@ class gPaIRS(QMainWindow):
720
726
  self.ui.tabAreaWidget.setupTabArea(self.tabWidgets,icons)
721
727
  self.ui.tabAreaWidget.gui=self
722
728
  self.tabWidgets=self.tabWidgets+[self.ui.tabAreaWidget]
729
+ self.ui.tabAreaWidget.setVisible=lambda visible: self.tabAreaWidgetSetVisible(visible)
723
730
  self.tabNames=[tab.TABname for tab in self.tabWidgets]
724
731
 
725
732
  self.w_Input.ui.imTreeWidget.disableTab=self.disableTab_ImTree
@@ -853,7 +860,7 @@ class gPaIRS(QMainWindow):
853
860
  self.ui.Explorer.inheritance=self.inheritance
854
861
 
855
862
  self.brush_icon=QIcon(icons_path+"brush_cursor.png")
856
- self.w_Vis.ui.icon.addfuncclick['copy_VIS']=lambda: self.copy_link_action(self.w_Vis.ui.name_tab,lambda isl,ima: self.copy_VIS(isl,ima),menuTitle='Copy graphical settings from...',icon=self.brush_icon)
863
+ self.w_Vis.ui.icon.addfuncclick['copy_VIS']=lambda: self.copy_link_action(self.w_Vis.ui.name_tab,lambda isl,ima: self.copy_VIS(isl,ima),menuTitle='Copy graphical settings from...',message='No other process of the same type is available!',icon=self.brush_icon)
857
864
  self.w_Vis.ui.icon.setCustomCursor()
858
865
 
859
866
  self.defineTABbridges()
@@ -875,6 +882,15 @@ class gPaIRS(QMainWindow):
875
882
  ind[-1]=-1
876
883
  self.setTABpars_at(ind)
877
884
 
885
+ def setMenuStyle(self):
886
+ menu_style = gPaIRS_QMenu_style
887
+ self.ui.menu.setStyleSheet(menu_style)
888
+ self.ui.menuFile.setStyleSheet(menu_style)
889
+ self.ui.menuWindow.setStyleSheet(menu_style)
890
+ self.ui.menuHelp.setStyleSheet(menu_style)
891
+ self.menuDebug.setStyleSheet(menu_style)
892
+ self.ui.menubar.setStyleSheet(menu_style.replace("QMenu","QMenuBar").replace("none","white"))
893
+
878
894
  def defineMenuActions(self):
879
895
  self.projectTree.button_open_action=self.open_project
880
896
  self.projectTree.button_save_action=self.save_project
@@ -896,6 +912,12 @@ class gPaIRS(QMainWindow):
896
912
  a.triggered.connect(getattr(self,'menu_'+aName+'_action'))
897
913
  self.ui.aExit.triggered.connect(lambda: self.close())
898
914
 
915
+ self.ui.actionDefault_sizes.triggered.connect(self.setDefaultSizes)
916
+ self.ui.actionSmall_sizes.triggered.connect(lambda: self.setFullScreenSizes(0.5))
917
+ self.ui.actionFull_screen_sizes.triggered.connect(lambda: self.setFullScreenSizes(1))
918
+ self.ui.actionFloating_Vis_layout.triggered.connect(self.arrangeMainAndTabs)
919
+ self.ui.actionDock_all.triggered.connect(self.dockAll)
920
+
899
921
  self.showChanges=lambda: changes(self,Log_Tab,fileChanges)
900
922
  self.ui.actionChanges.triggered.connect(self.showChanges)
901
923
  self.ui.actionGuide.triggered.connect(self.guide)
@@ -975,6 +997,7 @@ class gPaIRS(QMainWindow):
975
997
  d=0
976
998
 
977
999
  menu=QMenu(b)
1000
+ menu.setStyleSheet(gPaIRS_QMenu_style)
978
1001
  act=[]
979
1002
  nur=len(krange)
980
1003
  flag=nur==Num_Prevs_back_forw
@@ -1034,7 +1057,7 @@ class gPaIRS(QMainWindow):
1034
1057
  ITE:ITEpar=self.ui.Explorer.ITEfromInd(ind)
1035
1058
  ITE.ind[-1]=ind_new[-1]
1036
1059
  self.ui.Explorer.ITEpar.ind[-1]=ind_new[-1]
1037
- ITEs:ITEpar=self.ui.Explorer.ITEsfromInd(ind)
1060
+ ITEs:ITEpar=self.ui.Explorer.ITEsfromInd(ind_new)
1038
1061
  ITEs[0].modifiedDate=currentTimeString()
1039
1062
  ITEs[0].date=f'Modified: {ITE.modifiedDate}'
1040
1063
 
@@ -1051,9 +1074,15 @@ class gPaIRS(QMainWindow):
1051
1074
  self.TREpar.copyfrom(TRE)
1052
1075
  self.adjustItemWidgets(ind)
1053
1076
 
1054
- self.inheritance(ind)
1055
- self.IOVinheritance(ind)
1077
+ self.inheritance(ind_new)
1078
+ self.IOVinheritance(ind_new)
1056
1079
  self.adjustDependencies(ITE)
1080
+
1081
+ for w in self.tabWidgets[:-1]:
1082
+ w:gPaIRS_Tab
1083
+ w.adjustFromTABparInd(ind_new)
1084
+ w.setTABWarnLabel()
1085
+ self.w_Log.setLogText()
1057
1086
  #self.checkFutureProc()
1058
1087
  tab.add_TABpar_bridge=add_TABpar_bridge
1059
1088
 
@@ -1109,17 +1138,30 @@ class gPaIRS(QMainWindow):
1109
1138
  focusWidget.setFocus()
1110
1139
  tab.setTABpar_bridge=setTABpar_bridge
1111
1140
 
1112
- def logBridge(self):
1113
- LOG:LOGpar = self.w_Log.TABpar
1114
- ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1141
+ def logBridge(self,ind=None):
1142
+ if ind is None:
1143
+ OUT:OUTpar = self.w_Output.TABpar
1144
+ LOG:LOGpar = self.w_Log.TABpar
1145
+ VIS:VISpar = self.w_Vis.TABpar
1146
+ ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1147
+ else:
1148
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1149
+ LOG:LOGpar = self.w_Log.TABpar_at(ind)
1150
+ VIS:VISpar = self.w_Vis.TABpar_at(ind)
1151
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1152
+
1153
+ if LOG is None or LOG.FlagNone: return
1115
1154
 
1116
1155
  if ITE.flagRun==0:
1117
1156
  warningMessages=[]
1118
1157
  errorMessages=[]
1119
1158
  for w in self.tabWidgets[:-1]:
1120
1159
  w:gPaIRS_Tab
1121
- par:TABpar= w.TABpar
1122
- if w!=self.w_Log and not par.FlagNone:
1160
+ if ind is None:
1161
+ par:TABpar= w.TABpar
1162
+ else:
1163
+ par:TABpar= w.TABpar_at(ind)
1164
+ if w!=self.w_Log and par is not None and not par.FlagNone:
1123
1165
  if par.OptionDone==0: errorMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1124
1166
  elif par.OptionDone!=1: warningMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1125
1167
 
@@ -1131,6 +1173,23 @@ class gPaIRS(QMainWindow):
1131
1173
  if errorText:
1132
1174
  errorText='\n\n'+ITE.procdata.headerSection('CRITICAL ISSUES',errorText,'X')
1133
1175
  LOG.text=PaIRS_Header+ITE.procdata.itemname+warnigText+errorText
1176
+ if VIS.FlagView:
1177
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1178
+ logfile=ITE.procdata.procOutName()+'.log'
1179
+ if ITE.procdata.outPathRoot=='': logfile=outPathRoot+logfile
1180
+ border='o' #·●⦁᛫
1181
+ headerWidth=54
1182
+ result_text = '\n\n\n\n\n'+ITE.procdata.eyeHeaderSection('EXISTING PROCESS LOG',width=headerWidth,border=border) +f"\nLog file: '{os.path.basename(logfile)}'\n\n"
1183
+ if os.path.isfile(logfile):
1184
+ try:
1185
+ with open(logfile, 'r', encoding='utf-8') as f:
1186
+ log_content = f.read()
1187
+ result_text += "\n" + log_content
1188
+ except Exception as e:
1189
+ result_text += f"\nError reading log file '{os.path.basename(logfile)}:'\n{e}"
1190
+ else:
1191
+ result_text += f"\nLog file '{os.path.basename(logfile)}' not found!"
1192
+ LOG.text+=result_text+'\n\n'+ITE.procdata.headerSection('END of EXISTING PROCESS LOG',' ',border,headerWidth)
1134
1193
  else:
1135
1194
  LOG.text=ITE.procdata.Log
1136
1195
 
@@ -1771,9 +1830,13 @@ class gPaIRS(QMainWindow):
1771
1830
  stepList=self.linkableSteps(FlagExcludeLinked=FlagExcludeLinked)
1772
1831
  ITE=self.ui.Explorer.ITEpar
1773
1832
  if len(stepList)==0:
1774
- showTip(self,message)
1833
+ show_mouse_tooltip(self,message)
1775
1834
  return None
1835
+
1836
+ style=button.styleSheet()
1837
+ button.setStyleSheet("")
1776
1838
  menu = QMenu(self)
1839
+ menu.setStyleSheet(gPaIRS_QMenu_style)
1777
1840
  title_action = QAction(menuTitle, self)
1778
1841
  if icon: title_action.setIcon(icon)
1779
1842
  title_action.setDisabled(True) # Disabilita l'azione per evitare l'interazione
@@ -1784,7 +1847,9 @@ class gPaIRS(QMainWindow):
1784
1847
  nameItem=' '+key
1785
1848
  action:QAction = menu.addAction(TreeIcons.icons[item['icon']], nameItem)
1786
1849
  action.triggered.connect(lambda _, name=key: fun(ITE.ind,stepList[name]['ind']))
1787
- return menu.exec(QCursor.pos()) #menu.exec(button.mapToGlobal(button.rect().bottomLeft()))
1850
+ menu.exec(QCursor.pos()) #menu.exec(button.mapToGlobal(button.rect().bottomLeft()))
1851
+ button.setStyleSheet(style)
1852
+ return
1788
1853
 
1789
1854
  def button_step_inherit_action(self):
1790
1855
  self.copy_link_action(self.ui.button_step_inherit,lambda isl,ima: self.IOVcopy(isl,ima),menuTitle='Copy input/output data from...', message='No process step available!', stepListType=1)
@@ -2341,7 +2406,8 @@ class gPaIRS(QMainWindow):
2341
2406
  for f,v in zip(fields,Var):
2342
2407
  result[f]=v
2343
2408
  result=self.w_Vis.calcMagnitude(result)
2344
- result=self.w_Vis.calcZVorticity(result)
2409
+ FlagUnit=VIS_ind.Out.xres!=1.0 or VIS_ind.Out.pixAR!=1.0
2410
+ result=self.w_Vis.calcZVorticity(result,FlagUnit)
2345
2411
  self.w_Vis.result_Current=result
2346
2412
  else:
2347
2413
  VIS_ind.result_file_Current=''
@@ -2637,8 +2703,8 @@ class gPaIRS(QMainWindow):
2637
2703
  self.saveCal('_Mod')
2638
2704
  if self.w_Vis_CalVi.calibView.calib.FlagCalibration:
2639
2705
  self.appendCalibration()
2640
- #indTree,indItem,ind=self.w_Import.INPpar.indexes()
2641
- #self.actualBridge('Import',indTree,indItem,ind)
2706
+ #indTree,indItem,ind=self.w_Input_CalVi.INPpar.indexes()
2707
+ #self.actualBridge('Input_CalVi',indTree,indItem,ind)
2642
2708
  self.initDataAndSetImgFromGui(self.w_Input_CalVi.INPpar,self.w_Process_CalVi.PROpar)
2643
2709
  self.w_Vis_CalVi.stopCalVi()
2644
2710
 
@@ -2931,6 +2997,7 @@ class gPaIRS(QMainWindow):
2931
2997
  TABpar_ind.FlagInit=True
2932
2998
  else:
2933
2999
  TABpar_ind.FlagInit=False
3000
+ self.logBridge(indITE)
2934
3001
  return FlagCheck
2935
3002
 
2936
3003
  #*************************************************** Projects
@@ -3068,7 +3135,7 @@ class gPaIRS(QMainWindow):
3068
3135
 
3069
3136
  #*************************************************** Sizes, font & layout
3070
3137
  def updateGPAparGeometry(self):
3071
- self.GPApar.Geometry=self.saveGeometry().toBase64().data().decode()
3138
+ self.GPApar.Geometry=save_frame_geometry_to_param(self) #self.saveGeometry().toBase64().data().decode()
3072
3139
  self.GPApar.WindowState=self.saveState().toBase64().data().decode()
3073
3140
  #g=self.geometry()
3074
3141
  #self.GPApar.Geometry=[g.x(), g.y(), g.width(), g.height()]
@@ -3085,8 +3152,18 @@ class gPaIRS(QMainWindow):
3085
3152
  pri.Coding.blue(f'scrollArea: {a.objectName()}')
3086
3153
  scrollAreaValues[a.objectName()]=[a.horizontalScrollBar().value(),a.verticalScrollBar().value()]
3087
3154
  self.GPApar.ScrollAreaValues=scrollAreaValues
3155
+ for w in self.tabWidgets[:-1]:
3156
+ w:Vis_Tab
3157
+ self.GPApar.globalVals[w.TABname]=w.syncPrevGlobalFields(FlagSync=False)
3158
+ if hasattr(w,'tabWin'):
3159
+ if not w.TABname in self.GPApar.tabWinPar: self.GPApar.tabWinPar[w.TABname]={}
3160
+ self.GPApar.tabWinPar[w.TABname]['active']=w.tabWin is not None
3161
+ if self.GPApar.tabWinPar[w.TABname]['active']:
3162
+ self.GPApar.tabWinPar[w.TABname]['geometry']=save_frame_geometry_to_param(w.tabWin)
3163
+ self.GPApar.tabWinPar[w.TABname]['windowState']=w.tabWin.saveState().toBase64().data().decode()
3164
+ self.GPApar.tabWinPar[w.TABname]['visible']=w.tabWin.isVisible()
3088
3165
  return
3089
-
3166
+
3090
3167
  def setFontPixelSize(self):
3091
3168
  if self.fontPixelSize==self.GPApar.fontPixelSize: return
3092
3169
  fPixSize=self.GPApar.fontPixelSize
@@ -3166,13 +3243,134 @@ class gPaIRS(QMainWindow):
3166
3243
  self.resize(w,h)
3167
3244
  self.ui.main_splitter.setSizes(main_splitter_sizes)
3168
3245
  self.updateGeometry()
3169
- x=(self.maximumGeometry.width()-w)*0.5
3170
- y=(self.maximumGeometry.height()-h)*0.5
3171
3246
  if self.falseShow(): self.hide()
3172
- self.move(x,y)
3247
+ self.moveWindowToCenter()
3248
+ self.dockAll()
3249
+
3250
+ def setFullScreenSizes(self, fac=1.0):
3251
+ screen_geom = self.maximumGeometry
3252
+
3253
+ frame = self.frameGeometry()
3254
+ dw = frame.width() - self.width()
3255
+ dh = frame.height() - self.height()
3256
+
3257
+ target_fw = int(screen_geom.width() * fac)
3258
+ target_fh = int(screen_geom.height() * fac)
3259
+ cw = max(100, target_fw - dw)
3260
+ ch = max(100, target_fh - dh)
3261
+
3262
+ self.resize(cw, ch)
3263
+ self.moveWindowToCenter()
3173
3264
  self.app.processEvents()
3174
3265
  self.updateGPAparGeometry()
3175
-
3266
+
3267
+ def moveWindowToCenter(self):
3268
+ screen_geom = self.maximumGeometry
3269
+ frame = self.frameGeometry()
3270
+ frame.moveCenter(screen_geom.center())
3271
+ self.move(frame.topLeft())
3272
+
3273
+ def arrangeMainAndTabs(self):
3274
+ """
3275
+ Arrange the main window and extracted tab windows across the screen.
3276
+
3277
+ - The main window is aligned to the left, using half the screen width.
3278
+ - All tab widgets are ensured to be in extracted windows.
3279
+ - Extracted tab windows are placed on the right side of the screen.
3280
+ """
3281
+ def fit_window_frame_to_rect(win, target_rect: QRect):
3282
+ """
3283
+ Resize/move 'win' so that its *frameGeometry* matches target_rect,
3284
+ compensating for window frame and title bar.
3285
+ """
3286
+ # misura delta frame-client (cornice+title bar)
3287
+ frame = win.frameGeometry()
3288
+ dw = frame.width() - win.width()
3289
+ dh = frame.height() - win.height()
3290
+
3291
+ # vogliamo frame = target_rect -> client = target - delta
3292
+ cw = max(100, target_rect.width() - dw)
3293
+ ch = max(100, target_rect.height() - dh)
3294
+
3295
+ win.resize(cw, ch)
3296
+ frame = win.frameGeometry()
3297
+ frame.moveTopLeft(target_rect.topLeft())
3298
+ win.move(frame.topLeft())
3299
+
3300
+ screen_geom = self.maximumGeometry # assumed QRect
3301
+ # --- Set main window on the left half ---
3302
+ half_w = screen_geom.width() // 2
3303
+ h = screen_geom.height()
3304
+ left_rect = QRect(
3305
+ screen_geom.left(),
3306
+ screen_geom.top(),
3307
+ min(self.minimumWidth(), half_w),
3308
+ h
3309
+ )
3310
+ fit_window_frame_to_rect(self,left_rect)
3311
+
3312
+ # --- Compute right-side rects, starting exactly after the main frame ---
3313
+ left_frame = self.frameGeometry()
3314
+ right_x = left_frame.right() + 1
3315
+
3316
+ right_rect = QRect(
3317
+ right_x,
3318
+ screen_geom.top(),
3319
+ screen_geom.right() - right_x + 1,
3320
+ h
3321
+ )
3322
+
3323
+ wC = screen_geom.width() // 3
3324
+ right_rect_CalVi = QRect(
3325
+ screen_geom.left() + wC,
3326
+ screen_geom.top(),
3327
+ screen_geom.right() - (screen_geom.left() + wC) + 1,
3328
+ h
3329
+ )
3330
+
3331
+ # --- Handle tab windows ---
3332
+ tabs = self.tabWidgets[:-1]
3333
+ for i, w in enumerate(tabs):
3334
+ w: Vis_Tab
3335
+
3336
+ if not hasattr(w, 'tabWin'):
3337
+ continue
3338
+
3339
+ if w.tabWin is None:
3340
+ w.undockfig()
3341
+
3342
+ if w.tabWin is None:
3343
+ continue
3344
+
3345
+ rectw = right_rect_CalVi if w.TABname == 'Vis_CalVi' else right_rect
3346
+
3347
+ # imposta geometria tenendo conto della cornice del tabWin
3348
+ fit_window_frame_to_rect(w.tabWin, rectw)
3349
+
3350
+ # ripristina visibilità coerente con lo stato dell'interfaccia
3351
+ visible = (
3352
+ self.ui.tabAreaWidget.SPLpar.FlagVisible[i]
3353
+ and self.ui.tabAreaWidget.isVisible()
3354
+ and self.isVisible()
3355
+ )
3356
+ w.tabWin.setVisible(visible)
3357
+
3358
+ self.app.processEvents()
3359
+ self.updateGPAparGeometry()
3360
+
3361
+ def dockAll(self):
3362
+ tabs = self.tabWidgets[:-1]
3363
+ for i, w in enumerate(tabs):
3364
+ w:Vis_Tab
3365
+ # ensure extracted window exists
3366
+ if not hasattr(w,'tabWin'): continue
3367
+ if w.tabWin is not None:
3368
+ w.tabWin.close()
3369
+ self.GPApar.tabWinPar[w.TABname].pop('geometry')
3370
+ self.GPApar.tabWinPar[w.TABname].pop('windowState')
3371
+ self.app.processEvents()
3372
+ self.updateGPAparGeometry()
3373
+
3176
3374
  def setGPaIRSTitle(self):
3177
3375
  cfgString=f': {self.GPApar.outName}' if self.GPApar.outName and self.GPApar.outName!=lastcfgname else ''
3178
3376
  if not self.GPApar.FlagSaved: cfgString+='*'
@@ -3183,14 +3381,35 @@ class gPaIRS(QMainWindow):
3183
3381
  windowTitle+=cfgString
3184
3382
  self.setWindowTitle(windowTitle)
3185
3383
 
3384
+ def tabAreaWidgetSetVisible(self,visible):
3385
+ for i, w in enumerate(self.tabWidgets[:-1]):
3386
+ w:Vis_Tab
3387
+ if not hasattr(w,'tabWin'): continue
3388
+ if w.tabWin is None: continue
3389
+ w.tabWin.setVisible(self.ui.tabAreaWidget.SPLpar.FlagVisible[i] and visible and self.isVisible())
3390
+ return type(self.ui.tabAreaWidget).setVisible(self.ui.tabAreaWidget,visible)
3391
+
3392
+ def setVisible(self, visible):
3393
+ for i, w in enumerate(self.tabWidgets[:-1]):
3394
+ w:Vis_Tab
3395
+ if not hasattr(w,'tabWin'): continue
3396
+ if w.tabWin is None: continue
3397
+ w.tabWin.setVisible(self.ui.tabAreaWidget.SPLpar.FlagVisible[i] and self.ui.tabAreaWidget.isVisible() and visible)
3398
+ return super().setVisible(visible)
3399
+
3186
3400
  #*************************************************** Menus
3187
3401
  #********************* File
3188
3402
  def setGPAlayout(self):
3189
3403
  self.setFontPixelSize()
3190
3404
  self.setGPaIRSPalette()
3191
-
3192
- geometry=QByteArray.fromBase64(self.GPApar.Geometry.encode())
3193
- self.restoreGeometry(geometry)
3405
+
3406
+ windowState = QByteArray.fromBase64(self.GPApar.WindowState.encode())
3407
+ self.restoreState(windowState)
3408
+
3409
+ #geometry=QByteArray.fromBase64(self.GPApar.Geometry.encode())
3410
+ #self.restoreGeometry(geometry)
3411
+ restore_frame_geometry_from_param(self, self.GPApar.Geometry)
3412
+
3194
3413
  #if isinstance(self.GPApar.Geometry,list) and len(self.GPApar.Geometry)==4:
3195
3414
  # g=self.GPApar.Geometry
3196
3415
  # try:
@@ -3201,14 +3420,6 @@ class gPaIRS(QMainWindow):
3201
3420
  #else:
3202
3421
  # self.setDefaultSizes()
3203
3422
 
3204
- windowState = QByteArray.fromBase64(self.GPApar.WindowState.encode())
3205
- self.restoreState(windowState)
3206
- #try:
3207
- # s=self.GPApar.WindowState
3208
- # self.setWindowState(Qt.WindowState(s[0]))
3209
- #except:
3210
- # pri.Info.yellow(f'Error while restoring window state:\n{traceback.format_exc()}\n\nDefault window state will be set!\n\n')
3211
-
3212
3423
  for s in self.ui.Explorer.findChildren(QSplitter)+[self.ui.main_splitter,self.ui.Operating_Tabs_splitter]:
3213
3424
  s:QSplitter
3214
3425
  if s.objectName() in self.GPApar.SplitterSizes:
@@ -3220,6 +3431,21 @@ class gPaIRS(QMainWindow):
3220
3431
  a.horizontalScrollBar().setValue(scrollAreaValues[0])
3221
3432
  a.verticalScrollBar().setValue(scrollAreaValues[1])
3222
3433
  self.setNumCores()
3434
+ for w in self.tabWidgets[:-1]:
3435
+ w:gPaIRS_Tab
3436
+ if w.TABname in self.GPApar.globalVals:
3437
+ exceptions=self.GPApar.globalExceptions[w.TABname] if w.TABname in self.GPApar.globalExceptions else []
3438
+ w.syncPrevGlobalFields(ref_vals=self.GPApar.globalVals[w.TABname],exceptions=exceptions)
3439
+ w.TABpar_old.copyfrom(w.TABpar_at(self.GPApar.ind))
3440
+
3441
+ if hasattr(w,'tabWin') and w.TABname in self.GPApar.tabWinPar and self.GPApar.tabWinPar[w.TABname]['active']:
3442
+ d=self.GPApar.tabWinPar[w.TABname]
3443
+ w:Vis_Tab
3444
+ w.undockfig()
3445
+ windowState = QByteArray.fromBase64(d['windowState'].encode())
3446
+ w.tabWin.restoreState(windowState)
3447
+ restore_frame_geometry_from_param(w.tabWin,d['geometry'])
3448
+ w.tabWin.setVisible(d['visible'] and self.ui.tabAreaWidget.isVisible() and self.isVisible())
3223
3449
 
3224
3450
  def setNumCores(self):
3225
3451
  if self.GPApar.NumCores >NUMTHREADS_MAX:
@@ -3582,12 +3808,6 @@ class gPaIRS(QMainWindow):
3582
3808
  if Flag_fullDEBUG:
3583
3809
  self.menuDebug.addSeparator()
3584
3810
 
3585
- self.ui.aDefSizes = self.menuDebug.addAction("Set default sizes")
3586
- self.ui.aDefSizes.triggered.connect(self.setDefaultSizes)
3587
-
3588
- self.ui.aUndock = self.menuDebug.addAction("Undock a widget")
3589
- self.ui.aUndock.triggered.connect(self.extractWidget)
3590
-
3591
3811
  self.ui.aLogo = self.menuDebug.addAction("Change PaIRS logo")
3592
3812
  self.ui.aLogo.triggered.connect(self.happyLogo)
3593
3813
 
@@ -3683,6 +3903,8 @@ class gPaIRS(QMainWindow):
3683
3903
  ['11/07/1987', 'Happy birthday to Carlo! 🎈🎂🍾'],
3684
3904
  ['19/09/1963', 'Happy birthday to Gennaro! 🎈🎂🍾'],
3685
3905
  ['27/11/1940', 'Happy birthday to prof. Carlomagno! 🎈🎂🍾'],
3906
+ ['01/12/1969', 'Happy birthday to Giuseppe S.! 🎈🎂🍾'],
3907
+ ['28/02/1981', 'Happy birthday to Rosaria! 🎈🎂🍾'],
3686
3908
  ['18/10/1985', 'Happy birthday to Stefano! 🎈🎂🍾'],
3687
3909
  ['13/08/1985', 'Happy birthday to Andrea! 🎈🎂🍾'],
3688
3910
  ['22/12/1988', 'Happy birthday to Jack! 🎈🎂🍾'],
@@ -3690,6 +3912,13 @@ class gPaIRS(QMainWindow):
3690
3912
  ['03/11/1989', 'Happy birthday to Massimo! 🎈🎂🍾'],
3691
3913
  ['15/06/1991', 'Happy birthday to Mattia! 🎈🎂🍾'],
3692
3914
  ['14/07/1993', 'Happy birthday to Mirko! 🎈🎂🍾'],
3915
+ ['13/03/1997', 'Happy birthday to Giosuè! 🎈🎂🍾'],
3916
+ ['24/09/1998', 'Happy birthday to Piergiorgio! 🎈🎂🍾'],
3917
+ ['15/01/1999', 'Happy birthday to Alessandro! 🎈🎂🍾'],
3918
+ ['20/02/1999', 'Happy birthday to Cristina! 🎈🎂🍾'],
3919
+ ['20/09/2000', 'Happy birthday to Antonio M.! 🎈🎂🍾'],
3920
+ ['21/09/2000', 'Happy birthday to Gabriele! 🎈🎂🍾'],
3921
+ ['16/11/2000', 'Happy birthday to Antonio D.! 🎈🎂🍾'],
3693
3922
  ['01/01', 'Happy New Year! 🎊🧨'],
3694
3923
  ['25/12', 'Merry Christmas! 🎄✨'],
3695
3924
  ['31/10', 'Happy Halloween! 🎃👻'],
@@ -3712,6 +3941,34 @@ class gPaIRS(QMainWindow):
3712
3941
  self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_rect.png"))
3713
3942
  self.ui.lab_happy_days.hide()
3714
3943
 
3944
+ def startHappyLogoWatcher(self):
3945
+ """Re-check date at next midnight and periodically as keep-alive."""
3946
+ # one-shot timer to just-after-midnight (00:01)
3947
+ def _schedule_midnight():
3948
+ now=QDateTime.currentDateTime()
3949
+ next_day = now.date().addDays(1)
3950
+ next_midnight = QDateTime(next_day, QTime(0, 0))
3951
+ msec=now.msecsTo(next_midnight.addSecs(60)) # 00:01
3952
+ if msec<60_000: msec=60_000 # safety minimum
3953
+ self._happy_midnight=QTimer(self)
3954
+ self._happy_midnight.setSingleShot(True)
3955
+ self._happy_midnight.timeout.connect(_on_tick)
3956
+ self._happy_midnight.start(msec)
3957
+
3958
+ def _on_tick():
3959
+ # Re-apply logo state and reschedule
3960
+ self.setupLogo()
3961
+ _schedule_midnight()
3962
+
3963
+ # keep-alive each few hours (handles sleep/wake or clock drift)
3964
+ self._happy_keepalive=QTimer(self)
3965
+ self._happy_keepalive.setInterval(3*60*60*1000) # 3h
3966
+ self._happy_keepalive.timeout.connect(self.setupLogo)
3967
+ self._happy_keepalive.start()
3968
+
3969
+ # initial schedule
3970
+ _schedule_midnight()
3971
+
3715
3972
  def happyLogo(self):
3716
3973
  self.FlagHappyLogo=not self.FlagHappyLogo
3717
3974
  if self.FlagHappyLogo:
@@ -3728,6 +3985,7 @@ class gPaIRS(QMainWindow):
3728
3985
 
3729
3986
  def paletteContextMenuEvent(self, event):
3730
3987
  contextMenu = QMenu(self)
3988
+ contextMenu.setStyleSheet(gPaIRS_QMenu_style)
3731
3989
  act=[]
3732
3990
  for n in self.paletteNames:
3733
3991
  act.append(contextMenu.addAction(f"{n} mode"))
@@ -3739,9 +3997,10 @@ class gPaIRS(QMainWindow):
3739
3997
  if a==userAct:
3740
3998
  self.GPApar.paletteType=k
3741
3999
  self.setGPaIRSPalette()
3742
-
4000
+
3743
4001
  def launchPaIRS(flagDebug=False,flagInputDebug=False):
3744
4002
  print('\n'+PaIRS_Header+'Starting the interface...')
4003
+ #QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True)
3745
4004
  app=PaIRSApp.instance()
3746
4005
  if not app:app = QApplication(sys.argv)
3747
4006
  app.setStyle('Fusion')
@@ -3751,7 +4010,7 @@ def launchPaIRS(flagDebug=False,flagInputDebug=False):
3751
4010
  app.setFont(font)
3752
4011
  app.pyicon=app.windowIcon()
3753
4012
  icon=QIcon()
3754
- icon.addFile(''+ icons_path +'icon_PaIRS.png',QSize(), QIcon.Normal, QIcon.Off)
4013
+ icon.addFile(icons_path+'icon_PaIRS.ico',QSize(), QIcon.Normal, QIcon.Off)
3755
4014
  app.setWindowIcon(icon)
3756
4015
  try:
3757
4016
  if (platform.system() == "Windows"):
@@ -3838,7 +4097,7 @@ def splashAnimation(self:QLabel,logo:QLabel):
3838
4097
  self.anim_group.finished.connect(self.hide)
3839
4098
  self.anim_group.finished.connect(logo.show)
3840
4099
  self.anim_group.start()
3841
-
4100
+
3842
4101
  def quitPaIRS(app:QApplication,flagPrint=True):
3843
4102
  app.setWindowIcon(app.pyicon)
3844
4103
  app.quit()
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file