Support filling highlight path in Text.
This commit is contained in:
parent
dc8313f6ae
commit
6dc93b53a1
3 changed files with 221 additions and 83 deletions
|
|
@ -199,6 +199,13 @@ void FillQuotePaint(
|
||||||
const style::QuoteStyle &st,
|
const style::QuoteStyle &st,
|
||||||
SkipBlockPaintParts parts = {});
|
SkipBlockPaintParts parts = {});
|
||||||
|
|
||||||
|
struct HighlightInfoRequest {
|
||||||
|
TextSelection range;
|
||||||
|
QRect interpolateTo;
|
||||||
|
float64 interpolateProgress = 0.;
|
||||||
|
QPainterPath *outPath = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct PaintContext {
|
struct PaintContext {
|
||||||
QPoint position;
|
QPoint position;
|
||||||
int outerWidth = 0; // For automatic RTL Ui inversion.
|
int outerWidth = 0; // For automatic RTL Ui inversion.
|
||||||
|
|
@ -220,6 +227,8 @@ struct PaintContext {
|
||||||
TextSelection selection;
|
TextSelection selection;
|
||||||
bool fullWidthSelection = true;
|
bool fullWidthSelection = true;
|
||||||
|
|
||||||
|
HighlightInfoRequest *highlight = nullptr;
|
||||||
|
|
||||||
int elisionHeight = 0;
|
int elisionHeight = 0;
|
||||||
int elisionRemoveFromEnd = 0;
|
int elisionRemoveFromEnd = 0;
|
||||||
bool elisionOneLine = false;
|
bool elisionOneLine = false;
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,7 @@ void Renderer::draw(QPainter &p, const PaintContext &context) {
|
||||||
_breakEverywhere = _geometry.breakEverywhere;
|
_breakEverywhere = _geometry.breakEverywhere;
|
||||||
_spoilerCache = context.spoiler;
|
_spoilerCache = context.spoiler;
|
||||||
_selection = context.selection;
|
_selection = context.selection;
|
||||||
|
_highlight = context.highlight;
|
||||||
_fullWidthSelection = context.fullWidthSelection;
|
_fullWidthSelection = context.fullWidthSelection;
|
||||||
_align = context.align;
|
_align = context.align;
|
||||||
_cachedNow = context.now;
|
_cachedNow = context.now;
|
||||||
|
|
@ -245,6 +246,9 @@ void Renderer::enumerate() {
|
||||||
if (_p) {
|
if (_p) {
|
||||||
paintSpoilerRects();
|
paintSpoilerRects();
|
||||||
}
|
}
|
||||||
|
if (_highlight) {
|
||||||
|
composeHighlightPath();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
auto blockIndex = 0;
|
auto blockIndex = 0;
|
||||||
|
|
@ -892,39 +896,39 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} else if (_p && (_type == TextBlockType::Emoji || _type == TextBlockType::CustomEmoji)) {
|
} else if (_p
|
||||||
|
&& (_type == TextBlockType::Emoji
|
||||||
|
|| _type == TextBlockType::CustomEmoji)) {
|
||||||
auto glyphX = x;
|
auto glyphX = x;
|
||||||
auto spacesWidth = (si.width - currentBlock->f_width());
|
auto spacesWidth = (si.width - currentBlock->f_width());
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
glyphX += spacesWidth;
|
glyphX += spacesWidth;
|
||||||
}
|
}
|
||||||
FixedRange fillSelect;
|
const auto fillSelect = _background.selectActiveBlock
|
||||||
FixedRange fillSpoiler;
|
? FixedRange{ x, x + si.width }
|
||||||
if (_background.selectActiveBlock) {
|
: findSelectEmojiRange(
|
||||||
fillSelect = { x, x + si.width };
|
si,
|
||||||
} else if (_localFrom + si.position < _selection.to) {
|
currentBlock,
|
||||||
auto chFrom = _str + currentBlock->position();
|
nextBlock,
|
||||||
auto chTo = chFrom + ((nextBlock ? nextBlock->position() : _t->_text.size()) - currentBlock->position());
|
x,
|
||||||
if (_localFrom + si.position >= _selection.from) { // could be without space
|
glyphX,
|
||||||
if (chTo == chFrom || (chTo - 1)->unicode() != QChar::Space || _selection.to >= (chTo - _str)) {
|
_selection);
|
||||||
fillSelect = { x, x + si.width };
|
fillSelectRange(fillSelect);
|
||||||
} else { // or with space
|
if (_highlight) {
|
||||||
fillSelect = { glyphX, glyphX + currentBlock->f_width() };
|
pushHighlightRange(findSelectEmojiRange(
|
||||||
}
|
si,
|
||||||
} else if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space && (chTo - 1 - _str) >= _selection.from) {
|
currentBlock,
|
||||||
if (rtl) { // rtl space only
|
nextBlock,
|
||||||
fillSelect = { x, glyphX };
|
x,
|
||||||
} else { // ltr space only
|
glyphX,
|
||||||
fillSelect = { x + currentBlock->f_width(), x + si.width };
|
_highlight->range));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto hasSpoiler = _background.spoiler
|
const auto hasSpoiler = _background.spoiler
|
||||||
&& (_spoilerOpacity > 0.);
|
&& (_spoilerOpacity > 0.);
|
||||||
if (hasSpoiler) {
|
const auto fillSpoiler = hasSpoiler
|
||||||
fillSpoiler = { x, x + si.width };
|
? FixedRange{ x, x + si.width }
|
||||||
}
|
: FixedRange();
|
||||||
fillSelectRange(fillSelect);
|
|
||||||
const auto opacity = _p->opacity();
|
const auto opacity = _p->opacity();
|
||||||
if (!hasSpoiler || _spoilerOpacity < 1.) {
|
if (!hasSpoiler || _spoilerOpacity < 1.) {
|
||||||
if (hasSpoiler) {
|
if (hasSpoiler) {
|
||||||
|
|
@ -1058,58 +1062,39 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
gf.justified = false;
|
gf.justified = false;
|
||||||
InitTextItemWithScriptItem(gf, si);
|
InitTextItemWithScriptItem(gf, si);
|
||||||
|
|
||||||
auto itemRange = FixedRange{ x, x + itemWidth };
|
const auto itemRange = FixedRange{ x, x + itemWidth };
|
||||||
auto fillSelect = FixedRange();
|
|
||||||
auto hasSelected = false;
|
|
||||||
auto hasNotSelected = true;
|
|
||||||
auto selectedRect = QRect();
|
auto selectedRect = QRect();
|
||||||
if (_background.selectActiveBlock) {
|
auto fillSelect = itemRange;
|
||||||
fillSelect = itemRange;
|
if (!_background.selectActiveBlock) {
|
||||||
fillSelectRange(fillSelect);
|
fillSelect = findSelectTextRange(
|
||||||
} else if (_localFrom + itemStart < _selection.to && _localFrom + itemEnd > _selection.from) {
|
si,
|
||||||
hasSelected = true;
|
itemStart,
|
||||||
auto selX = x;
|
itemEnd,
|
||||||
auto selWidth = itemWidth;
|
x,
|
||||||
if (_localFrom + itemStart >= _selection.from && _localFrom + itemEnd <= _selection.to) {
|
itemWidth,
|
||||||
hasNotSelected = false;
|
gf,
|
||||||
} else {
|
_selection);
|
||||||
selWidth = 0;
|
const auto from = fillSelect.from.toInt();
|
||||||
int itemL = itemEnd - itemStart;
|
selectedRect = QRect(
|
||||||
int selStart = _selection.from - (_localFrom + itemStart), selEnd = _selection.to - (_localFrom + itemStart);
|
from,
|
||||||
if (selStart < 0) selStart = 0;
|
_y + _yDelta,
|
||||||
if (selEnd > itemL) selEnd = itemL;
|
fillSelect.till.toInt() - from,
|
||||||
for (int ch = 0, g; ch < selEnd;) {
|
_fontHeight);
|
||||||
g = logClusters[itemStart - si.position + ch];
|
}
|
||||||
QFixed gwidth = glyphs.effectiveAdvance(g);
|
const auto hasSelected = !fillSelect.empty();
|
||||||
// ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes
|
const auto hasNotSelected = (fillSelect.from != itemRange.from)
|
||||||
int ch2 = ch + 1;
|
|| (fillSelect.till != itemRange.till);
|
||||||
while ((ch2 < itemL) && (g == logClusters[itemStart - si.position + ch2])) {
|
|
||||||
++ch2;
|
|
||||||
}
|
|
||||||
if (ch2 <= selStart) {
|
|
||||||
selX += gwidth;
|
|
||||||
} else if (ch >= selStart && ch2 <= selEnd) {
|
|
||||||
selWidth += gwidth;
|
|
||||||
} else {
|
|
||||||
int sStart = ch, sEnd = ch2;
|
|
||||||
if (ch < selStart) {
|
|
||||||
sStart = selStart;
|
|
||||||
selX += QFixed(sStart - ch) * gwidth / QFixed(ch2 - ch);
|
|
||||||
}
|
|
||||||
if (ch2 >= selEnd) {
|
|
||||||
sEnd = selEnd;
|
|
||||||
selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch);
|
|
||||||
}
|
|
||||||
ch = ch2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rtl) selX = x + itemWidth - (selX - x) - selWidth;
|
|
||||||
selectedRect = QRect(selX.toInt(), _y + _yDelta, (selX + selWidth).toInt() - selX.toInt(), _fontHeight);
|
|
||||||
fillSelect = { selX, selX + selWidth };
|
|
||||||
fillSelectRange(fillSelect);
|
fillSelectRange(fillSelect);
|
||||||
|
|
||||||
|
if (_highlight) {
|
||||||
|
pushHighlightRange(findSelectTextRange(
|
||||||
|
si,
|
||||||
|
itemStart,
|
||||||
|
itemEnd,
|
||||||
|
x,
|
||||||
|
itemWidth,
|
||||||
|
gf,
|
||||||
|
_highlight->range));
|
||||||
}
|
}
|
||||||
const auto hasSpoiler = _background.spoiler
|
const auto hasSpoiler = _background.spoiler
|
||||||
&& (_spoilerOpacity > 0.);
|
&& (_spoilerOpacity > 0.);
|
||||||
|
|
@ -1200,10 +1185,98 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
|
||||||
|
|
||||||
x += itemWidth;
|
x += itemWidth;
|
||||||
}
|
}
|
||||||
fillSpoilerRects();
|
fillRectsFromRanges();
|
||||||
return !_elidedLine;
|
return !_elidedLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FixedRange Renderer::findSelectEmojiRange(
|
||||||
|
const QScriptItem &si,
|
||||||
|
const Ui::Text::AbstractBlock *currentBlock,
|
||||||
|
const Ui::Text::AbstractBlock *nextBlock,
|
||||||
|
QFixed x,
|
||||||
|
QFixed glyphX,
|
||||||
|
TextSelection selection) const {
|
||||||
|
if (_localFrom + si.position >= selection.to) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto chFrom = _str + currentBlock->position();
|
||||||
|
auto chTo = chFrom + ((nextBlock ? nextBlock->position() : _t->_text.size()) - currentBlock->position());
|
||||||
|
if (_localFrom + si.position >= selection.from) { // could be without space
|
||||||
|
if (chTo == chFrom || (chTo - 1)->unicode() != QChar::Space || selection.to >= (chTo - _str)) {
|
||||||
|
return { x, x + si.width };
|
||||||
|
} else { // or with space
|
||||||
|
return { glyphX, glyphX + currentBlock->f_width() };
|
||||||
|
}
|
||||||
|
} else if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space && (chTo - 1 - _str) >= selection.from) {
|
||||||
|
const auto rtl = (si.analysis.bidiLevel % 2);
|
||||||
|
if (rtl) { // rtl space only
|
||||||
|
return { x, glyphX };
|
||||||
|
} else { // ltr space only
|
||||||
|
return { x + currentBlock->f_width(), x + si.width };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedRange Renderer::findSelectTextRange(
|
||||||
|
const QScriptItem &si,
|
||||||
|
int itemStart,
|
||||||
|
int itemEnd,
|
||||||
|
QFixed x,
|
||||||
|
QFixed itemWidth,
|
||||||
|
const QTextItemInt &gf,
|
||||||
|
TextSelection selection) const {
|
||||||
|
if (_localFrom + itemStart >= selection.to
|
||||||
|
|| _localFrom + itemEnd <= selection.from) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto selX = x;
|
||||||
|
auto selWidth = itemWidth;
|
||||||
|
const auto rtl = (si.analysis.bidiLevel % 2);
|
||||||
|
if (_localFrom + itemStart < selection.from
|
||||||
|
|| _localFrom + itemEnd > selection.to) {
|
||||||
|
selWidth = 0;
|
||||||
|
const auto itemL = itemEnd - itemStart;
|
||||||
|
const auto selStart = std::max(
|
||||||
|
selection.from - (_localFrom + itemStart),
|
||||||
|
0);
|
||||||
|
const auto selEnd = std::min(
|
||||||
|
selection.to - (_localFrom + itemStart),
|
||||||
|
itemL);
|
||||||
|
const auto lczero = gf.logClusters[0];
|
||||||
|
for (int ch = 0, g; ch < selEnd;) {
|
||||||
|
g = gf.logClusters[ch];
|
||||||
|
const auto gwidth = gf.glyphs.effectiveAdvance(g - lczero);
|
||||||
|
// ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes
|
||||||
|
int ch2 = ch + 1;
|
||||||
|
while ((ch2 < itemL) && (g == gf.logClusters[ch2])) {
|
||||||
|
++ch2;
|
||||||
|
}
|
||||||
|
if (ch2 <= selStart) {
|
||||||
|
selX += gwidth;
|
||||||
|
} else if (ch >= selStart && ch2 <= selEnd) {
|
||||||
|
selWidth += gwidth;
|
||||||
|
} else {
|
||||||
|
int sStart = ch, sEnd = ch2;
|
||||||
|
if (ch < selStart) {
|
||||||
|
sStart = selStart;
|
||||||
|
selX += QFixed(sStart - ch) * gwidth / QFixed(ch2 - ch);
|
||||||
|
}
|
||||||
|
if (ch2 >= selEnd) {
|
||||||
|
sEnd = selEnd;
|
||||||
|
selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
selWidth += QFixed(sEnd - sStart) * gwidth / QFixed(ch2 - ch);
|
||||||
|
}
|
||||||
|
ch = ch2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rtl) selX = x + itemWidth - (selX - x) - selWidth;
|
||||||
|
|
||||||
|
return { selX, selX + selWidth };
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::fillSelectRange(FixedRange range) {
|
void Renderer::fillSelectRange(FixedRange range) {
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1213,6 +1286,13 @@ void Renderer::fillSelectRange(FixedRange range) {
|
||||||
_p->fillRect(left, _y + _yDelta, width, _fontHeight, _palette->selectBg);
|
_p->fillRect(left, _y + _yDelta, width, _fontHeight, _palette->selectBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::pushHighlightRange(FixedRange range) {
|
||||||
|
if (range.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AppendRange(_highlightRanges, range);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::pushSpoilerRange(
|
void Renderer::pushSpoilerRange(
|
||||||
FixedRange range,
|
FixedRange range,
|
||||||
FixedRange selected,
|
FixedRange selected,
|
||||||
|
|
@ -1233,12 +1313,13 @@ void Renderer::pushSpoilerRange(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::fillSpoilerRects() {
|
void Renderer::fillRectsFromRanges() {
|
||||||
fillSpoilerRects(_spoilerRects, _spoilerRanges);
|
fillRectsFromRanges(_spoilerRects, _spoilerRanges);
|
||||||
fillSpoilerRects(_spoilerSelectedRects, _spoilerSelectedRanges);
|
fillRectsFromRanges(_spoilerSelectedRects, _spoilerSelectedRanges);
|
||||||
|
fillRectsFromRanges(_highlightRects, _highlightRanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::fillSpoilerRects(
|
void Renderer::fillRectsFromRanges(
|
||||||
QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
||||||
QVarLengthArray<FixedRange> &ranges) {
|
QVarLengthArray<FixedRange> &ranges) {
|
||||||
if (ranges.empty()) {
|
if (ranges.empty()) {
|
||||||
|
|
@ -1306,6 +1387,32 @@ void Renderer::paintSpoilerRects(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::composeHighlightPath() {
|
||||||
|
Expects(_highlight != nullptr);
|
||||||
|
Expects(_highlight->outPath != nullptr);
|
||||||
|
|
||||||
|
if (_highlight->interpolateProgress >= 1.) {
|
||||||
|
_highlight->outPath->addRect(_highlight->interpolateTo);
|
||||||
|
} else if (_highlight->interpolateProgress <= 0.) {
|
||||||
|
for (const auto &rect : _highlightRects) {
|
||||||
|
_highlight->outPath->addRect(rect);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const auto to = _highlight->interpolateTo;
|
||||||
|
const auto progress = _highlight->interpolateProgress;
|
||||||
|
const auto lerp = [=](int from, int to) {
|
||||||
|
return from + (to - from) * progress;
|
||||||
|
};
|
||||||
|
for (const auto &rect : _highlightRects) {
|
||||||
|
_highlight->outPath->addRect(
|
||||||
|
lerp(rect.x(), to.x()),
|
||||||
|
lerp(rect.y(), to.y()),
|
||||||
|
lerp(rect.width(), to.width()),
|
||||||
|
lerp(rect.height(), to.height()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::elideSaveBlock(int32 blockIndex, const AbstractBlock *&_endBlock, int32 elideStart, int32 elideWidth) {
|
void Renderer::elideSaveBlock(int32 blockIndex, const AbstractBlock *&_endBlock, int32 elideStart, int32 elideWidth) {
|
||||||
if (_elideSavedBlock) {
|
if (_elideSavedBlock) {
|
||||||
restoreAfterElided();
|
restoreAfterElided();
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@
|
||||||
|
|
||||||
#include <private/qtextengine_p.h>
|
#include <private/qtextengine_p.h>
|
||||||
|
|
||||||
|
class QTextItemInt;
|
||||||
struct QScriptAnalysis;
|
struct QScriptAnalysis;
|
||||||
struct QScriptLine;
|
struct QScriptLine;
|
||||||
|
struct QScriptItem;
|
||||||
|
|
||||||
namespace Ui::Text {
|
namespace Ui::Text {
|
||||||
|
|
||||||
|
|
@ -62,13 +64,29 @@ private:
|
||||||
uint16 _lineEnd,
|
uint16 _lineEnd,
|
||||||
const String::TextBlocks::const_iterator &_endBlockIter,
|
const String::TextBlocks::const_iterator &_endBlockIter,
|
||||||
const String::TextBlocks::const_iterator &_end);
|
const String::TextBlocks::const_iterator &_end);
|
||||||
|
[[nodiscard]] FixedRange findSelectEmojiRange(
|
||||||
|
const QScriptItem &si,
|
||||||
|
const Ui::Text::AbstractBlock *currentBlock,
|
||||||
|
const Ui::Text::AbstractBlock *nextBlock,
|
||||||
|
QFixed x,
|
||||||
|
QFixed glyphX,
|
||||||
|
TextSelection selection) const;
|
||||||
|
[[nodiscard]] FixedRange findSelectTextRange(
|
||||||
|
const QScriptItem &si,
|
||||||
|
int itemStart,
|
||||||
|
int itemEnd,
|
||||||
|
QFixed x,
|
||||||
|
QFixed itemWidth,
|
||||||
|
const QTextItemInt &gf,
|
||||||
|
TextSelection selection) const;
|
||||||
void fillSelectRange(FixedRange range);
|
void fillSelectRange(FixedRange range);
|
||||||
|
void pushHighlightRange(FixedRange range);
|
||||||
void pushSpoilerRange(
|
void pushSpoilerRange(
|
||||||
FixedRange range,
|
FixedRange range,
|
||||||
FixedRange selected,
|
FixedRange selected,
|
||||||
bool isElidedItem);
|
bool isElidedItem);
|
||||||
void fillSpoilerRects();
|
void fillRectsFromRanges();
|
||||||
void fillSpoilerRects(
|
void fillRectsFromRanges(
|
||||||
QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
||||||
QVarLengthArray<FixedRange> &ranges);
|
QVarLengthArray<FixedRange> &ranges);
|
||||||
void paintSpoilerRects();
|
void paintSpoilerRects();
|
||||||
|
|
@ -76,6 +94,7 @@ private:
|
||||||
const QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
const QVarLengthArray<QRect, kSpoilersRectsSize> &rects,
|
||||||
const style::color &color,
|
const style::color &color,
|
||||||
int index);
|
int index);
|
||||||
|
void composeHighlightPath();
|
||||||
void elideSaveBlock(
|
void elideSaveBlock(
|
||||||
int32 blockIndex,
|
int32 blockIndex,
|
||||||
const AbstractBlock *&_endBlock,
|
const AbstractBlock *&_endBlock,
|
||||||
|
|
@ -137,13 +156,16 @@ private:
|
||||||
int _yTo = 0;
|
int _yTo = 0;
|
||||||
TextSelection _selection = { 0, 0 };
|
TextSelection _selection = { 0, 0 };
|
||||||
bool _fullWidthSelection = true;
|
bool _fullWidthSelection = true;
|
||||||
|
HighlightInfoRequest *_highlight = nullptr;
|
||||||
const QChar *_str = nullptr;
|
const QChar *_str = nullptr;
|
||||||
mutable crl::time _cachedNow = 0;
|
mutable crl::time _cachedNow = 0;
|
||||||
float64 _spoilerOpacity = 0.;
|
float64 _spoilerOpacity = 0.;
|
||||||
QVarLengthArray<FixedRange> _spoilerRanges;
|
QVarLengthArray<FixedRange> _spoilerRanges;
|
||||||
QVarLengthArray<FixedRange> _spoilerSelectedRanges;
|
QVarLengthArray<FixedRange> _spoilerSelectedRanges;
|
||||||
|
QVarLengthArray<FixedRange> _highlightRanges;
|
||||||
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerRects;
|
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerRects;
|
||||||
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerSelectedRects;
|
QVarLengthArray<QRect, kSpoilersRectsSize> _spoilerSelectedRects;
|
||||||
|
QVarLengthArray<QRect, kSpoilersRectsSize> _highlightRects;
|
||||||
|
|
||||||
std::optional<CustomEmoji::Context> _customEmojiContext;
|
std::optional<CustomEmoji::Context> _customEmojiContext;
|
||||||
int _customEmojiSize = 0;
|
int _customEmojiSize = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue