src/eric7/EricWidgets/EricToolButton.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import enum 10 import enum
11 11
12 from PyQt6.QtCore import pyqtSlot, pyqtSignal, Qt, QTimer, QSize 12 from PyQt6.QtCore import pyqtSlot, pyqtSignal, Qt, QTimer, QSize
13 from PyQt6.QtWidgets import ( 13 from PyQt6.QtWidgets import (
14 QToolButton, QStyle, QStyleOptionToolButton, QStyleOption, QApplication, 14 QToolButton,
15 QLabel 15 QStyle,
16 QStyleOptionToolButton,
17 QStyleOption,
18 QApplication,
19 QLabel,
16 ) 20 )
17 21
18 22
19 class EricToolButtonOptions(enum.IntEnum): 23 class EricToolButtonOptions(enum.IntEnum):
20 """ 24 """
21 Class defining the tool button options. 25 Class defining the tool button options.
22 """ 26 """
27
23 DEFAULT = 0 28 DEFAULT = 0
24 SHOW_MENU_INSIDE = 1 29 SHOW_MENU_INSIDE = 1
25 TOOLBAR_LOOKUP = 2 30 TOOLBAR_LOOKUP = 2
26 31
27 32
28 class EricToolButton(QToolButton): 33 class EricToolButton(QToolButton):
29 """ 34 """
30 Class implementing a specialized tool button subclass. 35 Class implementing a specialized tool button subclass.
31 36
32 @signal aboutToShowMenu() emitted before the tool button menu is shown 37 @signal aboutToShowMenu() emitted before the tool button menu is shown
33 @signal aboutToHideMenu() emitted before the tool button menu is hidden 38 @signal aboutToHideMenu() emitted before the tool button menu is hidden
34 @signal middleClicked() emitted when the middle mouse button was clicked 39 @signal middleClicked() emitted when the middle mouse button was clicked
35 @signal controlClicked() emitted when the left mouse button was 40 @signal controlClicked() emitted when the left mouse button was
36 clicked while pressing the Ctrl key 41 clicked while pressing the Ctrl key
37 @signal doubleClicked() emitted when the left mouse button was 42 @signal doubleClicked() emitted when the left mouse button was
38 double clicked 43 double clicked
39 """ 44 """
45
40 aboutToShowMenu = pyqtSignal() 46 aboutToShowMenu = pyqtSignal()
41 aboutToHideMenu = pyqtSignal() 47 aboutToHideMenu = pyqtSignal()
42 middleClicked = pyqtSignal() 48 middleClicked = pyqtSignal()
43 controlClicked = pyqtSignal() 49 controlClicked = pyqtSignal()
44 doubleClicked = pyqtSignal() 50 doubleClicked = pyqtSignal()
45 51
46 def __init__(self, parent=None): 52 def __init__(self, parent=None):
47 """ 53 """
48 Constructor 54 Constructor
49 55
50 @param parent reference to the parent widget 56 @param parent reference to the parent widget
51 @type QWidget 57 @type QWidget
52 """ 58 """
53 super().__init__(parent) 59 super().__init__(parent)
54 60
55 self.setMinimumWidth(16) 61 self.setMinimumWidth(16)
56 62
57 self.__menu = None 63 self.__menu = None
58 self.__options = EricToolButtonOptions.DEFAULT 64 self.__options = EricToolButtonOptions.DEFAULT
59 65
60 self.__badgeLabel = QLabel(self) 66 self.__badgeLabel = QLabel(self)
61 font = self.__badgeLabel.font() 67 font = self.__badgeLabel.font()
62 font.setPixelSize(int(self.__badgeLabel.height() / 2.5)) 68 font.setPixelSize(int(self.__badgeLabel.height() / 2.5))
63 self.__badgeLabel.setFont(font) 69 self.__badgeLabel.setFont(font)
64 self.__badgeLabel.hide() 70 self.__badgeLabel.hide()
65 71
66 opt = QStyleOptionToolButton() 72 opt = QStyleOptionToolButton()
67 self.initStyleOption(opt) 73 self.initStyleOption(opt)
68 74
69 self.__pressTimer = QTimer() 75 self.__pressTimer = QTimer()
70 self.__pressTimer.setSingleShot(True) 76 self.__pressTimer.setSingleShot(True)
71 self.__pressTimer.setInterval( 77 self.__pressTimer.setInterval(
72 QApplication.style().styleHint( 78 QApplication.style().styleHint(
73 QStyle.StyleHint.SH_ToolButton_PopupDelay, opt, self)) 79 QStyle.StyleHint.SH_ToolButton_PopupDelay, opt, self
80 )
81 )
74 self.__pressTimer.timeout.connect(self.__showMenu) 82 self.__pressTimer.timeout.connect(self.__showMenu)
75 83
76 ################################################################## 84 ##################################################################
77 ## Menu handling methods below. 85 ## Menu handling methods below.
78 ## 86 ##
79 ## The menu is handled in EricToolButton and is not passed to 87 ## The menu is handled in EricToolButton and is not passed to
80 ## QToolButton. No menu indicator will be shown in the button. 88 ## QToolButton. No menu indicator will be shown in the button.
81 ################################################################## 89 ##################################################################
82 90
83 def menu(self): 91 def menu(self):
84 """ 92 """
85 Public method to get a reference to the tool button menu. 93 Public method to get a reference to the tool button menu.
86 94
87 @return reference to the tool button menu 95 @return reference to the tool button menu
88 @rtype QMenu 96 @rtype QMenu
89 """ 97 """
90 return self.__menu 98 return self.__menu
91 99
92 def setMenu(self, menu): 100 def setMenu(self, menu):
93 """ 101 """
94 Public method to set the tool button menu. 102 Public method to set the tool button menu.
95 103
96 @param menu reference to the tool button menu 104 @param menu reference to the tool button menu
97 @type QMenu 105 @type QMenu
98 """ 106 """
99 if menu is not None: 107 if menu is not None:
100 if self.__menu: 108 if self.__menu:
101 self.__menu.aboutToHide.disconnect(self.__menuAboutToHide) 109 self.__menu.aboutToHide.disconnect(self.__menuAboutToHide)
102 110
103 self.__menu = menu 111 self.__menu = menu
104 self.__menu.aboutToHide.connect(self.__menuAboutToHide) 112 self.__menu.aboutToHide.connect(self.__menuAboutToHide)
105 113
106 def showMenuInside(self): 114 def showMenuInside(self):
107 """ 115 """
108 Public method to check, if the menu edge shall be aligned with 116 Public method to check, if the menu edge shall be aligned with
109 the button. 117 the button.
110 118
111 @return flag indicating that the menu edge shall be aligned 119 @return flag indicating that the menu edge shall be aligned
112 @rtype bool 120 @rtype bool
113 """ 121 """
114 return bool(self.__options & EricToolButtonOptions.SHOW_MENU_INSIDE) 122 return bool(self.__options & EricToolButtonOptions.SHOW_MENU_INSIDE)
115 123
116 def setShowMenuInside(self, enable): 124 def setShowMenuInside(self, enable):
117 """ 125 """
118 Public method to set a flag to show the menu edge aligned with 126 Public method to set a flag to show the menu edge aligned with
119 the button. 127 the button.
120 128
121 @param enable flag indicating to align the menu edge to the button 129 @param enable flag indicating to align the menu edge to the button
122 @type bool 130 @type bool
123 """ 131 """
124 if enable: 132 if enable:
125 self.__options |= EricToolButtonOptions.SHOW_MENU_INSIDE 133 self.__options |= EricToolButtonOptions.SHOW_MENU_INSIDE
126 else: 134 else:
127 self.__options &= ~EricToolButtonOptions.SHOW_MENU_INSIDE 135 self.__options &= ~EricToolButtonOptions.SHOW_MENU_INSIDE
128 136
129 @pyqtSlot() 137 @pyqtSlot()
130 def __showMenu(self): 138 def __showMenu(self):
131 """ 139 """
132 Private slot to show the tool button menu. 140 Private slot to show the tool button menu.
133 """ 141 """
134 if self.__menu is None or self.__menu.isVisible(): 142 if self.__menu is None or self.__menu.isVisible():
135 return 143 return
136 144
137 self.aboutToShowMenu.emit() 145 self.aboutToShowMenu.emit()
138 146
139 if self.__options & EricToolButtonOptions.SHOW_MENU_INSIDE: 147 if self.__options & EricToolButtonOptions.SHOW_MENU_INSIDE:
140 pos = self.mapToGlobal(self.rect().bottomRight()) 148 pos = self.mapToGlobal(self.rect().bottomRight())
141 if ( 149 if QApplication.layoutDirection() == Qt.LayoutDirection.RightToLeft:
142 QApplication.layoutDirection() ==
143 Qt.LayoutDirection.RightToLeft
144 ):
145 pos.setX(pos.x() - self.rect().width()) 150 pos.setX(pos.x() - self.rect().width())
146 else: 151 else:
147 pos.setX(pos.x() - self.__menu.sizeHint().width()) 152 pos.setX(pos.x() - self.__menu.sizeHint().width())
148 else: 153 else:
149 pos = self.mapToGlobal(self.rect().bottomLeft()) 154 pos = self.mapToGlobal(self.rect().bottomLeft())
150 155
151 self.__menu.popup(pos) 156 self.__menu.popup(pos)
152 157
153 @pyqtSlot() 158 @pyqtSlot()
154 def __menuAboutToHide(self): 159 def __menuAboutToHide(self):
155 """ 160 """
156 Private slot to handle the tool button menu about to be hidden. 161 Private slot to handle the tool button menu about to be hidden.
157 """ 162 """
158 self.setDown(False) 163 self.setDown(False)
159 self.aboutToHideMenu.emit() 164 self.aboutToHideMenu.emit()
160 165
161 ################################################################## 166 ##################################################################
162 ## Methods to handle the tool button look 167 ## Methods to handle the tool button look
163 ################################################################## 168 ##################################################################
164 169
165 def toolbarButtonLook(self): 170 def toolbarButtonLook(self):
166 """ 171 """
167 Public method to check, if the button has the toolbar look. 172 Public method to check, if the button has the toolbar look.
168 173
169 @return flag indicating toolbar look 174 @return flag indicating toolbar look
170 @rtype bool 175 @rtype bool
171 """ 176 """
172 return bool(self.__options & EricToolButtonOptions.TOOLBAR_LOOKUP) 177 return bool(self.__options & EricToolButtonOptions.TOOLBAR_LOOKUP)
173 178
174 def setToolbarButtonLook(self, enable): 179 def setToolbarButtonLook(self, enable):
175 """ 180 """
176 Public method to set the toolbar look state. 181 Public method to set the toolbar look state.
177 182
178 @param enable flag indicating toolbar look 183 @param enable flag indicating toolbar look
179 @type bool 184 @type bool
180 """ 185 """
181 if enable: 186 if enable:
182 self.__options |= EricToolButtonOptions.TOOLBAR_LOOKUP 187 self.__options |= EricToolButtonOptions.TOOLBAR_LOOKUP
183 188
184 opt = QStyleOption() 189 opt = QStyleOption()
185 opt.initFrom(self) 190 opt.initFrom(self)
186 size = self.style().pixelMetric( 191 size = self.style().pixelMetric(
187 QStyle.PixelMetric.PM_ToolBarIconSize, opt, self) 192 QStyle.PixelMetric.PM_ToolBarIconSize, opt, self
193 )
188 self.setIconSize(QSize(size, size)) 194 self.setIconSize(QSize(size, size))
189 else: 195 else:
190 self.__options &= ~EricToolButtonOptions.TOOLBAR_LOOKUP 196 self.__options &= ~EricToolButtonOptions.TOOLBAR_LOOKUP
191 197
192 self.setProperty("toolbar-look", enable) 198 self.setProperty("toolbar-look", enable)
193 self.style().unpolish(self) 199 self.style().unpolish(self)
194 self.style().polish(self) 200 self.style().polish(self)
195 201
196 ################################################################## 202 ##################################################################
197 ## Methods to handle some event types 203 ## Methods to handle some event types
198 ################################################################## 204 ##################################################################
199 205
200 def mousePressEvent(self, evt): 206 def mousePressEvent(self, evt):
201 """ 207 """
202 Protected method to handle mouse press events. 208 Protected method to handle mouse press events.
203 209
204 @param evt reference to the mouse event 210 @param evt reference to the mouse event
205 @type QMouseEvent 211 @type QMouseEvent
206 """ 212 """
207 if self.popupMode() == QToolButton.ToolButtonPopupMode.DelayedPopup: 213 if self.popupMode() == QToolButton.ToolButtonPopupMode.DelayedPopup:
208 self.__pressTimer.start() 214 self.__pressTimer.start()
209 215
210 if ( 216 if (
211 (evt.buttons() == Qt.MouseButton.LeftButton and 217 evt.buttons() == Qt.MouseButton.LeftButton
212 self.__menu is not None and 218 and self.__menu is not None
213 (self.popupMode() == 219 and (self.popupMode() == QToolButton.ToolButtonPopupMode.InstantPopup)
214 QToolButton.ToolButtonPopupMode.InstantPopup)) or 220 ) or (evt.buttons() == Qt.MouseButton.RightButton and self.__menu is not None):
215 (evt.buttons() == Qt.MouseButton.RightButton and
216 self.__menu is not None)
217 ):
218 self.setDown(True) 221 self.setDown(True)
219 self.__showMenu() 222 self.__showMenu()
220 else: 223 else:
221 super().mousePressEvent(evt) 224 super().mousePressEvent(evt)
222 225
223 def mouseReleaseEvent(self, evt): 226 def mouseReleaseEvent(self, evt):
224 """ 227 """
225 Protected method to handle mouse release events. 228 Protected method to handle mouse release events.
226 229
227 @param evt reference to the mouse event 230 @param evt reference to the mouse event
228 @type QMouseEvent 231 @type QMouseEvent
229 """ 232 """
230 self.__pressTimer.stop() 233 self.__pressTimer.stop()
231 234
232 if ( 235 if evt.button() == Qt.MouseButton.MiddleButton and self.rect().contains(
233 evt.button() == Qt.MouseButton.MiddleButton and 236 evt.position().toPoint()
234 self.rect().contains(evt.position().toPoint())
235 ): 237 ):
236 self.middleClicked.emit() 238 self.middleClicked.emit()
237 self.setDown(False) 239 self.setDown(False)
238 elif ( 240 elif (
239 evt.button() == Qt.MouseButton.LeftButton and 241 evt.button() == Qt.MouseButton.LeftButton
240 self.rect().contains(evt.position().toPoint()) and 242 and self.rect().contains(evt.position().toPoint())
241 evt.modifiers() == Qt.KeyboardModifier.ControlModifier 243 and evt.modifiers() == Qt.KeyboardModifier.ControlModifier
242 ): 244 ):
243 self.controlClicked.emit() 245 self.controlClicked.emit()
244 self.setDown(False) 246 self.setDown(False)
245 else: 247 else:
246 super().mouseReleaseEvent(evt) 248 super().mouseReleaseEvent(evt)
247 249
248 def mouseDoubleClickEvent(self, evt): 250 def mouseDoubleClickEvent(self, evt):
249 """ 251 """
250 Protected method to handle mouse double click events. 252 Protected method to handle mouse double click events.
251 253
252 @param evt reference to the mouse event 254 @param evt reference to the mouse event
253 @type QMouseEvent 255 @type QMouseEvent
254 """ 256 """
255 super().mouseDoubleClickEvent(evt) 257 super().mouseDoubleClickEvent(evt)
256 258
257 self.__pressTimer.stop() 259 self.__pressTimer.stop()
258 260
259 if evt.buttons() == Qt.MouseButton.LeftButton: 261 if evt.buttons() == Qt.MouseButton.LeftButton:
260 self.doubleClicked.emit() 262 self.doubleClicked.emit()
261 263
262 def contextMenuEvent(self, evt): 264 def contextMenuEvent(self, evt):
263 """ 265 """
264 Protected method to handle context menu events. 266 Protected method to handle context menu events.
265 267
266 @param evt reference to the context menu event 268 @param evt reference to the context menu event
267 @type QContextMenuEvent 269 @type QContextMenuEvent
268 """ 270 """
269 # block to prevent showing the context menu and the tool button menu 271 # block to prevent showing the context menu and the tool button menu
270 if self.__menu is not None: 272 if self.__menu is not None:
271 return 273 return
272 274
273 super().contextMenuEvent(evt) 275 super().contextMenuEvent(evt)
274 276
275 ################################################################## 277 ##################################################################
276 ## Methods to handle the tool button badge 278 ## Methods to handle the tool button badge
277 ################################################################## 279 ##################################################################
278 280
279 def setBadgeText(self, text): 281 def setBadgeText(self, text):
280 """ 282 """
281 Public method to set the badge text. 283 Public method to set the badge text.
282 284
283 @param text badge text to be set 285 @param text badge text to be set
284 @type str 286 @type str
285 """ 287 """
286 if text: 288 if text:
287 self.__badgeLabel.setText(text) 289 self.__badgeLabel.setText(text)
289 self.__badgeLabel.move(self.width() - self.__badgeLabel.width(), 0) 291 self.__badgeLabel.move(self.width() - self.__badgeLabel.width(), 0)
290 self.__badgeLabel.show() 292 self.__badgeLabel.show()
291 else: 293 else:
292 self.__badgeLabel.clear() 294 self.__badgeLabel.clear()
293 self.__badgeLabel.hide() 295 self.__badgeLabel.hide()
294 296
295 def badgeText(self): 297 def badgeText(self):
296 """ 298 """
297 Public method to get the badge text. 299 Public method to get the badge text.
298 300
299 @return badge text 301 @return badge text
300 @rtype str 302 @rtype str
301 """ 303 """
302 return self.__badgeLabel.text() 304 return self.__badgeLabel.text()

eric ide

mercurial