|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to enter data for an image markup. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 from PyQt5.QtCore import pyqtSlot, QSize |
|
13 from PyQt5.QtGui import QImage, QImageReader |
|
14 from PyQt5.QtWidgets import QDialog, QDialogButtonBox |
|
15 |
|
16 from E5Gui.E5PathPicker import E5PathPickerModes |
|
17 |
|
18 from .Ui_ImageMarkupDialog import Ui_ImageMarkupDialog |
|
19 |
|
20 |
|
21 class ImageMarkupDialog(QDialog, Ui_ImageMarkupDialog): |
|
22 """ |
|
23 Class implementing a dialog to enter data for an image markup. |
|
24 """ |
|
25 HtmlMode = 0 |
|
26 MarkDownMode = 1 |
|
27 RestMode = 2 |
|
28 |
|
29 def __init__(self, mode, parent=None): |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param parent reference to the parent widget |
|
34 @type QWidget |
|
35 """ |
|
36 super(ImageMarkupDialog, self).__init__(parent) |
|
37 self.setupUi(self) |
|
38 |
|
39 if mode == ImageMarkupDialog.MarkDownMode: |
|
40 self.sizeCheckBox.setEnabled(False) |
|
41 self.aspectRatioCheckBox.setEnabled(False) |
|
42 self.widthSpinBox.setEnabled(False) |
|
43 self.heightSpinBox.setEnabled(False) |
|
44 elif mode == ImageMarkupDialog.RestMode: |
|
45 self.titleEdit.setEnabled(False) |
|
46 |
|
47 self.__mode = mode |
|
48 self.__originalImageSize = QSize() |
|
49 |
|
50 filters = { |
|
51 'bmp': self.tr("Windows Bitmap File (*.bmp)"), |
|
52 'cur': self.tr("Windows Cursor File (*.cur)"), |
|
53 'dds': self.tr("DirectDraw-Surface File (*.dds)"), |
|
54 'gif': self.tr("Graphic Interchange Format File (*.gif)"), |
|
55 'icns': self.tr("Apple Icon File (*.icns)"), |
|
56 'ico': self.tr("Windows Icon File (*.ico)"), |
|
57 'jp2': self.tr("JPEG2000 File (*.jp2)"), |
|
58 'jpg': self.tr("JPEG File (*.jpg)"), |
|
59 'jpeg': self.tr("JPEG File (*.jpeg)"), |
|
60 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"), |
|
61 'pbm': self.tr("Portable Bitmap File (*.pbm)"), |
|
62 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"), |
|
63 'pgm': self.tr("Portable Graymap File (*.pgm)"), |
|
64 'png': self.tr("Portable Network Graphics File (*.png)"), |
|
65 'ppm': self.tr("Portable Pixmap File (*.ppm)"), |
|
66 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"), |
|
67 'svg': self.tr("Scalable Vector Graphics File (*.svg)"), |
|
68 'svgz': self.tr("Compressed Scalable Vector Graphics File" |
|
69 " (*.svgz)"), |
|
70 'tga': self.tr("Targa Graphic File (*.tga)"), |
|
71 'tif': self.tr("TIFF File (*.tif)"), |
|
72 'tiff': self.tr("TIFF File (*.tiff)"), |
|
73 'wbmp': self.tr("WAP Bitmap File (*.wbmp)"), |
|
74 'webp': self.tr("WebP Image File (*.webp)"), |
|
75 'xbm': self.tr("X11 Bitmap File (*.xbm)"), |
|
76 'xpm': self.tr("X11 Pixmap File (*.xpm)"), |
|
77 } |
|
78 |
|
79 inputFormats = [] |
|
80 readFormats = QImageReader.supportedImageFormats() |
|
81 for readFormat in readFormats: |
|
82 try: |
|
83 inputFormats.append(filters[bytes(readFormat).decode()]) |
|
84 except KeyError: |
|
85 pass |
|
86 inputFormats.sort() |
|
87 inputFormats.append(self.tr("All Files (*)")) |
|
88 if filters["png"] in inputFormats: |
|
89 inputFormats.remove(filters["png"]) |
|
90 inputFormats.insert(0, filters["png"]) |
|
91 self.imagePicker.setFilters(';;'.join(inputFormats)) |
|
92 self.imagePicker.setMode(E5PathPickerModes.OpenFileMode) |
|
93 |
|
94 self.sizeCheckBox.setChecked(True) |
|
95 self.aspectRatioCheckBox.setChecked(True) |
|
96 |
|
97 msh = self.minimumSizeHint() |
|
98 self.resize(max(self.width(), msh.width()), msh.height()) |
|
99 |
|
100 self.__updateOkButton() |
|
101 |
|
102 def __updateOkButton(self): |
|
103 """ |
|
104 Private slot to set the state of the OK button. |
|
105 """ |
|
106 enable = bool(self.imagePicker.text()) |
|
107 if self.__mode == ImageMarkupDialog.MarkDownMode: |
|
108 enable = enable and bool(self.altTextEdit.text()) |
|
109 |
|
110 self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) |
|
111 |
|
112 @pyqtSlot(str) |
|
113 def on_imagePicker_textChanged(self, address): |
|
114 """ |
|
115 Private slot handling changes of the image path. |
|
116 |
|
117 @param address image address (URL or local path) |
|
118 @type str |
|
119 """ |
|
120 if address and "://" not in address: |
|
121 image = QImage(address) |
|
122 # load the file to set the size spin boxes |
|
123 if image.isNull(): |
|
124 self.widthSpinBox.setValue(0) |
|
125 self.heightSpinBox.setValue(0) |
|
126 self.__originalImageSize = QSize() |
|
127 self.__aspectRatio = 1 |
|
128 else: |
|
129 self.widthSpinBox.setValue(image.width()) |
|
130 self.heightSpinBox.setValue(image.height()) |
|
131 self.__originalImageSize = image.size() |
|
132 self.__aspectRatio = \ |
|
133 float(self.__originalImageSize.height()) / \ |
|
134 self.__originalImageSize.width() |
|
135 else: |
|
136 self.widthSpinBox.setValue(0) |
|
137 self.heightSpinBox.setValue(0) |
|
138 self.__originalImageSize = QSize() |
|
139 self.__aspectRatio = 1 |
|
140 |
|
141 self.__updateOkButton() |
|
142 |
|
143 @pyqtSlot(str) |
|
144 def on_altTextEdit_textChanged(self, txt): |
|
145 """ |
|
146 Private slot handling changes of the alternative text. |
|
147 |
|
148 @param txt alternative text |
|
149 @type str |
|
150 """ |
|
151 self.__updateOkButton() |
|
152 |
|
153 @pyqtSlot(bool) |
|
154 def on_sizeCheckBox_toggled(self, checked): |
|
155 """ |
|
156 Public slot to reset the width and height spin boxes. |
|
157 |
|
158 @param checked flag indicating the state of the check box |
|
159 @type bool |
|
160 """ |
|
161 if checked: |
|
162 self.widthSpinBox.setValue(self.__originalImageSize.width()) |
|
163 self.heightSpinBox.setValue(self.__originalImageSize.height()) |
|
164 |
|
165 @pyqtSlot(bool) |
|
166 def on_aspectRatioCheckBox_toggled(self, checked): |
|
167 """ |
|
168 Public slot to adjust the height to match the original aspect ratio. |
|
169 |
|
170 @param checked flag indicating the state of the check box |
|
171 @type bool |
|
172 """ |
|
173 if checked and self.__originalImageSize.isValid(): |
|
174 height = self.widthSpinBox.value() * self.__aspectRatio |
|
175 self.heightSpinBox.setValue(height) |
|
176 |
|
177 @pyqtSlot(int) |
|
178 def on_widthSpinBox_valueChanged(self, width): |
|
179 """ |
|
180 Private slot to adjust the height spin box. |
|
181 |
|
182 @param width width for the image |
|
183 @type int |
|
184 """ |
|
185 if self.aspectRatioCheckBox.isChecked() and \ |
|
186 self.widthSpinBox.hasFocus(): |
|
187 height = width * self.__aspectRatio |
|
188 self.heightSpinBox.setValue(height) |
|
189 |
|
190 @pyqtSlot(int) |
|
191 def on_heightSpinBox_valueChanged(self, height): |
|
192 """ |
|
193 Private slot to adjust the width spin box. |
|
194 |
|
195 @param height height for the image |
|
196 @type int |
|
197 """ |
|
198 if self.aspectRatioCheckBox.isChecked() and \ |
|
199 self.heightSpinBox.hasFocus(): |
|
200 width = height / self.__aspectRatio |
|
201 self.widthSpinBox.setValue(width) |
|
202 |
|
203 def getData(self): |
|
204 """ |
|
205 Public method to get the entered data. |
|
206 |
|
207 @return tuple containing the image address, alternative text, |
|
208 title text, flag to keep the original size, width and height |
|
209 @rtype tuple of (str, str, str, bool, int, int) |
|
210 """ |
|
211 return ( |
|
212 self.imagePicker.text(), |
|
213 self.altTextEdit.text(), |
|
214 self.titleEdit.text(), |
|
215 self.sizeCheckBox.isChecked(), |
|
216 self.widthSpinBox.value(), |
|
217 self.heightSpinBox.value(), |
|
218 ) |