mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
VTextEdit: support previewing inline images
This commit is contained in:
parent
3e7fa998ee
commit
d2ee3e66d6
@ -23,20 +23,44 @@ bool VImageResourceManager2::contains(const QString &p_name) const
|
||||
QSet<int> VImageResourceManager2::updateBlockInfos(const QVector<VBlockImageInfo2> &p_blocksInfo)
|
||||
{
|
||||
QSet<QString> usedImages;
|
||||
QHash<int, VBlockImageInfo2> newBlocksInfo;
|
||||
QHash<int, QVector<VBlockImageInfo2>> newBlocksInfo;
|
||||
|
||||
for (auto const & info : p_blocksInfo) {
|
||||
auto it = newBlocksInfo.insert(info.m_blockNumber, info);
|
||||
VBlockImageInfo2 &newInfo = it.value();
|
||||
if (newInfo.m_padding < 0) {
|
||||
newInfo.m_padding = 0;
|
||||
VBlockImageInfo2 *newInfo = NULL;
|
||||
auto blockIt = newBlocksInfo.find(info.m_blockNumber);
|
||||
if (blockIt == newBlocksInfo.end()) {
|
||||
// New block.
|
||||
QVector<VBlockImageInfo2> vec(1, info);
|
||||
auto it = newBlocksInfo.insert(info.m_blockNumber, vec);
|
||||
newInfo = &it.value().last();
|
||||
} else {
|
||||
// Multiple images for a block.
|
||||
QVector<VBlockImageInfo2> &vec = blockIt.value();
|
||||
int i;
|
||||
for (i = 0; i < vec.size(); ++i) {
|
||||
Q_ASSERT(vec[i].m_blockNumber == info.m_blockNumber);
|
||||
if (info < vec[i]) {
|
||||
vec.insert(i, info);
|
||||
newInfo = &vec[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == vec.size()) {
|
||||
vec.append(info);
|
||||
newInfo = &vec.last();
|
||||
}
|
||||
}
|
||||
|
||||
auto imageIt = m_images.find(newInfo.m_imageName);
|
||||
if (newInfo->m_padding < 0) {
|
||||
newInfo->m_padding = 0;
|
||||
}
|
||||
|
||||
auto imageIt = m_images.find(newInfo->m_imageName);
|
||||
if (imageIt != m_images.end()) {
|
||||
// Fill the width and height.
|
||||
newInfo.m_imageSize = imageIt.value().size();
|
||||
usedImages.insert(newInfo.m_imageName);
|
||||
newInfo->m_imageSize = imageIt.value().size();
|
||||
usedImages.insert(newInfo->m_imageName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +85,7 @@ QSet<int> VImageResourceManager2::updateBlockInfos(const QVector<VBlockImageInfo
|
||||
return affectedBlocks;
|
||||
}
|
||||
|
||||
const VBlockImageInfo2 *VImageResourceManager2::findImageInfoByBlock(int p_blockNumber) const
|
||||
const QVector<VBlockImageInfo2> *VImageResourceManager2::findImageInfoByBlock(int p_blockNumber) const
|
||||
{
|
||||
auto it = m_blocksInfo.find(p_blockNumber);
|
||||
if (it != m_blocksInfo.end()) {
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
// Return changed blocks' block number.
|
||||
QSet<int> updateBlockInfos(const QVector<VBlockImageInfo2> &p_blocksInfo);
|
||||
|
||||
const VBlockImageInfo2 *findImageInfoByBlock(int p_blockNumber) const;
|
||||
const QVector<VBlockImageInfo2> *findImageInfoByBlock(int p_blockNumber) const;
|
||||
|
||||
const QPixmap *findImage(const QString &p_name) const;
|
||||
|
||||
@ -39,7 +39,9 @@ private:
|
||||
QHash<QString, QPixmap> m_images;
|
||||
|
||||
// Image info of all the blocks with image.
|
||||
QHash<int, VBlockImageInfo2> m_blocksInfo;
|
||||
// One block may contain multiple inline images or only one block image.
|
||||
// If there are multiple inline images, they are sorted by the start position.
|
||||
QHash<int, QVector<VBlockImageInfo2>> m_blocksInfo;
|
||||
};
|
||||
|
||||
#endif // VIMAGERESOURCEMANAGER2_H
|
||||
|
@ -226,11 +226,6 @@ void VPreviewManager::updateBlockImageInfo(const QVector<ImageLinkInfo> &p_image
|
||||
for (int i = 0; i < p_imageLinks.size(); ++i) {
|
||||
const ImageLinkInfo &link = p_imageLinks[i];
|
||||
|
||||
// Skip inline images.
|
||||
if (!link.m_isBlock) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString name = imageResourceName(link);
|
||||
if (name.isEmpty()) {
|
||||
continue;
|
||||
@ -240,7 +235,9 @@ void VPreviewManager::updateBlockImageInfo(const QVector<ImageLinkInfo> &p_image
|
||||
name,
|
||||
link.m_startPos - link.m_blockPos,
|
||||
link.m_endPos - link.m_blockPos,
|
||||
link.m_padding);
|
||||
link.m_padding,
|
||||
!link.m_isBlock);
|
||||
|
||||
blockInfos.push_back(info);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "vimageresourcemanager2.h"
|
||||
#include "vtextedit.h"
|
||||
|
||||
#define MARKER_THICKNESS 2
|
||||
#define MAX_INLINE_IMAGE_HEIGHT 400
|
||||
|
||||
VTextDocumentLayout::VTextDocumentLayout(QTextDocument *p_doc,
|
||||
VImageResourceManager2 *p_imageMgr)
|
||||
@ -223,7 +225,9 @@ void VTextDocumentLayout::draw(QPainter *p_painter, const PaintContext &p_contex
|
||||
selections,
|
||||
p_context.clip.isValid() ? p_context.clip : QRectF());
|
||||
|
||||
drawBlockImage(p_painter, block, offset);
|
||||
drawImages(p_painter, block, offset);
|
||||
|
||||
drawMarkers(p_painter, block, offset);
|
||||
|
||||
// Draw the cursor.
|
||||
int blpos = block.position();
|
||||
@ -502,8 +506,6 @@ void VTextDocumentLayout::layoutBlock(const QTextBlock &p_block)
|
||||
QTextDocument *doc = document();
|
||||
Q_ASSERT(m_margin == doc->documentMargin());
|
||||
|
||||
// The height (y) of the next line.
|
||||
qreal height = 0;
|
||||
QTextLayout *tl = p_block.layout();
|
||||
QTextOption option = doc->defaultTextOption();
|
||||
tl->setTextOption(option);
|
||||
@ -521,40 +523,126 @@ void VTextDocumentLayout::layoutBlock(const QTextBlock &p_block)
|
||||
|
||||
availableWidth -= (2 * m_margin + extraMargin + m_cursorMargin + m_cursorWidth);
|
||||
|
||||
tl->beginLayout();
|
||||
QVector<Marker> markers;
|
||||
QVector<ImagePaintInfo> images;
|
||||
|
||||
while (true) {
|
||||
QTextLine line = tl->createLine();
|
||||
if (!line.isValid()) {
|
||||
break;
|
||||
}
|
||||
|
||||
line.setLeadingIncluded(true);
|
||||
line.setLineWidth(availableWidth);
|
||||
height += m_lineLeading;
|
||||
line.setPosition(QPointF(m_margin, height));
|
||||
height += line.height();
|
||||
}
|
||||
|
||||
tl->endLayout();
|
||||
layoutLines(p_block, tl, markers, images, availableWidth, 0);
|
||||
|
||||
// Set this block's line count to its layout's line count.
|
||||
// That is one block may occupy multiple visual lines.
|
||||
const_cast<QTextBlock&>(p_block).setLineCount(p_block.isVisible() ? tl->lineCount() : 0);
|
||||
|
||||
// Update the info about this block.
|
||||
finishBlockLayout(p_block);
|
||||
finishBlockLayout(p_block, markers, images);
|
||||
}
|
||||
|
||||
void VTextDocumentLayout::finishBlockLayout(const QTextBlock &p_block)
|
||||
qreal VTextDocumentLayout::layoutLines(const QTextBlock &p_block,
|
||||
QTextLayout *p_tl,
|
||||
QVector<Marker> &p_markers,
|
||||
QVector<ImagePaintInfo> &p_images,
|
||||
qreal p_availableWidth,
|
||||
qreal p_height)
|
||||
{
|
||||
// Handle block inline image.
|
||||
bool hasInlineImages = false;
|
||||
const QVector<VBlockImageInfo2> *info = NULL;
|
||||
if (m_blockImageEnabled) {
|
||||
info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||
|
||||
if (info
|
||||
&& !info->isEmpty()
|
||||
&& info->first().m_inlineImage) {
|
||||
hasInlineImages = true;
|
||||
}
|
||||
}
|
||||
|
||||
p_tl->beginLayout();
|
||||
|
||||
int imgIdx = 0;
|
||||
|
||||
while (true) {
|
||||
QTextLine line = p_tl->createLine();
|
||||
if (!line.isValid()) {
|
||||
break;
|
||||
}
|
||||
|
||||
line.setLeadingIncluded(true);
|
||||
line.setLineWidth(p_availableWidth);
|
||||
p_height += m_lineLeading;
|
||||
|
||||
if (hasInlineImages) {
|
||||
QVector<const VBlockImageInfo2 *> images;
|
||||
QVector<QPair<qreal, qreal>> imageRange;
|
||||
qreal imgHeight = fetchInlineImagesForOneLine(*info,
|
||||
&line,
|
||||
m_margin,
|
||||
imgIdx,
|
||||
images,
|
||||
imageRange);
|
||||
|
||||
for (int i = 0; i < images.size(); ++i) {
|
||||
layoutInlineImage(images[i],
|
||||
p_height,
|
||||
imgHeight,
|
||||
imageRange[i].first,
|
||||
imageRange[i].second,
|
||||
p_markers,
|
||||
p_images);
|
||||
}
|
||||
|
||||
if (!images.isEmpty()) {
|
||||
p_height += imgHeight + MARKER_THICKNESS + MARKER_THICKNESS;
|
||||
}
|
||||
}
|
||||
|
||||
line.setPosition(QPointF(m_margin, p_height));
|
||||
p_height += line.height();
|
||||
}
|
||||
|
||||
p_tl->endLayout();
|
||||
|
||||
return p_height;
|
||||
}
|
||||
|
||||
void VTextDocumentLayout::layoutInlineImage(const VBlockImageInfo2 *p_info,
|
||||
qreal p_heightInBlock,
|
||||
qreal p_imageSpaceHeight,
|
||||
qreal p_xStart,
|
||||
qreal p_xEnd,
|
||||
QVector<Marker> &p_markers,
|
||||
QVector<ImagePaintInfo> &p_images)
|
||||
{
|
||||
Marker mk;
|
||||
qreal mky = p_imageSpaceHeight + p_heightInBlock + MARKER_THICKNESS;
|
||||
mk.m_start = QPointF(p_xStart, mky);
|
||||
mk.m_end = QPointF(p_xEnd, mky);
|
||||
p_markers.append(mk);
|
||||
|
||||
if (p_info) {
|
||||
QSize size = p_info->m_imageSize;
|
||||
scaleSize(size, p_xEnd - p_xStart, p_imageSpaceHeight);
|
||||
|
||||
ImagePaintInfo ipi;
|
||||
ipi.m_name = p_info->m_imageName;
|
||||
ipi.m_rect = QRectF(QPointF(p_xStart,
|
||||
p_heightInBlock + p_imageSpaceHeight - size.height()),
|
||||
size);
|
||||
p_images.append(ipi);
|
||||
}
|
||||
}
|
||||
|
||||
void VTextDocumentLayout::finishBlockLayout(const QTextBlock &p_block,
|
||||
const QVector<Marker> &p_markers,
|
||||
const QVector<ImagePaintInfo> &p_images)
|
||||
{
|
||||
// Update rect and offset.
|
||||
Q_ASSERT(p_block.isValid());
|
||||
int num = p_block.blockNumber();
|
||||
Q_ASSERT(m_blocks.size() > num);
|
||||
ImagePaintInfo ipi;
|
||||
BlockInfo &info = m_blocks[num];
|
||||
info.reset();
|
||||
info.m_rect = blockRectFromTextLayout(p_block);
|
||||
info.m_rect = blockRectFromTextLayout(p_block, &ipi);
|
||||
Q_ASSERT(!info.m_rect.isNull());
|
||||
int pre = previousValidBlockNumber(num);
|
||||
if (pre == -1) {
|
||||
@ -563,6 +651,30 @@ void VTextDocumentLayout::finishBlockLayout(const QTextBlock &p_block)
|
||||
info.m_offset = m_blocks[pre].bottom();
|
||||
}
|
||||
|
||||
bool hasImage = false;
|
||||
if (ipi.isValid()) {
|
||||
Q_ASSERT(p_markers.isEmpty());
|
||||
Q_ASSERT(p_images.isEmpty());
|
||||
info.m_images.append(ipi);
|
||||
hasImage = true;
|
||||
} else if (!p_markers.isEmpty()) {
|
||||
// Q_ASSERT(!p_images.isEmpty());
|
||||
info.m_markers = p_markers;
|
||||
info.m_images = p_images;
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
// Add vertical marker.
|
||||
if (hasImage) {
|
||||
// Fill the marker.
|
||||
// Will be adjusted using offset.
|
||||
Marker mk;
|
||||
mk.m_start = QPointF(-1, 0);
|
||||
mk.m_end = QPointF(-1, info.m_rect.height());
|
||||
|
||||
info.m_markers.append(mk);
|
||||
}
|
||||
|
||||
if (info.hasOffset()) {
|
||||
fillOffsetFrom(num);
|
||||
}
|
||||
@ -622,8 +734,13 @@ int VTextDocumentLayout::cursorWidth() const
|
||||
return m_cursorWidth;
|
||||
}
|
||||
|
||||
QRectF VTextDocumentLayout::blockRectFromTextLayout(const QTextBlock &p_block)
|
||||
QRectF VTextDocumentLayout::blockRectFromTextLayout(const QTextBlock &p_block,
|
||||
ImagePaintInfo *p_image)
|
||||
{
|
||||
if (p_image) {
|
||||
*p_image = ImagePaintInfo();
|
||||
}
|
||||
|
||||
QTextLayout *tl = p_block.layout();
|
||||
if (tl->lineCount() < 1) {
|
||||
return QRectF();
|
||||
@ -637,17 +754,29 @@ QRectF VTextDocumentLayout::blockRectFromTextLayout(const QTextBlock &p_block)
|
||||
br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));
|
||||
}
|
||||
|
||||
// Handle block image.
|
||||
// Handle block non-inline image.
|
||||
if (m_blockImageEnabled) {
|
||||
const VBlockImageInfo2 *info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||
if (info && !info->m_imageSize.isNull()) {
|
||||
int maximumWidth = tlRect.width();
|
||||
int padding;
|
||||
QSize size;
|
||||
adjustImagePaddingAndSize(info, maximumWidth, padding, size);
|
||||
int dw = padding + size.width() + m_margin - br.width();
|
||||
int dh = size.height() + m_lineLeading;
|
||||
br.adjust(0, 0, dw > 0 ? dw : 0, dh);
|
||||
const QVector<VBlockImageInfo2> *info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||
if (info && info->size() == 1) {
|
||||
const VBlockImageInfo2& img = info->first();
|
||||
if (!img.m_inlineImage && !img.m_imageSize.isNull()) {
|
||||
int maximumWidth = tlRect.width();
|
||||
int padding;
|
||||
QSize size;
|
||||
adjustImagePaddingAndSize(&img, maximumWidth, padding, size);
|
||||
|
||||
if (p_image) {
|
||||
p_image->m_name = img.m_imageName;
|
||||
p_image->m_rect = QRectF(padding + m_margin,
|
||||
br.height() + m_lineLeading,
|
||||
size.width(),
|
||||
size.height());
|
||||
}
|
||||
|
||||
int dw = padding + size.width() + m_margin - br.width();
|
||||
int dh = size.height() + m_lineLeading;
|
||||
br.adjust(0, 0, dw > 0 ? dw : 0, dh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,41 +858,53 @@ void VTextDocumentLayout::adjustImagePaddingAndSize(const VBlockImageInfo2 *p_in
|
||||
}
|
||||
}
|
||||
|
||||
void VTextDocumentLayout::drawBlockImage(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset)
|
||||
void VTextDocumentLayout::drawImages(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset)
|
||||
{
|
||||
if (!m_blockImageEnabled) {
|
||||
if (m_blocks.size() <= p_block.blockNumber()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const VBlockImageInfo2 *info = m_imageMgr->findImageInfoByBlock(p_block.blockNumber());
|
||||
if (!info || info->m_imageSize.isNull()) {
|
||||
const QVector<ImagePaintInfo> &images = m_blocks[p_block.blockNumber()].m_images;
|
||||
if (images.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPixmap *image = m_imageMgr->findImage(info->m_imageName);
|
||||
Q_ASSERT(image);
|
||||
for (auto const & img : images) {
|
||||
const QPixmap *image = m_imageMgr->findImage(img.m_name);
|
||||
Q_ASSERT(image);
|
||||
QRect targetRect = img.m_rect.adjusted(p_offset.x(),
|
||||
p_offset.y(),
|
||||
p_offset.x(),
|
||||
p_offset.y()).toRect();
|
||||
|
||||
// Draw block image.
|
||||
QTextLayout *tl = p_block.layout();
|
||||
QRectF tlRect = tl->boundingRect();
|
||||
int maximumWidth = tlRect.width();
|
||||
int padding;
|
||||
QSize size;
|
||||
adjustImagePaddingAndSize(info, maximumWidth, padding, size);
|
||||
QRect targetRect(p_offset.x() + padding,
|
||||
p_offset.y() + tlRect.height() + m_lineLeading,
|
||||
size.width(),
|
||||
size.height());
|
||||
p_painter->drawPixmap(targetRect, *image);
|
||||
}
|
||||
}
|
||||
|
||||
p_painter->drawPixmap(targetRect, *image);
|
||||
|
||||
// Draw a thin line to link them.
|
||||
void VTextDocumentLayout::drawMarkers(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset)
|
||||
{
|
||||
if (m_blocks.size() <= p_block.blockNumber()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector<Marker> &markers = m_blocks[p_block.blockNumber()].m_markers;
|
||||
if (markers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPen oldPen = p_painter->pen();
|
||||
QPen newPen(m_imageLineColor, 2, Qt::DashLine);
|
||||
QPen newPen(m_imageLineColor, MARKER_THICKNESS, Qt::DashLine);
|
||||
p_painter->setPen(newPen);
|
||||
p_painter->drawLine(QPointF(2, p_offset.y()), QPointF(2, targetRect.bottom()));
|
||||
|
||||
for (auto const & mk : markers) {
|
||||
p_painter->drawLine(mk.m_start + p_offset, mk.m_end + p_offset);
|
||||
}
|
||||
|
||||
p_painter->setPen(oldPen);
|
||||
}
|
||||
|
||||
@ -810,3 +951,101 @@ void VTextDocumentLayout::relayout(const QSet<int> &p_blocks)
|
||||
|
||||
updateDocumentSize();
|
||||
}
|
||||
|
||||
qreal VTextDocumentLayout::fetchInlineImagesForOneLine(const QVector<VBlockImageInfo2> &p_info,
|
||||
const QTextLine *p_line,
|
||||
qreal p_margin,
|
||||
int &p_index,
|
||||
QVector<const VBlockImageInfo2 *> &p_images,
|
||||
QVector<QPair<qreal, qreal>> &p_imageRange)
|
||||
{
|
||||
qreal maxHeight = 0;
|
||||
int start = p_line->textStart();
|
||||
int end = p_line->textLength() + start;
|
||||
|
||||
for (int i = 0; i < p_info.size(); ++i) {
|
||||
const VBlockImageInfo2 &img = p_info[i];
|
||||
Q_ASSERT(img.m_inlineImage);
|
||||
|
||||
if (img.m_imageSize.isNull()) {
|
||||
p_index = i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (img.m_startPos >= start && img.m_startPos < end) {
|
||||
// Start of a new image.
|
||||
qreal startX = p_line->cursorToX(img.m_startPos) + p_margin;
|
||||
qreal endX;
|
||||
if (img.m_endPos <= end) {
|
||||
// End an image.
|
||||
endX = p_line->cursorToX(img.m_endPos) + p_margin;
|
||||
p_images.append(&img);
|
||||
p_imageRange.append(QPair<qreal, qreal>(startX, endX));
|
||||
|
||||
QSize size = img.m_imageSize;
|
||||
scaleSize(size, endX - startX, MAX_INLINE_IMAGE_HEIGHT);
|
||||
if (size.height() > maxHeight) {
|
||||
maxHeight = size.height();
|
||||
}
|
||||
|
||||
// Image i has been drawn.
|
||||
p_index = i + 1;
|
||||
} else {
|
||||
// This image cross the line.
|
||||
endX = p_line->x() + p_line->width() + p_margin;
|
||||
if (end - img.m_startPos >= ((img.m_endPos - img.m_startPos) >> 1)) {
|
||||
// Put image at this side.
|
||||
p_images.append(&img);
|
||||
p_imageRange.append(QPair<qreal, qreal>(startX, endX));
|
||||
|
||||
QSize size = img.m_imageSize;
|
||||
scaleSize(size, endX - startX, MAX_INLINE_IMAGE_HEIGHT);
|
||||
if (size.height() > maxHeight) {
|
||||
maxHeight = size.height();
|
||||
}
|
||||
|
||||
// Image i has been drawn.
|
||||
p_index = i + 1;
|
||||
} else {
|
||||
// Just put a marker here.
|
||||
p_images.append(NULL);
|
||||
p_imageRange.append(QPair<qreal, qreal>(startX, endX));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if (img.m_endPos > start && img.m_startPos < start) {
|
||||
qreal startX = p_line->x() + p_margin;
|
||||
qreal endX = img.m_endPos > end ? p_line->x() + p_line->width()
|
||||
: p_line->cursorToX(img.m_endPos);
|
||||
if (p_index <= i) {
|
||||
// Image i has not been drawn. Draw it here.
|
||||
p_images.append(&img);
|
||||
p_imageRange.append(QPair<qreal, qreal>(startX, endX));
|
||||
|
||||
QSize size = img.m_imageSize;
|
||||
scaleSize(size, endX - startX, MAX_INLINE_IMAGE_HEIGHT);
|
||||
if (size.height() > maxHeight) {
|
||||
maxHeight = size.height();
|
||||
}
|
||||
|
||||
// Image i has been drawn.
|
||||
p_index = i + 1;
|
||||
} else {
|
||||
// Image i has been drawn. Just put a marker here.
|
||||
p_images.append(NULL);
|
||||
p_imageRange.append(QPair<qreal, qreal>(startX, endX));
|
||||
}
|
||||
|
||||
if (img.m_endPos >= end) {
|
||||
break;
|
||||
}
|
||||
} else if (img.m_endPos <= start) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
|
@ -57,6 +57,27 @@ protected:
|
||||
void documentChanged(int p_from, int p_charsRemoved, int p_charsAdded) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Denote the start and end position of a marker line.
|
||||
struct Marker
|
||||
{
|
||||
QPointF m_start;
|
||||
QPointF m_end;
|
||||
};
|
||||
|
||||
struct ImagePaintInfo
|
||||
{
|
||||
// The rect to draw the image.
|
||||
QRectF m_rect;
|
||||
|
||||
// Name of the image.
|
||||
QString m_name;
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
return !m_name.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockInfo
|
||||
{
|
||||
BlockInfo()
|
||||
@ -68,6 +89,8 @@ private:
|
||||
{
|
||||
m_offset = -1;
|
||||
m_rect = QRectF();
|
||||
m_markers.clear();
|
||||
m_images.clear();
|
||||
}
|
||||
|
||||
bool hasOffset() const
|
||||
@ -94,10 +117,50 @@ private:
|
||||
// The bounding rect of this block, including the margins.
|
||||
// Null for invalid.
|
||||
QRectF m_rect;
|
||||
|
||||
// Markers to draw for this block.
|
||||
// Y is the offset within this block.
|
||||
QVector<Marker> m_markers;
|
||||
|
||||
// Images to draw for this block.
|
||||
// Y is the offset within this block.
|
||||
QVector<ImagePaintInfo> m_images;
|
||||
};
|
||||
|
||||
void layoutBlock(const QTextBlock &p_block);
|
||||
|
||||
// Returns the total height of this block after layouting lines and inline
|
||||
// images.
|
||||
qreal layoutLines(const QTextBlock &p_block,
|
||||
QTextLayout *p_tl,
|
||||
QVector<Marker> &p_markers,
|
||||
QVector<ImagePaintInfo> &p_images,
|
||||
qreal p_availableWidth,
|
||||
qreal p_height);
|
||||
|
||||
// Layout inline image in a line.
|
||||
// @p_info: if NULL, means just layout a marker.
|
||||
// Returns the image height.
|
||||
void layoutInlineImage(const VBlockImageInfo2 *p_info,
|
||||
qreal p_heightInBlock,
|
||||
qreal p_imageSpaceHeight,
|
||||
qreal p_xStart,
|
||||
qreal p_xEnd,
|
||||
QVector<Marker> &p_markers,
|
||||
QVector<ImagePaintInfo> &p_images);
|
||||
|
||||
// Get inline images belonging to @p_line from @p_info.
|
||||
// @p_index: image [0, p_index) has been drawn.
|
||||
// @p_images: contains all images and markers (NULL element indicates it
|
||||
// is just a placeholder for the marker.
|
||||
// Returns the maximum height of the images.
|
||||
qreal fetchInlineImagesForOneLine(const QVector<VBlockImageInfo2> &p_info,
|
||||
const QTextLine *p_line,
|
||||
qreal p_margin,
|
||||
int &p_index,
|
||||
QVector<const VBlockImageInfo2 *> &p_images,
|
||||
QVector<QPair<qreal, qreal>> &p_imageRange);
|
||||
|
||||
// Clear the layout of @p_block.
|
||||
// Also clear all the offset behind this block.
|
||||
void clearBlockLayout(QTextBlock &p_block);
|
||||
@ -115,7 +178,9 @@ private:
|
||||
|
||||
bool validateBlocks() const;
|
||||
|
||||
void finishBlockLayout(const QTextBlock &p_block);
|
||||
void finishBlockLayout(const QTextBlock &p_block,
|
||||
const QVector<Marker> &p_markers,
|
||||
const QVector<ImagePaintInfo> &p_images);
|
||||
|
||||
int previousValidBlockNumber(int p_number) const;
|
||||
|
||||
@ -136,8 +201,11 @@ private:
|
||||
void blockRangeFromRectBS(const QRectF &p_rect, int &p_first, int &p_last) const;
|
||||
|
||||
// Return a rect from the layout.
|
||||
// If @p_imageRect is not NULL and there is block image for this block, it will
|
||||
// be set to the rect of that image.
|
||||
// Return a null rect if @p_block has not been layouted.
|
||||
QRectF blockRectFromTextLayout(const QTextBlock &p_block);
|
||||
QRectF blockRectFromTextLayout(const QTextBlock &p_block,
|
||||
ImagePaintInfo *p_image = NULL);
|
||||
|
||||
// Update document size when only block @p_blockNumber is changed and the height
|
||||
// remain the same.
|
||||
@ -150,9 +218,15 @@ private:
|
||||
|
||||
// Draw images of block @p_block.
|
||||
// @p_offset: the offset for the drawing of the block.
|
||||
void drawBlockImage(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset);
|
||||
void drawImages(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset);
|
||||
|
||||
void drawMarkers(QPainter *p_painter,
|
||||
const QTextBlock &p_block,
|
||||
const QPointF &p_offset);
|
||||
|
||||
void scaleSize(QSize &p_size, int p_width, int p_height);
|
||||
|
||||
// Document margin on left/right/bottom.
|
||||
qreal m_margin;
|
||||
@ -201,4 +275,10 @@ inline void VTextDocumentLayout::setImageLineColor(const QColor &p_color)
|
||||
m_imageLineColor = p_color;
|
||||
}
|
||||
|
||||
inline void VTextDocumentLayout::scaleSize(QSize &p_size, int p_width, int p_height)
|
||||
{
|
||||
if (p_size.width() > p_width || p_size.height() > p_height) {
|
||||
p_size.scale(p_width, p_height, Qt::KeepAspectRatio);
|
||||
}
|
||||
}
|
||||
#endif // VTEXTDOCUMENTLAYOUT_H
|
||||
|
@ -50,6 +50,19 @@ public:
|
||||
&& m_imageSize == p_other.m_imageSize;
|
||||
}
|
||||
|
||||
bool operator<(const VBlockImageInfo2 &p_other) const
|
||||
{
|
||||
if (m_blockNumber < p_other.m_blockNumber) {
|
||||
return true;
|
||||
} else if (m_blockNumber > p_other.m_blockNumber) {
|
||||
return false;
|
||||
} else if (m_startPos < p_other.m_startPos) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
return QString("VBlockImageInfo2 block %1 start %2 end %3 padding %4 "
|
||||
|
Loading…
x
Reference in New Issue
Block a user