src/eric7/IconEditor/IconEditorGrid.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
10 import enum 10 import enum
11 import os 11 import os
12 12
13 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QRect, QSize 13 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QRect, QSize
14 from PyQt6.QtGui import ( 14 from PyQt6.QtGui import (
15 QImage, QColor, QPixmap, qRgba, QPainter, QCursor, QBrush, qGray, qAlpha, 15 QImage,
16 QUndoCommand, QUndoStack 16 QColor,
17 QPixmap,
18 qRgba,
19 QPainter,
20 QCursor,
21 QBrush,
22 qGray,
23 qAlpha,
24 QUndoCommand,
25 QUndoStack,
17 ) 26 )
18 from PyQt6.QtWidgets import QWidget, QSizePolicy, QApplication, QDialog 27 from PyQt6.QtWidgets import QWidget, QSizePolicy, QApplication, QDialog
19 28
20 from EricWidgets import EricMessageBox 29 from EricWidgets import EricMessageBox
21 from EricWidgets.EricApplication import ericApp 30 from EricWidgets.EricApplication import ericApp
23 32
24 class IconEditCommand(QUndoCommand): 33 class IconEditCommand(QUndoCommand):
25 """ 34 """
26 Class implementing an undo command for the icon editor. 35 Class implementing an undo command for the icon editor.
27 """ 36 """
37
28 def __init__(self, grid, text, oldImage, parent=None): 38 def __init__(self, grid, text, oldImage, parent=None):
29 """ 39 """
30 Constructor 40 Constructor
31 41
32 @param grid reference to the icon editor grid (IconEditorGrid) 42 @param grid reference to the icon editor grid (IconEditorGrid)
33 @param text text for the undo command (string) 43 @param text text for the undo command (string)
34 @param oldImage copy of the icon before the changes were applied 44 @param oldImage copy of the icon before the changes were applied
35 (QImage) 45 (QImage)
36 @param parent reference to the parent command (QUndoCommand) 46 @param parent reference to the parent command (QUndoCommand)
37 """ 47 """
38 super().__init__(text, parent) 48 super().__init__(text, parent)
39 49
40 self.__grid = grid 50 self.__grid = grid
41 self.__imageBefore = QImage(oldImage) 51 self.__imageBefore = QImage(oldImage)
42 self.__imageAfter = None 52 self.__imageAfter = None
43 53
44 def setAfterImage(self, image): 54 def setAfterImage(self, image):
45 """ 55 """
46 Public method to set the image after the changes were applied. 56 Public method to set the image after the changes were applied.
47 57
48 @param image copy of the icon after the changes were applied (QImage) 58 @param image copy of the icon after the changes were applied (QImage)
49 """ 59 """
50 self.__imageAfter = QImage(image) 60 self.__imageAfter = QImage(image)
51 61
52 def undo(self): 62 def undo(self):
53 """ 63 """
54 Public method to perform the undo. 64 Public method to perform the undo.
55 """ 65 """
56 self.__grid.setIconImage(self.__imageBefore, undoRedo=True) 66 self.__grid.setIconImage(self.__imageBefore, undoRedo=True)
57 67
58 def redo(self): 68 def redo(self):
59 """ 69 """
60 Public method to perform the redo. 70 Public method to perform the redo.
61 """ 71 """
62 if self.__imageAfter: 72 if self.__imageAfter:
63 self.__grid.setIconImage(self.__imageAfter, undoRedo=True) 73 self.__grid.setIconImage(self.__imageAfter, undoRedo=True)
64 74
65 75
66 class IconEditorTool(enum.IntEnum): 76 class IconEditorTool(enum.IntEnum):
67 """ 77 """
68 Class defining the edit tools. 78 Class defining the edit tools.
69 """ 79 """
80
70 PENCIL = 1 81 PENCIL = 1
71 RUBBER = 2 82 RUBBER = 2
72 LINE = 3 83 LINE = 3
73 RECTANGLE = 4 84 RECTANGLE = 4
74 FILLED_RECTANGLE = 5 85 FILLED_RECTANGLE = 5
76 FILLED_CIRCLE = 7 87 FILLED_CIRCLE = 7
77 ELLIPSE = 8 88 ELLIPSE = 8
78 FILLED_ELLIPSE = 9 89 FILLED_ELLIPSE = 9
79 FILL = 10 90 FILL = 10
80 COLOR_PICKER = 11 91 COLOR_PICKER = 11
81 92
82 SELECT_RECTANGLE = 100 93 SELECT_RECTANGLE = 100
83 SELECT_CIRCLE = 101 94 SELECT_CIRCLE = 101
84 95
85 96
86 class IconEditorGrid(QWidget): 97 class IconEditorGrid(QWidget):
87 """ 98 """
88 Class implementing the icon editor grid. 99 Class implementing the icon editor grid.
89 100
90 @signal canRedoChanged(bool) emitted after the redo status has changed 101 @signal canRedoChanged(bool) emitted after the redo status has changed
91 @signal canUndoChanged(bool) emitted after the undo status has changed 102 @signal canUndoChanged(bool) emitted after the undo status has changed
92 @signal clipboardImageAvailable(bool) emitted to signal the availability 103 @signal clipboardImageAvailable(bool) emitted to signal the availability
93 of an image to be pasted 104 of an image to be pasted
94 @signal colorChanged(QColor) emitted after the drawing color was changed 105 @signal colorChanged(QColor) emitted after the drawing color was changed
99 @signal selectionAvailable(bool) emitted to signal a change of the 110 @signal selectionAvailable(bool) emitted to signal a change of the
100 selection 111 selection
101 @signal sizeChanged(int, int) emitted after the size has been changed 112 @signal sizeChanged(int, int) emitted after the size has been changed
102 @signal zoomChanged(int) emitted to signal a change of the zoom value 113 @signal zoomChanged(int) emitted to signal a change of the zoom value
103 """ 114 """
115
104 canRedoChanged = pyqtSignal(bool) 116 canRedoChanged = pyqtSignal(bool)
105 canUndoChanged = pyqtSignal(bool) 117 canUndoChanged = pyqtSignal(bool)
106 clipboardImageAvailable = pyqtSignal(bool) 118 clipboardImageAvailable = pyqtSignal(bool)
107 colorChanged = pyqtSignal(QColor) 119 colorChanged = pyqtSignal(QColor)
108 imageChanged = pyqtSignal(bool) 120 imageChanged = pyqtSignal(bool)
109 positionChanged = pyqtSignal(int, int) 121 positionChanged = pyqtSignal(int, int)
110 previewChanged = pyqtSignal(QPixmap) 122 previewChanged = pyqtSignal(QPixmap)
111 selectionAvailable = pyqtSignal(bool) 123 selectionAvailable = pyqtSignal(bool)
112 sizeChanged = pyqtSignal(int, int) 124 sizeChanged = pyqtSignal(int, int)
113 zoomChanged = pyqtSignal(int) 125 zoomChanged = pyqtSignal(int)
114 126
115 MarkColor = QColor(255, 255, 255, 255) 127 MarkColor = QColor(255, 255, 255, 255)
116 NoMarkColor = QColor(0, 0, 0, 0) 128 NoMarkColor = QColor(0, 0, 0, 0)
117 129
118 ZoomMinimum = 100 130 ZoomMinimum = 100
119 ZoomMaximum = 10000 131 ZoomMaximum = 10000
120 ZoomStep = 100 132 ZoomStep = 100
121 ZoomDefault = 1200 133 ZoomDefault = 1200
122 ZoomPercent = True 134 ZoomPercent = True
123 135
124 def __init__(self, parent=None): 136 def __init__(self, parent=None):
125 """ 137 """
126 Constructor 138 Constructor
127 139
128 @param parent reference to the parent widget (QWidget) 140 @param parent reference to the parent widget (QWidget)
129 """ 141 """
130 super().__init__(parent) 142 super().__init__(parent)
131 143
132 self.setAttribute(Qt.WidgetAttribute.WA_StaticContents) 144 self.setAttribute(Qt.WidgetAttribute.WA_StaticContents)
133 self.setSizePolicy(QSizePolicy.Policy.Minimum, 145 self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
134 QSizePolicy.Policy.Minimum) 146
135
136 self.__curColor = Qt.GlobalColor.black 147 self.__curColor = Qt.GlobalColor.black
137 self.__zoom = 12 148 self.__zoom = 12
138 self.__curTool = IconEditorTool.PENCIL 149 self.__curTool = IconEditorTool.PENCIL
139 self.__startPos = QPoint() 150 self.__startPos = QPoint()
140 self.__endPos = QPoint() 151 self.__endPos = QPoint()
142 self.__selecting = False 153 self.__selecting = False
143 self.__selRect = QRect() 154 self.__selRect = QRect()
144 self.__isPasting = False 155 self.__isPasting = False
145 self.__clipboardSize = QSize() 156 self.__clipboardSize = QSize()
146 self.__pasteRect = QRect() 157 self.__pasteRect = QRect()
147 158
148 self.__undoStack = QUndoStack(self) 159 self.__undoStack = QUndoStack(self)
149 self.__currentUndoCmd = None 160 self.__currentUndoCmd = None
150 161
151 self.__image = QImage(32, 32, QImage.Format.Format_ARGB32) 162 self.__image = QImage(32, 32, QImage.Format.Format_ARGB32)
152 self.__image.fill(Qt.GlobalColor.transparent) 163 self.__image.fill(Qt.GlobalColor.transparent)
153 self.__markImage = QImage(self.__image) 164 self.__markImage = QImage(self.__image)
154 self.__markImage.fill(self.NoMarkColor.rgba()) 165 self.__markImage.fill(self.NoMarkColor.rgba())
155 166
156 self.__compositingMode = ( 167 self.__compositingMode = QPainter.CompositionMode.CompositionMode_SourceOver
157 QPainter.CompositionMode.CompositionMode_SourceOver
158 )
159 self.__lastPos = (-1, -1) 168 self.__lastPos = (-1, -1)
160 169
161 self.__gridEnabled = True 170 self.__gridEnabled = True
162 self.__selectionAvailable = False 171 self.__selectionAvailable = False
163 172
164 self.__initCursors() 173 self.__initCursors()
165 self.__initUndoTexts() 174 self.__initUndoTexts()
166 175
167 self.setMouseTracking(True) 176 self.setMouseTracking(True)
168 177
169 self.__undoStack.canRedoChanged.connect(self.canRedoChanged) 178 self.__undoStack.canRedoChanged.connect(self.canRedoChanged)
170 self.__undoStack.canUndoChanged.connect(self.canUndoChanged) 179 self.__undoStack.canUndoChanged.connect(self.canUndoChanged)
171 self.__undoStack.cleanChanged.connect(self.__cleanChanged) 180 self.__undoStack.cleanChanged.connect(self.__cleanChanged)
172 181
173 self.imageChanged.connect(self.__updatePreviewPixmap) 182 self.imageChanged.connect(self.__updatePreviewPixmap)
174 QApplication.clipboard().dataChanged.connect(self.__checkClipboard) 183 QApplication.clipboard().dataChanged.connect(self.__checkClipboard)
175 184
176 self.__checkClipboard() 185 self.__checkClipboard()
177 186
178 def __initCursors(self): 187 def __initCursors(self):
179 """ 188 """
180 Private method to initialize the various cursors. 189 Private method to initialize the various cursors.
181 """ 190 """
182 cursorsPath = os.path.join(os.path.dirname(__file__), "cursors") 191 cursorsPath = os.path.join(os.path.dirname(__file__), "cursors")
183 192
184 self.__normalCursor = QCursor(Qt.CursorShape.ArrowCursor) 193 self.__normalCursor = QCursor(Qt.CursorShape.ArrowCursor)
185 194
186 pix = QPixmap(os.path.join(cursorsPath, "colorpicker-cursor.xpm")) 195 pix = QPixmap(os.path.join(cursorsPath, "colorpicker-cursor.xpm"))
187 mask = pix.createHeuristicMask() 196 mask = pix.createHeuristicMask()
188 pix.setMask(mask) 197 pix.setMask(mask)
189 self.__colorPickerCursor = QCursor(pix, 1, 21) 198 self.__colorPickerCursor = QCursor(pix, 1, 21)
190 199
191 pix = QPixmap(os.path.join(cursorsPath, "paintbrush-cursor.xpm")) 200 pix = QPixmap(os.path.join(cursorsPath, "paintbrush-cursor.xpm"))
192 mask = pix.createHeuristicMask() 201 mask = pix.createHeuristicMask()
193 pix.setMask(mask) 202 pix.setMask(mask)
194 self.__paintCursor = QCursor(pix, 0, 19) 203 self.__paintCursor = QCursor(pix, 0, 19)
195 204
196 pix = QPixmap(os.path.join(cursorsPath, "fill-cursor.xpm")) 205 pix = QPixmap(os.path.join(cursorsPath, "fill-cursor.xpm"))
197 mask = pix.createHeuristicMask() 206 mask = pix.createHeuristicMask()
198 pix.setMask(mask) 207 pix.setMask(mask)
199 self.__fillCursor = QCursor(pix, 3, 20) 208 self.__fillCursor = QCursor(pix, 3, 20)
200 209
201 pix = QPixmap(os.path.join(cursorsPath, "aim-cursor.xpm")) 210 pix = QPixmap(os.path.join(cursorsPath, "aim-cursor.xpm"))
202 mask = pix.createHeuristicMask() 211 mask = pix.createHeuristicMask()
203 pix.setMask(mask) 212 pix.setMask(mask)
204 self.__aimCursor = QCursor(pix, 10, 10) 213 self.__aimCursor = QCursor(pix, 10, 10)
205 214
206 pix = QPixmap(os.path.join(cursorsPath, "eraser-cursor.xpm")) 215 pix = QPixmap(os.path.join(cursorsPath, "eraser-cursor.xpm"))
207 mask = pix.createHeuristicMask() 216 mask = pix.createHeuristicMask()
208 pix.setMask(mask) 217 pix.setMask(mask)
209 self.__rubberCursor = QCursor(pix, 1, 16) 218 self.__rubberCursor = QCursor(pix, 1, 16)
210 219
211 def __initUndoTexts(self): 220 def __initUndoTexts(self):
212 """ 221 """
213 Private method to initialize texts to be associated with undo commands 222 Private method to initialize texts to be associated with undo commands
214 for the various drawing tools. 223 for the various drawing tools.
215 """ 224 """
223 IconEditorTool.FILLED_CIRCLE: self.tr("Draw Filled Circle"), 232 IconEditorTool.FILLED_CIRCLE: self.tr("Draw Filled Circle"),
224 IconEditorTool.ELLIPSE: self.tr("Draw Ellipse"), 233 IconEditorTool.ELLIPSE: self.tr("Draw Ellipse"),
225 IconEditorTool.FILLED_ELLIPSE: self.tr("Draw Filled Ellipse"), 234 IconEditorTool.FILLED_ELLIPSE: self.tr("Draw Filled Ellipse"),
226 IconEditorTool.FILL: self.tr("Fill Region"), 235 IconEditorTool.FILL: self.tr("Fill Region"),
227 } 236 }
228 237
229 def isDirty(self): 238 def isDirty(self):
230 """ 239 """
231 Public method to check the dirty status. 240 Public method to check the dirty status.
232 241
233 @return flag indicating a modified status (boolean) 242 @return flag indicating a modified status (boolean)
234 """ 243 """
235 return self.__dirty 244 return self.__dirty
236 245
237 def setDirty(self, dirty, setCleanState=False): 246 def setDirty(self, dirty, setCleanState=False):
238 """ 247 """
239 Public slot to set the dirty flag. 248 Public slot to set the dirty flag.
240 249
241 @param dirty flag indicating the new modification status (boolean) 250 @param dirty flag indicating the new modification status (boolean)
242 @param setCleanState flag indicating to set the undo stack to clean 251 @param setCleanState flag indicating to set the undo stack to clean
243 (boolean) 252 (boolean)
244 """ 253 """
245 self.__dirty = dirty 254 self.__dirty = dirty
246 self.imageChanged.emit(dirty) 255 self.imageChanged.emit(dirty)
247 256
248 if not dirty and setCleanState: 257 if not dirty and setCleanState:
249 self.__undoStack.setClean() 258 self.__undoStack.setClean()
250 259
251 def sizeHint(self): 260 def sizeHint(self):
252 """ 261 """
253 Public method to report the size hint. 262 Public method to report the size hint.
254 263
255 @return size hint (QSize) 264 @return size hint (QSize)
256 """ 265 """
257 size = self.__zoom * self.__image.size() 266 size = self.__zoom * self.__image.size()
258 if self.__zoom >= 3 and self.__gridEnabled: 267 if self.__zoom >= 3 and self.__gridEnabled:
259 size += QSize(1, 1) 268 size += QSize(1, 1)
260 return size 269 return size
261 270
262 def setPenColor(self, newColor): 271 def setPenColor(self, newColor):
263 """ 272 """
264 Public method to set the drawing color. 273 Public method to set the drawing color.
265 274
266 @param newColor reference to the new color (QColor) 275 @param newColor reference to the new color (QColor)
267 """ 276 """
268 self.__curColor = QColor(newColor) 277 self.__curColor = QColor(newColor)
269 self.colorChanged.emit(QColor(newColor)) 278 self.colorChanged.emit(QColor(newColor))
270 279
271 def penColor(self): 280 def penColor(self):
272 """ 281 """
273 Public method to get the current drawing color. 282 Public method to get the current drawing color.
274 283
275 @return current drawing color (QColor) 284 @return current drawing color (QColor)
276 """ 285 """
277 return QColor(self.__curColor) 286 return QColor(self.__curColor)
278 287
279 def setCompositingMode(self, mode): 288 def setCompositingMode(self, mode):
280 """ 289 """
281 Public method to set the compositing mode. 290 Public method to set the compositing mode.
282 291
283 @param mode compositing mode to set (QPainter.CompositionMode) 292 @param mode compositing mode to set (QPainter.CompositionMode)
284 """ 293 """
285 self.__compositingMode = mode 294 self.__compositingMode = mode
286 295
287 def compositingMode(self): 296 def compositingMode(self):
288 """ 297 """
289 Public method to get the compositing mode. 298 Public method to get the compositing mode.
290 299
291 @return compositing mode (QPainter.CompositionMode) 300 @return compositing mode (QPainter.CompositionMode)
292 """ 301 """
293 return self.__compositingMode 302 return self.__compositingMode
294 303
295 def setTool(self, tool): 304 def setTool(self, tool):
296 """ 305 """
297 Public method to set the current drawing tool. 306 Public method to set the current drawing tool.
298 307
299 @param tool drawing tool to be used 308 @param tool drawing tool to be used
300 @type IconEditorTool 309 @type IconEditorTool
301 """ 310 """
302 self.__curTool = tool 311 self.__curTool = tool
303 self.__lastPos = (-1, -1) 312 self.__lastPos = (-1, -1)
304 313
305 if self.__curTool in [ 314 if self.__curTool in [
306 IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE 315 IconEditorTool.SELECT_RECTANGLE,
316 IconEditorTool.SELECT_CIRCLE,
307 ]: 317 ]:
308 self.__selecting = True 318 self.__selecting = True
309 else: 319 else:
310 self.__selecting = False 320 self.__selecting = False
311 321
312 if self.__curTool in [ 322 if self.__curTool in [
313 IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE, 323 IconEditorTool.SELECT_RECTANGLE,
324 IconEditorTool.SELECT_CIRCLE,
314 IconEditorTool.LINE, 325 IconEditorTool.LINE,
315 IconEditorTool.RECTANGLE, IconEditorTool.FILLED_RECTANGLE, 326 IconEditorTool.RECTANGLE,
316 IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE, 327 IconEditorTool.FILLED_RECTANGLE,
317 IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE 328 IconEditorTool.CIRCLE,
329 IconEditorTool.FILLED_CIRCLE,
330 IconEditorTool.ELLIPSE,
331 IconEditorTool.FILLED_ELLIPSE,
318 ]: 332 ]:
319 self.setCursor(self.__aimCursor) 333 self.setCursor(self.__aimCursor)
320 elif self.__curTool == IconEditorTool.FILL: 334 elif self.__curTool == IconEditorTool.FILL:
321 self.setCursor(self.__fillCursor) 335 self.setCursor(self.__fillCursor)
322 elif self.__curTool == IconEditorTool.COLOR_PICKER: 336 elif self.__curTool == IconEditorTool.COLOR_PICKER:
325 self.setCursor(self.__paintCursor) 339 self.setCursor(self.__paintCursor)
326 elif self.__curTool == IconEditorTool.RUBBER: 340 elif self.__curTool == IconEditorTool.RUBBER:
327 self.setCursor(self.__rubberCursor) 341 self.setCursor(self.__rubberCursor)
328 else: 342 else:
329 self.setCursor(self.__normalCursor) 343 self.setCursor(self.__normalCursor)
330 344
331 def tool(self): 345 def tool(self):
332 """ 346 """
333 Public method to get the current drawing tool. 347 Public method to get the current drawing tool.
334 348
335 @return current drawing tool 349 @return current drawing tool
336 @rtype IconEditorTool 350 @rtype IconEditorTool
337 """ 351 """
338 return self.__curTool 352 return self.__curTool
339 353
340 def setIconImage(self, newImage, undoRedo=False, clearUndo=False): 354 def setIconImage(self, newImage, undoRedo=False, clearUndo=False):
341 """ 355 """
342 Public method to set a new icon image. 356 Public method to set a new icon image.
343 357
344 @param newImage reference to the new image (QImage) 358 @param newImage reference to the new image (QImage)
345 @param undoRedo flag indicating an undo or redo operation (boolean) 359 @param undoRedo flag indicating an undo or redo operation (boolean)
346 @param clearUndo flag indicating to clear the undo stack (boolean) 360 @param clearUndo flag indicating to clear the undo stack (boolean)
347 """ 361 """
348 if newImage != self.__image: 362 if newImage != self.__image:
349 self.__image = newImage.convertToFormat( 363 self.__image = newImage.convertToFormat(QImage.Format.Format_ARGB32)
350 QImage.Format.Format_ARGB32)
351 self.update() 364 self.update()
352 self.updateGeometry() 365 self.updateGeometry()
353 self.resize(self.sizeHint()) 366 self.resize(self.sizeHint())
354 367
355 self.__markImage = QImage(self.__image) 368 self.__markImage = QImage(self.__image)
356 self.__markImage.fill(self.NoMarkColor.rgba()) 369 self.__markImage.fill(self.NoMarkColor.rgba())
357 370
358 if undoRedo: 371 if undoRedo:
359 self.setDirty(not self.__undoStack.isClean()) 372 self.setDirty(not self.__undoStack.isClean())
360 else: 373 else:
361 self.setDirty(False) 374 self.setDirty(False)
362 375
363 if clearUndo: 376 if clearUndo:
364 self.__undoStack.clear() 377 self.__undoStack.clear()
365 378
366 self.sizeChanged.emit(*self.iconSize()) 379 self.sizeChanged.emit(*self.iconSize())
367 380
368 def iconImage(self): 381 def iconImage(self):
369 """ 382 """
370 Public method to get a copy of the icon image. 383 Public method to get a copy of the icon image.
371 384
372 @return copy of the icon image (QImage) 385 @return copy of the icon image (QImage)
373 """ 386 """
374 return QImage(self.__image) 387 return QImage(self.__image)
375 388
376 def iconSize(self): 389 def iconSize(self):
377 """ 390 """
378 Public method to get the size of the icon. 391 Public method to get the size of the icon.
379 392
380 @return width and height of the image as a tuple (integer, integer) 393 @return width and height of the image as a tuple (integer, integer)
381 """ 394 """
382 return self.__image.width(), self.__image.height() 395 return self.__image.width(), self.__image.height()
383 396
384 def setZoomFactor(self, newZoom): 397 def setZoomFactor(self, newZoom):
385 """ 398 """
386 Public method to set the zoom factor in percent. 399 Public method to set the zoom factor in percent.
387 400
388 @param newZoom zoom factor (integer >= 100) 401 @param newZoom zoom factor (integer >= 100)
389 """ 402 """
390 newZoom = max(100, newZoom) # must not be less than 100 403 newZoom = max(100, newZoom) # must not be less than 100
391 if newZoom != self.__zoom: 404 if newZoom != self.__zoom:
392 self.__zoom = newZoom // 100 405 self.__zoom = newZoom // 100
393 self.update() 406 self.update()
394 self.updateGeometry() 407 self.updateGeometry()
395 self.resize(self.sizeHint()) 408 self.resize(self.sizeHint())
396 self.zoomChanged.emit(int(self.__zoom * 100)) 409 self.zoomChanged.emit(int(self.__zoom * 100))
397 410
398 def zoomFactor(self): 411 def zoomFactor(self):
399 """ 412 """
400 Public method to get the current zoom factor in percent. 413 Public method to get the current zoom factor in percent.
401 414
402 @return zoom factor (integer) 415 @return zoom factor (integer)
403 """ 416 """
404 return self.__zoom * 100 417 return self.__zoom * 100
405 418
406 def setGridEnabled(self, enable): 419 def setGridEnabled(self, enable):
407 """ 420 """
408 Public method to enable the display of grid lines. 421 Public method to enable the display of grid lines.
409 422
410 @param enable enabled status of the grid lines (boolean) 423 @param enable enabled status of the grid lines (boolean)
411 """ 424 """
412 if enable != self.__gridEnabled: 425 if enable != self.__gridEnabled:
413 self.__gridEnabled = enable 426 self.__gridEnabled = enable
414 self.update() 427 self.update()
415 428
416 def isGridEnabled(self): 429 def isGridEnabled(self):
417 """ 430 """
418 Public method to get the grid lines status. 431 Public method to get the grid lines status.
419 432
420 @return enabled status of the grid lines (boolean) 433 @return enabled status of the grid lines (boolean)
421 """ 434 """
422 return self.__gridEnabled 435 return self.__gridEnabled
423 436
424 def paintEvent(self, evt): 437 def paintEvent(self, evt):
425 """ 438 """
426 Protected method called to repaint some of the widget. 439 Protected method called to repaint some of the widget.
427 440
428 @param evt reference to the paint event object (QPaintEvent) 441 @param evt reference to the paint event object (QPaintEvent)
429 """ 442 """
430 painter = QPainter(self) 443 painter = QPainter(self)
431 444
432 if self.__zoom >= 3 and self.__gridEnabled: 445 if self.__zoom >= 3 and self.__gridEnabled:
433 if ericApp().usesDarkPalette(): 446 if ericApp().usesDarkPalette():
434 painter.setPen(self.palette().window().color()) 447 painter.setPen(self.palette().window().color())
435 else: 448 else:
436 painter.setPen(self.palette().windowText().color()) 449 painter.setPen(self.palette().windowText().color())
437 i = 0 450 i = 0
438 while i <= self.__image.width(): 451 while i <= self.__image.width():
439 painter.drawLine( 452 painter.drawLine(
440 self.__zoom * i, 0, 453 self.__zoom * i,
441 self.__zoom * i, self.__zoom * self.__image.height()) 454 0,
455 self.__zoom * i,
456 self.__zoom * self.__image.height(),
457 )
442 i += 1 458 i += 1
443 j = 0 459 j = 0
444 while j <= self.__image.height(): 460 while j <= self.__image.height():
445 painter.drawLine( 461 painter.drawLine(
446 0, self.__zoom * j, 462 0,
447 self.__zoom * self.__image.width(), self.__zoom * j) 463 self.__zoom * j,
464 self.__zoom * self.__image.width(),
465 self.__zoom * j,
466 )
448 j += 1 467 j += 1
449 468
450 col = QColor("#aaa") 469 col = QColor("#aaa")
451 painter.setPen(Qt.PenStyle.DashLine) 470 painter.setPen(Qt.PenStyle.DashLine)
452 for i in range(0, self.__image.width()): 471 for i in range(0, self.__image.width()):
453 for j in range(0, self.__image.height()): 472 for j in range(0, self.__image.height()):
454 rect = self.__pixelRect(i, j) 473 rect = self.__pixelRect(i, j)
455 if evt.region().intersects(rect): 474 if evt.region().intersects(rect):
456 color = QColor.fromRgba(self.__image.pixel(i, j)) 475 color = QColor.fromRgba(self.__image.pixel(i, j))
457 painter.fillRect(rect, QBrush(Qt.GlobalColor.white)) 476 painter.fillRect(rect, QBrush(Qt.GlobalColor.white))
458 painter.fillRect(QRect(rect.topLeft(), rect.center()), col) 477 painter.fillRect(QRect(rect.topLeft(), rect.center()), col)
459 painter.fillRect(QRect(rect.center(), rect.bottomRight()), 478 painter.fillRect(QRect(rect.center(), rect.bottomRight()), col)
460 col)
461 painter.fillRect(rect, QBrush(color)) 479 painter.fillRect(rect, QBrush(color))
462 480
463 if self.__isMarked(i, j): 481 if self.__isMarked(i, j):
464 painter.drawRect(rect.adjusted(0, 0, -1, -1)) 482 painter.drawRect(rect.adjusted(0, 0, -1, -1))
465 483
466 painter.end() 484 painter.end()
467 485
468 def __pixelRect(self, i, j): 486 def __pixelRect(self, i, j):
469 """ 487 """
470 Private method to determine the rectangle for a given pixel coordinate. 488 Private method to determine the rectangle for a given pixel coordinate.
471 489
472 @param i x-coordinate of the pixel in the image (integer) 490 @param i x-coordinate of the pixel in the image (integer)
473 @param j y-coordinate of the pixel in the image (integer) 491 @param j y-coordinate of the pixel in the image (integer)
474 @return rectangle for the given pixel coordinates (QRect) 492 @return rectangle for the given pixel coordinates (QRect)
475 """ 493 """
476 if self.__zoom >= 3 and self.__gridEnabled: 494 if self.__zoom >= 3 and self.__gridEnabled:
477 return QRect(self.__zoom * i + 1, self.__zoom * j + 1, 495 return QRect(
478 self.__zoom - 1, self.__zoom - 1) 496 self.__zoom * i + 1,
497 self.__zoom * j + 1,
498 self.__zoom - 1,
499 self.__zoom - 1,
500 )
479 else: 501 else:
480 return QRect(self.__zoom * i, self.__zoom * j, 502 return QRect(self.__zoom * i, self.__zoom * j, self.__zoom, self.__zoom)
481 self.__zoom, self.__zoom) 503
482
483 def mousePressEvent(self, evt): 504 def mousePressEvent(self, evt):
484 """ 505 """
485 Protected method to handle mouse button press events. 506 Protected method to handle mouse button press events.
486 507
487 @param evt reference to the mouse event object (QMouseEvent) 508 @param evt reference to the mouse event object (QMouseEvent)
488 """ 509 """
489 if evt.button() == Qt.MouseButton.LeftButton: 510 if evt.button() == Qt.MouseButton.LeftButton:
490 if self.__isPasting: 511 if self.__isPasting:
491 self.__isPasting = False 512 self.__isPasting = False
492 self.editPaste(True) 513 self.editPaste(True)
493 self.__markImage.fill(self.NoMarkColor.rgba()) 514 self.__markImage.fill(self.NoMarkColor.rgba())
494 self.update(self.__pasteRect) 515 self.update(self.__pasteRect)
495 self.__pasteRect = QRect() 516 self.__pasteRect = QRect()
496 return 517 return
497 518
498 if self.__curTool == IconEditorTool.PENCIL: 519 if self.__curTool == IconEditorTool.PENCIL:
499 cmd = IconEditCommand(self, self.__undoTexts[self.__curTool], 520 cmd = IconEditCommand(
500 self.__image) 521 self, self.__undoTexts[self.__curTool], self.__image
522 )
501 self.__setImagePixel(evt.position().toPoint(), True) 523 self.__setImagePixel(evt.position().toPoint(), True)
502 self.setDirty(True) 524 self.setDirty(True)
503 self.__undoStack.push(cmd) 525 self.__undoStack.push(cmd)
504 self.__currentUndoCmd = cmd 526 self.__currentUndoCmd = cmd
505 elif self.__curTool == IconEditorTool.RUBBER: 527 elif self.__curTool == IconEditorTool.RUBBER:
506 cmd = IconEditCommand(self, self.__undoTexts[self.__curTool], 528 cmd = IconEditCommand(
507 self.__image) 529 self, self.__undoTexts[self.__curTool], self.__image
530 )
508 self.__setImagePixel(evt.position().toPoint(), False) 531 self.__setImagePixel(evt.position().toPoint(), False)
509 self.setDirty(True) 532 self.setDirty(True)
510 self.__undoStack.push(cmd) 533 self.__undoStack.push(cmd)
511 self.__currentUndoCmd = cmd 534 self.__currentUndoCmd = cmd
512 elif self.__curTool == IconEditorTool.FILL: 535 elif self.__curTool == IconEditorTool.FILL:
513 i, j = self.__imageCoordinates(evt.position().toPoint()) 536 i, j = self.__imageCoordinates(evt.position().toPoint())
514 col = QColor() 537 col = QColor()
515 col.setRgba(self.__image.pixel(i, j)) 538 col.setRgba(self.__image.pixel(i, j))
516 cmd = IconEditCommand(self, self.__undoTexts[self.__curTool], 539 cmd = IconEditCommand(
517 self.__image) 540 self, self.__undoTexts[self.__curTool], self.__image
541 )
518 self.__drawFlood(i, j, col) 542 self.__drawFlood(i, j, col)
519 self.setDirty(True) 543 self.setDirty(True)
520 self.__undoStack.push(cmd) 544 self.__undoStack.push(cmd)
521 cmd.setAfterImage(self.__image) 545 cmd.setAfterImage(self.__image)
522 elif self.__curTool == IconEditorTool.COLOR_PICKER: 546 elif self.__curTool == IconEditorTool.COLOR_PICKER:
526 self.setPenColor(col) 550 self.setPenColor(col)
527 else: 551 else:
528 self.__unMark() 552 self.__unMark()
529 self.__startPos = evt.position().toPoint() 553 self.__startPos = evt.position().toPoint()
530 self.__endPos = evt.position().toPoint() 554 self.__endPos = evt.position().toPoint()
531 555
532 def mouseMoveEvent(self, evt): 556 def mouseMoveEvent(self, evt):
533 """ 557 """
534 Protected method to handle mouse move events. 558 Protected method to handle mouse move events.
535 559
536 @param evt reference to the mouse event object (QMouseEvent) 560 @param evt reference to the mouse event object (QMouseEvent)
537 """ 561 """
538 self.positionChanged.emit( 562 self.positionChanged.emit(*self.__imageCoordinates(evt.position().toPoint()))
539 *self.__imageCoordinates(evt.position().toPoint())) 563
540 564 if self.__isPasting and not (evt.buttons() & Qt.MouseButton.LeftButton):
541 if (
542 self.__isPasting and
543 not (evt.buttons() & Qt.MouseButton.LeftButton)
544 ):
545 self.__drawPasteRect(evt.position().toPoint()) 565 self.__drawPasteRect(evt.position().toPoint())
546 return 566 return
547 567
548 if evt.buttons() & Qt.MouseButton.LeftButton: 568 if evt.buttons() & Qt.MouseButton.LeftButton:
549 if self.__curTool == IconEditorTool.PENCIL: 569 if self.__curTool == IconEditorTool.PENCIL:
550 self.__setImagePixel(evt.position().toPoint(), True) 570 self.__setImagePixel(evt.position().toPoint(), True)
551 self.setDirty(True) 571 self.setDirty(True)
552 elif self.__curTool == IconEditorTool.RUBBER: 572 elif self.__curTool == IconEditorTool.RUBBER:
553 self.__setImagePixel(evt.position().toPoint(), False) 573 self.__setImagePixel(evt.position().toPoint(), False)
554 self.setDirty(True) 574 self.setDirty(True)
555 elif self.__curTool in [IconEditorTool.FILL, 575 elif self.__curTool in [IconEditorTool.FILL, IconEditorTool.COLOR_PICKER]:
556 IconEditorTool.COLOR_PICKER]: 576 pass # do nothing
557 pass # do nothing
558 else: 577 else:
559 self.__drawTool(evt.position().toPoint(), True) 578 self.__drawTool(evt.position().toPoint(), True)
560 579
561 def mouseReleaseEvent(self, evt): 580 def mouseReleaseEvent(self, evt):
562 """ 581 """
563 Protected method to handle mouse button release events. 582 Protected method to handle mouse button release events.
564 583
565 @param evt reference to the mouse event object (QMouseEvent) 584 @param evt reference to the mouse event object (QMouseEvent)
566 """ 585 """
567 if evt.button() == Qt.MouseButton.LeftButton: 586 if evt.button() == Qt.MouseButton.LeftButton:
568 if ( 587 if (
569 self.__curTool in [IconEditorTool.PENCIL, 588 self.__curTool in [IconEditorTool.PENCIL, IconEditorTool.RUBBER]
570 IconEditorTool.RUBBER] and 589 and self.__currentUndoCmd
571 self.__currentUndoCmd
572 ): 590 ):
573 self.__currentUndoCmd.setAfterImage(self.__image) 591 self.__currentUndoCmd.setAfterImage(self.__image)
574 self.__currentUndoCmd = None 592 self.__currentUndoCmd = None
575 593
576 if self.__curTool not in [ 594 if self.__curTool not in [
577 IconEditorTool.PENCIL, IconEditorTool.RUBBER, 595 IconEditorTool.PENCIL,
578 IconEditorTool.FILL, IconEditorTool.COLOR_PICKER, 596 IconEditorTool.RUBBER,
579 IconEditorTool.SELECT_RECTANGLE, IconEditorTool.SELECT_CIRCLE 597 IconEditorTool.FILL,
598 IconEditorTool.COLOR_PICKER,
599 IconEditorTool.SELECT_RECTANGLE,
600 IconEditorTool.SELECT_CIRCLE,
580 ]: 601 ]:
581 cmd = IconEditCommand(self, self.__undoTexts[self.__curTool], 602 cmd = IconEditCommand(
582 self.__image) 603 self, self.__undoTexts[self.__curTool], self.__image
604 )
583 if self.__drawTool(evt.position().toPoint(), False): 605 if self.__drawTool(evt.position().toPoint(), False):
584 self.__undoStack.push(cmd) 606 self.__undoStack.push(cmd)
585 cmd.setAfterImage(self.__image) 607 cmd.setAfterImage(self.__image)
586 self.setDirty(True) 608 self.setDirty(True)
587 609
588 def __setImagePixel(self, pos, opaque): 610 def __setImagePixel(self, pos, opaque):
589 """ 611 """
590 Private slot to set or erase a pixel. 612 Private slot to set or erase a pixel.
591 613
592 @param pos position of the pixel in the widget (QPoint) 614 @param pos position of the pixel in the widget (QPoint)
593 @param opaque flag indicating a set operation (boolean) 615 @param opaque flag indicating a set operation (boolean)
594 """ 616 """
595 i, j = self.__imageCoordinates(pos) 617 i, j = self.__imageCoordinates(pos)
596 618
597 if self.__image.rect().contains(i, j) and (i, j) != self.__lastPos: 619 if self.__image.rect().contains(i, j) and (i, j) != self.__lastPos:
598 if opaque: 620 if opaque:
599 painter = QPainter(self.__image) 621 painter = QPainter(self.__image)
600 painter.setPen(self.penColor()) 622 painter.setPen(self.penColor())
601 painter.setCompositionMode(self.__compositingMode) 623 painter.setCompositionMode(self.__compositingMode)
602 painter.drawPoint(i, j) 624 painter.drawPoint(i, j)
603 else: 625 else:
604 self.__image.setPixel(i, j, qRgba(0, 0, 0, 0)) 626 self.__image.setPixel(i, j, qRgba(0, 0, 0, 0))
605 self.__lastPos = (i, j) 627 self.__lastPos = (i, j)
606 628
607 self.update(self.__pixelRect(i, j)) 629 self.update(self.__pixelRect(i, j))
608 630
609 def __imageCoordinates(self, pos): 631 def __imageCoordinates(self, pos):
610 """ 632 """
611 Private method to convert from widget to image coordinates. 633 Private method to convert from widget to image coordinates.
612 634
613 @param pos widget coordinate (QPoint) 635 @param pos widget coordinate (QPoint)
614 @return tuple with the image coordinates (tuple of two integers) 636 @return tuple with the image coordinates (tuple of two integers)
615 """ 637 """
616 i = pos.x() // self.__zoom 638 i = pos.x() // self.__zoom
617 j = pos.y() // self.__zoom 639 j = pos.y() // self.__zoom
618 return i, j 640 return i, j
619 641
620 def __drawPasteRect(self, pos): 642 def __drawPasteRect(self, pos):
621 """ 643 """
622 Private slot to draw a rectangle for signaling a paste operation. 644 Private slot to draw a rectangle for signaling a paste operation.
623 645
624 @param pos widget position of the paste rectangle (QPoint) 646 @param pos widget position of the paste rectangle (QPoint)
625 """ 647 """
626 self.__markImage.fill(self.NoMarkColor.rgba()) 648 self.__markImage.fill(self.NoMarkColor.rgba())
627 if self.__pasteRect.isValid(): 649 if self.__pasteRect.isValid():
628 self.__updateImageRect( 650 self.__updateImageRect(
629 self.__pasteRect.topLeft(), 651 self.__pasteRect.topLeft(),
630 self.__pasteRect.bottomRight() + QPoint(1, 1)) 652 self.__pasteRect.bottomRight() + QPoint(1, 1),
631 653 )
654
632 x, y = self.__imageCoordinates(pos) 655 x, y = self.__imageCoordinates(pos)
633 isize = self.__image.size() 656 isize = self.__image.size()
634 sx = ( 657 sx = (
635 self.__clipboardSize.width() 658 self.__clipboardSize.width()
636 if x + self.__clipboardSize.width() <= isize.width() else 659 if x + self.__clipboardSize.width() <= isize.width()
637 isize.width() - x 660 else isize.width() - x
638 ) 661 )
639 sy = ( 662 sy = (
640 self.__clipboardSize.height() 663 self.__clipboardSize.height()
641 if y + self.__clipboardSize.height() <= isize.height() else 664 if y + self.__clipboardSize.height() <= isize.height()
642 isize.height() - y 665 else isize.height() - y
643 ) 666 )
644 667
645 self.__pasteRect = QRect(QPoint(x, y), QSize(sx - 1, sy - 1)) 668 self.__pasteRect = QRect(QPoint(x, y), QSize(sx - 1, sy - 1))
646 669
647 painter = QPainter(self.__markImage) 670 painter = QPainter(self.__markImage)
648 painter.setPen(self.MarkColor) 671 painter.setPen(self.MarkColor)
649 painter.drawRect(self.__pasteRect) 672 painter.drawRect(self.__pasteRect)
650 painter.end() 673 painter.end()
651 674
652 self.__updateImageRect(self.__pasteRect.topLeft(), 675 self.__updateImageRect(
653 self.__pasteRect.bottomRight() + QPoint(1, 1)) 676 self.__pasteRect.topLeft(), self.__pasteRect.bottomRight() + QPoint(1, 1)
654 677 )
678
655 def __drawTool(self, pos, mark): 679 def __drawTool(self, pos, mark):
656 """ 680 """
657 Private method to perform a draw operation depending of the current 681 Private method to perform a draw operation depending of the current
658 tool. 682 tool.
659 683
660 @param pos widget coordinate to perform the draw operation at (QPoint) 684 @param pos widget coordinate to perform the draw operation at (QPoint)
661 @param mark flag indicating a mark operation (boolean) 685 @param mark flag indicating a mark operation (boolean)
662 @return flag indicating a successful draw (boolean) 686 @return flag indicating a successful draw (boolean)
663 """ 687 """
664 self.__unMark() 688 self.__unMark()
665 689
666 if mark: 690 if mark:
667 self.__endPos = QPoint(pos) 691 self.__endPos = QPoint(pos)
668 drawColor = self.MarkColor 692 drawColor = self.MarkColor
669 img = self.__markImage 693 img = self.__markImage
670 else: 694 else:
671 drawColor = self.penColor() 695 drawColor = self.penColor()
672 img = self.__image 696 img = self.__image
673 697
674 start = QPoint(*self.__imageCoordinates(self.__startPos)) 698 start = QPoint(*self.__imageCoordinates(self.__startPos))
675 end = QPoint(*self.__imageCoordinates(pos)) 699 end = QPoint(*self.__imageCoordinates(pos))
676 700
677 painter = QPainter(img) 701 painter = QPainter(img)
678 painter.setPen(drawColor) 702 painter.setPen(drawColor)
679 painter.setCompositionMode(self.__compositingMode) 703 painter.setCompositionMode(self.__compositingMode)
680 704
681 if self.__curTool == IconEditorTool.LINE: 705 if self.__curTool == IconEditorTool.LINE:
682 painter.drawLine(start, end) 706 painter.drawLine(start, end)
683 707
684 elif self.__curTool in [ 708 elif self.__curTool in [
685 IconEditorTool.RECTANGLE, IconEditorTool.FILLED_RECTANGLE, 709 IconEditorTool.RECTANGLE,
686 IconEditorTool.SELECT_RECTANGLE 710 IconEditorTool.FILLED_RECTANGLE,
711 IconEditorTool.SELECT_RECTANGLE,
687 ]: 712 ]:
688 left = min(start.x(), end.x()) 713 left = min(start.x(), end.x())
689 top = min(start.y(), end.y()) 714 top = min(start.y(), end.y())
690 right = max(start.x(), end.x()) 715 right = max(start.x(), end.x())
691 bottom = max(start.y(), end.y()) 716 bottom = max(start.y(), end.y())
695 for y in range(top, bottom + 1): 720 for y in range(top, bottom + 1):
696 painter.drawLine(left, y, right, y) 721 painter.drawLine(left, y, right, y)
697 else: 722 else:
698 painter.drawRect(left, top, right - left, bottom - top) 723 painter.drawRect(left, top, right - left, bottom - top)
699 if self.__selecting: 724 if self.__selecting:
700 self.__selRect = QRect( 725 self.__selRect = QRect(left, top, right - left + 1, bottom - top + 1)
701 left, top, right - left + 1, bottom - top + 1)
702 self.__selectionAvailable = True 726 self.__selectionAvailable = True
703 self.selectionAvailable.emit(True) 727 self.selectionAvailable.emit(True)
704 728
705 elif self.__curTool in [ 729 elif self.__curTool in [
706 IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE, 730 IconEditorTool.CIRCLE,
707 IconEditorTool.SELECT_CIRCLE 731 IconEditorTool.FILLED_CIRCLE,
732 IconEditorTool.SELECT_CIRCLE,
708 ]: 733 ]:
709 deltaX = abs(start.x() - end.x()) 734 deltaX = abs(start.x() - end.x())
710 deltaY = abs(start.y() - end.y()) 735 deltaY = abs(start.y() - end.y())
711 r = max(deltaX, deltaY) 736 r = max(deltaX, deltaY)
712 if self.__curTool in [ 737 if self.__curTool in [
713 IconEditorTool.FILLED_CIRCLE, IconEditorTool.SELECT_CIRCLE 738 IconEditorTool.FILLED_CIRCLE,
739 IconEditorTool.SELECT_CIRCLE,
714 ]: 740 ]:
715 painter.setBrush(QBrush(drawColor)) 741 painter.setBrush(QBrush(drawColor))
716 painter.drawEllipse(start, r, r) 742 painter.drawEllipse(start, r, r)
717 if self.__selecting: 743 if self.__selecting:
718 self.__selRect = QRect(start.x() - r, start.y() - r, 744 self.__selRect = QRect(
719 2 * r + 1, 2 * r + 1) 745 start.x() - r, start.y() - r, 2 * r + 1, 2 * r + 1
746 )
720 self.__selectionAvailable = True 747 self.__selectionAvailable = True
721 self.selectionAvailable.emit(True) 748 self.selectionAvailable.emit(True)
722 749
723 elif self.__curTool in [ 750 elif self.__curTool in [IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE]:
724 IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE
725 ]:
726 r1 = abs(start.x() - end.x()) 751 r1 = abs(start.x() - end.x())
727 r2 = abs(start.y() - end.y()) 752 r2 = abs(start.y() - end.y())
728 if r1 == 0 or r2 == 0: 753 if r1 == 0 or r2 == 0:
729 return False 754 return False
730 if self.__curTool == IconEditorTool.FILLED_ELLIPSE: 755 if self.__curTool == IconEditorTool.FILLED_ELLIPSE:
731 painter.setBrush(QBrush(drawColor)) 756 painter.setBrush(QBrush(drawColor))
732 painter.drawEllipse(start, r1, r2) 757 painter.drawEllipse(start, r1, r2)
733 758
734 painter.end() 759 painter.end()
735 760
736 if self.__curTool in [ 761 if self.__curTool in [
737 IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE, 762 IconEditorTool.CIRCLE,
738 IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE 763 IconEditorTool.FILLED_CIRCLE,
764 IconEditorTool.ELLIPSE,
765 IconEditorTool.FILLED_ELLIPSE,
739 ]: 766 ]:
740 self.update() 767 self.update()
741 else: 768 else:
742 self.__updateRect(self.__startPos, pos) 769 self.__updateRect(self.__startPos, pos)
743 770
744 return True 771 return True
745 772
746 def __drawFlood(self, i, j, oldColor, doUpdate=True): 773 def __drawFlood(self, i, j, oldColor, doUpdate=True):
747 """ 774 """
748 Private method to perform a flood fill operation. 775 Private method to perform a flood fill operation.
749 776
750 @param i x-value in image coordinates (integer) 777 @param i x-value in image coordinates (integer)
751 @param j y-value in image coordinates (integer) 778 @param j y-value in image coordinates (integer)
752 @param oldColor reference to the color at position i, j (QColor) 779 @param oldColor reference to the color at position i, j (QColor)
753 @param doUpdate flag indicating an update is requested (boolean) 780 @param doUpdate flag indicating an update is requested (boolean)
754 (used for speed optimizations) 781 (used for speed optimizations)
755 """ 782 """
756 if ( 783 if (
757 not self.__image.rect().contains(i, j) or 784 not self.__image.rect().contains(i, j)
758 self.__image.pixel(i, j) != oldColor.rgba() or 785 or self.__image.pixel(i, j) != oldColor.rgba()
759 self.__image.pixel(i, j) == self.penColor().rgba() 786 or self.__image.pixel(i, j) == self.penColor().rgba()
760 ): 787 ):
761 return 788 return
762 789
763 self.__image.setPixel(i, j, self.penColor().rgba()) 790 self.__image.setPixel(i, j, self.penColor().rgba())
764 791
765 self.__drawFlood(i, j - 1, oldColor, False) 792 self.__drawFlood(i, j - 1, oldColor, False)
766 self.__drawFlood(i, j + 1, oldColor, False) 793 self.__drawFlood(i, j + 1, oldColor, False)
767 self.__drawFlood(i - 1, j, oldColor, False) 794 self.__drawFlood(i - 1, j, oldColor, False)
768 self.__drawFlood(i + 1, j, oldColor, False) 795 self.__drawFlood(i + 1, j, oldColor, False)
769 796
770 if doUpdate: 797 if doUpdate:
771 self.update() 798 self.update()
772 799
773 def __updateRect(self, pos1, pos2): 800 def __updateRect(self, pos1, pos2):
774 """ 801 """
775 Private slot to update parts of the widget. 802 Private slot to update parts of the widget.
776 803
777 @param pos1 top, left position for the update in widget coordinates 804 @param pos1 top, left position for the update in widget coordinates
778 (QPoint) 805 (QPoint)
779 @param pos2 bottom, right position for the update in widget 806 @param pos2 bottom, right position for the update in widget
780 coordinates (QPoint) 807 coordinates (QPoint)
781 """ 808 """
782 self.__updateImageRect(QPoint(*self.__imageCoordinates(pos1)), 809 self.__updateImageRect(
783 QPoint(*self.__imageCoordinates(pos2))) 810 QPoint(*self.__imageCoordinates(pos1)),
784 811 QPoint(*self.__imageCoordinates(pos2)),
812 )
813
785 def __updateImageRect(self, ipos1, ipos2): 814 def __updateImageRect(self, ipos1, ipos2):
786 """ 815 """
787 Private slot to update parts of the widget. 816 Private slot to update parts of the widget.
788 817
789 @param ipos1 top, left position for the update in image coordinates 818 @param ipos1 top, left position for the update in image coordinates
790 (QPoint) 819 (QPoint)
791 @param ipos2 bottom, right position for the update in image 820 @param ipos2 bottom, right position for the update in image
792 coordinates (QPoint) 821 coordinates (QPoint)
793 """ 822 """
794 r1 = self.__pixelRect(ipos1.x(), ipos1.y()) 823 r1 = self.__pixelRect(ipos1.x(), ipos1.y())
795 r2 = self.__pixelRect(ipos2.x(), ipos2.y()) 824 r2 = self.__pixelRect(ipos2.x(), ipos2.y())
796 825
797 left = min(r1.x(), r2.x()) 826 left = min(r1.x(), r2.x())
798 top = min(r1.y(), r2.y()) 827 top = min(r1.y(), r2.y())
799 right = max(r1.x() + r1.width(), r2.x() + r2.width()) 828 right = max(r1.x() + r1.width(), r2.x() + r2.width())
800 bottom = max(r1.y() + r1.height(), r2.y() + r2.height()) 829 bottom = max(r1.y() + r1.height(), r2.y() + r2.height())
801 self.update(left, top, right - left + 1, bottom - top + 1) 830 self.update(left, top, right - left + 1, bottom - top + 1)
802 831
803 def __unMark(self): 832 def __unMark(self):
804 """ 833 """
805 Private slot to remove the mark indicator. 834 Private slot to remove the mark indicator.
806 """ 835 """
807 self.__markImage.fill(self.NoMarkColor.rgba()) 836 self.__markImage.fill(self.NoMarkColor.rgba())
808 if self.__curTool in [ 837 if self.__curTool in [
809 IconEditorTool.CIRCLE, IconEditorTool.FILLED_CIRCLE, 838 IconEditorTool.CIRCLE,
810 IconEditorTool.ELLIPSE, IconEditorTool.FILLED_ELLIPSE, 839 IconEditorTool.FILLED_CIRCLE,
811 IconEditorTool.SELECT_CIRCLE 840 IconEditorTool.ELLIPSE,
841 IconEditorTool.FILLED_ELLIPSE,
842 IconEditorTool.SELECT_CIRCLE,
812 ]: 843 ]:
813 self.update() 844 self.update()
814 else: 845 else:
815 self.__updateRect(self.__startPos, self.__endPos) 846 self.__updateRect(self.__startPos, self.__endPos)
816 847
817 if self.__selecting: 848 if self.__selecting:
818 self.__selRect = QRect() 849 self.__selRect = QRect()
819 self.__selectionAvailable = False 850 self.__selectionAvailable = False
820 self.selectionAvailable.emit(False) 851 self.selectionAvailable.emit(False)
821 852
822 def __isMarked(self, i, j): 853 def __isMarked(self, i, j):
823 """ 854 """
824 Private method to check, if a pixel is marked. 855 Private method to check, if a pixel is marked.
825 856
826 @param i x-value in image coordinates (integer) 857 @param i x-value in image coordinates (integer)
827 @param j y-value in image coordinates (integer) 858 @param j y-value in image coordinates (integer)
828 @return flag indicating a marked pixel (boolean) 859 @return flag indicating a marked pixel (boolean)
829 """ 860 """
830 return self.__markImage.pixel(i, j) == self.MarkColor.rgba() 861 return self.__markImage.pixel(i, j) == self.MarkColor.rgba()
831 862
832 def __updatePreviewPixmap(self): 863 def __updatePreviewPixmap(self):
833 """ 864 """
834 Private slot to generate and signal an updated preview pixmap. 865 Private slot to generate and signal an updated preview pixmap.
835 """ 866 """
836 p = QPixmap.fromImage(self.__image) 867 p = QPixmap.fromImage(self.__image)
837 self.previewChanged.emit(p) 868 self.previewChanged.emit(p)
838 869
839 def previewPixmap(self): 870 def previewPixmap(self):
840 """ 871 """
841 Public method to generate a preview pixmap. 872 Public method to generate a preview pixmap.
842 873
843 @return preview pixmap (QPixmap) 874 @return preview pixmap (QPixmap)
844 """ 875 """
845 p = QPixmap.fromImage(self.__image) 876 p = QPixmap.fromImage(self.__image)
846 return p 877 return p
847 878
848 def __checkClipboard(self): 879 def __checkClipboard(self):
849 """ 880 """
850 Private slot to check, if the clipboard contains a valid image, and 881 Private slot to check, if the clipboard contains a valid image, and
851 signal the result. 882 signal the result.
852 """ 883 """
853 ok = self.__clipboardImage()[1] 884 ok = self.__clipboardImage()[1]
854 self.__clipboardImageAvailable = ok 885 self.__clipboardImageAvailable = ok
855 self.clipboardImageAvailable.emit(ok) 886 self.clipboardImageAvailable.emit(ok)
856 887
857 def canPaste(self): 888 def canPaste(self):
858 """ 889 """
859 Public slot to check the availability of the paste operation. 890 Public slot to check the availability of the paste operation.
860 891
861 @return flag indicating availability of paste (boolean) 892 @return flag indicating availability of paste (boolean)
862 """ 893 """
863 return self.__clipboardImageAvailable 894 return self.__clipboardImageAvailable
864 895
865 def __clipboardImage(self): 896 def __clipboardImage(self):
866 """ 897 """
867 Private method to get an image from the clipboard. 898 Private method to get an image from the clipboard.
868 899
869 @return tuple with the image (QImage) and a flag indicating a 900 @return tuple with the image (QImage) and a flag indicating a
870 valid image (boolean) 901 valid image (boolean)
871 """ 902 """
872 img = QApplication.clipboard().image() 903 img = QApplication.clipboard().image()
873 ok = not img.isNull() 904 ok = not img.isNull()
874 if ok: 905 if ok:
875 img = img.convertToFormat(QImage.Format.Format_ARGB32) 906 img = img.convertToFormat(QImage.Format.Format_ARGB32)
876 907
877 return img, ok 908 return img, ok
878 909
879 def __getSelectionImage(self, cut): 910 def __getSelectionImage(self, cut):
880 """ 911 """
881 Private method to get an image from the selection. 912 Private method to get an image from the selection.
882 913
883 @param cut flag indicating to cut the selection (boolean) 914 @param cut flag indicating to cut the selection (boolean)
884 @return image of the selection (QImage) 915 @return image of the selection (QImage)
885 """ 916 """
886 if cut: 917 if cut:
887 cmd = IconEditCommand(self, self.tr("Cut Selection"), 918 cmd = IconEditCommand(self, self.tr("Cut Selection"), self.__image)
888 self.__image) 919
889
890 img = QImage(self.__selRect.size(), QImage.Format.Format_ARGB32) 920 img = QImage(self.__selRect.size(), QImage.Format.Format_ARGB32)
891 img.fill(Qt.GlobalColor.transparent) 921 img.fill(Qt.GlobalColor.transparent)
892 for i in range(0, self.__selRect.width()): 922 for i in range(0, self.__selRect.width()):
893 for j in range(0, self.__selRect.height()): 923 for j in range(0, self.__selRect.height()):
894 if ( 924 if self.__image.rect().contains(
895 self.__image.rect().contains( 925 self.__selRect.x() + i, self.__selRect.y() + j
896 self.__selRect.x() + i, self.__selRect.y() + j) and 926 ) and self.__isMarked(self.__selRect.x() + i, self.__selRect.y() + j):
897 self.__isMarked(self.__selRect.x() + i, 927 img.setPixel(
898 self.__selRect.y() + j) 928 i,
899 ): 929 j,
900 img.setPixel(i, j, self.__image.pixel( 930 self.__image.pixel(
901 self.__selRect.x() + i, self.__selRect.y() + j)) 931 self.__selRect.x() + i, self.__selRect.y() + j
932 ),
933 )
902 if cut: 934 if cut:
903 self.__image.setPixel(self.__selRect.x() + i, 935 self.__image.setPixel(
904 self.__selRect.y() + j, 936 self.__selRect.x() + i,
905 Qt.GlobalColor.transparent) 937 self.__selRect.y() + j,
906 938 Qt.GlobalColor.transparent,
939 )
940
907 if cut: 941 if cut:
908 self.__undoStack.push(cmd) 942 self.__undoStack.push(cmd)
909 cmd.setAfterImage(self.__image) 943 cmd.setAfterImage(self.__image)
910 944
911 self.__unMark() 945 self.__unMark()
912 946
913 if cut: 947 if cut:
914 self.update(self.__selRect) 948 self.update(self.__selRect)
915 949
916 return img 950 return img
917 951
918 def editCopy(self): 952 def editCopy(self):
919 """ 953 """
920 Public slot to copy the selection. 954 Public slot to copy the selection.
921 """ 955 """
922 if self.__selRect.isValid(): 956 if self.__selRect.isValid():
923 img = self.__getSelectionImage(False) 957 img = self.__getSelectionImage(False)
924 QApplication.clipboard().setImage(img) 958 QApplication.clipboard().setImage(img)
925 959
926 def editCut(self): 960 def editCut(self):
927 """ 961 """
928 Public slot to cut the selection. 962 Public slot to cut the selection.
929 """ 963 """
930 if self.__selRect.isValid(): 964 if self.__selRect.isValid():
931 img = self.__getSelectionImage(True) 965 img = self.__getSelectionImage(True)
932 QApplication.clipboard().setImage(img) 966 QApplication.clipboard().setImage(img)
933 967
934 @pyqtSlot() 968 @pyqtSlot()
935 def editPaste(self, pasting=False): 969 def editPaste(self, pasting=False):
936 """ 970 """
937 Public slot to paste an image from the clipboard. 971 Public slot to paste an image from the clipboard.
938 972
939 @param pasting flag indicating part two of the paste operation 973 @param pasting flag indicating part two of the paste operation
940 (boolean) 974 (boolean)
941 """ 975 """
942 img, ok = self.__clipboardImage() 976 img, ok = self.__clipboardImage()
943 if ok: 977 if ok:
944 if ( 978 if (
945 img.width() > self.__image.width() or 979 img.width() > self.__image.width()
946 img.height() > self.__image.height() 980 or img.height() > self.__image.height()
947 ): 981 ):
948 res = EricMessageBox.yesNo( 982 res = EricMessageBox.yesNo(
949 self, 983 self,
950 self.tr("Paste"), 984 self.tr("Paste"),
951 self.tr( 985 self.tr(
952 """<p>The clipboard image is larger than the""" 986 """<p>The clipboard image is larger than the"""
953 """ current image.<br/>Paste as new image?</p>""")) 987 """ current image.<br/>Paste as new image?</p>"""
988 ),
989 )
954 if res: 990 if res:
955 self.editPasteAsNew() 991 self.editPasteAsNew()
956 return 992 return
957 elif not pasting: 993 elif not pasting:
958 self.__isPasting = True 994 self.__isPasting = True
959 self.__clipboardSize = img.size() 995 self.__clipboardSize = img.size()
960 else: 996 else:
961 cmd = IconEditCommand(self, self.tr("Paste Clipboard"), 997 cmd = IconEditCommand(self, self.tr("Paste Clipboard"), self.__image)
962 self.__image)
963 self.__markImage.fill(self.NoMarkColor.rgba()) 998 self.__markImage.fill(self.NoMarkColor.rgba())
964 painter = QPainter(self.__image) 999 painter = QPainter(self.__image)
965 painter.setPen(self.penColor()) 1000 painter.setPen(self.penColor())
966 painter.setCompositionMode(self.__compositingMode) 1001 painter.setCompositionMode(self.__compositingMode)
967 painter.drawImage( 1002 painter.drawImage(
968 self.__pasteRect.x(), self.__pasteRect.y(), img, 0, 0, 1003 self.__pasteRect.x(),
1004 self.__pasteRect.y(),
1005 img,
1006 0,
1007 0,
969 self.__pasteRect.width() + 1, 1008 self.__pasteRect.width() + 1,
970 self.__pasteRect.height() + 1) 1009 self.__pasteRect.height() + 1,
971 1010 )
1011
972 self.__undoStack.push(cmd) 1012 self.__undoStack.push(cmd)
973 cmd.setAfterImage(self.__image) 1013 cmd.setAfterImage(self.__image)
974 1014
975 self.__updateImageRect( 1015 self.__updateImageRect(
976 self.__pasteRect.topLeft(), 1016 self.__pasteRect.topLeft(),
977 self.__pasteRect.bottomRight() + QPoint(1, 1)) 1017 self.__pasteRect.bottomRight() + QPoint(1, 1),
1018 )
978 else: 1019 else:
979 EricMessageBox.warning( 1020 EricMessageBox.warning(
980 self, 1021 self,
981 self.tr("Pasting Image"), 1022 self.tr("Pasting Image"),
982 self.tr("""Invalid image data in clipboard.""")) 1023 self.tr("""Invalid image data in clipboard."""),
983 1024 )
1025
984 def editPasteAsNew(self): 1026 def editPasteAsNew(self):
985 """ 1027 """
986 Public slot to paste the clipboard as a new image. 1028 Public slot to paste the clipboard as a new image.
987 """ 1029 """
988 img, ok = self.__clipboardImage() 1030 img, ok = self.__clipboardImage()
989 if ok: 1031 if ok:
990 cmd = IconEditCommand( 1032 cmd = IconEditCommand(
991 self, self.tr("Paste Clipboard as New Image"), 1033 self, self.tr("Paste Clipboard as New Image"), self.__image
992 self.__image) 1034 )
993 self.setIconImage(img) 1035 self.setIconImage(img)
994 self.setDirty(True) 1036 self.setDirty(True)
995 self.__undoStack.push(cmd) 1037 self.__undoStack.push(cmd)
996 cmd.setAfterImage(self.__image) 1038 cmd.setAfterImage(self.__image)
997 1039
998 def editSelectAll(self): 1040 def editSelectAll(self):
999 """ 1041 """
1000 Public slot to select the complete image. 1042 Public slot to select the complete image.
1001 """ 1043 """
1002 self.__unMark() 1044 self.__unMark()
1003 1045
1004 self.__startPos = QPoint(0, 0) 1046 self.__startPos = QPoint(0, 0)
1005 self.__endPos = QPoint(self.rect().bottomRight()) 1047 self.__endPos = QPoint(self.rect().bottomRight())
1006 self.__markImage.fill(self.MarkColor.rgba()) 1048 self.__markImage.fill(self.MarkColor.rgba())
1007 self.__selRect = self.__image.rect() 1049 self.__selRect = self.__image.rect()
1008 self.__selectionAvailable = True 1050 self.__selectionAvailable = True
1009 self.selectionAvailable.emit(True) 1051 self.selectionAvailable.emit(True)
1010 1052
1011 self.update() 1053 self.update()
1012 1054
1013 def editClear(self): 1055 def editClear(self):
1014 """ 1056 """
1015 Public slot to clear the image. 1057 Public slot to clear the image.
1016 """ 1058 """
1017 self.__unMark() 1059 self.__unMark()
1018 1060
1019 cmd = IconEditCommand(self, self.tr("Clear Image"), self.__image) 1061 cmd = IconEditCommand(self, self.tr("Clear Image"), self.__image)
1020 self.__image.fill(Qt.GlobalColor.transparent) 1062 self.__image.fill(Qt.GlobalColor.transparent)
1021 self.update() 1063 self.update()
1022 self.setDirty(True) 1064 self.setDirty(True)
1023 self.__undoStack.push(cmd) 1065 self.__undoStack.push(cmd)
1024 cmd.setAfterImage(self.__image) 1066 cmd.setAfterImage(self.__image)
1025 1067
1026 def editResize(self): 1068 def editResize(self):
1027 """ 1069 """
1028 Public slot to resize the image. 1070 Public slot to resize the image.
1029 """ 1071 """
1030 from .IconSizeDialog import IconSizeDialog 1072 from .IconSizeDialog import IconSizeDialog
1073
1031 dlg = IconSizeDialog(self.__image.width(), self.__image.height()) 1074 dlg = IconSizeDialog(self.__image.width(), self.__image.height())
1032 res = dlg.exec() 1075 res = dlg.exec()
1033 if res == QDialog.DialogCode.Accepted: 1076 if res == QDialog.DialogCode.Accepted:
1034 newWidth, newHeight = dlg.getData() 1077 newWidth, newHeight = dlg.getData()
1035 if ( 1078 if newWidth != self.__image.width() or newHeight != self.__image.height():
1036 newWidth != self.__image.width() or 1079 cmd = IconEditCommand(self, self.tr("Resize Image"), self.__image)
1037 newHeight != self.__image.height()
1038 ):
1039 cmd = IconEditCommand(self, self.tr("Resize Image"),
1040 self.__image)
1041 img = self.__image.scaled( 1080 img = self.__image.scaled(
1042 newWidth, newHeight, Qt.AspectRatioMode.IgnoreAspectRatio, 1081 newWidth,
1043 Qt.TransformationMode.SmoothTransformation) 1082 newHeight,
1083 Qt.AspectRatioMode.IgnoreAspectRatio,
1084 Qt.TransformationMode.SmoothTransformation,
1085 )
1044 self.setIconImage(img) 1086 self.setIconImage(img)
1045 self.setDirty(True) 1087 self.setDirty(True)
1046 self.__undoStack.push(cmd) 1088 self.__undoStack.push(cmd)
1047 cmd.setAfterImage(self.__image) 1089 cmd.setAfterImage(self.__image)
1048 1090
1049 def editNew(self): 1091 def editNew(self):
1050 """ 1092 """
1051 Public slot to generate a new, empty image. 1093 Public slot to generate a new, empty image.
1052 """ 1094 """
1053 from .IconSizeDialog import IconSizeDialog 1095 from .IconSizeDialog import IconSizeDialog
1096
1054 dlg = IconSizeDialog(self.__image.width(), self.__image.height()) 1097 dlg = IconSizeDialog(self.__image.width(), self.__image.height())
1055 res = dlg.exec() 1098 res = dlg.exec()
1056 if res == QDialog.DialogCode.Accepted: 1099 if res == QDialog.DialogCode.Accepted:
1057 width, height = dlg.getData() 1100 width, height = dlg.getData()
1058 img = QImage(width, height, QImage.Format.Format_ARGB32) 1101 img = QImage(width, height, QImage.Format.Format_ARGB32)
1059 img.fill(Qt.GlobalColor.transparent) 1102 img.fill(Qt.GlobalColor.transparent)
1060 self.setIconImage(img) 1103 self.setIconImage(img)
1061 1104
1062 def grayScale(self): 1105 def grayScale(self):
1063 """ 1106 """
1064 Public slot to convert the image to gray preserving transparency. 1107 Public slot to convert the image to gray preserving transparency.
1065 """ 1108 """
1066 cmd = IconEditCommand(self, self.tr("Convert to Grayscale"), 1109 cmd = IconEditCommand(self, self.tr("Convert to Grayscale"), self.__image)
1067 self.__image)
1068 for x in range(self.__image.width()): 1110 for x in range(self.__image.width()):
1069 for y in range(self.__image.height()): 1111 for y in range(self.__image.height()):
1070 col = self.__image.pixel(x, y) 1112 col = self.__image.pixel(x, y)
1071 if col != qRgba(0, 0, 0, 0): 1113 if col != qRgba(0, 0, 0, 0):
1072 gray = qGray(col) 1114 gray = qGray(col)
1073 self.__image.setPixel( 1115 self.__image.setPixel(x, y, qRgba(gray, gray, gray, qAlpha(col)))
1074 x, y, qRgba(gray, gray, gray, qAlpha(col)))
1075 self.update() 1116 self.update()
1076 self.setDirty(True) 1117 self.setDirty(True)
1077 self.__undoStack.push(cmd) 1118 self.__undoStack.push(cmd)
1078 cmd.setAfterImage(self.__image) 1119 cmd.setAfterImage(self.__image)
1079 1120
1081 """ 1122 """
1082 Public slot to perform an undo operation. 1123 Public slot to perform an undo operation.
1083 """ 1124 """
1084 if self.__undoStack.canUndo(): 1125 if self.__undoStack.canUndo():
1085 self.__undoStack.undo() 1126 self.__undoStack.undo()
1086 1127
1087 def editRedo(self): 1128 def editRedo(self):
1088 """ 1129 """
1089 Public slot to perform a redo operation. 1130 Public slot to perform a redo operation.
1090 """ 1131 """
1091 if self.__undoStack.canRedo(): 1132 if self.__undoStack.canRedo():
1092 self.__undoStack.redo() 1133 self.__undoStack.redo()
1093 1134
1094 def canUndo(self): 1135 def canUndo(self):
1095 """ 1136 """
1096 Public method to return the undo status. 1137 Public method to return the undo status.
1097 1138
1098 @return flag indicating the availability of undo (boolean) 1139 @return flag indicating the availability of undo (boolean)
1099 """ 1140 """
1100 return self.__undoStack.canUndo() 1141 return self.__undoStack.canUndo()
1101 1142
1102 def canRedo(self): 1143 def canRedo(self):
1103 """ 1144 """
1104 Public method to return the redo status. 1145 Public method to return the redo status.
1105 1146
1106 @return flag indicating the availability of redo (boolean) 1147 @return flag indicating the availability of redo (boolean)
1107 """ 1148 """
1108 return self.__undoStack.canRedo() 1149 return self.__undoStack.canRedo()
1109 1150
1110 def __cleanChanged(self, clean): 1151 def __cleanChanged(self, clean):
1111 """ 1152 """
1112 Private slot to handle the undo stack clean state change. 1153 Private slot to handle the undo stack clean state change.
1113 1154
1114 @param clean flag indicating the clean state (boolean) 1155 @param clean flag indicating the clean state (boolean)
1115 """ 1156 """
1116 self.setDirty(not clean) 1157 self.setDirty(not clean)
1117 1158
1118 def shutdown(self): 1159 def shutdown(self):
1119 """ 1160 """
1120 Public slot to perform some shutdown actions. 1161 Public slot to perform some shutdown actions.
1121 """ 1162 """
1122 self.__undoStack.canRedoChanged.disconnect(self.canRedoChanged) 1163 self.__undoStack.canRedoChanged.disconnect(self.canRedoChanged)
1123 self.__undoStack.canUndoChanged.disconnect(self.canUndoChanged) 1164 self.__undoStack.canUndoChanged.disconnect(self.canUndoChanged)
1124 self.__undoStack.cleanChanged.disconnect(self.__cleanChanged) 1165 self.__undoStack.cleanChanged.disconnect(self.__cleanChanged)
1125 1166
1126 def isSelectionAvailable(self): 1167 def isSelectionAvailable(self):
1127 """ 1168 """
1128 Public method to check the availability of a selection. 1169 Public method to check the availability of a selection.
1129 1170
1130 @return flag indicating the availability of a selection (boolean) 1171 @return flag indicating the availability of a selection (boolean)
1131 """ 1172 """
1132 return self.__selectionAvailable 1173 return self.__selectionAvailable

eric ide

mercurial