eric6/E5Gui/E5ToolButton.py

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

eric ide

mercurial