eric6/IconEditor/IconEditorWindow.py

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

eric ide

mercurial