mirror of https://github.com/procxx/kepka.git
Extract sticker-specific HistoryView code.
This commit is contained in:
parent
850940116d
commit
1d52ba7a42
|
@ -769,7 +769,11 @@ std::unique_ptr<HistoryView::Media> MediaFile::createView(
|
||||||
not_null<HistoryView::Element*> message,
|
not_null<HistoryView::Element*> message,
|
||||||
not_null<HistoryItem*> realParent) {
|
not_null<HistoryItem*> realParent) {
|
||||||
if (_document->sticker()) {
|
if (_document->sticker()) {
|
||||||
return std::make_unique<HistoryView::Sticker>(message, _document);
|
return std::make_unique<HistoryView::UnwrappedMedia>(
|
||||||
|
message,
|
||||||
|
std::make_unique<HistoryView::StickerContent>(
|
||||||
|
message,
|
||||||
|
_document));
|
||||||
} else if (_document->isAnimation()) {
|
} else if (_document->isAnimation()) {
|
||||||
return std::make_unique<HistoryView::Gif>(message, _document);
|
return std::make_unique<HistoryView::Gif>(message, _document);
|
||||||
} else if (_document->isVideoFile()) {
|
} else if (_document->isVideoFile()) {
|
||||||
|
|
|
@ -1087,7 +1087,8 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but
|
||||||
if (uponSelected) {
|
if (uponSelected) {
|
||||||
_mouseAction = MouseAction::PrepareDrag; // start text drag
|
_mouseAction = MouseAction::PrepareDrag; // start text drag
|
||||||
} else if (!_pressWasInactive) {
|
} else if (!_pressWasInactive) {
|
||||||
if (dynamic_cast<HistoryView::Sticker*>(App::pressedItem()->media())
|
const auto media = App::pressedItem()->media();
|
||||||
|
if ((media && media->dragItem())
|
||||||
|| _mouseCursorState == CursorState::Date) {
|
|| _mouseCursorState == CursorState::Date) {
|
||||||
_mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
|
_mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -345,7 +345,9 @@ void Element::refreshMedia() {
|
||||||
if (_data->media()) {
|
if (_data->media()) {
|
||||||
_media = _data->media()->createView(this);
|
_media = _data->media()->createView(this);
|
||||||
} else if (const auto document = emojiStickers->stickerForEmoji(_data)) {
|
} else if (const auto document = emojiStickers->stickerForEmoji(_data)) {
|
||||||
_media = std::make_unique<Sticker>(this, document);
|
_media = std::make_unique<UnwrappedMedia>(
|
||||||
|
this,
|
||||||
|
std::make_unique<StickerContent>(this, document));
|
||||||
} else {
|
} else {
|
||||||
_media = nullptr;
|
_media = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -888,8 +888,10 @@ bool ListWidget::requiredToStartDragging(
|
||||||
not_null<Element*> view) const {
|
not_null<Element*> view) const {
|
||||||
if (_mouseCursorState == CursorState::Date) {
|
if (_mouseCursorState == CursorState::Date) {
|
||||||
return true;
|
return true;
|
||||||
} else if (dynamic_cast<Sticker*>(view->media()) != nullptr) {
|
} else if (const auto media = view->media()) {
|
||||||
return true;
|
if (media->dragItem()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,9 @@ std::unique_ptr<Media> CreateAttach(
|
||||||
return std::make_unique<GroupedMedia>(parent, collage);
|
return std::make_unique<GroupedMedia>(parent, collage);
|
||||||
} else if (document) {
|
} else if (document) {
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
return std::make_unique<Sticker>(parent, document);
|
return std::make_unique<UnwrappedMedia>(
|
||||||
|
parent,
|
||||||
|
std::make_unique<StickerContent>(parent, document));
|
||||||
} else if (document->isAnimation()) {
|
} else if (document->isAnimation()) {
|
||||||
return std::make_unique<Gif>(parent, document);
|
return std::make_unique<Gif>(parent, document);
|
||||||
} else if (document->isVideoFile()) {
|
} else if (document->isVideoFile()) {
|
||||||
|
|
|
@ -39,4 +39,14 @@ std::unique_ptr<Media> CreateAttach(
|
||||||
const QString &webpageUrl = QString());
|
const QString &webpageUrl = QString());
|
||||||
int unitedLineHeight();
|
int unitedLineHeight();
|
||||||
|
|
||||||
|
[[nodiscard]] inline QSize NonEmptySize(QSize size) {
|
||||||
|
return QSize(std::max(size.width(), 1), std::max(size.height(), 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline QSize DownscaledSize(QSize size, QSize box) {
|
||||||
|
return (size.width() > box.width() || size.height() > box.height())
|
||||||
|
? size.scaled(box, Qt::IgnoreAspectRatio)
|
||||||
|
: size;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "history/view/media/history_view_media_unwrapped.h"
|
||||||
|
|
||||||
|
#include "history/view/media/history_view_media_common.h"
|
||||||
|
#include "history/view/history_view_element.h"
|
||||||
|
#include "history/view/history_view_cursor_state.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "history/history_item_components.h"
|
||||||
|
#include "layout.h"
|
||||||
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
UnwrappedMedia::Content::~Content() = default;
|
||||||
|
|
||||||
|
UnwrappedMedia::UnwrappedMedia(
|
||||||
|
not_null<Element*> parent,
|
||||||
|
std::unique_ptr<Content> content)
|
||||||
|
: Media(parent)
|
||||||
|
, _content(std::move(content)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize UnwrappedMedia::countOptimalSize() {
|
||||||
|
_content->refreshLink();
|
||||||
|
_contentSize = NonEmptySize(DownscaledSize(
|
||||||
|
_content->size(),
|
||||||
|
{ st::maxStickerSize, st::maxStickerSize }));
|
||||||
|
auto maxWidth = std::max(_contentSize.width(), st::minPhotoSize);
|
||||||
|
auto minHeight = std::max(_contentSize.height(), st::minPhotoSize);
|
||||||
|
accumulate_max(
|
||||||
|
maxWidth,
|
||||||
|
_parent->infoWidth() + 2 * st::msgDateImgPadding.x());
|
||||||
|
if (_parent->media() == this) {
|
||||||
|
maxWidth += additionalWidth();
|
||||||
|
}
|
||||||
|
return { maxWidth, minHeight };
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize UnwrappedMedia::countCurrentSize(int newWidth) {
|
||||||
|
const auto item = _parent->data();
|
||||||
|
accumulate_min(newWidth, maxWidth());
|
||||||
|
if (_parent->media() == this) {
|
||||||
|
auto via = item->Get<HistoryMessageVia>();
|
||||||
|
auto reply = item->Get<HistoryMessageReply>();
|
||||||
|
if (via || reply) {
|
||||||
|
int usew = maxWidth() - additionalWidth(via, reply);
|
||||||
|
int availw = newWidth - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.left();
|
||||||
|
if (via) {
|
||||||
|
via->resize(availw);
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
reply->resize(availw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { newWidth, minHeight() };
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnwrappedMedia::draw(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &r,
|
||||||
|
TextSelection selection,
|
||||||
|
crl::time ms) const {
|
||||||
|
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool selected = (selection == FullSelection);
|
||||||
|
|
||||||
|
const auto outbg = _parent->hasOutLayout();
|
||||||
|
const auto inWebPage = (_parent->media() != this);
|
||||||
|
|
||||||
|
const auto item = _parent->data();
|
||||||
|
int usew = maxWidth(), usex = 0;
|
||||||
|
auto via = inWebPage ? nullptr : item->Get<HistoryMessageVia>();
|
||||||
|
auto reply = inWebPage ? nullptr : item->Get<HistoryMessageReply>();
|
||||||
|
if (via || reply) {
|
||||||
|
usew -= additionalWidth(via, reply);
|
||||||
|
if (outbg) {
|
||||||
|
usex = width() - usew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rtl()) usex = width() - usex - usew;
|
||||||
|
|
||||||
|
const auto inner = QRect(usex, 0, usew, height());
|
||||||
|
_content->draw(p, inner, selected);
|
||||||
|
|
||||||
|
if (!inWebPage) {
|
||||||
|
drawSurrounding(p, inner, selected, via, reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnwrappedMedia::drawSurrounding(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &inner,
|
||||||
|
bool selected,
|
||||||
|
const HistoryMessageVia *via,
|
||||||
|
const HistoryMessageReply *reply) const {
|
||||||
|
auto fullRight = inner.x() + inner.width();
|
||||||
|
auto fullBottom = inner.y() + inner.height();
|
||||||
|
if (needInfoDisplay()) {
|
||||||
|
_parent->drawInfo(
|
||||||
|
p,
|
||||||
|
fullRight,
|
||||||
|
fullBottom,
|
||||||
|
inner.x() * 2 + inner.width(),
|
||||||
|
selected,
|
||||||
|
InfoDisplayType::Background);
|
||||||
|
}
|
||||||
|
if (via || reply) {
|
||||||
|
int rectw = width() - inner.width() - st::msgReplyPadding.left();
|
||||||
|
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
||||||
|
if (via) {
|
||||||
|
recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
recth += st::msgReplyBarSize.height();
|
||||||
|
}
|
||||||
|
const auto outbg = _parent->hasOutLayout();
|
||||||
|
int rectx = outbg ? 0 : (inner.width() + st::msgReplyPadding.left());
|
||||||
|
int recty = st::msgDateImgDelta;
|
||||||
|
if (rtl()) rectx = width() - rectx - rectw;
|
||||||
|
|
||||||
|
App::roundRect(p, rectx, recty, rectw, recth, selected ? st::msgServiceBgSelected : st::msgServiceBg, selected ? StickerSelectedCorners : StickerCorners);
|
||||||
|
p.setPen(st::msgServiceFg);
|
||||||
|
rectx += st::msgReplyPadding.left();
|
||||||
|
rectw -= st::msgReplyPadding.left() + st::msgReplyPadding.right();
|
||||||
|
if (via) {
|
||||||
|
p.setFont(st::msgDateFont);
|
||||||
|
p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * rectx + rectw, via->text);
|
||||||
|
int skip = st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
||||||
|
recty += skip;
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
HistoryMessageReply::PaintFlags flags = 0;
|
||||||
|
if (selected) {
|
||||||
|
flags |= HistoryMessageReply::PaintFlag::Selected;
|
||||||
|
}
|
||||||
|
reply->paint(p, _parent, rectx, recty, rectw, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_parent->displayRightAction()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
_parent->drawRightAction(p, fastShareLeft, fastShareTop, 2 * inner.x() + inner.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
|
||||||
|
auto result = TextState(_parent);
|
||||||
|
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto outbg = _parent->hasOutLayout();
|
||||||
|
auto inWebPage = (_parent->media() != this);
|
||||||
|
|
||||||
|
const auto item = _parent->data();
|
||||||
|
int usew = maxWidth(), usex = 0;
|
||||||
|
auto via = inWebPage ? nullptr : item->Get<HistoryMessageVia>();
|
||||||
|
auto reply = inWebPage ? nullptr : item->Get<HistoryMessageReply>();
|
||||||
|
if (via || reply) {
|
||||||
|
usew -= additionalWidth(via, reply);
|
||||||
|
if (outbg) {
|
||||||
|
usex = width() - usew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rtl()) usex = width() - usex - usew;
|
||||||
|
|
||||||
|
if (via || reply) {
|
||||||
|
int rectw = width() - usew - st::msgReplyPadding.left();
|
||||||
|
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
||||||
|
if (via) {
|
||||||
|
recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
recth += st::msgReplyBarSize.height();
|
||||||
|
}
|
||||||
|
int rectx = outbg ? 0 : (usew + st::msgReplyPadding.left());
|
||||||
|
int recty = st::msgDateImgDelta;
|
||||||
|
if (rtl()) rectx = width() - rectx - rectw;
|
||||||
|
|
||||||
|
if (via) {
|
||||||
|
int viah = st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? 0 : st::msgReplyPadding.bottom());
|
||||||
|
if (QRect(rectx, recty, rectw, viah).contains(point)) {
|
||||||
|
result.link = via->link;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int skip = st::msgServiceNameFont->height + (reply ? 2 * st::msgReplyPadding.top() : 0);
|
||||||
|
recty += skip;
|
||||||
|
recth -= skip;
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
if (QRect(rectx, recty, rectw, recth).contains(point)) {
|
||||||
|
result.link = reply->replyToLink();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_parent->media() == this) {
|
||||||
|
auto fullRight = usex + usew;
|
||||||
|
auto fullBottom = height();
|
||||||
|
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
|
||||||
|
result.cursor = CursorState::Date;
|
||||||
|
}
|
||||||
|
if (_parent->displayRightAction()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->rightActionLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pixLeft = usex + (usew - _contentSize.width()) / 2;
|
||||||
|
auto pixTop = (minHeight() - _contentSize.height()) / 2;
|
||||||
|
if (QRect({ pixLeft, pixTop }, _contentSize).contains(point)) {
|
||||||
|
result.link = _content->link();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnwrappedMedia::needInfoDisplay() const {
|
||||||
|
return (_parent->data()->id < 0 || _parent->isUnderCursor());
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnwrappedMedia::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const {
|
||||||
|
int result = 0;
|
||||||
|
if (via) {
|
||||||
|
accumulate_max(result, st::msgReplyPadding.left() + st::msgReplyPadding.left() + via->maxWidth + st::msgReplyPadding.left());
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
accumulate_max(result, st::msgReplyPadding.left() + reply->replyToWidth());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnwrappedMedia::additionalWidth() const {
|
||||||
|
const auto item = _parent->data();
|
||||||
|
return additionalWidth(
|
||||||
|
item->Get<HistoryMessageVia>(),
|
||||||
|
item->Get<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "history/view/media/history_view_media.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
struct HistoryMessageVia;
|
||||||
|
struct HistoryMessageReply;
|
||||||
|
struct HistoryMessageForwarded;
|
||||||
|
|
||||||
|
namespace HistoryView {
|
||||||
|
|
||||||
|
class UnwrappedMedia final : public Media {
|
||||||
|
public:
|
||||||
|
class Content {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] virtual QSize size() = 0;
|
||||||
|
virtual void draw(Painter &p, const QRect &r, bool selected) = 0;
|
||||||
|
[[nodiscard]] virtual ClickHandlerPtr link() = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual DocumentData *document() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual void clearStickerLoopPlayed() {
|
||||||
|
}
|
||||||
|
virtual void unloadHeavyPart() {
|
||||||
|
}
|
||||||
|
virtual void refreshLink() {
|
||||||
|
}
|
||||||
|
virtual ~Content() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
UnwrappedMedia(
|
||||||
|
not_null<Element*> parent,
|
||||||
|
std::unique_ptr<Content> content);
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
||||||
|
TextState textState(QPoint point, StateRequest request) const override;
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool dragItem() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *getDocument() const override {
|
||||||
|
return _content->document();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool hidesForwardedInfo() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void clearStickerLoopPlayed() override {
|
||||||
|
_content->clearStickerLoopPlayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unloadHeavyPart() override {
|
||||||
|
_content->unloadHeavyPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawSurrounding(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &inner,
|
||||||
|
bool selected,
|
||||||
|
const HistoryMessageVia *via,
|
||||||
|
const HistoryMessageReply *reply) const;
|
||||||
|
|
||||||
|
QSize countOptimalSize() override;
|
||||||
|
QSize countCurrentSize(int newWidth) override;
|
||||||
|
|
||||||
|
bool needInfoDisplay() const;
|
||||||
|
int additionalWidth(
|
||||||
|
const HistoryMessageVia *via,
|
||||||
|
const HistoryMessageReply *reply) const;
|
||||||
|
int additionalWidth() const;
|
||||||
|
|
||||||
|
std::unique_ptr<Content> _content;
|
||||||
|
QSize _contentSize;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HistoryView
|
|
@ -34,99 +34,155 @@ double GetEmojiStickerZoom(not_null<Main::Session*> session) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Sticker::Sticker(
|
StickerContent::StickerContent(
|
||||||
not_null<Element*> parent,
|
not_null<Element*> parent,
|
||||||
not_null<DocumentData*> document)
|
not_null<DocumentData*> document)
|
||||||
: Media(parent)
|
: _parent(parent)
|
||||||
, _data(document) {
|
, _document(document) {
|
||||||
_data->loadThumbnail(parent->data()->fullId());
|
_document->loadThumbnail(parent->data()->fullId());
|
||||||
}
|
}
|
||||||
|
|
||||||
Sticker::~Sticker() {
|
StickerContent::~StickerContent() {
|
||||||
unloadLottie();
|
unloadLottie();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sticker::isEmojiSticker() const {
|
bool StickerContent::isEmojiSticker() const {
|
||||||
return (_parent->data()->media() == nullptr);
|
return (_parent->data()->media() == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Sticker::countOptimalSize() {
|
QSize StickerContent::size() {
|
||||||
auto sticker = _data->sticker();
|
_size = _document->dimensions;
|
||||||
|
|
||||||
if (!_packLink) {
|
|
||||||
if (isEmojiSticker()) {
|
|
||||||
const auto weak = base::make_weak(this);
|
|
||||||
_packLink = std::make_shared<LambdaClickHandler>([weak] {
|
|
||||||
const auto that = weak.get();
|
|
||||||
if (!that) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
that->_lottieOncePlayed = false;
|
|
||||||
that->_parent->data()->history()->owner().requestViewRepaint(
|
|
||||||
that->_parent);
|
|
||||||
});
|
|
||||||
} else if (sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
|
||||||
_packLink = std::make_shared<LambdaClickHandler>([document = _data] {
|
|
||||||
StickerSetBox::Show(App::wnd()->sessionController(), document);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_pixw = _data->dimensions.width();
|
|
||||||
_pixh = _data->dimensions.height();
|
|
||||||
if (isEmojiSticker()) {
|
if (isEmojiSticker()) {
|
||||||
constexpr auto kIdealStickerSize = 512;
|
constexpr auto kIdealStickerSize = 512;
|
||||||
const auto zoom = GetEmojiStickerZoom(&history()->session());
|
const auto zoom = GetEmojiStickerZoom(&_document->session());
|
||||||
const auto convert = [&](int size) {
|
const auto convert = [&](int size) {
|
||||||
return int(size * st::maxStickerSize * zoom / kIdealStickerSize);
|
return int(size * st::maxStickerSize * zoom / kIdealStickerSize);
|
||||||
};
|
};
|
||||||
_pixw = convert(_pixw);
|
_size = QSize(convert(_size.width()), convert(_size.height()));
|
||||||
_pixh = convert(_pixh);
|
}
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerContent::draw(
|
||||||
|
Painter &p,
|
||||||
|
const QRect &r,
|
||||||
|
bool selected) {
|
||||||
|
const auto sticker = _document->sticker();
|
||||||
|
if (!sticker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_document->checkStickerLarge();
|
||||||
|
const auto loaded = _document->loaded();
|
||||||
|
if (sticker->animated && !_lottie && loaded) {
|
||||||
|
setupLottie();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lottie && _lottie->ready()) {
|
||||||
|
paintLottie(p, r, selected);
|
||||||
} else {
|
} else {
|
||||||
if (_pixw > st::maxStickerSize) {
|
paintPixmap(p, r, selected);
|
||||||
_pixh = (st::maxStickerSize * _pixh) / _pixw;
|
|
||||||
_pixw = st::maxStickerSize;
|
|
||||||
}
|
|
||||||
if (_pixh > st::maxStickerSize) {
|
|
||||||
_pixw = (st::maxStickerSize * _pixw) / _pixh;
|
|
||||||
_pixh = st::maxStickerSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (_pixw < 1) _pixw = 1;
|
|
||||||
if (_pixh < 1) _pixh = 1;
|
|
||||||
auto maxWidth = qMax(_pixw, st::minPhotoSize);
|
|
||||||
auto minHeight = qMax(_pixh, st::minPhotoSize);
|
|
||||||
accumulate_max(
|
|
||||||
maxWidth,
|
|
||||||
_parent->infoWidth() + 2 * st::msgDateImgPadding.x());
|
|
||||||
if (_parent->media() == this) {
|
|
||||||
maxWidth += additionalWidth();
|
|
||||||
}
|
|
||||||
return { maxWidth, minHeight };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Sticker::countCurrentSize(int newWidth) {
|
void StickerContent::paintLottie(Painter &p, const QRect &r, bool selected) {
|
||||||
const auto item = _parent->data();
|
auto request = Lottie::FrameRequest();
|
||||||
accumulate_min(newWidth, maxWidth());
|
request.box = _size * cIntRetinaFactor();
|
||||||
if (_parent->media() == this) {
|
if (selected) {
|
||||||
auto via = item->Get<HistoryMessageVia>();
|
request.colored = st::msgStickerOverlay->c;
|
||||||
auto reply = item->Get<HistoryMessageReply>();
|
}
|
||||||
if (via || reply) {
|
const auto frame = _lottie->frameInfo(request);
|
||||||
int usew = maxWidth() - additionalWidth(via, reply);
|
const auto size = frame.image.size() / cIntRetinaFactor();
|
||||||
int availw = newWidth - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.left();
|
p.drawImage(
|
||||||
if (via) {
|
QRect(
|
||||||
via->resize(availw);
|
QPoint(
|
||||||
}
|
r.x() + (r.width() - size.width()) / 2,
|
||||||
if (reply) {
|
r.y() + (r.height() - size.height()) / 2),
|
||||||
reply->resize(availw);
|
size),
|
||||||
}
|
frame.image);
|
||||||
}
|
|
||||||
|
const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
|
||||||
|
const auto playOnce = isEmojiSticker()
|
||||||
|
|| !_document->session().settings().loopAnimatedStickers();
|
||||||
|
if (!paused
|
||||||
|
&& (!playOnce || frame.index != 0 || !_lottieOncePlayed)
|
||||||
|
&& _lottie->markFrameShown()
|
||||||
|
&& playOnce
|
||||||
|
&& !_lottieOncePlayed) {
|
||||||
|
_lottieOncePlayed = true;
|
||||||
|
_parent->delegate()->elementStartStickerLoop(_parent);
|
||||||
}
|
}
|
||||||
return { newWidth, minHeight() };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sticker::setupLottie() {
|
void StickerContent::paintPixmap(Painter &p, const QRect &r, bool selected) {
|
||||||
|
const auto pixmap = paintedPixmap(selected);
|
||||||
|
if (!pixmap.isNull()) {
|
||||||
|
p.drawPixmap(
|
||||||
|
QPoint(
|
||||||
|
r.x() + (r.width() - _size.width()) / 2,
|
||||||
|
r.y() + (r.height() - _size.height()) / 2),
|
||||||
|
pixmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap StickerContent::paintedPixmap(bool selected) const {
|
||||||
|
const auto o = _parent->data()->fullId();
|
||||||
|
const auto w = _size.width();
|
||||||
|
const auto h = _size.height();
|
||||||
|
const auto &c = st::msgStickerOverlay;
|
||||||
|
const auto good = _document->goodThumbnail();
|
||||||
|
if (good && !good->loaded()) {
|
||||||
|
good->load({});
|
||||||
|
}
|
||||||
|
if (const auto image = _document->getStickerLarge()) {
|
||||||
|
return selected
|
||||||
|
? image->pixColored(o, c, w, h)
|
||||||
|
: image->pix(o, w, h);
|
||||||
|
//
|
||||||
|
// Inline thumbnails can't have alpha channel.
|
||||||
|
//
|
||||||
|
//} else if (const auto blurred = _document->thumbnailInline()) {
|
||||||
|
// return selected
|
||||||
|
// ? blurred->pixBlurredColored(o, c, w, h)
|
||||||
|
// : blurred->pixBlurred(o, w, h);
|
||||||
|
} else if (good && good->loaded()) {
|
||||||
|
return selected
|
||||||
|
? good->pixColored(o, c, w, h)
|
||||||
|
: good->pix(o, w, h);
|
||||||
|
} else if (const auto thumbnail = _document->thumbnail()) {
|
||||||
|
return selected
|
||||||
|
? thumbnail->pixBlurredColored(o, c, w, h)
|
||||||
|
: thumbnail->pixBlurred(o, w, h);
|
||||||
|
}
|
||||||
|
return QPixmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerContent::refreshLink() {
|
||||||
|
if (_link) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto sticker = _document->sticker();
|
||||||
|
if (isEmojiSticker()) {
|
||||||
|
const auto weak = base::make_weak(this);
|
||||||
|
_link = std::make_shared<LambdaClickHandler>([weak] {
|
||||||
|
const auto that = weak.get();
|
||||||
|
if (!that) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
that->_lottieOncePlayed = false;
|
||||||
|
that->_parent->data()->history()->owner().requestViewRepaint(
|
||||||
|
that->_parent);
|
||||||
|
});
|
||||||
|
} else if (sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
||||||
|
_link = std::make_shared<LambdaClickHandler>([document = _document] {
|
||||||
|
StickerSetBox::Show(App::wnd()->sessionController(), document);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerContent::setupLottie() {
|
||||||
_lottie = Stickers::LottiePlayerFromDocument(
|
_lottie = Stickers::LottiePlayerFromDocument(
|
||||||
_data,
|
_document,
|
||||||
Stickers::LottieSize::MessageHistory,
|
Stickers::LottieSize::MessageHistory,
|
||||||
QSize(st::maxStickerSize, st::maxStickerSize) * cIntRetinaFactor(),
|
QSize(st::maxStickerSize, st::maxStickerSize) * cIntRetinaFactor(),
|
||||||
Lottie::Quality::High);
|
Lottie::Quality::High);
|
||||||
|
@ -142,7 +198,7 @@ void Sticker::setupLottie() {
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sticker::unloadLottie() {
|
void StickerContent::unloadLottie() {
|
||||||
if (!_lottie) {
|
if (!_lottie) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -150,247 +206,4 @@ void Sticker::unloadLottie() {
|
||||||
_parent->data()->history()->owner().unregisterHeavyViewPart(_parent);
|
_parent->data()->history()->owner().unregisterHeavyViewPart(_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sticker::draw(
|
|
||||||
Painter &p,
|
|
||||||
const QRect &r,
|
|
||||||
TextSelection selection,
|
|
||||||
crl::time ms) const {
|
|
||||||
auto sticker = _data->sticker();
|
|
||||||
if (!sticker) return;
|
|
||||||
|
|
||||||
if (sticker->animated && !_lottie && _data->loaded()) {
|
|
||||||
const_cast<Sticker*>(this)->setupLottie();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
|
||||||
|
|
||||||
_data->checkStickerLarge();
|
|
||||||
bool loaded = _data->loaded();
|
|
||||||
bool selected = (selection == FullSelection);
|
|
||||||
|
|
||||||
auto outbg = _parent->hasOutLayout();
|
|
||||||
auto inWebPage = (_parent->media() != this);
|
|
||||||
|
|
||||||
const auto item = _parent->data();
|
|
||||||
int usew = maxWidth(), usex = 0;
|
|
||||||
auto via = inWebPage ? nullptr : item->Get<HistoryMessageVia>();
|
|
||||||
auto reply = inWebPage ? nullptr : item->Get<HistoryMessageReply>();
|
|
||||||
if (via || reply) {
|
|
||||||
usew -= additionalWidth(via, reply);
|
|
||||||
if (outbg) {
|
|
||||||
usex = width() - usew;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rtl()) usex = width() - usex - usew;
|
|
||||||
|
|
||||||
const auto lottieReady = (_lottie && _lottie->ready());
|
|
||||||
const auto &pixmap = [&]() -> const QPixmap & {
|
|
||||||
const auto o = item->fullId();
|
|
||||||
const auto w = _pixw;
|
|
||||||
const auto h = _pixh;
|
|
||||||
const auto &c = st::msgStickerOverlay;
|
|
||||||
const auto good = _data->goodThumbnail();
|
|
||||||
if (!lottieReady && good && !good->loaded()) {
|
|
||||||
good->load({});
|
|
||||||
}
|
|
||||||
static QPixmap empty;
|
|
||||||
if (lottieReady) {
|
|
||||||
return empty;
|
|
||||||
} else if (const auto image = _data->getStickerLarge()) {
|
|
||||||
return selected
|
|
||||||
? image->pixColored(o, c, w, h)
|
|
||||||
: image->pix(o, w, h);
|
|
||||||
//
|
|
||||||
// Inline thumbnails can't have alpha channel.
|
|
||||||
//
|
|
||||||
//} else if (const auto blurred = _data->thumbnailInline()) {
|
|
||||||
// return selected
|
|
||||||
// ? blurred->pixBlurredColored(o, c, w, h)
|
|
||||||
// : blurred->pixBlurred(o, w, h);
|
|
||||||
} else if (good && good->loaded()) {
|
|
||||||
return selected
|
|
||||||
? good->pixColored(o, c, w, h)
|
|
||||||
: good->pix(o, w, h);
|
|
||||||
} else if (const auto thumbnail = _data->thumbnail()) {
|
|
||||||
return selected
|
|
||||||
? thumbnail->pixBlurredColored(o, c, w, h)
|
|
||||||
: thumbnail->pixBlurred(o, w, h);
|
|
||||||
} else {
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
if (!pixmap.isNull()) {
|
|
||||||
p.drawPixmap(
|
|
||||||
QPoint{ usex + (usew - _pixw) / 2, (minHeight() - _pixh) / 2 },
|
|
||||||
pixmap);
|
|
||||||
} else if (lottieReady) {
|
|
||||||
auto request = Lottie::FrameRequest();
|
|
||||||
request.box = QSize(_pixw, _pixh) * cIntRetinaFactor();
|
|
||||||
if (selected) {
|
|
||||||
request.colored = st::msgStickerOverlay->c;
|
|
||||||
}
|
|
||||||
const auto frame = _lottie->frameInfo(request);
|
|
||||||
const auto size = frame.image.size() / cIntRetinaFactor();
|
|
||||||
p.drawImage(
|
|
||||||
QRect(
|
|
||||||
QPoint(
|
|
||||||
usex + (usew - size.width()) / 2,
|
|
||||||
(minHeight() - size.height()) / 2),
|
|
||||||
size),
|
|
||||||
frame.image);
|
|
||||||
|
|
||||||
const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
|
|
||||||
const auto playOnce = isEmojiSticker()
|
|
||||||
|| !_data->session().settings().loopAnimatedStickers();
|
|
||||||
if (!paused
|
|
||||||
&& (!playOnce || frame.index != 0 || !_lottieOncePlayed)
|
|
||||||
&& _lottie->markFrameShown()
|
|
||||||
&& playOnce
|
|
||||||
&& !_lottieOncePlayed) {
|
|
||||||
_lottieOncePlayed = true;
|
|
||||||
_parent->delegate()->elementStartStickerLoop(_parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!inWebPage) {
|
|
||||||
auto fullRight = usex + usew;
|
|
||||||
auto fullBottom = height();
|
|
||||||
if (needInfoDisplay()) {
|
|
||||||
_parent->drawInfo(p, fullRight, fullBottom, usex * 2 + usew, selected, InfoDisplayType::Background);
|
|
||||||
}
|
|
||||||
if (via || reply) {
|
|
||||||
int rectw = width() - usew - st::msgReplyPadding.left();
|
|
||||||
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
|
||||||
if (via) {
|
|
||||||
recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
recth += st::msgReplyBarSize.height();
|
|
||||||
}
|
|
||||||
int rectx = outbg ? 0 : (usew + st::msgReplyPadding.left());
|
|
||||||
int recty = st::msgDateImgDelta;
|
|
||||||
if (rtl()) rectx = width() - rectx - rectw;
|
|
||||||
|
|
||||||
App::roundRect(p, rectx, recty, rectw, recth, selected ? st::msgServiceBgSelected : st::msgServiceBg, selected ? StickerSelectedCorners : StickerCorners);
|
|
||||||
p.setPen(st::msgServiceFg);
|
|
||||||
rectx += st::msgReplyPadding.left();
|
|
||||||
rectw -= st::msgReplyPadding.left() + st::msgReplyPadding.right();
|
|
||||||
if (via) {
|
|
||||||
p.setFont(st::msgDateFont);
|
|
||||||
p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * rectx + rectw, via->text);
|
|
||||||
int skip = st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
|
||||||
recty += skip;
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
HistoryMessageReply::PaintFlags flags = 0;
|
|
||||||
if (selected) {
|
|
||||||
flags |= HistoryMessageReply::PaintFlag::Selected;
|
|
||||||
}
|
|
||||||
reply->paint(p, _parent, rectx, recty, rectw, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_parent->displayRightAction()) {
|
|
||||||
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
|
||||||
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
|
||||||
_parent->drawRightAction(p, fastShareLeft, fastShareTop, 2 * usex + usew);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextState Sticker::textState(QPoint point, StateRequest request) const {
|
|
||||||
auto result = TextState(_parent);
|
|
||||||
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto outbg = _parent->hasOutLayout();
|
|
||||||
auto inWebPage = (_parent->media() != this);
|
|
||||||
|
|
||||||
const auto item = _parent->data();
|
|
||||||
int usew = maxWidth(), usex = 0;
|
|
||||||
auto via = inWebPage ? nullptr : item->Get<HistoryMessageVia>();
|
|
||||||
auto reply = inWebPage ? nullptr : item->Get<HistoryMessageReply>();
|
|
||||||
if (via || reply) {
|
|
||||||
usew -= additionalWidth(via, reply);
|
|
||||||
if (outbg) {
|
|
||||||
usex = width() - usew;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rtl()) usex = width() - usex - usew;
|
|
||||||
|
|
||||||
if (via || reply) {
|
|
||||||
int rectw = width() - usew - st::msgReplyPadding.left();
|
|
||||||
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
|
||||||
if (via) {
|
|
||||||
recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0);
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
recth += st::msgReplyBarSize.height();
|
|
||||||
}
|
|
||||||
int rectx = outbg ? 0 : (usew + st::msgReplyPadding.left());
|
|
||||||
int recty = st::msgDateImgDelta;
|
|
||||||
if (rtl()) rectx = width() - rectx - rectw;
|
|
||||||
|
|
||||||
if (via) {
|
|
||||||
int viah = st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? 0 : st::msgReplyPadding.bottom());
|
|
||||||
if (QRect(rectx, recty, rectw, viah).contains(point)) {
|
|
||||||
result.link = via->link;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
int skip = st::msgServiceNameFont->height + (reply ? 2 * st::msgReplyPadding.top() : 0);
|
|
||||||
recty += skip;
|
|
||||||
recth -= skip;
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
if (QRect(rectx, recty, rectw, recth).contains(point)) {
|
|
||||||
result.link = reply->replyToLink();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_parent->media() == this) {
|
|
||||||
auto fullRight = usex + usew;
|
|
||||||
auto fullBottom = height();
|
|
||||||
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
|
|
||||||
result.cursor = CursorState::Date;
|
|
||||||
}
|
|
||||||
if (_parent->displayRightAction()) {
|
|
||||||
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
|
||||||
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
|
||||||
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
|
||||||
result.link = _parent->rightActionLink();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pixLeft = usex + (usew - _pixw) / 2;
|
|
||||||
auto pixTop = (minHeight() - _pixh) / 2;
|
|
||||||
if (QRect(pixLeft, pixTop, _pixw, _pixh).contains(point)) {
|
|
||||||
result.link = _packLink;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sticker::needInfoDisplay() const {
|
|
||||||
return (_parent->data()->id < 0 || _parent->isUnderCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
int Sticker::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const {
|
|
||||||
int result = 0;
|
|
||||||
if (via) {
|
|
||||||
accumulate_max(result, st::msgReplyPadding.left() + st::msgReplyPadding.left() + via->maxWidth + st::msgReplyPadding.left());
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
accumulate_max(result, st::msgReplyPadding.left() + reply->replyToWidth());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Sticker::additionalWidth() const {
|
|
||||||
const auto item = _parent->data();
|
|
||||||
return additionalWidth(
|
|
||||||
item->Get<HistoryMessageVia>(),
|
|
||||||
item->Get<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -7,13 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "history/view/media/history_view_media.h"
|
#include "history/view/media/history_view_media_unwrapped.h"
|
||||||
#include "base/weak_ptr.h"
|
#include "base/weak_ptr.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
|
||||||
struct HistoryMessageVia;
|
namespace Data {
|
||||||
struct HistoryMessageReply;
|
struct FileOrigin;
|
||||||
struct HistoryMessageForwarded;
|
} // namespace Data
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class SinglePlayer;
|
class SinglePlayer;
|
||||||
|
@ -21,65 +21,46 @@ class SinglePlayer;
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
class Sticker : public Media, public base::has_weak_ptr {
|
class StickerContent final
|
||||||
|
: public UnwrappedMedia::Content
|
||||||
|
, public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
Sticker(
|
StickerContent(
|
||||||
not_null<Element*> parent,
|
not_null<Element*> parent,
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
~Sticker();
|
~StickerContent();
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
|
QSize size() override;
|
||||||
TextState textState(QPoint point, StateRequest request) const override;
|
void draw(Painter &p, const QRect &r, bool selected) override;
|
||||||
|
ClickHandlerPtr link() override {
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
return _link;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool dragItem() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentData *getDocument() const override {
|
DocumentData *document() override {
|
||||||
return _data;
|
return _document;
|
||||||
}
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool hidesForwardedInfo() const override {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
void clearStickerLoopPlayed() override {
|
void clearStickerLoopPlayed() override {
|
||||||
_lottieOncePlayed = false;
|
_lottieOncePlayed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadHeavyPart() override {
|
void unloadHeavyPart() override {
|
||||||
unloadLottie();
|
unloadLottie();
|
||||||
}
|
}
|
||||||
|
void refreshLink() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] bool isEmojiSticker() const;
|
[[nodiscard]] bool isEmojiSticker() const;
|
||||||
|
void paintLottie(Painter &p, const QRect &r, bool selected);
|
||||||
QSize countOptimalSize() override;
|
void paintPixmap(Painter &p, const QRect &r, bool selected);
|
||||||
QSize countCurrentSize(int newWidth) override;
|
[[nodiscard]] QPixmap paintedPixmap(bool selected) const;
|
||||||
|
|
||||||
bool needInfoDisplay() const;
|
|
||||||
int additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const;
|
|
||||||
int additionalWidth() const;
|
|
||||||
|
|
||||||
void setupLottie();
|
void setupLottie();
|
||||||
void unloadLottie();
|
void unloadLottie();
|
||||||
|
|
||||||
int _pixw = 1;
|
const not_null<Element*> _parent;
|
||||||
int _pixh = 1;
|
const not_null<DocumentData*> _document;
|
||||||
ClickHandlerPtr _packLink;
|
|
||||||
DocumentData *_data = nullptr;
|
|
||||||
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||||
|
ClickHandlerPtr _link;
|
||||||
|
QSize _size;
|
||||||
mutable bool _lottieOncePlayed = false;
|
mutable bool _lottieOncePlayed = false;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
|
|
@ -296,6 +296,8 @@
|
||||||
<(src_loc)/history/view/media/history_view_media_common.cpp
|
<(src_loc)/history/view/media/history_view_media_common.cpp
|
||||||
<(src_loc)/history/view/media/history_view_media_grouped.h
|
<(src_loc)/history/view/media/history_view_media_grouped.h
|
||||||
<(src_loc)/history/view/media/history_view_media_grouped.cpp
|
<(src_loc)/history/view/media/history_view_media_grouped.cpp
|
||||||
|
<(src_loc)/history/view/media/history_view_media_unwrapped.h
|
||||||
|
<(src_loc)/history/view/media/history_view_media_unwrapped.cpp
|
||||||
<(src_loc)/history/view/media/history_view_photo.h
|
<(src_loc)/history/view/media/history_view_photo.h
|
||||||
<(src_loc)/history/view/media/history_view_photo.cpp
|
<(src_loc)/history/view/media/history_view_photo.cpp
|
||||||
<(src_loc)/history/view/media/history_view_poll.h
|
<(src_loc)/history/view/media/history_view_poll.h
|
||||||
|
|
Loading…
Reference in New Issue