PaIRS-UniNa 0.2.5__cp313-cp313-win_amd64.whl → 0.2.9__cp313-cp313-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 (42) hide show
  1. PaIRS_UniNa/Calibration_Tab.py +15 -0
  2. PaIRS_UniNa/Changes.txt +54 -2
  3. PaIRS_UniNa/Explorer.py +118 -19
  4. PaIRS_UniNa/FolderLoop.py +196 -6
  5. PaIRS_UniNa/Input_Tab.py +167 -55
  6. PaIRS_UniNa/Input_Tab_CalVi.py +15 -17
  7. PaIRS_UniNa/Input_Tab_tools.py +9 -10
  8. PaIRS_UniNa/Output_Tab.py +2 -4
  9. PaIRS_UniNa/PaIRS_pypacks.py +227 -56
  10. PaIRS_UniNa/Process_Tab.py +2 -2
  11. PaIRS_UniNa/Process_Tab_Disp.py +1 -1
  12. PaIRS_UniNa/SPIVCalHelp.py +155 -0
  13. PaIRS_UniNa/Saving_tools.py +7 -7
  14. PaIRS_UniNa/TabTools.py +7 -4
  15. PaIRS_UniNa/Vis_Tab.py +129 -60
  16. PaIRS_UniNa/Whatsnew.py +15 -3
  17. PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
  18. PaIRS_UniNa/__init__.py +4 -4
  19. PaIRS_UniNa/addwidgets_ps.py +28 -20
  20. PaIRS_UniNa/calibView.py +7 -0
  21. PaIRS_UniNa/gPaIRS.py +179 -34
  22. PaIRS_UniNa/icons/flaticon_PaIRS_download_warning.png +0 -0
  23. PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
  24. PaIRS_UniNa/icons/folder_loop_cleanup_off.png +0 -0
  25. PaIRS_UniNa/icons/information.png +0 -0
  26. PaIRS_UniNa/icons/information2.png +0 -0
  27. PaIRS_UniNa/icons/pencil_bw.png +0 -0
  28. PaIRS_UniNa/icons/scan_path_loop.png +0 -0
  29. PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
  30. PaIRS_UniNa/icons/spiv_setup_no.png +0 -0
  31. PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
  32. PaIRS_UniNa/pivParFor.py +1 -1
  33. PaIRS_UniNa/procTools.py +51 -3
  34. PaIRS_UniNa/rqrdpckgs.txt +6 -5
  35. PaIRS_UniNa/stereoPivParFor.py +1 -1
  36. PaIRS_UniNa/ui_Calibration_Tab.py +90 -57
  37. PaIRS_UniNa/ui_gPairs.py +9 -3
  38. PaIRS_UniNa/whatsnew.txt +4 -4
  39. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.9.dist-info}/METADATA +32 -17
  40. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.9.dist-info}/RECORD +42 -32
  41. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.9.dist-info}/WHEEL +0 -0
  42. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.9.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,7 @@ InitCheck=True #False=Collap closed, True=opened
8
8
  #fonts
9
9
  font_italic=True
10
10
  font_weight=QFont.DemiBold
11
+ backgroundcolor_none=" background-color: none;"
11
12
  backgroundcolor_changing=" background-color: rgb(255,230,230);"
12
13
  color_changing="color: rgb(33,33,255); "+backgroundcolor_changing
13
14
  color_changing_black="color: rgb(0,0,0); "+backgroundcolor_changing
@@ -63,7 +64,7 @@ class MyQLineEdit(QtWidgets.QLineEdit):
63
64
  if hasStyleFlag:
64
65
  if b.styleFlag: continue
65
66
  b.flagS=True
66
- b.initialStyle=b.styleSheet()
67
+ b.initialStyle=b.styleSheet()+" "+backgroundcolor_none
67
68
  b.setEnabled(False)
68
69
  b.disabledStyle=b.styleSheet()
69
70
  b.setEnabled(True)
@@ -97,24 +98,32 @@ class MyQLineEdit(QtWidgets.QLineEdit):
97
98
  super().mouseReleaseEvent(event) #to preserve classical behaviour before adding the below
98
99
  self.setCompleterList()
99
100
 
101
+ def enterEvent(self, event):
102
+ super().enterEvent(event)
103
+ if not self.font()==self.font_changing and not self.hasFocus():
104
+ self.setFont(self.font_changing)
105
+
106
+ def leaveEvent(self, event):
107
+ super().leaveEvent(event)
108
+ if self.font()==self.font_changing and not self.hasFocus():
109
+ self.setFont(self.initialFont)
110
+
100
111
  def focusInEvent(self, event):
101
112
  super().focusInEvent(event)
102
113
  for f in self.addfuncin:
103
114
  self.addfuncin[f]()
104
115
  self.focusInFun()
105
-
116
+
106
117
  def setFocus(self):
107
118
  super().setFocus()
108
119
  self.focusInFun()
109
120
 
110
121
  def focusInFun(self):
111
- #self.setCompleterList()
112
- if not self.font()==self.font_changing:
113
- self.setStyleSheet(setSS(self,self.initialStyle+" "+color_changing))
114
- self.setFont(self.font_changing)
115
- for b in self.bros:
116
- if (not b==self) and b.flagS:
117
- b.setStyleSheet(b.initialStyle+" "+color_changing_black)
122
+ self.setStyleSheet(setSS(self,self.initialStyle+" "+color_changing))
123
+ self.setFont(self.font_changing)
124
+ for b in self.bros:
125
+ if (not b==self) and b.flagS:
126
+ b.setStyleSheet(b.initialStyle+" "+color_changing_black)
118
127
 
119
128
  def focusOutEvent(self, event):
120
129
  super().focusOutEvent(event) #to preserve classical behaviour before adding the below
@@ -127,15 +136,14 @@ class MyQLineEdit(QtWidgets.QLineEdit):
127
136
  self.focusOutFun()
128
137
 
129
138
  def focusOutFun(self):
130
- if self.font()==self.font_changing:
131
- for b in self.bros:
132
- if b.flagS:
133
- if hasattr(b,'default_stylesheet'):
134
- b.setStyleSheet(b.default_stylesheet)
135
- else:
136
- b.setStyleSheet(setSS(b,b.initialStyle))
137
- if b.flagF:
138
- b.setFont(b.initialFont)
139
+ for b in self.bros:
140
+ if b.flagS:
141
+ if hasattr(b,'default_stylesheet'):
142
+ b.setStyleSheet(b.default_stylesheet)
143
+ else:
144
+ b.setStyleSheet(setSS(b,b.initialStyle))
145
+ if b.flagF:
146
+ b.setFont(b.initialFont)
139
147
  #self.addlab.clear()
140
148
 
141
149
  def showCompleter(self):
@@ -188,7 +196,7 @@ class MyQSpin(QtWidgets.QSpinBox):
188
196
  self.bros=[self]+self.addwid
189
197
  for b in self.bros:
190
198
  if b.styleFlag: continue
191
- b.initialStyle=b.styleSheet()
199
+ b.initialStyle=b.styleSheet()+" "+backgroundcolor_none
192
200
  b.initialFont=b.font()
193
201
  b.font_changing=font_changing
194
202
  b.styleFlag=True
@@ -282,7 +290,7 @@ class MyQDoubleSpin(QtWidgets.QDoubleSpinBox):
282
290
  self.bros=[self]+self.addwid
283
291
  for b in self.bros:
284
292
  if self.styleFlag: continue
285
- b.initialStyle=b.styleSheet()
293
+ b.initialStyle=b.styleSheet()+" "+backgroundcolor_none
286
294
  b.initialFont=b.font()
287
295
  b.font_changing=font_changing
288
296
  b.styleFlag=True
PaIRS_UniNa/calibView.py CHANGED
@@ -729,6 +729,13 @@ class CalibView(QLabel):
729
729
  else:
730
730
  calVect.remPointsDo[p]=Off
731
731
  self.calib.cal.removeBulk()
732
+ if self.calib.cal.flagCalibrated:
733
+ self.calib.cal.checkCalibration() #needed because use the main thread and may exit with an exception
734
+ strPriCalib=self.calib.prettyPrintCalib()
735
+ strPriErrCalib=self.calib.prettyPrintErrCalib()
736
+ pri.Process.blue (strPriErrCalib)
737
+
738
+ self.calib.signals.textFromCalib.emit(strPriErrCalib+'\n'+strPriCalib)
732
739
  self.plotPlane(self.calib.plane)
733
740
 
734
741
  @Slot(int)
PaIRS_UniNa/gPaIRS.py CHANGED
@@ -131,8 +131,14 @@ class infoPaIRS(QMainWindow):
131
131
  websiteString=f'<a href="{website}"><span style=" text-decoration: underline; color:#0000ff; font-size:11pt">{website}</a>'
132
132
  infotext=infotext.replace('wwww',websiteString)
133
133
  self.ui.info.setText(infotext)
134
- self.ui.req.setText(self.requirements())
135
-
134
+ if Flag_ISEXE:
135
+ #self.ui.tabWidget.removeTab(3)
136
+ self.ui.tabWidget.setTabText(3,'Packages')
137
+ self.ui.req.setText(self.distPackages())
138
+ else:
139
+ self.ui.tabWidget.setTabText(3,'Requirements')
140
+ self.ui.req.setText(self.requirements())
141
+
136
142
  self.fontPixelSize=gui.GPApar.fontPixelSize
137
143
  self.setFontSizeText()
138
144
 
@@ -158,6 +164,59 @@ class infoPaIRS(QMainWindow):
158
164
  setFontSizeText(self.ui.tom_cv,[fPixSize+1])
159
165
  setFontSizeText(self.ui.list_ref,[fPixSize+1])
160
166
 
167
+ def distPackages(self):
168
+ # Read the contents of the file and split by lines
169
+ with open(rqrdpckgs_filename, 'r') as file:
170
+ lines = file.readlines()
171
+
172
+ # Introductory sentence
173
+ intro_text = """
174
+ <p style="font-size: 12pt; font-weight: normal; text-align: justify;">
175
+ Python packages included in the current executable:
176
+ </p>
177
+ <p>
178
+
179
+ </p>
180
+ """
181
+
182
+ # Start the HTML table with improved styling
183
+ html_table = intro_text + """
184
+ <table border="1" style="width: 100%; align-items: center;">
185
+ <thead>
186
+ <tr>
187
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Package</th>
188
+ <th style="padding: 10px; font-size: 11pt; font-weight: bold;">Version</th>
189
+ </tr>
190
+ </thead>
191
+ <tbody>
192
+ """
193
+
194
+ # Iterate over each line in the file
195
+ for line in lines:
196
+ # Split each line into package name, min vers11pt max version, and other info
197
+ package_info = line.strip().split()
198
+
199
+ # Ensure the line has the expected format
200
+ if len(package_info) >= 3:
201
+ package_name = package_info[0]
202
+ if package_name[0]=='#': continue
203
+ max_version = package_info[2]
204
+
205
+ # Append a row to the HTML table
206
+ html_table += f"""
207
+ <tr>
208
+ <td style="padding: 10px; font-size: 11pt">{package_name}</td>
209
+ <td style="padding: 10px; font-size: 11pt">{max_version}</td>
210
+ </tr>
211
+ """
212
+
213
+ # Close the table tags
214
+ html_table += """
215
+ </tbody>
216
+ </table>
217
+ """
218
+ return html_table
219
+
161
220
  def requirements(self):
162
221
  # Read the contents of the file and split by lines
163
222
  with open(rqrdpckgs_filename, 'r') as file:
@@ -166,7 +225,7 @@ class infoPaIRS(QMainWindow):
166
225
  # Introductory sentence
167
226
  intro_text = """
168
227
  <p style="font-size: 12pt; font-weight: normal; text-align: justify;">
169
- Required packages along with their minimum and maximum supported versions:
228
+ Required Python packages with their minimum and maximum supported versions:
170
229
  </p>
171
230
  <p>
172
231
 
@@ -195,6 +254,7 @@ class infoPaIRS(QMainWindow):
195
254
  # Ensure the line has the expected format
196
255
  if len(package_info) >= 3:
197
256
  package_name = package_info[0]
257
+ if package_name[0]=='#': continue
198
258
  min_version = package_info[1]
199
259
  max_version = package_info[2]
200
260
  curr_version = package_info[3]
@@ -277,7 +337,7 @@ class gPaIRS(QMainWindow):
277
337
  self.save_last_workspace()
278
338
  self.closeAll()
279
339
  if self.GPApar.FlagOutDated:
280
- warningLatestVersion(self,self.app,flagExit=1,flagWarning=abs(self.GPApar.FlagOutDated)==1)
340
+ warningLatestVersion(self,self.app,flagExit=1,flagWarning=self.GPApar.FlagOutDated in (-1,1,-1000))
281
341
  self.close()
282
342
  self.app.processEvents()
283
343
  self.app.SecondaryThreads=self.SecondaryThreads
@@ -353,6 +413,7 @@ class gPaIRS(QMainWindow):
353
413
  self.cfgname=lastcfgname
354
414
  self.FlagHappyLogo=False
355
415
  self.setupLogo()
416
+ self.startHappyLogoWatcher()
356
417
 
357
418
  self.GPApar_old=GPApar()
358
419
  self.GPApar=GPApar()
@@ -414,6 +475,8 @@ class gPaIRS(QMainWindow):
414
475
  #------------------------------------- Graphical interface: miscellanea
415
476
  self.flaticon_PaIRS_download=QIcon()
416
477
  self.flaticon_PaIRS_download.addFile(icons_path+'flaticon_PaIRS_download.png')
478
+ self.flaticon_PaIRS_download_warning=QIcon()
479
+ self.flaticon_PaIRS_download_warning.addFile(icons_path+'flaticon_PaIRS_download_warning.png')
417
480
  self.flaticon_PaIRS_beta=QIcon()
418
481
  self.flaticon_PaIRS_beta.addFile(icons_path+'flaticon_PaIRS_beta.png')
419
482
 
@@ -837,6 +900,10 @@ class gPaIRS(QMainWindow):
837
900
  self.showChanges=lambda: changes(self,Log_Tab,fileChanges)
838
901
  self.ui.actionChanges.triggered.connect(self.showChanges)
839
902
  self.ui.actionGuide.triggered.connect(self.guide)
903
+ self.ui.actionDownload.setVisible(not Flag_ISEXE)
904
+ if not Flag_ISEXE:
905
+ self.ui.menuHelp.insertSeparator(self.ui.actionDownload)
906
+ self.ui.actionDownload.triggered.connect(self.downloadApp)
840
907
  self.ui.actionAbout.triggered.connect(self.about)
841
908
 
842
909
  self.ui.button_PaIRS_download.clicked.connect(lambda: button_download_PaIRS_action(self,self.app))
@@ -875,7 +942,11 @@ class gPaIRS(QMainWindow):
875
942
  for w in self.tabWidgets:
876
943
  if not w.TABpar.FlagNone:
877
944
  w:gPaIRS_Tab
878
- if FlagAdjustPar: w.adjustTABpar()
945
+ if FlagAdjustPar:
946
+ FlagSettingPar=TABpar.FlagSettingPar
947
+ TABpar.FlagSettingPar=True
948
+ w.adjustTABpar()
949
+ TABpar.FlagSettingPar=FlagSettingPar
879
950
  if FlagBridge: self.bridge(w.TABname)
880
951
  FlagAdjustPar=False
881
952
  FlagBridge=False
@@ -993,12 +1064,15 @@ class gPaIRS(QMainWindow):
993
1064
  TABname=tab.TABname
994
1065
  self.bridge(TABname)
995
1066
  if FlagAdjustPar:
1067
+ FlagSettingPar=TABpar.FlagSettingPar
1068
+ TABpar.FlagSettingPar=True
996
1069
  for w in self.tabWidgets:
997
1070
  if w.TABpar.FlagNone: continue
998
1071
  w:gPaIRS_Tab
999
1072
  if w!=tab:
1000
1073
  w.adjustTABpar()
1001
1074
  self.bridge(w.TABname)
1075
+ TABpar.FlagSettingPar=FlagSettingPar
1002
1076
  FlagAdjustPar=False
1003
1077
  FlagBridge=False
1004
1078
  FlagDisplayControls=False
@@ -1037,7 +1111,9 @@ class gPaIRS(QMainWindow):
1037
1111
  tab.setTABpar_bridge=setTABpar_bridge
1038
1112
 
1039
1113
  def logBridge(self):
1114
+ OUT:OUTpar = self.w_Output.TABpar
1040
1115
  LOG:LOGpar = self.w_Log.TABpar
1116
+ VIS:VISpar = self.w_Vis.TABpar
1041
1117
  ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1042
1118
 
1043
1119
  if ITE.flagRun==0:
@@ -1058,6 +1134,23 @@ class gPaIRS(QMainWindow):
1058
1134
  if errorText:
1059
1135
  errorText='\n\n'+ITE.procdata.headerSection('CRITICAL ISSUES',errorText,'X')
1060
1136
  LOG.text=PaIRS_Header+ITE.procdata.itemname+warnigText+errorText
1137
+ if VIS.FlagView:
1138
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1139
+ logfile=ITE.procdata.procOutName()+'.log'
1140
+ if ITE.procdata.outPathRoot=='': logfile=outPathRoot+logfile
1141
+ border='o' #·●⦁᛫
1142
+ headerWidth=54
1143
+ 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"
1144
+ if os.path.isfile(logfile):
1145
+ try:
1146
+ with open(logfile, 'r', encoding='utf-8') as f:
1147
+ log_content = f.read()
1148
+ result_text += "\n" + log_content
1149
+ except Exception as e:
1150
+ result_text += f"\nError reading log file '{os.path.basename(logfile)}:'\n{e}"
1151
+ else:
1152
+ result_text += f"\nLog file '{os.path.basename(logfile)}' not found!"
1153
+ LOG.text+=result_text+'\n\n'+ITE.procdata.headerSection('END of EXISTING PROCESS LOG',' ',border,headerWidth)
1061
1154
  else:
1062
1155
  LOG.text=ITE.procdata.Log
1063
1156
 
@@ -1408,6 +1501,7 @@ class gPaIRS(QMainWindow):
1408
1501
  self.checkProcesses(FlagInit=False,ind=ind_child)
1409
1502
  ITE_ind:ITEpar = self.ui.Explorer.ITEfromInd(ind_child)
1410
1503
  self.ui.Explorer.setITElayout(ITE_ind)
1504
+ self.inheritance(ind_child)
1411
1505
 
1412
1506
  def IOVcopy(self,ind_slave,ind_master):
1413
1507
  ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind_master) #self.ui.Explorer.ITEfromTRE(self.TREpar)
@@ -2267,7 +2361,8 @@ class gPaIRS(QMainWindow):
2267
2361
  for f,v in zip(fields,Var):
2268
2362
  result[f]=v
2269
2363
  result=self.w_Vis.calcMagnitude(result)
2270
- result=self.w_Vis.calcZVorticity(result)
2364
+ FlagUnit=VIS_ind.Out.xres!=1.0 or VIS_ind.Out.pixAR!=1.0
2365
+ result=self.w_Vis.calcZVorticity(result,FlagUnit)
2271
2366
  self.w_Vis.result_Current=result
2272
2367
  else:
2273
2368
  VIS_ind.result_file_Current=''
@@ -2444,7 +2539,8 @@ class gPaIRS(QMainWindow):
2444
2539
  if self.procdata:
2445
2540
  pri.Time.red(f'stopProcs self.contProc={self.contProc}/{self.nProc} self.numCallBackTotOk={self.numCallBackTotOk} numFinalized={self.procdata.numFinalized} {self.FlagRun}')
2446
2541
 
2447
- if self.contProc==self.indProc+1:
2542
+ FlagEnd = self.contProc==self.indProc+1 if self.FlagRun==2 else self.contProc==self.nProc
2543
+ if FlagEnd:
2448
2544
  self.ui.Explorer.updateSwitchMovies(self.currind,FlagStart=False)
2449
2545
  self.setSwitchEnabled(True)
2450
2546
  self.disableDropping(False)
@@ -3102,7 +3198,7 @@ class gPaIRS(QMainWindow):
3102
3198
  cfgString=f': {self.GPApar.outName}' if self.GPApar.outName and self.GPApar.outName!=lastcfgname else ''
3103
3199
  if not self.GPApar.FlagSaved: cfgString+='*'
3104
3200
  if Flag_DEBUG:#TA per non incasinarmi
3105
- windowTitle=f'PaIRS (v{version}.{__subversion__} - {__date__}) -- cfg v{uicfg_version} -- PIV {self.PIVvers} -- {platform.system()}'
3201
+ windowTitle=f'PaIRS (v{version}.{__subversion__} - {__date__}) -- cfg v{uicfg_version} -- PIV {self.PIVvers} -- {platform.system()} -- Python {platform.python_version()}'
3106
3202
  else:
3107
3203
  windowTitle=f'PaIRS (v{version})'
3108
3204
  windowTitle+=cfgString
@@ -3187,7 +3283,7 @@ class gPaIRS(QMainWindow):
3187
3283
  #dir=self.w_Input.INPpar.path,\
3188
3284
  options=optionNativeDialog)
3189
3285
  if not filename: return
3190
- waitingWindow=warningDialog(self,'Please, wait while retrieving previous workspace!\nIf this action takes too much time, please consider to close the workspace before quitting PaIRS next time)',pixmap=''+ icons_path +'sandglass.png',flagNoButtons=True,flagScreenCenter=True)
3286
+ waitingWindow=warningDialog(self,'Please, wait while retrieving previous workspace!\n(If this action takes too much time, please consider to close the workspace before quitting PaIRS next time.)',pixmap=''+ icons_path +'sandglass.png',flagNoButtons=True,flagScreenCenter=True)
3191
3287
  self.app.processEvents()
3192
3288
  errorString=''
3193
3289
  try:
@@ -3302,6 +3398,11 @@ class gPaIRS(QMainWindow):
3302
3398
  url = QUrl("https://www.pairs.unina.it/web/PaIRS-UniNa-v020-Guide.pdf")
3303
3399
  QDesktopServices.openUrl(url)
3304
3400
 
3401
+ def downloadApp(self):
3402
+ #url = QUrl("http://wpage.unina.it/etfd/PaIRS/PaIRS-UniNa-Guide.pdf")
3403
+ url = QUrl(EXEurl)
3404
+ QDesktopServices.openUrl(url)
3405
+
3305
3406
  def about(self):
3306
3407
  if self.aboutDialog:
3307
3408
  self.aboutDialog.hide()
@@ -3475,27 +3576,28 @@ class gPaIRS(QMainWindow):
3475
3576
  self.aCheckConnections=aFocusWid
3476
3577
  self.ui.aFocusWid.triggered.connect(aFocusWid)
3477
3578
 
3478
- self.menuDebug.addSeparator()
3479
- self.ui.aResetRequiredPackagesFile = self.menuDebug.addAction("Reset rqrdpckgs.txt file")
3480
- def aResetRequiredPackagesFile():
3481
- resetRequiredPackagesFile()
3482
- self.ui.aResetRequiredPackagesFile.triggered.connect(aResetRequiredPackagesFile)
3483
-
3484
- self.ui.aCheckRequiredPackages = self.menuDebug.addAction("Requirements' version check")
3485
- def aCheckRequiredPackages():
3486
- checkRequiredPackages(self,FlagDisplay=True)
3487
- self.ui.aCheckRequiredPackages.triggered.connect(aCheckRequiredPackages)
3488
-
3489
- self.ui.aShowPackIssue = self.menuDebug.addAction("Show/hide version check button")
3490
- def aShowPackIssue():
3491
- self.FlagPackIssue=not self.FlagPackIssue
3492
- self.ui.button_packissue.setVisible(self.FlagPackIssue)
3493
- self.ui.aShowPackIssue.triggered.connect(aShowPackIssue)
3494
-
3495
- self.ui.aTryCheckRequiredPackages = self.menuDebug.addAction("Try requirements' version check")
3496
- def aTryCheckRequiredPackages():
3497
- checkRequiredPackages(self,FlagDisplay=True,FlagForcePrint=True)
3498
- self.ui.aTryCheckRequiredPackages.triggered.connect(aTryCheckRequiredPackages)
3579
+ if not Flag_ISEXE:
3580
+ self.menuDebug.addSeparator()
3581
+ self.ui.aResetRequiredPackagesFile = self.menuDebug.addAction("Reset rqrdpckgs.txt file")
3582
+ def aResetRequiredPackagesFile():
3583
+ resetRequiredPackagesFile()
3584
+ self.ui.aResetRequiredPackagesFile.triggered.connect(aResetRequiredPackagesFile)
3585
+
3586
+ self.ui.aCheckRequiredPackages = self.menuDebug.addAction("Requirements' version check")
3587
+ def aCheckRequiredPackages():
3588
+ checkRequiredPackages(self,FlagDisplay=True)
3589
+ self.ui.aCheckRequiredPackages.triggered.connect(aCheckRequiredPackages)
3590
+
3591
+ self.ui.aShowPackIssue = self.menuDebug.addAction("Show/hide version check button")
3592
+ def aShowPackIssue():
3593
+ self.FlagPackIssue=not self.FlagPackIssue
3594
+ self.ui.button_packissue.setVisible(self.FlagPackIssue)
3595
+ self.ui.aShowPackIssue.triggered.connect(aShowPackIssue)
3596
+
3597
+ self.ui.aTryCheckRequiredPackages = self.menuDebug.addAction("Try requirements' version check")
3598
+ def aTryCheckRequiredPackages():
3599
+ checkRequiredPackages(self,FlagDisplay=True,FlagForcePrint=True)
3600
+ self.ui.aTryCheckRequiredPackages.triggered.connect(aTryCheckRequiredPackages)
3499
3601
 
3500
3602
  #--------------------------- graphics
3501
3603
  if Flag_fullDEBUG:
@@ -3579,10 +3681,13 @@ class gPaIRS(QMainWindow):
3579
3681
  self.menuDebug.menuAction().setVisible(Flag)
3580
3682
 
3581
3683
  def setButtonDownload(self,):
3582
- self.ui.button_PaIRS_download.setVisible(self.GPApar.FlagOutDated not in (0,-1000))
3684
+ self.ui.button_PaIRS_download.setVisible(self.GPApar.FlagOutDated!=0)
3583
3685
  if self.GPApar.FlagOutDated>0:
3584
3686
  self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_download)
3585
- self.ui.button_PaIRS_download.setToolTip("Download the latest version of PaIRS-UniNa")
3687
+ self.ui.button_PaIRS_download.setToolTip("Download the latest version of PaIRS-UniNa.")
3688
+ elif self.GPApar.FlagOutDated==-1000:
3689
+ self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_download_warning)
3690
+ self.ui.button_PaIRS_download.setToolTip("Issue with verifying the latest release!")
3586
3691
  else:
3587
3692
  self.ui.button_PaIRS_download.setIcon(self.flaticon_PaIRS_beta)
3588
3693
  self.ui.button_PaIRS_download.setToolTip("A beta version is currently used!")
@@ -3599,6 +3704,8 @@ class gPaIRS(QMainWindow):
3599
3704
  ['11/07/1987', 'Happy birthday to Carlo! 🎈🎂🍾'],
3600
3705
  ['19/09/1963', 'Happy birthday to Gennaro! 🎈🎂🍾'],
3601
3706
  ['27/11/1940', 'Happy birthday to prof. Carlomagno! 🎈🎂🍾'],
3707
+ ['01/12/1969', 'Happy birthday to Giuseppe S.! 🎈🎂🍾'],
3708
+ ['28/02/1981', 'Happy birthday to Rosaria! 🎈🎂🍾'],
3602
3709
  ['18/10/1985', 'Happy birthday to Stefano! 🎈🎂🍾'],
3603
3710
  ['13/08/1985', 'Happy birthday to Andrea! 🎈🎂🍾'],
3604
3711
  ['22/12/1988', 'Happy birthday to Jack! 🎈🎂🍾'],
@@ -3606,6 +3713,13 @@ class gPaIRS(QMainWindow):
3606
3713
  ['03/11/1989', 'Happy birthday to Massimo! 🎈🎂🍾'],
3607
3714
  ['15/06/1991', 'Happy birthday to Mattia! 🎈🎂🍾'],
3608
3715
  ['14/07/1993', 'Happy birthday to Mirko! 🎈🎂🍾'],
3716
+ ['13/03/1997', 'Happy birthday to Giosuè! 🎈🎂🍾'],
3717
+ ['24/09/1998', 'Happy birthday to Piergiorgio! 🎈🎂🍾'],
3718
+ ['15/01/1999', 'Happy birthday to Alessandro! 🎈🎂🍾'],
3719
+ ['20/02/1999', 'Happy birthday to Cristina! 🎈🎂🍾'],
3720
+ ['20/09/2000', 'Happy birthday to Antonio M.! 🎈🎂🍾'],
3721
+ ['21/09/2000', 'Happy birthday to Gabriele! 🎈🎂🍾'],
3722
+ ['16/11/2000', 'Happy birthday to Antonio D.! 🎈🎂🍾'],
3609
3723
  ['01/01', 'Happy New Year! 🎊🧨'],
3610
3724
  ['25/12', 'Merry Christmas! 🎄✨'],
3611
3725
  ['31/10', 'Happy Halloween! 🎃👻'],
@@ -3628,6 +3742,34 @@ class gPaIRS(QMainWindow):
3628
3742
  self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_rect.png"))
3629
3743
  self.ui.lab_happy_days.hide()
3630
3744
 
3745
+ def startHappyLogoWatcher(self):
3746
+ """Re-check date at next midnight and periodically as keep-alive."""
3747
+ # one-shot timer to just-after-midnight (00:01)
3748
+ def _schedule_midnight():
3749
+ now=QDateTime.currentDateTime()
3750
+ next_day = now.date().addDays(1)
3751
+ next_midnight = QDateTime(next_day, QTime(0, 0))
3752
+ msec=now.msecsTo(next_midnight.addSecs(60)) # 00:01
3753
+ if msec<60_000: msec=60_000 # safety minimum
3754
+ self._happy_midnight=QTimer(self)
3755
+ self._happy_midnight.setSingleShot(True)
3756
+ self._happy_midnight.timeout.connect(_on_tick)
3757
+ self._happy_midnight.start(msec)
3758
+
3759
+ def _on_tick():
3760
+ # Re-apply logo state and reschedule
3761
+ self.setupLogo()
3762
+ _schedule_midnight()
3763
+
3764
+ # keep-alive each few hours (handles sleep/wake or clock drift)
3765
+ self._happy_keepalive=QTimer(self)
3766
+ self._happy_keepalive.setInterval(3*60*60*1000) # 3h
3767
+ self._happy_keepalive.timeout.connect(self.setupLogo)
3768
+ self._happy_keepalive.start()
3769
+
3770
+ # initial schedule
3771
+ _schedule_midnight()
3772
+
3631
3773
  def happyLogo(self):
3632
3774
  self.FlagHappyLogo=not self.FlagHappyLogo
3633
3775
  if self.FlagHappyLogo:
@@ -3724,7 +3866,10 @@ def launchPaIRS(flagDebug=False,flagInputDebug=False):
3724
3866
  splashAnimation(splash,gui.ui.logo)
3725
3867
  #QTimer.singleShot(time_showSplashOnTop,splash.hide)
3726
3868
  print('\nWelcome to PaIRS!\nEnjoy it!')
3727
- checkRequiredPackages(gui)
3869
+ if not getattr(sys, 'frozen', False): #made by pyInstaller
3870
+ checkRequiredPackages(gui)
3871
+ else:
3872
+ gui.FlagPackIssue=False
3728
3873
  gui.ui.button_packissue.setVisible(gui.FlagPackIssue)
3729
3874
  if os.path.exists(fileWhatsNew[0]): gui.whatsNew()
3730
3875
  app.exec()
@@ -3751,7 +3896,7 @@ def splashAnimation(self:QLabel,logo:QLabel):
3751
3896
  self.anim_group.finished.connect(self.hide)
3752
3897
  self.anim_group.finished.connect(logo.show)
3753
3898
  self.anim_group.start()
3754
-
3899
+
3755
3900
  def quitPaIRS(app:QApplication,flagPrint=True):
3756
3901
  app.setWindowIcon(app.pyicon)
3757
3902
  app.quit()
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
PaIRS_UniNa/pivParFor.py CHANGED
@@ -78,7 +78,7 @@ def procPIV(i,procId ,PIV,data:dataTreePar,numUsedProcs,*args,**kwargs):
78
78
  where FLAG_FINALIZED_OR_ERR = [ p|e for (p,e) in zip(FLAG_FINALIZED,FLAG_READ_ERR)]
79
79
  numProcOrErrTot=sum(1 if (f&FLAG_FINALIZED_OR_ERR[0])or(not f&FLAG_PROC[0]) else 0 for f in flagOut)
80
80
  to delete images
81
- pa='C:\desk\dl\apairs\jetcross\'
81
+ pa='C:\\desk\\dl\\apairs\\jetcross\\'
82
82
  no='zR2jet0_0004a'
83
83
  I =imread([pa no '.png']);
84
84
  I=I*0+1;
PaIRS_UniNa/procTools.py CHANGED
@@ -328,7 +328,7 @@ class dataTreePar(TABpar):
328
328
 
329
329
  def setCompleteLog(self):
330
330
  warn1=self.headerSection('WARNINGS',self.warnings[1],'!')
331
- if self.flagRun:
331
+ if self.flagRun not in (0,-10):
332
332
  warn0=''
333
333
  self.createLogProc()
334
334
  LogProc = self.headerSection('OUTPUT',self.procLog[0])
@@ -338,7 +338,10 @@ class dataTreePar(TABpar):
338
338
  if self.warnings[0]: warn0='*Further information:\n'+self.warnings[0]+'\n'
339
339
  self.Log=self.createLogHeader()+procLog+warn0+warn1
340
340
  else:
341
- self.Log=self.createLogHeader()+warn1
341
+ if self.flagRun:
342
+ self.Log=self.createLogHeader()
343
+ else:
344
+ self.Log=self.createLogHeader()+warn1
342
345
 
343
346
  def createWarningLog(self,warning):
344
347
  warn1=self.headerSection('WARNINGS',warning,'!')
@@ -352,9 +355,54 @@ class dataTreePar(TABpar):
352
355
  if len(args)>1: n=args[1]
353
356
  ln=len(nameSection)
354
357
  ns=int((n-ln)/2)
355
- Log=f'{f"{c}"*n}\n{" "*ns}{nameSection}{" "*ns}\n{f"{c}"*n}\n'+Log+'\n'
358
+ header=f'{f"{c}"*n}\n{" "*ns}{nameSection}{" "*ns}\n{f"{c}"*n}\n'
359
+ if Log!=' ': Log=header+Log+'\n'
360
+ else: Log=header
356
361
  return Log
357
362
 
363
+ def eyeHeaderSection(self, text:str, width:int=54, height:int=11, border:str='o', pad:int=0)->str:
364
+ """
365
+ Draw an eye-shaped frame with the given text centered on the middle row.
366
+ Works in monospace consoles or QTextEdit. Uses a smooth parametric eye curve.
367
+ """
368
+ width=max(width, len(text)+2*pad+2)
369
+ height=max(5, height|(1)) # make it odd
370
+ mid=height//2
371
+ # eye boundary: y = a*(1 - |x|^p)^b, mirrored top/bottom
372
+ import math
373
+ p,b=1.6,1.0 # shape controls (p: pointiness, b: roundness)
374
+ ax=width/2-1
375
+ ay=mid-1 # vertical semi-size (controls thickness of eye)
376
+ eps=0.6 # border thickness in "cells"
377
+
378
+ rows=[]
379
+ for r in range(height):
380
+ y=(r-mid)/ay # -1..1
381
+ line=[]
382
+ for c in range(width):
383
+ x=(c- (width-1)/2)/ax # -1..1
384
+ # target boundary (top curve positive y, bottom negative)
385
+ yb = (1 - abs(x)**p)
386
+ yb = (yb if yb>0 else 0)**b # clamp
387
+ # distance to boundary (abs because top/bottom)
388
+ d=abs(abs(y)-yb)
389
+ ch=' '
390
+ if yb<=0 and abs(y)<eps/ay: # very ends -> leave blank
391
+ ch=' '
392
+ elif d*ay<=eps and yb>0: # on border
393
+ ch=border
394
+ line.append(ch)
395
+ rows.append(''.join(line))
396
+
397
+ # write text on middle row
398
+ body=list(rows[mid])
399
+ s=f' {text} '
400
+ start=(width-len(s))//2
401
+ body[start:start+len(s)]=list(s)
402
+ rows[mid]=''.join(body)
403
+
404
+ return '\n'.join(rows)
405
+
358
406
  def createLogProc(self):
359
407
  splitAs='\n '#used to join the strings together tab or spaces may be use to indent the error
360
408
  numImgTot=len(self.list_pim) if self.Step!=StepTypes.min else (2*len(self.list_pim))
PaIRS_UniNa/rqrdpckgs.txt CHANGED
@@ -1,8 +1,9 @@
1
- scipy 1.14.0 1.16.0 0
2
- matplotlib 3.9.0 3.10.3 0
1
+ scipy 1.14.0 1.16.1 0
2
+ matplotlib 3.9.0 3.10.6 0
3
3
  pillow 10.4.0 11.3.0 0
4
- numpy 2.0.0 2.3.1 0
5
- pyside6 6.7.0 6.9.1 0
4
+ numpy 2.0.0 2.3.2 0
5
+ pyside6 6.7.0 6.9.2 0
6
6
  unidecode 1.3.0 1.4.0 0
7
7
  psutil 6.0.0 7.0.0 0
8
- debugpy 1.6.6 1.8.14 0
8
+ debugpy 1.6.6 1.8.16 0
9
+ certifi 2025.7.14 2025.8.3 0
@@ -67,7 +67,7 @@ def procStereoPIV(i,procId ,StereoPIV,data:dataTreePar,numUsedProcs,*args,**kwar
67
67
  where FLAG_FINALIZED_OR_ERR = [ p|e for (p,e) in zip(FLAG_FINALIZED,FLAG_READ_ERR)]
68
68
  numProcOrErrTot=sum(1 if (f&FLAG_FINALIZED_OR_ERR[0])or(not f&FLAG_PROC[0]) else 0 for f in flagOut)
69
69
  to delete images
70
- pa='C:\desk\dl\apairs\jetcross\'
70
+ pa='C:\\desk\\dl\\apairs\\jetcross\\'
71
71
  no='zR2jet0_0004a'
72
72
  I =imread([pa no '.png']);
73
73
  I=I*0+1;