From 6588242793d97a1d8fa2931609d696d8f68660bc Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 27 Sep 2021 21:02:16 +0400 Subject: [PATCH] Prepare correct custom chat theme preview. --- Telegram/SourceFiles/ui/chat/chat_theme.cpp | 7 +- Telegram/SourceFiles/ui/chat/chat_theme.h | 4 + .../ui/chat/choose_theme_controller.cpp | 152 +++++++++++++----- Telegram/lib_ui | 2 +- 4 files changed, 125 insertions(+), 40 deletions(-) diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.cpp b/Telegram/SourceFiles/ui/chat/chat_theme.cpp index ffdf8a8ac5..52d87b72e8 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_theme.cpp @@ -124,9 +124,8 @@ constexpr auto kMinAcceptableContrast = 1.14;// 4.5; QImage::Format_ARGB32_Premultiplied), .gradient = gradient, .area = request.area, - .waitingForNegativePattern = (request.background.isPattern - && request.background.prepared.isNull() - && request.background.patternOpacity < 0.) + .waitingForNegativePattern + = request.background.waitingForNegativePattern() }; } else { const auto rects = ComputeChatBackgroundRects( @@ -427,6 +426,8 @@ void ChatTheme::updateBackgroundImageFrom(ChatThemeBackground &&background) { _cacheBackgroundTimer->cancel(); } cacheBackgroundNow(); + } else { + _repaintBackgroundRequests.fire({}); } } diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.h b/Telegram/SourceFiles/ui/chat/chat_theme.h index bcc357fbdc..e8393bec53 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.h +++ b/Telegram/SourceFiles/ui/chat/chat_theme.h @@ -32,6 +32,10 @@ struct ChatThemeBackground { int gradientRotation = 0; bool isPattern = false; bool tile = false; + + [[nodiscard]] bool waitingForNegativePattern() const { + return isPattern && prepared.isNull() && (patternOpacity < 0.); + } }; bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b); diff --git a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp index 15742b7e0f..2bb2b445ed 100644 --- a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp +++ b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/chat/chat_theme.h" +#include "ui/chat/message_bubble.h" #include "ui/wrap/vertical_layout.h" #include "main/main_session.h" #include "window/window_session_controller.h" @@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_widgets.h" #include "styles/style_layers.h" // boxTitle. #include "styles/style_settings.h" +#include "styles/style_window.h" namespace Ui { namespace { @@ -33,11 +35,86 @@ namespace { constexpr auto kDisableElement = "disable"_cs; [[nodiscard]] QImage GeneratePreview(not_null theme) { - const auto &colors = theme->background().colors; - auto result = Images::GenerateGradient( - st::settingsThemePreviewSize * style::DevicePixelRatio(), - colors.empty() ? std::vector{ 1, QColor(0, 0, 0) } : colors - ).convertToFormat(QImage::Format_ARGB32_Premultiplied); + const auto &background = theme->background(); + const auto &colors = background.colors; + const auto size = st::settingsThemePreviewSize; + auto prepared = background.prepared; + const auto paintPattern = [&](QPainter &p, bool inverted) { + if (prepared.isNull()) { + return; + } + const auto w = prepared.width(); + const auto h = prepared.height(); + const auto scaled = size.scaled( + st::windowMinWidth / 2, + st::windowMinHeight / 2, + Qt::KeepAspectRatio); + const auto use = (scaled.width() > w || scaled.height() > h) + ? scaled.scaled({ w, h }, Qt::KeepAspectRatio) + : scaled; + const auto good = QSize( + std::max(use.width(), 1), + std::max(use.height(), 1)); + auto small = prepared.copy(QRect( + QPoint( + (w - good.width()) / 2, + (h - good.height()) / 2), + good)); + if (inverted) { + small = Ui::InvertPatternImage(std::move(small)); + } + p.drawImage( + QRect(QPoint(), size * style::DevicePixelRatio()), + small); + }; + const auto fullsize = size * style::DevicePixelRatio(); + auto result = background.waitingForNegativePattern() + ? QImage( + fullsize, + QImage::Format_ARGB32_Premultiplied) + : Ui::GenerateBackgroundImage( + fullsize, + colors.empty() ? std::vector{ 1, QColor(0, 0, 0) } : colors, + background.gradientRotation, + background.patternOpacity, + paintPattern); + if (background.waitingForNegativePattern()) { + result.fill(Qt::black); + } + { + auto p = QPainter(&result); + const auto sent = QRect( + QPoint( + (size.width() + - st::settingsThemeBubbleSize.width() + - st::settingsThemeBubblePosition.x()), + st::settingsThemeBubblePosition.y()), + st::settingsThemeBubbleSize); + const auto received = QRect( + st::settingsThemeBubblePosition.x(), + sent.y() + sent.height() + st::settingsThemeBubbleSkip, + sent.width(), + sent.height()); + const auto radius = st::settingsThemeBubbleRadius; + + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + if (const auto pattern = theme->bubblesBackgroundPattern()) { + auto bubble = pattern->pixmap.toImage().scaled( + sent.size() * style::DevicePixelRatio(), + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation + ).convertToFormat(QImage::Format_ARGB32_Premultiplied); + const auto corners = Images::CornersMask(radius); + Images::prepareRound(bubble, corners); + p.drawImage(sent, bubble); + } else { + p.setBrush(theme->palette()->msgOutBg()->c); + p.drawRoundedRect(sent, radius, radius); + } + p.setBrush(theme->palette()->msgInBg()->c); + p.drawRoundedRect(received, radius, radius); + } Images::prepareRound(result, ImageRoundRadius::Large); return result; } @@ -220,30 +297,6 @@ void ChooseThemeController::paintEntry(QPainter &p, const Entry &entry) { const auto geometry = entry.geometry; p.drawImage(geometry, entry.preview); - if (entry.theme) { - const auto received = QRect( - st::settingsThemeBubblePosition, - st::settingsThemeBubbleSize); - const auto sent = QRect( - (geometry.width() - - received.width() - - st::settingsThemeBubblePosition.x()), - received.y() + received.height() + st::settingsThemeBubbleSkip, - received.width(), - received.height()); - const auto radius = st::settingsThemeBubbleRadius; - - const auto sentBg = entry.theme->palette()->msgOutBg()->c; - const auto receivedBg = entry.theme->palette()->msgInBg()->c; - - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - - p.setBrush(receivedBg); - p.drawRoundedRect(received.translated(geometry.topLeft()), radius, radius); - p.setBrush(sentBg); - p.drawRoundedRect(sent.translated(geometry.topLeft()), radius, radius); - } const auto size = Ui::Emoji::GetSizeLarge(); const auto factor = style::DevicePixelRatio(); const auto skip = st::normalFont->spacew * 2; @@ -376,14 +429,41 @@ void ChooseThemeController::fill( ) | rpl::start_with_next([=](std::shared_ptr &&data) { const auto id = data->key(); const auto i = ranges::find(_entries, id, &Entry::id); - if (i != end(_entries)) { - i->theme = std::move(data); - i->preview = GeneratePreview(i->theme.get()); - if (_chosen == i->emoji->text()) { - _controller->overridePeerTheme(_peer, i->theme); - } - _inner->update(); + if (i == end(_entries)) { + return; } + const auto theme = data.get(); + i->theme = std::move(data); + i->preview = GeneratePreview(theme); + if (_chosen == i->emoji->text()) { + _controller->overridePeerTheme(_peer, i->theme); + } + _inner->update(); + + if (!theme->background().isPattern + || !theme->background().prepared.isNull()) { + return; + } + // Subscribe to pattern loading if needed. + theme->repaintBackgroundRequests( + ) | rpl::filter([=] { + const auto i = ranges::find( + _entries, + id, + &Entry::id); + return (i == end(_entries)) + || !i->theme->background().prepared.isNull(); + }) | rpl::take(1) | rpl::start_with_next([=] { + const auto i = ranges::find( + _entries, + id, + &Entry::id); + if (i == end(_entries)) { + return; + } + i->preview = GeneratePreview(theme); + _inner->update(); + }, _cachingLifetime); }, _cachingLifetime); _entries.back().preview; x += single.width() + skip; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index e62d92f655..40fc5b35f0 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit e62d92f655a60b507bada9e387fb48aae89a5e72 +Subproject commit 40fc5b35f005d14b7216d956051a55429d984065