|
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() |