src/eric7/IconEditor/IconEditorGrid.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/IconEditor/IconEditorGrid.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/IconEditor/IconEditorGrid.py	Wed Jul 13 14:55:47 2022 +0200
@@ -12,8 +12,17 @@
 
 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QRect, QSize
 from PyQt6.QtGui import (
-    QImage, QColor, QPixmap, qRgba, QPainter, QCursor, QBrush, qGray, qAlpha,
-    QUndoCommand, QUndoStack
+    QImage,
+    QColor,
+    QPixmap,
+    qRgba,
+    QPainter,
+    QCursor,
+    QBrush,
+    qGray,
+    qAlpha,
+    QUndoCommand,
+    QUndoStack,
 )
 from PyQt6.QtWidgets import QWidget, QSizePolicy, QApplication, QDialog
 
@@ -25,10 +34,11 @@
     """
     Class implementing an undo command for the icon editor.
     """
+
     def __init__(self, grid, text, oldImage, parent=None):
         """
         Constructor
-        
+
         @param grid reference to the icon editor grid (IconEditorGrid)
         @param text text for the undo command (string)
         @param oldImage copy of the icon before the changes were applied
@@ -36,37 +46,38 @@
         @param parent reference to the parent command (QUndoCommand)
         """
         super().__init__(text, parent)
-        
+
         self.__grid = grid
         self.__imageBefore = QImage(oldImage)
         self.__imageAfter = None
-    
+
     def setAfterImage(self, image):
         """
         Public method to set the image after the changes were applied.
-        
+
         @param image copy of the icon after the changes were applied (QImage)
         """
         self.__imageAfter = QImage(image)
-    
+
     def undo(self):
         """
         Public method to perform the undo.
         """
         self.__grid.setIconImage(self.__imageBefore, undoRedo=True)
-    
+
     def redo(self):
         """
         Public method to perform the redo.
         """
         if self.__imageAfter:
             self.__grid.setIconImage(self.__imageAfter, undoRedo=True)
-    
+
 
 class IconEditorTool(enum.IntEnum):
     """
     Class defining the edit tools.
     """
+
     PENCIL = 1
     RUBBER = 2
     LINE = 3
@@ -78,7 +89,7 @@
     FILLED_ELLIPSE = 9
     FILL = 10
     COLOR_PICKER = 11
-    
+
     SELECT_RECTANGLE = 100
     SELECT_CIRCLE = 101
 
@@ -86,7 +97,7 @@
 class IconEditorGrid(QWidget):
     """
     Class implementing the icon editor grid.
-    
+
     @signal canRedoChanged(bool) emitted after the redo status has changed
     @signal canUndoChanged(bool) emitted after the undo status has changed
     @signal clipboardImageAvailable(bool) emitted to signal the availability
@@ -101,6 +112,7 @@
     @signal sizeChanged(int, int) emitted after the size has been changed
     @signal zoomChanged(int) emitted to signal a change of the zoom value
     """
+
     canRedoChanged = pyqtSignal(bool)
     canUndoChanged = pyqtSignal(bool)
     clipboardImageAvailable = pyqtSignal(bool)
@@ -111,28 +123,27 @@
     selectionAvailable = pyqtSignal(bool)
     sizeChanged = pyqtSignal(int, int)
     zoomChanged = pyqtSignal(int)
-    
+
     MarkColor = QColor(255, 255, 255, 255)
     NoMarkColor = QColor(0, 0, 0, 0)
-    
+
     ZoomMinimum = 100
     ZoomMaximum = 10000
     ZoomStep = 100
     ZoomDefault = 1200
     ZoomPercent = True
-    
+
     def __init__(self, parent=None):
         """
         Constructor
-        
+
         @param parent reference to the parent widget (QWidget)
         """
         super().__init__(parent)
-        
+
         self.setAttribute(Qt.WidgetAttribute.WA_StaticContents)
-        self.setSizePolicy(QSizePolicy.Policy.Minimum,
-                           QSizePolicy.Policy.Minimum)
-        
+        self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
+
         self.__curColor = Qt.GlobalColor.black
         self.__zoom = 12
         self.__curTool = IconEditorTool.PENCIL
@@ -144,70 +155,68 @@
         self.__isPasting = False
         self.__clipboardSize = QSize()
         self.__pasteRect = QRect()
-        
+
         self.__undoStack = QUndoStack(self)
         self.__currentUndoCmd = None
-        
+
         self.__image = QImage(32, 32, QImage.Format.Format_ARGB32)
         self.__image.fill(Qt.GlobalColor.transparent)
         self.__markImage = QImage(self.__image)
         self.__markImage.fill(self.NoMarkColor.rgba())
-        
-        self.__compositingMode = (
-            QPainter.CompositionMode.CompositionMode_SourceOver
-        )
+
+        self.__compositingMode = QPainter.CompositionMode.CompositionMode_SourceOver
         self.__lastPos = (-1, -1)
-        
+
         self.__gridEnabled = True
         self.__selectionAvailable = False
-        
+
         self.__initCursors()
         self.__initUndoTexts()
-        
+
         self.setMouseTracking(True)
-        
+
         self.__undoStack.canRedoChanged.connect(self.canRedoChanged)
         self.__undoStack.canUndoChanged.connect(self.canUndoChanged)
         self.__undoStack.cleanChanged.connect(self.__cleanChanged)
-        
+
         self.imageChanged.connect(self.__updatePreviewPixmap)
         QApplication.clipboard().dataChanged.connect(self.__checkClipboard)
-        
+
         self.__checkClipboard()
-    
+
     def __initCursors(self):
         """
         Private method to initialize the various cursors.
         """
         cursorsPath = os.path.join(os.path.dirname(__file__), "cursors")
-        
+
         self.__normalCursor = QCursor(Qt.CursorShape.ArrowCursor)
-        
+
         pix = QPixmap(os.path.join(cursorsPath, "colorpicker-cursor.xpm"))
         mask = pix.createHeuristicMask()
         pix.setMask(mask)
         self.__colorPickerCursor = QCursor(pix, 1, 21)
-        
+
         pix = QPixmap(os.path.join(cursorsPath, "paintbrush-cursor.xpm"))
         mask = pix.createHeuristicMask()
         pix.setMask(mask)
         self.__paintCursor = QCursor(pix, 0, 19)
-        
+
         pix = QPixmap(os.path.join(cursorsPath, "fill-cursor.xpm"))
         mask = pix.createHeuristicMask()
         pix.setMask(mask)
         self.__fillCursor = QCursor(pix, 3, 20)
-        
+
         pix = QPixmap(os.path.join(cursorsPath, "aim-cursor.xpm"))
         mask = pix.createHeuristicMask()
         pix.setMask(mask)
         self.__aimCursor = QCursor(pix, 10, 10)
-        
+
         pix = QPixmap(os.path.join(cursorsPath, "eraser-cursor.xpm"))
         mask = pix.createHeuristicMask()
         pix.setMask(mask)
         self.__rubberCursor = QCursor(pix, 1, 16)
-    
+
     def __initUndoTexts(self):
         """
         Private method to initialize texts to be associated with undo commands
@@ -225,96 +234,101 @@
             IconEditorTool.FILLED_ELLIPSE: self.tr("Draw Filled Ellipse"),
             IconEditorTool.FILL: self.tr("Fill Region"),
         }
-    
+
     def isDirty(self):
         """
         Public method to check the dirty status.
-        
+
         @return flag indicating a modified status (boolean)
         """
         return self.__dirty
-    
+
     def setDirty(self, dirty, setCleanState=False):
         """
         Public slot to set the dirty flag.
-        
+
         @param dirty flag indicating the new modification status (boolean)
         @param setCleanState flag indicating to set the undo stack to clean
             (boolean)
         """
         self.__dirty = dirty
         self.imageChanged.emit(dirty)
-        
+
         if not dirty and setCleanState:
             self.__undoStack.setClean()
-    
+
     def sizeHint(self):
         """
         Public method to report the size hint.
-        
+
         @return size hint (QSize)
         """
         size = self.__zoom * self.__image.size()
         if self.__zoom >= 3 and self.__gridEnabled:
             size += QSize(1, 1)
         return size
-    
+
     def setPenColor(self, newColor):
         """
         Public method to set the drawing color.
-        
+
         @param newColor reference to the new color (QColor)
         """
         self.__curColor = QColor(newColor)
         self.colorChanged.emit(QColor(newColor))
-    
+
     def penColor(self):
         """
         Public method to get the current drawing color.
-        
+
         @return current drawing color (QColor)
         """
         return QColor(self.__curColor)
-    
+
     def setCompositingMode(self, mode):
         """
         Public method to set the compositing mode.
-        
+
         @param mode compositing mode to set (QPainter.CompositionMode)
         """
         self.__compositingMode = mode
-    
+
     def compositingMode(self):
         """
         Public method to get the compositing mode.
-        
+
         @return compositing mode (QPainter.CompositionMode)
         """
         return self.__compositingMode
-    
+
     def setTool(self, tool):
         """
         Public method to set the current drawing tool.
-        
+
         @param tool drawing tool to be used
         @type IconEditorTool
         """
         self.__curTool = tool
         self.__lastPos = (-1, -1)
-        
+
         if self.__curTool in [
-            IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE
+            IconEditorTool.SELECT_RECTANGLE,
+            IconEditorTool.SELECT_CIRCLE,
         ]:
             self.__selecting = True
         else:
             self.__selecting = False
-        
+
         if self.__curTool in [
-            IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE,
+            IconEditorTool.SELECT_RECTANGLE,
+            IconEditorTool.SELECT_CIRCLE,
             IconEditorTool.LINE,
-            IconEditorTool.RECTANGLE, IconEditorTool.FILLED_RECTANGLE,
-            IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE,
-            IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE
+            IconEditorTool.RECTANGLE,
+            IconEditorTool.FILLED_RECTANGLE,
+            IconEditorTool.CIRCLE,
+            IconEditorTool.FILLED_CIRCLE,
+            IconEditorTool.ELLIPSE,
+            IconEditorTool.FILLED_ELLIPSE,
         ]:
             self.setCursor(self.__aimCursor)
         elif self.__curTool == IconEditorTool.FILL:
@@ -327,108 +341,107 @@
             self.setCursor(self.__rubberCursor)
         else:
             self.setCursor(self.__normalCursor)
-    
+
     def tool(self):
         """
         Public method to get the current drawing tool.
-        
+
         @return current drawing tool
         @rtype IconEditorTool
         """
         return self.__curTool
-    
+
     def setIconImage(self, newImage, undoRedo=False, clearUndo=False):
         """
         Public method to set a new icon image.
-        
+
         @param newImage reference to the new image (QImage)
         @param undoRedo flag indicating an undo or redo operation (boolean)
         @param clearUndo flag indicating to clear the undo stack (boolean)
         """
         if newImage != self.__image:
-            self.__image = newImage.convertToFormat(
-                QImage.Format.Format_ARGB32)
+            self.__image = newImage.convertToFormat(QImage.Format.Format_ARGB32)
             self.update()
             self.updateGeometry()
             self.resize(self.sizeHint())
-            
+
             self.__markImage = QImage(self.__image)
             self.__markImage.fill(self.NoMarkColor.rgba())
-            
+
             if undoRedo:
                 self.setDirty(not self.__undoStack.isClean())
             else:
                 self.setDirty(False)
-            
+
             if clearUndo:
                 self.__undoStack.clear()
-            
+
             self.sizeChanged.emit(*self.iconSize())
-    
+
     def iconImage(self):
         """
         Public method to get a copy of the icon image.
-        
+
         @return copy of the icon image (QImage)
         """
         return QImage(self.__image)
-    
+
     def iconSize(self):
         """
         Public method to get the size of the icon.
-        
+
         @return width and height of the image as a tuple (integer, integer)
         """
         return self.__image.width(), self.__image.height()
-    
+
     def setZoomFactor(self, newZoom):
         """
         Public method to set the zoom factor in percent.
-        
+
         @param newZoom zoom factor (integer >= 100)
         """
-        newZoom = max(100, newZoom)   # must not be less than 100
+        newZoom = max(100, newZoom)  # must not be less than 100
         if newZoom != self.__zoom:
             self.__zoom = newZoom // 100
             self.update()
             self.updateGeometry()
             self.resize(self.sizeHint())
             self.zoomChanged.emit(int(self.__zoom * 100))
-    
+
     def zoomFactor(self):
         """
         Public method to get the current zoom factor in percent.
-        
+
         @return zoom factor (integer)
         """
         return self.__zoom * 100
-    
+
     def setGridEnabled(self, enable):
         """
         Public method to enable the display of grid lines.
-        
+
         @param enable enabled status of the grid lines (boolean)
         """
         if enable != self.__gridEnabled:
             self.__gridEnabled = enable
             self.update()
-    
+
     def isGridEnabled(self):
         """
         Public method to get the grid lines status.
-        
+
         @return enabled status of the grid lines (boolean)
         """
         return self.__gridEnabled
-    
+
     def paintEvent(self, evt):
         """
         Protected method called to repaint some of the widget.
-        
+
         @param evt reference to the paint event object (QPaintEvent)
         """
         painter = QPainter(self)
-        
+
         if self.__zoom >= 3 and self.__gridEnabled:
             if ericApp().usesDarkPalette():
                 painter.setPen(self.palette().window().color())
@@ -437,16 +450,22 @@
             i = 0
             while i <= self.__image.width():
                 painter.drawLine(
-                    self.__zoom * i, 0,
-                    self.__zoom * i, self.__zoom * self.__image.height())
+                    self.__zoom * i,
+                    0,
+                    self.__zoom * i,
+                    self.__zoom * self.__image.height(),
+                )
                 i += 1
             j = 0
             while j <= self.__image.height():
                 painter.drawLine(
-                    0, self.__zoom * j,
-                    self.__zoom * self.__image.width(), self.__zoom * j)
+                    0,
+                    self.__zoom * j,
+                    self.__zoom * self.__image.width(),
+                    self.__zoom * j,
+                )
                 j += 1
-        
+
         col = QColor("#aaa")
         painter.setPen(Qt.PenStyle.DashLine)
         for i in range(0, self.__image.width()):
@@ -456,34 +475,36 @@
                     color = QColor.fromRgba(self.__image.pixel(i, j))
                     painter.fillRect(rect, QBrush(Qt.GlobalColor.white))
                     painter.fillRect(QRect(rect.topLeft(), rect.center()), col)
-                    painter.fillRect(QRect(rect.center(), rect.bottomRight()),
-                                     col)
+                    painter.fillRect(QRect(rect.center(), rect.bottomRight()), col)
                     painter.fillRect(rect, QBrush(color))
-                
+
                     if self.__isMarked(i, j):
                         painter.drawRect(rect.adjusted(0, 0, -1, -1))
-        
+
         painter.end()
-    
+
     def __pixelRect(self, i, j):
         """
         Private method to determine the rectangle for a given pixel coordinate.
-        
+
         @param i x-coordinate of the pixel in the image (integer)
         @param j y-coordinate of the pixel in the image (integer)
         @return rectangle for the given pixel coordinates (QRect)
         """
         if self.__zoom >= 3 and self.__gridEnabled:
-            return QRect(self.__zoom * i + 1, self.__zoom * j + 1,
-                         self.__zoom - 1, self.__zoom - 1)
+            return QRect(
+                self.__zoom * i + 1,
+                self.__zoom * j + 1,
+                self.__zoom - 1,
+                self.__zoom - 1,
+            )
         else:
-            return QRect(self.__zoom * i, self.__zoom * j,
-                         self.__zoom, self.__zoom)
-    
+            return QRect(self.__zoom * i, self.__zoom * j, self.__zoom, self.__zoom)
+
     def mousePressEvent(self, evt):
         """
         Protected method to handle mouse button press events.
-        
+
         @param evt reference to the mouse event object (QMouseEvent)
         """
         if evt.button() == Qt.MouseButton.LeftButton:
@@ -494,17 +515,19 @@
                 self.update(self.__pasteRect)
                 self.__pasteRect = QRect()
                 return
-            
+
             if self.__curTool == IconEditorTool.PENCIL:
-                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
-                                      self.__image)
+                cmd = IconEditCommand(
+                    self, self.__undoTexts[self.__curTool], self.__image
+                )
                 self.__setImagePixel(evt.position().toPoint(), True)
                 self.setDirty(True)
                 self.__undoStack.push(cmd)
                 self.__currentUndoCmd = cmd
             elif self.__curTool == IconEditorTool.RUBBER:
-                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
-                                      self.__image)
+                cmd = IconEditCommand(
+                    self, self.__undoTexts[self.__curTool], self.__image
+                )
                 self.__setImagePixel(evt.position().toPoint(), False)
                 self.setDirty(True)
                 self.__undoStack.push(cmd)
@@ -513,8 +536,9 @@
                 i, j = self.__imageCoordinates(evt.position().toPoint())
                 col = QColor()
                 col.setRgba(self.__image.pixel(i, j))
-                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
-                                      self.__image)
+                cmd = IconEditCommand(
+                    self, self.__undoTexts[self.__curTool], self.__image
+                )
                 self.__drawFlood(i, j, col)
                 self.setDirty(True)
                 self.__undoStack.push(cmd)
@@ -528,23 +552,19 @@
                 self.__unMark()
                 self.__startPos = evt.position().toPoint()
                 self.__endPos = evt.position().toPoint()
-    
+
     def mouseMoveEvent(self, evt):
         """
         Protected method to handle mouse move events.
-        
+
         @param evt reference to the mouse event object (QMouseEvent)
         """
-        self.positionChanged.emit(
-            *self.__imageCoordinates(evt.position().toPoint()))
-        
-        if (
-            self.__isPasting and
-            not (evt.buttons() & Qt.MouseButton.LeftButton)
-        ):
+        self.positionChanged.emit(*self.__imageCoordinates(evt.position().toPoint()))
+
+        if self.__isPasting and not (evt.buttons() & Qt.MouseButton.LeftButton):
             self.__drawPasteRect(evt.position().toPoint())
             return
-        
+
         if evt.buttons() & Qt.MouseButton.LeftButton:
             if self.__curTool == IconEditorTool.PENCIL:
                 self.__setImagePixel(evt.position().toPoint(), True)
@@ -552,48 +572,50 @@
             elif self.__curTool == IconEditorTool.RUBBER:
                 self.__setImagePixel(evt.position().toPoint(), False)
                 self.setDirty(True)
-            elif self.__curTool in [IconEditorTool.FILL,
-                                    IconEditorTool.COLOR_PICKER]:
-                pass    # do nothing
+            elif self.__curTool in [IconEditorTool.FILL, IconEditorTool.COLOR_PICKER]:
+                pass  # do nothing
             else:
                 self.__drawTool(evt.position().toPoint(), True)
-    
+
     def mouseReleaseEvent(self, evt):
         """
         Protected method to handle mouse button release events.
-        
+
         @param evt reference to the mouse event object (QMouseEvent)
         """
         if evt.button() == Qt.MouseButton.LeftButton:
             if (
-                self.__curTool in [IconEditorTool.PENCIL,
-                                   IconEditorTool.RUBBER] and
-                self.__currentUndoCmd
+                self.__curTool in [IconEditorTool.PENCIL, IconEditorTool.RUBBER]
+                and self.__currentUndoCmd
             ):
                 self.__currentUndoCmd.setAfterImage(self.__image)
                 self.__currentUndoCmd = None
-            
+
             if self.__curTool not in [
-                IconEditorTool.PENCIL, IconEditorTool.RUBBER,
-                IconEditorTool.FILL, IconEditorTool.COLOR_PICKER,
-                IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE
+                IconEditorTool.PENCIL,
+                IconEditorTool.RUBBER,
+                IconEditorTool.FILL,
+                IconEditorTool.COLOR_PICKER,
+                IconEditorTool.SELECT_RECTANGLE,
+                IconEditorTool.SELECT_CIRCLE,
             ]:
-                cmd = IconEditCommand(self, self.__undoTexts[self.__curTool],
-                                      self.__image)
+                cmd = IconEditCommand(
+                    self, self.__undoTexts[self.__curTool], self.__image
+                )
                 if self.__drawTool(evt.position().toPoint(), False):
                     self.__undoStack.push(cmd)
                     cmd.setAfterImage(self.__image)
                     self.setDirty(True)
-    
+
     def __setImagePixel(self, pos, opaque):
         """
         Private slot to set or erase a pixel.
-        
+
         @param pos position of the pixel in the widget (QPoint)
         @param opaque flag indicating a set operation (boolean)
         """
         i, j = self.__imageCoordinates(pos)
-        
+
         if self.__image.rect().contains(i, j) and (i, j) != self.__lastPos:
             if opaque:
                 painter = QPainter(self.__image)
@@ -603,66 +625,68 @@
             else:
                 self.__image.setPixel(i, j, qRgba(0, 0, 0, 0))
             self.__lastPos = (i, j)
-        
+
             self.update(self.__pixelRect(i, j))
-    
+
     def __imageCoordinates(self, pos):
         """
         Private method to convert from widget to image coordinates.
-        
+
         @param pos widget coordinate (QPoint)
         @return tuple with the image coordinates (tuple of two integers)
         """
         i = pos.x() // self.__zoom
         j = pos.y() // self.__zoom
         return i, j
-    
+
     def __drawPasteRect(self, pos):
         """
         Private slot to draw a rectangle for signaling a paste operation.
-        
+
         @param pos widget position of the paste rectangle (QPoint)
         """
         self.__markImage.fill(self.NoMarkColor.rgba())
         if self.__pasteRect.isValid():
             self.__updateImageRect(
                 self.__pasteRect.topLeft(),
-                self.__pasteRect.bottomRight() + QPoint(1, 1))
-        
+                self.__pasteRect.bottomRight() + QPoint(1, 1),
+            )
+
         x, y = self.__imageCoordinates(pos)
         isize = self.__image.size()
         sx = (
             self.__clipboardSize.width()
-            if x + self.__clipboardSize.width() <= isize.width() else
-            isize.width() - x
+            if x + self.__clipboardSize.width() <= isize.width()
+            else isize.width() - x
         )
         sy = (
             self.__clipboardSize.height()
-            if y + self.__clipboardSize.height() <= isize.height() else
-            isize.height() - y
+            if y + self.__clipboardSize.height() <= isize.height()
+            else isize.height() - y
         )
-        
+
         self.__pasteRect = QRect(QPoint(x, y), QSize(sx - 1, sy - 1))
-        
+
         painter = QPainter(self.__markImage)
         painter.setPen(self.MarkColor)
         painter.drawRect(self.__pasteRect)
         painter.end()
-        
-        self.__updateImageRect(self.__pasteRect.topLeft(),
-                               self.__pasteRect.bottomRight() + QPoint(1, 1))
-    
+
+        self.__updateImageRect(
+            self.__pasteRect.topLeft(), self.__pasteRect.bottomRight() + QPoint(1, 1)
+        )
+
     def __drawTool(self, pos, mark):
         """
         Private method to perform a draw operation depending of the current
         tool.
-        
+
         @param pos widget coordinate to perform the draw operation at (QPoint)
         @param mark flag indicating a mark operation (boolean)
         @return flag indicating a successful draw (boolean)
         """
         self.__unMark()
-        
+
         if mark:
             self.__endPos = QPoint(pos)
             drawColor = self.MarkColor
@@ -670,20 +694,21 @@
         else:
             drawColor = self.penColor()
             img = self.__image
-        
+
         start = QPoint(*self.__imageCoordinates(self.__startPos))
         end = QPoint(*self.__imageCoordinates(pos))
-        
+
         painter = QPainter(img)
         painter.setPen(drawColor)
         painter.setCompositionMode(self.__compositingMode)
-        
+
         if self.__curTool == IconEditorTool.LINE:
             painter.drawLine(start, end)
-        
+
         elif self.__curTool in [
-            IconEditorTool.RECTANGLE, IconEditorTool.FILLED_RECTANGLE,
-            IconEditorTool.SELECT_RECTANGLE
+            IconEditorTool.RECTANGLE,
+            IconEditorTool.FILLED_RECTANGLE,
+            IconEditorTool.SELECT_RECTANGLE,
         ]:
             left = min(start.x(), end.x())
             top = min(start.y(), end.y())
@@ -697,32 +722,32 @@
             else:
                 painter.drawRect(left, top, right - left, bottom - top)
             if self.__selecting:
-                self.__selRect = QRect(
-                    left, top, right - left + 1, bottom - top + 1)
+                self.__selRect = QRect(left, top, right - left + 1, bottom - top + 1)
                 self.__selectionAvailable = True
                 self.selectionAvailable.emit(True)
-        
+
         elif self.__curTool in [
-            IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE,
-            IconEditorTool.SELECT_CIRCLE
+            IconEditorTool.CIRCLE,
+            IconEditorTool.FILLED_CIRCLE,
+            IconEditorTool.SELECT_CIRCLE,
         ]:
             deltaX = abs(start.x() - end.x())
             deltaY = abs(start.y() - end.y())
             r = max(deltaX, deltaY)
             if self.__curTool in [
-                IconEditorTool.FILLED_CIRCLE, IconEditorTool.SELECT_CIRCLE
+                IconEditorTool.FILLED_CIRCLE,
+                IconEditorTool.SELECT_CIRCLE,
             ]:
                 painter.setBrush(QBrush(drawColor))
             painter.drawEllipse(start, r, r)
             if self.__selecting:
-                self.__selRect = QRect(start.x() - r, start.y() - r,
-                                       2 * r + 1, 2 * r + 1)
+                self.__selRect = QRect(
+                    start.x() - r, start.y() - r, 2 * r + 1, 2 * r + 1
+                )
                 self.__selectionAvailable = True
                 self.selectionAvailable.emit(True)
-        
-        elif self.__curTool in [
-            IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE
-        ]:
+
+        elif self.__curTool in [IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE]:
             r1 = abs(start.x() - end.x())
             r2 = abs(start.y() - end.y())
             if r1 == 0 or r2 == 0:
@@ -730,23 +755,25 @@
             if self.__curTool == IconEditorTool.FILLED_ELLIPSE:
                 painter.setBrush(QBrush(drawColor))
             painter.drawEllipse(start, r1, r2)
-        
+
         painter.end()
-        
+
         if self.__curTool in [
-            IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE,
-            IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE
+            IconEditorTool.CIRCLE,
+            IconEditorTool.FILLED_CIRCLE,
+            IconEditorTool.ELLIPSE,
+            IconEditorTool.FILLED_ELLIPSE,
         ]:
             self.update()
         else:
             self.__updateRect(self.__startPos, pos)
-        
+
         return True
-    
+
     def __drawFlood(self, i, j, oldColor, doUpdate=True):
         """
         Private method to perform a flood fill operation.
-        
+
         @param i x-value in image coordinates (integer)
         @param j y-value in image coordinates (integer)
         @param oldColor reference to the color at position i, j (QColor)
@@ -754,38 +781,40 @@
             (used for speed optimizations)
         """
         if (
-            not self.__image.rect().contains(i, j) or
-            self.__image.pixel(i, j) != oldColor.rgba() or
-            self.__image.pixel(i, j) == self.penColor().rgba()
+            not self.__image.rect().contains(i, j)
+            or self.__image.pixel(i, j) != oldColor.rgba()
+            or self.__image.pixel(i, j) == self.penColor().rgba()
         ):
             return
-        
+
         self.__image.setPixel(i, j, self.penColor().rgba())
-        
+
         self.__drawFlood(i, j - 1, oldColor, False)
         self.__drawFlood(i, j + 1, oldColor, False)
         self.__drawFlood(i - 1, j, oldColor, False)
         self.__drawFlood(i + 1, j, oldColor, False)
-        
+
         if doUpdate:
             self.update()
-    
+
     def __updateRect(self, pos1, pos2):
         """
         Private slot to update parts of the widget.
-        
+
         @param pos1 top, left position for the update in widget coordinates
             (QPoint)
         @param pos2 bottom, right position for the update in widget
             coordinates (QPoint)
         """
-        self.__updateImageRect(QPoint(*self.__imageCoordinates(pos1)),
-                               QPoint(*self.__imageCoordinates(pos2)))
-    
+        self.__updateImageRect(
+            QPoint(*self.__imageCoordinates(pos1)),
+            QPoint(*self.__imageCoordinates(pos2)),
+        )
+
     def __updateImageRect(self, ipos1, ipos2):
         """
         Private slot to update parts of the widget.
-        
+
         @param ipos1 top, left position for the update in image coordinates
             (QPoint)
         @param ipos2 bottom, right position for the update in image
@@ -793,58 +822,60 @@
         """
         r1 = self.__pixelRect(ipos1.x(), ipos1.y())
         r2 = self.__pixelRect(ipos2.x(), ipos2.y())
-        
+
         left = min(r1.x(), r2.x())
         top = min(r1.y(), r2.y())
         right = max(r1.x() + r1.width(), r2.x() + r2.width())
         bottom = max(r1.y() + r1.height(), r2.y() + r2.height())
         self.update(left, top, right - left + 1, bottom - top + 1)
-    
+
     def __unMark(self):
         """
         Private slot to remove the mark indicator.
         """
         self.__markImage.fill(self.NoMarkColor.rgba())
         if self.__curTool in [
-            IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE,
-            IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE,
-            IconEditorTool.SELECT_CIRCLE
+            IconEditorTool.CIRCLE,
+            IconEditorTool.FILLED_CIRCLE,
+            IconEditorTool.ELLIPSE,
+            IconEditorTool.FILLED_ELLIPSE,
+            IconEditorTool.SELECT_CIRCLE,
         ]:
             self.update()
         else:
             self.__updateRect(self.__startPos, self.__endPos)
-        
+
         if self.__selecting:
             self.__selRect = QRect()
             self.__selectionAvailable = False
             self.selectionAvailable.emit(False)
-    
+
     def __isMarked(self, i, j):
         """
         Private method to check, if a pixel is marked.
-        
+
         @param i x-value in image coordinates (integer)
         @param j y-value in image coordinates (integer)
         @return flag indicating a marked pixel (boolean)
         """
         return self.__markImage.pixel(i, j) == self.MarkColor.rgba()
-    
+
     def __updatePreviewPixmap(self):
         """
         Private slot to generate and signal an updated preview pixmap.
         """
         p = QPixmap.fromImage(self.__image)
         self.previewChanged.emit(p)
-    
+
     def previewPixmap(self):
         """
         Public method to generate a preview pixmap.
-        
+
         @return preview pixmap (QPixmap)
         """
         p = QPixmap.fromImage(self.__image)
         return p
-    
+
     def __checkClipboard(self):
         """
         Private slot to check, if the clipboard contains a valid image, and
@@ -853,19 +884,19 @@
         ok = self.__clipboardImage()[1]
         self.__clipboardImageAvailable = ok
         self.clipboardImageAvailable.emit(ok)
-    
+
     def canPaste(self):
         """
         Public slot to check the availability of the paste operation.
-        
+
         @return flag indicating availability of paste (boolean)
         """
         return self.__clipboardImageAvailable
-    
+
     def __clipboardImage(self):
         """
         Private method to get an image from the clipboard.
-        
+
         @return tuple with the image (QImage) and a flag indicating a
             valid image (boolean)
         """
@@ -873,48 +904,51 @@
         ok = not img.isNull()
         if ok:
             img = img.convertToFormat(QImage.Format.Format_ARGB32)
-        
+
         return img, ok
-    
+
     def __getSelectionImage(self, cut):
         """
         Private method to get an image from the selection.
-        
+
         @param cut flag indicating to cut the selection (boolean)
         @return image of the selection (QImage)
         """
         if cut:
-            cmd = IconEditCommand(self, self.tr("Cut Selection"),
-                                  self.__image)
-        
+            cmd = IconEditCommand(self, self.tr("Cut Selection"), self.__image)
+
         img = QImage(self.__selRect.size(), QImage.Format.Format_ARGB32)
         img.fill(Qt.GlobalColor.transparent)
         for i in range(0, self.__selRect.width()):
             for j in range(0, self.__selRect.height()):
-                if (
-                    self.__image.rect().contains(
-                        self.__selRect.x() + i, self.__selRect.y() + j) and
-                    self.__isMarked(self.__selRect.x() + i,
-                                    self.__selRect.y() + j)
-                ):
-                    img.setPixel(i, j, self.__image.pixel(
-                        self.__selRect.x() + i, self.__selRect.y() + j))
+                if self.__image.rect().contains(
+                    self.__selRect.x() + i, self.__selRect.y() + j
+                ) and self.__isMarked(self.__selRect.x() + i, self.__selRect.y() + j):
+                    img.setPixel(
+                        i,
+                        j,
+                        self.__image.pixel(
+                            self.__selRect.x() + i, self.__selRect.y() + j
+                        ),
+                    )
                     if cut:
-                        self.__image.setPixel(self.__selRect.x() + i,
-                                              self.__selRect.y() + j,
-                                              Qt.GlobalColor.transparent)
-        
+                        self.__image.setPixel(
+                            self.__selRect.x() + i,
+                            self.__selRect.y() + j,
+                            Qt.GlobalColor.transparent,
+                        )
+
         if cut:
             self.__undoStack.push(cmd)
             cmd.setAfterImage(self.__image)
-        
+
         self.__unMark()
-        
+
         if cut:
             self.update(self.__selRect)
-        
+
         return img
-    
+
     def editCopy(self):
         """
         Public slot to copy the selection.
@@ -922,7 +956,7 @@
         if self.__selRect.isValid():
             img = self.__getSelectionImage(False)
             QApplication.clipboard().setImage(img)
-    
+
     def editCut(self):
         """
         Public slot to cut the selection.
@@ -930,27 +964,29 @@
         if self.__selRect.isValid():
             img = self.__getSelectionImage(True)
             QApplication.clipboard().setImage(img)
-    
+
     @pyqtSlot()
     def editPaste(self, pasting=False):
         """
         Public slot to paste an image from the clipboard.
-        
+
         @param pasting flag indicating part two of the paste operation
             (boolean)
         """
         img, ok = self.__clipboardImage()
         if ok:
             if (
-                img.width() > self.__image.width() or
-                img.height() > self.__image.height()
+                img.width() > self.__image.width()
+                or img.height() > self.__image.height()
             ):
                 res = EricMessageBox.yesNo(
                     self,
                     self.tr("Paste"),
                     self.tr(
                         """<p>The clipboard image is larger than the"""
-                        """ current image.<br/>Paste as new image?</p>"""))
+                        """ current image.<br/>Paste as new image?</p>"""
+                    ),
+                )
                 if res:
                     self.editPasteAsNew()
                 return
@@ -958,29 +994,35 @@
                 self.__isPasting = True
                 self.__clipboardSize = img.size()
             else:
-                cmd = IconEditCommand(self, self.tr("Paste Clipboard"),
-                                      self.__image)
+                cmd = IconEditCommand(self, self.tr("Paste Clipboard"), self.__image)
                 self.__markImage.fill(self.NoMarkColor.rgba())
                 painter = QPainter(self.__image)
                 painter.setPen(self.penColor())
                 painter.setCompositionMode(self.__compositingMode)
                 painter.drawImage(
-                    self.__pasteRect.x(), self.__pasteRect.y(), img, 0, 0,
+                    self.__pasteRect.x(),
+                    self.__pasteRect.y(),
+                    img,
+                    0,
+                    0,
                     self.__pasteRect.width() + 1,
-                    self.__pasteRect.height() + 1)
-                
+                    self.__pasteRect.height() + 1,
+                )
+
                 self.__undoStack.push(cmd)
                 cmd.setAfterImage(self.__image)
-                
+
                 self.__updateImageRect(
                     self.__pasteRect.topLeft(),
-                    self.__pasteRect.bottomRight() + QPoint(1, 1))
+                    self.__pasteRect.bottomRight() + QPoint(1, 1),
+                )
         else:
             EricMessageBox.warning(
                 self,
                 self.tr("Pasting Image"),
-                self.tr("""Invalid image data in clipboard."""))
-    
+                self.tr("""Invalid image data in clipboard."""),
+            )
+
     def editPasteAsNew(self):
         """
         Public slot to paste the clipboard as a new image.
@@ -988,69 +1030,70 @@
         img, ok = self.__clipboardImage()
         if ok:
             cmd = IconEditCommand(
-                self, self.tr("Paste Clipboard as New Image"),
-                self.__image)
+                self, self.tr("Paste Clipboard as New Image"), self.__image
+            )
             self.setIconImage(img)
             self.setDirty(True)
             self.__undoStack.push(cmd)
             cmd.setAfterImage(self.__image)
-    
+
     def editSelectAll(self):
         """
         Public slot to select the complete image.
         """
         self.__unMark()
-        
+
         self.__startPos = QPoint(0, 0)
         self.__endPos = QPoint(self.rect().bottomRight())
         self.__markImage.fill(self.MarkColor.rgba())
         self.__selRect = self.__image.rect()
         self.__selectionAvailable = True
         self.selectionAvailable.emit(True)
-        
+
         self.update()
-    
+
     def editClear(self):
         """
         Public slot to clear the image.
         """
         self.__unMark()
-        
+
         cmd = IconEditCommand(self, self.tr("Clear Image"), self.__image)
         self.__image.fill(Qt.GlobalColor.transparent)
         self.update()
         self.setDirty(True)
         self.__undoStack.push(cmd)
         cmd.setAfterImage(self.__image)
-    
+
     def editResize(self):
         """
         Public slot to resize the image.
         """
         from .IconSizeDialog import IconSizeDialog
+
         dlg = IconSizeDialog(self.__image.width(), self.__image.height())
         res = dlg.exec()
         if res == QDialog.DialogCode.Accepted:
             newWidth, newHeight = dlg.getData()
-            if (
-                newWidth != self.__image.width() or
-                newHeight != self.__image.height()
-            ):
-                cmd = IconEditCommand(self, self.tr("Resize Image"),
-                                      self.__image)
+            if newWidth != self.__image.width() or newHeight != self.__image.height():
+                cmd = IconEditCommand(self, self.tr("Resize Image"), self.__image)
                 img = self.__image.scaled(
-                    newWidth, newHeight, Qt.AspectRatioMode.IgnoreAspectRatio,
-                    Qt.TransformationMode.SmoothTransformation)
+                    newWidth,
+                    newHeight,
+                    Qt.AspectRatioMode.IgnoreAspectRatio,
+                    Qt.TransformationMode.SmoothTransformation,
+                )
                 self.setIconImage(img)
                 self.setDirty(True)
                 self.__undoStack.push(cmd)
                 cmd.setAfterImage(self.__image)
-    
+
     def editNew(self):
         """
         Public slot to generate a new, empty image.
         """
         from .IconSizeDialog import IconSizeDialog
+
         dlg = IconSizeDialog(self.__image.width(), self.__image.height())
         res = dlg.exec()
         if res == QDialog.DialogCode.Accepted:
@@ -1058,20 +1101,18 @@
             img = QImage(width, height, QImage.Format.Format_ARGB32)
             img.fill(Qt.GlobalColor.transparent)
             self.setIconImage(img)
-    
+
     def grayScale(self):
         """
         Public slot to convert the image to gray preserving transparency.
         """
-        cmd = IconEditCommand(self, self.tr("Convert to Grayscale"),
-                              self.__image)
+        cmd = IconEditCommand(self, self.tr("Convert to Grayscale"), self.__image)
         for x in range(self.__image.width()):
             for y in range(self.__image.height()):
                 col = self.__image.pixel(x, y)
                 if col != qRgba(0, 0, 0, 0):
                     gray = qGray(col)
-                    self.__image.setPixel(
-                        x, y, qRgba(gray, gray, gray, qAlpha(col)))
+                    self.__image.setPixel(x, y, qRgba(gray, gray, gray, qAlpha(col)))
         self.update()
         self.setDirty(True)
         self.__undoStack.push(cmd)
@@ -1083,38 +1124,38 @@
         """
         if self.__undoStack.canUndo():
             self.__undoStack.undo()
-    
+
     def editRedo(self):
         """
         Public slot to perform a redo operation.
         """
         if self.__undoStack.canRedo():
             self.__undoStack.redo()
-    
+
     def canUndo(self):
         """
         Public method to return the undo status.
-        
+
         @return flag indicating the availability of undo (boolean)
         """
         return self.__undoStack.canUndo()
-    
+
     def canRedo(self):
         """
         Public method to return the redo status.
-        
+
         @return flag indicating the availability of redo (boolean)
         """
         return self.__undoStack.canRedo()
-    
+
     def __cleanChanged(self, clean):
         """
         Private slot to handle the undo stack clean state change.
-        
+
         @param clean flag indicating the clean state (boolean)
         """
         self.setDirty(not clean)
-    
+
     def shutdown(self):
         """
         Public slot to perform some shutdown actions.
@@ -1122,11 +1163,11 @@
         self.__undoStack.canRedoChanged.disconnect(self.canRedoChanged)
         self.__undoStack.canUndoChanged.disconnect(self.canUndoChanged)
         self.__undoStack.cleanChanged.disconnect(self.__cleanChanged)
-    
+
     def isSelectionAvailable(self):
         """
         Public method to check the availability of a selection.
-        
+
         @return flag indicating the availability of a selection (boolean)
         """
         return self.__selectionAvailable

eric ide

mercurial