src/eric7/EricWidgets/EricSideBar.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2008 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a sidebar class.
8 """
9
10 import enum
11 import json
12
13 from PyQt6.QtCore import pyqtSlot, Qt, QSize
14 from PyQt6.QtWidgets import QWidget, QStackedWidget, QBoxLayout
15
16 from .EricIconBar import EricIconBar
17
18
19 class EricSideBarSide(enum.Enum):
20 """
21 Class defining the sidebar sides.
22 """
23 NORTH = 0
24 EAST = 1
25 SOUTH = 2
26 WEST = 3
27
28
29 class EricSideBar(QWidget):
30 """
31 Class implementing a sidebar with a widget area, that is hidden or shown,
32 if the current tab is clicked again.
33 """
34 Version = 4
35
36 def __init__(self, orientation=None,
37 iconBarSize=EricIconBar.DefaultBarSize, parent=None):
38 """
39 Constructor
40
41 @param orientation orientation of the sidebar widget
42 @type EricSideBarSide
43 @param iconBarSize size category for the bar (one of 'xs', 'sm', 'md',
44 'lg', 'xl', 'xxl')
45 @type str
46 @param parent parent widget
47 @type QWidget
48 """
49 super().__init__(parent)
50
51 # initial layout is done for NORTH
52 self.__iconBar = EricIconBar(orientation=Qt.Orientation.Horizontal,
53 barSize=iconBarSize)
54
55 self.__stackedWidget = QStackedWidget(self)
56 self.__stackedWidget.setContentsMargins(0, 0, 0, 0)
57
58 self.layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
59 self.layout.setContentsMargins(0, 0, 0, 0)
60 self.layout.setSpacing(3)
61 self.layout.addWidget(self.__iconBar)
62 self.layout.addWidget(self.__stackedWidget)
63 self.setLayout(self.layout)
64
65 self.__minimized = False
66 self.__minSize = 0
67 self.__maxSize = 0
68 self.__bigSize = QSize()
69
70 self.__hasFocus = False
71 # flag storing if this widget or any child has the focus
72 self.__autoHide = False
73
74 self.__orientation = EricSideBarSide.NORTH
75 if orientation is None:
76 orientation = EricSideBarSide.NORTH
77 self.setOrientation(orientation)
78
79 self.__iconBar.currentChanged.connect(
80 self.__stackedWidget.setCurrentIndex)
81 self.__iconBar.currentChanged.connect(
82 self.__currentIconChanged)
83 self.__iconBar.currentClicked.connect(
84 self.__currentIconClicked)
85
86 def __shrinkIt(self):
87 """
88 Private method to shrink the sidebar.
89 """
90 self.__minimized = True
91 self.__bigSize = self.size()
92 if self.__orientation in (
93 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
94 ):
95 self.__minSize = self.minimumSizeHint().height()
96 self.__maxSize = self.maximumHeight()
97 else:
98 self.__minSize = self.minimumSizeHint().width()
99 self.__maxSize = self.maximumWidth()
100
101 self.__stackedWidget.hide()
102
103 if self.__orientation in (
104 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
105 ):
106 self.setFixedHeight(self.__iconBar.minimumSizeHint().height())
107 else:
108 self.setFixedWidth(self.__iconBar.minimumSizeHint().width())
109
110 def __expandIt(self):
111 """
112 Private method to expand the sidebar.
113 """
114 self.__minimized = False
115 self.__stackedWidget.show()
116 self.resize(self.__bigSize)
117 if self.__orientation in (
118 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
119 ):
120 minSize = max(self.__minSize, self.minimumSizeHint().height())
121 self.setMinimumHeight(minSize)
122 self.setMaximumHeight(self.__maxSize)
123 else:
124 minSize = max(self.__minSize, self.minimumSizeHint().width())
125 self.setMinimumWidth(minSize)
126 self.setMaximumWidth(self.__maxSize)
127
128 def isMinimized(self):
129 """
130 Public method to check the minimized state.
131
132 @return flag indicating the minimized state (boolean)
133 """
134 return self.__minimized
135
136 @pyqtSlot(int)
137 def __currentIconChanged(self, index):
138 """
139 Private slot to handle a change of the current icon.
140
141 @param index index of the current icon
142 @type int
143 """
144 if self.isMinimized():
145 self.__expandIt()
146
147 @pyqtSlot(int)
148 def __currentIconClicked(self, index):
149 """
150 Private slot to handle a click of the current icon.
151
152 @param index index of the clicked icon
153 @type int
154 """
155 if self.isMinimized():
156 self.__expandIt()
157 else:
158 self.__shrinkIt()
159
160 def addTab(self, widget, icon, label=None):
161 """
162 Public method to add a tab to the sidebar.
163
164 @param widget reference to the widget to add
165 @type QWidget
166 @param icon reference to the icon of the widget
167 @type QIcon
168 @param label the label text of the widget
169 @type str
170 """
171 self.__iconBar.addIcon(icon, label)
172 self.__stackedWidget.addWidget(widget)
173 if self.__orientation in (
174 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
175 ):
176 self.__minSize = self.minimumSizeHint().height()
177 else:
178 self.__minSize = self.minimumSizeHint().width()
179
180 def insertTab(self, index, widget, icon, label=None):
181 """
182 Public method to insert a tab into the sidebar.
183
184 @param index the index to insert the tab at
185 @type int
186 @param widget reference to the widget to insert
187 @type QWidget
188 @param icon reference to the icon of the widget
189 @type QIcon
190 @param label the label text of the widget
191 @type str
192 """
193 self.__iconBar.insertIcon(index, icon, label)
194
195 self.__stackedWidget.insertWidget(index, widget)
196 if self.__orientation in (
197 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
198 ):
199 self.__minSize = self.minimumSizeHint().height()
200 else:
201 self.__minSize = self.minimumSizeHint().width()
202
203 def removeTab(self, index):
204 """
205 Public method to remove a tab.
206
207 @param index the index of the tab to remove
208 @type int
209 """
210 self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index))
211 self.__iconBar.removeIcon(index)
212 if self.__orientation in (
213 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
214 ):
215 self.__minSize = self.minimumSizeHint().height()
216 else:
217 self.__minSize = self.minimumSizeHint().width()
218
219 def clear(self):
220 """
221 Public method to remove all tabs.
222 """
223 while self.count() > 0:
224 self.removeTab(0)
225
226 def prevTab(self):
227 """
228 Public slot used to show the previous tab.
229 """
230 ind = self.currentIndex() - 1
231 if ind == -1:
232 ind = self.count() - 1
233
234 self.setCurrentIndex(ind)
235 self.currentWidget().setFocus()
236
237 def nextTab(self):
238 """
239 Public slot used to show the next tab.
240 """
241 ind = self.currentIndex() + 1
242 if ind == self.count():
243 ind = 0
244
245 self.setCurrentIndex(ind)
246 self.currentWidget().setFocus()
247
248 def count(self):
249 """
250 Public method to get the number of tabs.
251
252 @return number of tabs in the sidebar (integer)
253 """
254 return self.__iconBar.count()
255
256 def currentIndex(self):
257 """
258 Public method to get the index of the current tab.
259
260 @return index of the current tab (integer)
261 """
262 return self.__stackedWidget.currentIndex()
263
264 def setCurrentIndex(self, index):
265 """
266 Public slot to set the current index.
267
268 @param index the index to set as the current index (integer)
269 """
270 self.__iconBar.setCurrentIndex(index)
271 self.__stackedWidget.setCurrentIndex(index)
272 if self.isMinimized():
273 self.__expandIt()
274
275 def currentWidget(self):
276 """
277 Public method to get a reference to the current widget.
278
279 @return reference to the current widget (QWidget)
280 """
281 return self.__stackedWidget.currentWidget()
282
283 def setCurrentWidget(self, widget):
284 """
285 Public slot to set the current widget.
286
287 @param widget reference to the widget to become the current widget
288 (QWidget)
289 """
290 self.__stackedWidget.setCurrentWidget(widget)
291 self.__iconBar.setCurrentIndex(self.__stackedWidget.currentIndex())
292 if self.isMinimized():
293 self.__expandIt()
294
295 def indexOf(self, widget):
296 """
297 Public method to get the index of the given widget.
298
299 @param widget reference to the widget to get the index of (QWidget)
300 @return index of the given widget (integer)
301 """
302 return self.__stackedWidget.indexOf(widget)
303
304 def orientation(self):
305 """
306 Public method to get the orientation of the sidebar.
307
308 @return orientation of the sidebar
309 @rtype EricSideBarSide
310 """
311 return self.__orientation
312
313 def setOrientation(self, orient):
314 """
315 Public method to set the orientation of the sidebar.
316
317 @param orient orientation of the sidebar
318 @type EricSideBarSide
319 """
320 if orient == EricSideBarSide.NORTH:
321 self.__iconBar.setOrientation(Qt.Orientation.Horizontal)
322 self.layout.setDirection(QBoxLayout.Direction.TopToBottom)
323 elif orient == EricSideBarSide.EAST:
324 self.__iconBar.setOrientation(Qt.Orientation.Vertical)
325 self.layout.setDirection(QBoxLayout.Direction.RightToLeft)
326 elif orient == EricSideBarSide.SOUTH:
327 self.__iconBar.setOrientation(Qt.Orientation.Horizontal)
328 self.layout.setDirection(QBoxLayout.Direction.BottomToTop)
329 elif orient == EricSideBarSide.WEST:
330 self.__iconBar.setOrientation(Qt.Orientation.Vertical)
331 self.layout.setDirection(QBoxLayout.Direction.LeftToRight)
332 self.__orientation = orient
333
334 def widget(self, index):
335 """
336 Public method to get a reference to the widget associated with a tab.
337
338 @param index index of the tab (integer)
339 @return reference to the widget (QWidget)
340 """
341 return self.__stackedWidget.widget(index)
342
343 def setIconBarColor(self, color):
344 """
345 Public method to set the icon bar color.
346
347 @param color icon bar color
348 @type QColor
349 """
350 self.__iconBar.setColor(color)
351
352 def iconBarColor(self):
353 """
354 Public method to get the icon bar color.
355
356 @return icon bar color
357 @rtype QColor
358 """
359 return self.__iconBar.color()
360
361 def setIconBarSize(self, barSize):
362 """
363 Public method to set the icon bar size.
364
365 @param barSize size category for the bar (one of 'xs', 'sm', 'md',
366 'lg', 'xl', 'xxl')
367 @type str
368 """
369 self.__iconBar.setBarSize(barSize)
370 if self.isMinimized():
371 self.__shrinkIt()
372 else:
373 self.__expandIt()
374
375 def barSize(self):
376 """
377 Public method to get the icon bar size.
378
379 @return barSize size category for the bar (one of 'xs', 'sm', 'md',
380 'lg', 'xl', 'xxl')
381 @rtype str
382 """
383 return self.__iconBar.barSize()
384
385 def saveState(self):
386 """
387 Public method to save the state of the sidebar.
388
389 @return saved state as a byte array (QByteArray)
390 """
391 self.__bigSize = self.size()
392 if self.__orientation in (
393 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
394 ):
395 self.__minSize = self.minimumSizeHint().height()
396 self.__maxSize = self.maximumHeight()
397 else:
398 self.__minSize = self.minimumSizeHint().width()
399 self.__maxSize = self.maximumWidth()
400
401 dataDict = {
402 "version": self.Version,
403 "minimized": self.__minimized,
404 "big_size": [self.__bigSize.width(), self.__bigSize.height()],
405 "min_size": self.__minSize,
406 "max_size": self.__maxSize,
407 }
408 data = json.dumps(dataDict)
409
410 return data
411
412 def restoreState(self, state):
413 """
414 Public method to restore the state of the sidebar.
415
416 @param state byte array containing the saved state (QByteArray)
417 @return flag indicating success (boolean)
418 """
419 if not isinstance(state, str) or state == "":
420 return False
421
422 try:
423 stateDict = json.loads(state)
424 except json.JSONDecodeError:
425 return False
426
427 if not stateDict:
428 return False
429
430 if self.__orientation in (
431 EricSideBarSide.NORTH, EricSideBarSide.SOUTH
432 ):
433 minSize = self.layout.minimumSize().height()
434 maxSize = self.maximumHeight()
435 else:
436 minSize = self.layout.minimumSize().width()
437 maxSize = self.maximumWidth()
438
439 if stateDict["version"] in (2, 3, 4):
440 if stateDict["minimized"] and not self.__minimized:
441 self.__shrinkIt()
442
443 self.__bigSize = QSize(*stateDict["big_size"])
444 self.__minSize = max(stateDict["min_size"], minSize)
445 self.__maxSize = max(stateDict["max_size"], maxSize)
446
447 if not stateDict["minimized"]:
448 self.__expandIt()
449
450 return True
451
452 return False

eric ide

mercurial