From 9a717b885ad4570f6e64e76cc3480c1772c814f5 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 24 Jan 2023 21:07:09 +0300 Subject: [PATCH] Moved out preview for userpic emoji builder to separated file. --- Telegram/CMakeLists.txt | 2 + .../info_userpic_emoji_builder_preview.cpp | 191 ++++++++++++++++ .../info_userpic_emoji_builder_preview.h | 75 ++++++ .../info_userpic_emoji_builder_widget.cpp | 213 +----------------- 4 files changed, 269 insertions(+), 212 deletions(-) create mode 100644 Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp create mode 100644 Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index ed6bfbef0..97b04f565 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -861,6 +861,8 @@ PRIVATE info/userpic/info_userpic_emoji_builder.h info/userpic/info_userpic_emoji_builder_menu_item.cpp info/userpic/info_userpic_emoji_builder_menu_item.h + info/userpic/info_userpic_emoji_builder_preview.cpp + info/userpic/info_userpic_emoji_builder_preview.h info/userpic/info_userpic_emoji_builder_widget.cpp info/userpic/info_userpic_emoji_builder_widget.h inline_bots/bot_attach_web_view.cpp diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp new file mode 100644 index 000000000..1aa4f9813 --- /dev/null +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp @@ -0,0 +1,191 @@ +/* +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 "info/userpic/info_userpic_emoji_builder_preview.h" + +#include "chat_helpers/stickers_lottie.h" +#include "data/data_document.h" +#include "data/data_document_media.h" +#include "data/data_session.h" +#include "history/view/media/history_view_sticker_player.h" +#include "main/main_session.h" +#include "ui/painter.h" +#include "ui/rect.h" + +namespace UserpicBuilder { + +PreviewPainter::PreviewPainter(int size) +: _size(size) +, _emojiSize(base::SafeRound(_size / M_SQRT2)) +, _frameRect(Rect(Size(_size)) - Margins((_size - _emojiSize) / 2)) { +} + +not_null PreviewPainter::document() const { + Expects(_media != nullptr); + return _media->owner(); +} + +void PreviewPainter::setDocument( + not_null document, + Fn updateCallback) { + if (_media && (document == _media->owner())) { + return; + } + _lifetime.destroy(); + + const auto sticker = document->sticker(); + Assert(sticker != nullptr); + _media = document->createMediaView(); + _media->checkStickerLarge(); + _media->goodThumbnailWanted(); + + rpl::single() | rpl::then( + document->owner().session().downloaderTaskFinished() + ) | rpl::start_with_next([=] { + if (!_media->loaded()) { + return; + } + _lifetime.destroy(); + const auto emojiSize = Size(_emojiSize); + if (sticker->isLottie()) { + _player = std::make_unique( + ChatHelpers::LottiePlayerFromDocument( + _media.get(), + // + ChatHelpers::StickerLottieSize::EmojiInteractionReserved7, + emojiSize, + Lottie::Quality::High)); + } else if (sticker->isWebm()) { + _player = std::make_unique( + _media->owner()->location(), + _media->bytes(), + emojiSize); + } else if (sticker) { + _player = std::make_unique( + _media->owner()->location(), + _media->bytes(), + emojiSize); + } + if (_player) { + _player->setRepaintCallback(updateCallback); + } else { + updateCallback(); + } + }, _lifetime); +} + +void PreviewPainter::paintBackground(QPainter &p, const QBrush &brush) { + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(brush); + p.drawEllipse(0, 0, _size, _size); +} + +bool PreviewPainter::paintForeground(QPainter &p) { + if (_player && _player->ready()) { + // resolveIsColored(); + const auto frame = _player->frame( + Size(_emojiSize), + (/*_isColored + ? st::profileVerifiedCheckBg->c + : */QColor(0, 0, 0, 0)), + false, + crl::now(), + _paused); + + if (frame.image.width() == frame.image.height()) { + p.drawImage(_frameRect, frame.image); + } else { + auto frameRect = Rect(frame.image.size().scaled( + _frameRect.size(), + Qt::KeepAspectRatio)); + frameRect.moveCenter(_frameRect.center()); + p.drawImage(frameRect, frame.image); + } + if (!_paused) { + _player->markFrameShown(); + } + return true; + } + return false; +} + +EmojiUserpic::EmojiUserpic(not_null parent, const QSize &size) +: Ui::RpWidget(parent) +, _painter(size.width()) +, _duration(st::slideWrapDuration) { + resize(size); +} + +void EmojiUserpic::setDocument(not_null document) { + _painter.setDocument(document, [=] { update(); }); +} + +void EmojiUserpic::result(int size, Fn done) { + const auto colors = ranges::views::all( + _stops + ) | ranges::views::transform([](const QGradientStop &stop) { + return stop.second; + }) | ranges::to_vector; + const auto painter = lifetime().make_state(size); + // Reset to the first frame. + painter->setDocument(_painter.document(), [=] { + auto background = Images::GenerateLinearGradient(Size(size), colors); + + auto p = QPainter(&background); + while (true) { + if (painter->paintForeground(p)) { + break; + } + } + done(std::move(background)); + }); +} + +void EmojiUserpic::setGradientStops(QGradientStops stops) { + if (_stops == stops) { + return; + } + if (!_stops.empty()) { + auto gradient = QLinearGradient(0, 0, width() / 2., height()); + gradient.setStops(base::take(_stops)); + _previousBrush = QBrush(std::move(gradient)); + } + _stops = std::move(stops); + { + auto gradient = QLinearGradient(0, 0, width() / 2., height()); + gradient.setStops(_stops); + _brush = QBrush(std::move(gradient)); + } + if (_duration) { + _animation.stop(); + _animation.start([=] { update(); }, 0., 1., _duration); + } else { + update(); + } +} + +void EmojiUserpic::paintEvent(QPaintEvent *event) { + auto p = QPainter(this); + + if (_animation.animating() && (_previousBrush != Qt::NoBrush)) { + _painter.paintBackground(p, _previousBrush); + + p.setOpacity(_animation.value(1.)); + } + + _painter.paintBackground(p, _brush); + + p.setOpacity(1.); + _painter.paintForeground(p); +} + +void EmojiUserpic::setDuration(crl::time duration) { + _duration = duration; +} + +} // namespace UserpicBuilder diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.h b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.h new file mode 100644 index 000000000..371e0109c --- /dev/null +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.h @@ -0,0 +1,75 @@ +/* +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 "ui/rp_widget.h" + +#include "ui/effects/animations.h" + +namespace Data { +class DocumentMedia; +} // namespace Data + +namespace HistoryView { +class StickerPlayer; +} // namespace HistoryView + +class DocumentData; + +namespace UserpicBuilder { + +class PreviewPainter final { +public: + PreviewPainter(int size); + + [[nodiscard]] not_null document() const; + + void setDocument( + not_null document, + Fn updateCallback); + + void paintBackground(QPainter &p, const QBrush &brush); + bool paintForeground(QPainter &p); + +private: + const int _size; + const int _emojiSize; + const QRect _frameRect; + + std::shared_ptr _media; + std::unique_ptr _player; + bool _paused = true; + rpl::lifetime _lifetime; + +}; + +class EmojiUserpic final : public Ui::RpWidget { +public: + EmojiUserpic(not_null parent, const QSize &size); + + void result(int size, Fn done); + void setGradientStops(QGradientStops stops); + void setDocument(not_null document); + void setDuration(crl::time duration); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + PreviewPainter _painter; + + QBrush _previousBrush; + QBrush _brush; + QGradientStops _stops; + + crl::time _duration; + Ui::Animations::Simple _animation; + +}; + +} // namespace UserpicBuilder diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp index 0ee047c8a..ed803fd6d 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp @@ -11,16 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "chat_helpers/emoji_list_widget.h" #include "chat_helpers/stickers_list_widget.h" -#include "chat_helpers/stickers_lottie.h" -#include "data/data_document.h" -#include "data/data_document_media.h" #include "data/data_message_reactions.h" #include "data/data_session.h" #include "data/stickers/data_custom_emoji.h" #include "editor/photo_editor_layer_widget.h" // Editor::kProfilePhotoSize. -#include "history/view/media/history_view_sticker_player.h" #include "info/userpic/info_userpic_bubble_wrap.h" #include "info/userpic/info_userpic_colors_palette_chooser.h" +#include "info/userpic/info_userpic_emoji_builder_preview.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/settings_common.h" @@ -43,214 +40,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace UserpicBuilder { namespace { -class PreviewPainter final { -public: - PreviewPainter(int size); - - [[nodiscard]] not_null document() const; - - void setDocument( - not_null document, - Fn updateCallback); - - void paintBackground(QPainter &p, const QBrush &brush); - bool paintForeground(QPainter &p); - -private: - const int _size; - const int _emojiSize; - const QRect _frameRect; - - std::shared_ptr _media; - std::unique_ptr _player; - bool _paused = true; - rpl::lifetime _lifetime; - -}; - -PreviewPainter::PreviewPainter(int size) -: _size(size) -, _emojiSize(base::SafeRound(_size / M_SQRT2)) -, _frameRect(Rect(Size(_size)) - Margins((_size - _emojiSize) / 2)) { -} - -not_null PreviewPainter::document() const { - Expects(_media != nullptr); - return _media->owner(); -} - -void PreviewPainter::setDocument( - not_null document, - Fn updateCallback) { - if (_media && (document == _media->owner())) { - return; - } - _lifetime.destroy(); - - const auto sticker = document->sticker(); - Assert(sticker != nullptr); - _media = document->createMediaView(); - _media->checkStickerLarge(); - _media->goodThumbnailWanted(); - - rpl::single() | rpl::then( - document->owner().session().downloaderTaskFinished() - ) | rpl::start_with_next([=] { - if (!_media->loaded()) { - return; - } - _lifetime.destroy(); - const auto emojiSize = Size(_emojiSize); - if (sticker->isLottie()) { - _player = std::make_unique( - ChatHelpers::LottiePlayerFromDocument( - _media.get(), - // - ChatHelpers::StickerLottieSize::EmojiInteractionReserved7, - emojiSize, - Lottie::Quality::High)); - } else if (sticker->isWebm()) { - _player = std::make_unique( - _media->owner()->location(), - _media->bytes(), - emojiSize); - } else if (sticker) { - _player = std::make_unique( - _media->owner()->location(), - _media->bytes(), - emojiSize); - } - if (_player) { - _player->setRepaintCallback(updateCallback); - } else { - updateCallback(); - } - }, _lifetime); -} - -void PreviewPainter::paintBackground(QPainter &p, const QBrush &brush) { - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.setBrush(brush); - p.drawEllipse(0, 0, _size, _size); -} - -bool PreviewPainter::paintForeground(QPainter &p) { - if (_player && _player->ready()) { - // resolveIsColored(); - const auto frame = _player->frame( - Size(_emojiSize), - (/*_isColored - ? st::profileVerifiedCheckBg->c - : */QColor(0, 0, 0, 0)), - false, - crl::now(), - _paused); - - if (frame.image.width() == frame.image.height()) { - p.drawImage(_frameRect, frame.image); - } else { - auto frameRect = Rect(frame.image.size().scaled( - _frameRect.size(), - Qt::KeepAspectRatio)); - frameRect.moveCenter(_frameRect.center()); - p.drawImage(frameRect, frame.image); - } - if (!_paused) { - _player->markFrameShown(); - } - return true; - } - return false; -} - -class EmojiUserpic final : public Ui::RpWidget { -public: - EmojiUserpic(not_null parent, const QSize &size); - - void result(int size, Fn done); - void setGradientStops(QGradientStops stops); - void setDocument(not_null document); - -protected: - void paintEvent(QPaintEvent *event) override; - -private: - PreviewPainter _painter; - - QBrush _previousBrush; - QBrush _brush; - QGradientStops _stops; - - Ui::Animations::Simple _animation; - -}; - -EmojiUserpic::EmojiUserpic(not_null parent, const QSize &size) -: Ui::RpWidget(parent) -, _painter(size.width()) { - resize(size); -} - -void EmojiUserpic::setDocument(not_null document) { - _painter.setDocument(document, [=] { update(); }); -} - -void EmojiUserpic::result(int size, Fn done) { - const auto colors = ranges::views::all( - _stops - ) | ranges::views::transform([](const QGradientStop &stop) { - return stop.second; - }) | ranges::to_vector; - const auto painter = lifetime().make_state(size); - // Reset to the first frame. - painter->setDocument(_painter.document(), [=] { - auto background = Images::GenerateLinearGradient(Size(size), colors); - - auto p = QPainter(&background); - while (true) { - if (painter->paintForeground(p)) { - break; - } - } - done(std::move(background)); - }); -} - -void EmojiUserpic::setGradientStops(QGradientStops stops) { - if (_stops == stops) { - return; - } - if (!_stops.empty()) { - auto gradient = QLinearGradient(0, 0, width() / 2., height()); - gradient.setStops(base::take(_stops)); - _previousBrush = QBrush(std::move(gradient)); - } - _stops = std::move(stops); - { - auto gradient = QLinearGradient(0, 0, width() / 2., height()); - gradient.setStops(_stops); - _brush = QBrush(std::move(gradient)); - } - _animation.stop(); - _animation.start([=] { update(); }, 0., 1., st::slideWrapDuration); -} - -void EmojiUserpic::paintEvent(QPaintEvent *event) { - auto p = QPainter(this); - - if (_animation.animating() && (_previousBrush != Qt::NoBrush)) { - _painter.paintBackground(p, _previousBrush); - - p.setOpacity(_animation.value(1.)); - } - - _painter.paintBackground(p, _brush); - - p.setOpacity(1.); - _painter.paintForeground(p); -} - class EmojiSelector final : public Ui::RpWidget { public: EmojiSelector(