src/eric7/EricWidgets/EricPassivePopup.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) 2010 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing dialog-like popup that displays messages without
8 interrupting the user.
9 """
10
11 import enum
12
13 from PyQt6.QtCore import pyqtSignal, Qt, QTimer, QPoint, QRect
14 from PyQt6.QtWidgets import QFrame, QVBoxLayout, QApplication
15
16
17 class EricPassivePopupStyle(enum.Enum):
18 """
19 Class defining the popup styles.
20 """
21 BOXED = 0 # box with no shadow
22 STYLED = 1 # styled panel with no shadow
23 CUSTOM = 128 # reserved for extensions
24
25
26 class EricPassivePopup(QFrame):
27 """
28 Class implementing dialog-like popup that displays messages without
29 interrupting the user.
30
31 @signal clicked emitted to indicate a mouse button click
32 """
33 DefaultPopupTime = 6 * 1000 # time im milliseconds
34
35 clicked = pyqtSignal((), (QPoint, ))
36
37 def __init__(self, style=EricPassivePopupStyle.BOXED, parent=None):
38 """
39 Constructor
40
41 @param style style of the popup
42 @type EricPassivePopupStyle
43 @param parent reference to the parent widget
44 @type QWidget
45 """
46 super().__init__(None)
47
48 self.__msgView = None
49 self.__topLayout = None
50 self.__hideDelay = EricPassivePopup.DefaultPopupTime
51 self.__hideTimer = QTimer(self)
52 self.__autoDelete = False
53 self.__fixedPosition = QPoint()
54
55 self.setWindowFlags(
56 Qt.WindowType.Tool |
57 Qt.WindowType.X11BypassWindowManagerHint |
58 Qt.WindowType.WindowStaysOnTopHint |
59 Qt.WindowType.FramelessWindowHint
60 )
61 if style == EricPassivePopupStyle.STYLED:
62 self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Plain)
63 else:
64 # default style is Boxed - Plain
65 self.setFrameStyle(QFrame.Shape.Box | QFrame.Shadow.Plain)
66 self.setLineWidth(2)
67 self.__hideTimer.timeout.connect(self.hide)
68 self.clicked.connect(self.hide)
69
70 self.__customData = {} # dictionary to store some custom data
71
72 def setView(self, child):
73 """
74 Public method to set the message view.
75
76 @param child reference to the widget to set as the message view
77 (QWidget)
78 """
79 self.__msgView = child
80 self.__topLayout = QVBoxLayout(self)
81 self.__topLayout.addWidget(self.__msgView)
82 self.__topLayout.activate()
83
84 def view(self):
85 """
86 Public method to get a reference to the message view.
87
88 @return reference to the message view (QWidget)
89 """
90 return self.__msgView
91
92 def setVisible(self, visible):
93 """
94 Public method to show or hide the popup.
95
96 @param visible flag indicating the visibility status (boolean)
97 """
98 if not visible:
99 super().setVisible(visible)
100 return
101
102 if self.size() != self.sizeHint():
103 self.resize(self.sizeHint())
104
105 if self.__fixedPosition.isNull():
106 self.__positionSelf()
107 else:
108 self.move(self.__fixedPosition)
109 super().setVisible(True)
110
111 delay = self.__hideDelay
112 if delay < 0:
113 delay = EricPassivePopup.DefaultPopupTime
114 if delay > 0:
115 self.__hideTimer.start(delay)
116
117 def show(self, p=None):
118 """
119 Public slot to show the popup.
120
121 @param p position for the popup (QPoint)
122 """
123 if p is not None:
124 self.__fixedPosition = p
125 super().show()
126
127 def setTimeout(self, delay):
128 """
129 Public method to set the delay for the popup is removed automatically.
130
131 Setting the delay to 0 disables the timeout. If you're doing this, you
132 may want to connect the clicked() signal to the hide() slot. Setting
133 the delay to -1 makes it use the default value.
134
135 @param delay value for the delay in milliseconds (integer)
136 """
137 self.__hideDelay = delay
138 if self.__hideTimer.isActive():
139 if delay:
140 if delay == -1:
141 delay = EricPassivePopup.DefaultPopupTime
142 self.__hideTimer.start(delay)
143 else:
144 self.__hideTimer.stop()
145
146 def timeout(self):
147 """
148 Public method to get the delay before the popup is removed
149 automatically.
150
151 @return the delay before the popup is removed automatically (integer)
152 """
153 return self.__hideDelay
154
155 def mouseReleaseEvent(self, evt):
156 """
157 Protected method to handle a mouse release event.
158
159 @param evt reference to the mouse event (QMouseEvent)
160 """
161 self.clicked.emit()
162 self.clicked.emit(evt.position().toPoint())
163
164 def hideEvent(self, evt):
165 """
166 Protected method to handle the hide event.
167
168 @param evt reference to the hide event (QHideEvent)
169 """
170 self.__hideTimer.stop()
171
172 def __defaultArea(self):
173 """
174 Private method to determine the default rectangle to be passed to
175 moveNear().
176
177 @return default rectangle (QRect)
178 """
179 return QRect(100, 100, 200, 200)
180
181 def __positionSelf(self):
182 """
183 Private method to position the popup.
184 """
185 self.__moveNear(self.__defaultArea())
186
187 def __moveNear(self, target):
188 """
189 Private method to move the popup to be adjacent to the specified
190 rectangle.
191
192 @param target rectangle to be placed at (QRect)
193 """
194 pos = self.__calculateNearbyPoint(target)
195 self.move(pos.x(), pos.y())
196
197 def __calculateNearbyPoint(self, target):
198 """
199 Private method to calculate the position to place the popup near the
200 specified rectangle.
201
202 @param target rectangle to be placed at (QRect)
203 @return position to place the popup (QPoint)
204 """
205 pos = target.topLeft()
206 x = pos.x()
207 y = pos.y()
208 w = self.minimumSizeHint().width()
209 h = self.minimumSizeHint().height()
210
211 r = QApplication.screenAt(QPoint(x + w // 2, y + h // 2)).geometry()
212
213 if x < r.center().x():
214 x += target.width()
215 else:
216 x -= w
217
218 # It's apparently trying to go off screen, so display it ALL at the
219 # bottom.
220 if (y + h) > r.bottom():
221 y = r.bottom() - h
222
223 if (x + w) > r.right():
224 x = r.right() - w
225
226 if y < r.top():
227 y = r.top()
228
229 if x < r.left():
230 x = r.left()
231
232 return QPoint(x, y)
233
234 def setCustomData(self, key, data):
235 """
236 Public method to set some custom data.
237
238 @param key key for the custom data
239 @type str
240 @param data data to be stored
241 @type any
242 """
243 self.__customData[key] = data
244
245 def getCustomData(self, key):
246 """
247 Public method to get some custom data.
248
249 @param key key for the custom data
250 @type str
251 @return stored data
252 @rtype any
253 """
254 return self.__customData[key]

eric ide

mercurial