mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
547 lines
20 KiB
C++
547 lines
20 KiB
C++
#include "previewhelper.h"
|
|
|
|
#include <QDebug>
|
|
#include <QTextDocument>
|
|
#include <QTextBlock>
|
|
#include <QTimer>
|
|
|
|
#include <vtextedit/texteditorconfig.h>
|
|
#include <vtextedit/textutils.h>
|
|
|
|
#include <utils/utils.h>
|
|
|
|
#include "markdowneditor.h"
|
|
#include "plantumlhelper.h"
|
|
#include "graphvizhelper.h"
|
|
|
|
using namespace vnotex;
|
|
|
|
PreviewHelper::CodeBlockPreviewData::CodeBlockPreviewData(const vte::peg::FencedCodeBlock &p_codeBlock)
|
|
: m_startBlock(p_codeBlock.m_startBlock),
|
|
m_endBlock(p_codeBlock.m_endBlock),
|
|
m_lang(p_codeBlock.m_lang)
|
|
{
|
|
}
|
|
|
|
void PreviewHelper::CodeBlockPreviewData::updateInplacePreview(QTextDocument *p_doc,
|
|
const QPixmap &p_image,
|
|
const QString &p_imageName,
|
|
QRgb p_background,
|
|
int p_tabStopWidth)
|
|
{
|
|
const auto block = p_doc->findBlockByNumber(m_endBlock);
|
|
if (block.isValid()) {
|
|
m_inplacePreview.reset(new vte::PreviewItem());
|
|
m_inplacePreview->m_startPos = block.position();
|
|
m_inplacePreview->m_endPos = m_inplacePreview->m_startPos + block.length();
|
|
m_inplacePreview->m_blockPos = m_inplacePreview->m_startPos;
|
|
m_inplacePreview->m_blockNumber = m_endBlock;
|
|
m_inplacePreview->m_padding = vte::PreviewMgr::calculateBlockMargin(block, p_tabStopWidth);
|
|
m_inplacePreview->m_name = p_imageName;
|
|
m_inplacePreview->m_backgroundColor = p_background;
|
|
m_inplacePreview->m_isBlockwise = true;
|
|
m_inplacePreview->m_image = p_image;
|
|
} else {
|
|
m_inplacePreview.clear();
|
|
}
|
|
}
|
|
|
|
PreviewHelper::MathBlockPreviewData::MathBlockPreviewData(const vte::peg::MathBlock &p_mathBlock)
|
|
: m_blockNumber(p_mathBlock.m_blockNumber),
|
|
m_previewedAsBlock(p_mathBlock.m_previewedAsBlock),
|
|
m_index(p_mathBlock.m_index),
|
|
m_length(p_mathBlock.m_length)
|
|
{
|
|
}
|
|
|
|
void PreviewHelper::MathBlockPreviewData::updateInplacePreview(QTextDocument *p_doc,
|
|
const QPixmap &p_image,
|
|
const QString &p_imageName,
|
|
int p_tabStopWidth)
|
|
{
|
|
const auto block = p_doc->findBlockByNumber(m_blockNumber);
|
|
if (block.isValid()) {
|
|
m_inplacePreview.reset(new vte::PreviewItem());
|
|
m_inplacePreview->m_startPos = block.position() + m_index;
|
|
m_inplacePreview->m_endPos = m_inplacePreview->m_startPos + m_length;
|
|
m_inplacePreview->m_blockPos = block.position();
|
|
m_inplacePreview->m_blockNumber = m_blockNumber;
|
|
m_inplacePreview->m_padding = vte::PreviewMgr::calculateBlockMargin(block, p_tabStopWidth);
|
|
m_inplacePreview->m_name = p_imageName;
|
|
m_inplacePreview->m_isBlockwise = m_previewedAsBlock;
|
|
m_inplacePreview->m_image = p_image;
|
|
} else {
|
|
m_inplacePreview.clear();
|
|
}
|
|
}
|
|
|
|
int PreviewHelper::GraphPreviewData::s_imageIndex = 0;
|
|
|
|
PreviewHelper::GraphPreviewData::GraphPreviewData(TimeStamp p_timeStamp,
|
|
const QString &p_format,
|
|
const QByteArray &p_data,
|
|
QRgb p_background,
|
|
qreal p_scaleFactor)
|
|
: m_timeStamp(p_timeStamp),
|
|
m_background(p_background)
|
|
{
|
|
if (p_data.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
m_name = QString::number(++s_imageIndex);
|
|
|
|
bool needScale = p_scaleFactor > 1.01;
|
|
if (needScale) {
|
|
if (p_format == QStringLiteral("svg")) {
|
|
m_image = Utils::svgToPixmap(p_data, p_background, p_scaleFactor);
|
|
} else {
|
|
QPixmap tmpImg;
|
|
tmpImg.loadFromData(p_data, p_format.toLocal8Bit().data());
|
|
m_image = tmpImg.scaledToWidth(tmpImg.width() * p_scaleFactor, Qt::SmoothTransformation);
|
|
}
|
|
} else {
|
|
m_image.loadFromData(p_data, p_format.toLocal8Bit().data());
|
|
}
|
|
}
|
|
|
|
bool PreviewHelper::GraphPreviewData::isNull() const
|
|
{
|
|
return m_timeStamp == 0;
|
|
}
|
|
|
|
PreviewHelper::PreviewHelper(MarkdownEditor *p_editor, QObject *p_parent)
|
|
: QObject(p_parent),
|
|
m_inplacePreviewSources(SourceFlag::FlowChart
|
|
| SourceFlag::Mermaid
|
|
| SourceFlag::WaveDrom
|
|
| SourceFlag::PlantUml
|
|
| SourceFlag::Graphviz
|
|
| SourceFlag::Math),
|
|
m_codeBlockCache(100, nullptr),
|
|
m_mathBlockCache(100, nullptr)
|
|
{
|
|
setMarkdownEditor(p_editor);
|
|
|
|
const int interval = 1000;
|
|
m_codeBlockTimer = new QTimer(this);
|
|
m_codeBlockTimer->setSingleShot(true);
|
|
m_codeBlockTimer->setInterval(interval);
|
|
connect(m_codeBlockTimer, &QTimer::timeout,
|
|
this, &PreviewHelper::handleCodeBlocksUpdate);
|
|
|
|
m_mathBlockTimer = new QTimer(this);
|
|
m_mathBlockTimer->setSingleShot(true);
|
|
m_mathBlockTimer->setInterval(interval);
|
|
connect(m_mathBlockTimer, &QTimer::timeout,
|
|
this, &PreviewHelper::handleMathBlocksUpdate);
|
|
}
|
|
|
|
void PreviewHelper::codeBlocksUpdated(vte::TimeStamp p_timeStamp,
|
|
const QVector<vte::peg::FencedCodeBlock> &p_codeBlocks)
|
|
{
|
|
Q_UNUSED(p_timeStamp);
|
|
if (!m_inplacePreviewCodeBlocksEnabled) {
|
|
return;
|
|
}
|
|
|
|
m_pendingCodeBlocks = p_codeBlocks;
|
|
m_codeBlockTimer->start();
|
|
}
|
|
|
|
void PreviewHelper::handleCodeBlocksUpdate()
|
|
{
|
|
++m_codeBlockTimeStamp;
|
|
m_codeBlocksData.clear();
|
|
|
|
QVector<int> needPreviewBlocks;
|
|
|
|
for (int i = 0; i < m_pendingCodeBlocks.size(); ++i) {
|
|
const auto &cb = m_pendingCodeBlocks[i];
|
|
|
|
const auto needPreview = isLangNeedPreview(cb.m_lang);
|
|
if (!needPreview.first && !needPreview.second) {
|
|
continue;
|
|
}
|
|
|
|
m_codeBlocksData.append(CodeBlockPreviewData(cb));
|
|
const int blockPreviewIdx = m_codeBlocksData.size() - 1;
|
|
|
|
bool cacheHit = false;
|
|
auto &cachedData = m_codeBlockCache.get(cb.m_text);
|
|
if (cachedData) {
|
|
cacheHit = true;
|
|
cachedData->m_timeStamp = m_codeBlockTimeStamp;
|
|
m_codeBlocksData[blockPreviewIdx].updateInplacePreview(m_document,
|
|
cachedData->m_image,
|
|
cachedData->m_name,
|
|
cachedData->m_background,
|
|
m_tabStopWidth);
|
|
}
|
|
|
|
if (m_inplacePreviewCodeBlocksEnabled && needPreview.first && !cacheHit) {
|
|
m_codeBlocksData[blockPreviewIdx].m_text = cb.m_text;
|
|
needPreviewBlocks.push_back(blockPreviewIdx);
|
|
}
|
|
}
|
|
|
|
for (auto idx : needPreviewBlocks) {
|
|
inplacePreviewCodeBlock(idx);
|
|
}
|
|
|
|
updateEditorInplacePreviewCodeBlock();
|
|
|
|
m_pendingCodeBlocks.clear();
|
|
}
|
|
|
|
bool PreviewHelper::checkPreviewSourceLang(SourceFlag p_flag, const QString &p_lang) const
|
|
{
|
|
switch (p_flag) {
|
|
case SourceFlag::FlowChart:
|
|
return p_lang == QStringLiteral("flow") || p_lang == QStringLiteral("flowchart");
|
|
|
|
case SourceFlag::WaveDrom:
|
|
return p_lang == QStringLiteral("wavedrom");
|
|
|
|
case SourceFlag::Mermaid:
|
|
return p_lang == QStringLiteral("mermaid");
|
|
|
|
case SourceFlag::PlantUml:
|
|
return p_lang == QStringLiteral("puml") || p_lang == QStringLiteral("plantuml");
|
|
|
|
case SourceFlag::Graphviz:
|
|
return p_lang == QStringLiteral("dot") || p_lang == QStringLiteral("graphviz");
|
|
|
|
case SourceFlag::Math:
|
|
return p_lang == QStringLiteral("mathjax");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QPair<bool, bool> PreviewHelper::isLangNeedPreview(const QString &p_lang) const
|
|
{
|
|
QPair<bool, bool> res(false, false);
|
|
if ((isInplacePreviewSourceEnabled(SourceFlag::FlowChart) && checkPreviewSourceLang(SourceFlag::FlowChart, p_lang))
|
|
|| (isInplacePreviewSourceEnabled(SourceFlag::WaveDrom) && checkPreviewSourceLang(SourceFlag::WaveDrom, p_lang))
|
|
|| (isInplacePreviewSourceEnabled(SourceFlag::Mermaid) && checkPreviewSourceLang(SourceFlag::Mermaid, p_lang))
|
|
|| (isInplacePreviewSourceEnabled(SourceFlag::PlantUml) && checkPreviewSourceLang(SourceFlag::PlantUml, p_lang))
|
|
|| (isInplacePreviewSourceEnabled(SourceFlag::Graphviz) && checkPreviewSourceLang(SourceFlag::Graphviz, p_lang))
|
|
|| (isInplacePreviewSourceEnabled(SourceFlag::Math) && checkPreviewSourceLang(SourceFlag::Math, p_lang))) {
|
|
res.first = res.second = true;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
bool PreviewHelper::isInplacePreviewSourceEnabled(SourceFlag p_flag) const
|
|
{
|
|
return m_inplacePreviewSources & p_flag;
|
|
}
|
|
|
|
void PreviewHelper::inplacePreviewCodeBlock(int p_blockPreviewIdx)
|
|
{
|
|
const auto &blockData = m_codeBlocksData[p_blockPreviewIdx];
|
|
Q_ASSERT(!blockData.m_text.isEmpty());
|
|
if (checkPreviewSourceLang(SourceFlag::FlowChart, blockData.m_lang)
|
|
|| checkPreviewSourceLang(SourceFlag::WaveDrom, blockData.m_lang)
|
|
|| checkPreviewSourceLang(SourceFlag::Mermaid, blockData.m_lang)
|
|
|| (checkPreviewSourceLang(SourceFlag::PlantUml, blockData.m_lang) && m_webPlantUmlEnabled)
|
|
|| (checkPreviewSourceLang(SourceFlag::Graphviz, blockData.m_lang) && m_webGraphvizEnabled)
|
|
|| checkPreviewSourceLang(SourceFlag::Math, blockData.m_lang)) {
|
|
emit graphPreviewRequested(p_blockPreviewIdx,
|
|
m_codeBlockTimeStamp,
|
|
blockData.m_lang,
|
|
vte::TextUtils::removeCodeBlockFence(blockData.m_text));
|
|
return;
|
|
}
|
|
|
|
if (!m_webPlantUmlEnabled && checkPreviewSourceLang(SourceFlag::PlantUml, blockData.m_lang)) {
|
|
// Local PlantUml.
|
|
PlantUmlHelper::getInst().process(static_cast<quint64>(p_blockPreviewIdx),
|
|
m_codeBlockTimeStamp,
|
|
QStringLiteral("svg"),
|
|
vte::TextUtils::removeCodeBlockFence(blockData.m_text),
|
|
this,
|
|
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
|
handleLocalData(id, timeStamp, format, data, true);
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!m_webGraphvizEnabled && checkPreviewSourceLang(SourceFlag::Graphviz, blockData.m_lang)) {
|
|
// Local PlantUml.
|
|
GraphvizHelper::getInst().process(static_cast<quint64>(p_blockPreviewIdx),
|
|
m_codeBlockTimeStamp,
|
|
QStringLiteral("svg"),
|
|
vte::TextUtils::removeCodeBlockFence(blockData.m_text),
|
|
this,
|
|
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
|
handleLocalData(id, timeStamp, format, data, false);
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
void PreviewHelper::handleGraphPreviewData(const MarkdownViewerAdapter::PreviewData &p_data)
|
|
{
|
|
if (p_data.m_timeStamp != m_codeBlockTimeStamp) {
|
|
return;
|
|
}
|
|
if (p_data.m_id >= static_cast<quint64>(m_codeBlocksData.size()) || p_data.m_data.isEmpty()) {
|
|
updateEditorInplacePreviewCodeBlock();
|
|
return;
|
|
}
|
|
|
|
auto &blockData = m_codeBlocksData[p_data.m_id];
|
|
const bool forcedBackground = needForcedBackground(blockData.m_lang);
|
|
auto previewData = QSharedPointer<GraphPreviewData>::create(p_data.m_timeStamp,
|
|
p_data.m_format,
|
|
p_data.m_data,
|
|
forcedBackground ? m_editor->getPreviewBackground() : 0,
|
|
p_data.m_needScale ? getEditorScaleFactor() : 1);
|
|
m_codeBlockCache.set(blockData.m_text, previewData);
|
|
blockData.m_text.clear();
|
|
|
|
blockData.updateInplacePreview(m_document,
|
|
previewData->m_image,
|
|
previewData->m_name,
|
|
previewData->m_background,
|
|
m_tabStopWidth);
|
|
|
|
updateEditorInplacePreviewCodeBlock();
|
|
}
|
|
|
|
void PreviewHelper::updateEditorInplacePreviewCodeBlock()
|
|
{
|
|
QSet<int> obsoleteBlocks;
|
|
QVector<QSharedPointer<vte::PreviewItem>> previewItems;
|
|
previewItems.reserve(m_codeBlocksData.size());
|
|
for (const auto &blockData : m_codeBlocksData) {
|
|
if (blockData.m_inplacePreview) {
|
|
if (!blockData.m_inplacePreview->m_image.isNull()) {
|
|
previewItems.append(blockData.m_inplacePreview);
|
|
} else {
|
|
obsoleteBlocks.insert(blockData.m_inplacePreview->m_blockNumber);
|
|
}
|
|
} else {
|
|
obsoleteBlocks.insert(blockData.m_endBlock);
|
|
}
|
|
}
|
|
|
|
if (previewItems.isEmpty() && m_previousInplacePreviewCodeBlockSize == 0) {
|
|
return;
|
|
}
|
|
|
|
emit inplacePreviewCodeBlockUpdated(previewItems);
|
|
|
|
m_previousInplacePreviewCodeBlockSize = previewItems.size();
|
|
|
|
if (!obsoleteBlocks.isEmpty()) {
|
|
emit potentialObsoletePreviewBlocksUpdated(obsoleteBlocks.values());
|
|
}
|
|
|
|
m_codeBlockCache.setCapacityHint(m_codeBlocksData.size());
|
|
}
|
|
|
|
void PreviewHelper::setMarkdownEditor(MarkdownEditor *p_editor)
|
|
{
|
|
Q_ASSERT(!m_editor);
|
|
m_editor = p_editor;
|
|
if (m_editor) {
|
|
m_document = m_editor->document();
|
|
m_tabStopWidth = m_editor->getConfig().m_tabStopWidth;
|
|
}
|
|
}
|
|
|
|
void PreviewHelper::mathBlocksUpdated(const QVector<vte::peg::MathBlock> &p_mathBlocks)
|
|
{
|
|
if (!m_inplacePreviewMathBlocksEnabled || !isInplacePreviewSourceEnabled(SourceFlag::Math)) {
|
|
return;
|
|
}
|
|
|
|
m_pendingMathBlocks = p_mathBlocks;
|
|
m_mathBlockTimer->start();
|
|
}
|
|
|
|
void PreviewHelper::handleMathBlocksUpdate()
|
|
{
|
|
++m_mathBlockTimeStamp;
|
|
m_mathBlocksData.clear();
|
|
m_mathBlocksData.reserve(m_pendingMathBlocks.size());
|
|
|
|
bool needUpdateEditorInplacePreview = true;
|
|
|
|
for (const auto &mb : m_pendingMathBlocks) {
|
|
m_mathBlocksData.append(MathBlockPreviewData(mb));
|
|
const int blockPreviewIdx = m_mathBlocksData.size() - 1;
|
|
|
|
bool cacheHit = false;
|
|
auto &cachedData = m_mathBlockCache.get(mb.m_text);
|
|
if (cachedData) {
|
|
cacheHit = true;
|
|
cachedData->m_timeStamp = m_mathBlockTimeStamp;
|
|
m_mathBlocksData[blockPreviewIdx].updateInplacePreview(m_document,
|
|
cachedData->m_image,
|
|
cachedData->m_name,
|
|
m_tabStopWidth);
|
|
}
|
|
|
|
if (!cacheHit) {
|
|
needUpdateEditorInplacePreview = false;
|
|
m_mathBlocksData[blockPreviewIdx].m_text = mb.m_text;
|
|
inplacePreviewMathBlock(blockPreviewIdx);
|
|
}
|
|
}
|
|
|
|
if (needUpdateEditorInplacePreview) {
|
|
updateEditorInplacePreviewMathBlock();
|
|
}
|
|
|
|
m_pendingMathBlocks.clear();
|
|
}
|
|
|
|
void PreviewHelper::inplacePreviewMathBlock(int p_blockPreviewIdx)
|
|
{
|
|
const auto &blockData = m_mathBlocksData[p_blockPreviewIdx];
|
|
Q_ASSERT(!blockData.m_text.isEmpty());
|
|
emit mathPreviewRequested(p_blockPreviewIdx, m_mathBlockTimeStamp, blockData.m_text);
|
|
}
|
|
|
|
void PreviewHelper::updateEditorInplacePreviewMathBlock()
|
|
{
|
|
QSet<int> obsoleteBlocks;
|
|
QVector<QSharedPointer<vte::PreviewItem>> previewItems;
|
|
previewItems.reserve(m_mathBlocksData.size());
|
|
for (const auto &blockData : m_mathBlocksData) {
|
|
if (blockData.m_inplacePreview) {
|
|
if (!blockData.m_inplacePreview->m_image.isNull()) {
|
|
previewItems.append(blockData.m_inplacePreview);
|
|
} else {
|
|
obsoleteBlocks.insert(blockData.m_inplacePreview->m_blockNumber);
|
|
}
|
|
} else {
|
|
obsoleteBlocks.insert(blockData.m_blockNumber);
|
|
}
|
|
}
|
|
|
|
if (previewItems.isEmpty() && m_previousInplacePreviewMathBlockSize == 0) {
|
|
return;
|
|
}
|
|
|
|
emit inplacePreviewMathBlockUpdated(previewItems);
|
|
|
|
m_previousInplacePreviewMathBlockSize = previewItems.size();
|
|
|
|
if (!obsoleteBlocks.isEmpty()) {
|
|
emit potentialObsoletePreviewBlocksUpdated(obsoleteBlocks.values());
|
|
}
|
|
|
|
m_mathBlockCache.setCapacityHint(m_mathBlocksData.size());
|
|
}
|
|
|
|
void PreviewHelper::handleMathPreviewData(const MarkdownViewerAdapter::PreviewData &p_data)
|
|
{
|
|
if (p_data.m_timeStamp != m_mathBlockTimeStamp) {
|
|
return;
|
|
}
|
|
if (p_data.m_id >= static_cast<quint64>(m_mathBlocksData.size()) || p_data.m_data.isEmpty()) {
|
|
updateEditorInplacePreviewMathBlock();
|
|
return;
|
|
}
|
|
|
|
auto &blockData = m_mathBlocksData[p_data.m_id];
|
|
auto previewData = QSharedPointer<GraphPreviewData>::create(p_data.m_timeStamp,
|
|
p_data.m_format,
|
|
p_data.m_data,
|
|
0,
|
|
p_data.m_needScale ? getEditorScaleFactor() : 1);
|
|
m_mathBlockCache.set(blockData.m_text, previewData);
|
|
blockData.m_text.clear();
|
|
|
|
blockData.updateInplacePreview(m_document,
|
|
previewData->m_image,
|
|
previewData->m_name,
|
|
m_tabStopWidth);
|
|
|
|
updateEditorInplacePreviewMathBlock();
|
|
}
|
|
|
|
qreal PreviewHelper::getEditorScaleFactor() const
|
|
{
|
|
if (m_editor) {
|
|
return m_editor->getConfig().m_scaleFactor;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void PreviewHelper::setWebPlantUmlEnabled(bool p_enabled)
|
|
{
|
|
m_webPlantUmlEnabled = p_enabled;
|
|
}
|
|
|
|
void PreviewHelper::setWebGraphvizEnabled(bool p_enabled)
|
|
{
|
|
m_webGraphvizEnabled = p_enabled;
|
|
}
|
|
|
|
void PreviewHelper::handleLocalData(quint64 p_id,
|
|
TimeStamp p_timeStamp,
|
|
const QString &p_format,
|
|
const QString &p_data,
|
|
bool p_forcedBackground)
|
|
{
|
|
if (p_timeStamp != m_codeBlockTimeStamp) {
|
|
return;
|
|
}
|
|
|
|
Q_UNUSED(p_format);
|
|
Q_ASSERT(p_format == QStringLiteral("svg"));
|
|
|
|
if (p_id >= static_cast<quint64>(m_codeBlocksData.size()) || p_data.isEmpty()) {
|
|
updateEditorInplacePreviewCodeBlock();
|
|
return;
|
|
}
|
|
|
|
auto &blockData = m_codeBlocksData[p_id];
|
|
auto previewData = QSharedPointer<GraphPreviewData>::create(p_timeStamp,
|
|
p_format,
|
|
p_data.toUtf8(),
|
|
p_forcedBackground ? m_editor->getPreviewBackground() : 0,
|
|
getEditorScaleFactor());
|
|
m_codeBlockCache.set(blockData.m_text, previewData);
|
|
blockData.m_text.clear();
|
|
|
|
blockData.updateInplacePreview(m_document,
|
|
previewData->m_image,
|
|
previewData->m_name,
|
|
previewData->m_background,
|
|
m_tabStopWidth);
|
|
|
|
updateEditorInplacePreviewCodeBlock();
|
|
}
|
|
|
|
bool PreviewHelper::needForcedBackground(const QString &p_lang) const
|
|
{
|
|
if (checkPreviewSourceLang(SourceFlag::PlantUml, p_lang)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void PreviewHelper::setInplacePreviewSources(SourceFlags p_srcs)
|
|
{
|
|
m_inplacePreviewSources = p_srcs;
|
|
}
|
|
|
|
void PreviewHelper::setInplacePreviewCodeBlocksEnabled(bool p_enabled)
|
|
{
|
|
m_inplacePreviewCodeBlocksEnabled = p_enabled;
|
|
}
|
|
|
|
void PreviewHelper::setInplacePreviewMathBlocksEnabled(bool p_enabled)
|
|
{
|
|
m_inplacePreviewMathBlocksEnabled = p_enabled;
|
|
}
|