diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 93e574d8..3e9785f3 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -20,10 +20,16 @@ enable_mermaid=false enable_mathjax=false ; -1 - calculate the factor web_zoom_factor=-1 + ; Syntax highlight within code blocks in edit mode enable_code_block_highlight=true + +; Enable image preview in edit mode enable_preview_images=true +; Enable image preview constraint in edit mode to constrain the widht of the preview +enable_preview_image_constraint=false + [session] tools_dock_checked=true diff --git a/src/translations/vnote_zh_CN.qm b/src/translations/vnote_zh_CN.qm index a237559f..f390e172 100644 Binary files a/src/translations/vnote_zh_CN.qm and b/src/translations/vnote_zh_CN.qm differ diff --git a/src/translations/vnote_zh_CN.ts b/src/translations/vnote_zh_CN.ts index 7de4d36c..8cc39c8f 100644 --- a/src/translations/vnote_zh_CN.ts +++ b/src/translations/vnote_zh_CN.ts @@ -694,7 +694,7 @@ - + &Edit 编辑 (&E) @@ -789,229 +789,239 @@ 编辑模式中启用图片预览 - + + Constrain The Width Of Previewed Images + 限制预览图片宽度 + + + + Constrain the width of previewed images to the edit window in edit mode + 编辑模式中根据编辑窗口大小限制预览图片的宽度 + + + &View 查看 (&V) - + &File 文件 (&F) - + &Import Notes From Files 导入文件 (&I) - + Import notes from files into current directory 从文件中导入笔记到当前目录 - + Settings 设置 - + View and change settings for VNote 查看并更改VNote的配置 - + Exit 退出 - + Exit VNote 退出VNote - + Insert &Image 插入图片 (&I) - - + + Find/Replace 查找/替换 - + Open Find/Replace dialog to search in current note 打开查找/替换对话框以在当前笔记中查找 - + Find Next 查找下一个 - + Find next occurence 查找下一处出现 - + Find Previous 查找上一个 - + Find previous occurence 查找上一处出现 - + Replace 替换 - + Replace current occurence 替换当前出现 - + Replace && Find 替换并查找 - + Replace current occurence and find the next one 替换当前出现并查找下一个 - + Replace All 全部替换 - + Replace all occurences in current note 替换当前笔记中的所有出现 - + Highlight Searched Pattern 高亮查找模式 - + Highlight all occurences of searched pattern 高亮查找模式的所有出现 - + &Expand Tab 扩展Tab (&E) - + Expand entered Tab to spaces 将输入的Tab扩展为空格 - + Expand Tab to 2 spaces 扩展Tab为2个空格 - + Expand Tab to 4 spaces 扩展Tab为4个空格 - + Expand Tab to 8 spaces 扩展Tab为8个空格 - + Auto Indent 自动缩进 - + Indent automatically when inserting a new line 插入新行时自动缩进 - + Auto List 自动列表 - + Continue the list automatically when inserting a new line 插入新行时自动继续列表 - + Highlight Selected Words 高亮选定字词 - + Highlight all occurences of selected words 高亮选定字词的所有出现 - + Select Files (HTML or Markdown) To Import 选择需要导入的文件(HTML或Markdown) - + Import Notes From File 导入文件 - + Imported notes: %1 succeed, %2 failed. 已导入笔记: %1 成功, %2 失败。 - + Use system's background color configuration for Markdown rendering 使用系统的背景色设置对Markdown进行渲染 - + Set as the background color for Markdown rendering 使用该背景色对Markdown进行渲染 - - + + &Add Style 添加样式 (&A) - + Open the folder to add your custom CSS style files 打开样式文件夹以添加自定义CSS样式文件 - + Editor &Style 编辑器样式 (&S) - + Open the folder to add your custom MDHL style files 打开样式文件夹以添加自定义MDHL样式文件 - + Set as the editor style 使用该样式设置编辑器 - + 2 Spaces 2个空格 @@ -1086,103 +1096,103 @@ 编辑模式中启用代码块语法高亮 - + Insert an image from file into current note 从文件中插入图片到当前笔记 - + 4 Spaces 4个空格 - + 8 Spaces 8个空格 - + Highlight Cursor Line 高亮光标所在行 - + Highlight current cursor line 高亮当前光标所在行 - + Tab Stop Width Tab Stop宽度 - + Tools 工具 - + Outline 大纲 - + Fail to import files maybe due to name conflicts. 导入文件失败 (可能是因为名字冲突)。 - + v%1 v %1 - + VNote is a Vim-inspired note-taking application for Markdown. VNote是一个受Vim启发而开发的专注于Markdown的笔记软件。 - + Visit https://github.com/tamlok/vnote.git for more information. 更多信息请访问 https://github.com/tamlok/vnote.git。 - + About VNote 关于VNote - + &Rendering Background 渲染背景 (&R) - - + + System 默认 - + Rendering &Style 渲染样式 (&S) - + Set as the CSS style for Markdown rendering 使用该CSS样式对Markdown进行渲染 - + &Background Color 背景颜色 (&B) - + Use system's background color configuration for editor 为编辑器使用系统的背景色设置 - + Set as the background color for editor 使用该背景色设置编辑器 diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index ba219966..be0387d5 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -126,6 +126,9 @@ void VConfigManager::initialize() m_enablePreviewImages = getConfigFromSettings("global", "enable_preview_images").toBool(); + + m_enablePreviewImageConstraint = getConfigFromSettings("global", + "enable_preview_image_constraint").toBool(); } void VConfigManager::readPredefinedColorsFromSettings() diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 35e70edc..54cf483a 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -160,6 +160,9 @@ public: inline bool getEnablePreviewImages() const; inline void setEnablePreviewImages(bool p_enabled); + inline bool getEnablePreviewImageConstraint() const; + inline void setEnablePreviewImageConstraint(bool p_enabled); + // Get the folder the ini file exists. QString getConfigFolder() const; @@ -270,6 +273,9 @@ private: // Preview images in edit mode. bool m_enablePreviewImages; + // Constrain the width of image preview in edit mode. + bool m_enablePreviewImageConstraint; + // The name of the config file in each directory, obsolete. // Use c_dirConfigFile instead. static const QString c_obsoleteDirConfigFile; @@ -711,4 +717,20 @@ inline void VConfigManager::setEnablePreviewImages(bool p_enabled) m_enablePreviewImages); } +inline bool VConfigManager::getEnablePreviewImageConstraint() const +{ + return m_enablePreviewImageConstraint; +} + +inline void VConfigManager::setEnablePreviewImageConstraint(bool p_enabled) +{ + if (m_enablePreviewImageConstraint == p_enabled) { + return; + } + + m_enablePreviewImageConstraint = p_enabled; + setConfigToSettings("global", "enable_preview_image_constraint", + m_enablePreviewImageConstraint); +} + #endif // VCONFIGMANAGER_H diff --git a/src/vimagepreviewer.cpp b/src/vimagepreviewer.cpp index 4510199d..5f1cff59 100644 --- a/src/vimagepreviewer.cpp +++ b/src/vimagepreviewer.cpp @@ -15,10 +15,13 @@ extern VConfigManager vconfig; enum ImageProperty { ImagePath = 1 }; +const int VImagePreviewer::c_minImageWidth = 100; + VImagePreviewer::VImagePreviewer(VMdEdit *p_edit, int p_timeToPreview) : QObject(p_edit), m_edit(p_edit), m_document(p_edit->document()), m_file(p_edit->getFile()), m_enablePreview(true), m_isPreviewing(false), - m_requestCearBlocks(false), m_requestRefreshBlocks(false) + m_requestCearBlocks(false), m_requestRefreshBlocks(false), + m_updatePending(false), m_imageWidth(c_minImageWidth) { m_timer = new QTimer(this); m_timer->setSingleShot(true); @@ -49,6 +52,11 @@ void VImagePreviewer::timerTimeout() return; } + if (m_isPreviewing) { + m_updatePending = true; + return; + } + previewImages(); } @@ -70,6 +78,9 @@ void VImagePreviewer::previewImages() return; } + // Get the width of the m_edit. + m_imageWidth = qMax(m_edit->size().width() - 50, c_minImageWidth); + m_isPreviewing = true; QTextBlock block = m_document->begin(); while (block.isValid() && m_enablePreview) { @@ -101,6 +112,12 @@ void VImagePreviewer::previewImages() refresh(); } + if (m_updatePending) { + m_updatePending = false; + m_timer->stop(); + m_timer->start(); + } + emit m_edit->statusChanged(); } @@ -224,6 +241,9 @@ QTextBlock VImagePreviewer::insertImagePreviewBlock(QTextBlock &p_block, QTextImageFormat imgFormat; imgFormat.setName(imageName); imgFormat.setProperty(ImagePath, p_imagePath); + + updateImageWidth(imgFormat); + cursor.insertImage(imgFormat); cursor.endEditBlock(); @@ -240,13 +260,18 @@ void VImagePreviewer::updateImagePreviewBlock(QTextBlock &p_block, QTextImageFormat format = fetchFormatFromPreviewBlock(p_block); V_ASSERT(format.isValid()); QString curPath = format.property(ImagePath).toString(); + QString imageName; if (curPath == p_imagePath) { + if (updateImageWidth(format)) { + goto update; + } + return; } // Update it with the new image. - QString imageName = imageCacheResourceName(p_imagePath); + imageName = imageCacheResourceName(p_imagePath); if (imageName.isEmpty()) { // Delete current preview block. removeBlock(p_block); @@ -255,6 +280,10 @@ void VImagePreviewer::updateImagePreviewBlock(QTextBlock &p_block, format.setName(imageName); format.setProperty(ImagePath, p_imagePath); + + updateImageWidth(format); + +update: updateFormatInPreviewBlock(p_block, format); } @@ -391,7 +420,10 @@ QTextImageFormat VImagePreviewer::fetchFormatFromPreviewBlock(QTextBlock &p_bloc void VImagePreviewer::updateFormatInPreviewBlock(QTextBlock &p_block, const QTextImageFormat &p_format) { + bool modified = m_edit->isModified(); + QTextCursor cursor(p_block); + cursor.beginEditBlock(); int shift = p_block.text().indexOf(QChar::ObjectReplacementCharacter); if (shift > 0) { cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, shift); @@ -403,6 +435,9 @@ void VImagePreviewer::updateFormatInPreviewBlock(QTextBlock &p_block, V_ASSERT(cursor.charFormat().toImageFormat().isValid()); cursor.setCharFormat(p_format); + cursor.endEditBlock(); + + m_edit->setModified(modified); } QString VImagePreviewer::imageCacheResourceName(const QString &p_imagePath) @@ -411,7 +446,7 @@ QString VImagePreviewer::imageCacheResourceName(const QString &p_imagePath) auto it = m_imageCache.find(p_imagePath); if (it != m_imageCache.end()) { - return it.value(); + return it.value().m_name; } // Add it to the resource cache even if it may exist there. @@ -431,7 +466,7 @@ QString VImagePreviewer::imageCacheResourceName(const QString &p_imagePath) QString name(imagePathToCacheResourceName(p_imagePath)); m_document->addResource(QTextDocument::ImageResource, name, image); - m_imageCache.insert(p_imagePath, name); + m_imageCache.insert(p_imagePath, ImageInfo(name, image.width())); return name; } @@ -454,7 +489,7 @@ void VImagePreviewer::imageDownloaded(const QByteArray &p_data, const QString &p m_timer->stop(); QString name(imagePathToCacheResourceName(p_url)); m_document->addResource(QTextDocument::ImageResource, name, image); - m_imageCache.insert(p_url, name); + m_imageCache.insert(p_url, ImageInfo(name, image.width())); qDebug() << "downloaded image cache insert" << p_url << name; @@ -487,5 +522,31 @@ QImage VImagePreviewer::fetchCachedImageFromPreviewBlock(QTextBlock &p_block) return QImage(); } - return m_document->resource(QTextDocument::ImageResource, it.value()).value(); + return m_document->resource(QTextDocument::ImageResource, it.value().m_name).value(); +} + +bool VImagePreviewer::updateImageWidth(QTextImageFormat &p_format) +{ + QString path = p_format.property(ImagePath).toString(); + auto it = m_imageCache.find(path); + + if (it != m_imageCache.end()) { + int newWidth = it.value().m_width; + if (vconfig.getEnablePreviewImageConstraint()) { + newWidth = qMin(m_imageWidth, it.value().m_width); + } + + if (newWidth != p_format.width()) { + p_format.setWidth(newWidth); + return true; + } + } + + return false; +} + +void VImagePreviewer::update() +{ + m_timer->stop(); + m_timer->start(); } diff --git a/src/vimagepreviewer.h b/src/vimagepreviewer.h index 7620ee93..afd17adc 100644 --- a/src/vimagepreviewer.h +++ b/src/vimagepreviewer.h @@ -30,12 +30,25 @@ public: // Then re-preview all the blocks. void refresh(); + void update(); + private slots: void timerTimeout(); void handleContentChange(int p_position, int p_charsRemoved, int p_charsAdded); void imageDownloaded(const QByteArray &p_data, const QString &p_url); private: + struct ImageInfo + { + ImageInfo(const QString &p_name, int p_width) + : m_name(p_name), m_width(p_width) + { + } + + QString m_name; + int m_width; + }; + void previewImages(); bool isValidImagePreviewBlock(QTextBlock &p_block); @@ -77,6 +90,9 @@ private: QString imagePathToCacheResourceName(const QString &p_imagePath); + // Return true if and only if there is update. + bool updateImageWidth(QTextImageFormat &p_format); + VMdEdit *m_edit; QTextDocument *m_document; VFile *m_file; @@ -85,11 +101,17 @@ private: bool m_isPreviewing; bool m_requestCearBlocks; bool m_requestRefreshBlocks; + bool m_updatePending; // Map from image full path to QUrl identifier in the QTextDocument's cache. - QHash m_imageCache;; + QHash m_imageCache;; VDownloader *m_downloader; + + // The preview width. + int m_imageWidth; + + static const int c_minImageWidth; }; #endif // VIMAGEPREVIEWER_H diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index 50b87689..b0e41e3e 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -390,6 +390,14 @@ void VMainWindow::initMarkdownMenu() // TODO: add the action to the menu after handling the UNDO history well. // markdownMenu->addAction(previewImageAct); previewImageAct->setChecked(vconfig.getEnablePreviewImages()); + + QAction *previewWidthAct = new QAction(tr("Constrain The Width Of Previewed Images"), this); + previewWidthAct->setToolTip(tr("Constrain the width of previewed images to the edit window in edit mode")); + previewWidthAct->setCheckable(true); + connect(previewWidthAct, &QAction::triggered, + this, &VMainWindow::enableImagePreviewConstraint); + markdownMenu->addAction(previewWidthAct); + previewWidthAct->setChecked(vconfig.getEnablePreviewImageConstraint()); } void VMainWindow::initViewMenu() @@ -1288,6 +1296,11 @@ void VMainWindow::enableImagePreview(bool p_checked) vconfig.setEnablePreviewImages(p_checked); } +void VMainWindow::enableImagePreviewConstraint(bool p_checked) +{ + vconfig.setEnablePreviewImageConstraint(p_checked); +} + void VMainWindow::shortcutHelp() { QString locale = VUtils::getLocale(); diff --git a/src/vmainwindow.h b/src/vmainwindow.h index 9f4a555b..530e84ef 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -77,6 +77,7 @@ private slots: void changeAutoList(bool p_checked); void enableCodeBlockHighlight(bool p_checked); void enableImagePreview(bool p_checked); + void enableImagePreviewConstraint(bool p_checked); protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 8470ff54..3101ebea 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -387,3 +387,10 @@ QImage VMdEdit::selectedImage() } return image; } + +void VMdEdit::resizeEvent(QResizeEvent *p_event) +{ + m_imagePreviewer->update(); + + VEdit::resizeEvent(p_event); +} diff --git a/src/vmdedit.h b/src/vmdedit.h index b1e0ddec..7358acaf 100644 --- a/src/vmdedit.h +++ b/src/vmdedit.h @@ -52,6 +52,7 @@ protected: bool canInsertFromMimeData(const QMimeData *source) const Q_DECL_OVERRIDE; void insertFromMimeData(const QMimeData *source) Q_DECL_OVERRIDE; void updateFontAndPalette() Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE; private: void initInitImages();