E5Gui/E5ToolButton.py

changeset 5745
4f4316e83318
child 6048
82ad8ec9548c
equal deleted inserted replaced
5744:d53474dcb9e6 5745:4f4316e83318
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 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
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 opt = QStyleOptionToolButton()
54 self.initStyleOption(opt)
55
56 self.__pressTimer = QTimer()
57 self.__pressTimer.setSingleShot(True)
58 self.__pressTimer.setInterval(
59 QApplication.style().styleHint(
60 QStyle.SH_ToolButton_PopupDelay, opt, self))
61 self.__pressTimer.timeout.connect(self.__showMenu)
62
63 ##################################################################
64 ## Menu handling methods below.
65 ##
66 ## The menu is handled in E5ToolButton and is not passed to
67 ## QToolButton. No menu indicator will be shown in the button.
68 ##################################################################
69
70 def menu(self):
71 """
72 Public method to get a reference to the tool button menu.
73
74 @return reference to the tool button menu
75 @rtype QMenu
76 """
77 return self.__menu
78
79 def setMenu(self, menu):
80 """
81 Public method to set the tool button menu.
82
83 @param menu reference to the tool button menu
84 @type QMenu
85 """
86 assert menu is not None
87
88 if self.__menu:
89 self.__menu.aboutToHide.disconnect(self.__menuAboutToHide)
90
91 self.__menu = menu
92 self.__menu.aboutToHide.connect(self.__menuAboutToHide)
93
94 def showMenuInside(self):
95 """
96 Public method to check, if the menu edge shall be aligned with
97 the button.
98
99 @return flag indicating that the menu edge shall be aligned
100 @rtype bool
101 """
102 return bool(self.__options & E5ToolButton.ShowMenuInsideOption)
103
104 def setShowMenuInside(self, enable):
105 """
106 Public method to set a flag to show the menu edge aligned with
107 the button.
108
109 @param enable flag indicating to align the menu edge to the button
110 @type bool
111 """
112 if enable:
113 self.__options |= E5ToolButton.ShowMenuInsideOption
114 else:
115 self.__options &= ~E5ToolButton.ShowMenuInsideOption
116
117 @pyqtSlot()
118 def __showMenu(self):
119 """
120 Private slot to show the tool button menu.
121 """
122 if self.__menu is None or self.__menu.isVisible():
123 return
124
125 self.aboutToShowMenu.emit()
126
127 if self.__options & E5ToolButton.ShowMenuInsideOption:
128 pos = self.mapToGlobal(self.rect().bottomRight())
129 if QApplication.layoutDirection() == Qt.RightToLeft:
130 pos.setX(pos.x() - self.rect().width())
131 else:
132 pos.setX(pos.x() - self.__menu.sizeHint().width())
133 else:
134 pos = self.mapToGlobal(self.rect().bottomLeft())
135
136 self.__menu.popup(pos)
137
138 @pyqtSlot()
139 def __menuAboutToHide(self):
140 """
141 Private slot to handle the tool button menu about to be hidden.
142 """
143 self.setDown(False)
144 self.aboutToHideMenu.emit()
145
146 ##################################################################
147 ## Methods to handle the tool button look
148 ##################################################################
149
150 def toolbarButtonLook(self):
151 """
152 Public method to check, if the button has the toolbar look.
153
154 @return flag indicating toolbar look
155 @rtype bool
156 """
157 return bool(self.__options & E5ToolButton.ToolBarLookOption)
158
159 def setToolbarButtonLook(self, enable):
160 """
161 Public method to set the toolbar look state.
162
163 @param enable flag indicating toolbar look
164 @type bool
165 """
166 if enable:
167 self.__options |= E5ToolButton.ToolBarLookOption
168
169 opt = QStyleOption()
170 opt.initFrom(self)
171 size = self.style().pixelMetric(
172 QStyle.PM_ToolBarIconSize, opt, self)
173 self.setIconSize(QSize(size, size))
174 else:
175 self.__options &= ~E5ToolButton.ToolBarLookOption
176
177 self.setProperty("toolbar-look", enable)
178 self.style().unpolish(self)
179 self.style().polish(self)
180
181 ##################################################################
182 ## Methods to handle some event types
183 ##################################################################
184
185 def mousePressEvent(self, evt):
186 """
187 Protected method to handle mouse press events.
188
189 @param evt reference to the mouse event
190 @type QMouseEvent
191 """
192 if self.popupMode() == QToolButton.DelayedPopup:
193 self.__pressTimer.start()
194
195 if evt.buttons() == Qt.LeftButton and \
196 self.__menu is not None and \
197 self.popupMode() == QToolButton.InstantPopup:
198 self.setDown(True)
199 self.__showMenu()
200 elif evt.buttons() == Qt.RightButton and \
201 self.__menu is not None:
202 self.setDown(True)
203 self.__showMenu()
204 else:
205 super(E5ToolButton, self).mousePressEvent(evt)
206
207 def mouseReleaseEvent(self, evt):
208 """
209 Protected method to handle mouse release events.
210
211 @param evt reference to the mouse event
212 @type QMouseEvent
213 """
214 self.__pressTimer.stop()
215
216 if evt.button() == Qt.MiddleButton and \
217 self.rect().contains(evt.pos()):
218 self.middleClicked.emit()
219 self.setDown(False)
220 elif evt.button() == Qt.LeftButton and \
221 self.rect().contains(evt.pos()) and \
222 evt.modifiers() == Qt.ControlModifier:
223 self.controlClicked.emit()
224 self.setDown(False)
225 else:
226 super(E5ToolButton, self).mouseReleaseEvent(evt)
227
228 def mouseDoubleClickEvent(self, evt):
229 """
230 Protected method to handle mouse double click events.
231
232 @param evt reference to the mouse event
233 @type QMouseEvent
234 """
235 super(E5ToolButton, self).mouseDoubleClickEvent(evt)
236
237 self.__pressTimer.stop()
238
239 if evt.buttons() == Qt.LeftButton:
240 self.doubleClicked.emit()
241
242 def contextMenuEvent(self, evt):
243 """
244 Protected method to handle context menu events.
245
246 @param evt reference to the context menu event
247 @type QContextMenuEvent
248 """
249 # block to prevent showing the context menu and the tool button menu
250 if self.__menu is not None:
251 return
252
253 super(E5ToolButton, self).contextMenuEvent(evt)

eric ide

mercurial