Wed, 30 Dec 2020 11:00:05 +0100
Updated copyright for 2021.
# -*- coding: utf-8 -*- # Copyright (c) 2017 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a dialog to enter data for an image markup. """ from PyQt5.QtCore import pyqtSlot, QSize from PyQt5.QtGui import QImage, QImageReader from PyQt5.QtWidgets import QDialog, QDialogButtonBox from E5Gui.E5PathPicker import E5PathPickerModes from .Ui_ImageMarkupDialog import Ui_ImageMarkupDialog class ImageMarkupDialog(QDialog, Ui_ImageMarkupDialog): """ Class implementing a dialog to enter data for an image markup. """ HtmlMode = 0 MarkDownMode = 1 RestMode = 2 def __init__(self, mode, parent=None): """ Constructor @param mode mode of the dialog @type int @param parent reference to the parent widget @type QWidget """ super(ImageMarkupDialog, self).__init__(parent) self.setupUi(self) if mode == ImageMarkupDialog.MarkDownMode: self.sizeCheckBox.setEnabled(False) self.aspectRatioCheckBox.setEnabled(False) self.widthSpinBox.setEnabled(False) self.heightSpinBox.setEnabled(False) elif mode == ImageMarkupDialog.RestMode: self.titleEdit.setEnabled(False) self.__mode = mode self.__originalImageSize = QSize() filters = { 'bmp': self.tr("Windows Bitmap File (*.bmp)"), 'cur': self.tr("Windows Cursor File (*.cur)"), 'dds': self.tr("DirectDraw-Surface File (*.dds)"), 'gif': self.tr("Graphic Interchange Format File (*.gif)"), 'icns': self.tr("Apple Icon File (*.icns)"), 'ico': self.tr("Windows Icon File (*.ico)"), 'jp2': self.tr("JPEG2000 File (*.jp2)"), 'jpg': self.tr("JPEG File (*.jpg)"), 'jpeg': self.tr("JPEG File (*.jpeg)"), 'mng': self.tr("Multiple-Image Network Graphics File (*.mng)"), 'pbm': self.tr("Portable Bitmap File (*.pbm)"), 'pcx': self.tr("Paintbrush Bitmap File (*.pcx)"), 'pgm': self.tr("Portable Graymap File (*.pgm)"), 'png': self.tr("Portable Network Graphics File (*.png)"), 'ppm': self.tr("Portable Pixmap File (*.ppm)"), 'sgi': self.tr("Silicon Graphics Image File (*.sgi)"), 'svg': self.tr("Scalable Vector Graphics File (*.svg)"), 'svgz': self.tr("Compressed Scalable Vector Graphics File" " (*.svgz)"), 'tga': self.tr("Targa Graphic File (*.tga)"), 'tif': self.tr("TIFF File (*.tif)"), 'tiff': self.tr("TIFF File (*.tiff)"), 'wbmp': self.tr("WAP Bitmap File (*.wbmp)"), 'webp': self.tr("WebP Image File (*.webp)"), 'xbm': self.tr("X11 Bitmap File (*.xbm)"), 'xpm': self.tr("X11 Pixmap File (*.xpm)"), } inputFormats = [] readFormats = QImageReader.supportedImageFormats() for readFormat in readFormats: try: inputFormats.append(filters[bytes(readFormat).decode()]) except KeyError: pass inputFormats.sort() inputFormats.append(self.tr("All Files (*)")) if filters["png"] in inputFormats: inputFormats.remove(filters["png"]) inputFormats.insert(0, filters["png"]) self.imagePicker.setFilters(';;'.join(inputFormats)) self.imagePicker.setMode(E5PathPickerModes.OpenFileMode) self.sizeCheckBox.setChecked(True) self.aspectRatioCheckBox.setChecked(True) msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) self.__updateOkButton() def __updateOkButton(self): """ Private slot to set the state of the OK button. """ enable = bool(self.imagePicker.text()) if self.__mode == ImageMarkupDialog.MarkDownMode: enable = enable and bool(self.altTextEdit.text()) self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) @pyqtSlot(str) def on_imagePicker_textChanged(self, address): """ Private slot handling changes of the image path. @param address image address (URL or local path) @type str """ if address and "://" not in address: image = QImage(address) # load the file to set the size spin boxes if image.isNull(): self.widthSpinBox.setValue(0) self.heightSpinBox.setValue(0) self.__originalImageSize = QSize() self.__aspectRatio = 1 else: self.widthSpinBox.setValue(image.width()) self.heightSpinBox.setValue(image.height()) self.__originalImageSize = image.size() self.__aspectRatio = ( float(self.__originalImageSize.height()) / self.__originalImageSize.width() ) else: self.widthSpinBox.setValue(0) self.heightSpinBox.setValue(0) self.__originalImageSize = QSize() self.__aspectRatio = 1 self.__updateOkButton() @pyqtSlot(str) def on_altTextEdit_textChanged(self, txt): """ Private slot handling changes of the alternative text. @param txt alternative text @type str """ self.__updateOkButton() @pyqtSlot(bool) def on_sizeCheckBox_toggled(self, checked): """ Private slot to reset the width and height spin boxes. @param checked flag indicating the state of the check box @type bool """ if checked: self.widthSpinBox.setValue(self.__originalImageSize.width()) self.heightSpinBox.setValue(self.__originalImageSize.height()) @pyqtSlot(bool) def on_aspectRatioCheckBox_toggled(self, checked): """ Private slot to adjust the height to match the original aspect ratio. @param checked flag indicating the state of the check box @type bool """ if checked and self.__originalImageSize.isValid(): height = self.widthSpinBox.value() * self.__aspectRatio self.heightSpinBox.setValue(height) @pyqtSlot(int) def on_widthSpinBox_valueChanged(self, width): """ Private slot to adjust the height spin box. @param width width for the image @type int """ if ( self.aspectRatioCheckBox.isChecked() and self.widthSpinBox.hasFocus() ): height = width * self.__aspectRatio self.heightSpinBox.setValue(height) @pyqtSlot(int) def on_heightSpinBox_valueChanged(self, height): """ Private slot to adjust the width spin box. @param height height for the image @type int """ if ( self.aspectRatioCheckBox.isChecked() and self.heightSpinBox.hasFocus() ): width = height / self.__aspectRatio self.widthSpinBox.setValue(width) def getData(self): """ Public method to get the entered data. @return tuple containing the image address, alternative text, title text, flag to keep the original size, width and height @rtype tuple of (str, str, str, bool, int, int) """ return ( self.imagePicker.text(), self.altTextEdit.text(), self.titleEdit.text(), self.sizeCheckBox.isChecked(), self.widthSpinBox.value(), self.heightSpinBox.value(), )