PaIRS-UniNa 0.2.5__cp312-cp312-win_amd64.whl → 0.2.8__cp312-cp312-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 (54) hide show
  1. PaIRS_UniNa/Changes.txt +45 -2
  2. PaIRS_UniNa/Explorer.py +3126 -3059
  3. PaIRS_UniNa/FolderLoop.py +561 -371
  4. PaIRS_UniNa/Input_Tab.py +826 -714
  5. PaIRS_UniNa/Input_Tab_CalVi.py +15 -17
  6. PaIRS_UniNa/Input_Tab_tools.py +3019 -3017
  7. PaIRS_UniNa/Output_Tab.py +2 -4
  8. PaIRS_UniNa/PaIRS.py +17 -17
  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/Saving_tools.py +277 -277
  13. PaIRS_UniNa/TabTools.py +7 -4
  14. PaIRS_UniNa/Vis_Tab.py +129 -60
  15. PaIRS_UniNa/Whatsnew.py +15 -3
  16. PaIRS_UniNa/_PaIRS_PIV.pyd +0 -0
  17. PaIRS_UniNa/__init__.py +4 -4
  18. PaIRS_UniNa/addwidgets_ps.py +28 -20
  19. PaIRS_UniNa/calibView.py +7 -0
  20. PaIRS_UniNa/gPaIRS.py +3889 -3745
  21. PaIRS_UniNa/icons/flaticon_PaIRS_download_warning.png +0 -0
  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/pencil_bw.png +0 -0
  25. PaIRS_UniNa/icons/scan_path_loop.png +0 -0
  26. PaIRS_UniNa/icons/scan_path_loop_off.png +0 -0
  27. PaIRS_UniNa/listLib.py +301 -301
  28. PaIRS_UniNa/parForMulti.py +433 -433
  29. PaIRS_UniNa/pivParFor.py +1 -1
  30. PaIRS_UniNa/procTools.py +51 -3
  31. PaIRS_UniNa/rqrdpckgs.txt +6 -5
  32. PaIRS_UniNa/stereoPivParFor.py +1 -1
  33. PaIRS_UniNa/tabSplitter.py +606 -606
  34. PaIRS_UniNa/ui_Calibration_Tab.py +542 -542
  35. PaIRS_UniNa/ui_Custom_Top.py +294 -294
  36. PaIRS_UniNa/ui_Input_Tab.py +1098 -1098
  37. PaIRS_UniNa/ui_Input_Tab_CalVi.py +1280 -1280
  38. PaIRS_UniNa/ui_Log_Tab.py +261 -261
  39. PaIRS_UniNa/ui_Output_Tab.py +2360 -2360
  40. PaIRS_UniNa/ui_Process_Tab.py +3808 -3808
  41. PaIRS_UniNa/ui_Process_Tab_CalVi.py +1547 -1547
  42. PaIRS_UniNa/ui_Process_Tab_Disp.py +1139 -1139
  43. PaIRS_UniNa/ui_Process_Tab_Min.py +435 -435
  44. PaIRS_UniNa/ui_ResizePopup.py +203 -203
  45. PaIRS_UniNa/ui_Vis_Tab.py +1626 -1626
  46. PaIRS_UniNa/ui_Vis_Tab_CalVi.py +1249 -1249
  47. PaIRS_UniNa/ui_Whatsnew.py +131 -131
  48. PaIRS_UniNa/ui_gPairs.py +873 -867
  49. PaIRS_UniNa/ui_infoPaIRS.py +550 -550
  50. PaIRS_UniNa/whatsnew.txt +4 -4
  51. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.8.dist-info}/METADATA +31 -17
  52. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.8.dist-info}/RECORD +54 -48
  53. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.8.dist-info}/WHEEL +0 -0
  54. {pairs_unina-0.2.5.dist-info → pairs_unina-0.2.8.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())