src/eric7/Snapshot/SnapshotRegionGrabber.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/Snapshot/SnapshotRegionGrabber.py
--- a/src/eric7/Snapshot/SnapshotRegionGrabber.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/Snapshot/SnapshotRegionGrabber.py	Wed Jul 13 14:55:47 2022 +0200
@@ -9,8 +9,16 @@
 
 from PyQt6.QtCore import pyqtSignal, Qt, QRect, QPoint, QTimer, QLocale
 from PyQt6.QtGui import (
-    QPixmap, QColor, QRegion, QPainter, QPalette, QPaintEngine, QPen, QBrush,
-    QGuiApplication, QCursor
+    QPixmap,
+    QColor,
+    QRegion,
+    QPainter,
+    QPalette,
+    QPaintEngine,
+    QPen,
+    QBrush,
+    QGuiApplication,
+    QCursor,
 )
 from PyQt6.QtWidgets import QWidget, QToolTip
 
@@ -20,7 +28,7 @@
 def drawRect(painter, rect, outline, fill=None):
     """
     Module function to draw a rectangle with the given parameters.
-    
+
     @param painter reference to the painter to be used (QPainter)
     @param rect rectangle to be drawn (QRect)
     @param outline color of the outline (QColor)
@@ -28,7 +36,7 @@
     """
     clip = QRegion(rect)
     clip = clip.subtracted(QRegion(rect.adjusted(1, 1, -1, -1)))
-    
+
     painter.save()
     painter.setClipRegion(clip)
     painter.setPen(Qt.PenStyle.NoPen)
@@ -44,21 +52,22 @@
 class SnapshotRegionGrabber(QWidget):
     """
     Class implementing a grabber widget for a rectangular snapshot region.
-    
+
     @signal grabbed(QPixmap) emitted after the region was grabbed
     """
+
     grabbed = pyqtSignal(QPixmap)
-    
+
     StrokeMask = 0
     FillMask = 1
-    
+
     Rectangle = 0
     Ellipse = 1
-    
+
     def __init__(self, mode=Rectangle):
         """
         Constructor
-        
+
         @param mode region grabber mode (SnapshotRegionGrabber.Rectangle or
             SnapshotRegionGrabber.Ellipse)
         @exception ValueError raised to indicate a bad value for the 'mode'
@@ -66,17 +75,16 @@
         """
         super().__init__(
             None,
-            Qt.WindowType.X11BypassWindowManagerHint |
-            Qt.WindowType.WindowStaysOnTopHint |
-            Qt.WindowType.FramelessWindowHint |
-            Qt.WindowType.Tool
+            Qt.WindowType.X11BypassWindowManagerHint
+            | Qt.WindowType.WindowStaysOnTopHint
+            | Qt.WindowType.FramelessWindowHint
+            | Qt.WindowType.Tool,
         )
-        
-        if mode not in [SnapshotRegionGrabber.Rectangle,
-                        SnapshotRegionGrabber.Ellipse]:
+
+        if mode not in [SnapshotRegionGrabber.Rectangle, SnapshotRegionGrabber.Ellipse]:
             raise ValueError("Bad value for 'mode' parameter.")
         self.__mode = mode
-        
+
         self.__selection = QRect()
         self.__mouseDown = False
         self.__newSelection = False
@@ -87,7 +95,7 @@
         self.__dragStartPoint = QPoint()
         self.__selectionBeforeDrag = QRect()
         self.__locale = QLocale()
-        
+
         # naming conventions for handles
         # T top, B bottom, R Right, L left
         # 2 letters: a corner
@@ -100,20 +108,28 @@
         self.__THandle = QRect(0, 0, self.__handleSize, self.__handleSize)
         self.__RHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
         self.__BHandle = QRect(0, 0, self.__handleSize, self.__handleSize)
-        self.__handles = [self.__TLHandle, self.__TRHandle, self.__BLHandle,
-                          self.__BRHandle, self.__LHandle, self.__THandle,
-                          self.__RHandle, self.__BHandle]
+        self.__handles = [
+            self.__TLHandle,
+            self.__TRHandle,
+            self.__BLHandle,
+            self.__BRHandle,
+            self.__LHandle,
+            self.__THandle,
+            self.__RHandle,
+            self.__BHandle,
+        ]
         self.__helpTextRect = QRect()
         self.__helpText = self.tr(
             "Select a region using the mouse. To take the snapshot, press"
-            " the Enter key or double click. Press Esc to quit.")
-        
+            " the Enter key or double click. Press Esc to quit."
+        )
+
         self.__pixmap = QPixmap()
-        
+
         self.setMouseTracking(True)
-        
+
         QTimer.singleShot(200, self.__initialize)
-    
+
     def __initialize(self):
         """
         Private slot to initialize the rest of the widget.
@@ -123,14 +139,16 @@
             screen = QGuiApplication.screenAt(QCursor.pos())
             geom = screen.geometry()
             self.__pixmap = screen.grabWindow(
-                0, geom.x(), geom.y(), geom.width(), geom.height())
+                0, geom.x(), geom.y(), geom.width(), geom.height()
+            )
         else:
             # Linux variant
             # Windows variant
             screen = QGuiApplication.screens()[0]
             geom = screen.availableVirtualGeometry()
             self.__pixmap = screen.grabWindow(
-                0, geom.x(), geom.y(), geom.width(), geom.height())
+                0, geom.x(), geom.y(), geom.width(), geom.height()
+            )
         self.resize(self.__pixmap.size())
         self.move(geom.x(), geom.y())
         self.setCursor(Qt.CursorShape.CrossCursor)
@@ -139,31 +157,32 @@
         self.grabMouse()
         self.grabKeyboard()
         self.activateWindow()
-    
+
     def paintEvent(self, evt):
         """
         Protected method handling paint events.
-        
+
         @param evt paint event (QPaintEvent)
         """
-        if self.__grabbing:     # grabWindow() should just get the background
+        if self.__grabbing:  # grabWindow() should just get the background
             return
-        
+
         painter = QPainter(self)
         pal = QPalette(QToolTip.palette())
         font = QToolTip.font()
-        
-        handleColor = pal.color(QPalette.ColorGroup.Active,
-                                QPalette.ColorRole.Highlight)
+
+        handleColor = pal.color(
+            QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight
+        )
         handleColor.setAlpha(160)
         overlayColor = QColor(0, 0, 0, 160)
-        textColor = pal.color(QPalette.ColorGroup.Active,
-                              QPalette.ColorRole.Text)
-        textBackgroundColor = pal.color(QPalette.ColorGroup.Active,
-                                        QPalette.ColorRole.Base)
+        textColor = pal.color(QPalette.ColorGroup.Active, QPalette.ColorRole.Text)
+        textBackgroundColor = pal.color(
+            QPalette.ColorGroup.Active, QPalette.ColorRole.Base
+        )
         painter.drawPixmap(0, 0, self.__pixmap)
         painter.setFont(font)
-        
+
         r = QRect(self.__selection)
         if not self.__selection.isNull():
             grey = QRegion(self.rect())
@@ -178,23 +197,26 @@
             painter.drawRect(self.rect())
             painter.setClipRect(self.rect())
             drawRect(painter, r, handleColor)
-        
+
         if self.__showHelp:
             painter.setPen(textColor)
             painter.setBrush(textBackgroundColor)
             self.__helpTextRect = painter.boundingRect(
                 self.rect().adjusted(2, 2, -2, -2),
-                Qt.TextFlag.TextWordWrap, self.__helpText).translated(0, 0)
+                Qt.TextFlag.TextWordWrap,
+                self.__helpText,
+            ).translated(0, 0)
             self.__helpTextRect.adjust(-2, -2, 4, 2)
-            drawRect(painter, self.__helpTextRect, textColor,
-                     textBackgroundColor)
+            drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor)
             painter.drawText(
                 self.__helpTextRect.adjusted(3, 3, -3, -3),
-                Qt.TextFlag.TextWordWrap, self.__helpText)
-        
+                Qt.TextFlag.TextWordWrap,
+                self.__helpText,
+            )
+
         if self.__selection.isNull():
             return
-        
+
         # The grabbed region is everything which is covered by the drawn
         # rectangles (border included). This means that there is no 0px
         # selection, since a 0px wide rectangle will always be drawn as a line.
@@ -202,24 +224,23 @@
             self.__locale.toString(self.__selection.x()),
             self.__locale.toString(self.__selection.y()),
             self.__locale.toString(self.__selection.width()),
-            self.__locale.toString(self.__selection.height())
+            self.__locale.toString(self.__selection.height()),
         )
-        textRect = painter.boundingRect(self.rect(),
-                                        Qt.AlignmentFlag.AlignLeft, txt)
+        textRect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignLeft, txt)
         boundingRect = textRect.adjusted(-4, 0, 0, 0)
-        
+
         if (
-            textRect.width() < r.width() - 2 * self.__handleSize and
-            textRect.height() < r.height() - 2 * self.__handleSize and
-            r.width() > 100 and
-            r.height() > 100
+            textRect.width() < r.width() - 2 * self.__handleSize
+            and textRect.height() < r.height() - 2 * self.__handleSize
+            and r.width() > 100
+            and r.height() > 100
         ):
             # center, unsuitable for small selections
             boundingRect.moveCenter(r.center())
             textRect.moveCenter(r.center())
         elif (
-            r.y() - 3 > textRect.height() and
-            r.x() + textRect.width() < self.rect().width()
+            r.y() - 3 > textRect.height()
+            and r.x() + textRect.width() < self.rect().width()
         ):
             # on top, left aligned
             boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3))
@@ -229,8 +250,8 @@
             boundingRect.moveTopRight(QPoint(r.x() - 3, r.y()))
             textRect.moveTopRight(QPoint(r.x() - 5, r.y()))
         elif (
-            r.bottom() + 3 + textRect.height() < self.rect().bottom() and
-            r.right() > textRect.width()
+            r.bottom() + 3 + textRect.height() < self.rect().bottom()
+            and r.right() > textRect.width()
         ):
             # at bottom, right aligned
             boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3))
@@ -239,38 +260,34 @@
             # right, bottom aligned
             boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom()))
             textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom()))
-        
+
         # If the above didn't catch it, you are running on a very
         # tiny screen...
         drawRect(painter, boundingRect, textColor, textBackgroundColor)
         painter.drawText(textRect, Qt.AlignmentFlag.AlignHCenter, txt)
-        
+
         if (
-            (r.height() > self.__handleSize * 2 and
-             r.width() > self.__handleSize * 2) or
-            not self.__mouseDown
-        ):
+            r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2
+        ) or not self.__mouseDown:
             self.__updateHandles()
             painter.setPen(Qt.PenStyle.NoPen)
             painter.setBrush(handleColor)
-            painter.setClipRegion(
-                self.__handleMask(SnapshotRegionGrabber.StrokeMask))
+            painter.setClipRegion(self.__handleMask(SnapshotRegionGrabber.StrokeMask))
             painter.drawRect(self.rect())
             handleColor.setAlpha(60)
             painter.setBrush(handleColor)
-            painter.setClipRegion(
-                self.__handleMask(SnapshotRegionGrabber.FillMask))
+            painter.setClipRegion(self.__handleMask(SnapshotRegionGrabber.FillMask))
             painter.drawRect(self.rect())
-    
+
     def resizeEvent(self, evt):
         """
         Protected method to handle resize events.
-        
+
         @param evt resize event (QResizeEvent)
         """
         if self.__selection.isNull():
             return
-        
+
         r = QRect(self.__selection)
         r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
         r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
@@ -279,15 +296,14 @@
             self.__selection = QRect()
         else:
             self.__selection = self.__normalizeSelection(r)
-    
+
     def mousePressEvent(self, evt):
         """
         Protected method to handle mouse button presses.
-        
+
         @param evt mouse press event (QMouseEvent)
         """
-        self.__showHelp = not self.__helpTextRect.contains(
-            evt.position().toPoint())
+        self.__showHelp = not self.__helpTextRect.contains(evt.position().toPoint())
         if evt.button() == Qt.MouseButton.LeftButton:
             self.__mouseDown = True
             self.__dragStartPoint = evt.position().toPoint()
@@ -302,77 +318,84 @@
             self.__selection = QRect()
             self.setCursor(Qt.CursorShape.CrossCursor)
         self.update()
-    
+
     def mouseMoveEvent(self, evt):
         """
         Protected method to handle mouse movements.
-        
+
         @param evt mouse move event (QMouseEvent)
         """
-        shouldShowHelp = not self.__helpTextRect.contains(
-            evt.position().toPoint())
+        shouldShowHelp = not self.__helpTextRect.contains(evt.position().toPoint())
         if shouldShowHelp != self.__showHelp:
             self.__showHelp = shouldShowHelp
             self.update()
-        
+
         if self.__mouseDown:
             if self.__newSelection:
                 p = evt.position().toPoint()
                 r = self.rect()
                 self.__selection = self.__normalizeSelection(
-                    QRect(self.__dragStartPoint,
-                          self.__limitPointToRect(p, r)))
+                    QRect(self.__dragStartPoint, self.__limitPointToRect(p, r))
+                )
             elif self.__mouseOverHandle is None:
                 # moving the whole selection
                 r = self.rect().normalized()
                 s = self.__selectionBeforeDrag.normalized()
-                p = (
-                    s.topLeft() + evt.position().toPoint() -
-                    self.__dragStartPoint
+                p = s.topLeft() + evt.position().toPoint() - self.__dragStartPoint
+                r.setBottomRight(
+                    r.bottomRight() - QPoint(s.width(), s.height()) + QPoint(1, 1)
                 )
-                r.setBottomRight(
-                    r.bottomRight() - QPoint(s.width(), s.height()) +
-                    QPoint(1, 1))
                 if not r.isNull() and r.isValid():
                     self.__selection.moveTo(self.__limitPointToRect(p, r))
             else:
                 # dragging a handle
                 r = QRect(self.__selectionBeforeDrag)
                 offset = evt.position().toPoint() - self.__dragStartPoint
-                
+
                 if self.__mouseOverHandle in [
-                        self.__TLHandle, self.__THandle, self.__TRHandle]:
+                    self.__TLHandle,
+                    self.__THandle,
+                    self.__TRHandle,
+                ]:
                     r.setTop(r.top() + offset.y())
-                
+
                 if self.__mouseOverHandle in [
-                        self.__TLHandle, self.__LHandle, self.__BLHandle]:
+                    self.__TLHandle,
+                    self.__LHandle,
+                    self.__BLHandle,
+                ]:
                     r.setLeft(r.left() + offset.x())
-                
+
                 if self.__mouseOverHandle in [
-                        self.__BLHandle, self.__BHandle, self.__BRHandle]:
+                    self.__BLHandle,
+                    self.__BHandle,
+                    self.__BRHandle,
+                ]:
                     r.setBottom(r.bottom() + offset.y())
-                
+
                 if self.__mouseOverHandle in [
-                        self.__TRHandle, self.__RHandle, self.__BRHandle]:
+                    self.__TRHandle,
+                    self.__RHandle,
+                    self.__BRHandle,
+                ]:
                     r.setRight(r.right() + offset.x())
-                
+
                 r.setTopLeft(self.__limitPointToRect(r.topLeft(), self.rect()))
-                r.setBottomRight(
-                    self.__limitPointToRect(r.bottomRight(), self.rect()))
+                r.setBottomRight(self.__limitPointToRect(r.bottomRight(), self.rect()))
                 self.__selection = self.__normalizeSelection(r)
-            
+
             self.update()
         else:
             if self.__selection.isNull():
                 return
-            
+
             found = False
             for r in self.__handles:
                 if r.contains(evt.position().toPoint()):
                     self.__mouseOverHandle = r
                     found = True
                     break
-            
+
             if not found:
                 self.__mouseOverHandle = None
                 if self.__selection.contains(evt.position().toPoint()):
@@ -380,46 +403,41 @@
                 else:
                     self.setCursor(Qt.CursorShape.CrossCursor)
             else:
-                if self.__mouseOverHandle in [self.__TLHandle,
-                                              self.__BRHandle]:
+                if self.__mouseOverHandle in [self.__TLHandle, self.__BRHandle]:
                     self.setCursor(Qt.CursorShape.SizeFDiagCursor)
-                elif self.__mouseOverHandle in [self.__TRHandle,
-                                                self.__BLHandle]:
+                elif self.__mouseOverHandle in [self.__TRHandle, self.__BLHandle]:
                     self.setCursor(Qt.CursorShape.SizeBDiagCursor)
-                elif self.__mouseOverHandle in [self.__LHandle,
-                                                self.__RHandle]:
+                elif self.__mouseOverHandle in [self.__LHandle, self.__RHandle]:
                     self.setCursor(Qt.CursorShape.SizeHorCursor)
-                elif self.__mouseOverHandle in [self.__THandle,
-                                                self.__BHandle]:
+                elif self.__mouseOverHandle in [self.__THandle, self.__BHandle]:
                     self.setCursor(Qt.CursorShape.SizeVerCursor)
-    
+
     def mouseReleaseEvent(self, evt):
         """
         Protected method to handle mouse button releases.
-        
+
         @param evt mouse release event (QMouseEvent)
         """
         self.__mouseDown = False
         self.__newSelection = False
-        if (
-            self.__mouseOverHandle is None and
-            self.__selection.contains(evt.position().toPoint())
+        if self.__mouseOverHandle is None and self.__selection.contains(
+            evt.position().toPoint()
         ):
             self.setCursor(Qt.CursorShape.OpenHandCursor)
         self.update()
-    
+
     def mouseDoubleClickEvent(self, evt):
         """
         Protected method to handle mouse double clicks.
-        
+
         @param evt mouse double click event (QMouseEvent)
         """
         self.__grabRect()
-    
+
     def keyPressEvent(self, evt):
         """
         Protected method to handle key presses.
-        
+
         @param evt key press event (QKeyEvent)
         """
         if evt.key() == Qt.Key.Key_Escape:
@@ -428,32 +446,28 @@
             self.__grabRect()
         else:
             evt.ignore()
-    
+
     def __updateHandles(self):
         """
         Private method to update the handles.
         """
         r = QRect(self.__selection)
         s2 = self.__handleSize // 2
-        
+
         self.__TLHandle.moveTopLeft(r.topLeft())
         self.__TRHandle.moveTopRight(r.topRight())
         self.__BLHandle.moveBottomLeft(r.bottomLeft())
         self.__BRHandle.moveBottomRight(r.bottomRight())
-        
-        self.__LHandle.moveTopLeft(
-            QPoint(r.x(), r.y() + r.height() // 2 - s2))
-        self.__THandle.moveTopLeft(
-            QPoint(r.x() + r.width() // 2 - s2, r.y()))
-        self.__RHandle.moveTopRight(
-            QPoint(r.right(), r.y() + r.height() // 2 - s2))
-        self.__BHandle.moveBottomLeft(
-            QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
-    
+
+        self.__LHandle.moveTopLeft(QPoint(r.x(), r.y() + r.height() // 2 - s2))
+        self.__THandle.moveTopLeft(QPoint(r.x() + r.width() // 2 - s2, r.y()))
+        self.__RHandle.moveTopRight(QPoint(r.right(), r.y() + r.height() // 2 - s2))
+        self.__BHandle.moveBottomLeft(QPoint(r.x() + r.width() // 2 - s2, r.bottom()))
+
     def __handleMask(self, maskType):
         """
         Private method to calculate the handle mask.
-        
+
         @param maskType type of the mask to be used
             (SnapshotRegionGrabber.FillMask or
             SnapshotRegionGrabber.StrokeMask)
@@ -467,11 +481,11 @@
             else:
                 mask += QRegion(rect.adjusted(1, 1, -1, -1))
         return mask
-    
+
     def __limitPointToRect(self, point, rect):
         """
         Private method to limit the given point to the given rectangle.
-        
+
         @param point point to be limited (QPoint)
         @param rect rectangle the point shall be limited to (QRect)
         @return limited point (QPoint)
@@ -490,11 +504,11 @@
         else:
             q.setY(rect.bottom())
         return q
-    
+
     def __normalizeSelection(self, sel):
         """
         Private method to normalize the given selection.
-        
+
         @param sel selection to be normalized (QRect)
         @return normalized selection (QRect)
         """
@@ -510,7 +524,7 @@
             rect.setTop(top + height - 1)
             rect.setBottom(top)
         return rect
-    
+
     def __grabRect(self):
         """
         Private method to grab the selected rectangle (i.e. do the snapshot).
@@ -519,37 +533,39 @@
             ell = QRegion(self.__selection, QRegion.RegionType.Ellipse)
             if not ell.isEmpty():
                 self.__grabbing = True
-                
+
                 xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
                 yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
                 translatedEll = ell.translated(xOffset, yOffset)
-                
+
                 pixmap2 = QPixmap(ell.boundingRect().size())
                 pixmap2.fill(Qt.GlobalColor.transparent)
-                
+
                 pt = QPainter()
                 pt.begin(pixmap2)
                 if pt.paintEngine().hasFeature(
                     QPaintEngine.PaintEngineFeature.PorterDuff
                 ):
                     pt.setRenderHints(
-                        QPainter.RenderHint.Antialiasing |
-                        QPainter.RenderHint.SmoothPixmapTransform,
-                        True)
+                        QPainter.RenderHint.Antialiasing
+                        | QPainter.RenderHint.SmoothPixmapTransform,
+                        True,
+                    )
                     pt.setBrush(Qt.GlobalColor.black)
                     pt.setPen(QPen(QBrush(Qt.GlobalColor.black), 0.5))
                     pt.drawEllipse(translatedEll.boundingRect())
                     pt.setCompositionMode(
-                        QPainter.CompositionMode.CompositionMode_SourceIn)
+                        QPainter.CompositionMode.CompositionMode_SourceIn
+                    )
                 else:
                     pt.setClipRegion(translatedEll)
                     pt.setCompositionMode(
-                        QPainter.CompositionMode.CompositionMode_Source)
-                
-                pt.drawPixmap(pixmap2.rect(), self.__pixmap,
-                              ell.boundingRect())
+                        QPainter.CompositionMode.CompositionMode_Source
+                    )
+
+                pt.drawPixmap(pixmap2.rect(), self.__pixmap, ell.boundingRect())
                 pt.end()
-                
+
                 self.grabbed.emit(pixmap2)
         else:
             r = QRect(self.__selection)

eric ide

mercurial