src/eric7/IconEditor/IconEditorWindow.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 9162
8b75b1668583
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the icon editor main window.
8 """
9
10 import os
11 import contextlib
12 import pathlib
13
14 from PyQt6.QtCore import pyqtSignal, Qt, QSize, QSignalMapper, QEvent
15 from PyQt6.QtGui import (
16 QPalette, QImage, QImageReader, QImageWriter, QKeySequence
17 )
18 from PyQt6.QtWidgets import QScrollArea, QLabel, QDockWidget, QWhatsThis
19
20 from EricGui.EricAction import EricAction, createActionGroup
21 from EricWidgets import EricFileDialog, EricMessageBox
22 from EricWidgets.EricMainWindow import EricMainWindow
23 from EricWidgets.EricZoomWidget import EricZoomWidget
24
25 from .IconEditorGrid import IconEditorGrid, IconEditorTool
26
27 import UI.PixmapCache
28 import UI.Config
29
30 import Preferences
31
32
33 class IconEditorWindow(EricMainWindow):
34 """
35 Class implementing the web browser main window.
36
37 @signal editorClosed() emitted after the window was requested to close down
38 """
39 editorClosed = pyqtSignal()
40
41 windows = []
42
43 def __init__(self, fileName="", parent=None, fromEric=False,
44 initShortcutsOnly=False, project=None):
45 """
46 Constructor
47
48 @param fileName name of a file to load on startup (string)
49 @param parent parent widget of this window (QWidget)
50 @param fromEric flag indicating whether it was called from within
51 eric (boolean)
52 @param initShortcutsOnly flag indicating to just initialize the
53 keyboard shortcuts (boolean)
54 @param project reference to the project object (Project)
55 """
56 super().__init__(parent)
57 self.setObjectName("eric7_icon_editor")
58
59 self.fromEric = fromEric
60 self.initShortcutsOnly = initShortcutsOnly
61 self.setWindowIcon(UI.PixmapCache.getIcon("iconEditor"))
62
63 if self.initShortcutsOnly:
64 self.__initActions()
65 else:
66 if not self.fromEric:
67 self.setStyle(Preferences.getUI("Style"),
68 Preferences.getUI("StyleSheet"))
69 self.__editor = IconEditorGrid()
70 self.__scrollArea = QScrollArea()
71 self.__scrollArea.setWidget(self.__editor)
72 self.__scrollArea.viewport().setBackgroundRole(
73 QPalette.ColorRole.Dark)
74 self.__scrollArea.viewport().setAutoFillBackground(True)
75 self.setCentralWidget(self.__scrollArea)
76
77 g = Preferences.getGeometry("IconEditorGeometry")
78 if g.isEmpty():
79 s = QSize(600, 500)
80 self.resize(s)
81 else:
82 self.restoreGeometry(g)
83
84 self.__initActions()
85 self.__initMenus()
86 self.__initToolbars()
87 self.__createStatusBar()
88 self.__initFileFilters()
89 self.__createPaletteDock()
90
91 self.__palette.previewChanged(self.__editor.previewPixmap())
92 self.__palette.colorChanged(self.__editor.penColor())
93 self.__palette.setCompositingMode(self.__editor.compositingMode())
94
95 self.__class__.windows.append(self)
96
97 state = Preferences.getIconEditor("IconEditorState")
98 self.restoreState(state)
99
100 self.__editor.imageChanged.connect(self.__modificationChanged)
101 self.__editor.positionChanged.connect(self.__updatePosition)
102 self.__editor.sizeChanged.connect(self.__updateSize)
103 self.__editor.previewChanged.connect(self.__palette.previewChanged)
104 self.__editor.colorChanged.connect(self.__palette.colorChanged)
105 self.__palette.colorSelected.connect(self.__editor.setPenColor)
106 self.__palette.compositingChanged.connect(
107 self.__editor.setCompositingMode)
108
109 self.__setCurrentFile("")
110 if fileName:
111 self.__loadIconFile(fileName)
112
113 self.__checkActions()
114
115 self.__project = project
116 self.__lastOpenPath = ""
117 self.__lastSavePath = ""
118
119 self.grabGesture(Qt.GestureType.PinchGesture)
120
121 def __initFileFilters(self):
122 """
123 Private method to define the supported image file filters.
124 """
125 filters = {
126 'bmp': self.tr("Windows Bitmap File (*.bmp)"),
127 'cur': self.tr("Windows Cursor File (*.cur)"),
128 'dds': self.tr("DirectDraw-Surface File (*.dds)"),
129 'gif': self.tr("Graphic Interchange Format File (*.gif)"),
130 'icns': self.tr("Apple Icon File (*.icns)"),
131 'ico': self.tr("Windows Icon File (*.ico)"),
132 'jp2': self.tr("JPEG2000 File (*.jp2)"),
133 'jpg': self.tr("JPEG File (*.jpg)"),
134 'jpeg': self.tr("JPEG File (*.jpeg)"),
135 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"),
136 'pbm': self.tr("Portable Bitmap File (*.pbm)"),
137 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"),
138 'pgm': self.tr("Portable Graymap File (*.pgm)"),
139 'png': self.tr("Portable Network Graphics File (*.png)"),
140 'ppm': self.tr("Portable Pixmap File (*.ppm)"),
141 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"),
142 'svg': self.tr("Scalable Vector Graphics File (*.svg)"),
143 'svgz': self.tr("Compressed Scalable Vector Graphics File"
144 " (*.svgz)"),
145 'tga': self.tr("Targa Graphic File (*.tga)"),
146 'tif': self.tr("TIFF File (*.tif)"),
147 'tiff': self.tr("TIFF File (*.tiff)"),
148 'wbmp': self.tr("WAP Bitmap File (*.wbmp)"),
149 'webp': self.tr("WebP Image File (*.webp)"),
150 'xbm': self.tr("X11 Bitmap File (*.xbm)"),
151 'xpm': self.tr("X11 Pixmap File (*.xpm)"),
152 }
153
154 inputFormats = []
155 readFormats = QImageReader.supportedImageFormats()
156 for readFormat in readFormats:
157 with contextlib.suppress(KeyError):
158 inputFormats.append(filters[bytes(readFormat).decode()])
159 inputFormats.sort()
160 inputFormats.append(self.tr("All Files (*)"))
161 self.__inputFilter = ';;'.join(inputFormats)
162
163 outputFormats = []
164 writeFormats = QImageWriter.supportedImageFormats()
165 for writeFormat in writeFormats:
166 with contextlib.suppress(KeyError):
167 outputFormats.append(filters[bytes(writeFormat).decode()])
168 outputFormats.sort()
169 self.__outputFilter = ';;'.join(outputFormats)
170
171 self.__defaultFilter = filters['png']
172
173 def __initActions(self):
174 """
175 Private method to define the user interface actions.
176 """
177 # list of all actions
178 self.__actions = []
179
180 self.__initFileActions()
181 self.__initEditActions()
182 self.__initViewActions()
183 self.__initToolsActions()
184 self.__initHelpActions()
185
186 def __initFileActions(self):
187 """
188 Private method to define the file related user interface actions.
189 """
190 self.newAct = EricAction(
191 self.tr('New'),
192 UI.PixmapCache.getIcon("new"),
193 self.tr('&New'),
194 QKeySequence(self.tr("Ctrl+N", "File|New")),
195 0, self, 'iconEditor_file_new')
196 self.newAct.setStatusTip(self.tr('Create a new icon'))
197 self.newAct.setWhatsThis(self.tr(
198 """<b>New</b>"""
199 """<p>This creates a new icon.</p>"""
200 ))
201 self.newAct.triggered.connect(self.__newIcon)
202 self.__actions.append(self.newAct)
203
204 self.newWindowAct = EricAction(
205 self.tr('New Window'),
206 UI.PixmapCache.getIcon("newWindow"),
207 self.tr('New &Window'),
208 0, 0, self, 'iconEditor_file_new_window')
209 self.newWindowAct.setStatusTip(self.tr(
210 'Open a new icon editor window'))
211 self.newWindowAct.setWhatsThis(self.tr(
212 """<b>New Window</b>"""
213 """<p>This opens a new icon editor window.</p>"""
214 ))
215 self.newWindowAct.triggered.connect(self.__newWindow)
216 self.__actions.append(self.newWindowAct)
217
218 self.openAct = EricAction(
219 self.tr('Open'),
220 UI.PixmapCache.getIcon("open"),
221 self.tr('&Open...'),
222 QKeySequence(self.tr("Ctrl+O", "File|Open")),
223 0, self, 'iconEditor_file_open')
224 self.openAct.setStatusTip(self.tr('Open an icon file for editing'))
225 self.openAct.setWhatsThis(self.tr(
226 """<b>Open File</b>"""
227 """<p>This opens a new icon file for editing."""
228 """ It pops up a file selection dialog.</p>"""
229 ))
230 self.openAct.triggered.connect(self.__openIcon)
231 self.__actions.append(self.openAct)
232
233 self.saveAct = EricAction(
234 self.tr('Save'),
235 UI.PixmapCache.getIcon("fileSave"),
236 self.tr('&Save'),
237 QKeySequence(self.tr("Ctrl+S", "File|Save")),
238 0, self, 'iconEditor_file_save')
239 self.saveAct.setStatusTip(self.tr('Save the current icon'))
240 self.saveAct.setWhatsThis(self.tr(
241 """<b>Save File</b>"""
242 """<p>Save the contents of the icon editor window.</p>"""
243 ))
244 self.saveAct.triggered.connect(self.__saveIcon)
245 self.__actions.append(self.saveAct)
246
247 self.saveAsAct = EricAction(
248 self.tr('Save As'),
249 UI.PixmapCache.getIcon("fileSaveAs"),
250 self.tr('Save &As...'),
251 QKeySequence(self.tr("Shift+Ctrl+S", "File|Save As")),
252 0, self, 'iconEditor_file_save_as')
253 self.saveAsAct.setStatusTip(
254 self.tr('Save the current icon to a new file'))
255 self.saveAsAct.setWhatsThis(self.tr(
256 """<b>Save As...</b>"""
257 """<p>Saves the current icon to a new file.</p>"""
258 ))
259 self.saveAsAct.triggered.connect(self.__saveIconAs)
260 self.__actions.append(self.saveAsAct)
261
262 self.closeAct = EricAction(
263 self.tr('Close'),
264 UI.PixmapCache.getIcon("close"),
265 self.tr('&Close'),
266 QKeySequence(self.tr("Ctrl+W", "File|Close")),
267 0, self, 'iconEditor_file_close')
268 self.closeAct.setStatusTip(self.tr(
269 'Close the current icon editor window'))
270 self.closeAct.setWhatsThis(self.tr(
271 """<b>Close</b>"""
272 """<p>Closes the current icon editor window.</p>"""
273 ))
274 self.closeAct.triggered.connect(self.close)
275 self.__actions.append(self.closeAct)
276
277 self.closeAllAct = EricAction(
278 self.tr('Close All'),
279 self.tr('Close &All'),
280 0, 0, self, 'iconEditor_file_close_all')
281 self.closeAllAct.setStatusTip(self.tr(
282 'Close all icon editor windows'))
283 self.closeAllAct.setWhatsThis(self.tr(
284 """<b>Close All</b>"""
285 """<p>Closes all icon editor windows except the first one.</p>"""
286 ))
287 self.closeAllAct.triggered.connect(self.__closeAll)
288 self.__actions.append(self.closeAllAct)
289
290 self.closeOthersAct = EricAction(
291 self.tr('Close Others'),
292 self.tr('Close Others'),
293 0, 0, self, 'iconEditor_file_close_others')
294 self.closeOthersAct.setStatusTip(self.tr(
295 'Close all other icon editor windows'))
296 self.closeOthersAct.setWhatsThis(self.tr(
297 """<b>Close Others</b>"""
298 """<p>Closes all other icon editor windows.</p>"""
299 ))
300 self.closeOthersAct.triggered.connect(self.__closeOthers)
301 self.__actions.append(self.closeOthersAct)
302
303 self.exitAct = EricAction(
304 self.tr('Quit'),
305 UI.PixmapCache.getIcon("exit"),
306 self.tr('&Quit'),
307 QKeySequence(self.tr("Ctrl+Q", "File|Quit")),
308 0, self, 'iconEditor_file_quit')
309 self.exitAct.setStatusTip(self.tr('Quit the icon editor'))
310 self.exitAct.setWhatsThis(self.tr(
311 """<b>Quit</b>"""
312 """<p>Quit the icon editor.</p>"""
313 ))
314 if not self.fromEric:
315 self.exitAct.triggered.connect(self.__closeAll)
316 self.__actions.append(self.exitAct)
317
318 def __initEditActions(self):
319 """
320 Private method to create the Edit actions.
321 """
322 self.undoAct = EricAction(
323 self.tr('Undo'),
324 UI.PixmapCache.getIcon("editUndo"),
325 self.tr('&Undo'),
326 QKeySequence(self.tr("Ctrl+Z", "Edit|Undo")),
327 QKeySequence(self.tr("Alt+Backspace", "Edit|Undo")),
328 self, 'iconEditor_edit_undo')
329 self.undoAct.setStatusTip(self.tr('Undo the last change'))
330 self.undoAct.setWhatsThis(self.tr(
331 """<b>Undo</b>"""
332 """<p>Undo the last change done.</p>"""
333 ))
334 self.undoAct.triggered.connect(self.__editor.editUndo)
335 self.__actions.append(self.undoAct)
336
337 self.redoAct = EricAction(
338 self.tr('Redo'),
339 UI.PixmapCache.getIcon("editRedo"),
340 self.tr('&Redo'),
341 QKeySequence(self.tr("Ctrl+Shift+Z", "Edit|Redo")),
342 0, self, 'iconEditor_edit_redo')
343 self.redoAct.setStatusTip(self.tr('Redo the last change'))
344 self.redoAct.setWhatsThis(self.tr(
345 """<b>Redo</b>"""
346 """<p>Redo the last change done.</p>"""
347 ))
348 self.redoAct.triggered.connect(self.__editor.editRedo)
349 self.__actions.append(self.redoAct)
350
351 self.cutAct = EricAction(
352 self.tr('Cut'),
353 UI.PixmapCache.getIcon("editCut"),
354 self.tr('Cu&t'),
355 QKeySequence(self.tr("Ctrl+X", "Edit|Cut")),
356 QKeySequence(self.tr("Shift+Del", "Edit|Cut")),
357 self, 'iconEditor_edit_cut')
358 self.cutAct.setStatusTip(self.tr('Cut the selection'))
359 self.cutAct.setWhatsThis(self.tr(
360 """<b>Cut</b>"""
361 """<p>Cut the selected image area to the clipboard.</p>"""
362 ))
363 self.cutAct.triggered.connect(self.__editor.editCut)
364 self.__actions.append(self.cutAct)
365
366 self.copyAct = EricAction(
367 self.tr('Copy'),
368 UI.PixmapCache.getIcon("editCopy"),
369 self.tr('&Copy'),
370 QKeySequence(self.tr("Ctrl+C", "Edit|Copy")),
371 QKeySequence(self.tr("Ctrl+Ins", "Edit|Copy")),
372 self, 'iconEditor_edit_copy')
373 self.copyAct.setStatusTip(self.tr('Copy the selection'))
374 self.copyAct.setWhatsThis(self.tr(
375 """<b>Copy</b>"""
376 """<p>Copy the selected image area to the clipboard.</p>"""
377 ))
378 self.copyAct.triggered.connect(self.__editor.editCopy)
379 self.__actions.append(self.copyAct)
380
381 self.pasteAct = EricAction(
382 self.tr('Paste'),
383 UI.PixmapCache.getIcon("editPaste"),
384 self.tr('&Paste'),
385 QKeySequence(self.tr("Ctrl+V", "Edit|Paste")),
386 QKeySequence(self.tr("Shift+Ins", "Edit|Paste")),
387 self, 'iconEditor_edit_paste')
388 self.pasteAct.setStatusTip(self.tr('Paste the clipboard image'))
389 self.pasteAct.setWhatsThis(self.tr(
390 """<b>Paste</b>"""
391 """<p>Paste the clipboard image.</p>"""
392 ))
393 self.pasteAct.triggered.connect(self.__editor.editPaste)
394 self.__actions.append(self.pasteAct)
395
396 self.pasteNewAct = EricAction(
397 self.tr('Paste as New'),
398 self.tr('Paste as &New'),
399 0, 0, self, 'iconEditor_edit_paste_as_new')
400 self.pasteNewAct.setStatusTip(self.tr(
401 'Paste the clipboard image replacing the current one'))
402 self.pasteNewAct.setWhatsThis(self.tr(
403 """<b>Paste as New</b>"""
404 """<p>Paste the clipboard image replacing the current one.</p>"""
405 ))
406 self.pasteNewAct.triggered.connect(self.__editor.editPasteAsNew)
407 self.__actions.append(self.pasteNewAct)
408
409 self.deleteAct = EricAction(
410 self.tr('Clear'),
411 UI.PixmapCache.getIcon("editDelete"),
412 self.tr('Cl&ear'),
413 QKeySequence(self.tr("Alt+Shift+C", "Edit|Clear")),
414 0,
415 self, 'iconEditor_edit_clear')
416 self.deleteAct.setStatusTip(self.tr('Clear the icon image'))
417 self.deleteAct.setWhatsThis(self.tr(
418 """<b>Clear</b>"""
419 """<p>Clear the icon image and set it to be completely"""
420 """ transparent.</p>"""
421 ))
422 self.deleteAct.triggered.connect(self.__editor.editClear)
423 self.__actions.append(self.deleteAct)
424
425 self.selectAllAct = EricAction(
426 self.tr('Select All'),
427 self.tr('&Select All'),
428 QKeySequence(self.tr("Ctrl+A", "Edit|Select All")),
429 0,
430 self, 'iconEditor_edit_select_all')
431 self.selectAllAct.setStatusTip(self.tr(
432 'Select the complete icon image'))
433 self.selectAllAct.setWhatsThis(self.tr(
434 """<b>Select All</b>"""
435 """<p>Selects the complete icon image.</p>"""
436 ))
437 self.selectAllAct.triggered.connect(self.__editor.editSelectAll)
438 self.__actions.append(self.selectAllAct)
439
440 self.resizeAct = EricAction(
441 self.tr('Change Size'),
442 UI.PixmapCache.getIcon("transformResize"),
443 self.tr('Change Si&ze...'),
444 0, 0,
445 self, 'iconEditor_edit_change_size')
446 self.resizeAct.setStatusTip(self.tr('Change the icon size'))
447 self.resizeAct.setWhatsThis(self.tr(
448 """<b>Change Size...</b>"""
449 """<p>Changes the icon size.</p>"""
450 ))
451 self.resizeAct.triggered.connect(self.__editor.editResize)
452 self.__actions.append(self.resizeAct)
453
454 self.grayscaleAct = EricAction(
455 self.tr('Grayscale'),
456 UI.PixmapCache.getIcon("grayscale"),
457 self.tr('&Grayscale'),
458 0, 0,
459 self, 'iconEditor_edit_grayscale')
460 self.grayscaleAct.setStatusTip(self.tr(
461 'Change the icon to grayscale'))
462 self.grayscaleAct.setWhatsThis(self.tr(
463 """<b>Grayscale</b>"""
464 """<p>Changes the icon to grayscale.</p>"""
465 ))
466 self.grayscaleAct.triggered.connect(self.__editor.grayScale)
467 self.__actions.append(self.grayscaleAct)
468
469 self.redoAct.setEnabled(False)
470 self.__editor.canRedoChanged.connect(self.redoAct.setEnabled)
471
472 self.undoAct.setEnabled(False)
473 self.__editor.canUndoChanged.connect(self.undoAct.setEnabled)
474
475 self.cutAct.setEnabled(False)
476 self.copyAct.setEnabled(False)
477 self.__editor.selectionAvailable.connect(self.cutAct.setEnabled)
478 self.__editor.selectionAvailable.connect(self.copyAct.setEnabled)
479
480 self.pasteAct.setEnabled(self.__editor.canPaste())
481 self.pasteNewAct.setEnabled(self.__editor.canPaste())
482 self.__editor.clipboardImageAvailable.connect(
483 self.pasteAct.setEnabled)
484 self.__editor.clipboardImageAvailable.connect(
485 self.pasteNewAct.setEnabled)
486
487 def __initViewActions(self):
488 """
489 Private method to create the View actions.
490 """
491 self.zoomInAct = EricAction(
492 self.tr('Zoom in'),
493 UI.PixmapCache.getIcon("zoomIn"),
494 self.tr('Zoom &in'),
495 QKeySequence(self.tr("Ctrl++", "View|Zoom in")),
496 0, self, 'iconEditor_view_zoom_in')
497 self.zoomInAct.setStatusTip(self.tr('Zoom in on the icon'))
498 self.zoomInAct.setWhatsThis(self.tr(
499 """<b>Zoom in</b>"""
500 """<p>Zoom in on the icon. This makes the grid bigger.</p>"""
501 ))
502 self.zoomInAct.triggered.connect(self.__zoomIn)
503 self.__actions.append(self.zoomInAct)
504
505 self.zoomOutAct = EricAction(
506 self.tr('Zoom out'),
507 UI.PixmapCache.getIcon("zoomOut"),
508 self.tr('Zoom &out'),
509 QKeySequence(self.tr("Ctrl+-", "View|Zoom out")),
510 0, self, 'iconEditor_view_zoom_out')
511 self.zoomOutAct.setStatusTip(self.tr('Zoom out on the icon'))
512 self.zoomOutAct.setWhatsThis(self.tr(
513 """<b>Zoom out</b>"""
514 """<p>Zoom out on the icon. This makes the grid smaller.</p>"""
515 ))
516 self.zoomOutAct.triggered.connect(self.__zoomOut)
517 self.__actions.append(self.zoomOutAct)
518
519 self.zoomResetAct = EricAction(
520 self.tr('Zoom reset'),
521 UI.PixmapCache.getIcon("zoomReset"),
522 self.tr('Zoom &reset'),
523 QKeySequence(self.tr("Ctrl+0", "View|Zoom reset")),
524 0, self, 'iconEditor_view_zoom_reset')
525 self.zoomResetAct.setStatusTip(self.tr(
526 'Reset the zoom of the icon'))
527 self.zoomResetAct.setWhatsThis(self.tr(
528 """<b>Zoom reset</b>"""
529 """<p>Reset the zoom of the icon. """
530 """This sets the zoom factor to 100%.</p>"""
531 ))
532 self.zoomResetAct.triggered.connect(self.__zoomReset)
533 self.__actions.append(self.zoomResetAct)
534
535 self.showGridAct = EricAction(
536 self.tr('Show Grid'),
537 UI.PixmapCache.getIcon("grid"),
538 self.tr('Show &Grid'),
539 0, 0,
540 self, 'iconEditor_view_show_grid')
541 self.showGridAct.setStatusTip(self.tr(
542 'Toggle the display of the grid'))
543 self.showGridAct.setWhatsThis(self.tr(
544 """<b>Show Grid</b>"""
545 """<p>Toggle the display of the grid.</p>"""
546 ))
547 self.showGridAct.triggered[bool].connect(self.__editor.setGridEnabled)
548 self.__actions.append(self.showGridAct)
549 self.showGridAct.setCheckable(True)
550 self.showGridAct.setChecked(self.__editor.isGridEnabled())
551
552 def __initToolsActions(self):
553 """
554 Private method to create the View actions.
555 """
556 self.esm = QSignalMapper(self)
557 self.esm.mappedInt.connect(self.__editor.setTool)
558
559 self.drawingActGrp = createActionGroup(self)
560 self.drawingActGrp.setExclusive(True)
561
562 self.drawPencilAct = EricAction(
563 self.tr('Freehand'),
564 UI.PixmapCache.getIcon("drawBrush"),
565 self.tr('&Freehand'),
566 0, 0,
567 self.drawingActGrp, 'iconEditor_tools_pencil')
568 self.drawPencilAct.setWhatsThis(self.tr(
569 """<b>Free hand</b>"""
570 """<p>Draws non linear lines.</p>"""
571 ))
572 self.drawPencilAct.setCheckable(True)
573 self.esm.setMapping(self.drawPencilAct, IconEditorTool.PENCIL)
574 self.drawPencilAct.triggered.connect(self.esm.map)
575 self.__actions.append(self.drawPencilAct)
576
577 self.drawColorPickerAct = EricAction(
578 self.tr('Color Picker'),
579 UI.PixmapCache.getIcon("colorPicker"),
580 self.tr('&Color Picker'),
581 0, 0,
582 self.drawingActGrp, 'iconEditor_tools_color_picker')
583 self.drawColorPickerAct.setWhatsThis(self.tr(
584 """<b>Color Picker</b>"""
585 """<p>The color of the pixel clicked on will become """
586 """the current draw color.</p>"""
587 ))
588 self.drawColorPickerAct.setCheckable(True)
589 self.esm.setMapping(self.drawColorPickerAct,
590 IconEditorTool.COLOR_PICKER)
591 self.drawColorPickerAct.triggered.connect(self.esm.map)
592 self.__actions.append(self.drawColorPickerAct)
593
594 self.drawRectangleAct = EricAction(
595 self.tr('Rectangle'),
596 UI.PixmapCache.getIcon("drawRectangle"),
597 self.tr('&Rectangle'),
598 0, 0,
599 self.drawingActGrp, 'iconEditor_tools_rectangle')
600 self.drawRectangleAct.setWhatsThis(self.tr(
601 """<b>Rectangle</b>"""
602 """<p>Draw a rectangle.</p>"""
603 ))
604 self.drawRectangleAct.setCheckable(True)
605 self.esm.setMapping(self.drawRectangleAct, IconEditorTool.RECTANGLE)
606 self.drawRectangleAct.triggered.connect(self.esm.map)
607 self.__actions.append(self.drawRectangleAct)
608
609 self.drawFilledRectangleAct = EricAction(
610 self.tr('Filled Rectangle'),
611 UI.PixmapCache.getIcon("drawRectangleFilled"),
612 self.tr('F&illed Rectangle'),
613 0, 0,
614 self.drawingActGrp, 'iconEditor_tools_filled_rectangle')
615 self.drawFilledRectangleAct.setWhatsThis(self.tr(
616 """<b>Filled Rectangle</b>"""
617 """<p>Draw a filled rectangle.</p>"""
618 ))
619 self.drawFilledRectangleAct.setCheckable(True)
620 self.esm.setMapping(self.drawFilledRectangleAct,
621 IconEditorTool.FILLED_RECTANGLE)
622 self.drawFilledRectangleAct.triggered.connect(self.esm.map)
623 self.__actions.append(self.drawFilledRectangleAct)
624
625 self.drawCircleAct = EricAction(
626 self.tr('Circle'),
627 UI.PixmapCache.getIcon("drawCircle"),
628 self.tr('Circle'),
629 0, 0,
630 self.drawingActGrp, 'iconEditor_tools_circle')
631 self.drawCircleAct.setWhatsThis(self.tr(
632 """<b>Circle</b>"""
633 """<p>Draw a circle.</p>"""
634 ))
635 self.drawCircleAct.setCheckable(True)
636 self.esm.setMapping(self.drawCircleAct, IconEditorTool.CIRCLE)
637 self.drawCircleAct.triggered.connect(self.esm.map)
638 self.__actions.append(self.drawCircleAct)
639
640 self.drawFilledCircleAct = EricAction(
641 self.tr('Filled Circle'),
642 UI.PixmapCache.getIcon("drawCircleFilled"),
643 self.tr('Fille&d Circle'),
644 0, 0,
645 self.drawingActGrp, 'iconEditor_tools_filled_circle')
646 self.drawFilledCircleAct.setWhatsThis(self.tr(
647 """<b>Filled Circle</b>"""
648 """<p>Draw a filled circle.</p>"""
649 ))
650 self.drawFilledCircleAct.setCheckable(True)
651 self.esm.setMapping(self.drawFilledCircleAct,
652 IconEditorTool.FILLED_CIRCLE)
653 self.drawFilledCircleAct.triggered.connect(self.esm.map)
654 self.__actions.append(self.drawFilledCircleAct)
655
656 self.drawEllipseAct = EricAction(
657 self.tr('Ellipse'),
658 UI.PixmapCache.getIcon("drawEllipse"),
659 self.tr('&Ellipse'),
660 0, 0,
661 self.drawingActGrp, 'iconEditor_tools_ellipse')
662 self.drawEllipseAct.setWhatsThis(self.tr(
663 """<b>Ellipse</b>"""
664 """<p>Draw an ellipse.</p>"""
665 ))
666 self.drawEllipseAct.setCheckable(True)
667 self.esm.setMapping(self.drawEllipseAct, IconEditorTool.ELLIPSE)
668 self.drawEllipseAct.triggered.connect(self.esm.map)
669 self.__actions.append(self.drawEllipseAct)
670
671 self.drawFilledEllipseAct = EricAction(
672 self.tr('Filled Ellipse'),
673 UI.PixmapCache.getIcon("drawEllipseFilled"),
674 self.tr('Fille&d Elli&pse'),
675 0, 0,
676 self.drawingActGrp, 'iconEditor_tools_filled_ellipse')
677 self.drawFilledEllipseAct.setWhatsThis(self.tr(
678 """<b>Filled Ellipse</b>"""
679 """<p>Draw a filled ellipse.</p>"""
680 ))
681 self.drawFilledEllipseAct.setCheckable(True)
682 self.esm.setMapping(self.drawFilledEllipseAct,
683 IconEditorTool.FILLED_ELLIPSE)
684 self.drawFilledEllipseAct.triggered.connect(self.esm.map)
685 self.__actions.append(self.drawFilledEllipseAct)
686
687 self.drawFloodFillAct = EricAction(
688 self.tr('Flood Fill'),
689 UI.PixmapCache.getIcon("drawFill"),
690 self.tr('Fl&ood Fill'),
691 0, 0,
692 self.drawingActGrp, 'iconEditor_tools_flood_fill')
693 self.drawFloodFillAct.setWhatsThis(self.tr(
694 """<b>Flood Fill</b>"""
695 """<p>Fill adjoining pixels with the same color with """
696 """the current color.</p>"""
697 ))
698 self.drawFloodFillAct.setCheckable(True)
699 self.esm.setMapping(self.drawFloodFillAct, IconEditorTool.FILL)
700 self.drawFloodFillAct.triggered.connect(self.esm.map)
701 self.__actions.append(self.drawFloodFillAct)
702
703 self.drawLineAct = EricAction(
704 self.tr('Line'),
705 UI.PixmapCache.getIcon("drawLine"),
706 self.tr('&Line'),
707 0, 0,
708 self.drawingActGrp, 'iconEditor_tools_line')
709 self.drawLineAct.setWhatsThis(self.tr(
710 """<b>Line</b>"""
711 """<p>Draw a line.</p>"""
712 ))
713 self.drawLineAct.setCheckable(True)
714 self.esm.setMapping(self.drawLineAct, IconEditorTool.LINE)
715 self.drawLineAct.triggered.connect(self.esm.map)
716 self.__actions.append(self.drawLineAct)
717
718 self.drawEraserAct = EricAction(
719 self.tr('Eraser (Transparent)'),
720 UI.PixmapCache.getIcon("drawEraser"),
721 self.tr('Eraser (&Transparent)'),
722 0, 0,
723 self.drawingActGrp, 'iconEditor_tools_eraser')
724 self.drawEraserAct.setWhatsThis(self.tr(
725 """<b>Eraser (Transparent)</b>"""
726 """<p>Erase pixels by setting them to transparent.</p>"""
727 ))
728 self.drawEraserAct.setCheckable(True)
729 self.esm.setMapping(self.drawEraserAct, IconEditorTool.RUBBER)
730 self.drawEraserAct.triggered.connect(self.esm.map)
731 self.__actions.append(self.drawEraserAct)
732
733 self.drawRectangleSelectionAct = EricAction(
734 self.tr('Rectangular Selection'),
735 UI.PixmapCache.getIcon("selectRectangle"),
736 self.tr('Rect&angular Selection'),
737 0, 0,
738 self.drawingActGrp, 'iconEditor_tools_selection_rectangle')
739 self.drawRectangleSelectionAct.setWhatsThis(self.tr(
740 """<b>Rectangular Selection</b>"""
741 """<p>Select a rectangular section of the icon using"""
742 """ the mouse.</p>"""
743 ))
744 self.drawRectangleSelectionAct.setCheckable(True)
745 self.esm.setMapping(self.drawRectangleSelectionAct,
746 IconEditorTool.SELECT_RECTANGLE)
747 self.drawRectangleSelectionAct.triggered.connect(self.esm.map)
748 self.__actions.append(self.drawRectangleSelectionAct)
749
750 self.drawCircleSelectionAct = EricAction(
751 self.tr('Circular Selection'),
752 UI.PixmapCache.getIcon("selectCircle"),
753 self.tr('Rect&angular Selection'),
754 0, 0,
755 self.drawingActGrp, 'iconEditor_tools_selection_circle')
756 self.drawCircleSelectionAct.setWhatsThis(self.tr(
757 """<b>Circular Selection</b>"""
758 """<p>Select a circular section of the icon using"""
759 """ the mouse.</p>"""
760 ))
761 self.drawCircleSelectionAct.setCheckable(True)
762 self.esm.setMapping(self.drawCircleSelectionAct,
763 IconEditorTool.SELECT_CIRCLE)
764 self.drawCircleSelectionAct.triggered.connect(self.esm.map)
765 self.__actions.append(self.drawCircleSelectionAct)
766
767 self.drawPencilAct.trigger()
768
769 def __initHelpActions(self):
770 """
771 Private method to create the Help actions.
772 """
773 self.aboutAct = EricAction(
774 self.tr('About'),
775 self.tr('&About'),
776 0, 0, self, 'iconEditor_help_about')
777 self.aboutAct.setStatusTip(self.tr(
778 'Display information about this software'))
779 self.aboutAct.setWhatsThis(self.tr(
780 """<b>About</b>"""
781 """<p>Display some information about this software.</p>"""))
782 self.aboutAct.triggered.connect(self.__about)
783 self.__actions.append(self.aboutAct)
784
785 self.aboutQtAct = EricAction(
786 self.tr('About Qt'),
787 self.tr('About &Qt'),
788 0, 0, self, 'iconEditor_help_about_qt')
789 self.aboutQtAct.setStatusTip(
790 self.tr('Display information about the Qt toolkit'))
791 self.aboutQtAct.setWhatsThis(self.tr(
792 """<b>About Qt</b>"""
793 """<p>Display some information about the Qt toolkit.</p>"""
794 ))
795 self.aboutQtAct.triggered.connect(self.__aboutQt)
796 self.__actions.append(self.aboutQtAct)
797
798 self.whatsThisAct = EricAction(
799 self.tr('What\'s This?'),
800 UI.PixmapCache.getIcon("whatsThis"),
801 self.tr('&What\'s This?'),
802 QKeySequence(self.tr("Shift+F1", "Help|What's This?'")),
803 0, self, 'iconEditor_help_whats_this')
804 self.whatsThisAct.setStatusTip(self.tr('Context sensitive help'))
805 self.whatsThisAct.setWhatsThis(self.tr(
806 """<b>Display context sensitive help</b>"""
807 """<p>In What's This? mode, the mouse cursor shows an arrow"""
808 """ with a question mark, and you can click on the interface"""
809 """ elements to get a short description of what they do and"""
810 """ how to use them. In dialogs, this feature can be accessed"""
811 """ using the context help button in the titlebar.</p>"""
812 ))
813 self.whatsThisAct.triggered.connect(self.__whatsThis)
814 self.__actions.append(self.whatsThisAct)
815
816 def __initMenus(self):
817 """
818 Private method to create the menus.
819 """
820 mb = self.menuBar()
821
822 menu = mb.addMenu(self.tr('&File'))
823 menu.setTearOffEnabled(True)
824 menu.addAction(self.newAct)
825 menu.addAction(self.newWindowAct)
826 menu.addAction(self.openAct)
827 menu.addSeparator()
828 menu.addAction(self.saveAct)
829 menu.addAction(self.saveAsAct)
830 menu.addSeparator()
831 menu.addAction(self.closeAct)
832 menu.addAction(self.closeOthersAct)
833 if self.fromEric:
834 menu.addAction(self.closeAllAct)
835 else:
836 menu.addSeparator()
837 menu.addAction(self.exitAct)
838
839 menu = mb.addMenu(self.tr("&Edit"))
840 menu.setTearOffEnabled(True)
841 menu.addAction(self.undoAct)
842 menu.addAction(self.redoAct)
843 menu.addSeparator()
844 menu.addAction(self.cutAct)
845 menu.addAction(self.copyAct)
846 menu.addAction(self.pasteAct)
847 menu.addAction(self.pasteNewAct)
848 menu.addAction(self.deleteAct)
849 menu.addSeparator()
850 menu.addAction(self.selectAllAct)
851 menu.addSeparator()
852 menu.addAction(self.resizeAct)
853 menu.addAction(self.grayscaleAct)
854
855 menu = mb.addMenu(self.tr('&View'))
856 menu.setTearOffEnabled(True)
857 menu.addAction(self.zoomInAct)
858 menu.addAction(self.zoomResetAct)
859 menu.addAction(self.zoomOutAct)
860 menu.addSeparator()
861 menu.addAction(self.showGridAct)
862
863 menu = mb.addMenu(self.tr('&Tools'))
864 menu.setTearOffEnabled(True)
865 menu.addAction(self.drawPencilAct)
866 menu.addAction(self.drawColorPickerAct)
867 menu.addAction(self.drawRectangleAct)
868 menu.addAction(self.drawFilledRectangleAct)
869 menu.addAction(self.drawCircleAct)
870 menu.addAction(self.drawFilledCircleAct)
871 menu.addAction(self.drawEllipseAct)
872 menu.addAction(self.drawFilledEllipseAct)
873 menu.addAction(self.drawFloodFillAct)
874 menu.addAction(self.drawLineAct)
875 menu.addAction(self.drawEraserAct)
876 menu.addSeparator()
877 menu.addAction(self.drawRectangleSelectionAct)
878 menu.addAction(self.drawCircleSelectionAct)
879
880 mb.addSeparator()
881
882 menu = mb.addMenu(self.tr("&Help"))
883 menu.addAction(self.aboutAct)
884 menu.addAction(self.aboutQtAct)
885 menu.addSeparator()
886 menu.addAction(self.whatsThisAct)
887
888 def __initToolbars(self):
889 """
890 Private method to create the toolbars.
891 """
892 filetb = self.addToolBar(self.tr("File"))
893 filetb.setObjectName("FileToolBar")
894 filetb.setIconSize(UI.Config.ToolBarIconSize)
895 filetb.addAction(self.newAct)
896 filetb.addAction(self.newWindowAct)
897 filetb.addAction(self.openAct)
898 filetb.addSeparator()
899 filetb.addAction(self.saveAct)
900 filetb.addAction(self.saveAsAct)
901 filetb.addSeparator()
902 filetb.addAction(self.closeAct)
903 if not self.fromEric:
904 filetb.addAction(self.exitAct)
905
906 edittb = self.addToolBar(self.tr("Edit"))
907 edittb.setObjectName("EditToolBar")
908 edittb.setIconSize(UI.Config.ToolBarIconSize)
909 edittb.addAction(self.undoAct)
910 edittb.addAction(self.redoAct)
911 edittb.addSeparator()
912 edittb.addAction(self.cutAct)
913 edittb.addAction(self.copyAct)
914 edittb.addAction(self.pasteAct)
915 edittb.addSeparator()
916 edittb.addAction(self.resizeAct)
917 edittb.addAction(self.grayscaleAct)
918
919 viewtb = self.addToolBar(self.tr("View"))
920 viewtb.setObjectName("ViewToolBar")
921 viewtb.setIconSize(UI.Config.ToolBarIconSize)
922 viewtb.addAction(self.showGridAct)
923
924 toolstb = self.addToolBar(self.tr("Tools"))
925 toolstb.setObjectName("ToolsToolBar")
926 toolstb.setIconSize(UI.Config.ToolBarIconSize)
927 toolstb.addAction(self.drawPencilAct)
928 toolstb.addAction(self.drawColorPickerAct)
929 toolstb.addAction(self.drawRectangleAct)
930 toolstb.addAction(self.drawFilledRectangleAct)
931 toolstb.addAction(self.drawCircleAct)
932 toolstb.addAction(self.drawFilledCircleAct)
933 toolstb.addAction(self.drawEllipseAct)
934 toolstb.addAction(self.drawFilledEllipseAct)
935 toolstb.addAction(self.drawFloodFillAct)
936 toolstb.addAction(self.drawLineAct)
937 toolstb.addAction(self.drawEraserAct)
938 toolstb.addSeparator()
939 toolstb.addAction(self.drawRectangleSelectionAct)
940 toolstb.addAction(self.drawCircleSelectionAct)
941
942 helptb = self.addToolBar(self.tr("Help"))
943 helptb.setObjectName("HelpToolBar")
944 helptb.setIconSize(UI.Config.ToolBarIconSize)
945 helptb.addAction(self.whatsThisAct)
946
947 def __createStatusBar(self):
948 """
949 Private method to initialize the status bar.
950 """
951 self.__statusBar = self.statusBar()
952 self.__statusBar.setSizeGripEnabled(True)
953
954 self.__sbSize = QLabel(self.__statusBar)
955 self.__statusBar.addPermanentWidget(self.__sbSize)
956 self.__sbSize.setWhatsThis(self.tr(
957 """<p>This part of the status bar displays the icon size.</p>"""
958 ))
959 self.__updateSize(*self.__editor.iconSize())
960
961 self.__sbPos = QLabel(self.__statusBar)
962 self.__statusBar.addPermanentWidget(self.__sbPos)
963 self.__sbPos.setWhatsThis(self.tr(
964 """<p>This part of the status bar displays the cursor"""
965 """ position.</p>"""
966 ))
967 self.__updatePosition(0, 0)
968
969 self.__zoomWidget = EricZoomWidget(
970 UI.PixmapCache.getPixmap("zoomOut"),
971 UI.PixmapCache.getPixmap("zoomIn"),
972 UI.PixmapCache.getPixmap("zoomReset"), self)
973 self.__zoomWidget.setMinimum(IconEditorGrid.ZoomMinimum)
974 self.__zoomWidget.setMaximum(IconEditorGrid.ZoomMaximum)
975 self.__zoomWidget.setDefault(IconEditorGrid.ZoomDefault)
976 self.__zoomWidget.setSingleStep(IconEditorGrid.ZoomStep)
977 self.__zoomWidget.setPercent(IconEditorGrid.ZoomPercent)
978 self.__statusBar.addPermanentWidget(self.__zoomWidget)
979 self.__zoomWidget.setValue(self.__editor.zoomFactor())
980 self.__zoomWidget.valueChanged.connect(self.__editor.setZoomFactor)
981 self.__editor.zoomChanged.connect(self.__zoomWidget.setValue)
982
983 self.__updateZoom()
984
985 def __createPaletteDock(self):
986 """
987 Private method to initialize the palette dock widget.
988 """
989 from .IconEditorPalette import IconEditorPalette
990
991 self.__paletteDock = QDockWidget(self)
992 self.__paletteDock.setObjectName("paletteDock")
993 self.__paletteDock.setFeatures(
994 QDockWidget.DockWidgetFeature.DockWidgetClosable |
995 QDockWidget.DockWidgetFeature.DockWidgetMovable |
996 QDockWidget.DockWidgetFeature.DockWidgetFloatable
997 )
998 self.__paletteDock.setWindowTitle("Palette")
999 self.__palette = IconEditorPalette()
1000 self.__paletteDock.setWidget(self.__palette)
1001 self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea,
1002 self.__paletteDock)
1003
1004 def closeEvent(self, evt):
1005 """
1006 Protected event handler for the close event.
1007
1008 @param evt the close event (QCloseEvent)
1009 <br />This event is simply accepted after the history has been
1010 saved and all window references have been deleted.
1011 """
1012 if self.__maybeSave():
1013 self.__editor.shutdown()
1014
1015 state = self.saveState()
1016 Preferences.setIconEditor("IconEditorState", state)
1017
1018 Preferences.setGeometry("IconEditorGeometry", self.saveGeometry())
1019
1020 with contextlib.suppress(ValueError):
1021 if self.fromEric or len(self.__class__.windows) > 1:
1022 del self.__class__.windows[
1023 self.__class__.windows.index(self)]
1024
1025 if not self.fromEric:
1026 Preferences.syncPreferences()
1027
1028 evt.accept()
1029 self.editorClosed.emit()
1030 else:
1031 evt.ignore()
1032
1033 def __newIcon(self):
1034 """
1035 Private slot to create a new icon.
1036 """
1037 if self.__maybeSave():
1038 self.__editor.editNew()
1039 self.__setCurrentFile("")
1040
1041 self.__checkActions()
1042
1043 def __newWindow(self):
1044 """
1045 Private slot called to open a new icon editor window.
1046 """
1047 ie = IconEditorWindow(parent=self.parent(), fromEric=self.fromEric,
1048 project=self.__project)
1049 ie.setRecentPaths(self.__lastOpenPath, self.__lastSavePath)
1050 ie.show()
1051
1052 def __openIcon(self):
1053 """
1054 Private slot to open an icon file.
1055 """
1056 if self.__maybeSave():
1057 if (
1058 not self.__lastOpenPath and
1059 self.__project is not None and
1060 self.__project.isOpen()
1061 ):
1062 self.__lastOpenPath = self.__project.getProjectPath()
1063
1064 fileName = EricFileDialog.getOpenFileNameAndFilter(
1065 self,
1066 self.tr("Open icon file"),
1067 self.__lastOpenPath,
1068 self.__inputFilter,
1069 self.__defaultFilter)[0]
1070 if fileName:
1071 self.__loadIconFile(fileName)
1072 self.__lastOpenPath = os.path.dirname(fileName)
1073 self.__checkActions()
1074
1075 def __saveIcon(self):
1076 """
1077 Private slot to save the icon.
1078
1079 @return flag indicating success (boolean)
1080 """
1081 if not self.__fileName:
1082 return self.__saveIconAs()
1083 else:
1084 return self.__saveIconFile(self.__fileName)
1085
1086 def __saveIconAs(self):
1087 """
1088 Private slot to save the icon with a new name.
1089
1090 @return flag indicating success (boolean)
1091 """
1092 if (
1093 not self.__lastSavePath and
1094 self.__project is not None and
1095 self.__project.isOpen()
1096 ):
1097 self.__lastSavePath = self.__project.getProjectPath()
1098 if not self.__lastSavePath and self.__lastOpenPath:
1099 self.__lastSavePath = self.__lastOpenPath
1100
1101 fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
1102 self,
1103 self.tr("Save icon file"),
1104 self.__lastSavePath,
1105 self.__outputFilter,
1106 self.__defaultFilter,
1107 EricFileDialog.DontConfirmOverwrite)
1108 if not fileName:
1109 return False
1110
1111 fpath = pathlib.Path(fileName)
1112 if not fpath.suffix:
1113 ex = selectedFilter.split("(*")[1].split(")")[0]
1114 if ex:
1115 fpath = fpath.with_suffix(ex)
1116 if fpath.exists():
1117 res = EricMessageBox.yesNo(
1118 self,
1119 self.tr("Save icon file"),
1120 self.tr("<p>The file <b>{0}</b> already exists."
1121 " Overwrite it?</p>").format(fpath),
1122 icon=EricMessageBox.Warning)
1123 if not res:
1124 return False
1125
1126 self.__lastSavePath = str(fpath.parent)
1127
1128 return self.__saveIconFile(str(fpath))
1129
1130 def __closeAll(self):
1131 """
1132 Private slot to close all windows.
1133 """
1134 self.__closeOthers()
1135 self.close()
1136
1137 def __closeOthers(self):
1138 """
1139 Private slot to close all other windows.
1140 """
1141 for win in self.__class__.windows[:]:
1142 if win != self:
1143 win.close()
1144
1145 def __loadIconFile(self, fileName):
1146 """
1147 Private method to load an icon file.
1148
1149 @param fileName name of the icon file to load (string).
1150 """
1151 img = QImage(fileName)
1152 if img.isNull():
1153 EricMessageBox.warning(
1154 self, self.tr("eric Icon Editor"),
1155 self.tr("Cannot read file '{0}'.").format(fileName))
1156 else:
1157 self.__editor.setIconImage(img, clearUndo=True)
1158 self.__setCurrentFile(fileName)
1159
1160 def __saveIconFile(self, fileName):
1161 """
1162 Private method to save to the given file.
1163
1164 @param fileName name of the file to save to (string)
1165 @return flag indicating success (boolean)
1166 """
1167 img = self.__editor.iconImage()
1168 res = img.save(fileName)
1169
1170 if not res:
1171 EricMessageBox.warning(
1172 self, self.tr("eric Icon Editor"),
1173 self.tr("Cannot write file '{0}'.")
1174 .format(fileName))
1175
1176 self.__checkActions()
1177
1178 return False
1179
1180 self.__editor.setDirty(False, setCleanState=True)
1181
1182 self.__setCurrentFile(fileName)
1183 self.__statusBar.showMessage(self.tr("Icon saved"), 2000)
1184
1185 self.__checkActions()
1186
1187 return True
1188
1189 def __setCurrentFile(self, fileName):
1190 """
1191 Private method to register the file name of the current file.
1192
1193 @param fileName name of the file to register (string)
1194 """
1195 self.__fileName = fileName
1196
1197 shownName = (
1198 self.__strippedName(self.__fileName)
1199 if self.__fileName else
1200 self.tr("Untitled")
1201 )
1202
1203 self.setWindowTitle(self.tr("{0}[*] - {1}")
1204 .format(shownName, self.tr("Icon Editor")))
1205
1206 self.setWindowModified(self.__editor.isDirty())
1207
1208 def __strippedName(self, fullFileName):
1209 """
1210 Private method to return the filename part of the given path.
1211
1212 @param fullFileName full pathname of the given file (string)
1213 @return filename part (string)
1214 """
1215 return pathlib.Path(fullFileName).name
1216
1217 def __maybeSave(self):
1218 """
1219 Private method to ask the user to save the file, if it was modified.
1220
1221 @return flag indicating, if it is ok to continue (boolean)
1222 """
1223 if self.__editor.isDirty():
1224 ret = EricMessageBox.okToClearData(
1225 self,
1226 self.tr("eric Icon Editor"),
1227 self.tr("""The icon image has unsaved changes."""),
1228 self.__saveIcon)
1229 if not ret:
1230 return False
1231 return True
1232
1233 def setRecentPaths(self, openPath, savePath):
1234 """
1235 Public method to set the last open and save paths.
1236
1237 @param openPath least recently used open path (string)
1238 @param savePath least recently used save path (string)
1239 """
1240 if openPath:
1241 self.__lastOpenPath = openPath
1242 if savePath:
1243 self.__lastSavePath = savePath
1244
1245 def __checkActions(self):
1246 """
1247 Private slot to check some actions for their enable/disable status.
1248 """
1249 self.saveAct.setEnabled(self.__editor.isDirty())
1250
1251 def __modificationChanged(self, m):
1252 """
1253 Private slot to handle the modificationChanged signal.
1254
1255 @param m modification status
1256 """
1257 self.setWindowModified(m)
1258 self.__checkActions()
1259
1260 def __updatePosition(self, x, y):
1261 """
1262 Private slot to show the current cursor position.
1263
1264 @param x x-coordinate (integer)
1265 @param y y-coordinate (integer)
1266 """
1267 self.__sbPos.setText("X: {0:d} Y: {1:d}".format(x + 1, y + 1))
1268
1269 def __updateSize(self, w, h):
1270 """
1271 Private slot to show the current icon size.
1272
1273 @param w width of the icon (integer)
1274 @param h height of the icon (integer)
1275 """
1276 self.__sbSize.setText("Size: {0:d} x {1:d}".format(w, h))
1277
1278 def __updateZoom(self):
1279 """
1280 Private slot to show the current zoom factor.
1281 """
1282 self.zoomOutAct.setEnabled(
1283 self.__editor.zoomFactor() > IconEditorGrid.ZoomMinimum)
1284 self.zoomInAct.setEnabled(
1285 self.__editor.zoomFactor() < IconEditorGrid.ZoomMaximum)
1286
1287 def __zoomIn(self):
1288 """
1289 Private slot called to handle the zoom in action.
1290 """
1291 self.__editor.setZoomFactor(
1292 self.__editor.zoomFactor() + IconEditorGrid.ZoomStep)
1293 self.__updateZoom()
1294
1295 def __zoomOut(self):
1296 """
1297 Private slot called to handle the zoom out action.
1298 """
1299 self.__editor.setZoomFactor(
1300 self.__editor.zoomFactor() - IconEditorGrid.ZoomStep)
1301 self.__updateZoom()
1302
1303 def __zoomReset(self):
1304 """
1305 Private slot called to handle the zoom reset action.
1306 """
1307 self.__editor.setZoomFactor(IconEditorGrid.ZoomDefault)
1308 self.__updateZoom()
1309
1310 def __about(self):
1311 """
1312 Private slot to show a little About message.
1313 """
1314 EricMessageBox.about(
1315 self, self.tr("About eric Icon Editor"),
1316 self.tr("The eric Icon Editor is a simple editor component"
1317 " to perform icon drawing tasks."))
1318
1319 def __aboutQt(self):
1320 """
1321 Private slot to handle the About Qt dialog.
1322 """
1323 EricMessageBox.aboutQt(self, "eric Icon Editor")
1324
1325 def __whatsThis(self):
1326 """
1327 Private slot called in to enter Whats This mode.
1328 """
1329 QWhatsThis.enterWhatsThisMode()
1330
1331 def wheelEvent(self, evt):
1332 """
1333 Protected method to handle wheel events.
1334
1335 @param evt reference to the wheel event (QWheelEvent)
1336 """
1337 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
1338 delta = evt.angleDelta().y()
1339 if delta < 0:
1340 self.__zoomOut()
1341 elif delta > 0:
1342 self.__zoomIn()
1343 evt.accept()
1344 return
1345
1346 super().wheelEvent(evt)
1347
1348 def event(self, evt):
1349 """
1350 Public method handling events.
1351
1352 @param evt reference to the event (QEvent)
1353 @return flag indicating, if the event was handled (boolean)
1354 """
1355 if evt.type() == QEvent.Type.Gesture:
1356 self.gestureEvent(evt)
1357 return True
1358
1359 return super().event(evt)
1360
1361 def gestureEvent(self, evt):
1362 """
1363 Protected method handling gesture events.
1364
1365 @param evt reference to the gesture event (QGestureEvent
1366 """
1367 pinch = evt.gesture(Qt.GestureType.PinchGesture)
1368 if pinch:
1369 if pinch.state() == Qt.GestureState.GestureStarted:
1370 pinch.setTotalScaleFactor(self.__editor.zoomFactor() / 100.0)
1371 elif pinch.state() == Qt.GestureState.GestureUpdated:
1372 self.__editor.setZoomFactor(
1373 int(pinch.totalScaleFactor() * 100))
1374 self.__updateZoom()
1375 evt.accept()

eric ide

mercurial