--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QScintilla/MarkupProviders/ImageMarkupDialog.py Sun Jan 08 18:52:16 2017 +0100 @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter data for an image markup. +""" + +from __future__ import unicode_literals + +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 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): + """ + Public 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): + """ + Public 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(), + )