PaIRS-UniNa 0.2.7__cp312-cp312-macosx_11_0_universal2.whl → 0.2.10__cp312-cp312-macosx_11_0_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. PaIRS_UniNa/Calibration_Tab.py +16 -0
  2. PaIRS_UniNa/Changes.txt +39 -0
  3. PaIRS_UniNa/Explorer.py +311 -75
  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 +17 -15
  8. PaIRS_UniNa/Output_Tab.py +1 -3
  9. PaIRS_UniNa/PaIRS_pypacks.py +63 -65
  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 +2 -0
  14. PaIRS_UniNa/TabTools.py +165 -6
  15. PaIRS_UniNa/Vis_Tab.py +50 -22
  16. PaIRS_UniNa/Vis_Tab_CalVi.py +1 -2
  17. PaIRS_UniNa/Whatsnew.py +4 -3
  18. PaIRS_UniNa/_PaIRS_PIV.so +0 -0
  19. PaIRS_UniNa/__init__.py +3 -3
  20. PaIRS_UniNa/addwidgets_ps.py +570 -70
  21. PaIRS_UniNa/gPaIRS.py +118 -17
  22. PaIRS_UniNa/icons/folder_loop_cleanup.png +0 -0
  23. PaIRS_UniNa/icons/folder_loop_cleanup_off.png +0 -0
  24. PaIRS_UniNa/icons/information.png +0 -0
  25. PaIRS_UniNa/icons/information2.png +0 -0
  26. PaIRS_UniNa/icons/scan_path_loop.png +0 -0
  27. PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
  28. PaIRS_UniNa/icons/spiv_setup_no.png +0 -0
  29. PaIRS_UniNa/icons/spiv_setup_ok.png +0 -0
  30. PaIRS_UniNa/procTools.py +46 -1
  31. PaIRS_UniNa/rqrdpckgs.txt +7 -7
  32. PaIRS_UniNa/ui_Calibration_Tab.py +92 -59
  33. PaIRS_UniNa/ui_gPairs.py +8 -8
  34. PaIRS_UniNa/whatsnew.txt +2 -3
  35. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/METADATA +7 -8
  36. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/RECORD +38 -30
  37. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/WHEEL +0 -0
  38. {pairs_unina-0.2.7.dist-info → pairs_unina-0.2.10.dist-info}/top_level.txt +0 -0
PaIRS_UniNa/gPaIRS.py CHANGED
@@ -413,6 +413,7 @@ class gPaIRS(QMainWindow):
413
413
  self.cfgname=lastcfgname
414
414
  self.FlagHappyLogo=False
415
415
  self.setupLogo()
416
+ self.startHappyLogoWatcher()
416
417
 
417
418
  self.GPApar_old=GPApar()
418
419
  self.GPApar=GPApar()
@@ -573,17 +574,19 @@ class gPaIRS(QMainWindow):
573
574
 
574
575
  self.ui.workspace_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
575
576
  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;"))
577
+ self.ui.workspace_icon.released.connect(lambda btn=self.ui.workspace_icon: btn.setStyleSheet(btn.default_stylesheet))
577
578
  pixmap_workspace=QPixmap(icons_path+'workspace.png')
578
579
  self.ui.workspace_icon.clicked.connect(lambda: self.warningDialog(self.GPApar.InfoMessage(),pixmap=pixmap_workspace,title='Workspace information'))
579
580
 
580
581
  self.currITEpar=self.TREpar
581
582
  self.ui.title_icon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
582
583
  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;"))
584
+ self.ui.title_icon.released.connect(lambda btn=self.ui.title_icon: btn.setStyleSheet(btn.default_stylesheet))
584
585
  pixmap_workspace=QPixmap(icons_path+'workspace.png')
585
586
  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
587
 
588
+ setButtonHoverStyle(self.ui.logo,FlagBorder=False,borderRadius=int(self.ui.logo.height()/2))
589
+
587
590
  class RCLbar:
588
591
  buttons={0: self.ui.button_reset_step,
589
592
  1: self.ui.button_step_inherit,
@@ -605,6 +608,7 @@ class gPaIRS(QMainWindow):
605
608
 
606
609
  #------------------------------------- Debug
607
610
  self.addDebugMenu()
611
+ self.setMenuStyle()
608
612
  self.menuDebug.setFont(self.ui.menuFile.font())
609
613
  self.menuDebug.menuAction().setVisible(Flag_DEBUG)
610
614
  self.userDebugShortcut = QShortcut(QKeySequence('Shift+Alt+D'), self)
@@ -853,7 +857,7 @@ class gPaIRS(QMainWindow):
853
857
  self.ui.Explorer.inheritance=self.inheritance
854
858
 
855
859
  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)
860
+ 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
861
  self.w_Vis.ui.icon.setCustomCursor()
858
862
 
859
863
  self.defineTABbridges()
@@ -875,6 +879,14 @@ class gPaIRS(QMainWindow):
875
879
  ind[-1]=-1
876
880
  self.setTABpars_at(ind)
877
881
 
882
+ def setMenuStyle(self):
883
+ menu_style = gPaIRS_QMenu_style
884
+ self.ui.menu.setStyleSheet(menu_style)
885
+ self.ui.menuFile.setStyleSheet(menu_style)
886
+ self.ui.menuHelp.setStyleSheet(menu_style)
887
+ self.menuDebug.setStyleSheet(menu_style)
888
+ self.ui.menubar.setStyleSheet(menu_style.replace("QMenu","QMenuBar"))
889
+
878
890
  def defineMenuActions(self):
879
891
  self.projectTree.button_open_action=self.open_project
880
892
  self.projectTree.button_save_action=self.save_project
@@ -1034,7 +1046,7 @@ class gPaIRS(QMainWindow):
1034
1046
  ITE:ITEpar=self.ui.Explorer.ITEfromInd(ind)
1035
1047
  ITE.ind[-1]=ind_new[-1]
1036
1048
  self.ui.Explorer.ITEpar.ind[-1]=ind_new[-1]
1037
- ITEs:ITEpar=self.ui.Explorer.ITEsfromInd(ind)
1049
+ ITEs:ITEpar=self.ui.Explorer.ITEsfromInd(ind_new)
1038
1050
  ITEs[0].modifiedDate=currentTimeString()
1039
1051
  ITEs[0].date=f'Modified: {ITE.modifiedDate}'
1040
1052
 
@@ -1051,9 +1063,15 @@ class gPaIRS(QMainWindow):
1051
1063
  self.TREpar.copyfrom(TRE)
1052
1064
  self.adjustItemWidgets(ind)
1053
1065
 
1054
- self.inheritance(ind)
1055
- self.IOVinheritance(ind)
1066
+ self.inheritance(ind_new)
1067
+ self.IOVinheritance(ind_new)
1056
1068
  self.adjustDependencies(ITE)
1069
+
1070
+ for w in self.tabWidgets[:-1]:
1071
+ w:gPaIRS_Tab
1072
+ w.adjustFromTABparInd(ind_new)
1073
+ w.setTABWarnLabel()
1074
+ self.w_Log.setLogText()
1057
1075
  #self.checkFutureProc()
1058
1076
  tab.add_TABpar_bridge=add_TABpar_bridge
1059
1077
 
@@ -1109,17 +1127,30 @@ class gPaIRS(QMainWindow):
1109
1127
  focusWidget.setFocus()
1110
1128
  tab.setTABpar_bridge=setTABpar_bridge
1111
1129
 
1112
- def logBridge(self):
1113
- LOG:LOGpar = self.w_Log.TABpar
1114
- ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1130
+ def logBridge(self,ind=None):
1131
+ if ind is None:
1132
+ OUT:OUTpar = self.w_Output.TABpar
1133
+ LOG:LOGpar = self.w_Log.TABpar
1134
+ VIS:VISpar = self.w_Vis.TABpar
1135
+ ITE:ITEpar = self.ui.Explorer.ITEpar #self.ui.Explorer.ITEfromTRE(self.TREpar)
1136
+ else:
1137
+ OUT:OUTpar = self.w_Output.TABpar_at(ind)
1138
+ LOG:LOGpar = self.w_Log.TABpar_at(ind)
1139
+ VIS:VISpar = self.w_Vis.TABpar_at(ind)
1140
+ ITE:ITEpar = self.ui.Explorer.ITEfromInd(ind) #self.ui.Explorer.ITEfromTRE(self.TREpar)
1141
+
1142
+ if LOG is None or LOG.FlagNone: return
1115
1143
 
1116
1144
  if ITE.flagRun==0:
1117
1145
  warningMessages=[]
1118
1146
  errorMessages=[]
1119
1147
  for w in self.tabWidgets[:-1]:
1120
1148
  w:gPaIRS_Tab
1121
- par:TABpar= w.TABpar
1122
- if w!=self.w_Log and not par.FlagNone:
1149
+ if ind is None:
1150
+ par:TABpar= w.TABpar
1151
+ else:
1152
+ par:TABpar= w.TABpar_at(ind)
1153
+ if w!=self.w_Log and par is not None and not par.FlagNone:
1123
1154
  if par.OptionDone==0: errorMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1124
1155
  elif par.OptionDone!=1: warningMessages.append('--- '+w.TABname+' ---\n'+par.warningMessage)
1125
1156
 
@@ -1131,6 +1162,23 @@ class gPaIRS(QMainWindow):
1131
1162
  if errorText:
1132
1163
  errorText='\n\n'+ITE.procdata.headerSection('CRITICAL ISSUES',errorText,'X')
1133
1164
  LOG.text=PaIRS_Header+ITE.procdata.itemname+warnigText+errorText
1165
+ if VIS.FlagView:
1166
+ outPathRoot=myStandardRoot(OUT.path+OUT.subfold+OUT.root)
1167
+ logfile=ITE.procdata.procOutName()+'.log'
1168
+ if ITE.procdata.outPathRoot=='': logfile=outPathRoot+logfile
1169
+ border='o' #·●⦁᛫
1170
+ headerWidth=54
1171
+ 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"
1172
+ if os.path.isfile(logfile):
1173
+ try:
1174
+ with open(logfile, 'r', encoding='utf-8') as f:
1175
+ log_content = f.read()
1176
+ result_text += "\n" + log_content
1177
+ except Exception as e:
1178
+ result_text += f"\nError reading log file '{os.path.basename(logfile)}:'\n{e}"
1179
+ else:
1180
+ result_text += f"\nLog file '{os.path.basename(logfile)}' not found!"
1181
+ LOG.text+=result_text+'\n\n'+ITE.procdata.headerSection('END of EXISTING PROCESS LOG',' ',border,headerWidth)
1134
1182
  else:
1135
1183
  LOG.text=ITE.procdata.Log
1136
1184
 
@@ -1771,8 +1819,11 @@ class gPaIRS(QMainWindow):
1771
1819
  stepList=self.linkableSteps(FlagExcludeLinked=FlagExcludeLinked)
1772
1820
  ITE=self.ui.Explorer.ITEpar
1773
1821
  if len(stepList)==0:
1774
- showTip(self,message)
1822
+ show_mouse_tooltip(self,message)
1775
1823
  return None
1824
+
1825
+ style=button.styleSheet()
1826
+ button.setStyleSheet("")
1776
1827
  menu = QMenu(self)
1777
1828
  title_action = QAction(menuTitle, self)
1778
1829
  if icon: title_action.setIcon(icon)
@@ -1784,7 +1835,9 @@ class gPaIRS(QMainWindow):
1784
1835
  nameItem=' '+key
1785
1836
  action:QAction = menu.addAction(TreeIcons.icons[item['icon']], nameItem)
1786
1837
  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()))
1838
+ menu.exec(QCursor.pos()) #menu.exec(button.mapToGlobal(button.rect().bottomLeft()))
1839
+ button.setStyleSheet(style)
1840
+ return
1788
1841
 
1789
1842
  def button_step_inherit_action(self):
1790
1843
  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 +2394,8 @@ class gPaIRS(QMainWindow):
2341
2394
  for f,v in zip(fields,Var):
2342
2395
  result[f]=v
2343
2396
  result=self.w_Vis.calcMagnitude(result)
2344
- result=self.w_Vis.calcZVorticity(result)
2397
+ FlagUnit=VIS_ind.Out.xres!=1.0 or VIS_ind.Out.pixAR!=1.0
2398
+ result=self.w_Vis.calcZVorticity(result,FlagUnit)
2345
2399
  self.w_Vis.result_Current=result
2346
2400
  else:
2347
2401
  VIS_ind.result_file_Current=''
@@ -2637,8 +2691,8 @@ class gPaIRS(QMainWindow):
2637
2691
  self.saveCal('_Mod')
2638
2692
  if self.w_Vis_CalVi.calibView.calib.FlagCalibration:
2639
2693
  self.appendCalibration()
2640
- #indTree,indItem,ind=self.w_Import.INPpar.indexes()
2641
- #self.actualBridge('Import',indTree,indItem,ind)
2694
+ #indTree,indItem,ind=self.w_Input_CalVi.INPpar.indexes()
2695
+ #self.actualBridge('Input_CalVi',indTree,indItem,ind)
2642
2696
  self.initDataAndSetImgFromGui(self.w_Input_CalVi.INPpar,self.w_Process_CalVi.PROpar)
2643
2697
  self.w_Vis_CalVi.stopCalVi()
2644
2698
 
@@ -2931,6 +2985,7 @@ class gPaIRS(QMainWindow):
2931
2985
  TABpar_ind.FlagInit=True
2932
2986
  else:
2933
2987
  TABpar_ind.FlagInit=False
2988
+ self.logBridge(indITE)
2934
2989
  return FlagCheck
2935
2990
 
2936
2991
  #*************************************************** Projects
@@ -3085,6 +3140,9 @@ class gPaIRS(QMainWindow):
3085
3140
  pri.Coding.blue(f'scrollArea: {a.objectName()}')
3086
3141
  scrollAreaValues[a.objectName()]=[a.horizontalScrollBar().value(),a.verticalScrollBar().value()]
3087
3142
  self.GPApar.ScrollAreaValues=scrollAreaValues
3143
+ for w in self.tabWidgets[:-1]:
3144
+ w:gPaIRS_Tab
3145
+ self.GPApar.globalVals[w.TABname]=w.syncPrevGlobalFields(FlagSync=False)
3088
3146
  return
3089
3147
 
3090
3148
  def setFontPixelSize(self):
@@ -3220,6 +3278,11 @@ class gPaIRS(QMainWindow):
3220
3278
  a.horizontalScrollBar().setValue(scrollAreaValues[0])
3221
3279
  a.verticalScrollBar().setValue(scrollAreaValues[1])
3222
3280
  self.setNumCores()
3281
+ for w in self.tabWidgets[:-1]:
3282
+ w:gPaIRS_Tab
3283
+ if w.TABname in self.GPApar.globalVals:
3284
+ exceptions=self.GPApar.globalExceptions[w.TABname] if w.TABname in self.GPApar.globalExceptions else []
3285
+ w.syncPrevGlobalFields(ref_vals=self.GPApar.globalVals[w.TABname],exceptions=exceptions)
3223
3286
 
3224
3287
  def setNumCores(self):
3225
3288
  if self.GPApar.NumCores >NUMTHREADS_MAX:
@@ -3683,6 +3746,8 @@ class gPaIRS(QMainWindow):
3683
3746
  ['11/07/1987', 'Happy birthday to Carlo! 🎈🎂🍾'],
3684
3747
  ['19/09/1963', 'Happy birthday to Gennaro! 🎈🎂🍾'],
3685
3748
  ['27/11/1940', 'Happy birthday to prof. Carlomagno! 🎈🎂🍾'],
3749
+ ['01/12/1969', 'Happy birthday to Giuseppe S.! 🎈🎂🍾'],
3750
+ ['28/02/1981', 'Happy birthday to Rosaria! 🎈🎂🍾'],
3686
3751
  ['18/10/1985', 'Happy birthday to Stefano! 🎈🎂🍾'],
3687
3752
  ['13/08/1985', 'Happy birthday to Andrea! 🎈🎂🍾'],
3688
3753
  ['22/12/1988', 'Happy birthday to Jack! 🎈🎂🍾'],
@@ -3690,6 +3755,13 @@ class gPaIRS(QMainWindow):
3690
3755
  ['03/11/1989', 'Happy birthday to Massimo! 🎈🎂🍾'],
3691
3756
  ['15/06/1991', 'Happy birthday to Mattia! 🎈🎂🍾'],
3692
3757
  ['14/07/1993', 'Happy birthday to Mirko! 🎈🎂🍾'],
3758
+ ['13/03/1997', 'Happy birthday to Giosuè! 🎈🎂🍾'],
3759
+ ['24/09/1998', 'Happy birthday to Piergiorgio! 🎈🎂🍾'],
3760
+ ['15/01/1999', 'Happy birthday to Alessandro! 🎈🎂🍾'],
3761
+ ['20/02/1999', 'Happy birthday to Cristina! 🎈🎂🍾'],
3762
+ ['20/09/2000', 'Happy birthday to Antonio M.! 🎈🎂🍾'],
3763
+ ['21/09/2000', 'Happy birthday to Gabriele! 🎈🎂🍾'],
3764
+ ['16/11/2000', 'Happy birthday to Antonio D.! 🎈🎂🍾'],
3693
3765
  ['01/01', 'Happy New Year! 🎊🧨'],
3694
3766
  ['25/12', 'Merry Christmas! 🎄✨'],
3695
3767
  ['31/10', 'Happy Halloween! 🎃👻'],
@@ -3712,6 +3784,34 @@ class gPaIRS(QMainWindow):
3712
3784
  self.ui.logo.setPixmap(QPixmap(u""+ icons_path +"logo_PaIRS_rect.png"))
3713
3785
  self.ui.lab_happy_days.hide()
3714
3786
 
3787
+ def startHappyLogoWatcher(self):
3788
+ """Re-check date at next midnight and periodically as keep-alive."""
3789
+ # one-shot timer to just-after-midnight (00:01)
3790
+ def _schedule_midnight():
3791
+ now=QDateTime.currentDateTime()
3792
+ next_day = now.date().addDays(1)
3793
+ next_midnight = QDateTime(next_day, QTime(0, 0))
3794
+ msec=now.msecsTo(next_midnight.addSecs(60)) # 00:01
3795
+ if msec<60_000: msec=60_000 # safety minimum
3796
+ self._happy_midnight=QTimer(self)
3797
+ self._happy_midnight.setSingleShot(True)
3798
+ self._happy_midnight.timeout.connect(_on_tick)
3799
+ self._happy_midnight.start(msec)
3800
+
3801
+ def _on_tick():
3802
+ # Re-apply logo state and reschedule
3803
+ self.setupLogo()
3804
+ _schedule_midnight()
3805
+
3806
+ # keep-alive each few hours (handles sleep/wake or clock drift)
3807
+ self._happy_keepalive=QTimer(self)
3808
+ self._happy_keepalive.setInterval(3*60*60*1000) # 3h
3809
+ self._happy_keepalive.timeout.connect(self.setupLogo)
3810
+ self._happy_keepalive.start()
3811
+
3812
+ # initial schedule
3813
+ _schedule_midnight()
3814
+
3715
3815
  def happyLogo(self):
3716
3816
  self.FlagHappyLogo=not self.FlagHappyLogo
3717
3817
  if self.FlagHappyLogo:
@@ -3742,6 +3842,7 @@ class gPaIRS(QMainWindow):
3742
3842
 
3743
3843
  def launchPaIRS(flagDebug=False,flagInputDebug=False):
3744
3844
  print('\n'+PaIRS_Header+'Starting the interface...')
3845
+ #QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True)
3745
3846
  app=PaIRSApp.instance()
3746
3847
  if not app:app = QApplication(sys.argv)
3747
3848
  app.setStyle('Fusion')
@@ -3838,7 +3939,7 @@ def splashAnimation(self:QLabel,logo:QLabel):
3838
3939
  self.anim_group.finished.connect(self.hide)
3839
3940
  self.anim_group.finished.connect(logo.show)
3840
3941
  self.anim_group.start()
3841
-
3942
+
3842
3943
  def quitPaIRS(app:QApplication,flagPrint=True):
3843
3944
  app.setWindowIcon(app.pyicon)
3844
3945
  app.quit()
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
PaIRS_UniNa/procTools.py CHANGED
@@ -355,9 +355,54 @@ class dataTreePar(TABpar):
355
355
  if len(args)>1: n=args[1]
356
356
  ln=len(nameSection)
357
357
  ns=int((n-ln)/2)
358
- 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
359
361
  return Log
360
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
+
361
406
  def createLogProc(self):
362
407
  splitAs='\n '#used to join the strings together tab or spaces may be use to indent the error
363
408
  numImgTot=len(self.list_pim) if self.Step!=StepTypes.min else (2*len(self.list_pim))
PaIRS_UniNa/rqrdpckgs.txt CHANGED
@@ -1,9 +1,9 @@
1
- scipy 1.14.0 1.16.1 0
2
- matplotlib 3.9.0 3.10.6 0
3
- pillow 10.4.0 11.3.0 0
4
- numpy 2.0.0 2.3.2 0
5
- pyside6 6.7.0 6.9.2 0
1
+ scipy 1.14.0 1.16.3 0
2
+ matplotlib 3.9.0 3.10.8 0
3
+ pillow 10.4.0 12.1.0 0
4
+ numpy 2.0.0 2.4.0 0
5
+ pyside6 6.7.0 6.10.1 0
6
6
  unidecode 1.3.0 1.4.0 0
7
- psutil 6.0.0 7.0.0 0
7
+ psutil 6.0.0 7.2.1 0
8
8
  debugpy 1.6.6 1.8.16 0
9
- certifi 2025.7.14 2025.8.3 0
9
+ certifi 2025.7.14 2026.1.4 0