mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 14:50:24 +00:00
Use QImage bubbles background for some Media parts.
This commit is contained in:
parent
f4fdadd3b0
commit
784d57a2bc
@ -619,8 +619,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
.visibleAreaTop = _visibleAreaTop,
|
||||
.visibleAreaTopGlobal = visibleAreaTopGlobal,
|
||||
.clip = clip,
|
||||
.initialShift = top,
|
||||
});
|
||||
}).translated(0, -top);
|
||||
p.translate(0, top);
|
||||
if (context.clip.y() < view->height()) while (top < drawToY) {
|
||||
context.selection = itemRenderSelection(
|
||||
@ -639,8 +638,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
|
||||
const auto height = view->height();
|
||||
top += height;
|
||||
context.viewport.translate(0, -height);
|
||||
context.clip.translate(0, -height);
|
||||
context.translate(0, -height);
|
||||
p.translate(0, height);
|
||||
|
||||
++iItem;
|
||||
@ -672,8 +670,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
.clip = clip.intersected(
|
||||
QRect(0, hdrawtop, width(), clip.top() + clip.height())
|
||||
),
|
||||
.initialShift = top,
|
||||
});
|
||||
}).translated(0, -top);
|
||||
p.translate(0, top);
|
||||
while (top < drawToY) {
|
||||
const auto height = view->height();
|
||||
@ -704,8 +701,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
top += height;
|
||||
context.viewport.translate(0, -height);
|
||||
context.clip.translate(0, -height);
|
||||
context.translate(0, -height);
|
||||
p.translate(0, height);
|
||||
|
||||
++iItem;
|
||||
|
@ -198,6 +198,22 @@ struct PaintContext {
|
||||
QRect clip;
|
||||
TextSelection selection;
|
||||
crl::time now = 0;
|
||||
|
||||
void translate(int x, int y) {
|
||||
viewport.translate(x, y);
|
||||
clip.translate(x, y);
|
||||
}
|
||||
void translate(QPoint point) {
|
||||
translate(point.x(), point.y());
|
||||
}
|
||||
[[nodiscard]] PaintContext translated(int x, int y) const {
|
||||
auto result = *this;
|
||||
result.translate(x, y);
|
||||
return result;
|
||||
}
|
||||
[[nodiscard]] PaintContext translated(QPoint point) const {
|
||||
return translated(point.x(), point.y());
|
||||
}
|
||||
};
|
||||
|
||||
class Element
|
||||
|
@ -594,25 +594,22 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||
auto mediaTop = (trect.y() + trect.height() - mediaHeight);
|
||||
|
||||
p.translate(mediaLeft, mediaTop);
|
||||
media->draw(
|
||||
p,
|
||||
context.clip.translated(-mediaLeft, -mediaTop),
|
||||
skipTextSelection(context.selection), context.now);
|
||||
auto mediaContext = context.translated(-mediaLeft, -mediaTop);
|
||||
mediaContext.selection = skipTextSelection(context.selection);
|
||||
media->draw(p, mediaContext);
|
||||
p.translate(-mediaLeft, -mediaTop);
|
||||
}
|
||||
if (entry) {
|
||||
auto entryLeft = inner.left();
|
||||
auto entryTop = trect.y() + trect.height();
|
||||
p.translate(entryLeft, entryTop);
|
||||
auto entrySelection = skipTextSelection(context.selection);
|
||||
auto entryContext = context.translated(-entryLeft, -entryTop);
|
||||
entryContext.selection = skipTextSelection(context.selection);
|
||||
if (mediaDisplayed) {
|
||||
entrySelection = media->skipSelection(entrySelection);
|
||||
entryContext.selection = media->skipSelection(
|
||||
entryContext.selection);
|
||||
}
|
||||
entry->draw(
|
||||
p,
|
||||
context.clip.translated(-entryLeft, -entryTop),
|
||||
entrySelection,
|
||||
context.now);
|
||||
entry->draw(p, entryContext);
|
||||
p.translate(-entryLeft, -entryTop);
|
||||
}
|
||||
const auto needDrawInfo = entry
|
||||
@ -652,11 +649,9 @@ void Message::draw(Painter &p, const PaintContext &context) const {
|
||||
}
|
||||
} else if (media && media->isDisplayed()) {
|
||||
p.translate(g.topLeft());
|
||||
media->draw(
|
||||
p,
|
||||
context.clip.translated(-g.topLeft()),
|
||||
skipTextSelection(context.selection),
|
||||
context.now);
|
||||
auto mediaContext = context.translated(-g.topLeft());
|
||||
mediaContext.selection = skipTextSelection(context.selection);
|
||||
media->draw(p, mediaContext);
|
||||
p.translate(-g.topLeft());
|
||||
}
|
||||
|
||||
|
@ -561,7 +561,9 @@ void Service::draw(Painter &p, const PaintContext &context) const {
|
||||
height -= st::msgServiceMargin.top() + media->height();
|
||||
auto left = st::msgServiceMargin.left() + (g.width() - media->maxWidth()) / 2, top = st::msgServiceMargin.top() + height + st::msgServiceMargin.top();
|
||||
p.translate(left, top);
|
||||
media->draw(p, clip.translated(-left, -top), TextSelection(), context.now);
|
||||
auto mediaContext = context.translated(-left, -top);
|
||||
mediaContext.selection = TextSelection();
|
||||
media->draw(p, mediaContext);
|
||||
p.translate(-left, -top);
|
||||
}
|
||||
|
||||
|
@ -72,12 +72,12 @@ QSize Call::countOptimalSize() {
|
||||
return { maxWidth, minHeight };
|
||||
}
|
||||
|
||||
void Call::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Call::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
auto selected = (selection == FullSelection);
|
||||
auto selected = (context.selection == FullSelection);
|
||||
|
||||
accumulate_min(paintw, maxWidth());
|
||||
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
not_null<Element*> parent,
|
||||
not_null<Data::Call*> call);
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||
|
@ -153,12 +153,12 @@ QSize Contact::countOptimalSize() {
|
||||
return { maxWidth, minHeight };
|
||||
}
|
||||
|
||||
void Contact::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Contact::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
accumulate_min(paintw, maxWidth());
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
const QString &phone);
|
||||
~Contact();
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/format_song_document_name.h"
|
||||
#include "ui/chat/message_bubble.h"
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "layout/layout_selection.h" // FullSelection
|
||||
@ -325,19 +326,14 @@ QSize Document::countCurrentSize(int newWidth) {
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void Document::draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
TextSelection selection,
|
||||
crl::time ms) const {
|
||||
draw(p, width(), selection, ms, LayoutMode::Full);
|
||||
void Document::draw(Painter &p, const PaintContext &context) const {
|
||||
draw(p, width(), context, LayoutMode::Full);
|
||||
}
|
||||
|
||||
void Document::draw(
|
||||
Painter &p,
|
||||
int width,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
LayoutMode mode) const {
|
||||
if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
@ -349,7 +345,7 @@ void Document::draw(
|
||||
_dataMedia->automaticLoad(_realParent->fullId(), _realParent);
|
||||
}
|
||||
bool loaded = dataLoaded(), displayLoading = _data->displayLoading();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
int captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
@ -507,19 +503,33 @@ void Document::draw(
|
||||
}
|
||||
return nullptr;
|
||||
}();
|
||||
if (previous && radialOpacity > 0. && radialOpacity < 1.) {
|
||||
PaintInterpolatedIcon(p, *icon, *previous, radialOpacity, inner);
|
||||
|
||||
const auto paintContent = [&](Painter &q) {
|
||||
if (previous && radialOpacity > 0. && radialOpacity < 1.) {
|
||||
PaintInterpolatedIcon(q, *icon, *previous, radialOpacity, inner);
|
||||
} else {
|
||||
icon->paintInCenter(q, inner);
|
||||
}
|
||||
|
||||
if (radial && !cornerDownload) {
|
||||
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
|
||||
auto fg = outbg ? (selected ? st::historyFileOutRadialFgSelected : st::historyFileOutRadialFg) : (selected ? st::historyFileInRadialFgSelected : st::historyFileInRadialFg);
|
||||
_animation->radial.draw(q, rinner, st::msgFileRadialLine, fg);
|
||||
}
|
||||
};
|
||||
if (_data->isSongWithCover() || !usesBubblePattern(context)) {
|
||||
paintContent(p);
|
||||
} else {
|
||||
icon->paintInCenter(p, inner);
|
||||
Ui::PaintPatternBubblePart(
|
||||
p,
|
||||
context.viewport,
|
||||
context.bubblesPattern->pixmap,
|
||||
inner,
|
||||
paintContent,
|
||||
_iconCache);
|
||||
}
|
||||
|
||||
if (radial && !cornerDownload) {
|
||||
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
|
||||
auto fg = outbg ? (selected ? st::historyFileOutRadialFgSelected : st::historyFileOutRadialFg) : (selected ? st::historyFileInRadialFgSelected : st::historyFileInRadialFg);
|
||||
_animation->radial.draw(p, rinner, st::msgFileRadialLine, fg);
|
||||
}
|
||||
|
||||
drawCornerDownload(p, selected, mode);
|
||||
drawCornerDownload(p, context, mode);
|
||||
}
|
||||
auto namewidth = width - nameleft - nameright;
|
||||
auto statuswidth = namewidth;
|
||||
@ -595,7 +605,7 @@ void Document::draw(
|
||||
|
||||
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||
captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, selection);
|
||||
captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, context.selection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,7 +635,10 @@ bool Document::downloadInCorner() const {
|
||||
&& IsServerMsgId(_realParent->id);
|
||||
}
|
||||
|
||||
void Document::drawCornerDownload(Painter &p, bool selected, LayoutMode mode) const {
|
||||
void Document::drawCornerDownload(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
LayoutMode mode) const {
|
||||
if (dataLoaded()
|
||||
|| _data->loadedInMediaCache()
|
||||
|| !downloadInCorner()) {
|
||||
@ -633,6 +646,7 @@ void Document::drawCornerDownload(Painter &p, bool selected, LayoutMode mode) co
|
||||
}
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
const auto thumbed = false;
|
||||
const auto &st = (mode == LayoutMode::Full)
|
||||
? (thumbed ? st::msgFileThumbLayout : st::msgFileLayout)
|
||||
@ -640,11 +654,16 @@ void Document::drawCornerDownload(Painter &p, bool selected, LayoutMode mode) co
|
||||
const auto shift = st::historyAudioDownloadShift;
|
||||
const auto size = st::historyAudioDownloadSize;
|
||||
const auto inner = style::rtlrect(st.padding.left() + shift, st.padding.top() - topMinus + shift, size, size, width());
|
||||
auto pen = (selected
|
||||
? (outbg ? st::msgOutBgSelected : st::msgInBgSelected)
|
||||
: (outbg ? st::msgOutBg : st::msgInBg))->p;
|
||||
pen.setWidth(st::lineWidth);
|
||||
p.setPen(pen);
|
||||
const auto bubblePattern = usesBubblePattern(context);
|
||||
if (bubblePattern) {
|
||||
p.setPen(Qt::NoPen);
|
||||
} else {
|
||||
auto pen = (selected
|
||||
? (outbg ? st::msgOutBgSelected : st::msgInBgSelected)
|
||||
: (outbg ? st::msgOutBg : st::msgInBg))->p;
|
||||
pen.setWidth(st::lineWidth);
|
||||
p.setPen(pen);
|
||||
}
|
||||
if (selected) {
|
||||
p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected);
|
||||
} else {
|
||||
@ -660,11 +679,34 @@ void Document::drawCornerDownload(Painter &p, bool selected, LayoutMode mode) co
|
||||
}
|
||||
return &(outbg ? (selected ? st::historyAudioOutDownloadSelected : st::historyAudioOutDownload) : (selected ? st::historyAudioInDownloadSelected : st::historyAudioInDownload));
|
||||
}();
|
||||
icon->paintInCenter(p, inner);
|
||||
if (_animation && _animation->radial.animating()) {
|
||||
const auto rinner = inner.marginsRemoved(QMargins(st::historyAudioRadialLine, st::historyAudioRadialLine, st::historyAudioRadialLine, st::historyAudioRadialLine));
|
||||
auto fg = outbg ? (selected ? st::historyFileOutRadialFgSelected : st::historyFileOutRadialFg) : (selected ? st::historyFileInRadialFgSelected : st::historyFileInRadialFg);
|
||||
_animation->radial.draw(p, rinner, st::historyAudioRadialLine, fg);
|
||||
const auto paintContent = [&](Painter &q) {
|
||||
if (bubblePattern) {
|
||||
auto hq = PainterHighQualityEnabler(q);
|
||||
auto pen = st::msgOutBg->p;
|
||||
pen.setWidth(st::lineWidth);
|
||||
q.setPen(pen);
|
||||
q.setBrush(Qt::NoBrush);
|
||||
q.drawEllipse(inner);
|
||||
}
|
||||
icon->paintInCenter(q, inner);
|
||||
if (_animation && _animation->radial.animating()) {
|
||||
const auto rinner = inner.marginsRemoved(QMargins(st::historyAudioRadialLine, st::historyAudioRadialLine, st::historyAudioRadialLine, st::historyAudioRadialLine));
|
||||
auto fg = outbg ? (selected ? st::historyFileOutRadialFgSelected : st::historyFileOutRadialFg) : (selected ? st::historyFileInRadialFgSelected : st::historyFileInRadialFg);
|
||||
_animation->radial.draw(q, rinner, st::historyAudioRadialLine, fg);
|
||||
}
|
||||
};
|
||||
if (bubblePattern) {
|
||||
const auto add = st::lineWidth * 2;
|
||||
const auto target = inner.marginsAdded({ add, add, add, add });
|
||||
Ui::PaintPatternBubblePart(
|
||||
p,
|
||||
context.viewport,
|
||||
context.bubblesPattern->pixmap,
|
||||
target,
|
||||
paintContent,
|
||||
_cornerDownloadCache);
|
||||
} else {
|
||||
paintContent(p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -978,9 +1020,7 @@ QSize Document::sizeForGrouping(int width) const {
|
||||
|
||||
void Document::drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
@ -991,8 +1031,7 @@ void Document::drawGrouped(
|
||||
draw(
|
||||
p,
|
||||
geometry.width(),
|
||||
selection,
|
||||
ms,
|
||||
context.translated(-geometry.topLeft()),
|
||||
LayoutMode::Grouped);
|
||||
p.translate(-geometry.topLeft());
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
not_null<DocumentData*> document);
|
||||
~Document();
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
void updatePressed(QPoint point) override;
|
||||
|
||||
@ -65,9 +65,7 @@ public:
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
@ -109,8 +107,7 @@ private:
|
||||
void draw(
|
||||
Painter &p,
|
||||
int width,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
LayoutMode mode) const;
|
||||
[[nodiscard]] TextState textState(
|
||||
QPoint point,
|
||||
@ -131,7 +128,10 @@ private:
|
||||
bool updateStatusText() const; // returns showPause
|
||||
|
||||
[[nodiscard]] bool downloadInCorner() const;
|
||||
void drawCornerDownload(Painter &p, bool selected, LayoutMode mode) const;
|
||||
void drawCornerDownload(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
LayoutMode mode) const;
|
||||
[[nodiscard]] TextState cornerDownloadTextState(
|
||||
QPoint point,
|
||||
StateRequest request,
|
||||
@ -139,6 +139,8 @@ private:
|
||||
|
||||
not_null<DocumentData*> _data;
|
||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||
mutable QImage _iconCache;
|
||||
mutable QImage _cornerDownloadCache;
|
||||
|
||||
};
|
||||
|
||||
|
@ -198,12 +198,12 @@ TextSelection Game::fromDescriptionSelection(
|
||||
return ShiftItemSelection(selection, _title);
|
||||
}
|
||||
|
||||
void Game::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Game::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
auto &barfg = selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor);
|
||||
auto &semibold = selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg);
|
||||
@ -227,7 +227,7 @@ void Game::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
if (_title.hasSkipBlock()) {
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, selection);
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, context.selection);
|
||||
tshift += _titleLines * lineHeight;
|
||||
}
|
||||
if (_descriptionLines) {
|
||||
@ -236,7 +236,7 @@ void Game::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
if (_description.hasSkipBlock()) {
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
_description.drawLeftElided(p, padding.left(), tshift, paintw, width(), _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
||||
_description.drawLeftElided(p, padding.left(), tshift, paintw, width(), _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(context.selection));
|
||||
tshift += _descriptionLines * lineHeight;
|
||||
}
|
||||
if (_attach) {
|
||||
@ -247,10 +247,11 @@ void Game::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
auto attachTop = tshift - bubble.top();
|
||||
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
|
||||
|
||||
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
auto attachContext = context.translated(-attachLeft, -attachTop);
|
||||
attachContext.selection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
|
||||
p.translate(attachLeft, attachTop);
|
||||
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
|
||||
_attach->draw(p, attachContext);
|
||||
auto pixwidth = _attach->width();
|
||||
auto pixheight = _attach->height();
|
||||
|
||||
|
@ -22,7 +22,7 @@ public:
|
||||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
|
@ -276,14 +276,14 @@ bool Gif::autoplayEnabled() const {
|
||||
_data);
|
||||
}
|
||||
|
||||
void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Gif::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
ensureDataMediaCreated();
|
||||
const auto item = _parent->data();
|
||||
const auto loaded = dataLoaded();
|
||||
const auto displayLoading = item->isSending() || _data->displayLoading();
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
const auto autoPaused = _parent->delegate()->elementIsGifPaused();
|
||||
const auto cornerDownload = downloadInCorner();
|
||||
const auto canBePlayed = _dataMedia->canBePlayed();
|
||||
@ -613,7 +613,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
|
||||
}
|
||||
if (!isRound && !_caption.isEmpty()) {
|
||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||
_caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
||||
_caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, context.selection);
|
||||
} else if (!inWebPage) {
|
||||
auto fullRight = paintx + usex + usew;
|
||||
auto fullBottom = painty + painth;
|
||||
@ -896,9 +896,7 @@ QSize Gif::sizeForGrouping(int width) const {
|
||||
|
||||
void Gif::drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
@ -909,7 +907,7 @@ void Gif::drawGrouped(
|
||||
const auto item = _parent->data();
|
||||
const auto loaded = dataLoaded();
|
||||
const auto displayLoading = (item->id < 0) || _data->displayLoading();
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
const auto autoPaused = _parent->delegate()->elementIsGifPaused();
|
||||
const auto fullFeatured = fullFeaturedGrouped(sides);
|
||||
const auto cornerDownload = fullFeatured && downloadInCorner();
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
not_null<DocumentData*> document);
|
||||
~Gif();
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
@ -73,9 +73,7 @@ public:
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
|
@ -199,12 +199,12 @@ void Invoice::refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
}
|
||||
}
|
||||
|
||||
void Invoice::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Invoice::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
auto &semibold = selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg);
|
||||
|
||||
@ -226,14 +226,14 @@ void Invoice::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
if (_title.hasSkipBlock()) {
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleHeight / lineHeight, style::al_left, 0, -1, endskip, false, selection);
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleHeight / lineHeight, style::al_left, 0, -1, endskip, false, context.selection);
|
||||
tshift += _titleHeight;
|
||||
|
||||
p.setTextPalette(selected ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected) : (outbg ? st::outTextPalette : st::inTextPalette));
|
||||
}
|
||||
if (_descriptionHeight) {
|
||||
p.setPen(outbg ? st::webPageDescriptionOutFg : st::webPageDescriptionInFg);
|
||||
_description.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, toDescriptionSelection(selection));
|
||||
_description.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, toDescriptionSelection(context.selection));
|
||||
tshift += _descriptionHeight;
|
||||
}
|
||||
if (_attach) {
|
||||
@ -244,10 +244,11 @@ void Invoice::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
auto attachTop = tshift - bubble.top();
|
||||
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
|
||||
|
||||
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
auto attachContext = context.translated(-attachLeft, -attachTop);
|
||||
attachContext.selection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
|
||||
p.translate(attachLeft, attachTop);
|
||||
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
|
||||
_attach->draw(p, attachContext);
|
||||
auto pixwidth = _attach->width();
|
||||
|
||||
auto available = _status.maxWidth();
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
|
@ -148,12 +148,12 @@ TextSelection Location::fromDescriptionSelection(
|
||||
return ShiftItemSelection(selection, _title);
|
||||
}
|
||||
|
||||
void Location::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Location::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
bool bubble = _parent->hasBubble();
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
if (bubble) {
|
||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||
@ -166,12 +166,12 @@ void Location::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
|
||||
|
||||
if (!_title.isEmpty()) {
|
||||
p.setPen(outbg ? st::webPageTitleOutFg : st::webPageTitleInFg);
|
||||
_title.drawLeftElided(p, paintx + st::msgPadding.left(), painty, textw, width(), 2, style::al_left, 0, -1, 0, false, selection);
|
||||
_title.drawLeftElided(p, paintx + st::msgPadding.left(), painty, textw, width(), 2, style::al_left, 0, -1, 0, false, context.selection);
|
||||
painty += qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height);
|
||||
}
|
||||
if (!_description.isEmpty()) {
|
||||
p.setPen(outbg ? st::webPageDescriptionOutFg : st::webPageDescriptionInFg);
|
||||
_description.drawLeftElided(p, paintx + st::msgPadding.left(), painty, textw, width(), 3, style::al_left, 0, -1, 0, false, toDescriptionSelection(selection));
|
||||
_description.drawLeftElided(p, paintx + st::msgPadding.left(), painty, textw, width(), 3, style::al_left, 0, -1, 0, false, toDescriptionSelection(context.selection));
|
||||
painty += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height);
|
||||
}
|
||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
const QString &description = QString());
|
||||
~Location();
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "layout/layout_selection.h"
|
||||
#include "data/data_document.h"
|
||||
#include "ui/item_text_options.h"
|
||||
#include "ui/chat/message_bubble.h"
|
||||
@ -173,6 +174,13 @@ auto Media::getBubbleSelectionIntervals(
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Media::usesBubblePattern(const PaintContext &context) const {
|
||||
return (context.selection != FullSelection)
|
||||
&& _parent->hasOutLayout()
|
||||
&& context.bubblesPattern
|
||||
&& !context.viewport.isEmpty()
|
||||
&& !context.bubblesPattern->pixmap.size().isEmpty();
|
||||
}
|
||||
|
||||
PointState Media::pointState(QPoint point) const {
|
||||
return QRect(0, 0, width(), height()).contains(point)
|
||||
|
@ -40,6 +40,7 @@ enum class CursorState : char;
|
||||
enum class InfoDisplayType : char;
|
||||
struct TextState;
|
||||
struct StateRequest;
|
||||
struct PaintContext;
|
||||
class Element;
|
||||
|
||||
enum class MediaInBubbleState {
|
||||
@ -85,11 +86,7 @@ public:
|
||||
}
|
||||
virtual void drawHighlight(Painter &p, int top) const {
|
||||
}
|
||||
virtual void draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
TextSelection selection,
|
||||
crl::time ms) const = 0;
|
||||
virtual void draw(Painter &p, const PaintContext &context) const = 0;
|
||||
[[nodiscard]] virtual PointState pointState(QPoint point) const;
|
||||
[[nodiscard]] virtual TextState textState(
|
||||
QPoint point,
|
||||
@ -170,9 +167,7 @@ public:
|
||||
}
|
||||
virtual void drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
@ -299,6 +294,8 @@ protected:
|
||||
virtual void playAnimation(bool autoplay) {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool usesBubblePattern(const PaintContext &context) const;
|
||||
|
||||
const not_null<Element*> _parent;
|
||||
MediaInBubbleState _inBubbleState = MediaInBubbleState::None;
|
||||
|
||||
|
@ -281,21 +281,19 @@ void GroupedMedia::drawHighlight(Painter &p, int top) const {
|
||||
}
|
||||
}
|
||||
|
||||
void GroupedMedia::draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms) const {
|
||||
void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
|
||||
auto wasCache = false;
|
||||
auto nowCache = false;
|
||||
const auto groupPadding = groupedPadding();
|
||||
auto selection = context.selection;
|
||||
const auto fullSelection = (selection == FullSelection);
|
||||
const auto textSelection = (_mode == Mode::Column)
|
||||
&& !fullSelection
|
||||
&& !IsSubGroupSelection(selection);
|
||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||
const auto &part = _parts[i];
|
||||
const auto partSelection = fullSelection
|
||||
auto partContext = context;
|
||||
partContext.selection = fullSelection
|
||||
? FullSelection
|
||||
: textSelection
|
||||
? selection
|
||||
@ -313,9 +311,7 @@ void GroupedMedia::draw(
|
||||
}
|
||||
part.content->drawGrouped(
|
||||
p,
|
||||
clip,
|
||||
partSelection,
|
||||
ms,
|
||||
partContext,
|
||||
part.geometry.translated(0, groupPadding.top()),
|
||||
part.sides,
|
||||
cornersFromSides(part.sides),
|
||||
|
@ -32,11 +32,7 @@ public:
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
void drawHighlight(Painter &p, int top) const override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
PointState pointState(QPoint point) const override;
|
||||
TextState textState(
|
||||
QPoint point,
|
||||
|
@ -105,15 +105,11 @@ QSize UnwrappedMedia::countCurrentSize(int newWidth) {
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void UnwrappedMedia::draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
TextSelection selection,
|
||||
crl::time ms) const {
|
||||
void UnwrappedMedia::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||
return;
|
||||
}
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
const auto rightAligned = _parent->hasOutLayout()
|
||||
&& !_parent->delegate()->elementIsChatWide();
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
not_null<Element*> parent,
|
||||
std::unique_ptr<Content> content);
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
PointState pointState(QPoint point) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
|
@ -223,12 +223,12 @@ QSize Photo::countCurrentSize(int newWidth) {
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Photo::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
ensureDataMediaCreated();
|
||||
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
|
||||
auto selected = (selection == FullSelection);
|
||||
auto selected = (context.selection == FullSelection);
|
||||
auto loaded = _dataMedia->loaded();
|
||||
auto displayLoading = _data->displayLoading();
|
||||
|
||||
@ -330,7 +330,7 @@ void Photo::draw(Painter &p, const QRect &r, TextSelection selection, crl::time
|
||||
if (!_caption.isEmpty()) {
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||
_caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
||||
_caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, context.selection);
|
||||
} else if (!inWebPage) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
@ -489,9 +489,7 @@ QSize Photo::sizeForGrouping(int width) const {
|
||||
|
||||
void Photo::drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
@ -503,7 +501,7 @@ void Photo::drawGrouped(
|
||||
|
||||
validateGroupedCache(geometry, corners, cacheKey, cache);
|
||||
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
const auto loaded = _dataMedia->loaded();
|
||||
const auto displayLoading = _data->displayLoading();
|
||||
const auto bubble = _parent->hasBubble();
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
int width);
|
||||
~Photo();
|
||||
|
||||
void draw(Painter &p, const QRect &clip, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
@ -62,9 +62,7 @@ public:
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms,
|
||||
const PaintContext &context,
|
||||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "history/view/history_view_cursor_state.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "ui/chat/message_bubble.h"
|
||||
#include "ui/text/text_options.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/text/format_values.h"
|
||||
@ -715,15 +716,15 @@ void Poll::updateAnswerVotes() {
|
||||
}
|
||||
}
|
||||
|
||||
void Poll::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void Poll::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
checkSendingAnimation();
|
||||
_poll->checkResultsReload(_parent->data(), ms);
|
||||
_poll->checkResultsReload(_parent->data(), context.now);
|
||||
|
||||
const auto outbg = _parent->hasOutLayout();
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
const auto ®ular = selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg);
|
||||
|
||||
const auto padding = st::msgPadding;
|
||||
@ -734,14 +735,14 @@ void Poll::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
paintw -= padding.left() + padding.right();
|
||||
|
||||
p.setPen(outbg ? st::webPageTitleOutFg : st::webPageTitleInFg);
|
||||
_question.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, selection);
|
||||
_question.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, context.selection);
|
||||
tshift += _question.countHeight(paintw) + st::historyPollSubtitleSkip;
|
||||
|
||||
p.setPen(regular);
|
||||
_subtitle.drawLeftElided(p, padding.left(), tshift, paintw, width());
|
||||
paintRecentVoters(p, padding.left() + _subtitle.maxWidth(), tshift, selection);
|
||||
paintCloseByTimer(p, padding.left() + paintw, tshift, selection);
|
||||
paintShowSolution(p, padding.left() + paintw, tshift, selection);
|
||||
paintRecentVoters(p, padding.left() + _subtitle.maxWidth(), tshift, context);
|
||||
paintCloseByTimer(p, padding.left() + paintw, tshift, context.selection);
|
||||
paintShowSolution(p, padding.left() + paintw, tshift, context.selection);
|
||||
tshift += st::msgDateFont->height + st::historyPollAnswersSkip;
|
||||
|
||||
const auto progress = _answersAnimation
|
||||
@ -773,14 +774,14 @@ void Poll::draw(Painter &p, const QRect &r, TextSelection selection, crl::time m
|
||||
tshift,
|
||||
paintw,
|
||||
width(),
|
||||
selection);
|
||||
context.selection);
|
||||
tshift += height;
|
||||
}
|
||||
if (!inlineFooter()) {
|
||||
paintBottom(p, padding.left(), tshift, paintw, selection);
|
||||
paintBottom(p, padding.left(), tshift, paintw, context.selection);
|
||||
} else if (!_totalVotesLabel.isEmpty()) {
|
||||
tshift += st::msgPadding.bottom();
|
||||
paintInlineFooter(p, padding.left(), tshift, paintw, selection);
|
||||
paintInlineFooter(p, padding.left(), tshift, paintw, context.selection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -864,7 +865,7 @@ void Poll::paintRecentVoters(
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
TextSelection selection) const {
|
||||
const PaintContext &context) const {
|
||||
const auto count = int(_recentVoters.size());
|
||||
if (!count) {
|
||||
return;
|
||||
@ -875,7 +876,7 @@ void Poll::paintRecentVoters(
|
||||
auto y = top;
|
||||
const auto size = st::historyPollRecentVoterSize;
|
||||
const auto outbg = _parent->hasOutLayout();
|
||||
const auto selected = (selection == FullSelection);
|
||||
const auto selected = (context.selection == FullSelection);
|
||||
auto pen = (selected
|
||||
? (outbg ? st::msgOutBgSelected : st::msgInBgSelected)
|
||||
: (outbg ? st::msgOutBg : st::msgInBg))->p;
|
||||
@ -888,10 +889,26 @@ void Poll::paintRecentVoters(
|
||||
if (!was && recent.userpic) {
|
||||
created = true;
|
||||
}
|
||||
p.setPen(pen);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawEllipse(x, y, size, size);
|
||||
const auto paintContent = [&](Painter &p) {
|
||||
p.setPen(pen);
|
||||
p.setBrush(Qt::NoBrush);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawEllipse(x, y, size, size);
|
||||
};
|
||||
if (usesBubblePattern(context)) {
|
||||
const auto add = st::lineWidth * 2;
|
||||
const auto target = QRect(x, y, size, size).marginsAdded(
|
||||
{ add, add, add, add });
|
||||
Ui::PaintPatternBubblePart(
|
||||
p,
|
||||
context.viewport,
|
||||
context.bubblesPattern->pixmap,
|
||||
target,
|
||||
paintContent,
|
||||
_userpicCircleCache);
|
||||
} else {
|
||||
paintContent(p);
|
||||
}
|
||||
x -= st::historyPollRecentVoterSkip;
|
||||
}
|
||||
if (created) {
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
not_null<PollData*> poll);
|
||||
~Poll();
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||
@ -107,7 +107,7 @@ private:
|
||||
Painter &p,
|
||||
int left,
|
||||
int top,
|
||||
TextSelection selection) const;
|
||||
const PaintContext &context) const;
|
||||
void paintCloseByTimer(
|
||||
Painter &p,
|
||||
int right,
|
||||
@ -213,6 +213,7 @@ private:
|
||||
mutable std::unique_ptr<Ui::FireworksAnimation> _fireworksAnimation;
|
||||
Ui::Animations::Simple _wrongAnswerAnimation;
|
||||
mutable QPoint _lastLinkPoint;
|
||||
mutable QImage _userpicCircleCache;
|
||||
|
||||
mutable std::unique_ptr<CloseInformation> _close;
|
||||
|
||||
|
@ -150,7 +150,7 @@ QSize ThemeDocument::countCurrentSize(int newWidth) {
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
||||
void ThemeDocument::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void ThemeDocument::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
|
||||
ensureDataMediaCreated();
|
||||
@ -158,7 +158,7 @@ void ThemeDocument::draw(Painter &p, const QRect &r, TextSelection selection, cr
|
||||
if (_data) {
|
||||
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
|
||||
}
|
||||
auto selected = (selection == FullSelection);
|
||||
auto selected = (context.selection == FullSelection);
|
||||
auto loaded = dataLoaded();
|
||||
auto displayLoading = _data && _data->displayLoading();
|
||||
|
||||
|
@ -27,11 +27,7 @@ public:
|
||||
const std::optional<Data::WallPaper> ¶ms);
|
||||
~ThemeDocument();
|
||||
|
||||
void draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
TextSelection selection,
|
||||
crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
DocumentData *getDocument() const override {
|
||||
|
@ -448,12 +448,12 @@ void WebPage::unloadHeavyPart() {
|
||||
_photoMedia = nullptr;
|
||||
}
|
||||
|
||||
void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const {
|
||||
void WebPage::draw(Painter &p, const PaintContext &context) const {
|
||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||
auto paintw = width();
|
||||
|
||||
auto outbg = _parent->hasOutLayout();
|
||||
bool selected = (selection == FullSelection);
|
||||
bool selected = (context.selection == FullSelection);
|
||||
|
||||
auto &barfg = selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor);
|
||||
auto &semibold = selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg);
|
||||
@ -512,7 +512,7 @@ void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
if (_siteName.hasSkipBlock()) {
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
_siteName.drawLeftElided(p, padding.left(), tshift, paintw, width(), _siteNameLines, style::al_left, 0, -1, endskip, false, selection);
|
||||
_siteName.drawLeftElided(p, padding.left(), tshift, paintw, width(), _siteNameLines, style::al_left, 0, -1, endskip, false, context.selection);
|
||||
tshift += lineHeight;
|
||||
}
|
||||
if (_titleLines) {
|
||||
@ -521,7 +521,7 @@ void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
if (_title.hasSkipBlock()) {
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, toTitleSelection(selection));
|
||||
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, toTitleSelection(context.selection));
|
||||
tshift += _titleLines * lineHeight;
|
||||
}
|
||||
if (_descriptionLines) {
|
||||
@ -531,10 +531,10 @@ void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
endskip = _parent->skipBlockWidth();
|
||||
}
|
||||
if (_descriptionLines > 0) {
|
||||
_description.drawLeftElided(p, padding.left(), tshift, paintw, width(), _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
||||
_description.drawLeftElided(p, padding.left(), tshift, paintw, width(), _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(context.selection));
|
||||
tshift += _descriptionLines * lineHeight;
|
||||
} else {
|
||||
_description.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, toDescriptionSelection(selection));
|
||||
_description.drawLeft(p, padding.left(), tshift, paintw, width(), style::al_left, 0, -1, toDescriptionSelection(context.selection));
|
||||
tshift += _description.countHeight(paintw);
|
||||
}
|
||||
}
|
||||
@ -548,8 +548,9 @@ void WebPage::draw(Painter &p, const QRect &r, TextSelection selection, crl::tim
|
||||
|
||||
p.translate(attachLeft, attachTop);
|
||||
|
||||
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
|
||||
auto attachContext = context.translated(-attachLeft, -attachTop);
|
||||
attachContext.selection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||
_attach->draw(p, attachContext);
|
||||
auto pixwidth = _attach->width();
|
||||
auto pixheight = _attach->height();
|
||||
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
bool hideMessageText() const override {
|
||||
|
@ -93,10 +93,11 @@ void PaintPatternBubble(Painter &p, const SimpleBubble &args) {
|
||||
const auto fill = rect.intersected(args.patternViewport);
|
||||
if (!fill.isEmpty()) {
|
||||
p.setClipRect(fill);
|
||||
// #TODO bubbles optimizes
|
||||
const auto to = args.patternViewport;
|
||||
const auto from = QRect(QPoint(), pattern->pixmap.size());
|
||||
p.drawPixmap(to, pattern->pixmap, from);
|
||||
PaintPatternBubblePart(
|
||||
p,
|
||||
args.patternViewport,
|
||||
pattern->pixmap,
|
||||
fill);
|
||||
p.setClipping(false);
|
||||
}
|
||||
};
|
||||
@ -112,26 +113,13 @@ void PaintPatternBubble(Painter &p, const SimpleBubble &args) {
|
||||
int y,
|
||||
const QImage &mask,
|
||||
QImage &cache) {
|
||||
Expects(mask.bytesPerLine() == mask.width() * 4);
|
||||
Expects(mask.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
if (cache.size() != mask.size()) {
|
||||
cache = QImage(
|
||||
mask.size(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
cache.setDevicePixelRatio(mask.devicePixelRatio());
|
||||
Assert(cache.bytesPerLine() == cache.width() * 4);
|
||||
memcpy(cache.bits(), mask.constBits(), mask.sizeInBytes());
|
||||
|
||||
auto q = QPainter(&cache);
|
||||
q.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
const auto to = args.patternViewport.translated(-x, -y);
|
||||
const auto from = QRect(QPoint(), pattern->pixmap.size());
|
||||
q.drawPixmap(to, pattern->pixmap, from);
|
||||
q.end();
|
||||
|
||||
p.drawImage(x, y, cache);
|
||||
PaintPatternBubblePart(
|
||||
p,
|
||||
args.patternViewport,
|
||||
pattern->pixmap,
|
||||
QRect(QPoint(x, y), mask.size() / int(mask.devicePixelRatio())),
|
||||
mask,
|
||||
cache);
|
||||
};
|
||||
const auto fillCorner = [&](int x, int y, int index) {
|
||||
fillPattern(
|
||||
@ -365,4 +353,72 @@ void PaintBubble(Painter &p, const ComplexBubble &args) {
|
||||
}
|
||||
}
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target) {
|
||||
// #TODO bubbles optimizes
|
||||
const auto to = viewport;
|
||||
const auto from = QRect(QPoint(), pixmap.size());
|
||||
p.drawPixmap(to, pixmap, from);
|
||||
}
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target,
|
||||
const QImage &mask,
|
||||
QImage &cache) {
|
||||
Expects(mask.bytesPerLine() == mask.width() * 4);
|
||||
Expects(mask.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
if (cache.size() != mask.size()) {
|
||||
cache = QImage(
|
||||
mask.size(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
cache.setDevicePixelRatio(mask.devicePixelRatio());
|
||||
Assert(cache.bytesPerLine() == cache.width() * 4);
|
||||
memcpy(cache.bits(), mask.constBits(), mask.sizeInBytes());
|
||||
|
||||
auto q = QPainter(&cache);
|
||||
q.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
PaintPatternBubblePart(
|
||||
q,
|
||||
viewport.translated(-target.topLeft()),
|
||||
pixmap,
|
||||
QRect(QPoint(), cache.size() / int(cache.devicePixelRatio())));
|
||||
q.end();
|
||||
|
||||
p.drawImage(target, cache);
|
||||
}
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target,
|
||||
Fn<void(Painter&)> paintContent,
|
||||
QImage &cache) {
|
||||
Expects(paintContent != nullptr);
|
||||
|
||||
if (cache.size() != target.size() * style::DevicePixelRatio()) {
|
||||
cache = QImage(
|
||||
target.size() * style::DevicePixelRatio(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
}
|
||||
cache.fill(Qt::transparent);
|
||||
auto q = Painter(&cache);
|
||||
q.translate(-target.topLeft());
|
||||
paintContent(q);
|
||||
q.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
PaintPatternBubblePart(q, viewport, pixmap, target);
|
||||
q.end();
|
||||
|
||||
p.drawImage(target, cache);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
@ -49,4 +49,26 @@ struct ComplexBubble {
|
||||
void PaintBubble(Painter &p, const SimpleBubble &args);
|
||||
void PaintBubble(Painter &p, const ComplexBubble &args);
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target);
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target,
|
||||
const QImage &mask,
|
||||
QImage &cache);
|
||||
|
||||
void PaintPatternBubblePart(
|
||||
QPainter &p,
|
||||
const QRect &viewport,
|
||||
const QPixmap &pixmap,
|
||||
const QRect &target,
|
||||
Fn<void(Painter&)> paintContent,
|
||||
QImage &cache);
|
||||
|
||||
} // namespace Ui
|
||||
|
@ -1484,8 +1484,8 @@ HistoryView::PaintContext SessionController::bubblesContext(
|
||||
//}
|
||||
return {
|
||||
.bubblesPattern = _bubblesBackgroundPattern.get(),
|
||||
.viewport = viewport.translated(0, -args.initialShift),
|
||||
.clip = args.clip.translated(0, -args.initialShift),
|
||||
.viewport = viewport,
|
||||
.clip = args.clip,
|
||||
.now = crl::now(),
|
||||
};
|
||||
}
|
||||
|
@ -454,7 +454,6 @@ public:
|
||||
int visibleAreaTopGlobal = 0;
|
||||
int visibleAreaWidth = 0;
|
||||
QRect clip;
|
||||
int initialShift = 0;
|
||||
};
|
||||
[[nodiscard]] HistoryView::PaintContext bubblesContext(
|
||||
BubblesContextArgs &&args);
|
||||
|
Loading…
Reference in New Issue
Block a user