52 @param parent reference to the parent widget |
55 @param parent reference to the parent widget |
53 @type QWidget |
56 @type QWidget |
54 """ |
57 """ |
55 super().__init__(parent) |
58 super().__init__(parent) |
56 self.setupUi(self) |
59 self.setupUi(self) |
57 |
60 |
58 self.layout().setAlignment( |
61 self.layout().setAlignment( |
59 self.verticalLayout, |
62 self.verticalLayout, |
60 Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter |
63 Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, |
61 ) |
64 ) |
62 |
65 |
63 self.setStyleSheet(NotificationFrame.getStyleSheet(kind)) |
66 self.setStyleSheet(NotificationFrame.getStyleSheet(kind)) |
64 |
67 |
65 if icon is None: |
68 if icon is None: |
66 icon = NotificationFrame.getIcon(kind) |
69 icon = NotificationFrame.getIcon(kind) |
67 self.icon.setPixmap(icon) |
70 self.icon.setPixmap(icon) |
68 |
71 |
69 self.heading.setText(heading) |
72 self.heading.setText(heading) |
70 self.text.setText(text) |
73 self.text.setText(text) |
71 |
74 |
72 self.show() |
75 self.show() |
73 self.adjustSize() |
76 self.adjustSize() |
74 |
77 |
75 @classmethod |
78 @classmethod |
76 def getIcon(cls, kind): |
79 def getIcon(cls, kind): |
77 """ |
80 """ |
78 Class method to get the icon for a specific notification kind. |
81 Class method to get the icon for a specific notification kind. |
79 |
82 |
80 @param kind notification kind |
83 @param kind notification kind |
81 @type NotificationTypes |
84 @type NotificationTypes |
82 @return icon for the notification kind |
85 @return icon for the notification kind |
83 @rtype QPixmap |
86 @rtype QPixmap |
84 """ |
87 """ |
85 if kind == NotificationTypes.CRITICAL: |
88 if kind == NotificationTypes.CRITICAL: |
86 return UI.PixmapCache.getPixmap("notificationCritical48") |
89 return UI.PixmapCache.getPixmap("notificationCritical48") |
87 elif kind == NotificationTypes.WARNING: # __NO-TASK__ |
90 elif kind == NotificationTypes.WARNING: # __NO-TASK__ |
88 return UI.PixmapCache.getPixmap("notificationWarning48") |
91 return UI.PixmapCache.getPixmap("notificationWarning48") |
89 elif kind == NotificationTypes.INFORMATION: |
92 elif kind == NotificationTypes.INFORMATION: |
90 return UI.PixmapCache.getPixmap("notificationInformation48") |
93 return UI.PixmapCache.getPixmap("notificationInformation48") |
91 else: |
94 else: |
92 return UI.PixmapCache.getPixmap("notification48") |
95 return UI.PixmapCache.getPixmap("notification48") |
93 |
96 |
94 @classmethod |
97 @classmethod |
95 def getStyleSheet(cls, kind): |
98 def getStyleSheet(cls, kind): |
96 """ |
99 """ |
97 Class method to get a style sheet for specific notification kind. |
100 Class method to get a style sheet for specific notification kind. |
98 |
101 |
99 @param kind notification kind |
102 @param kind notification kind |
100 @type NotificationTypes |
103 @type NotificationTypes |
101 @return string containing the style sheet for the notification kind |
104 @return string containing the style sheet for the notification kind |
102 @rtype str |
105 @rtype str |
103 """ |
106 """ |
104 if kind == NotificationTypes.CRITICAL: |
107 if kind == NotificationTypes.CRITICAL: |
105 return NotificationFrame.NotificationStyleSheetTemplate.format( |
108 return NotificationFrame.NotificationStyleSheetTemplate.format( |
106 Preferences.getUI("NotificationCriticalForeground"), |
109 Preferences.getUI("NotificationCriticalForeground"), |
107 Preferences.getUI("NotificationCriticalBackground") |
110 Preferences.getUI("NotificationCriticalBackground"), |
108 ) |
111 ) |
109 elif kind == NotificationTypes.WARNING: # __NO-TASK__ |
112 elif kind == NotificationTypes.WARNING: # __NO-TASK__ |
110 return NotificationFrame.NotificationStyleSheetTemplate.format( |
113 return NotificationFrame.NotificationStyleSheetTemplate.format( |
111 Preferences.getUI("NotificationWarningForeground"), |
114 Preferences.getUI("NotificationWarningForeground"), |
112 Preferences.getUI("NotificationWarningBackground") |
115 Preferences.getUI("NotificationWarningBackground"), |
113 ) |
116 ) |
114 else: |
117 else: |
115 return "" |
118 return "" |
116 |
119 |
117 |
120 |
118 class NotificationWidget(QWidget): |
121 class NotificationWidget(QWidget): |
119 """ |
122 """ |
120 Class implementing a Notification list widget. |
123 Class implementing a Notification list widget. |
121 """ |
124 """ |
|
125 |
122 def __init__(self, parent=None, setPosition=False): |
126 def __init__(self, parent=None, setPosition=False): |
123 """ |
127 """ |
124 Constructor |
128 Constructor |
125 |
129 |
126 @param parent reference to the parent widget |
130 @param parent reference to the parent widget |
127 @type QWidget |
131 @type QWidget |
128 @param setPosition flag indicating to set the display |
132 @param setPosition flag indicating to set the display |
129 position interactively |
133 position interactively |
130 @type bool |
134 @type bool |
131 """ |
135 """ |
132 super().__init__(parent) |
136 super().__init__(parent) |
133 |
137 |
134 self.__layout = QVBoxLayout(self) |
138 self.__layout = QVBoxLayout(self) |
135 self.__layout.setContentsMargins(0, 0, 0, 0) |
139 self.__layout.setContentsMargins(0, 0, 0, 0) |
136 self.setLayout(self.__layout) |
140 self.setLayout(self.__layout) |
137 |
141 |
138 self.__timeout = 5000 |
142 self.__timeout = 5000 |
139 self.__dragPosition = QPoint() |
143 self.__dragPosition = QPoint() |
140 self.__timers = {} |
144 self.__timers = {} |
141 self.__notifications = [] |
145 self.__notifications = [] |
142 |
146 |
143 self.__settingPosition = setPosition |
147 self.__settingPosition = setPosition |
144 |
148 |
145 flags = ( |
149 flags = ( |
146 Qt.WindowType.Tool | |
150 Qt.WindowType.Tool |
147 Qt.WindowType.FramelessWindowHint | |
151 | Qt.WindowType.FramelessWindowHint |
148 Qt.WindowType.WindowStaysOnTopHint | |
152 | Qt.WindowType.WindowStaysOnTopHint |
149 Qt.WindowType.X11BypassWindowManagerHint |
153 | Qt.WindowType.X11BypassWindowManagerHint |
150 ) |
154 ) |
151 if Globals.isWindowsPlatform(): |
155 if Globals.isWindowsPlatform(): |
152 flags |= Qt.WindowType.ToolTip |
156 flags |= Qt.WindowType.ToolTip |
153 self.setWindowFlags(flags) |
157 self.setWindowFlags(flags) |
154 |
158 |
155 if self.__settingPosition: |
159 if self.__settingPosition: |
156 self.setCursor(Qt.CursorShape.OpenHandCursor) |
160 self.setCursor(Qt.CursorShape.OpenHandCursor) |
157 |
161 |
158 def showNotification(self, icon, heading, text, |
162 def showNotification( |
159 kind=NotificationTypes.INFORMATION, timeout=0): |
163 self, icon, heading, text, kind=NotificationTypes.INFORMATION, timeout=0 |
|
164 ): |
160 """ |
165 """ |
161 Public method to show a notification. |
166 Public method to show a notification. |
162 |
167 |
163 @param icon icon to be used |
168 @param icon icon to be used |
164 @type QPixmap |
169 @type QPixmap |
165 @param heading heading to be used |
170 @param heading heading to be used |
166 @type str |
171 @type str |
167 @param text text to be used |
172 @param text text to be used |
171 @param timeout timeout in seconds after which the notification is |
176 @param timeout timeout in seconds after which the notification is |
172 to be removed (0 = do not remove until it is clicked on) |
177 to be removed (0 = do not remove until it is clicked on) |
173 @type int |
178 @type int |
174 """ |
179 """ |
175 notificationFrame = NotificationFrame( |
180 notificationFrame = NotificationFrame( |
176 icon, heading, text, kind=kind, parent=self) |
181 icon, heading, text, kind=kind, parent=self |
|
182 ) |
177 self.__layout.addWidget(notificationFrame) |
183 self.__layout.addWidget(notificationFrame) |
178 self.__notifications.append(notificationFrame) |
184 self.__notifications.append(notificationFrame) |
179 |
185 |
180 self.show() |
186 self.show() |
181 |
187 |
182 self.__adjustSizeAndPosition() |
188 self.__adjustSizeAndPosition() |
183 |
189 |
184 if timeout: |
190 if timeout: |
185 timer = QTimer() |
191 timer = QTimer() |
186 self.__timers[id(notificationFrame)] = timer |
192 self.__timers[id(notificationFrame)] = timer |
187 timer.setSingleShot(True) |
193 timer.setSingleShot(True) |
188 timer.timeout.connect( |
194 timer.timeout.connect(lambda: self.__removeNotification(notificationFrame)) |
189 lambda: self.__removeNotification(notificationFrame) |
|
190 ) |
|
191 timer.setInterval(timeout * 1000) |
195 timer.setInterval(timeout * 1000) |
192 timer.start() |
196 timer.start() |
193 |
197 |
194 def __adjustSizeAndPosition(self): |
198 def __adjustSizeAndPosition(self): |
195 """ |
199 """ |
196 Private slot to adjust the notification list widget size and position. |
200 Private slot to adjust the notification list widget size and position. |
197 """ |
201 """ |
198 self.adjustSize() |
202 self.adjustSize() |
199 |
203 |
200 if not self.__settingPosition: |
204 if not self.__settingPosition: |
201 pos = Preferences.getUI("NotificationPosition") |
205 pos = Preferences.getUI("NotificationPosition") |
202 try: |
206 try: |
203 screen = self.screen() |
207 screen = self.screen() |
204 except AttributeError: |
208 except AttributeError: |
205 # < Qt 5.15 |
209 # < Qt 5.15 |
206 from PyQt6.QtGui import QGuiApplication |
210 from PyQt6.QtGui import QGuiApplication |
|
211 |
207 screen = QGuiApplication.screenAt(pos) |
212 screen = QGuiApplication.screenAt(pos) |
208 screenGeom = screen.geometry() |
213 screenGeom = screen.geometry() |
209 |
214 |
210 newX = pos.x() |
215 newX = pos.x() |
211 newY = pos.y() |
216 newY = pos.y() |
212 if newX < screenGeom.x(): |
217 if newX < screenGeom.x(): |
213 newX = screenGeom.x() |
218 newX = screenGeom.x() |
214 if newY < screenGeom.y(): |
219 if newY < screenGeom.y(): |
215 newY = screenGeom.y() |
220 newY = screenGeom.y() |
216 if newX + self.width() > screenGeom.width(): |
221 if newX + self.width() > screenGeom.width(): |
217 newX = screenGeom.width() - self.width() |
222 newX = screenGeom.width() - self.width() |
218 if newY + self.height() > screenGeom.height(): |
223 if newY + self.height() > screenGeom.height(): |
219 newY = screenGeom.height() - self.height() |
224 newY = screenGeom.height() - self.height() |
220 |
225 |
221 self.move(newX, newY) |
226 self.move(newX, newY) |
222 |
227 |
223 def __removeNotification(self, notification): |
228 def __removeNotification(self, notification): |
224 """ |
229 """ |
225 Private method to remove a notification from the list. |
230 Private method to remove a notification from the list. |
226 |
231 |
227 @param notification reference to the notification to be removed |
232 @param notification reference to the notification to be removed |
228 @type NotificationFrame |
233 @type NotificationFrame |
229 """ |
234 """ |
230 notification.hide() |
235 notification.hide() |
231 |
236 |
232 # delete timer of an auto close notification |
237 # delete timer of an auto close notification |
233 key = id(notification) |
238 key = id(notification) |
234 if key in self.__timers: |
239 if key in self.__timers: |
235 self.__timers[key].stop() |
240 self.__timers[key].stop() |
236 del self.__timers[key] |
241 del self.__timers[key] |
237 |
242 |
238 # delete the notification |
243 # delete the notification |
239 index = self.__layout.indexOf(notification) |
244 index = self.__layout.indexOf(notification) |
240 self.__layout.takeAt(index) |
245 self.__layout.takeAt(index) |
241 with contextlib.suppress(ValueError): |
246 with contextlib.suppress(ValueError): |
242 self.__notifications.remove(notification) |
247 self.__notifications.remove(notification) |
243 notification.deleteLater() |
248 notification.deleteLater() |
244 |
249 |
245 if self.__layout.count(): |
250 if self.__layout.count(): |
246 self.__adjustSizeAndPosition() |
251 self.__adjustSizeAndPosition() |
247 else: |
252 else: |
248 self.hide() |
253 self.hide() |
249 |
254 |
250 def mousePressEvent(self, evt): |
255 def mousePressEvent(self, evt): |
251 """ |
256 """ |
252 Protected method to handle presses of a mouse button. |
257 Protected method to handle presses of a mouse button. |
253 |
258 |
254 @param evt reference to the mouse event (QMouseEvent) |
259 @param evt reference to the mouse event (QMouseEvent) |
255 """ |
260 """ |
256 if not self.__settingPosition: |
261 if not self.__settingPosition: |
257 clickedLabel = self.childAt(evt.position().toPoint()) |
262 clickedLabel = self.childAt(evt.position().toPoint()) |
258 if clickedLabel: |
263 if clickedLabel: |
259 clickedNotification = clickedLabel.parent() |
264 clickedNotification = clickedLabel.parent() |
260 self.__removeNotification(clickedNotification) |
265 self.__removeNotification(clickedNotification) |
261 return |
266 return |
262 |
267 |
263 if evt.button() == Qt.MouseButton.LeftButton: |
268 if evt.button() == Qt.MouseButton.LeftButton: |
264 self.__dragPosition = ( |
269 self.__dragPosition = ( |
265 evt.globalPosition().toPoint() - self.frameGeometry().topLeft() |
270 evt.globalPosition().toPoint() - self.frameGeometry().topLeft() |
266 ) |
271 ) |
267 self.setCursor(Qt.CursorShape.ClosedHandCursor) |
272 self.setCursor(Qt.CursorShape.ClosedHandCursor) |
268 evt.accept() |
273 evt.accept() |
269 |
274 |
270 def mouseReleaseEvent(self, evt): |
275 def mouseReleaseEvent(self, evt): |
271 """ |
276 """ |
272 Protected method to handle releases of a mouse button. |
277 Protected method to handle releases of a mouse button. |
273 |
278 |
274 @param evt reference to the mouse event (QMouseEvent) |
279 @param evt reference to the mouse event (QMouseEvent) |
275 """ |
280 """ |
276 if ( |
281 if self.__settingPosition and evt.button() == Qt.MouseButton.LeftButton: |
277 self.__settingPosition and |
|
278 evt.button() == Qt.MouseButton.LeftButton |
|
279 ): |
|
280 self.setCursor(Qt.CursorShape.OpenHandCursor) |
282 self.setCursor(Qt.CursorShape.OpenHandCursor) |
281 |
283 |
282 def mouseMoveEvent(self, evt): |
284 def mouseMoveEvent(self, evt): |
283 """ |
285 """ |
284 Protected method to handle dragging the window. |
286 Protected method to handle dragging the window. |
285 |
287 |
286 @param evt reference to the mouse event (QMouseEvent) |
288 @param evt reference to the mouse event (QMouseEvent) |
287 """ |
289 """ |
288 if evt.buttons() & Qt.MouseButton.LeftButton: |
290 if evt.buttons() & Qt.MouseButton.LeftButton: |
289 self.move(evt.globalPosition().toPoint() - self.__dragPosition) |
291 self.move(evt.globalPosition().toPoint() - self.__dragPosition) |
290 evt.accept() |
292 evt.accept() |