PaIRS-UniNa 0.2.4__cp312-cp312-macosx_10_9_universal2.whl → 0.2.5__cp312-cp312-macosx_10_9_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.

Potentially problematic release.


This version of PaIRS-UniNa might be problematic. Click here for more details.

Files changed (57) hide show
  1. PaIRS_UniNa/Changes.txt +23 -0
  2. PaIRS_UniNa/Custom_Top.py +1 -1
  3. PaIRS_UniNa/Explorer.py +3059 -3049
  4. PaIRS_UniNa/FolderLoop.py +371 -371
  5. PaIRS_UniNa/Input_Tab.py +714 -709
  6. PaIRS_UniNa/Input_Tab_tools.py +3017 -3009
  7. PaIRS_UniNa/Output_Tab.py +2 -2
  8. PaIRS_UniNa/PaIRS.py +17 -17
  9. PaIRS_UniNa/PaIRS_PIV.py +56 -1
  10. PaIRS_UniNa/PaIRS_pypacks.py +143 -6
  11. PaIRS_UniNa/Process_Tab.py +6 -11
  12. PaIRS_UniNa/Process_Tab_Disp.py +8 -3
  13. PaIRS_UniNa/Saving_tools.py +277 -277
  14. PaIRS_UniNa/TabTools.py +56 -17
  15. PaIRS_UniNa/Vis_Tab.py +237 -78
  16. PaIRS_UniNa/Whatsnew.py +2 -0
  17. PaIRS_UniNa/_PaIRS_PIV.so +0 -0
  18. PaIRS_UniNa/__init__.py +2 -2
  19. PaIRS_UniNa/gPaIRS.py +3745 -3600
  20. PaIRS_UniNa/icons/pylog.png +0 -0
  21. PaIRS_UniNa/icons/python_warning.png +0 -0
  22. PaIRS_UniNa/icons/queue.png +0 -0
  23. PaIRS_UniNa/icons/uninitialized.png +0 -0
  24. PaIRS_UniNa/icons/window.png +0 -0
  25. PaIRS_UniNa/listLib.py +301 -301
  26. PaIRS_UniNa/parForMulti.py +433 -433
  27. PaIRS_UniNa/parForWorkers.py +46 -1
  28. PaIRS_UniNa/procTools.py +17 -7
  29. PaIRS_UniNa/rqrdpckgs.txt +8 -0
  30. PaIRS_UniNa/stereo.py +683 -683
  31. PaIRS_UniNa/tabSplitter.py +606 -606
  32. PaIRS_UniNa/ui_Calibration_Tab.py +542 -542
  33. PaIRS_UniNa/ui_Custom_Top.py +294 -294
  34. PaIRS_UniNa/ui_Input_Tab.py +1098 -1098
  35. PaIRS_UniNa/ui_Input_Tab_CalVi.py +1280 -1280
  36. PaIRS_UniNa/ui_Log_Tab.py +261 -261
  37. PaIRS_UniNa/ui_Output_Tab.py +2360 -2360
  38. PaIRS_UniNa/ui_Process_Tab.py +3808 -3808
  39. PaIRS_UniNa/ui_Process_Tab_CalVi.py +1547 -1547
  40. PaIRS_UniNa/ui_Process_Tab_Disp.py +1139 -968
  41. PaIRS_UniNa/ui_Process_Tab_Min.py +435 -435
  42. PaIRS_UniNa/ui_ResizePopup.py +203 -203
  43. PaIRS_UniNa/ui_Vis_Tab.py +1626 -1533
  44. PaIRS_UniNa/ui_Vis_Tab_CalVi.py +1249 -1249
  45. PaIRS_UniNa/ui_Whatsnew.py +131 -131
  46. PaIRS_UniNa/ui_gPairs.py +867 -849
  47. PaIRS_UniNa/ui_infoPaIRS.py +550 -428
  48. PaIRS_UniNa/whatsnew.txt +5 -4
  49. {PaIRS_UniNa-0.2.4.dist-info → pairs_unina-0.2.5.dist-info}/METADATA +38 -26
  50. {PaIRS_UniNa-0.2.4.dist-info → pairs_unina-0.2.5.dist-info}/RECORD +52 -52
  51. {PaIRS_UniNa-0.2.4.dist-info → pairs_unina-0.2.5.dist-info}/WHEEL +1 -1
  52. PaIRS_UniNa/icons/order.png +0 -0
  53. PaIRS_UniNa/icons/order_reverse.png +0 -0
  54. PaIRS_UniNa/icons/pencil_bw.png +0 -0
  55. PaIRS_UniNa/icons/run_piv.png +0 -0
  56. PaIRS_UniNa-0.2.4.dist-info/LICENSE +0 -19
  57. {PaIRS_UniNa-0.2.4.dist-info → pairs_unina-0.2.5.dist-info}/top_level.txt +0 -0
@@ -1,612 +1,612 @@
1
- import sys
1
+ import sys
2
2
  from .PaIRS_pypacks import *
3
3
  from .Input_Tab import *
4
4
  from .Output_Tab import *
5
5
  from .Process_Tab import *
6
6
  from .Log_Tab import *
7
7
  from .Vis_Tab import *
8
-
9
- class PaIRS_QSplitter(QSplitter):
10
- minimumResizeWidth=0
11
- class PaIRS_ToggleSplitterHandle(QtWidgets.QSplitterHandle):
12
- minimumHandleDisplacement=200
13
- def __init__(self, o: Qt.Orientation, parent: QSplitter):
14
- super().__init__(o, parent)
15
- self.index=parent.count()-1
16
- self.limits=[None,None]
17
- #pri.Coding.yellow(f'Splitter handle #{self.index}')
18
- self.init_pos=None
19
- return
20
-
21
- def mousePressEvent(self, event:QMouseEvent):
22
- super().mousePressEvent(event)
23
-
24
- TABpar.FlagSettingPar=True
25
- pa:PaIRS_QSplitter=self.parent()
26
- visibleHandles=[]
27
- widgets=[]
28
- visibleWidgets=[]
29
- for i in range(pa.count()):
30
- handle = pa.handle(i)
31
- if handle.isVisible():
32
- visibleHandles.append(handle)
33
- widget=pa.widget(i)
34
- widgets.append(widget)
35
- if widget.isVisible():
36
- visibleWidgets.append(widget)
37
- i=visibleHandles.index(self)
38
- self.index=widgets.index(visibleWidgets[i])
39
- """
40
- width=0
41
- index=-1
42
- sizes=pa.splitterSizes
43
- #sizes=pa.sizes()
44
- while self.pos().x()>width and index<pa.count()-1:
45
- index+=1
46
- w=pa.widget(index)
47
- if w:
48
- if w.isVisible():
49
- width+=sizes[index]+pa.handleWidth()
50
- self.index=index
51
- """
52
- pri.Coding.magenta(f'pos={self.pos().x()} index={self.index}')
53
-
54
- w=pa.widget(self.index)
55
- w.setMinimumWidth(pa.minimumSizes[self.index])
56
- w.widget.setMinimumWidth(pa.minimumSizes[self.index])
57
- w.setMaximumWidth(pa.maximumSizes[self.index])
58
- w.widget.setMaximumWidth(pa.maximumSizes[self.index])
59
-
60
- pri.Coding.magenta(f'{w.widget.TABname} [{pa.minimumSizes[self.index]},{pa.maximumSizes[self.index]}]')
61
- dwf=w.maximumWidth()-w.minimumWidth()
62
- pa.splitterReleased([pa.count()-1],[+dwf],FlagReleased=False)
63
-
64
- self.init_pos=self.pos().x()
65
- self.limits=[w.minimumWidth()-w.width(),w.maximumWidth()-w.width()]
66
-
67
- def mouseReleaseEvent(self, event:QMouseEvent):
68
- super().mouseReleaseEvent(event)
69
-
70
- TABpar.FlagSettingPar=False
71
- if self.init_pos:
72
- pa:PaIRS_QSplitter=self.parent()
73
- w=pa.widget(self.index)
74
- dw=self.pos().x()-self.init_pos
75
- dwf=pa.maximumSizes[self.index]-w.minimumWidth()
76
- indexes=[self.index,pa.count()-1]
77
- deltaWidths=[dw,-dwf]
78
- pa.splitterReleased(indexes,deltaWidths,FlagReleased=True)
79
-
80
- w.setFixedWidth(pa.splitterSizes[self.index])
81
- w.widget.setFixedWidth(pa.splitterSizes[self.index])
82
-
83
- def mouseMoveEvent(self, event: QMouseEvent):
84
- pa:PaIRS_QSplitter=self.parent()
85
- #pa.splitterMoving(event.pos().x(),self.index)
86
-
87
- pa.setSizes(pa.sizes())
88
-
89
- pos=event.pos().x()
90
- if pos and self.limits[0] and self.limits[1]:
91
- pos=max([self.limits[0],pos])
92
- pos=min([self.limits[1],pos])
93
- pos+=self.pos().x()+self.width()
94
-
95
-
96
- bar=pa.scrollArea.horizontalScrollBar()
97
- val=bar.value()
98
- wSA=pa.scrollArea.width()
99
- #pri.Coding.magenta(f'val={val}\t pos={pos}\t wSA={wSA}')
100
- if pos-val>wSA:
101
- bar.setValue(pos-wSA)
102
- elif pos<val:
103
- bar.setValue(pos)
104
- return super().mouseMoveEvent(event)
105
-
106
- def createHandle(self):
107
- handle =self.PaIRS_ToggleSplitterHandle(self.orientation(), self)
108
- handle.setCursor(QCursor(Qt.SplitHCursor if self.orientation() == Qt.Horizontal else Qt.SplitVCursor))
109
- return handle
110
-
111
- def __init__(self, orientation, parent=None):
112
- super().__init__(orientation, parent)
113
- self.setOpaqueResize(False)
114
- self.FlagInit=False
115
- self.splitterSizes=[]
116
- self.minimumSizes=[]
117
- self.maximumSizes=[]
118
- self.splitterMaximumSize=0
119
- self.scrollArea:PaIRS_QScrollArea=None
120
-
121
- def addWidget(self, widget):
122
- if not self.FlagInit: i=self.count()
123
- else: i=self.count()-1
124
- return self.insertWidget(i,widget)
125
-
126
- def insertWidget(self, i, widget):
127
- self.splitterSizes.insert(i,widget.minimumWidth())
128
- self.minimumSizes.insert(i,widget.minimumWidth())
129
- self.maximumSizes.insert(i,widget.maximumWidth()+int(self.handleWidth()*0.5))
130
- self.splitterMaximumSize+=self.minimumSizes[-1]+self.handleWidth()
131
- widget.setMaximumWidth(widget.minimumWidth())
132
- return super().insertWidget(i,widget)
133
-
134
- def replaceWidget(self, i, widget):
135
- self.splitterMaximumSize-=self.minimumSizes[i]+self.handleWidth()
136
- self.splitterSizes[i]=widget.minimumWidth()
137
- self.minimumSizes[i]=widget.minimumWidth()
138
- self.maximumSizes[i]=widget.maximumWidth()+int(self.handleWidth()*0.5)
139
- self.splitterMaximumSize+=self.minimumSizes[i]+self.handleWidth()
140
- widget.setMaximumWidth(widget.minimumWidth())
141
- return super().replaceWidget(i,widget)
142
-
143
- def setHandleWidth(self, width: int) -> None:
144
- self.maximumSizes=[m-int(0.5*self.handleWidth())+int(0.5*width) for m in self.maximumSizes]
145
- return super().setHandleWidth(width)
146
-
147
- def splitterReleased(self,indexes,deltaWidths,FlagReleased=True):
148
- for index,dw in zip(indexes,deltaWidths):
149
- w=self.widget(index)
150
- self.splitterSizes[index]=max([min([self.splitterSizes[index]+dw,w.maximumWidth()]),w.minimumWidth()])
151
- self.splitterResize(FlagReleased=FlagReleased)
152
- pri.Coding.green(f'i= {indexes}\t dw={deltaWidths}\t Splitter sizes: {self.splitterSizes}')
153
-
154
- def splitterResize(self,FlagVisible=None,FlagReleased=True):
155
- width=0
156
- if FlagReleased: self.splitterSizes[-1]=0
157
- for i in range(self.count()):
158
- w=self.widget(i)
159
- if FlagVisible is not None: flag=FlagVisible[i]
160
- else: flag=w.isVisible()
161
- if flag:
162
- width+=self.splitterSizes[i]+self.handleWidth()
163
- pa=self.parent().parent()
164
- if pa.width()>width:
165
- self.splitterSizes[-1]+=pa.width()-width
166
- width=pa.width()+self.handleWidth()
167
- self.setFixedWidth(width)
168
- self.setSizes(self.splitterSizes)
169
- if FlagReleased:
170
- for i in range(self.count()-1):
171
- w=self.widget(i)
172
- w.setFixedWidth(self.splitterSizes[i])
173
- w.widget.setFixedWidth(self.splitterSizes[i])
174
- return self.splitterSizes
175
-
176
- def resizeEvent(self,event):
177
- #self.splitterResize()
178
- return
179
-
180
- def setHandleVisibility(self):
181
- for i in range(self.count()):
182
- self.handle(i).setVisible(self.widget(i).isVisible())
183
-
184
- class PaIRS_QScrollArea(QScrollArea):
185
- def __init__(self,widgets=[],handleWidth=20,margin=0):
186
- super().__init__()
187
- self.handleWidth=handleWidth
188
- self.margin=margin
189
-
190
- self.setWidgetResizable(True)
191
- self.container_widget = QWidget()
192
- self.setWidget(self.container_widget)
193
- self.main_layout = QVBoxLayout(self.container_widget)
194
- self.main_layout.setContentsMargins(margin,margin,margin,margin)
195
-
196
- self.splitter=None
197
- self.setupSplitter(widgets)
198
-
199
- def setupSplitter(self,widgets):
200
- self.frames=[]
201
- if not widgets:
202
- return
203
- if self.splitter:
204
- self.main_layout.removeWidget(self.splitter)
205
- self.splitter=splitter=PaIRS_QSplitter(Qt.Horizontal)
206
- self.splitter.setObjectName('tabArea_splitter')
207
- self.widgets=widgets
208
-
209
- dw=0
210
- # Aggiungi alcuni widget al QSplitter
211
- for i,w in enumerate(widgets):
212
- w:gPaIRS_Tab
213
- w.blockSignals(True)
214
- frame = QFrame()
215
- frame_layout = QVBoxLayout(frame)
216
- frame_layout.setContentsMargins(0,0,0,0)
217
- frame.setMinimumWidth(w.minimumWidth())
218
- frame.setMaximumWidth(w.maximumWidth())
219
- dw+=max([dw,w.maximumWidth()-w.minimumWidth()])
220
-
221
- objName=f'{w.TABname}_frame'
222
- frame.setObjectName(objName)
223
- frame.setStyleSheet(f"""
224
- QFrame#{objName} {{
225
- border: 1px solid rgba(128, 128, 128, 0.5);
226
- border-radius: 15px;
227
- background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(128, 128, 128, 0), stop:1 rgba(224, 224, 224, 0.25));
228
- }}
229
- QWidget#scrollAreaWidgetContents{{
230
- background: transparent;
231
- }}
232
- """)
233
-
234
- splitter.addWidget(frame)
235
- splitter.setCollapsible(i,False)
236
- #if i in (0,3): frame.hide()
237
- frame_layout.addWidget(w)
238
- setattr(frame,'widget',w)
239
- frame.setVisible(False)
240
- self.frames.append(frame)
241
- if hasattr(w,'ui') and hasattr(w.ui,'scrollArea'):
242
- w.ui.scrollArea.setObjectName('scroll_area_'+w.TABname)
243
- w.blockSignals(False)
244
-
245
- frame = QFrame()
246
- objName=f'empty_frame'
247
- frame.setMinimumWidth(50)
248
- frame.setMaximumWidth(dw)
249
-
250
- frame.setObjectName(objName)
251
- frame.setStyleSheet(f"""
252
- QFrame#{objName} {{
253
- border: none;
254
- background: transparent;
255
- }}
256
- """)
257
- splitter.addWidget(frame)
258
- frame.setMaximumWidth(dw)
259
- setattr(frame,'TABname','Empty frame')
260
- setattr(frame,'widget',frame)
261
- self.frames.append(frame)
262
-
263
- splitter.setHandleWidth(self.handleWidth)
264
- splitter.scrollArea=self
265
- self.main_layout.addWidget(self.splitter)
266
-
267
- def resizeEvent(self, event: QResizeEvent):
268
- self.update()
269
- total_height = self.viewport().height()
270
- scrollbar_height = self.horizontalScrollBar().height() if self.horizontalScrollBar().isVisible() else 0
271
- available_height = total_height - scrollbar_height
272
- for f,w in zip(self.frames,self.widgets):
273
- f:QFrame
274
- available_height=max([available_height,w.minimumHeight()])
275
- for f,w in zip(self.frames,self.widgets):
276
- f:QFrame
277
- f.setMinimumHeight(available_height)
278
- self.splitter.setMinimumHeight(available_height)
279
- self.container_widget.setMinimumHeight(available_height+scrollbar_height)
280
-
281
- return super().resizeEvent(event)
282
-
283
- class SPLpar(TABpar):
284
- sizes_default = []
285
- FlagVisible_default = []
286
- horizontalBarValues_default = {}
287
- verticalBarValues_default = {}
288
- FlagCollapsibleBoxes_default = {}
289
-
290
- def __init__(self,Process=ProcessTypes.null,Step=StepTypes.null):
291
- self.setup(Process,Step)
292
- super().__init__('SPLpar','TabAreaWidget')
293
- self.unchecked_fields+=[]
294
-
295
- def setup(self,Process,Step):
296
- self.Process=Process
297
- self.Step=Step
298
- self.sizes=[s for s in SPLpar.sizes_default]
299
- self.FlagVisible=[f for f in SPLpar.FlagVisible_default]
300
- self.horizontalBarValues=copy.deepcopy(SPLpar.horizontalBarValues_default)
301
- self.verticalBarValues=copy.deepcopy(SPLpar.verticalBarValues_default)
302
- self.FlagCollapsibleBoxes=copy.deepcopy(SPLpar.FlagCollapsibleBoxes_default)
303
-
304
- class TabAreaWidget(gPaIRS_Tab):
305
- margin=10
306
-
307
- buttonSpacing=10
308
- buttonSize=[40,30]
309
- iconSize=20
310
-
311
- widgetMinimumWidth=550
312
- widgetMaximumWidth=1100
313
- widgetMinimumHeight=650
314
- tabAreaMinimumHeight=750
315
- widgetMaximumHeight=10000
316
- widgetHorizontalMargin=10
317
- widgetVerticalMargin=5
318
- handleWidth=20
319
-
320
- def __init__(self, parent: QWidget = None, widgets=[],icons=[]):
321
- super().__init__(parent,UiClass=None,ParClass=SPLpar)
322
- if __name__ == "__main__":
323
- iconW = QIcon()
324
- iconW.addFile(u""+ icons_path +"logo_PaIRS.png", QSize(), QIcon.Normal, QIcon.Off)
325
- self.setWindowTitle('Tab area widget')
326
- self.setWindowIcon(iconW)
327
- self.main_layout=QVBoxLayout()
328
-
329
- #------------------------------------- Graphical interface: miscellanea
330
- self.TABname='TabArea'
331
- m=self.margin
332
- self.setMinimumWidth(self.widgetMinimumWidth+m*2+self.handleWidth)
333
- self.tabAreaHeight=self.buttonSize[1]+self.buttonSpacing+self.tabAreaMinimumHeight+m*4
334
- #self.setMinimumHeight(self.buttonSize[1]+self.buttonSpacing+self.widgetMinimumHeight+m*4)
335
- self.main_layout.setContentsMargins(m,m,m,m)
336
- self.main_layout.setSpacing(self.buttonSpacing)
337
- self.setLayout(self.main_layout)
338
-
339
- self.buttonBar=QWidget()
340
- self.buttonBar_layout=QHBoxLayout()
341
- self.buttonBar_layout.setContentsMargins(0,0,0,0)
342
- self.buttonBar_layout.setSpacing(self.buttonSpacing)
343
- self.buttonBar.setLayout(self.buttonBar_layout)
344
- self.buttonSpacer=QSpacerItem(self.buttonSize[0],self.buttonSize[1],QSizePolicy.Expanding, QSizePolicy.Minimum)
345
- self.buttonBar_layout.addSpacerItem(self.buttonSpacer)
346
-
347
- self.scrollArea = PaIRS_QScrollArea(handleWidth=self.handleWidth)
348
- self.scrollArea.setObjectName('scroll_area_tabArea')
349
-
350
- self.main_layout.addWidget(self.buttonBar)
351
- self.main_layout.addWidget(self.scrollArea)
352
-
353
- #------------------------------------- Declaration of parameters
354
- self.SPLpar_base=SPLpar()
355
- self.SPLpar:SPLpar=self.TABpar
356
- self.SPLpar_old:SPLpar=self.TABpar_old
357
-
358
- #------------------------------------- Callbacks
359
- self.buttons=[]
360
- self.animation = QVariantAnimation(self.scrollArea)
361
- self.animation.valueChanged.connect(self.moveTo)
362
- self.scrollArea.horizontalScrollBar().valueChanged.connect(self.finishAnimation)
363
-
364
- self.setTABlayout=self.setSPLlayout
365
- self.FlagAddPrev=False
366
- self.FlagBridge=False
367
- self.FlagAnimationRunning=False
368
-
369
- self.setupWid()
370
- if __name__ == "__main__":
371
- self.app=app
372
- setAppGuiPalette(self)
373
-
374
- self.FlagDisplayControls=False
375
- self.setupTabArea(widgets,icons)
376
-
377
- def null(self):
378
- return True
379
-
380
- def setupTabArea(self,widgets,icons):
381
- self.widgets=widgets
382
- if not widgets: return
383
- for b in self.buttons:
384
- b:RichTextPushButton
385
- self.buttonBar_layout.removeWidget(b)
386
- b.setParent(None)
387
- self.buttons=[]
388
- self.setupButtons(widgets,icons)
389
- self.scrollArea.setupSplitter(widgets)
390
- self.scrollArea.splitter.splitterResize=self.splitterResize
391
-
392
- self.SPLpar.sizes=[w.width() for w in widgets]+[self.scrollArea.splitter.minimumResizeWidth]
393
- self.SPLpar.FlagVisible=[True for w in widgets]+[True]
394
- self.SPLpar.horizontalBarValues={}
395
- self.SPLpar.verticalBarValues={}
396
-
397
- self.scrollAreas=self.findChildren(QScrollArea)
398
- self.collapBoxes=[]
399
- for w in self.widgets:
400
- w:gPaIRS_Tab
401
- self.scrollAreas+=w.findChildren(QScrollArea)
402
- self.scrollAreas+=w.findChildren(QTextEdit)
403
- self.scrollAreas+=w.findChildren(QTableWidget)
404
- self.scrollAreas+=w.findChildren(QTreeWidget)
405
- self.collapBoxes+=w.findChildren(CollapsibleBox)
406
- for s in self.scrollAreas:
407
- s:QScrollArea
408
- if s.objectName()=='': continue
409
- self.SPLpar.horizontalBarValues[s.objectName()]=s.horizontalScrollBar().value()
410
- self.SPLpar.verticalBarValues[s.objectName()]=s.verticalScrollBar().value()
411
- s.horizontalScrollBar().valueChanged.connect(lambda v, scrllr=s: self.updateScrollBarValue(scrllr,True))
412
- s.verticalScrollBar().valueChanged.connect(lambda v, scrllr=s: self.updateScrollBarValue(scrllr,False))
413
- for cB in self.collapBoxes:
414
- cB:CollapsibleBox
415
- self.SPLpar.FlagCollapsibleBoxes[cB.objectName()]=cB.toggle_button.isChecked()
416
- cB.toggle_button.clicked.connect(lambda v, cllpbx=cB: self.updateFlagCollapsibleBox(cllpbx))
417
-
418
- SPLpar.sizes_default=[w.width() for w in widgets]+[self.scrollArea.splitter.minimumResizeWidth]
419
- SPLpar.FlagVisible_default=[True for w in widgets]+[True]
420
- for k in self.SPLpar.horizontalBarValues:
421
- SPLpar.horizontalBarValues_default[k]=0
422
- for k in self.SPLpar.verticalBarValues:
423
- SPLpar.verticalBarValues_default[k]=0
424
- for k in self.SPLpar.FlagCollapsibleBoxes:
425
- SPLpar.FlagCollapsibleBoxes_default[k]=True
426
- #self.nullCallback()
427
- #self.adjustTABparInd()
428
-
429
- def updateFlagCollapsibleBox(self,collapBox:CollapsibleBox):
430
- if self.FlagSettingPar: return
431
- self.SPLpar.FlagCollapsibleBoxes[collapBox.objectName()]=collapBox.toggle_button.isChecked()
432
- TABpar_ind:SPLpar=self.TABpar_at(self.TABpar.ind)
433
- if TABpar_ind: TABpar_ind.FlagCollapsibleBoxes[collapBox.objectName()]=collapBox.toggle_button.isChecked()
434
-
435
- def setFlagCollapsibleBox(self):
436
- for cB in self.collapBoxes:
437
- cB:CollapsibleBox
438
- if cB.objectName() in self.SPLpar.FlagCollapsibleBoxes:
439
- if self.SPLpar.FlagCollapsibleBoxes[cB.objectName()]!=cB.toggle_button.isChecked():
440
- cB.toggle_button.setChecked(self.SPLpar.FlagCollapsibleBoxes[cB.objectName()])
441
- cB.on_click()
442
-
443
- def updateScrollBarValue(self,scrollArea:QScrollArea=None,flagHorizontal:bool=True):
444
- if self.FlagAnimationRunning or self.FlagSettingPar: return
445
- TABpar_ind:SPLpar=self.TABpar_at(self.TABpar.ind)
446
-
447
- if flagHorizontal:
448
- pri.Coding.magenta(f'{scrollArea.objectName()} horizontal ScrollBar value: {scrollArea.horizontalScrollBar().value()}')
449
- self.SPLpar.horizontalBarValues[scrollArea.objectName()]=scrollArea.horizontalScrollBar().value()
450
- if TABpar_ind: TABpar_ind.horizontalBarValues[scrollArea.objectName()]=scrollArea.horizontalScrollBar().value()
451
- else:
452
- pri.Coding.magenta(f'{scrollArea.objectName()} vertical ScrollBar value: {scrollArea.verticalScrollBar().value()}')
453
- self.SPLpar.verticalBarValues[scrollArea.objectName()]=scrollArea.verticalScrollBar().value()
454
- if TABpar_ind: TABpar_ind.verticalBarValues[scrollArea.objectName()]=scrollArea.verticalScrollBar().value()
455
-
456
- def setScrollBarValues(self):
457
- for s in self.scrollAreas:
458
- s:QScrollArea
459
- if s.objectName() in self.SPLpar.horizontalBarValues:
460
- if self.SPLpar.horizontalBarValues[s.objectName()]!=s.horizontalScrollBar().value():
461
- s.horizontalScrollBar().setValue(self.SPLpar.horizontalBarValues[s.objectName()])
462
- if s.objectName() in self.SPLpar.verticalBarValues:
463
- if self.SPLpar.verticalBarValues[s.objectName()]!=s.verticalScrollBar().value():
464
- s.verticalScrollBar().setValue(self.SPLpar.verticalBarValues[s.objectName()])
465
-
466
- def setupButtons(self,widgets,icons):
467
- self.buttonBar_layout.removeItem(self.buttonSpacer)
468
-
469
- mh=self.widgetHorizontalMargin
470
- mv=self.widgetVerticalMargin
471
- for w,icon,index in zip(widgets,icons,range(len(widgets))):
472
- b=RichTextPushButton(self.buttonBar)
473
- b.lyt.setStretch(0,1)
474
- b.lyt.setStretch(1,0)
475
- b.setFixedSize(self.buttonSize[0],self.buttonSize[1])
476
- b.setStyleSheet(f"""
477
- RichTextPushButton {{
478
- border: 1px solid rgba(128, 128, 128, 0.5);
479
- border-radius: 5px;
480
- background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(128, 128, 128, 0), stop:1 rgba(224, 224, 224, 0.25));
481
- }}
482
- """)
483
- b.setCursor(Qt.CursorShape.PointingHandCursor)
484
-
485
- w:Input_Tab
486
- if hasattr(w,'ui'):
487
- if hasattr(w.ui,'name_tab'):
488
- b.setToolTip(w.ui.name_tab.text().replace(' ',''))
489
- b.setStatusTip(w.ui.name_tab.text().replace(' ',''))
490
- if hasattr(w.ui,'scrollArea') and not self.scrollArea.styleSheet():
491
- self.scrollArea.setStyleSheet(w.ui.scrollArea.styleSheet())
492
- b.setIcon(QIcon(icons_path+icon+'.png'))
493
- b.setIconSize(QSize(self.iconSize,self.iconSize))
494
-
495
- self.buttonBar_layout.addWidget(b)
496
- b.setVisible(False)
497
- self.buttons.append(b)
498
- w.buttonTab=b
499
-
500
- def defineButtonAction():
501
- butt=b
502
- wid=w
503
- i=index
504
- return lambda: self.buttonAction(butt,wid,i,self.scrollArea)
505
- b.clicked.connect(defineButtonAction())
506
- setattr(w,'buttonAction',defineButtonAction())
507
-
508
- def defineCloseTabAction():
509
- butt=b
510
- return lambda: self.closeTabAction(butt)
511
- w.ui.button_close_tab.clicked.connect(defineCloseTabAction())
512
-
513
- #pri.Coding.red(f"{w.ui.name_tab.text()}\t\t width: min={w.minimumWidth()}, max={w.maximumWidth()}\t height: min={w.minimumHeight()}, max={w.maximumHeight()}")
514
- w.setContentsMargins(mh,mv,mh,mv)
515
- w.setMinimumWidth(max([self.widgetMinimumWidth,w.minimumWidth()]))
516
- w.setMaximumWidth(max([self.widgetMaximumWidth,w.maximumWidth()]))
517
- w.setMinimumHeight(self.widgetMinimumHeight)
518
- w.setMaximumHeight(self.widgetMaximumHeight)
519
-
520
- self.buttonBar_layout.addItem(self.buttonSpacer)
521
-
522
- def buttonAction(self,b:RichTextPushButton,widget:gPaIRS_Tab,index:int,scrollArea:PaIRS_QScrollArea):
523
- self.openTabAction(b)
524
- barValue_end=-int(0.5*scrollArea.splitter.handleWidth())
525
- for i in range(index):
526
- w=scrollArea.splitter.widget(i)
527
- if w.isVisible():
528
- barValue_end+=scrollArea.splitter.splitterSizes[i]+scrollArea.splitter.handleWidth()
529
- if barValue_end!=self.scrollArea.horizontalScrollBar().value():
530
- self.startAnimation(barValue_end)
531
- else:
532
- self.finishAnimation()
533
- return
534
-
535
- def startAnimation(self,v):
536
- self.FlagAnimationRunning=True
537
- self.animation.stop()
538
- self.animation.setStartValue(self.scrollArea.horizontalScrollBar().value())
539
- self.animation.setEndValue(v)
540
- self.animation.setDuration(time_ScrollBar)
541
- self.animation.finished.connect(self.finishAnimation)
542
- self.animation.start()
543
-
544
- def finishAnimation(self):
545
- self.FlagAnimationRunning=False
546
- self.updateScrollBarValue(self.scrollArea,flagHorizontal=True)
547
-
548
- def moveTo(self, i):
549
- self.scrollArea.horizontalScrollBar().setValue(i)
550
-
551
- def openTabAction(self,b:RichTextPushButton):
552
- self.SPLpar.FlagVisible[self.buttons.index(b)]=True
553
- self.nullCallback(f'Open {b.toolTip()} tab')
554
- #self.adjustTABparInd()
555
-
556
- def closeTabAction(self,b:RichTextPushButton):
557
- self.SPLpar.FlagVisible[self.buttons.index(b)]=False
558
- self.nullCallback(f'Close {b.toolTip()} tab')
559
- #self.adjustTABparInd()
560
-
561
- def setSPLlayout(self):
562
- #self.setUpdatesEnabled(False)
563
- #if self.SPLpar.sizes!=self.scrollArea.splitter.splitterSizes:
564
- self.scrollArea.splitter.splitterSizes=[s for s in self.SPLpar.sizes]
565
- PaIRS_QSplitter.splitterResize(self.scrollArea.splitter,self.SPLpar.FlagVisible)
566
- #if self.SPLpar_old.isDifferentFrom(self.SPLpar,fields=['FlagVisible']):
567
- for w,b,f in zip(self.widgets,self.buttons,self.SPLpar.FlagVisible):
568
- w:QWidget
569
- w.parent().setVisible(f)
570
- b:RichTextPushButton
571
- b.setText('')
572
- if not f:
573
- fPixSize=b.font().pixelSize()
574
- s=f'<sup><span style=" font-size:{fPixSize-2}px"> 🔒</span></sup>'
575
- b.setText(s)
576
-
577
- #if self.SPLpar_old.barValue!=self.SPLpar.barValue:
578
- #self.scrollArea.horizontalScrollBar().setValue(self.SPLpar.barValue)
579
- self.scrollArea.horizontalScrollBar().setMaximum(self.scrollArea.splitter.width()-self.scrollArea.width())
580
- self.setScrollBarValues()
581
- self.setFlagCollapsibleBox()
582
-
583
- #self.setUpdatesEnabled(True)
584
- #self.parent().hide()
585
- #self.hide()
586
- self.parent().updateGeometry()
587
- self.updateGeometry()
588
- #self.show()
589
- #self.parent().show()
590
- return
591
-
592
- def splitterResize(self,FlagVisible=None,FlagReleased=True):
593
- splitterSizes=PaIRS_QSplitter.splitterResize(self.scrollArea.splitter,FlagVisible,FlagReleased)
594
- if FlagReleased:
595
- self.SPLpar.sizes=[s for s in splitterSizes]
596
- self.finishAnimation()
597
-
598
-
599
- if __name__ == "__main__":
600
- app = QApplication(sys.argv)
601
- app.setStyle('Fusion')
602
-
603
- tabAreaWidget=TabAreaWidget()
604
- icons=['import_logo','export_logo','process_icon','terminal','vect_field']
605
- tabs=[Input_Tab,Output_Tab,Process_Tab,Log_Tab,Vis_Tab]
606
- widgets=[None]*len(tabs)
607
- for i in range(len(tabs)):
608
- widgets[i]=tabs[i](tabAreaWidget,False)
609
- #tabAreaWidget.resize(1050,0)
610
- tabAreaWidget.setupTabArea(widgets,icons)
611
- tabAreaWidget.show()
612
- sys.exit(app.exec())
8
+
9
+ class PaIRS_QSplitter(QSplitter):
10
+ minimumResizeWidth=0
11
+ class PaIRS_ToggleSplitterHandle(QtWidgets.QSplitterHandle):
12
+ minimumHandleDisplacement=200
13
+ def __init__(self, o: Qt.Orientation, parent: QSplitter):
14
+ super().__init__(o, parent)
15
+ self.index=parent.count()-1
16
+ self.limits=[None,None]
17
+ #pri.Coding.yellow(f'Splitter handle #{self.index}')
18
+ self.init_pos=None
19
+ return
20
+
21
+ def mousePressEvent(self, event:QMouseEvent):
22
+ super().mousePressEvent(event)
23
+
24
+ TABpar.FlagSettingPar=True
25
+ pa:PaIRS_QSplitter=self.parent()
26
+ visibleHandles=[]
27
+ widgets=[]
28
+ visibleWidgets=[]
29
+ for i in range(pa.count()):
30
+ handle = pa.handle(i)
31
+ if handle.isVisible():
32
+ visibleHandles.append(handle)
33
+ widget=pa.widget(i)
34
+ widgets.append(widget)
35
+ if widget.isVisible():
36
+ visibleWidgets.append(widget)
37
+ i=visibleHandles.index(self)
38
+ self.index=widgets.index(visibleWidgets[i])
39
+ """
40
+ width=0
41
+ index=-1
42
+ sizes=pa.splitterSizes
43
+ #sizes=pa.sizes()
44
+ while self.pos().x()>width and index<pa.count()-1:
45
+ index+=1
46
+ w=pa.widget(index)
47
+ if w:
48
+ if w.isVisible():
49
+ width+=sizes[index]+pa.handleWidth()
50
+ self.index=index
51
+ """
52
+ pri.Coding.magenta(f'pos={self.pos().x()} index={self.index}')
53
+
54
+ w=pa.widget(self.index)
55
+ w.setMinimumWidth(pa.minimumSizes[self.index])
56
+ w.widget.setMinimumWidth(pa.minimumSizes[self.index])
57
+ w.setMaximumWidth(pa.maximumSizes[self.index])
58
+ w.widget.setMaximumWidth(pa.maximumSizes[self.index])
59
+
60
+ pri.Coding.magenta(f'{w.widget.TABname} [{pa.minimumSizes[self.index]},{pa.maximumSizes[self.index]}]')
61
+ dwf=w.maximumWidth()-w.minimumWidth()
62
+ pa.splitterReleased([pa.count()-1],[+dwf],FlagReleased=False)
63
+
64
+ self.init_pos=self.pos().x()
65
+ self.limits=[w.minimumWidth()-w.width(),w.maximumWidth()-w.width()]
66
+
67
+ def mouseReleaseEvent(self, event:QMouseEvent):
68
+ super().mouseReleaseEvent(event)
69
+
70
+ TABpar.FlagSettingPar=False
71
+ if self.init_pos:
72
+ pa:PaIRS_QSplitter=self.parent()
73
+ w=pa.widget(self.index)
74
+ dw=self.pos().x()-self.init_pos
75
+ dwf=pa.maximumSizes[self.index]-w.minimumWidth()
76
+ indexes=[self.index,pa.count()-1]
77
+ deltaWidths=[dw,-dwf]
78
+ pa.splitterReleased(indexes,deltaWidths,FlagReleased=True)
79
+
80
+ w.setFixedWidth(pa.splitterSizes[self.index])
81
+ w.widget.setFixedWidth(pa.splitterSizes[self.index])
82
+
83
+ def mouseMoveEvent(self, event: QMouseEvent):
84
+ pa:PaIRS_QSplitter=self.parent()
85
+ #pa.splitterMoving(event.pos().x(),self.index)
86
+
87
+ pa.setSizes(pa.sizes())
88
+
89
+ pos=event.pos().x()
90
+ if pos and self.limits[0] and self.limits[1]:
91
+ pos=max([self.limits[0],pos])
92
+ pos=min([self.limits[1],pos])
93
+ pos+=self.pos().x()+self.width()
94
+
95
+
96
+ bar=pa.scrollArea.horizontalScrollBar()
97
+ val=bar.value()
98
+ wSA=pa.scrollArea.width()
99
+ #pri.Coding.magenta(f'val={val}\t pos={pos}\t wSA={wSA}')
100
+ if pos-val>wSA:
101
+ bar.setValue(pos-wSA)
102
+ elif pos<val:
103
+ bar.setValue(pos)
104
+ return super().mouseMoveEvent(event)
105
+
106
+ def createHandle(self):
107
+ handle =self.PaIRS_ToggleSplitterHandle(self.orientation(), self)
108
+ handle.setCursor(QCursor(Qt.SplitHCursor if self.orientation() == Qt.Horizontal else Qt.SplitVCursor))
109
+ return handle
110
+
111
+ def __init__(self, orientation, parent=None):
112
+ super().__init__(orientation, parent)
113
+ self.setOpaqueResize(False)
114
+ self.FlagInit=False
115
+ self.splitterSizes=[]
116
+ self.minimumSizes=[]
117
+ self.maximumSizes=[]
118
+ self.splitterMaximumSize=0
119
+ self.scrollArea:PaIRS_QScrollArea=None
120
+
121
+ def addWidget(self, widget):
122
+ if not self.FlagInit: i=self.count()
123
+ else: i=self.count()-1
124
+ return self.insertWidget(i,widget)
125
+
126
+ def insertWidget(self, i, widget):
127
+ self.splitterSizes.insert(i,widget.minimumWidth())
128
+ self.minimumSizes.insert(i,widget.minimumWidth())
129
+ self.maximumSizes.insert(i,widget.maximumWidth()+int(self.handleWidth()*0.5))
130
+ self.splitterMaximumSize+=self.minimumSizes[-1]+self.handleWidth()
131
+ widget.setMaximumWidth(widget.minimumWidth())
132
+ return super().insertWidget(i,widget)
133
+
134
+ def replaceWidget(self, i, widget):
135
+ self.splitterMaximumSize-=self.minimumSizes[i]+self.handleWidth()
136
+ self.splitterSizes[i]=widget.minimumWidth()
137
+ self.minimumSizes[i]=widget.minimumWidth()
138
+ self.maximumSizes[i]=widget.maximumWidth()+int(self.handleWidth()*0.5)
139
+ self.splitterMaximumSize+=self.minimumSizes[i]+self.handleWidth()
140
+ widget.setMaximumWidth(widget.minimumWidth())
141
+ return super().replaceWidget(i,widget)
142
+
143
+ def setHandleWidth(self, width: int) -> None:
144
+ self.maximumSizes=[m-int(0.5*self.handleWidth())+int(0.5*width) for m in self.maximumSizes]
145
+ return super().setHandleWidth(width)
146
+
147
+ def splitterReleased(self,indexes,deltaWidths,FlagReleased=True):
148
+ for index,dw in zip(indexes,deltaWidths):
149
+ w=self.widget(index)
150
+ self.splitterSizes[index]=max([min([self.splitterSizes[index]+dw,w.maximumWidth()]),w.minimumWidth()])
151
+ self.splitterResize(FlagReleased=FlagReleased)
152
+ pri.Coding.green(f'i= {indexes}\t dw={deltaWidths}\t Splitter sizes: {self.splitterSizes}')
153
+
154
+ def splitterResize(self,FlagVisible=None,FlagReleased=True):
155
+ width=0
156
+ if FlagReleased: self.splitterSizes[-1]=0
157
+ for i in range(self.count()):
158
+ w=self.widget(i)
159
+ if FlagVisible is not None: flag=FlagVisible[i]
160
+ else: flag=w.isVisible()
161
+ if flag:
162
+ width+=self.splitterSizes[i]+self.handleWidth()
163
+ pa=self.parent().parent()
164
+ if pa.width()>width:
165
+ self.splitterSizes[-1]+=pa.width()-width
166
+ width=pa.width()+self.handleWidth()
167
+ self.setFixedWidth(width)
168
+ self.setSizes(self.splitterSizes)
169
+ if FlagReleased:
170
+ for i in range(self.count()-1):
171
+ w=self.widget(i)
172
+ w.setFixedWidth(self.splitterSizes[i])
173
+ w.widget.setFixedWidth(self.splitterSizes[i])
174
+ return self.splitterSizes
175
+
176
+ def resizeEvent(self,event):
177
+ #self.splitterResize()
178
+ return
179
+
180
+ def setHandleVisibility(self):
181
+ for i in range(self.count()):
182
+ self.handle(i).setVisible(self.widget(i).isVisible())
183
+
184
+ class PaIRS_QScrollArea(QScrollArea):
185
+ def __init__(self,widgets=[],handleWidth=20,margin=0):
186
+ super().__init__()
187
+ self.handleWidth=handleWidth
188
+ self.margin=margin
189
+
190
+ self.setWidgetResizable(True)
191
+ self.container_widget = QWidget()
192
+ self.setWidget(self.container_widget)
193
+ self.main_layout = QVBoxLayout(self.container_widget)
194
+ self.main_layout.setContentsMargins(margin,margin,margin,margin)
195
+
196
+ self.splitter=None
197
+ self.setupSplitter(widgets)
198
+
199
+ def setupSplitter(self,widgets):
200
+ self.frames=[]
201
+ if not widgets:
202
+ return
203
+ if self.splitter:
204
+ self.main_layout.removeWidget(self.splitter)
205
+ self.splitter=splitter=PaIRS_QSplitter(Qt.Horizontal)
206
+ self.splitter.setObjectName('tabArea_splitter')
207
+ self.widgets=widgets
208
+
209
+ dw=0
210
+ # Aggiungi alcuni widget al QSplitter
211
+ for i,w in enumerate(widgets):
212
+ w:gPaIRS_Tab
213
+ w.blockSignals(True)
214
+ frame = QFrame()
215
+ frame_layout = QVBoxLayout(frame)
216
+ frame_layout.setContentsMargins(0,0,0,0)
217
+ frame.setMinimumWidth(w.minimumWidth())
218
+ frame.setMaximumWidth(w.maximumWidth())
219
+ dw+=max([dw,w.maximumWidth()-w.minimumWidth()])
220
+
221
+ objName=f'{w.TABname}_frame'
222
+ frame.setObjectName(objName)
223
+ frame.setStyleSheet(f"""
224
+ QFrame#{objName} {{
225
+ border: 1px solid rgba(128, 128, 128, 0.5);
226
+ border-radius: 15px;
227
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(128, 128, 128, 0), stop:1 rgba(224, 224, 224, 0.25));
228
+ }}
229
+ QWidget#scrollAreaWidgetContents{{
230
+ background: transparent;
231
+ }}
232
+ """)
233
+
234
+ splitter.addWidget(frame)
235
+ splitter.setCollapsible(i,False)
236
+ #if i in (0,3): frame.hide()
237
+ frame_layout.addWidget(w)
238
+ setattr(frame,'widget',w)
239
+ frame.setVisible(False)
240
+ self.frames.append(frame)
241
+ if hasattr(w,'ui') and hasattr(w.ui,'scrollArea'):
242
+ w.ui.scrollArea.setObjectName('scroll_area_'+w.TABname)
243
+ w.blockSignals(False)
244
+
245
+ frame = QFrame()
246
+ objName=f'empty_frame'
247
+ frame.setMinimumWidth(50)
248
+ frame.setMaximumWidth(dw)
249
+
250
+ frame.setObjectName(objName)
251
+ frame.setStyleSheet(f"""
252
+ QFrame#{objName} {{
253
+ border: none;
254
+ background: transparent;
255
+ }}
256
+ """)
257
+ splitter.addWidget(frame)
258
+ frame.setMaximumWidth(dw)
259
+ setattr(frame,'TABname','Empty frame')
260
+ setattr(frame,'widget',frame)
261
+ self.frames.append(frame)
262
+
263
+ splitter.setHandleWidth(self.handleWidth)
264
+ splitter.scrollArea=self
265
+ self.main_layout.addWidget(self.splitter)
266
+
267
+ def resizeEvent(self, event: QResizeEvent):
268
+ self.update()
269
+ total_height = self.viewport().height()
270
+ scrollbar_height = self.horizontalScrollBar().height() if self.horizontalScrollBar().isVisible() else 0
271
+ available_height = total_height - scrollbar_height
272
+ for f,w in zip(self.frames,self.widgets):
273
+ f:QFrame
274
+ available_height=max([available_height,w.minimumHeight()])
275
+ for f,w in zip(self.frames,self.widgets):
276
+ f:QFrame
277
+ f.setMinimumHeight(available_height)
278
+ self.splitter.setMinimumHeight(available_height)
279
+ self.container_widget.setMinimumHeight(available_height+scrollbar_height)
280
+
281
+ return super().resizeEvent(event)
282
+
283
+ class SPLpar(TABpar):
284
+ sizes_default = []
285
+ FlagVisible_default = []
286
+ horizontalBarValues_default = {}
287
+ verticalBarValues_default = {}
288
+ FlagCollapsibleBoxes_default = {}
289
+
290
+ def __init__(self,Process=ProcessTypes.null,Step=StepTypes.null):
291
+ self.setup(Process,Step)
292
+ super().__init__('SPLpar','TabAreaWidget')
293
+ self.unchecked_fields+=[]
294
+
295
+ def setup(self,Process,Step):
296
+ self.Process=Process
297
+ self.Step=Step
298
+ self.sizes=[s for s in SPLpar.sizes_default]
299
+ self.FlagVisible=[f for f in SPLpar.FlagVisible_default]
300
+ self.horizontalBarValues=copy.deepcopy(SPLpar.horizontalBarValues_default)
301
+ self.verticalBarValues=copy.deepcopy(SPLpar.verticalBarValues_default)
302
+ self.FlagCollapsibleBoxes=copy.deepcopy(SPLpar.FlagCollapsibleBoxes_default)
303
+
304
+ class TabAreaWidget(gPaIRS_Tab):
305
+ margin=10
306
+
307
+ buttonSpacing=10
308
+ buttonSize=[40,30]
309
+ iconSize=20
310
+
311
+ widgetMinimumWidth=550
312
+ widgetMaximumWidth=1100
313
+ widgetMinimumHeight=650
314
+ tabAreaMinimumHeight=750
315
+ widgetMaximumHeight=10000
316
+ widgetHorizontalMargin=10
317
+ widgetVerticalMargin=5
318
+ handleWidth=20
319
+
320
+ def __init__(self, parent: QWidget = None, widgets=[],icons=[]):
321
+ super().__init__(parent,UiClass=None,ParClass=SPLpar)
322
+ if __name__ == "__main__":
323
+ iconW = QIcon()
324
+ iconW.addFile(u""+ icons_path +"logo_PaIRS.png", QSize(), QIcon.Normal, QIcon.Off)
325
+ self.setWindowTitle('Tab area widget')
326
+ self.setWindowIcon(iconW)
327
+ self.main_layout=QVBoxLayout()
328
+
329
+ #------------------------------------- Graphical interface: miscellanea
330
+ self.TABname='TabArea'
331
+ m=self.margin
332
+ self.setMinimumWidth(self.widgetMinimumWidth+m*2+self.handleWidth)
333
+ self.tabAreaHeight=self.buttonSize[1]+self.buttonSpacing+self.tabAreaMinimumHeight+m*4
334
+ #self.setMinimumHeight(self.buttonSize[1]+self.buttonSpacing+self.widgetMinimumHeight+m*4)
335
+ self.main_layout.setContentsMargins(m,m,m,m)
336
+ self.main_layout.setSpacing(self.buttonSpacing)
337
+ self.setLayout(self.main_layout)
338
+
339
+ self.buttonBar=QWidget()
340
+ self.buttonBar_layout=QHBoxLayout()
341
+ self.buttonBar_layout.setContentsMargins(0,0,0,0)
342
+ self.buttonBar_layout.setSpacing(self.buttonSpacing)
343
+ self.buttonBar.setLayout(self.buttonBar_layout)
344
+ self.buttonSpacer=QSpacerItem(self.buttonSize[0],self.buttonSize[1],QSizePolicy.Expanding, QSizePolicy.Minimum)
345
+ self.buttonBar_layout.addSpacerItem(self.buttonSpacer)
346
+
347
+ self.scrollArea = PaIRS_QScrollArea(handleWidth=self.handleWidth)
348
+ self.scrollArea.setObjectName('scroll_area_tabArea')
349
+
350
+ self.main_layout.addWidget(self.buttonBar)
351
+ self.main_layout.addWidget(self.scrollArea)
352
+
353
+ #------------------------------------- Declaration of parameters
354
+ self.SPLpar_base=SPLpar()
355
+ self.SPLpar:SPLpar=self.TABpar
356
+ self.SPLpar_old:SPLpar=self.TABpar_old
357
+
358
+ #------------------------------------- Callbacks
359
+ self.buttons=[]
360
+ self.animation = QVariantAnimation(self.scrollArea)
361
+ self.animation.valueChanged.connect(self.moveTo)
362
+ self.scrollArea.horizontalScrollBar().valueChanged.connect(self.finishAnimation)
363
+
364
+ self.setTABlayout=self.setSPLlayout
365
+ self.FlagAddPrev=False
366
+ self.FlagBridge=False
367
+ self.FlagAnimationRunning=False
368
+
369
+ self.setupWid()
370
+ if __name__ == "__main__":
371
+ self.app=app
372
+ setAppGuiPalette(self)
373
+
374
+ self.FlagDisplayControls=False
375
+ self.setupTabArea(widgets,icons)
376
+
377
+ def null(self):
378
+ return True
379
+
380
+ def setupTabArea(self,widgets,icons):
381
+ self.widgets=widgets
382
+ if not widgets: return
383
+ for b in self.buttons:
384
+ b:RichTextPushButton
385
+ self.buttonBar_layout.removeWidget(b)
386
+ b.setParent(None)
387
+ self.buttons=[]
388
+ self.setupButtons(widgets,icons)
389
+ self.scrollArea.setupSplitter(widgets)
390
+ self.scrollArea.splitter.splitterResize=self.splitterResize
391
+
392
+ self.SPLpar.sizes=[w.width() for w in widgets]+[self.scrollArea.splitter.minimumResizeWidth]
393
+ self.SPLpar.FlagVisible=[True for w in widgets]+[True]
394
+ self.SPLpar.horizontalBarValues={}
395
+ self.SPLpar.verticalBarValues={}
396
+
397
+ self.scrollAreas=self.findChildren(QScrollArea)
398
+ self.collapBoxes=[]
399
+ for w in self.widgets:
400
+ w:gPaIRS_Tab
401
+ self.scrollAreas+=w.findChildren(QScrollArea)
402
+ self.scrollAreas+=w.findChildren(QTextEdit)
403
+ self.scrollAreas+=w.findChildren(QTableWidget)
404
+ self.scrollAreas+=w.findChildren(QTreeWidget)
405
+ self.collapBoxes+=w.findChildren(CollapsibleBox)
406
+ for s in self.scrollAreas:
407
+ s:QScrollArea
408
+ if s.objectName()=='': continue
409
+ self.SPLpar.horizontalBarValues[s.objectName()]=s.horizontalScrollBar().value()
410
+ self.SPLpar.verticalBarValues[s.objectName()]=s.verticalScrollBar().value()
411
+ s.horizontalScrollBar().valueChanged.connect(lambda v, scrllr=s: self.updateScrollBarValue(scrllr,True))
412
+ s.verticalScrollBar().valueChanged.connect(lambda v, scrllr=s: self.updateScrollBarValue(scrllr,False))
413
+ for cB in self.collapBoxes:
414
+ cB:CollapsibleBox
415
+ self.SPLpar.FlagCollapsibleBoxes[cB.objectName()]=cB.toggle_button.isChecked()
416
+ cB.toggle_button.clicked.connect(lambda v, cllpbx=cB: self.updateFlagCollapsibleBox(cllpbx))
417
+
418
+ SPLpar.sizes_default=[w.width() for w in widgets]+[self.scrollArea.splitter.minimumResizeWidth]
419
+ SPLpar.FlagVisible_default=[True for w in widgets]+[True]
420
+ for k in self.SPLpar.horizontalBarValues:
421
+ SPLpar.horizontalBarValues_default[k]=0
422
+ for k in self.SPLpar.verticalBarValues:
423
+ SPLpar.verticalBarValues_default[k]=0
424
+ for k in self.SPLpar.FlagCollapsibleBoxes:
425
+ SPLpar.FlagCollapsibleBoxes_default[k]=True
426
+ #self.nullCallback()
427
+ #self.adjustTABparInd()
428
+
429
+ def updateFlagCollapsibleBox(self,collapBox:CollapsibleBox):
430
+ if self.FlagSettingPar: return
431
+ self.SPLpar.FlagCollapsibleBoxes[collapBox.objectName()]=collapBox.toggle_button.isChecked()
432
+ TABpar_ind:SPLpar=self.TABpar_at(self.TABpar.ind)
433
+ if TABpar_ind: TABpar_ind.FlagCollapsibleBoxes[collapBox.objectName()]=collapBox.toggle_button.isChecked()
434
+
435
+ def setFlagCollapsibleBox(self):
436
+ for cB in self.collapBoxes:
437
+ cB:CollapsibleBox
438
+ if cB.objectName() in self.SPLpar.FlagCollapsibleBoxes:
439
+ if self.SPLpar.FlagCollapsibleBoxes[cB.objectName()]!=cB.toggle_button.isChecked():
440
+ cB.toggle_button.setChecked(self.SPLpar.FlagCollapsibleBoxes[cB.objectName()])
441
+ cB.on_click()
442
+
443
+ def updateScrollBarValue(self,scrollArea:QScrollArea=None,flagHorizontal:bool=True):
444
+ if self.FlagAnimationRunning or self.FlagSettingPar: return
445
+ TABpar_ind:SPLpar=self.TABpar_at(self.TABpar.ind)
446
+
447
+ if flagHorizontal:
448
+ pri.Coding.magenta(f'{scrollArea.objectName()} horizontal ScrollBar value: {scrollArea.horizontalScrollBar().value()}')
449
+ self.SPLpar.horizontalBarValues[scrollArea.objectName()]=scrollArea.horizontalScrollBar().value()
450
+ if TABpar_ind: TABpar_ind.horizontalBarValues[scrollArea.objectName()]=scrollArea.horizontalScrollBar().value()
451
+ else:
452
+ pri.Coding.magenta(f'{scrollArea.objectName()} vertical ScrollBar value: {scrollArea.verticalScrollBar().value()}')
453
+ self.SPLpar.verticalBarValues[scrollArea.objectName()]=scrollArea.verticalScrollBar().value()
454
+ if TABpar_ind: TABpar_ind.verticalBarValues[scrollArea.objectName()]=scrollArea.verticalScrollBar().value()
455
+
456
+ def setScrollBarValues(self):
457
+ for s in self.scrollAreas:
458
+ s:QScrollArea
459
+ if s.objectName() in self.SPLpar.horizontalBarValues:
460
+ if self.SPLpar.horizontalBarValues[s.objectName()]!=s.horizontalScrollBar().value():
461
+ s.horizontalScrollBar().setValue(self.SPLpar.horizontalBarValues[s.objectName()])
462
+ if s.objectName() in self.SPLpar.verticalBarValues:
463
+ if self.SPLpar.verticalBarValues[s.objectName()]!=s.verticalScrollBar().value():
464
+ s.verticalScrollBar().setValue(self.SPLpar.verticalBarValues[s.objectName()])
465
+
466
+ def setupButtons(self,widgets,icons):
467
+ self.buttonBar_layout.removeItem(self.buttonSpacer)
468
+
469
+ mh=self.widgetHorizontalMargin
470
+ mv=self.widgetVerticalMargin
471
+ for w,icon,index in zip(widgets,icons,range(len(widgets))):
472
+ b=RichTextPushButton(self.buttonBar)
473
+ b.lyt.setStretch(0,1)
474
+ b.lyt.setStretch(1,0)
475
+ b.setFixedSize(self.buttonSize[0],self.buttonSize[1])
476
+ b.setStyleSheet(f"""
477
+ RichTextPushButton {{
478
+ border: 1px solid rgba(128, 128, 128, 0.5);
479
+ border-radius: 5px;
480
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgba(128, 128, 128, 0), stop:1 rgba(224, 224, 224, 0.25));
481
+ }}
482
+ """)
483
+ b.setCursor(Qt.CursorShape.PointingHandCursor)
484
+
485
+ w:Input_Tab
486
+ if hasattr(w,'ui'):
487
+ if hasattr(w.ui,'name_tab'):
488
+ b.setToolTip(w.ui.name_tab.text().replace(' ',''))
489
+ b.setStatusTip(w.ui.name_tab.text().replace(' ',''))
490
+ if hasattr(w.ui,'scrollArea') and not self.scrollArea.styleSheet():
491
+ self.scrollArea.setStyleSheet(w.ui.scrollArea.styleSheet())
492
+ b.setIcon(QIcon(icons_path+icon+'.png'))
493
+ b.setIconSize(QSize(self.iconSize,self.iconSize))
494
+
495
+ self.buttonBar_layout.addWidget(b)
496
+ b.setVisible(False)
497
+ self.buttons.append(b)
498
+ w.buttonTab=b
499
+
500
+ def defineButtonAction():
501
+ butt=b
502
+ wid=w
503
+ i=index
504
+ return lambda: self.buttonAction(butt,wid,i,self.scrollArea)
505
+ b.clicked.connect(defineButtonAction())
506
+ setattr(w,'buttonAction',defineButtonAction())
507
+
508
+ def defineCloseTabAction():
509
+ butt=b
510
+ return lambda: self.closeTabAction(butt)
511
+ w.ui.button_close_tab.clicked.connect(defineCloseTabAction())
512
+
513
+ #pri.Coding.red(f"{w.ui.name_tab.text()}\t\t width: min={w.minimumWidth()}, max={w.maximumWidth()}\t height: min={w.minimumHeight()}, max={w.maximumHeight()}")
514
+ w.setContentsMargins(mh,mv,mh,mv)
515
+ w.setMinimumWidth(max([self.widgetMinimumWidth,w.minimumWidth()]))
516
+ w.setMaximumWidth(max([self.widgetMaximumWidth,w.maximumWidth()]))
517
+ w.setMinimumHeight(self.widgetMinimumHeight)
518
+ w.setMaximumHeight(self.widgetMaximumHeight)
519
+
520
+ self.buttonBar_layout.addItem(self.buttonSpacer)
521
+
522
+ def buttonAction(self,b:RichTextPushButton,widget:gPaIRS_Tab,index:int,scrollArea:PaIRS_QScrollArea):
523
+ self.openTabAction(b)
524
+ barValue_end=-int(0.5*scrollArea.splitter.handleWidth())
525
+ for i in range(index):
526
+ w=scrollArea.splitter.widget(i)
527
+ if w.isVisible():
528
+ barValue_end+=scrollArea.splitter.splitterSizes[i]+scrollArea.splitter.handleWidth()
529
+ if barValue_end!=self.scrollArea.horizontalScrollBar().value():
530
+ self.startAnimation(barValue_end)
531
+ else:
532
+ self.finishAnimation()
533
+ return
534
+
535
+ def startAnimation(self,v):
536
+ self.FlagAnimationRunning=True
537
+ self.animation.stop()
538
+ self.animation.setStartValue(self.scrollArea.horizontalScrollBar().value())
539
+ self.animation.setEndValue(v)
540
+ self.animation.setDuration(time_ScrollBar)
541
+ self.animation.finished.connect(self.finishAnimation)
542
+ self.animation.start()
543
+
544
+ def finishAnimation(self):
545
+ self.FlagAnimationRunning=False
546
+ self.updateScrollBarValue(self.scrollArea,flagHorizontal=True)
547
+
548
+ def moveTo(self, i):
549
+ self.scrollArea.horizontalScrollBar().setValue(i)
550
+
551
+ def openTabAction(self,b:RichTextPushButton):
552
+ self.SPLpar.FlagVisible[self.buttons.index(b)]=True
553
+ self.nullCallback(f'Open {b.toolTip()} tab')
554
+ #self.adjustTABparInd()
555
+
556
+ def closeTabAction(self,b:RichTextPushButton):
557
+ self.SPLpar.FlagVisible[self.buttons.index(b)]=False
558
+ self.nullCallback(f'Close {b.toolTip()} tab')
559
+ #self.adjustTABparInd()
560
+
561
+ def setSPLlayout(self):
562
+ #self.setUpdatesEnabled(False)
563
+ #if self.SPLpar.sizes!=self.scrollArea.splitter.splitterSizes:
564
+ self.scrollArea.splitter.splitterSizes=[s for s in self.SPLpar.sizes]
565
+ PaIRS_QSplitter.splitterResize(self.scrollArea.splitter,self.SPLpar.FlagVisible)
566
+ #if self.SPLpar_old.isDifferentFrom(self.SPLpar,fields=['FlagVisible']):
567
+ for w,b,f in zip(self.widgets,self.buttons,self.SPLpar.FlagVisible):
568
+ w:QWidget
569
+ w.parent().setVisible(f)
570
+ b:RichTextPushButton
571
+ b.setText('')
572
+ if not f:
573
+ fPixSize=b.font().pixelSize()
574
+ s=f'<sup><span style=" font-size:{fPixSize-2}px"> 🔒</span></sup>'
575
+ b.setText(s)
576
+
577
+ #if self.SPLpar_old.barValue!=self.SPLpar.barValue:
578
+ #self.scrollArea.horizontalScrollBar().setValue(self.SPLpar.barValue)
579
+ self.scrollArea.horizontalScrollBar().setMaximum(self.scrollArea.splitter.width()-self.scrollArea.width())
580
+ self.setScrollBarValues()
581
+ self.setFlagCollapsibleBox()
582
+
583
+ #self.setUpdatesEnabled(True)
584
+ #self.parent().hide()
585
+ #self.hide()
586
+ self.parent().updateGeometry()
587
+ self.updateGeometry()
588
+ #self.show()
589
+ #self.parent().show()
590
+ return
591
+
592
+ def splitterResize(self,FlagVisible=None,FlagReleased=True):
593
+ splitterSizes=PaIRS_QSplitter.splitterResize(self.scrollArea.splitter,FlagVisible,FlagReleased)
594
+ if FlagReleased:
595
+ self.SPLpar.sizes=[s for s in splitterSizes]
596
+ self.finishAnimation()
597
+
598
+
599
+ if __name__ == "__main__":
600
+ app = QApplication(sys.argv)
601
+ app.setStyle('Fusion')
602
+
603
+ tabAreaWidget=TabAreaWidget()
604
+ icons=['import_logo','export_logo','process_icon','terminal','vect_field']
605
+ tabs=[Input_Tab,Output_Tab,Process_Tab,Log_Tab,Vis_Tab]
606
+ widgets=[None]*len(tabs)
607
+ for i in range(len(tabs)):
608
+ widgets[i]=tabs[i](tabAreaWidget,False)
609
+ #tabAreaWidget.resize(1050,0)
610
+ tabAreaWidget.setupTabArea(widgets,icons)
611
+ tabAreaWidget.show()
612
+ sys.exit(app.exec())