19 class EricWheelTabBar(QTabBar): |
19 class EricWheelTabBar(QTabBar): |
20 """ |
20 """ |
21 Class implementing a tab bar class substituting QTabBar to support wheel |
21 Class implementing a tab bar class substituting QTabBar to support wheel |
22 events. |
22 events. |
23 """ |
23 """ |
|
24 |
24 def __init__(self, parent=None): |
25 def __init__(self, parent=None): |
25 """ |
26 """ |
26 Constructor |
27 Constructor |
27 |
28 |
28 @param parent reference to the parent widget (QWidget) |
29 @param parent reference to the parent widget (QWidget) |
29 """ |
30 """ |
30 super().__init__(parent) |
31 super().__init__(parent) |
31 self._tabWidget = parent |
32 self._tabWidget = parent |
32 |
33 |
33 def wheelEvent(self, event): |
34 def wheelEvent(self, event): |
34 """ |
35 """ |
35 Protected slot to support wheel events. |
36 Protected slot to support wheel events. |
36 |
37 |
37 @param event reference to the wheel event (QWheelEvent) |
38 @param event reference to the wheel event (QWheelEvent) |
38 """ |
39 """ |
39 with contextlib.suppress(AttributeError): |
40 with contextlib.suppress(AttributeError): |
40 delta = event.angleDelta().y() |
41 delta = event.angleDelta().y() |
41 if delta > 0: |
42 if delta > 0: |
42 self._tabWidget.prevTab() |
43 self._tabWidget.prevTab() |
43 elif delta < 0: |
44 elif delta < 0: |
44 self._tabWidget.nextTab() |
45 self._tabWidget.nextTab() |
45 |
46 |
46 event.accept() |
47 event.accept() |
47 |
48 |
48 |
49 |
49 class EricDnDTabBar(EricWheelTabBar): |
50 class EricDnDTabBar(EricWheelTabBar): |
50 """ |
51 """ |
51 Class implementing a tab bar class substituting QTabBar. |
52 Class implementing a tab bar class substituting QTabBar. |
52 |
53 |
53 @signal tabMoveRequested(int, int) emitted to signal a tab move request |
54 @signal tabMoveRequested(int, int) emitted to signal a tab move request |
54 giving the old and new index position |
55 giving the old and new index position |
55 """ |
56 """ |
|
57 |
56 tabMoveRequested = pyqtSignal(int, int) |
58 tabMoveRequested = pyqtSignal(int, int) |
57 |
59 |
58 def __init__(self, parent=None): |
60 def __init__(self, parent=None): |
59 """ |
61 """ |
60 Constructor |
62 Constructor |
61 |
63 |
62 @param parent reference to the parent widget (QWidget) |
64 @param parent reference to the parent widget (QWidget) |
63 """ |
65 """ |
64 EricWheelTabBar.__init__(self, parent) |
66 EricWheelTabBar.__init__(self, parent) |
65 self.setAcceptDrops(True) |
67 self.setAcceptDrops(True) |
66 |
68 |
67 self.__dragStartPos = QPoint() |
69 self.__dragStartPos = QPoint() |
68 |
70 |
69 def mousePressEvent(self, event): |
71 def mousePressEvent(self, event): |
70 """ |
72 """ |
71 Protected method to handle mouse press events. |
73 Protected method to handle mouse press events. |
72 |
74 |
73 @param event reference to the mouse press event (QMouseEvent) |
75 @param event reference to the mouse press event (QMouseEvent) |
74 """ |
76 """ |
75 if event.button() == Qt.MouseButton.LeftButton: |
77 if event.button() == Qt.MouseButton.LeftButton: |
76 self.__dragStartPos = QPoint(event.position().toPoint()) |
78 self.__dragStartPos = QPoint(event.position().toPoint()) |
77 EricWheelTabBar.mousePressEvent(self, event) |
79 EricWheelTabBar.mousePressEvent(self, event) |
78 |
80 |
79 def mouseMoveEvent(self, event): |
81 def mouseMoveEvent(self, event): |
80 """ |
82 """ |
81 Protected method to handle mouse move events. |
83 Protected method to handle mouse move events. |
82 |
84 |
83 @param event reference to the mouse move event (QMouseEvent) |
85 @param event reference to the mouse move event (QMouseEvent) |
84 """ |
86 """ |
85 if ( |
87 if ( |
86 event.buttons() == Qt.MouseButton.LeftButton and |
88 event.buttons() == Qt.MouseButton.LeftButton |
87 (event.position().toPoint() - self.__dragStartPos) |
89 and (event.position().toPoint() - self.__dragStartPos).manhattanLength() |
88 .manhattanLength() > QApplication.startDragDistance() |
90 > QApplication.startDragDistance() |
89 ): |
91 ): |
90 drag = QDrag(self) |
92 drag = QDrag(self) |
91 mimeData = QMimeData() |
93 mimeData = QMimeData() |
92 index = self.tabAt(event.position().toPoint()) |
94 index = self.tabAt(event.position().toPoint()) |
93 mimeData.setText(self.tabText(index)) |
95 mimeData.setText(self.tabText(index)) |
94 mimeData.setData("action", b"tab-reordering") |
96 mimeData.setData("action", b"tab-reordering") |
95 mimeData.setData("tabbar-id", str(id(self)).encode("utf-8")) |
97 mimeData.setData("tabbar-id", str(id(self)).encode("utf-8")) |
96 drag.setMimeData(mimeData) |
98 drag.setMimeData(mimeData) |
97 drag.exec() |
99 drag.exec() |
98 EricWheelTabBar.mouseMoveEvent(self, event) |
100 EricWheelTabBar.mouseMoveEvent(self, event) |
99 |
101 |
100 def dragEnterEvent(self, event): |
102 def dragEnterEvent(self, event): |
101 """ |
103 """ |
102 Protected method to handle drag enter events. |
104 Protected method to handle drag enter events. |
103 |
105 |
104 @param event reference to the drag enter event (QDragEnterEvent) |
106 @param event reference to the drag enter event (QDragEnterEvent) |
105 """ |
107 """ |
106 mimeData = event.mimeData() |
108 mimeData = event.mimeData() |
107 formats = mimeData.formats() |
109 formats = mimeData.formats() |
108 if ( |
110 if ( |
109 "action" in formats and |
111 "action" in formats |
110 mimeData.data("action") == b"tab-reordering" and |
112 and mimeData.data("action") == b"tab-reordering" |
111 "tabbar-id" in formats and |
113 and "tabbar-id" in formats |
112 int(mimeData.data("tabbar-id")) == id(self) |
114 and int(mimeData.data("tabbar-id")) == id(self) |
113 ): |
115 ): |
114 event.acceptProposedAction() |
116 event.acceptProposedAction() |
115 EricWheelTabBar.dragEnterEvent(self, event) |
117 EricWheelTabBar.dragEnterEvent(self, event) |
116 |
118 |
117 def dropEvent(self, event): |
119 def dropEvent(self, event): |
118 """ |
120 """ |
119 Protected method to handle drop events. |
121 Protected method to handle drop events. |
120 |
122 |
121 @param event reference to the drop event (QDropEvent) |
123 @param event reference to the drop event (QDropEvent) |
122 """ |
124 """ |
123 fromIndex = self.tabAt(self.__dragStartPos) |
125 fromIndex = self.tabAt(self.__dragStartPos) |
124 toIndex = self.tabAt(event.position().toPoint()) |
126 toIndex = self.tabAt(event.position().toPoint()) |
125 if fromIndex != toIndex: |
127 if fromIndex != toIndex: |
129 |
131 |
130 |
132 |
131 class EricTabWidget(QTabWidget): |
133 class EricTabWidget(QTabWidget): |
132 """ |
134 """ |
133 Class implementing a tab widget class substituting QTabWidget. |
135 Class implementing a tab widget class substituting QTabWidget. |
134 |
136 |
135 It provides slots to show the previous and next tab and give |
137 It provides slots to show the previous and next tab and give |
136 them the input focus and it allows to have a context menu for the tabs. |
138 them the input focus and it allows to have a context menu for the tabs. |
137 |
139 |
138 @signal customTabContextMenuRequested(const QPoint & point, int index) |
140 @signal customTabContextMenuRequested(const QPoint & point, int index) |
139 emitted when a context menu for a tab is requested |
141 emitted when a context menu for a tab is requested |
140 """ |
142 """ |
|
143 |
141 customTabContextMenuRequested = pyqtSignal(QPoint, int) |
144 customTabContextMenuRequested = pyqtSignal(QPoint, int) |
142 |
145 |
143 def __init__(self, parent=None, dnd=False): |
146 def __init__(self, parent=None, dnd=False): |
144 """ |
147 """ |
145 Constructor |
148 Constructor |
146 |
149 |
147 @param parent reference to the parent widget (QWidget) |
150 @param parent reference to the parent widget (QWidget) |
148 @param dnd flag indicating the support for Drag & Drop (boolean) |
151 @param dnd flag indicating the support for Drag & Drop (boolean) |
149 """ |
152 """ |
150 super().__init__(parent) |
153 super().__init__(parent) |
151 |
154 |
152 if dnd: |
155 if dnd: |
153 if not hasattr(self, 'setMovable'): |
156 if not hasattr(self, "setMovable"): |
154 self.__tabBar = EricDnDTabBar(self) |
157 self.__tabBar = EricDnDTabBar(self) |
155 self.__tabBar.tabMoveRequested.connect(self.moveTab) |
158 self.__tabBar.tabMoveRequested.connect(self.moveTab) |
156 self.setTabBar(self.__tabBar) |
159 self.setTabBar(self.__tabBar) |
157 else: |
160 else: |
158 self.__tabBar = EricWheelTabBar(self) |
161 self.__tabBar = EricWheelTabBar(self) |
159 self.setTabBar(self.__tabBar) |
162 self.setTabBar(self.__tabBar) |
160 self.setMovable(True) |
163 self.setMovable(True) |
161 else: |
164 else: |
162 self.__tabBar = EricWheelTabBar(self) |
165 self.__tabBar = EricWheelTabBar(self) |
163 self.setTabBar(self.__tabBar) |
166 self.setTabBar(self.__tabBar) |
164 |
167 |
165 self.__lastCurrentIndex = -1 |
168 self.__lastCurrentIndex = -1 |
166 self.__currentIndex = -1 |
169 self.__currentIndex = -1 |
167 self.currentChanged.connect(self.__currentChanged) |
170 self.currentChanged.connect(self.__currentChanged) |
168 |
171 |
169 def setCustomTabBar(self, dnd, tabBar): |
172 def setCustomTabBar(self, dnd, tabBar): |
170 """ |
173 """ |
171 Public method to set a custom tab bar. |
174 Public method to set a custom tab bar. |
172 |
175 |
173 @param dnd flag indicating the support for Drag & Drop (boolean) |
176 @param dnd flag indicating the support for Drag & Drop (boolean) |
174 @param tabBar reference to the tab bar to set (QTabBar) |
177 @param tabBar reference to the tab bar to set (QTabBar) |
175 """ |
178 """ |
176 self.__tabBar = tabBar |
179 self.__tabBar = tabBar |
177 self.setTabBar(self.__tabBar) |
180 self.setTabBar(self.__tabBar) |
178 if dnd: |
181 if dnd: |
179 if isinstance(tabBar, EricDnDTabBar): |
182 if isinstance(tabBar, EricDnDTabBar): |
180 self.__tabBar.tabMoveRequested.connect(self.moveTab) |
183 self.__tabBar.tabMoveRequested.connect(self.moveTab) |
181 else: |
184 else: |
182 self.setMovable(True) |
185 self.setMovable(True) |
183 |
186 |
184 def __currentChanged(self, index): |
187 def __currentChanged(self, index): |
185 """ |
188 """ |
186 Private slot to handle the currentChanged signal. |
189 Private slot to handle the currentChanged signal. |
187 |
190 |
188 @param index index of the current tab |
191 @param index index of the current tab |
189 """ |
192 """ |
190 if index == -1: |
193 if index == -1: |
191 self.__lastCurrentIndex = -1 |
194 self.__lastCurrentIndex = -1 |
192 else: |
195 else: |
193 self.__lastCurrentIndex = self.__currentIndex |
196 self.__lastCurrentIndex = self.__currentIndex |
194 self.__currentIndex = index |
197 self.__currentIndex = index |
195 |
198 |
196 def switchTab(self): |
199 def switchTab(self): |
197 """ |
200 """ |
198 Public slot used to switch between the current and the previous |
201 Public slot used to switch between the current and the previous |
199 current tab. |
202 current tab. |
200 """ |
203 """ |
201 if self.__lastCurrentIndex == -1 or self.__currentIndex == -1: |
204 if self.__lastCurrentIndex == -1 or self.__currentIndex == -1: |
202 return |
205 return |
203 |
206 |
204 self.setCurrentIndex(self.__lastCurrentIndex) |
207 self.setCurrentIndex(self.__lastCurrentIndex) |
205 self.currentWidget().setFocus() |
208 self.currentWidget().setFocus() |
206 |
209 |
207 def nextTab(self): |
210 def nextTab(self): |
208 """ |
211 """ |
209 Public slot used to show the next tab. |
212 Public slot used to show the next tab. |
210 """ |
213 """ |
211 ind = self.currentIndex() + 1 |
214 ind = self.currentIndex() + 1 |
212 if ind == self.count(): |
215 if ind == self.count(): |
213 ind = 0 |
216 ind = 0 |
214 |
217 |
215 self.setCurrentIndex(ind) |
218 self.setCurrentIndex(ind) |
216 self.currentWidget().setFocus() |
219 self.currentWidget().setFocus() |
217 |
220 |
218 def prevTab(self): |
221 def prevTab(self): |
219 """ |
222 """ |
220 Public slot used to show the previous tab. |
223 Public slot used to show the previous tab. |
221 """ |
224 """ |
222 ind = self.currentIndex() - 1 |
225 ind = self.currentIndex() - 1 |
223 if ind == -1: |
226 if ind == -1: |
224 ind = self.count() - 1 |
227 ind = self.count() - 1 |
225 |
228 |
226 self.setCurrentIndex(ind) |
229 self.setCurrentIndex(ind) |
227 self.currentWidget().setFocus() |
230 self.currentWidget().setFocus() |
228 |
231 |
229 def setTabContextMenuPolicy(self, policy): |
232 def setTabContextMenuPolicy(self, policy): |
230 """ |
233 """ |
231 Public method to set the context menu policy of the tab. |
234 Public method to set the context menu policy of the tab. |
232 |
235 |
233 @param policy context menu policy to set (Qt.ContextMenuPolicy) |
236 @param policy context menu policy to set (Qt.ContextMenuPolicy) |
234 """ |
237 """ |
235 self.tabBar().setContextMenuPolicy(policy) |
238 self.tabBar().setContextMenuPolicy(policy) |
236 if policy == Qt.ContextMenuPolicy.CustomContextMenu: |
239 if policy == Qt.ContextMenuPolicy.CustomContextMenu: |
237 self.tabBar().customContextMenuRequested.connect( |
240 self.tabBar().customContextMenuRequested.connect( |
238 self.__handleTabCustomContextMenuRequested) |
241 self.__handleTabCustomContextMenuRequested |
|
242 ) |
239 else: |
243 else: |
240 self.tabBar().customContextMenuRequested.disconnect( |
244 self.tabBar().customContextMenuRequested.disconnect( |
241 self.__handleTabCustomContextMenuRequested) |
245 self.__handleTabCustomContextMenuRequested |
|
246 ) |
242 |
247 |
243 def __handleTabCustomContextMenuRequested(self, point): |
248 def __handleTabCustomContextMenuRequested(self, point): |
244 """ |
249 """ |
245 Private slot to handle the context menu request for the tabbar. |
250 Private slot to handle the context menu request for the tabbar. |
246 |
251 |
247 @param point point the context menu was requested (QPoint) |
252 @param point point the context menu was requested (QPoint) |
248 """ |
253 """ |
249 _tabbar = self.tabBar() |
254 _tabbar = self.tabBar() |
250 for index in range(_tabbar.count()): |
255 for index in range(_tabbar.count()): |
251 rect = _tabbar.tabRect(index) |
256 rect = _tabbar.tabRect(index) |
252 if rect.contains(point): |
257 if rect.contains(point): |
253 self.customTabContextMenuRequested.emit( |
258 self.customTabContextMenuRequested.emit( |
254 _tabbar.mapToParent(point), index) |
259 _tabbar.mapToParent(point), index |
|
260 ) |
255 return |
261 return |
256 |
262 |
257 self.customTabContextMenuRequested.emit(_tabbar.mapToParent(point), -1) |
263 self.customTabContextMenuRequested.emit(_tabbar.mapToParent(point), -1) |
258 |
264 |
259 def selectTab(self, pos): |
265 def selectTab(self, pos): |
260 """ |
266 """ |
261 Public method to get the index of a tab given a position. |
267 Public method to get the index of a tab given a position. |
262 |
268 |
263 @param pos position determining the tab index (QPoint) |
269 @param pos position determining the tab index (QPoint) |
264 @return index of the tab (integer) |
270 @return index of the tab (integer) |
265 """ |
271 """ |
266 _tabbar = self.tabBar() |
272 _tabbar = self.tabBar() |
267 for index in range(_tabbar.count()): |
273 for index in range(_tabbar.count()): |
268 rect = _tabbar.tabRect(index) |
274 rect = _tabbar.tabRect(index) |
269 if rect.contains(pos): |
275 if rect.contains(pos): |
270 return index |
276 return index |
271 |
277 |
272 return -1 |
278 return -1 |
273 |
279 |
274 def moveTab(self, curIndex, newIndex): |
280 def moveTab(self, curIndex, newIndex): |
275 """ |
281 """ |
276 Public method to move a tab to a new index. |
282 Public method to move a tab to a new index. |
277 |
283 |
278 @param curIndex index of tab to be moved (integer) |
284 @param curIndex index of tab to be moved (integer) |
279 @param newIndex index the tab should be moved to (integer) |
285 @param newIndex index the tab should be moved to (integer) |
280 """ |
286 """ |
281 # step 1: save the tab data of tab to be moved |
287 # step 1: save the tab data of tab to be moved |
282 toolTip = self.tabToolTip(curIndex) |
288 toolTip = self.tabToolTip(curIndex) |
283 text = self.tabText(curIndex) |
289 text = self.tabText(curIndex) |
284 icon = self.tabIcon(curIndex) |
290 icon = self.tabIcon(curIndex) |
285 whatsThis = self.tabWhatsThis(curIndex) |
291 whatsThis = self.tabWhatsThis(curIndex) |
286 widget = self.widget(curIndex) |
292 widget = self.widget(curIndex) |
287 curWidget = self.currentWidget() |
293 curWidget = self.currentWidget() |
288 |
294 |
289 # step 2: move the tab |
295 # step 2: move the tab |
290 self.removeTab(curIndex) |
296 self.removeTab(curIndex) |
291 self.insertTab(newIndex, widget, icon, text) |
297 self.insertTab(newIndex, widget, icon, text) |
292 |
298 |
293 # step 3: set the tab data again |
299 # step 3: set the tab data again |
294 self.setTabToolTip(newIndex, toolTip) |
300 self.setTabToolTip(newIndex, toolTip) |
295 self.setTabWhatsThis(newIndex, whatsThis) |
301 self.setTabWhatsThis(newIndex, whatsThis) |
296 |
302 |
297 # step 4: set current widget |
303 # step 4: set current widget |
298 self.setCurrentWidget(curWidget) |
304 self.setCurrentWidget(curWidget) |
299 |
305 |
300 def __freeSide(self): |
306 def __freeSide(self): |
301 """ |
307 """ |
302 Private method to determine the free side of a tab. |
308 Private method to determine the free side of a tab. |
303 |
309 |
304 @return free side (QTabBar.ButtonPosition) |
310 @return free side (QTabBar.ButtonPosition) |
305 """ |
311 """ |
306 side = self.__tabBar.style().styleHint( |
312 side = self.__tabBar.style().styleHint( |
307 QStyle.StyleHint.SH_TabBar_CloseButtonPosition, |
313 QStyle.StyleHint.SH_TabBar_CloseButtonPosition, None, None, None |
308 None, None, None) |
314 ) |
309 side = ( |
315 side = ( |
310 QTabBar.ButtonPosition.RightSide |
316 QTabBar.ButtonPosition.RightSide |
311 if side == QTabBar.ButtonPosition.LeftSide else |
317 if side == QTabBar.ButtonPosition.LeftSide |
312 QTabBar.ButtonPosition.LeftSide |
318 else QTabBar.ButtonPosition.LeftSide |
313 ) |
319 ) |
314 return side |
320 return side |
315 |
321 |
316 def animationLabel(self, index, animationFile, interval=100): |
322 def animationLabel(self, index, animationFile, interval=100): |
317 """ |
323 """ |
318 Public slot to set an animated icon. |
324 Public slot to set an animated icon. |
319 |
325 |
320 @param index tab index |
326 @param index tab index |
321 @type int |
327 @type int |
322 @param animationFile name of the file containing the animation |
328 @param animationFile name of the file containing the animation |
323 @type str |
329 @type str |
324 @param interval interval in milliseconds between animation frames |
330 @param interval interval in milliseconds between animation frames |