|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2012 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a grabber widget for a rectangular snapshot region. |
|
8 """ |
|
9 |
|
10 from PyQt6.QtCore import pyqtSignal, Qt, QRect, QPoint, QTimer, QLocale |
|
11 from PyQt6.QtGui import ( |
|
12 QPixmap, QColor, QRegion, QPainter, QPalette, QPaintEngine, QPen, QBrush, |
|
13 QGuiApplication, QCursor |
|
14 ) |
|
15 from PyQt6.QtWidgets import QWidget, QToolTip |
|
16 |
|
17 import Globals |
|
18 |
|
19 |
|
20 def drawRect(painter, rect, outline, fill=None): |
|
21 """ |
|
22 Module function to draw a rectangle with the given parameters. |
|
23 |
|
24 @param painter reference to the painter to be used (QPainter) |
|
25 @param rect rectangle to be drawn (QRect) |
|
26 @param outline color of the outline (QColor) |
|
27 @param fill fill color (QColor) |
|
28 """ |
|
29 clip = QRegion(rect) |
|
30 clip = clip.subtracted(QRegion(rect.adjusted(1, 1, -1, -1))) |
|
31 |
|
32 painter.save() |
|
33 painter.setClipRegion(clip) |
|
34 painter.setPen(Qt.PenStyle.NoPen) |
|
35 painter.setBrush(outline) |
|
36 painter.drawRect(rect) |
|
37 if fill is not None and fill.isValid(): |
|
38 painter.setClipping(False) |
|
39 painter.setBrush(fill) |
|
40 painter.drawRect(rect.adjusted(1, 1, -1, -1)) |
|
41 painter.restore() |
|
42 |
|
43 |
|
44 class SnapshotRegionGrabber(QWidget): |
|
45 """ |
|
46 Class implementing a grabber widget for a rectangular snapshot region. |
|
47 |
|
48 @signal grabbed(QPixmap) emitted after the region was grabbed |
|
49 """ |
|
50 grabbed = pyqtSignal(QPixmap) |
|
51 |
|
52 StrokeMask = 0 |
|
53 FillMask = 1 |
|
54 |
|
55 Rectangle = 0 |
|
56 Ellipse = 1 |
|
57 |
|
58 def __init__(self, mode=Rectangle): |
|
59 """ |
|
60 Constructor |
|
61 |
|
62 @param mode region grabber mode (SnapshotRegionGrabber.Rectangle or |
|
63 SnapshotRegionGrabber.Ellipse) |
|
64 @exception ValueError raised to indicate a bad value for the 'mode' |
|
65 parameter |
|
66 """ |
|
67 super().__init__( |
|
68 None, |
|
69 Qt.WindowType.X11BypassWindowManagerHint | |
|
70 Qt.WindowType.WindowStaysOnTopHint | |
|
71 Qt.WindowType.FramelessWindowHint | |
|
72 Qt.WindowType.Tool |
|
73 ) |
|
74 |
|
75 if mode not in [SnapshotRegionGrabber.Rectangle, |
|
76 SnapshotRegionGrabber.Ellipse]: |
|
77 raise ValueError("Bad value for 'mode' parameter.") |
|
78 self.__mode = mode |
|
79 |
|
80 self.__selection = QRect() |
|
81 self.__mouseDown = False |
|
82 self.__newSelection = False |
|
83 self.__handleSize = 10 |
|
84 self.__mouseOverHandle = None |
|
85 self.__showHelp = True |
|
86 self.__grabbing = False |
|
87 self.__dragStartPoint = QPoint() |
|
88 self.__selectionBeforeDrag = QRect() |
|
89 self.__locale = QLocale() |
|
90 |
|
91 # naming conventions for handles |
|
92 # T top, B bottom, R Right, L left |
|
93 # 2 letters: a corner |
|
94 # 1 letter: the handle on the middle of the corresponding side |
|
95 self.__TLHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
96 self.__TRHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
97 self.__BLHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
98 self.__BRHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
99 self.__LHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
100 self.__THandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
101 self.__RHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
102 self.__BHandle = QRect(0, 0, self.__handleSize, self.__handleSize) |
|
103 self.__handles = [self.__TLHandle, self.__TRHandle, self.__BLHandle, |
|
104 self.__BRHandle, self.__LHandle, self.__THandle, |
|
105 self.__RHandle, self.__BHandle] |
|
106 self.__helpTextRect = QRect() |
|
107 self.__helpText = self.tr( |
|
108 "Select a region using the mouse. To take the snapshot, press" |
|
109 " the Enter key or double click. Press Esc to quit.") |
|
110 |
|
111 self.__pixmap = QPixmap() |
|
112 |
|
113 self.setMouseTracking(True) |
|
114 |
|
115 QTimer.singleShot(200, self.__initialize) |
|
116 |
|
117 def __initialize(self): |
|
118 """ |
|
119 Private slot to initialize the rest of the widget. |
|
120 """ |
|
121 if Globals.isMacPlatform(): |
|
122 # macOS variant |
|
123 screen = QGuiApplication.screenAt(QCursor.pos()) |
|
124 geom = screen.geometry() |
|
125 self.__pixmap = screen.grabWindow( |
|
126 0, geom.x(), geom.y(), geom.width(), geom.height()) |
|
127 else: |
|
128 # Linux variant |
|
129 # Windows variant |
|
130 screen = QGuiApplication.screens()[0] |
|
131 geom = screen.availableVirtualGeometry() |
|
132 self.__pixmap = screen.grabWindow( |
|
133 0, geom.x(), geom.y(), geom.width(), geom.height()) |
|
134 self.resize(self.__pixmap.size()) |
|
135 self.move(geom.x(), geom.y()) |
|
136 self.setCursor(Qt.CursorShape.CrossCursor) |
|
137 self.show() |
|
138 |
|
139 self.grabMouse() |
|
140 self.grabKeyboard() |
|
141 self.activateWindow() |
|
142 |
|
143 def paintEvent(self, evt): |
|
144 """ |
|
145 Protected method handling paint events. |
|
146 |
|
147 @param evt paint event (QPaintEvent) |
|
148 """ |
|
149 if self.__grabbing: # grabWindow() should just get the background |
|
150 return |
|
151 |
|
152 painter = QPainter(self) |
|
153 pal = QPalette(QToolTip.palette()) |
|
154 font = QToolTip.font() |
|
155 |
|
156 handleColor = pal.color(QPalette.ColorGroup.Active, |
|
157 QPalette.ColorRole.Highlight) |
|
158 handleColor.setAlpha(160) |
|
159 overlayColor = QColor(0, 0, 0, 160) |
|
160 textColor = pal.color(QPalette.ColorGroup.Active, |
|
161 QPalette.ColorRole.Text) |
|
162 textBackgroundColor = pal.color(QPalette.ColorGroup.Active, |
|
163 QPalette.ColorRole.Base) |
|
164 painter.drawPixmap(0, 0, self.__pixmap) |
|
165 painter.setFont(font) |
|
166 |
|
167 r = QRect(self.__selection) |
|
168 if not self.__selection.isNull(): |
|
169 grey = QRegion(self.rect()) |
|
170 if self.__mode == SnapshotRegionGrabber.Ellipse: |
|
171 reg = QRegion(r, QRegion.RegionType.Ellipse) |
|
172 else: |
|
173 reg = QRegion(r) |
|
174 grey = grey.subtracted(reg) |
|
175 painter.setClipRegion(grey) |
|
176 painter.setPen(Qt.PenStyle.NoPen) |
|
177 painter.setBrush(overlayColor) |
|
178 painter.drawRect(self.rect()) |
|
179 painter.setClipRect(self.rect()) |
|
180 drawRect(painter, r, handleColor) |
|
181 |
|
182 if self.__showHelp: |
|
183 painter.setPen(textColor) |
|
184 painter.setBrush(textBackgroundColor) |
|
185 self.__helpTextRect = painter.boundingRect( |
|
186 self.rect().adjusted(2, 2, -2, -2), |
|
187 Qt.TextFlag.TextWordWrap, self.__helpText).translated(0, 0) |
|
188 self.__helpTextRect.adjust(-2, -2, 4, 2) |
|
189 drawRect(painter, self.__helpTextRect, textColor, |
|
190 textBackgroundColor) |
|
191 painter.drawText( |
|
192 self.__helpTextRect.adjusted(3, 3, -3, -3), |
|
193 Qt.TextFlag.TextWordWrap, self.__helpText) |
|
194 |
|
195 if self.__selection.isNull(): |
|
196 return |
|
197 |
|
198 # The grabbed region is everything which is covered by the drawn |
|
199 # rectangles (border included). This means that there is no 0px |
|
200 # selection, since a 0px wide rectangle will always be drawn as a line. |
|
201 txt = "{0}, {1} ({2} x {3})".format( |
|
202 self.__locale.toString(self.__selection.x()), |
|
203 self.__locale.toString(self.__selection.y()), |
|
204 self.__locale.toString(self.__selection.width()), |
|
205 self.__locale.toString(self.__selection.height()) |
|
206 ) |
|
207 textRect = painter.boundingRect(self.rect(), |
|
208 Qt.AlignmentFlag.AlignLeft, txt) |
|
209 boundingRect = textRect.adjusted(-4, 0, 0, 0) |
|
210 |
|
211 if ( |
|
212 textRect.width() < r.width() - 2 * self.__handleSize and |
|
213 textRect.height() < r.height() - 2 * self.__handleSize and |
|
214 r.width() > 100 and |
|
215 r.height() > 100 |
|
216 ): |
|
217 # center, unsuitable for small selections |
|
218 boundingRect.moveCenter(r.center()) |
|
219 textRect.moveCenter(r.center()) |
|
220 elif ( |
|
221 r.y() - 3 > textRect.height() and |
|
222 r.x() + textRect.width() < self.rect().width() |
|
223 ): |
|
224 # on top, left aligned |
|
225 boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) |
|
226 textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) |
|
227 elif r.x() - 3 > textRect.width(): |
|
228 # left, top aligned |
|
229 boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) |
|
230 textRect.moveTopRight(QPoint(r.x() - 5, r.y())) |
|
231 elif ( |
|
232 r.bottom() + 3 + textRect.height() < self.rect().bottom() and |
|
233 r.right() > textRect.width() |
|
234 ): |
|
235 # at bottom, right aligned |
|
236 boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) |
|
237 textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) |
|
238 elif r.right() + textRect.width() + 3 < self.rect().width(): |
|
239 # right, bottom aligned |
|
240 boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) |
|
241 textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) |
|
242 |
|
243 # If the above didn't catch it, you are running on a very |
|
244 # tiny screen... |
|
245 drawRect(painter, boundingRect, textColor, textBackgroundColor) |
|
246 painter.drawText(textRect, Qt.AlignmentFlag.AlignHCenter, txt) |
|
247 |
|
248 if ( |
|
249 (r.height() > self.__handleSize * 2 and |
|
250 r.width() > self.__handleSize * 2) or |
|
251 not self.__mouseDown |
|
252 ): |
|
253 self.__updateHandles() |
|
254 painter.setPen(Qt.PenStyle.NoPen) |
|
255 painter.setBrush(handleColor) |
|
256 painter.setClipRegion( |
|
257 self.__handleMask(SnapshotRegionGrabber.StrokeMask)) |
|
258 painter.drawRect(self.rect()) |
|
259 handleColor.setAlpha(60) |
|
260 painter.setBrush(handleColor) |
|
261 painter.setClipRegion( |
|
262 self.__handleMask(SnapshotRegionGrabber.FillMask)) |
|
263 painter.drawRect(self.rect()) |
|
264 |
|
265 def resizeEvent(self, evt): |
|
266 """ |
|
267 Protected method to handle resize events. |
|
268 |
|
269 @param evt resize event (QResizeEvent) |
|
270 """ |
|
271 if self.__selection.isNull(): |
|
272 return |
|
273 |
|
274 r = QRect(self.__selection) |
|
275 r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) |
|
276 r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect())) |
|
277 if r.width() <= 1 or r.height() <= 1: |
|
278 # This just results in ugly drawing... |
|
279 self.__selection = QRect() |
|
280 else: |
|
281 self.__selection = self.__normalizeSelection(r) |
|
282 |
|
283 def mousePressEvent(self, evt): |
|
284 """ |
|
285 Protected method to handle mouse button presses. |
|
286 |
|
287 @param evt mouse press event (QMouseEvent) |
|
288 """ |
|
289 self.__showHelp = not self.__helpTextRect.contains( |
|
290 evt.position().toPoint()) |
|
291 if evt.button() == Qt.MouseButton.LeftButton: |
|
292 self.__mouseDown = True |
|
293 self.__dragStartPoint = evt.position().toPoint() |
|
294 self.__selectionBeforeDrag = QRect(self.__selection) |
|
295 if not self.__selection.contains(evt.position().toPoint()): |
|
296 self.__newSelection = True |
|
297 self.__selection = QRect() |
|
298 else: |
|
299 self.setCursor(Qt.CursorShape.ClosedHandCursor) |
|
300 elif evt.button() == Qt.MouseButton.RightButton: |
|
301 self.__newSelection = False |
|
302 self.__selection = QRect() |
|
303 self.setCursor(Qt.CursorShape.CrossCursor) |
|
304 self.update() |
|
305 |
|
306 def mouseMoveEvent(self, evt): |
|
307 """ |
|
308 Protected method to handle mouse movements. |
|
309 |
|
310 @param evt mouse move event (QMouseEvent) |
|
311 """ |
|
312 shouldShowHelp = not self.__helpTextRect.contains( |
|
313 evt.position().toPoint()) |
|
314 if shouldShowHelp != self.__showHelp: |
|
315 self.__showHelp = shouldShowHelp |
|
316 self.update() |
|
317 |
|
318 if self.__mouseDown: |
|
319 if self.__newSelection: |
|
320 p = evt.position().toPoint() |
|
321 r = self.rect() |
|
322 self.__selection = self.__normalizeSelection( |
|
323 QRect(self.__dragStartPoint, |
|
324 self.__limitPointToRect(p, r))) |
|
325 elif self.__mouseOverHandle is None: |
|
326 # moving the whole selection |
|
327 r = self.rect().normalized() |
|
328 s = self.__selectionBeforeDrag.normalized() |
|
329 p = ( |
|
330 s.topLeft() + evt.position().toPoint() - |
|
331 self.__dragStartPoint |
|
332 ) |
|
333 r.setBottomRight( |
|
334 r.bottomRight() - QPoint(s.width(), s.height()) + |
|
335 QPoint(1, 1)) |
|
336 if not r.isNull() and r.isValid(): |
|
337 self.__selection.moveTo(self.__limitPointToRect(p, r)) |
|
338 else: |
|
339 # dragging a handle |
|
340 r = QRect(self.__selectionBeforeDrag) |
|
341 offset = evt.position().toPoint() - self.__dragStartPoint |
|
342 |
|
343 if self.__mouseOverHandle in [ |
|
344 self.__TLHandle, self.__THandle, self.__TRHandle]: |
|
345 r.setTop(r.top() + offset.y()) |
|
346 |
|
347 if self.__mouseOverHandle in [ |
|
348 self.__TLHandle, self.__LHandle, self.__BLHandle]: |
|
349 r.setLeft(r.left() + offset.x()) |
|
350 |
|
351 if self.__mouseOverHandle in [ |
|
352 self.__BLHandle, self.__BHandle, self.__BRHandle]: |
|
353 r.setBottom(r.bottom() + offset.y()) |
|
354 |
|
355 if self.__mouseOverHandle in [ |
|
356 self.__TRHandle, self.__RHandle, self.__BRHandle]: |
|
357 r.setRight(r.right() + offset.x()) |
|
358 |
|
359 r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect())) |
|
360 r.setBottomRight( |
|
361 self.__limitPointToRect(r.bottomRight(), self.rect())) |
|
362 self.__selection = self.__normalizeSelection(r) |
|
363 |
|
364 self.update() |
|
365 else: |
|
366 if self.__selection.isNull(): |
|
367 return |
|
368 |
|
369 found = False |
|
370 for r in self.__handles: |
|
371 if r.contains(evt.position().toPoint()): |
|
372 self.__mouseOverHandle = r |
|
373 found = True |
|
374 break |
|
375 |
|
376 if not found: |
|
377 self.__mouseOverHandle = None |
|
378 if self.__selection.contains(evt.position().toPoint()): |
|
379 self.setCursor(Qt.CursorShape.OpenHandCursor) |
|
380 else: |
|
381 self.setCursor(Qt.CursorShape.CrossCursor) |
|
382 else: |
|
383 if self.__mouseOverHandle in [self.__TLHandle, |
|
384 self.__BRHandle]: |
|
385 self.setCursor(Qt.CursorShape.SizeFDiagCursor) |
|
386 elif self.__mouseOverHandle in [self.__TRHandle, |
|
387 self.__BLHandle]: |
|
388 self.setCursor(Qt.CursorShape.SizeBDiagCursor) |
|
389 elif self.__mouseOverHandle in [self.__LHandle, |
|
390 self.__RHandle]: |
|
391 self.setCursor(Qt.CursorShape.SizeHorCursor) |
|
392 elif self.__mouseOverHandle in [self.__THandle, |
|
393 self.__BHandle]: |
|
394 self.setCursor(Qt.CursorShape.SizeVerCursor) |
|
395 |
|
396 def mouseReleaseEvent(self, evt): |
|
397 """ |
|
398 Protected method to handle mouse button releases. |
|
399 |
|
400 @param evt mouse release event (QMouseEvent) |
|
401 """ |
|
402 self.__mouseDown = False |
|
403 self.__newSelection = False |
|
404 if ( |
|
405 self.__mouseOverHandle is None and |
|
406 self.__selection.contains(evt.position().toPoint()) |
|
407 ): |
|
408 self.setCursor(Qt.CursorShape.OpenHandCursor) |
|
409 self.update() |
|
410 |
|
411 def mouseDoubleClickEvent(self, evt): |
|
412 """ |
|
413 Protected method to handle mouse double clicks. |
|
414 |
|
415 @param evt mouse double click event (QMouseEvent) |
|
416 """ |
|
417 self.__grabRect() |
|
418 |
|
419 def keyPressEvent(self, evt): |
|
420 """ |
|
421 Protected method to handle key presses. |
|
422 |
|
423 @param evt key press event (QKeyEvent) |
|
424 """ |
|
425 if evt.key() == Qt.Key.Key_Escape: |
|
426 self.grabbed.emit(QPixmap()) |
|
427 elif evt.key() in [Qt.Key.Key_Enter, Qt.Key.Key_Return]: |
|
428 self.__grabRect() |
|
429 else: |
|
430 evt.ignore() |
|
431 |
|
432 def __updateHandles(self): |
|
433 """ |
|
434 Private method to update the handles. |
|
435 """ |
|
436 r = QRect(self.__selection) |
|
437 s2 = self.__handleSize // 2 |
|
438 |
|
439 self.__TLHandle.moveTopLeft(r.topLeft()) |
|
440 self.__TRHandle.moveTopRight(r.topRight()) |
|
441 self.__BLHandle.moveBottomLeft(r.bottomLeft()) |
|
442 self.__BRHandle.moveBottomRight(r.bottomRight()) |
|
443 |
|
444 self.__LHandle.moveTopLeft( |
|
445 QPoint(r.x(), r.y() + r.height() // 2 - s2)) |
|
446 self.__THandle.moveTopLeft( |
|
447 QPoint(r.x() + r.width() // 2 - s2, r.y())) |
|
448 self.__RHandle.moveTopRight( |
|
449 QPoint(r.right(), r.y() + r.height() // 2 - s2)) |
|
450 self.__BHandle.moveBottomLeft( |
|
451 QPoint(r.x() + r.width() // 2 - s2, r.bottom())) |
|
452 |
|
453 def __handleMask(self, maskType): |
|
454 """ |
|
455 Private method to calculate the handle mask. |
|
456 |
|
457 @param maskType type of the mask to be used |
|
458 (SnapshotRegionGrabber.FillMask or |
|
459 SnapshotRegionGrabber.StrokeMask) |
|
460 @return calculated mask (QRegion) |
|
461 """ |
|
462 mask = QRegion() |
|
463 for rect in self.__handles: |
|
464 if maskType == SnapshotRegionGrabber.StrokeMask: |
|
465 r = QRegion(rect) |
|
466 mask += r.subtracted(QRegion(rect.adjusted(1, 1, -1, -1))) |
|
467 else: |
|
468 mask += QRegion(rect.adjusted(1, 1, -1, -1)) |
|
469 return mask |
|
470 |
|
471 def __limitPointToRect(self, point, rect): |
|
472 """ |
|
473 Private method to limit the given point to the given rectangle. |
|
474 |
|
475 @param point point to be limited (QPoint) |
|
476 @param rect rectangle the point shall be limited to (QRect) |
|
477 @return limited point (QPoint) |
|
478 """ |
|
479 q = QPoint() |
|
480 if point.x() < rect.x(): |
|
481 q.setX(rect.x()) |
|
482 elif point.x() < rect.right(): |
|
483 q.setX(point.x()) |
|
484 else: |
|
485 q.setX(rect.right()) |
|
486 if point.y() < rect.y(): |
|
487 q.setY(rect.y()) |
|
488 elif point.y() < rect.bottom(): |
|
489 q.setY(point.y()) |
|
490 else: |
|
491 q.setY(rect.bottom()) |
|
492 return q |
|
493 |
|
494 def __normalizeSelection(self, sel): |
|
495 """ |
|
496 Private method to normalize the given selection. |
|
497 |
|
498 @param sel selection to be normalized (QRect) |
|
499 @return normalized selection (QRect) |
|
500 """ |
|
501 rect = QRect(sel) |
|
502 if rect.width() <= 0: |
|
503 left = rect.left() |
|
504 width = rect.width() |
|
505 rect.setLeft(left + width - 1) |
|
506 rect.setRight(left) |
|
507 if rect.height() <= 0: |
|
508 top = rect.top() |
|
509 height = rect.height() |
|
510 rect.setTop(top + height - 1) |
|
511 rect.setBottom(top) |
|
512 return rect |
|
513 |
|
514 def __grabRect(self): |
|
515 """ |
|
516 Private method to grab the selected rectangle (i.e. do the snapshot). |
|
517 """ |
|
518 if self.__mode == SnapshotRegionGrabber.Ellipse: |
|
519 ell = QRegion(self.__selection, QRegion.RegionType.Ellipse) |
|
520 if not ell.isEmpty(): |
|
521 self.__grabbing = True |
|
522 |
|
523 xOffset = self.__pixmap.rect().x() - ell.boundingRect().x() |
|
524 yOffset = self.__pixmap.rect().y() - ell.boundingRect().y() |
|
525 translatedEll = ell.translated(xOffset, yOffset) |
|
526 |
|
527 pixmap2 = QPixmap(ell.boundingRect().size()) |
|
528 pixmap2.fill(Qt.GlobalColor.transparent) |
|
529 |
|
530 pt = QPainter() |
|
531 pt.begin(pixmap2) |
|
532 if pt.paintEngine().hasFeature( |
|
533 QPaintEngine.PaintEngineFeature.PorterDuff |
|
534 ): |
|
535 pt.setRenderHints( |
|
536 QPainter.RenderHint.Antialiasing | |
|
537 QPainter.RenderHint.SmoothPixmapTransform, |
|
538 True) |
|
539 pt.setBrush(Qt.GlobalColor.black) |
|
540 pt.setPen(QPen(QBrush(Qt.GlobalColor.black), 0.5)) |
|
541 pt.drawEllipse(translatedEll.boundingRect()) |
|
542 pt.setCompositionMode( |
|
543 QPainter.CompositionMode.CompositionMode_SourceIn) |
|
544 else: |
|
545 pt.setClipRegion(translatedEll) |
|
546 pt.setCompositionMode( |
|
547 QPainter.CompositionMode.CompositionMode_Source) |
|
548 |
|
549 pt.drawPixmap(pixmap2.rect(), self.__pixmap, |
|
550 ell.boundingRect()) |
|
551 pt.end() |
|
552 |
|
553 self.grabbed.emit(pixmap2) |
|
554 else: |
|
555 r = QRect(self.__selection) |
|
556 if not r.isNull() and r.isValid(): |
|
557 self.__grabbing = True |
|
558 self.grabbed.emit(self.__pixmap.copy(r)) |