mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
add VPlainTextEdit with custom layout
- Support block images; - Support line number; - Do NOT support line distance height due to constraint of QPlainTextEdit.
This commit is contained in:
parent
a265aed035
commit
5abcb1a8d9
10
src/src.pro
10
src/src.pro
@ -81,7 +81,10 @@ SOURCES += main.cpp\
|
|||||||
vtableofcontent.cpp \
|
vtableofcontent.cpp \
|
||||||
utils/vmetawordmanager.cpp \
|
utils/vmetawordmanager.cpp \
|
||||||
vlineedit.cpp \
|
vlineedit.cpp \
|
||||||
dialog/vinsertlinkdialog.cpp
|
dialog/vinsertlinkdialog.cpp \
|
||||||
|
vplaintextedit.cpp \
|
||||||
|
vimageresourcemanager.cpp \
|
||||||
|
vlinenumberarea.cpp
|
||||||
|
|
||||||
HEADERS += vmainwindow.h \
|
HEADERS += vmainwindow.h \
|
||||||
vdirectorytree.h \
|
vdirectorytree.h \
|
||||||
@ -150,7 +153,10 @@ HEADERS += vmainwindow.h \
|
|||||||
vtableofcontent.h \
|
vtableofcontent.h \
|
||||||
utils/vmetawordmanager.h \
|
utils/vmetawordmanager.h \
|
||||||
vlineedit.h \
|
vlineedit.h \
|
||||||
dialog/vinsertlinkdialog.h
|
dialog/vinsertlinkdialog.h \
|
||||||
|
vplaintextedit.h \
|
||||||
|
vimageresourcemanager.h \
|
||||||
|
vlinenumberarea.h
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
vnote.qrc \
|
vnote.qrc \
|
||||||
|
@ -97,3 +97,8 @@ void VEditOperations::setVimMode(VimMode p_mode)
|
|||||||
m_vim->setMode(p_mode);
|
m_vim->setMode(p_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VEditOperations::decorateText(TextDecoration p_decoration)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_decoration);
|
||||||
|
}
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
void requestUpdateVimStatus();
|
void requestUpdateVimStatus();
|
||||||
|
|
||||||
// Insert decoration markers or decorate selected text.
|
// Insert decoration markers or decorate selected text.
|
||||||
virtual void decorateText(TextDecoration p_decoration) {Q_UNUSED(p_decoration);};
|
virtual void decorateText(TextDecoration p_decoration);
|
||||||
|
|
||||||
// Set Vim mode if not NULL.
|
// Set Vim mode if not NULL.
|
||||||
void setVimMode(VimMode p_mode);
|
void setVimMode(VimMode p_mode);
|
||||||
|
132
src/vimageresourcemanager.cpp
Normal file
132
src/vimageresourcemanager.cpp
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include "vimageresourcemanager.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "vplaintextedit.h"
|
||||||
|
|
||||||
|
|
||||||
|
VImageResourceManager::VImageResourceManager()
|
||||||
|
: m_maximumImageWidth(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::addImage(const QString &p_name,
|
||||||
|
const QPixmap &p_image)
|
||||||
|
{
|
||||||
|
m_images.insert(p_name, p_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VImageResourceManager::contains(const QString &p_name) const
|
||||||
|
{
|
||||||
|
return m_images.contains(p_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::updateBlockInfos(const QVector<VBlockImageInfo> &p_blocksInfo,
|
||||||
|
int p_maximumWidth)
|
||||||
|
{
|
||||||
|
QSet<QString> usedImages;
|
||||||
|
m_blocksInfo.clear();
|
||||||
|
m_maximumImageWidth = 0;
|
||||||
|
|
||||||
|
for (auto const & info : p_blocksInfo) {
|
||||||
|
auto it = m_blocksInfo.insert(info.m_blockNumber, info);
|
||||||
|
VBlockImageInfo &newInfo = it.value();
|
||||||
|
auto imageIt = m_images.find(newInfo.m_imageName);
|
||||||
|
if (imageIt != m_images.end()) {
|
||||||
|
// Fill the width and height.
|
||||||
|
newInfo.m_imageWidth = imageIt.value().width();
|
||||||
|
newInfo.m_imageHeight = imageIt.value().height();
|
||||||
|
adjustWidthAndHeight(newInfo, p_maximumWidth);
|
||||||
|
updateMaximumImageWidth(newInfo, p_maximumWidth);
|
||||||
|
usedImages.insert(newInfo.m_imageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear unused images.
|
||||||
|
for (auto it = m_images.begin(); it != m_images.end();) {
|
||||||
|
if (!m_images.contains(it.key())) {
|
||||||
|
// Remove the image.
|
||||||
|
it = m_images.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "updateBlockInfos() blocks" << m_blocksInfo.size()
|
||||||
|
<< "images" << m_images.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const VBlockImageInfo *VImageResourceManager::findImageInfoByBlock(int p_blockNumber) const
|
||||||
|
{
|
||||||
|
auto it = m_blocksInfo.find(p_blockNumber);
|
||||||
|
if (it != m_blocksInfo.end()) {
|
||||||
|
return &it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap *VImageResourceManager::findImage(const QString &p_name) const
|
||||||
|
{
|
||||||
|
auto it = m_images.find(p_name);
|
||||||
|
if (it != m_images.end()) {
|
||||||
|
return &it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::clear()
|
||||||
|
{
|
||||||
|
m_blocksInfo.clear();
|
||||||
|
m_images.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::updateImageWidth(int p_maximumWidth)
|
||||||
|
{
|
||||||
|
qDebug() << "updateImageWidth()" << p_maximumWidth;
|
||||||
|
m_maximumImageWidth = 0;
|
||||||
|
for (auto it = m_blocksInfo.begin(); it != m_blocksInfo.end(); ++it) {
|
||||||
|
VBlockImageInfo &info = it.value();
|
||||||
|
auto imageIt = m_images.find(info.m_imageName);
|
||||||
|
if (imageIt != m_images.end()) {
|
||||||
|
info.m_imageWidth = imageIt.value().width();
|
||||||
|
info.m_imageHeight = imageIt.value().height();
|
||||||
|
adjustWidthAndHeight(info, p_maximumWidth);
|
||||||
|
updateMaximumImageWidth(info, p_maximumWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::adjustWidthAndHeight(VBlockImageInfo &p_info,
|
||||||
|
int p_maximumWidth)
|
||||||
|
{
|
||||||
|
int oriWidth = p_info.m_imageWidth;
|
||||||
|
int availableWidth = p_maximumWidth - p_info.m_margin;
|
||||||
|
if (availableWidth < p_info.m_imageWidth) {
|
||||||
|
if (availableWidth >= VPlainTextEdit::c_minimumImageWidth) {
|
||||||
|
p_info.m_imageWidth = availableWidth;
|
||||||
|
} else {
|
||||||
|
// Omit the margin when displaying this image.
|
||||||
|
p_info.m_imageWidth = p_maximumWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oriWidth != p_info.m_imageWidth) {
|
||||||
|
// Update the height respecting the ratio.
|
||||||
|
p_info.m_imageHeight = (1.0 * p_info.m_imageWidth / oriWidth) * p_info.m_imageHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VImageResourceManager::updateMaximumImageWidth(const VBlockImageInfo &p_info,
|
||||||
|
int p_maximumWidth)
|
||||||
|
{
|
||||||
|
int width = p_info.m_imageWidth + p_info.m_margin;
|
||||||
|
if (width > p_maximumWidth) {
|
||||||
|
width = p_info.m_imageWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width > m_maximumImageWidth) {
|
||||||
|
m_maximumImageWidth = width;
|
||||||
|
}
|
||||||
|
}
|
63
src/vimageresourcemanager.h
Normal file
63
src/vimageresourcemanager.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef VIMAGERESOURCEMANAGER_H
|
||||||
|
#define VIMAGERESOURCEMANAGER_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QTextBlock>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
struct VBlockImageInfo;
|
||||||
|
|
||||||
|
|
||||||
|
class VImageResourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VImageResourceManager();
|
||||||
|
|
||||||
|
// Add an image to the resource with @p_name as the key.
|
||||||
|
// If @p_name already exists in the resources, it will update it.
|
||||||
|
void addImage(const QString &p_name, const QPixmap &p_image);
|
||||||
|
|
||||||
|
// Whether the resources contains image with name @p_name.
|
||||||
|
bool contains(const QString &p_name) const;
|
||||||
|
|
||||||
|
// Update the block-image info for all blocks.
|
||||||
|
// @p_maximumWidth: maximum width of the images plus the margin.
|
||||||
|
void updateBlockInfos(const QVector<VBlockImageInfo> &p_blocksInfo,
|
||||||
|
int p_maximumWidth = INT_MAX);
|
||||||
|
|
||||||
|
const VBlockImageInfo *findImageInfoByBlock(int p_blockNumber) const;
|
||||||
|
|
||||||
|
const QPixmap *findImage(const QString &p_name) const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// Update the width of all the block info.
|
||||||
|
void updateImageWidth(int p_maximumWidth);
|
||||||
|
|
||||||
|
// Get the maximum width of all block images.
|
||||||
|
int getMaximumImageWidth() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Adjust the width and height according to @p_maximumWidth and margin.
|
||||||
|
void adjustWidthAndHeight(VBlockImageInfo &p_info, int p_maximumWidth);
|
||||||
|
|
||||||
|
void updateMaximumImageWidth(const VBlockImageInfo &p_info, int p_maximumWidth);
|
||||||
|
|
||||||
|
// All the images resources.
|
||||||
|
QHash<QString, QPixmap> m_images;
|
||||||
|
|
||||||
|
// Image info of all the blocks with image.
|
||||||
|
QHash<int, VBlockImageInfo> m_blocksInfo;
|
||||||
|
|
||||||
|
// Maximum width of all images from m_blocksInfo.
|
||||||
|
int m_maximumImageWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int VImageResourceManager::getMaximumImageWidth() const
|
||||||
|
{
|
||||||
|
return m_maximumImageWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VIMAGERESOURCEMANAGER_H
|
42
src/vlinenumberarea.cpp
Normal file
42
src/vlinenumberarea.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "vlinenumberarea.h"
|
||||||
|
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
VLineNumberArea::VLineNumberArea(VTextEditWithLineNumber *p_editor,
|
||||||
|
const QTextDocument *p_document,
|
||||||
|
int p_digitWidth,
|
||||||
|
int p_digitHeight,
|
||||||
|
QWidget *p_parent)
|
||||||
|
: QWidget(p_parent),
|
||||||
|
m_editor(p_editor),
|
||||||
|
m_document(p_document),
|
||||||
|
m_width(0),
|
||||||
|
m_blockCount(-1),
|
||||||
|
m_digitWidth(p_digitWidth),
|
||||||
|
m_digitHeight(p_digitHeight),
|
||||||
|
m_foregroundColor("black"),
|
||||||
|
m_backgroundColor("grey")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int VLineNumberArea::calculateWidth() const
|
||||||
|
{
|
||||||
|
int bc = m_document->blockCount();
|
||||||
|
if (m_blockCount == bc) {
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_cast<VLineNumberArea *>(this)->m_blockCount = bc;
|
||||||
|
int digits = 1;
|
||||||
|
int max = qMax(1, m_blockCount);
|
||||||
|
while (max >= 10) {
|
||||||
|
max /= 10;
|
||||||
|
++digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = m_digitWidth * (digits + 1);
|
||||||
|
const_cast<VLineNumberArea *>(this)->m_width = width;
|
||||||
|
|
||||||
|
return m_width;
|
||||||
|
}
|
95
src/vlinenumberarea.h
Normal file
95
src/vlinenumberarea.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#ifndef VLINENUMBERAREA_H
|
||||||
|
#define VLINENUMBERAREA_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
class QPaintEvent;
|
||||||
|
class QTextDocument;
|
||||||
|
|
||||||
|
|
||||||
|
enum class LineNumberType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Absolute,
|
||||||
|
Relative,
|
||||||
|
CodeBlock
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VTextEditWithLineNumber
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~VTextEditWithLineNumber() {}
|
||||||
|
|
||||||
|
virtual void paintLineNumberArea(QPaintEvent *p_event) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// To use VLineNumberArea, the editor should implement VTextEditWithLineNumber.
|
||||||
|
class VLineNumberArea : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VLineNumberArea(VTextEditWithLineNumber *p_editor,
|
||||||
|
const QTextDocument *p_document,
|
||||||
|
int p_digitWidth,
|
||||||
|
int p_digitHeight,
|
||||||
|
QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
QSize sizeHint() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
return QSize(calculateWidth(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int calculateWidth() const;
|
||||||
|
|
||||||
|
int getDigitHeight() const
|
||||||
|
{
|
||||||
|
return m_digitHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QColor &getBackgroundColor() const;
|
||||||
|
void setBackgroundColor(const QColor &p_color);
|
||||||
|
|
||||||
|
const QColor &getForegroundColor() const;
|
||||||
|
void setForegroundColor(const QColor &p_color);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *p_event) Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
m_editor->paintLineNumberArea(p_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VTextEditWithLineNumber *m_editor;
|
||||||
|
const QTextDocument *m_document;
|
||||||
|
int m_width;
|
||||||
|
int m_blockCount;
|
||||||
|
int m_digitWidth;
|
||||||
|
int m_digitHeight;
|
||||||
|
QColor m_foregroundColor;
|
||||||
|
QColor m_backgroundColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QColor &VLineNumberArea::getBackgroundColor() const
|
||||||
|
{
|
||||||
|
return m_backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VLineNumberArea::setBackgroundColor(const QColor &p_color)
|
||||||
|
{
|
||||||
|
m_backgroundColor = p_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QColor &VLineNumberArea::getForegroundColor() const
|
||||||
|
{
|
||||||
|
return m_foregroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VLineNumberArea::setForegroundColor(const QColor &p_color)
|
||||||
|
{
|
||||||
|
m_foregroundColor = p_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VLINENUMBERAREA_H
|
581
src/vplaintextedit.cpp
Normal file
581
src/vplaintextedit.cpp
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
#include "vplaintextedit.h"
|
||||||
|
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
#include "vimageresourcemanager.h"
|
||||||
|
|
||||||
|
|
||||||
|
const int VPlainTextEdit::c_minimumImageWidth = 100;
|
||||||
|
|
||||||
|
enum class BlockState
|
||||||
|
{
|
||||||
|
Normal = 1,
|
||||||
|
CodeBlockStart,
|
||||||
|
CodeBlock,
|
||||||
|
CodeBlockEnd
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
VPlainTextEdit::VPlainTextEdit(QWidget *p_parent)
|
||||||
|
: QPlainTextEdit(p_parent),
|
||||||
|
m_imageMgr(NULL),
|
||||||
|
m_blockImageEnabled(false),
|
||||||
|
m_imageWidthConstrainted(false),
|
||||||
|
m_maximumImageWidth(INT_MAX)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
VPlainTextEdit::VPlainTextEdit(const QString &p_text, QWidget *p_parent)
|
||||||
|
: QPlainTextEdit(p_text, p_parent),
|
||||||
|
m_imageMgr(NULL),
|
||||||
|
m_blockImageEnabled(false),
|
||||||
|
m_imageWidthConstrainted(false),
|
||||||
|
m_maximumImageWidth(INT_MAX)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
VPlainTextEdit::~VPlainTextEdit()
|
||||||
|
{
|
||||||
|
if (m_imageMgr) {
|
||||||
|
delete m_imageMgr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::init()
|
||||||
|
{
|
||||||
|
m_lineNumberType = LineNumberType::None;
|
||||||
|
|
||||||
|
m_imageMgr = new VImageResourceManager();
|
||||||
|
|
||||||
|
QTextDocument *doc = document();
|
||||||
|
QPlainTextDocumentLayout *layout = new VPlainTextDocumentLayout(doc,
|
||||||
|
m_imageMgr,
|
||||||
|
m_blockImageEnabled);
|
||||||
|
doc->setDocumentLayout(layout);
|
||||||
|
|
||||||
|
m_lineNumberArea = new VLineNumberArea(this,
|
||||||
|
document(),
|
||||||
|
fontMetrics().width(QLatin1Char('8')),
|
||||||
|
fontMetrics().height(),
|
||||||
|
this);
|
||||||
|
connect(document(), &QTextDocument::blockCountChanged,
|
||||||
|
this, &VPlainTextEdit::updateLineNumberAreaMargin);
|
||||||
|
connect(this, &QPlainTextEdit::textChanged,
|
||||||
|
this, &VPlainTextEdit::updateLineNumberArea);
|
||||||
|
connect(verticalScrollBar(), &QScrollBar::valueChanged,
|
||||||
|
this, &VPlainTextEdit::updateLineNumberArea);
|
||||||
|
connect(this, &QPlainTextEdit::cursorPositionChanged,
|
||||||
|
this, &VPlainTextEdit::updateLineNumberArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::updateBlockImages(const QVector<VBlockImageInfo> &p_blocksInfo)
|
||||||
|
{
|
||||||
|
if (m_blockImageEnabled) {
|
||||||
|
m_imageMgr->updateBlockInfos(p_blocksInfo, m_maximumImageWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::clearBlockImages()
|
||||||
|
{
|
||||||
|
m_imageMgr->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VPlainTextEdit::containsImage(const QString &p_imageName) const
|
||||||
|
{
|
||||||
|
return m_imageMgr->contains(p_imageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::addImage(const QString &p_imageName, const QPixmap &p_image)
|
||||||
|
{
|
||||||
|
if (m_blockImageEnabled) {
|
||||||
|
m_imageMgr->addImage(p_imageName, p_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fillBackground(QPainter *p,
|
||||||
|
const QRectF &rect,
|
||||||
|
QBrush brush,
|
||||||
|
const QRectF &gradientRect = QRectF())
|
||||||
|
{
|
||||||
|
p->save();
|
||||||
|
if (brush.style() >= Qt::LinearGradientPattern
|
||||||
|
&& brush.style() <= Qt::ConicalGradientPattern) {
|
||||||
|
if (!gradientRect.isNull()) {
|
||||||
|
QTransform m = QTransform::fromTranslate(gradientRect.left(),
|
||||||
|
gradientRect.top());
|
||||||
|
m.scale(gradientRect.width(),
|
||||||
|
gradientRect.height());
|
||||||
|
brush.setTransform(m);
|
||||||
|
const_cast<QGradient *>(brush.gradient())->setCoordinateMode(QGradient::LogicalMode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p->setBrushOrigin(rect.topLeft());
|
||||||
|
}
|
||||||
|
|
||||||
|
p->fillRect(rect, brush);
|
||||||
|
p->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::paintEvent(QPaintEvent *p_event)
|
||||||
|
{
|
||||||
|
QPainter painter(viewport());
|
||||||
|
QPointF offset(contentOffset());
|
||||||
|
|
||||||
|
QRect er = p_event->rect();
|
||||||
|
QRect viewportRect = viewport()->rect();
|
||||||
|
|
||||||
|
bool editable = !isReadOnly();
|
||||||
|
|
||||||
|
QTextBlock block = firstVisibleBlock();
|
||||||
|
qreal maximumWidth = document()->documentLayout()->documentSize().width();
|
||||||
|
|
||||||
|
// Set a brush origin so that the WaveUnderline knows where the wave started.
|
||||||
|
painter.setBrushOrigin(offset);
|
||||||
|
|
||||||
|
// Keep right margin clean from full-width selection.
|
||||||
|
int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)
|
||||||
|
- document()->documentMargin();
|
||||||
|
er.setRight(qMin(er.right(), maxX));
|
||||||
|
painter.setClipRect(er);
|
||||||
|
|
||||||
|
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
|
||||||
|
|
||||||
|
while (block.isValid()) {
|
||||||
|
QRectF r = blockBoundingRect(block).translated(offset);
|
||||||
|
QTextLayout *layout = block.layout();
|
||||||
|
|
||||||
|
if (!block.isVisible()) {
|
||||||
|
offset.ry() += r.height();
|
||||||
|
block = block.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
|
||||||
|
QTextBlockFormat blockFormat = block.blockFormat();
|
||||||
|
QBrush bg = blockFormat.background();
|
||||||
|
if (bg != Qt::NoBrush) {
|
||||||
|
QRectF contentsRect = r;
|
||||||
|
contentsRect.setWidth(qMax(r.width(), maximumWidth));
|
||||||
|
fillBackground(&painter, contentsRect, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QTextLayout::FormatRange> selections;
|
||||||
|
int blpos = block.position();
|
||||||
|
int bllen = block.length();
|
||||||
|
for (int i = 0; i < context.selections.size(); ++i) {
|
||||||
|
const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
|
||||||
|
const int selStart = range.cursor.selectionStart() - blpos;
|
||||||
|
const int selEnd = range.cursor.selectionEnd() - blpos;
|
||||||
|
if (selStart < bllen
|
||||||
|
&& selEnd > 0
|
||||||
|
&& selEnd > selStart) {
|
||||||
|
QTextLayout::FormatRange o;
|
||||||
|
o.start = selStart;
|
||||||
|
o.length = selEnd - selStart;
|
||||||
|
o.format = range.format;
|
||||||
|
selections.append(o);
|
||||||
|
} else if (!range.cursor.hasSelection()
|
||||||
|
&& range.format.hasProperty(QTextFormat::FullWidthSelection)
|
||||||
|
&& block.contains(range.cursor.position())) {
|
||||||
|
// For full width selections we don't require an actual selection, just
|
||||||
|
// a position to specify the line. That's more convenience in usage.
|
||||||
|
QTextLayout::FormatRange o;
|
||||||
|
QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
|
||||||
|
o.start = l.textStart();
|
||||||
|
o.length = l.textLength();
|
||||||
|
if (o.start + o.length == bllen - 1) {
|
||||||
|
++o.length; // include newline
|
||||||
|
}
|
||||||
|
|
||||||
|
o.format = range.format;
|
||||||
|
selections.append(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool drawCursor = (editable
|
||||||
|
|| (textInteractionFlags() & Qt::TextSelectableByKeyboard))
|
||||||
|
&& context.cursorPosition >= blpos
|
||||||
|
&& context.cursorPosition < blpos + bllen;
|
||||||
|
|
||||||
|
bool drawCursorAsBlock = drawCursor && overwriteMode() ;
|
||||||
|
if (drawCursorAsBlock) {
|
||||||
|
if (context.cursorPosition == blpos + bllen - 1) {
|
||||||
|
drawCursorAsBlock = false;
|
||||||
|
} else {
|
||||||
|
QTextLayout::FormatRange o;
|
||||||
|
o.start = context.cursorPosition - blpos;
|
||||||
|
o.length = 1;
|
||||||
|
o.format.setForeground(palette().base());
|
||||||
|
o.format.setBackground(palette().text());
|
||||||
|
selections.append(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!placeholderText().isEmpty()
|
||||||
|
&& document()->isEmpty()
|
||||||
|
&& layout->preeditAreaText().isEmpty()) {
|
||||||
|
QColor col = palette().text().color();
|
||||||
|
col.setAlpha(128);
|
||||||
|
painter.setPen(col);
|
||||||
|
const int margin = int(document()->documentMargin());
|
||||||
|
painter.drawText(r.adjusted(margin, 0, 0, 0),
|
||||||
|
Qt::AlignTop | Qt::TextWordWrap,
|
||||||
|
placeholderText());
|
||||||
|
} else {
|
||||||
|
layout->draw(&painter, offset, selections, er);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((drawCursor && !drawCursorAsBlock)
|
||||||
|
|| (editable
|
||||||
|
&& context.cursorPosition < -1
|
||||||
|
&& !layout->preeditAreaText().isEmpty())) {
|
||||||
|
int cpos = context.cursorPosition;
|
||||||
|
if (cpos < -1) {
|
||||||
|
cpos = layout->preeditAreaPosition() - (cpos + 2);
|
||||||
|
} else {
|
||||||
|
cpos -= blpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout->drawCursor(&painter, offset, cpos, cursorWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw preview image of this block if there is one.
|
||||||
|
drawImageOfBlock(block, &painter, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset.ry() += r.height();
|
||||||
|
if (offset.y() > viewportRect.height()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backgroundVisible()
|
||||||
|
&& !block.isValid()
|
||||||
|
&& offset.y() <= er.bottom()
|
||||||
|
&& (centerOnScroll()
|
||||||
|
|| verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
|
||||||
|
painter.fillRect(QRect(QPoint((int)er.left(),
|
||||||
|
(int)offset.y()),
|
||||||
|
er.bottomRight()),
|
||||||
|
palette().background());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::drawImageOfBlock(const QTextBlock &p_block,
|
||||||
|
QPainter *p_painter,
|
||||||
|
const QRectF &p_blockRect)
|
||||||
|
{
|
||||||
|
if (!m_blockImageEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VBlockImageInfo *info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||||
|
if (!info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QPixmap *image = m_imageMgr->findImage(info->m_imageName);
|
||||||
|
if (!image) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oriHeight = originalBlockBoundingRect(p_block).height();
|
||||||
|
bool noMargin = (info->m_margin + info->m_imageWidth > m_maximumImageWidth);
|
||||||
|
int margin = noMargin ? 0 : info->m_margin;
|
||||||
|
QRect tmpRect(p_blockRect.toRect());
|
||||||
|
QRect targetRect(tmpRect.x() + margin,
|
||||||
|
tmpRect.y() + oriHeight,
|
||||||
|
info->m_imageWidth,
|
||||||
|
qMax(info->m_imageHeight, tmpRect.height() - oriHeight));
|
||||||
|
|
||||||
|
p_painter->drawPixmap(targetRect, *image);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF VPlainTextEdit::originalBlockBoundingRect(const QTextBlock &p_block) const
|
||||||
|
{
|
||||||
|
return getLayout()->QPlainTextDocumentLayout::blockBoundingRect(p_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::setBlockImageEnabled(bool p_enabled)
|
||||||
|
{
|
||||||
|
if (m_blockImageEnabled == p_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_blockImageEnabled = p_enabled;
|
||||||
|
if (!p_enabled) {
|
||||||
|
clearBlockImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
getLayout()->setBlockImageEnabled(m_blockImageEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::setImageWidthConstrainted(bool p_enabled)
|
||||||
|
{
|
||||||
|
m_imageWidthConstrainted = p_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::resizeEvent(QResizeEvent *p_event)
|
||||||
|
{
|
||||||
|
bool needUpdate = false;
|
||||||
|
if (m_imageWidthConstrainted) {
|
||||||
|
const QSize &si = p_event->size();
|
||||||
|
m_maximumImageWidth = si.width();
|
||||||
|
needUpdate = true;
|
||||||
|
} else if (m_maximumImageWidth != INT_MAX) {
|
||||||
|
needUpdate = true;
|
||||||
|
m_maximumImageWidth = INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needUpdate) {
|
||||||
|
m_imageMgr->updateImageWidth(m_maximumImageWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPlainTextEdit::resizeEvent(p_event);
|
||||||
|
|
||||||
|
if (m_lineNumberType != LineNumberType::None) {
|
||||||
|
QRect rect = contentsRect();
|
||||||
|
m_lineNumberArea->setGeometry(QRect(rect.left(),
|
||||||
|
rect.top(),
|
||||||
|
m_lineNumberArea->calculateWidth(),
|
||||||
|
rect.height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::paintLineNumberArea(QPaintEvent *p_event)
|
||||||
|
{
|
||||||
|
if (m_lineNumberType == LineNumberType::None) {
|
||||||
|
updateLineNumberAreaMargin();
|
||||||
|
m_lineNumberArea->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(m_lineNumberArea);
|
||||||
|
painter.fillRect(p_event->rect(), m_lineNumberArea->getBackgroundColor());
|
||||||
|
|
||||||
|
QTextBlock block = firstVisibleBlock();
|
||||||
|
if (!block.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blockNumber = block.blockNumber();
|
||||||
|
int offsetY = (int)contentOffset().y();
|
||||||
|
QRectF rect = blockBoundingRect(block);
|
||||||
|
int top = offsetY + (int)rect.y();
|
||||||
|
int bottom = top + (int)rect.height();
|
||||||
|
int eventTop = p_event->rect().top();
|
||||||
|
int eventBtm = p_event->rect().bottom();
|
||||||
|
const int digitHeight = m_lineNumberArea->getDigitHeight();
|
||||||
|
const int curBlockNumber = textCursor().block().blockNumber();
|
||||||
|
painter.setPen(m_lineNumberArea->getForegroundColor());
|
||||||
|
|
||||||
|
// Display line number only in code block.
|
||||||
|
if (m_lineNumberType == LineNumberType::CodeBlock) {
|
||||||
|
int number = 0;
|
||||||
|
while (block.isValid() && top <= eventBtm) {
|
||||||
|
int blockState = block.userState();
|
||||||
|
switch (blockState) {
|
||||||
|
case (int)BlockState::CodeBlockStart:
|
||||||
|
Q_ASSERT(number == 0);
|
||||||
|
number = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)BlockState::CodeBlockEnd:
|
||||||
|
number = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (int)BlockState::CodeBlock:
|
||||||
|
if (number == 0) {
|
||||||
|
// Need to find current line number in code block.
|
||||||
|
QTextBlock startBlock = block.previous();
|
||||||
|
while (startBlock.isValid()) {
|
||||||
|
if (startBlock.userState() == (int)BlockState::CodeBlockStart) {
|
||||||
|
number = block.blockNumber() - startBlock.blockNumber();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
startBlock = startBlock.previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockState == (int)BlockState::CodeBlock) {
|
||||||
|
if (block.isVisible() && bottom >= eventTop) {
|
||||||
|
QString numberStr = QString::number(number);
|
||||||
|
painter.drawText(0,
|
||||||
|
top,
|
||||||
|
m_lineNumberArea->width(),
|
||||||
|
digitHeight,
|
||||||
|
Qt::AlignRight,
|
||||||
|
numberStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
++number;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.next();
|
||||||
|
top = bottom;
|
||||||
|
bottom = top + (int)blockBoundingRect(block).height();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle m_lineNumberType 1 and 2.
|
||||||
|
Q_ASSERT(m_lineNumberType == LineNumberType::Absolute
|
||||||
|
|| m_lineNumberType == LineNumberType::Relative);
|
||||||
|
while (block.isValid() && top <= eventBtm) {
|
||||||
|
if (block.isVisible() && bottom >= eventTop) {
|
||||||
|
bool currentLine = false;
|
||||||
|
int number = blockNumber + 1;
|
||||||
|
if (m_lineNumberType == LineNumberType::Relative) {
|
||||||
|
number = blockNumber - curBlockNumber;
|
||||||
|
if (number == 0) {
|
||||||
|
currentLine = true;
|
||||||
|
number = blockNumber + 1;
|
||||||
|
} else if (number < 0) {
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
} else if (blockNumber == curBlockNumber) {
|
||||||
|
currentLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString numberStr = QString::number(number);
|
||||||
|
|
||||||
|
if (currentLine) {
|
||||||
|
QFont font = painter.font();
|
||||||
|
font.setBold(true);
|
||||||
|
painter.setFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.drawText(0,
|
||||||
|
top,
|
||||||
|
m_lineNumberArea->width(),
|
||||||
|
digitHeight,
|
||||||
|
Qt::AlignRight,
|
||||||
|
numberStr);
|
||||||
|
|
||||||
|
if (currentLine) {
|
||||||
|
QFont font = painter.font();
|
||||||
|
font.setBold(false);
|
||||||
|
painter.setFont(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.next();
|
||||||
|
top = bottom;
|
||||||
|
bottom = top + (int)blockBoundingRect(block).height();
|
||||||
|
++blockNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VPlainTextDocumentLayout *VPlainTextEdit::getLayout() const
|
||||||
|
{
|
||||||
|
return qobject_cast<VPlainTextDocumentLayout *>(document()->documentLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::updateLineNumberAreaMargin()
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
if (m_lineNumberType != LineNumberType::None) {
|
||||||
|
width = m_lineNumberArea->calculateWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
setViewportMargins(width, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPlainTextEdit::updateLineNumberArea()
|
||||||
|
{
|
||||||
|
if (m_lineNumberType != LineNumberType::None) {
|
||||||
|
if (!m_lineNumberArea->isVisible()) {
|
||||||
|
updateLineNumberAreaMargin();
|
||||||
|
m_lineNumberArea->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lineNumberArea->update();
|
||||||
|
} else if (m_lineNumberArea->isVisible()) {
|
||||||
|
updateLineNumberAreaMargin();
|
||||||
|
m_lineNumberArea->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VPlainTextDocumentLayout::VPlainTextDocumentLayout(QTextDocument *p_document,
|
||||||
|
VImageResourceManager *p_imageMgr,
|
||||||
|
bool p_blockImageEnabled)
|
||||||
|
: QPlainTextDocumentLayout(p_document),
|
||||||
|
m_imageMgr(p_imageMgr),
|
||||||
|
m_blockImageEnabled(p_blockImageEnabled),
|
||||||
|
m_maximumImageWidth(INT_MAX)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF VPlainTextDocumentLayout::blockBoundingRect(const QTextBlock &p_block) const
|
||||||
|
{
|
||||||
|
QRectF br = QPlainTextDocumentLayout::blockBoundingRect(p_block);
|
||||||
|
if (!m_blockImageEnabled) {
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VBlockImageInfo *info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||||
|
if (info) {
|
||||||
|
int tmp = info->m_margin + info->m_imageWidth;
|
||||||
|
if (tmp > m_maximumImageWidth) {
|
||||||
|
Q_ASSERT(info->m_imageWidth <= m_maximumImageWidth);
|
||||||
|
tmp = info->m_imageWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal width = (qreal)(tmp);
|
||||||
|
qreal dw = width > br.width() ? width - br.width() : 0;
|
||||||
|
qreal dh = (qreal)info->m_imageHeight;
|
||||||
|
|
||||||
|
br.adjust(0, 0, dw, dh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF VPlainTextDocumentLayout::frameBoundingRect(QTextFrame *p_frame) const
|
||||||
|
{
|
||||||
|
QRectF fr = QPlainTextDocumentLayout::frameBoundingRect(p_frame);
|
||||||
|
if (!m_blockImageEnabled) {
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal imageWidth = (qreal)m_imageMgr->getMaximumImageWidth();
|
||||||
|
qreal dw = imageWidth - fr.width();
|
||||||
|
if (dw > 0) {
|
||||||
|
fr.adjust(0, 0, dw, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSizeF VPlainTextDocumentLayout::documentSize() const
|
||||||
|
{
|
||||||
|
QSizeF si = QPlainTextDocumentLayout::documentSize();
|
||||||
|
if (!m_blockImageEnabled) {
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal imageWidth = (qreal)m_imageMgr->getMaximumImageWidth();
|
||||||
|
if (imageWidth > si.width()) {
|
||||||
|
si.setWidth(imageWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return si;
|
||||||
|
}
|
179
src/vplaintextedit.h
Normal file
179
src/vplaintextedit.h
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#ifndef VPLAINTEXTEDIT_H
|
||||||
|
#define VPLAINTEXTEDIT_H
|
||||||
|
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QPlainTextDocumentLayout>
|
||||||
|
#include <QTextBlock>
|
||||||
|
|
||||||
|
#include "vlinenumberarea.h"
|
||||||
|
|
||||||
|
class QTextDocument;
|
||||||
|
class VImageResourceManager;
|
||||||
|
class QPaintEvent;
|
||||||
|
class QPainter;
|
||||||
|
class QResizeEvent;
|
||||||
|
|
||||||
|
|
||||||
|
struct VBlockImageInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VBlockImageInfo()
|
||||||
|
: m_blockNumber(-1), m_margin(0), m_imageWidth(0), m_imageHeight(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VBlockImageInfo(int p_blockNumber,
|
||||||
|
const QString &p_imageName,
|
||||||
|
int p_margin = 0)
|
||||||
|
: m_blockNumber(p_blockNumber),
|
||||||
|
m_imageName(p_imageName),
|
||||||
|
m_margin(p_margin),
|
||||||
|
m_imageWidth(0),
|
||||||
|
m_imageHeight(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block number.
|
||||||
|
int m_blockNumber;
|
||||||
|
|
||||||
|
// The name of the image corresponding to this block.
|
||||||
|
QString m_imageName;
|
||||||
|
|
||||||
|
// Left margin of the image.
|
||||||
|
int m_margin;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Width and height of the image display.
|
||||||
|
int m_imageWidth;
|
||||||
|
int m_imageHeight;
|
||||||
|
|
||||||
|
friend class VImageResourceManager;
|
||||||
|
friend class VPlainTextEdit;
|
||||||
|
friend class VPlainTextDocumentLayout;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VPlainTextEdit : public QPlainTextEdit, public VTextEditWithLineNumber
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VPlainTextEdit(QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
explicit VPlainTextEdit(const QString &p_text, QWidget *p_parent = nullptr);
|
||||||
|
|
||||||
|
virtual ~VPlainTextEdit();
|
||||||
|
|
||||||
|
// Update images of these given blocks.
|
||||||
|
// Images of blocks not given here will be clear.
|
||||||
|
void updateBlockImages(const QVector<VBlockImageInfo> &p_blocksInfo);
|
||||||
|
|
||||||
|
void clearBlockImages();
|
||||||
|
|
||||||
|
// Whether the resoruce manager contains image of name @p_imageName.
|
||||||
|
bool containsImage(const QString &p_imageName) const;
|
||||||
|
|
||||||
|
// Add an image to the resources.
|
||||||
|
void addImage(const QString &p_imageName, const QPixmap &p_image);
|
||||||
|
|
||||||
|
void setBlockImageEnabled(bool p_enabled);
|
||||||
|
|
||||||
|
void setImageWidthConstrainted(bool p_enabled);
|
||||||
|
|
||||||
|
void paintLineNumberArea(QPaintEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void setLineNumberType(LineNumberType p_type);
|
||||||
|
|
||||||
|
// The minimum width of an image in pixels.
|
||||||
|
static const int c_minimumImageWidth;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Most logics are copied from QPlainTextEdit.
|
||||||
|
// Differences: draw images for blocks with preview image.
|
||||||
|
void paintEvent(QPaintEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// Update viewport margin to hold the line number area.
|
||||||
|
void updateLineNumberAreaMargin();
|
||||||
|
|
||||||
|
void updateLineNumberArea();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// @p_blockRect: the content rect of @p_block.
|
||||||
|
void drawImageOfBlock(const QTextBlock &p_block,
|
||||||
|
QPainter *p_painter,
|
||||||
|
const QRectF &p_blockRect);
|
||||||
|
|
||||||
|
QRectF originalBlockBoundingRect(const QTextBlock &p_block) const;
|
||||||
|
|
||||||
|
VPlainTextDocumentLayout *getLayout() const;
|
||||||
|
|
||||||
|
// Widget to display line number area.
|
||||||
|
VLineNumberArea *m_lineNumberArea;
|
||||||
|
|
||||||
|
VImageResourceManager *m_imageMgr;
|
||||||
|
|
||||||
|
bool m_blockImageEnabled;
|
||||||
|
|
||||||
|
// Whether constraint the width of image to the width of the viewport.
|
||||||
|
bool m_imageWidthConstrainted;
|
||||||
|
|
||||||
|
// Maximum width of the images.
|
||||||
|
int m_maximumImageWidth;
|
||||||
|
|
||||||
|
LineNumberType m_lineNumberType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VPlainTextDocumentLayout : public QPlainTextDocumentLayout
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VPlainTextDocumentLayout(QTextDocument *p_document,
|
||||||
|
VImageResourceManager *p_imageMgr,
|
||||||
|
bool p_blockImageEnabled = false);
|
||||||
|
|
||||||
|
// Will adjust the rect if there is an image for this block.
|
||||||
|
QRectF blockBoundingRect(const QTextBlock &p_block) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QRectF frameBoundingRect(QTextFrame *p_frame) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QSizeF documentSize() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
void setBlockImageEnabled(bool p_enabled);
|
||||||
|
|
||||||
|
void setMaximumImageWidth(int p_width);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VImageResourceManager *m_imageMgr;
|
||||||
|
|
||||||
|
bool m_blockImageEnabled;
|
||||||
|
|
||||||
|
int m_maximumImageWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void VPlainTextDocumentLayout::setBlockImageEnabled(bool p_enabled)
|
||||||
|
{
|
||||||
|
m_blockImageEnabled = p_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VPlainTextDocumentLayout::setMaximumImageWidth(int p_width)
|
||||||
|
{
|
||||||
|
m_maximumImageWidth = p_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VPlainTextEdit::setLineNumberType(LineNumberType p_type)
|
||||||
|
{
|
||||||
|
if (p_type == m_lineNumberType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lineNumberType = p_type;
|
||||||
|
|
||||||
|
updateLineNumberArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // VPLAINTEXTEDIT_H
|
Loading…
x
Reference in New Issue
Block a user