Support quote icon in blockquote.

This commit is contained in:
John Preston 2023-10-13 16:13:08 +04:00
parent 6e7c4c1c4d
commit 46465fc5ce
4 changed files with 56 additions and 34 deletions

View file

@ -19,17 +19,24 @@ TextPalette {
linkAlwaysActive: bool; linkAlwaysActive: bool;
} }
ParagraphStyle {
padding: margins;
verticalSkip: pixels;
header: pixels;
headerPosition: point;
icon: icon;
iconPosition: point;
outline: pixels;
radius: pixels;
scrollable: bool;
}
TextStyle { TextStyle {
font: font; font: font;
linkUnderline: int; linkUnderline: int;
blockPadding: margins;
blockVerticalSkip: pixels;
blockHeader: pixels;
blockHeaderPosition: point;
blockOutline: pixels;
blockRadius: pixels;
preScrollable: bool;
lineHeight: pixels; lineHeight: pixels;
blockquote: ParagraphStyle;
pre: ParagraphStyle;
} }
kLinkUnderlineNever: 0; kLinkUnderlineNever: 0;
@ -58,10 +65,14 @@ defaultTextPalette: TextPalette {
selectSpoilerFg: msgInDateFgSelected; selectSpoilerFg: msgInDateFgSelected;
selectOverlay: msgSelectOverlay; selectOverlay: msgSelectOverlay;
} }
defaultParagraphStyle: ParagraphStyle {
}
defaultTextStyle: TextStyle { defaultTextStyle: TextStyle {
font: normalFont; font: normalFont;
linkUnderline: kLinkUnderlineActive; linkUnderline: kLinkUnderlineActive;
lineHeight: 0px; lineHeight: 0px;
blockquote: defaultParagraphStyle;
pre: defaultParagraphStyle;
} }
semiboldTextStyle: TextStyle(defaultTextStyle) { semiboldTextStyle: TextStyle(defaultTextStyle) {
font: semiboldFont; font: semiboldFont;

View file

@ -185,29 +185,34 @@ GeometryDescriptor SimpleGeometry(
} }
}; };
void ValidateBlockPaintCache( void ValidateBlockPaintCache(
BlockPaintCache &cache, BlockPaintCache &cache,
const style::TextStyle &st) { const style::ParagraphStyle &st) {
const auto icon = st.icon.empty() ? nullptr : &st.icon;
if (!cache.corners.isNull() if (!cache.corners.isNull()
&& cache.bgCached == cache.bg && cache.bgCached == cache.bg
&& cache.outlineCached == cache.outline && cache.outlineCached == cache.outline
&& (!cache.withHeader || cache.headerCached == cache.header) && (!st.header || cache.headerCached == cache.header)
&& (!cache.topright || cache.iconCached == cache.icon)) { && (!icon || cache.iconCached == cache.icon)) {
return; return;
} }
cache.bgCached = cache.bg; cache.bgCached = cache.bg;
cache.outlineCached = cache.outline; cache.outlineCached = cache.outline;
if (cache.withHeader) { if (st.header) {
cache.headerCached = cache.header; cache.headerCached = cache.header;
} }
if (cache.topright) { if (!st.icon.empty()) {
cache.iconCached = cache.icon; cache.iconCached = cache.icon;
} }
const auto radius = st.blockRadius; const auto radius = st.radius;
const auto header = cache.withHeader ? st.blockHeader : 0; const auto header = st.header;
const auto outline = st.blockOutline; const auto outline = st.outline;
const auto corner = std::max({ header, radius, outline }); const auto iconsize = icon
? std::max(
icon->width() + st.iconPosition.x(),
icon->height() + st.iconPosition.y())
: 0;
const auto corner = std::max({ header, radius, outline, iconsize });
const auto middle = st::lineWidth; const auto middle = st::lineWidth;
const auto side = 2 * corner + middle; const auto side = 2 * corner + middle;
const auto full = QSize(side, side); const auto full = QSize(side, side);
@ -233,6 +238,11 @@ void ValidateBlockPaintCache(
p.setBrush(cache.bg); p.setBrush(cache.bg);
p.setClipRect(outline, header, side - outline, side - header); p.setClipRect(outline, header, side - outline, side - header);
p.drawRoundedRect(0, 0, side, side, radius, radius); p.drawRoundedRect(0, 0, side, side, radius, radius);
if (icon) {
const auto left = side - icon->width() - st.iconPosition.x();
const auto top = st.iconPosition.y();
icon->paint(p, left, top, side, cache.icon);
}
p.end(); p.end();
cache.corners = std::move(image); cache.corners = std::move(image);
@ -242,7 +252,7 @@ void FillBlockPaint(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
const BlockPaintCache &cache, const BlockPaintCache &cache,
const style::TextStyle &st, const style::ParagraphStyle &st,
SkipBlockPaintParts parts) { SkipBlockPaintParts parts) {
const auto &image = cache.corners; const auto &image = cache.corners;
const auto ratio = int(image.devicePixelRatio()); const auto ratio = int(image.devicePixelRatio());
@ -265,7 +275,7 @@ void FillBlockPaint(
image, image,
QRect((iwidth - ihalf) * ratio, 0, ihalf * ratio, top * ratio)); QRect((iwidth - ihalf) * ratio, 0, ihalf * ratio, top * ratio));
if (const auto middle = width - 2 * ihalf) { if (const auto middle = width - 2 * ihalf) {
const auto header = cache.withHeader ? st.blockHeader : 0; const auto header = st.header;
const auto fillHeader = std::min(header, top); const auto fillHeader = std::min(header, top);
if (fillHeader) { if (fillHeader) {
p.fillRect(x + ihalf, y, middle, fillHeader, cache.header); p.fillRect(x + ihalf, y, middle, fillHeader, cache.header);
@ -316,7 +326,7 @@ void FillBlockPaint(
} }
rect.setHeight(height); rect.setHeight(height);
} }
const auto outline = st.blockOutline; const auto outline = st.outline;
if (outline) { if (outline) {
p.fillRect(x, y, outline, height, cache.outline); p.fillRect(x, y, outline, height, cache.outline);
} }
@ -1086,9 +1096,10 @@ QMargins String::paragraphPadding(ParagraphDetails *info) const {
if (!info) { if (!info) {
return {}; return {};
} }
const auto skip = _st->blockVerticalSkip; const auto &st = info->pre ? _st->pre : _st->blockquote;
const auto top = info->pre ? _st->blockHeader : 0; const auto skip = st.verticalSkip;
return _st->blockPadding + QMargins(0, top + skip, 0, skip); const auto top = st.header;
return st.padding + QMargins(0, top + skip, 0, skip);
} }
template < template <

View file

@ -24,6 +24,7 @@ enum class type : uchar;
namespace style { namespace style {
struct TextStyle; struct TextStyle;
struct TextPalette; struct TextPalette;
struct ParagraphStyle;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -175,15 +176,11 @@ struct BlockPaintCache {
QColor bg; QColor bg;
QColor outline; QColor outline;
QColor icon; QColor icon;
const style::icon *topright = nullptr;
QPoint toprightPosition;
bool withHeader = false;
}; };
void ValidateBlockPaintCache( void ValidateBlockPaintCache(
BlockPaintCache &cache, BlockPaintCache &cache,
const style::TextStyle &st); const style::ParagraphStyle &st);
struct SkipBlockPaintParts { struct SkipBlockPaintParts {
bool skipTop : 1 = false; bool skipTop : 1 = false;
@ -193,7 +190,7 @@ void FillBlockPaint(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
const BlockPaintCache &cache, const BlockPaintCache &cache,
const style::TextStyle &st, const style::ParagraphStyle &st,
SkipBlockPaintParts parts = {}); SkipBlockPaintParts parts = {});
struct PaintContext { struct PaintContext {

View file

@ -415,29 +415,32 @@ void Renderer::fillParagraphBg(int paddingBottom) {
? _blockquoteBlockCache ? _blockquoteBlockCache
: nullptr; : nullptr;
if (cache) { if (cache) {
const auto &st = _paragraph->pre
? _t->_st->pre
: _t->_st->blockquote;
auto &valid = _paragraph->pre auto &valid = _paragraph->pre
? _preBlockCacheValid ? _preBlockCacheValid
: _blockquoteBlockCacheValid; : _blockquoteBlockCacheValid;
if (!valid) { if (!valid) {
valid = true; valid = true;
ValidateBlockPaintCache(*cache, *_t->_st); ValidateBlockPaintCache(*cache, st);
} }
const auto skip = _t->_st->blockVerticalSkip; const auto skip = st.verticalSkip;
const auto isTop = (_y != _blockLineTop); const auto isTop = (_y != _blockLineTop);
const auto isBottom = (paddingBottom != 0); const auto isBottom = (paddingBottom != 0);
const auto top = _blockLineTop + (isTop ? skip : 0); const auto top = _blockLineTop + (isTop ? skip : 0);
const auto fill = _y + _lineHeight + paddingBottom - top const auto fill = _y + _lineHeight + paddingBottom - top
- (isBottom ? skip : 0); - (isBottom ? skip : 0);
const auto rect = QRect(_startLeft, top, _startLineWidth, fill); const auto rect = QRect(_startLeft, top, _startLineWidth, fill);
FillBlockPaint(*_p, rect, *cache, *_t->_st, { FillBlockPaint(*_p, rect, *cache, st, {
.skipTop = !isTop, .skipTop = !isTop,
.skipBottom = !isBottom, .skipBottom = !isBottom,
}); });
if (isTop && cache->withHeader) { if (isTop && st.header > 0) {
const auto font = _t->_st->font->monospace(); const auto font = _t->_st->font->monospace();
const auto topleft = rect.topLeft(); const auto topleft = rect.topLeft();
const auto position = topleft + _t->_st->blockHeaderPosition; const auto position = topleft + st.headerPosition;
const auto baseline = position + QPoint(0, font->ascent); const auto baseline = position + QPoint(0, font->ascent);
_p->setFont(font); _p->setFont(font);
_p->setPen(_palette->monoFg->p); _p->setPen(_palette->monoFg->p);