Преглед изворни кода

InsertImageDialog: support scaling image

Le Tan пре 7 година
родитељ
комит
9923feea14
4 измењених фајлова са 202 додато и 87 уклоњено
  1. 108 46
      src/dialog/vinsertimagedialog.cpp
  2. 18 5
      src/dialog/vinsertimagedialog.h
  3. 59 27
      src/vmdeditoperations.cpp
  4. 17 9
      src/vmdeditoperations.h

+ 108 - 46
src/dialog/vinsertimagedialog.cpp

@@ -14,7 +14,6 @@ VInsertImageDialog::VInsertImageDialog(const QString &p_title,
                                        bool p_browsable,
                                        QWidget *p_parent)
     : QDialog(p_parent),
-      m_image(NULL),
       m_browsable(p_browsable)
 {
     setupUI(p_title, p_imageTitle, p_imagePath);
@@ -35,40 +34,81 @@ VInsertImageDialog::VInsertImageDialog(const QString &p_title,
     handleInputChanged();
 }
 
-VInsertImageDialog::~VInsertImageDialog()
-{
-    delete m_image;
-    m_image = NULL;
-}
-
 void VInsertImageDialog::setupUI(const QString &p_title,
                                  const QString &p_imageTitle,
                                  const QString &p_imagePath)
 {
-    QLabel *pathLabel = new QLabel(tr("&From:"));
+    // Path.
     m_pathEdit = new VLineEdit(p_imagePath);
-    pathLabel->setBuddy(m_pathEdit);
-    browseBtn = new QPushButton(tr("&Browse"));
     m_pathEdit->setReadOnly(!m_browsable);
+    browseBtn = new QPushButton(tr("&Browse"));
     browseBtn->setEnabled(m_browsable);
 
-    QLabel *imageTitleLabel = new QLabel(tr("&Image title:"));
+    // Title.
     m_imageTitleEdit = new VMetaWordLineEdit(p_imageTitle);
     m_imageTitleEdit->selectAll();
-    imageTitleLabel->setBuddy(m_imageTitleEdit);
     QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_imageTitleRegExp),
                                                  m_imageTitleEdit);
     m_imageTitleEdit->setValidator(validator);
 
+    // Scale.
+    m_widthSpin = new QSpinBox();
+    m_widthSpin->setMinimum(1);
+    m_widthSpin->setSingleStep(10);
+    m_widthSpin->setSuffix(" px");
+    connect(m_widthSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
+            this, [this](int p_val) {
+                if (!m_image) {
+                    return;
+                }
+
+                int height = m_image->height() * (1.0 * p_val / m_image->width());
+                m_imageLabel->resize(p_val, height);
+            });
+
+    // 0.1 to 2.0 -> 1 to 20.
+    m_scaleSlider = new QSlider();
+    m_scaleSlider->setOrientation(Qt::Horizontal);
+    m_scaleSlider->setMinimum(1);
+    m_scaleSlider->setMaximum(20);
+    m_scaleSlider->setValue(10);
+    m_scaleSlider->setSingleStep(1);
+    m_scaleSlider->setPageStep(5);
+    connect(m_scaleSlider, &QSlider::valueChanged,
+            this, [this](int p_val) {
+                if (!m_image) {
+                    return;
+                }
+
+                int width = m_image->width();
+                qreal factor = 1.0;
+                if (p_val != 10) {
+                    factor = p_val / 10.0;
+                    width = m_image->width() * factor;
+                }
+
+                m_widthSpin->setValue(width);
+                m_sliderLabel->setText(QString::number(factor) + "x");
+            });
+
+    m_sliderLabel = new QLabel("1x");
+
     QGridLayout *topLayout = new QGridLayout();
-    topLayout->addWidget(pathLabel, 0, 0);
-    topLayout->addWidget(m_pathEdit, 0, 1);
-    topLayout->addWidget(browseBtn, 0, 2);
-    topLayout->addWidget(imageTitleLabel, 1, 0);
-    topLayout->addWidget(m_imageTitleEdit, 1, 1, 1, 2);
+    topLayout->addWidget(new QLabel(tr("From:")), 0, 0, 1, 1);
+    topLayout->addWidget(m_pathEdit, 0, 1, 1, 3);
+    topLayout->addWidget(browseBtn, 0, 4, 1, 1);
+    topLayout->addWidget(new QLabel(tr("Title:")), 1, 0, 1, 1);
+    topLayout->addWidget(m_imageTitleEdit, 1, 1, 1, 4);
+    topLayout->addWidget(new QLabel(tr("Scaling width:")), 2, 0, 1, 1);
+    topLayout->addWidget(m_widthSpin, 2, 1, 1, 1);
+    topLayout->addWidget(m_scaleSlider, 2, 2, 1, 2);
+    topLayout->addWidget(m_sliderLabel, 2, 4, 1, 1);
+
     topLayout->setColumnStretch(0, 0);
-    topLayout->setColumnStretch(1, 1);
-    topLayout->setColumnStretch(2, 0);
+    topLayout->setColumnStretch(1, 0);
+    topLayout->setColumnStretch(2, 1);
+    topLayout->setColumnStretch(3, 1);
+    topLayout->setColumnStretch(4, 0);
 
     // Ok is the default button.
     m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
@@ -76,15 +116,23 @@ void VInsertImageDialog::setupUI(const QString &p_title,
     connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
     m_btnBox->button(QDialogButtonBox::Ok)->setProperty("SpecialBtn", true);
 
-    imagePreviewLabel = new QLabel();
-    imagePreviewLabel->setVisible(false);
+    m_imageLabel = new QLabel();
+    m_imageLabel->setScaledContents(true);
+
+    m_previewArea = new QScrollArea();
+    m_previewArea->setBackgroundRole(QPalette::Dark);
+    m_previewArea->setWidget(m_imageLabel);
+    int minWidth = 512 * VUtils::calculateScaleFactor();
+    m_previewArea->setMinimumSize(minWidth, minWidth);
+
+    setImageControlsVisible(false);
 
     QVBoxLayout *mainLayout = new QVBoxLayout();
     mainLayout->addLayout(topLayout);
     mainLayout->addWidget(m_btnBox);
-    mainLayout->addWidget(imagePreviewLabel);
+    mainLayout->addWidget(m_previewArea);
     setLayout(mainLayout);
-    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
+
     setWindowTitle(p_title);
 
     m_imageTitleEdit->setFocus();
@@ -133,34 +181,29 @@ void VInsertImageDialog::handleBrowseBtnClicked()
     m_imageTitleEdit->setFocus();
 }
 
-void VInsertImageDialog::setImage(const QImage &image)
+void VInsertImageDialog::setImage(const QImage &p_image)
 {
-    if (image.isNull()) {
-        imagePreviewLabel->setVisible(false);
-        delete m_image;
-        m_image = NULL;
+    if (p_image.isNull()) {
+        m_image.clear();
+        m_imageLabel->clear();
 
-        handleInputChanged();
-        return;
-    }
-
-    int width = 512 * VUtils::calculateScaleFactor();
-    QSize previewSize(width, width);
-    if (!m_image) {
-        m_image = new QImage(image);
+        setImageControlsVisible(false);
     } else {
-        *m_image = image;
-    }
+        m_image.reset(new QImage(p_image));
 
-    QPixmap pixmap;
-    if (image.width() > width || image.height() > width) {
-        pixmap = QPixmap::fromImage(m_image->scaled(previewSize, Qt::KeepAspectRatio));
-    } else {
-        pixmap = QPixmap::fromImage(*m_image);
-    }
+        m_imageLabel->setPixmap(QPixmap::fromImage(*m_image));
+
+        m_imageLabel->adjustSize();
+
+        // Set the scaling widgets.
+        m_scaleSlider->setValue(10);
 
-    imagePreviewLabel->setPixmap(pixmap);
-    imagePreviewLabel->setVisible(true);
+        int width = m_image->width();
+        m_widthSpin->setMaximum(width * 5);
+        m_widthSpin->setValue(width);
+
+        setImageControlsVisible(true);
+    }
 
     handleInputChanged();
 }
@@ -281,3 +324,22 @@ void VInsertImageDialog::setPath(const QString &p_path)
     m_pathEdit->setText(p_path);
     handlePathEditChanged();
 }
+
+void VInsertImageDialog::setImageControlsVisible(bool p_visible)
+{
+    m_widthSpin->setEnabled(p_visible);
+    m_scaleSlider->setEnabled(p_visible);
+    m_sliderLabel->setEnabled(p_visible);
+
+    m_previewArea->setVisible(p_visible);
+}
+
+int VInsertImageDialog::getOverridenWidth() const
+{
+    int width = m_widthSpin->value();
+    if (m_image && m_image->width() != width) {
+        return width;
+    }
+
+    return 0;
+}

+ 18 - 5
src/dialog/vinsertimagedialog.h

@@ -13,6 +13,9 @@ class VLineEdit;
 class VMetaWordLineEdit;
 class QPushButton;
 class QDialogButtonBox;
+class QScrollArea;
+class QSpinBox;
+class QSlider;
 
 class VInsertImageDialog : public QDialog
 {
@@ -30,18 +33,19 @@ public:
                        bool p_browsable = true,
                        QWidget *p_parent = nullptr);
 
-    ~VInsertImageDialog();
-
     QString getImageTitleInput() const;
 
     QString getPathInput() const;
 
-    void setImage(const QImage &image);
+    void setImage(const QImage &p_image);
 
     QImage getImage() const;
 
     VInsertImageDialog::ImageType getImageType() const;
 
+    // Return 0 if no override.
+    int getOverridenWidth() const;
+
 public slots:
     void imageDownloaded(const QByteArray &data);
 
@@ -61,13 +65,22 @@ private:
 
     void setPath(const QString &p_path);
 
+    void setImageControlsVisible(bool p_visible);
+
     VMetaWordLineEdit *m_imageTitleEdit;
     VLineEdit *m_pathEdit;
     QPushButton *browseBtn;
+
+    QSpinBox *m_widthSpin;
+    QSlider *m_scaleSlider;
+    QLabel *m_sliderLabel;
+
     QDialogButtonBox *m_btnBox;
-    QLabel *imagePreviewLabel;
 
-    QImage *m_image;
+    QLabel *m_imageLabel;
+    QScrollArea *m_previewArea;
+
+    QSharedPointer<QImage> m_image;
 
     // Whether enable the browse action.
     bool m_browsable;

+ 59 - 27
src/vmdeditoperations.cpp

@@ -52,28 +52,51 @@ bool VMdEditOperations::insertImageFromMimeData(const QMimeData *source)
         insertImageFromQImage(dialog.getImageTitleInput(),
                               m_file->fetchImageFolderPath(),
                               m_file->getImageFolderInLink(),
-                              image);
+                              image,
+                              dialog.getOverridenWidth());
     }
 
     return true;
 }
 
-void VMdEditOperations::insertImageFromQImage(const QString &title,
-                                              const QString &path,
-                                              const QString &folderInLink,
-                                              const QImage &image)
+// @p_width, @p_height: 0 if no override.
+static QString imageLink(const QString &p_title,
+                         const QString &p_url,
+                         int p_width = 0,
+                         int p_height = 0)
 {
-    QString fileName = VUtils::generateImageFileName(path, title);
-    QString filePath = QDir(path).filePath(fileName);
+    QString scale;
+    if (p_width > 0) {
+        if (p_height > 0) {
+            scale = QString(" =%1x%2").arg(p_width).arg(p_height);
+        } else {
+            scale = QString(" =%1x").arg(p_width);
+        }
+    } else if (p_height > 0) {
+        scale = QString(" =x%1").arg(p_height);
+    }
+
+    return QString("![%1](%2%3)").arg(p_title).arg(p_url).arg(scale);
+}
+
+void VMdEditOperations::insertImageFromQImage(const QString &p_title,
+                                              const QString &p_folderPath,
+                                              const QString &p_folderInLink,
+                                              const QImage &p_image,
+                                              int p_width,
+                                              int p_height)
+{
+    QString fileName = VUtils::generateImageFileName(p_folderPath, p_title);
+    QString filePath = QDir(p_folderPath).filePath(fileName);
     V_ASSERT(!QFile(filePath).exists());
 
     QString errStr;
-    bool ret = VUtils::makePath(path);
+    bool ret = VUtils::makePath(p_folderPath);
     if (!ret) {
         errStr = tr("Fail to create image folder <span style=\"%1\">%2</span>.")
-                   .arg(g_config->c_dataTextStyle).arg(path);
+                   .arg(g_config->c_dataTextStyle).arg(p_folderPath);
     } else {
-        ret = image.save(filePath);
+        ret = p_image.save(filePath);
         if (!ret) {
             errStr = tr("Fail to save image <span style=\"%1\">%2</span>.")
                        .arg(g_config->c_dataTextStyle).arg(filePath);
@@ -82,7 +105,7 @@ void VMdEditOperations::insertImageFromQImage(const QString &title,
 
     if (!ret) {
         VUtils::showMessage(QMessageBox::Warning, tr("Warning"),
-                            tr("Fail to insert image <span style=\"%1\">%2</span>.").arg(g_config->c_dataTextStyle).arg(title),
+                            tr("Fail to insert image <span style=\"%1\">%2</span>.").arg(g_config->c_dataTextStyle).arg(p_title),
                             errStr,
                             QMessageBox::Ok,
                             QMessageBox::Ok,
@@ -90,11 +113,11 @@ void VMdEditOperations::insertImageFromQImage(const QString &title,
         return;
     }
 
-    QString url = QString("%1/%2").arg(folderInLink).arg(fileName);
-    QString md = QString("![%1](%2)").arg(title).arg(url);
-    insertText(md);
+    QString url = QString("%1/%2").arg(p_folderInLink).arg(fileName);
 
-    qDebug() << "insert image" << title << filePath;
+    insertText(imageLink(p_title, url, p_width, p_height));
+
+    qDebug() << "insert image" << p_title << filePath;
 
     VMdEditor *mdEditor = dynamic_cast<VMdEditor *>(m_editor);
     Q_ASSERT(mdEditor);
@@ -104,7 +127,9 @@ void VMdEditOperations::insertImageFromQImage(const QString &title,
 void VMdEditOperations::insertImageFromPath(const QString &p_title,
                                             const QString &p_folderPath,
                                             const QString &p_folderInLink,
-                                            const QString &p_srcImagePath)
+                                            const QString &p_srcImagePath,
+                                            int p_width,
+                                            int p_height)
 {
     insertImageFromPath(p_title,
                         p_folderPath,
@@ -112,7 +137,9 @@ void VMdEditOperations::insertImageFromPath(const QString &p_title,
                         p_srcImagePath,
                         true,
                         QString(),
-                        QString());
+                        QString(),
+                        p_width,
+                        p_height);
 }
 
 void VMdEditOperations::insertImageFromPath(const QString &p_title,
@@ -121,7 +148,9 @@ void VMdEditOperations::insertImageFromPath(const QString &p_title,
                                             const QString &p_srcImagePath,
                                             bool p_insertText,
                                             QString &p_destImagePath,
-                                            QString &p_urlInLink)
+                                            QString &p_urlInLink,
+                                            int p_width,
+                                            int p_height)
 {
     p_destImagePath.clear();
     p_urlInLink.clear();
@@ -161,8 +190,7 @@ void VMdEditOperations::insertImageFromPath(const QString &p_title,
     p_destImagePath = filePath;
 
     if (p_insertText) {
-        QString md = QString("![%1](%2)").arg(p_title).arg(p_urlInLink);
-        insertText(md);
+        insertText(imageLink(p_title, p_urlInLink, p_width, p_height));
     }
 
     qDebug() << "insert image" << p_title << filePath;
@@ -214,18 +242,21 @@ bool VMdEditOperations::insertImageFromURL(const QUrl &imageUrl)
             insertImageFromPath(dialog.getImageTitleInput(),
                                 m_file->fetchImageFolderPath(),
                                 m_file->getImageFolderInLink(),
-                                imagePath);
+                                imagePath,
+                                dialog.getOverridenWidth());
         } else {
             if (dialog.getImageType() == VInsertImageDialog::ImageType::LocalFile) {
                 insertImageFromPath(dialog.getImageTitleInput(),
                                     m_file->fetchImageFolderPath(),
                                     m_file->getImageFolderInLink(),
-                                    dialog.getPathInput());
+                                    dialog.getPathInput(),
+                                    dialog.getOverridenWidth());
             } else {
                 insertImageFromQImage(dialog.getImageTitleInput(),
                                       m_file->fetchImageFolderPath(),
                                       m_file->getImageFolderInLink(),
-                                      dialog.getImage());
+                                      dialog.getImage(),
+                                      dialog.getOverridenWidth());
             }
         }
     }
@@ -246,14 +277,16 @@ bool VMdEditOperations::insertImage()
             insertImageFromPath(dialog.getImageTitleInput(),
                                 m_file->fetchImageFolderPath(),
                                 m_file->getImageFolderInLink(),
-                                dialog.getPathInput());
+                                dialog.getPathInput(),
+                                dialog.getOverridenWidth());
         } else {
             QImage img = dialog.getImage();
             if (!img.isNull()) {
                 insertImageFromQImage(dialog.getImageTitleInput(),
                                       m_file->fetchImageFolderPath(),
                                       m_file->getImageFolderInLink(),
-                                      img);
+                                      img,
+                                      dialog.getOverridenWidth());
             }
         }
     }
@@ -1168,9 +1201,8 @@ bool VMdEditOperations::insertLink(const QString &p_linkText,
 bool VMdEditOperations::insertImageLink(const QString &p_linkText,
                                         const QString &p_linkUrl)
 {
-    QString link = QString("![%1](%2)").arg(p_linkText).arg(p_linkUrl);
     QTextCursor cursor = m_editor->textCursorW();
-    cursor.insertText(link);
+    cursor.insertText(imageLink(p_linkText, p_linkUrl));
     m_editor->setTextCursorW(cursor);
 
     setVimMode(VimMode::Insert);

+ 17 - 9
src/vmdeditoperations.h

@@ -41,7 +41,9 @@ public:
                              const QString &p_srcImagePath,
                              bool p_insertText,
                              QString &p_destImagePath,
-                             QString &p_urlInLink);
+                             QString &p_urlInLink,
+                             int p_width = 0,
+                             int p_height = 0);
 
 private:
     // Insert image from @p_srcImagePath as to @p_folderPath.
@@ -49,14 +51,20 @@ private:
     void insertImageFromPath(const QString &p_title,
                              const QString &p_folderPath,
                              const QString &p_folderInLink,
-                             const QString &p_srcImagePath);
-
-    // @title: title of the inserted image;
-    // @path: the image folder path to insert the image in;
-    // @folderInLink: the folder part in the image link.
-    // @image: the image to be inserted;
-    void insertImageFromQImage(const QString &title, const QString &path,
-                               const QString &folderInLink, const QImage &image);
+                             const QString &p_srcImagePath,
+                             int p_width = 0,
+                             int p_height = 0);
+
+    // @p_title: title of the inserted image;
+    // @p_folderPath: the image folder path to insert the image in;
+    // @p_folderInLink: the folder part in the image link.
+    // @p_image: the image to be inserted;
+    void insertImageFromQImage(const QString &p_title,
+                               const QString &p_folderPath,
+                               const QString &p_folderInLink,
+                               const QImage &p_image,
+                               int p_width = 0,
+                               int p_height = 0);
 
     // Key press handlers.
     bool handleKeyTab(QKeyEvent *p_event);