diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index c4013f39e..f94200a29 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "window/themes/window_theme.h" #include "ui/chat/chat_theme.h" +#include "ui/chat/chat_style.h" #include "ui/toast/toast.h" #include "ui/image/image.h" #include "ui/widgets/checkbox.h" @@ -365,6 +366,7 @@ BackgroundPreviewBox::BackgroundPreviewBox( const Data::WallPaper &paper) : SimpleElementDelegate(controller, [=] { update(); }) , _controller(controller) +, _chatStyle(std::make_unique()) , _text1(GenerateTextItem( delegate(), _controller->session().data().history(PeerData::kServiceNotificationsId), @@ -378,6 +380,8 @@ BackgroundPreviewBox::BackgroundPreviewBox( , _paper(paper) , _media(_paper.document() ? _paper.document()->createMediaView() : nullptr) , _radial([=](crl::time now) { radialAnimationCallback(now); }) { + _chatStyle->apply(controller->defaultChatTheme().get()); + if (_media) { _media->thumbnailWanted(_paper.fileOrigin()); } @@ -590,14 +594,10 @@ QRect BackgroundPreviewBox::radialRect() const { void BackgroundPreviewBox::paintTexts(Painter &p, crl::time ms) { const auto height1 = _text1->height(); const auto height2 = _text2->height(); - const auto context = HistoryView::PaintContext{ - .st = style::main_palette::get(), - .bubblesPattern = nullptr, // #TODO bubbles - .viewport = rect(), - .clip = rect(), - .selection = TextSelection(), - .now = ms, - }; + const auto context = _controller->defaultChatTheme()->preparePaintContext( + _chatStyle.get(), + rect(), + rect()); p.translate(0, textsTop()); paintDate(p); _text1->draw(p, context); diff --git a/Telegram/SourceFiles/boxes/background_preview_box.h b/Telegram/SourceFiles/boxes/background_preview_box.h index 0a89934df..24554cd84 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.h +++ b/Telegram/SourceFiles/boxes/background_preview_box.h @@ -25,6 +25,7 @@ class SessionController; namespace Ui { class Checkbox; +class ChatStyle; } // namespace Ui class BackgroundPreviewBox @@ -71,6 +72,7 @@ private: void checkBlurAnimationStart(); const not_null _controller; + std::unique_ptr _chatStyle; AdminLog::OwnedItem _text1; AdminLog::OwnedItem _text2; Data::WallPaper _paper; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index fa7ae0eaa..27a431a61 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -242,6 +242,14 @@ InnerWidget::InnerWidget( st::historyAdminLogEmptyWidth - st::historyAdminLogEmptyPadding.left() - st::historyAdminLogEmptyPadding.left()) { + Window::ChatThemeValueFromPeer( + controller, + channel + ) | rpl::start_with_next([=](std::shared_ptr &&theme) { + _theme = std::move(theme); + controller->setChatStyleTheme(_theme); + }, lifetime()); + setMouseTracking(true); _scrollDateHideTimer.setCallback([=] { scrollDateHideByTimer(); }); session().data().viewRepaintRequest( @@ -915,13 +923,12 @@ void InnerWidget::paintEvent(QPaintEvent *e) { if (from != end) { auto viewport = QRect(); // #TODO bubbles auto top = itemTop(from->get()); - auto context = HistoryView::PaintContext{ - .st = style::main_palette::get(), - .bubblesPattern = nullptr, - .viewport = viewport.translated(0, -top), - .clip = clip.translated(0, -top), - .now = crl::now(), - }; + auto context = _controller->preparePaintContext({ + .theme = _theme.get(), + .visibleAreaTop = _visibleTop, + .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), + .clip = clip, + }).translated(0, -top); p.translate(0, top); for (auto i = from; i != to; ++i) { const auto view = i->get(); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index 79cdcc806..732bbcc80 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -58,6 +58,9 @@ public: not_null channel); [[nodiscard]] Main::Session &session() const; + [[nodiscard]] not_null theme() const { + return _theme.get(); + } [[nodiscard]] rpl::producer<> showSearchSignal() const; [[nodiscard]] rpl::producer scrollToSignal() const; @@ -253,6 +256,7 @@ private: MTP::Sender _api; const std::unique_ptr _pathGradient; + std::shared_ptr _theme; std::vector _items; std::set _eventIds; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp index 2dca653a7..454468076 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_section.cpp @@ -470,11 +470,8 @@ void Widget::paintEvent(QPaintEvent *e) { //auto ms = crl::now(); //_historyDownShown.step(ms); - SectionWidget::PaintBackground( - controller(), - controller()->defaultChatTheme().get(), // #TODO themes - this, - e->rect()); + const auto clip = e->rect(); + SectionWidget::PaintBackground(controller(), _inner->theme(), this, clip); } void Widget::onScroll() { diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 354ddf333..3d6b6e1a5 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -163,6 +163,14 @@ HistoryInner::HistoryInner( , _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) { Instance = this; + Window::ChatThemeValueFromPeer( + controller, + _peer + ) | rpl::start_with_next([=](std::shared_ptr &&theme) { + _theme = std::move(theme); + controller->setChatStyleTheme(_theme); + }, lifetime()); + _touchSelectTimer.setSingleShot(true); connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); @@ -617,7 +625,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto top = mtop + block->y() + view->y(); auto context = _controller->preparePaintContext({ - .theme = _controller->defaultChatTheme().get(), // #TODO themes + .theme = _theme.get(), .visibleAreaTop = _visibleAreaTop, .visibleAreaTopGlobal = visibleAreaTopGlobal, .clip = clip, @@ -666,7 +674,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto readTill = (HistoryItem*)nullptr; auto top = htop + block->y() + view->y(); auto context = _controller->preparePaintContext({ - .theme = _controller->defaultChatTheme().get(), // #TODO themes + .theme = _theme.get(), .visibleAreaTop = _visibleAreaTop, .visibleAreaTopGlobal = visibleAreaTopGlobal, .visibleAreaWidth = width(), diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 03d455123..c3c72ca5c 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -34,6 +34,7 @@ class SessionController; } // namespace Window namespace Ui { +class ChatTheme; class PopupMenu; enum class ReportReason; class PathShiftGradient; @@ -55,7 +56,10 @@ public: not_null controller, not_null history); - Main::Session &session() const; + [[nodiscard]] Main::Session &session() const; + [[nodiscard]] not_null theme() const { + return _theme.get(); + } void messagesReceived(PeerData *peer, const QVector &messages); void messagesReceivedDown(PeerData *peer, const QVector &messages); @@ -344,6 +348,7 @@ private: const not_null _controller; const not_null _peer; const not_null _history; + std::shared_ptr _theme; History *_migrated = nullptr; int _contentWidth = 0; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c0bb6717f..2e00e68ff 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -4942,7 +4942,7 @@ void HistoryWidget::startItemRevealAnimations() { HistoryView::ListWidget::kItemRevealDuration, anim::easeOutCirc); if (item->out() || _history->peer->isSelf()) { - controller()->defaultChatTheme()->rotateComplexGradientBackground(); // #TODO themes + _list->theme()->rotateComplexGradientBackground(); } } } @@ -6888,7 +6888,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { Window::SectionWidget::PaintBackground( controller(), - controller()->defaultChatTheme().get(), // #TODO themes + _list ? _list->theme().get() : controller()->defaultChatTheme().get(), this, e->rect()); diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index ddd6086ba..a258c8aa0 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -143,6 +143,11 @@ public: not_null elementPathShiftGradient() override; void elementReplyTo(const FullMsgId &to) override; +protected: + [[nodiscard]] not_null controller() const { + return _controller; + } + private: const not_null _controller; const std::unique_ptr _pathGradient; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 913f1a42c..c30bfed98 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -1446,7 +1446,7 @@ void ListWidget::startItemRevealAnimations() { kItemRevealDuration, anim::easeOutCirc); if (view->data()->out()) { - controller()->defaultChatTheme()->rotateComplexGradientBackground(); // #TODO themes + _delegate->listChatTheme()->rotateComplexGradientBackground(); } } } @@ -1611,16 +1611,16 @@ void ListWidget::paintEvent(QPaintEvent *e) { auto to = std::lower_bound(begin(_items), end(_items), clip.top() + clip.height(), [this](auto &elem, int bottom) { return this->itemTop(elem) < bottom; }); + if (from != end(_items)) { auto viewport = QRect(); // #TODO bubbles auto top = itemTop(from->get()); - auto context = HistoryView::PaintContext{ - .st = style::main_palette::get(), - .bubblesPattern = nullptr, - .viewport = viewport.translated(0, -top), - .clip = clip.translated(0, -top), - .now = crl::now(), - }; + auto context = controller()->preparePaintContext({ + .theme = _delegate->listChatTheme(), + .visibleAreaTop = _visibleTop, + .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), + .clip = clip, + }).translated(0, -top); p.translate(0, top); for (auto i = from; i != to; ++i) { const auto view = *i; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 5d0910985..82fa9d1eb 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -21,6 +21,7 @@ class Session; namespace Ui { class PopupMenu; +class ChatTheme; } // namespace Ui namespace Window { @@ -91,6 +92,7 @@ public: const QString &command, const FullMsgId &context) = 0; virtual void listHandleViaClick(not_null bot) = 0; + virtual not_null listChatTheme() = 0; }; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index e48226673..53404b37b 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -559,6 +559,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { p, Ui::ComplexBubble{ .simple = Ui::SimpleBubble{ + .st = context.st, .geometry = g, .pattern = context.bubblesPattern, .patternViewport = context.viewport, diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index 99e21ed34..62eb30812 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -101,6 +101,14 @@ PinnedWidget::PinnedWidget( QString(), st::historyComposeButton)) , _scrollDown(_scroll.get(), st::historyToDown) { + Window::ChatThemeValueFromPeer( + controller, + history->peer + ) | rpl::start_with_next([=](std::shared_ptr &&theme) { + _theme = std::move(theme); + controller->setChatStyleTheme(_theme); + }, lifetime()); + _topBar->setActiveChat( TopBarWidget::ActiveChat{ .key = _history, @@ -457,11 +465,7 @@ void PinnedWidget::paintEvent(QPaintEvent *e) { const auto aboveHeight = _topBar->height(); const auto bg = e->rect().intersected( QRect(0, aboveHeight, width(), height() - aboveHeight)); - SectionWidget::PaintBackground( - controller(), - controller()->defaultChatTheme().get(), // #TODO themes - this, - bg); + SectionWidget::PaintBackground(controller(), _theme.get(), this, bg); } void PinnedWidget::onScroll() { @@ -654,6 +658,10 @@ void PinnedWidget::listSendBotCommand( void PinnedWidget::listHandleViaClick(not_null bot) { } +not_null PinnedWidget::listChatTheme() { + return _theme.get(); +} + void PinnedWidget::confirmDeleteSelected() { ConfirmDeleteSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index 9757935d1..9b8ce5fe9 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -102,6 +102,7 @@ public: const QString &command, const FullMsgId &context) override; void listHandleViaClick(not_null bot) override; + not_null listChatTheme() override; protected: void resizeEvent(QResizeEvent *e) override; @@ -145,6 +146,7 @@ private: void refreshClearButtonText(); const not_null _history; + std::shared_ptr _theme; PeerData *_migratedPeer = nullptr; QPointer _inner; object_ptr _topBar; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index fd3565701..77e146697 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -162,6 +162,14 @@ RepliesWidget::RepliesWidget( , _scroll(std::make_unique(this, st::historyScroll, false)) , _scrollDown(_scroll.get(), st::historyToDown) , _readRequestTimer([=] { sendReadTillRequest(); }) { + Window::ChatThemeValueFromPeer( + controller, + history->peer + ) | rpl::start_with_next([=](std::shared_ptr &&theme) { + _theme = std::move(theme); + controller->setChatStyleTheme(_theme); + }, lifetime()); + setupRoot(); setupRootView(); @@ -1511,11 +1519,7 @@ void RepliesWidget::paintEvent(QPaintEvent *e) { const auto aboveHeight = _topBar->height(); const auto bg = e->rect().intersected( QRect(0, aboveHeight, width(), height() - aboveHeight)); - SectionWidget::PaintBackground( - controller(), - controller()->defaultChatTheme().get(), // #TODO themes - this, - bg); + SectionWidget::PaintBackground(controller(), _theme.get(), this, bg); } void RepliesWidget::onScroll() { @@ -1786,6 +1790,10 @@ void RepliesWidget::listHandleViaClick(not_null bot) { _composeControls->setText({ '@' + bot->username + ' ' }); } +not_null RepliesWidget::listChatTheme() { + return _theme.get(); +} + void RepliesWidget::confirmDeleteSelected() { ConfirmDeleteSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index f56a511f4..0026c50c9 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -137,6 +137,7 @@ public: const QString &command, const FullMsgId &context) override; void listHandleViaClick(not_null bot) override; + not_null listChatTheme() override; protected: void resizeEvent(QResizeEvent *e) override; @@ -250,6 +251,7 @@ private: const not_null _history; const MsgId _rootId = 0; + std::shared_ptr _theme; HistoryItem *_root = nullptr; std::shared_ptr _replies; rpl::variable _areComments = false; diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index bed6a4ca8..5d18bfa6f 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -42,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/file_utilities.h" #include "main/main_session.h" #include "data/data_session.h" -#include "data/data_user.h" #include "data/data_scheduled_messages.h" #include "data/data_user.h" #include "storage/storage_media_prepare.h" @@ -101,6 +100,14 @@ ScheduledWidget::ScheduledWidget( ComposeControls::Mode::Scheduled, SendMenu::Type::Disabled)) , _scrollDown(_scroll, st::historyToDown) { + Window::ChatThemeValueFromPeer( + controller, + history->peer + ) | rpl::start_with_next([=](std::shared_ptr &&theme) { + _theme = std::move(theme); + controller->setChatStyleTheme(_theme); + }, lifetime()); + const auto state = Dialogs::EntryState{ .key = _history, .section = Dialogs::EntryState::Section::Scheduled, @@ -996,11 +1003,8 @@ void ScheduledWidget::paintEvent(QPaintEvent *e) { //auto ms = crl::now(); //_historyDownShown.step(ms); - SectionWidget::PaintBackground( - controller(), - controller()->defaultChatTheme().get(), // #TODO themes - this, - e->rect()); + const auto clip = e->rect(); + SectionWidget::PaintBackground(controller(), _theme.get(), this, clip); } void ScheduledWidget::onScroll() { @@ -1204,6 +1208,10 @@ void ScheduledWidget::listHandleViaClick(not_null bot) { _composeControls->setText({ '@' + bot->username + ' ' }); } +not_null ScheduledWidget::listChatTheme() { + return _theme.get(); +} + void ScheduledWidget::confirmSendNowSelected() { ConfirmSendNowSelectedItems(_inner); } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index ea3f92b5b..6bdd38cf4 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -118,6 +118,7 @@ public: const QString &command, const FullMsgId &context) override; void listHandleViaClick(not_null bot) override; + not_null listChatTheme() override; protected: void resizeEvent(QResizeEvent *e) override; @@ -206,6 +207,7 @@ private: Api::SendOptions options); const not_null _history; + std::shared_ptr _theme; object_ptr _scroll; QPointer _inner; object_ptr _topBar; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index 986dd1357..07a9fe5f5 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -78,12 +78,12 @@ static_assert(kDisplaySkipped != kTimeUnknown); return result; } const auto errors = std::fetestexcept(FE_ALL_EXCEPT); - LOG(("Streaming Error: Got NAN in std::round(%1), fe: %2." - ).arg(value - ).arg(errors)); if (const auto result = std::round(value); !std::isnan(result)) { return result; } + LOG(("Streaming Error: Got second NAN in std::round(%1), fe: %2." + ).arg(value + ).arg(errors)); std::feclearexcept(FE_ALL_EXCEPT); if (const auto result = std::round(value); !std::isnan(result)) { return result; diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index cc58ce4d3..5b7a08906 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_instance.h" #include "base/unixtime.h" #include "ui/chat/chat_theme.h" +#include "ui/chat/chat_style.h" #include "ui/widgets/checkbox.h" #include "ui/wrap/padding_wrap.h" #include "ui/wrap/vertical_layout.h" @@ -633,7 +634,9 @@ rpl::producer CallsPeer2PeerPrivacyController::exceptionsDescription() ForwardsPrivacyController::ForwardsPrivacyController( not_null controller) : SimpleElementDelegate(controller, [] {}) -, _controller(controller) { +, _controller(controller) +, _chatStyle(std::make_unique()) { + _chatStyle->apply(controller->defaultChatTheme().get()); } UserPrivacy::Key ForwardsPrivacyController::key() { @@ -715,13 +718,11 @@ object_ptr ForwardsPrivacyController::setupAboveWidget( rect); Painter p(widget); - const auto context = HistoryView::PaintContext{ - .st = style::main_palette::get(), - .bubblesPattern = nullptr, - .viewport = widget->rect(), - .clip = widget->rect(), - .now = crl::now(), - }; + const auto theme = _controller->defaultChatTheme().get(); + const auto context = theme->preparePaintContext( + _chatStyle.get(), + widget->rect(), + widget->rect()); p.translate(0, padding + view->marginBottom()); view->draw(p, context); diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.h b/Telegram/SourceFiles/settings/settings_privacy_controllers.h index ee2460ff7..d9028fa40 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.h +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.h @@ -16,6 +16,10 @@ namespace Window { class SessionController; } // namespace Window +namespace Ui { +class ChatStyle; +} // namespace Ui + namespace Settings { class BlockedBoxController : public PeerListController { @@ -193,6 +197,7 @@ private: Option value); const not_null _controller; + const std::unique_ptr _chatStyle; }; diff --git a/Telegram/SourceFiles/support/support_autocomplete.cpp b/Telegram/SourceFiles/support/support_autocomplete.cpp index f8a5a8bad..61ef97064 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.cpp +++ b/Telegram/SourceFiles/support/support_autocomplete.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "support/support_autocomplete.h" #include "ui/chat/chat_theme.h" +#include "ui/chat/chat_style.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/buttons.h" @@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "main/main_session_settings.h" #include "apiwrap.h" +#include "window/window_session_controller.h" #include "styles/style_chat_helpers.h" #include "styles/style_window.h" #include "styles/style_layers.h" @@ -502,9 +504,11 @@ ConfirmContactBox::ConfirmContactBox( const Contact &data, Fn submit) : SimpleElementDelegate(controller, [=] { update(); }) +, _chatStyle(std::make_unique()) , _comment(GenerateCommentItem(this, history, data)) , _contact(GenerateContactItem(this, history, data)) , _submit(submit) { + _chatStyle->apply(controller->defaultChatTheme().get()); } void ConfirmContactBox::prepare() { @@ -565,13 +569,11 @@ void ConfirmContactBox::paintEvent(QPaintEvent *e) { p.fillRect(e->rect(), st::boxBg); - const auto context = HistoryView::PaintContext{ - .st = style::main_palette::get(), - .bubblesPattern = nullptr, // #TODO bubbles - .viewport = rect(), - .clip = rect(), - .now = crl::now(), - }; + const auto theme = controller()->defaultChatTheme().get(); + const auto context = theme->preparePaintContext( + _chatStyle.get(), + rect(), + rect()); p.translate(st::boxPadding.left(), 0); if (_comment) { _comment->draw(p, context); diff --git a/Telegram/SourceFiles/support/support_autocomplete.h b/Telegram/SourceFiles/support/support_autocomplete.h index d2abc4671..5e85f9050 100644 --- a/Telegram/SourceFiles/support/support_autocomplete.h +++ b/Telegram/SourceFiles/support/support_autocomplete.h @@ -24,6 +24,7 @@ class SessionController; namespace Ui { class ScrollArea; class InputField; +class ChatStyle; } // namespace Ui namespace Support { @@ -83,6 +84,7 @@ protected: void keyPressEvent(QKeyEvent *e) override; private: + std::unique_ptr _chatStyle; AdminLog::OwnedItem _comment; AdminLog::OwnedItem _contact; Fn _submit; diff --git a/Telegram/SourceFiles/ui/cached_round_corners.cpp b/Telegram/SourceFiles/ui/cached_round_corners.cpp index 4637bea36..975c55ac7 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.cpp +++ b/Telegram/SourceFiles/ui/cached_round_corners.cpp @@ -18,19 +18,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { namespace { -struct CornersPixmaps { - QPixmap p[4]; -}; std::vector Corners; base::flat_map CornersMap; QImage CornersMaskLarge[4], CornersMaskSmall[4]; rpl::lifetime PaletteChangedLifetime; -void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr, QImage *cors = nullptr) { - Expects(Corners.size() > index); - +[[nodiscard]] std::array PrepareCorners(int32 radius, const QBrush &brush, const style::color *shadow = nullptr) { int32 r = radius * style::DevicePixelRatio(), s = st::msgShadow * style::DevicePixelRatio(); - QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied), localCors[4]; + QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied); { Painter p(&rect); PainterHighQualityEnabler hq(p); @@ -46,27 +41,31 @@ void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush, p.setBrush(brush); p.drawRoundedRect(0, 0, r * 3, r * 3, r, r); } - if (!cors) cors = localCors; - cors[0] = rect.copy(0, 0, r, r); - cors[1] = rect.copy(r * 2, 0, r, r); - cors[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0)); - cors[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); - if (index != SmallMaskCorners && index != LargeMaskCorners) { - for (int i = 0; i < 4; ++i) { - Corners[index].p[i] = PixmapFromImage(std::move(cors[i])); - Corners[index].p[i].setDevicePixelRatio(style::DevicePixelRatio()); - } + auto result = std::array(); + result[0] = rect.copy(0, 0, r, r); + result[1] = rect.copy(r * 2, 0, r, r); + result[2] = rect.copy(0, r * 2, r, r + (shadow ? s : 0)); + result[3] = rect.copy(r * 2, r * 2, r, r + (shadow ? s : 0)); + return result; +} + +void PrepareCorners(CachedRoundCorners index, int32 radius, const QBrush &brush, const style::color *shadow = nullptr) { + Expects(index < Corners.size()); + + auto images = PrepareCorners(radius, brush, shadow); + for (int i = 0; i < 4; ++i) { + Corners[index].p[i] = PixmapFromImage(std::move(images[i])); + Corners[index].p[i].setDevicePixelRatio(style::DevicePixelRatio()); } } void CreateMaskCorners() { - QImage mask[4]; - PrepareCorners(SmallMaskCorners, st::roundRadiusSmall, QColor(255, 255, 255), nullptr, mask); + auto mask = PrepareCorners(st::roundRadiusSmall, QColor(255, 255, 255), nullptr); for (int i = 0; i < 4; ++i) { CornersMaskSmall[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); CornersMaskSmall[i].setDevicePixelRatio(style::DevicePixelRatio()); } - PrepareCorners(LargeMaskCorners, st::historyMessageRadius, QColor(255, 255, 255), nullptr, mask); + mask = PrepareCorners(st::historyMessageRadius, QColor(255, 255, 255), nullptr); for (int i = 0; i < 4; ++i) { CornersMaskLarge[i] = mask[i].convertToFormat(QImage::Format_ARGB32_Premultiplied); CornersMaskLarge[i].setDevicePixelRatio(style::DevicePixelRatio()); @@ -231,23 +230,40 @@ void FillRoundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, style::colo } } -void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts) { - auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) | ((uint32(bg->c.red()) & 0xFF) << 16) | ((uint32(bg->c.green()) & 0xFF) << 8) | ((uint32(bg->c.blue()) & 0xFF) << 24); - auto i = CornersMap.find(colorKey); - if (i == CornersMap.cend()) { - QImage images[4]; - switch (radius) { - case ImageRoundRadius::Small: PrepareCorners(SmallMaskCorners, st::roundRadiusSmall, bg, nullptr, images); break; - case ImageRoundRadius::Large: PrepareCorners(LargeMaskCorners, st::historyMessageRadius, bg, nullptr, images); break; - default: p.fillRect(x, y, w, h, bg); return; - } +CornersPixmaps PrepareCornerPixmaps(int32 radius, style::color bg, const style::color *sh) { + auto images = PrepareCorners(radius, bg, sh); + auto result = CornersPixmaps(); + for (int j = 0; j < 4; ++j) { + result.p[j] = PixmapFromImage(std::move(images[j])); + result.p[j].setDevicePixelRatio(style::DevicePixelRatio()); + } + return result; +} - CornersPixmaps pixmaps; - for (int j = 0; j < 4; ++j) { - pixmaps.p[j] = PixmapFromImage(std::move(images[j])); - pixmaps.p[j].setDevicePixelRatio(style::DevicePixelRatio()); - } - i = CornersMap.emplace(colorKey, pixmaps).first; +CornersPixmaps PrepareCornerPixmaps(ImageRoundRadius radius, style::color bg, const style::color *sh) { + switch (radius) { + case ImageRoundRadius::Small: + return PrepareCornerPixmaps(st::roundRadiusSmall, bg, sh); + case ImageRoundRadius::Large: + return PrepareCornerPixmaps(st::historyMessageRadius, bg, sh); + } + Unexpected("Image round radius in PrepareCornerPixmaps."); +} + +void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts) { + if (radius == ImageRoundRadius::None) { + p.fillRect(x, y, w, h, bg); + return; + } + const auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) + | ((uint32(bg->c.red()) & 0xFF) << 16) + | ((uint32(bg->c.green()) & 0xFF) << 8) + | ((uint32(bg->c.blue()) & 0xFF)); + auto i = CornersMap.find(colorKey); + if (i == end(CornersMap)) { + i = CornersMap.emplace( + colorKey, + PrepareCornerPixmaps(radius, bg, nullptr)).first; } FillRoundRect(p, x, y, w, h, bg, i->second, nullptr, parts); } diff --git a/Telegram/SourceFiles/ui/cached_round_corners.h b/Telegram/SourceFiles/ui/cached_round_corners.h index 92e61df08..8ae588e43 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.h +++ b/Telegram/SourceFiles/ui/cached_round_corners.h @@ -15,10 +15,11 @@ enum class ImageRoundRadius; namespace Ui { -enum CachedRoundCorners : int { - SmallMaskCorners = 0x00, // for images - LargeMaskCorners, +struct CornersPixmaps { + QPixmap p[4]; +}; +enum CachedRoundCorners : int { BoxCorners, MenuCorners, BotKbOverCorners, @@ -69,6 +70,16 @@ inline void FillRoundRect(Painter &p, const QRect &rect, style::color bg, ImageR return FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts); } +[[nodiscard]] CornersPixmaps PrepareCornerPixmaps( + int32 radius, + style::color bg, + const style::color *sh); +[[nodiscard]] CornersPixmaps PrepareCornerPixmaps( + ImageRoundRadius radius, + style::color bg, + const style::color *sh); +void FillRoundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, const CornersPixmaps &corner, const style::color *shadow = nullptr, RectParts parts = RectPart::Full); + void StartCachedCorners(); void FinishCachedCorners(); diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp new file mode 100644 index 000000000..e0ce24371 --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -0,0 +1,125 @@ +/* +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 "ui/chat/chat_style.h" + +#include "ui/chat/chat_theme.h" +#include "styles/style_chat.h" + +namespace Ui { + +ChatStyle::ChatStyle() { + finalize(); + messageIcon( + &MessageStyle::tailLeft, + st::historyBubbleTailInLeft, + st::historyBubbleTailInLeftSelected, + st::historyBubbleTailOutLeft, + st::historyBubbleTailOutLeftSelected); + messageIcon( + &MessageStyle::tailRight, + st::historyBubbleTailInRight, + st::historyBubbleTailInRightSelected, + st::historyBubbleTailOutRight, + st::historyBubbleTailOutRightSelected); + messageColor( + &MessageStyle::msgBg, + msgInBg(), + msgInBgSelected(), + msgOutBg(), + msgOutBgSelected()); + messageColor( + &MessageStyle::msgShadow, + msgInShadow(), + msgInShadowSelected(), + msgOutShadow(), + msgOutShadowSelected()); +} + +void ChatStyle::apply(not_null theme) { + const auto themePalette = theme->palette(); + assignPalette(themePalette + ? themePalette + : style::main_palette::get().get()); + if (themePalette) { + _defaultPaletteChangeLifetime.destroy(); + } else { + style::PaletteChanged( + ) | rpl::start_with_next([=] { + assignPalette(style::main_palette::get()); + }, _defaultPaletteChangeLifetime); + } +} + +void ChatStyle::assignPalette(not_null palette) { + *static_cast(this) = *palette; + style::internal::resetIcons(); + for (auto &style : _messageStyles) { + style.corners = {}; + } +} + +const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const { + auto &result = messageStyleRaw(outbg, selected); + if (result.corners.p[0].isNull()) { + result.corners = Ui::PrepareCornerPixmaps( + st::historyMessageRadius, + result.msgBg, + &result.msgShadow); + } + return result; +} + +MessageStyle &ChatStyle::messageStyleRaw(bool outbg, bool selected) const { + return _messageStyles[(outbg ? 2 : 0) + (selected ? 1 : 0)]; +} + +void ChatStyle::icon(style::icon &my, const style::icon &original) { + my = original.withPalette(*this); +} + +MessageStyle &ChatStyle::messageIn() { + return messageStyleRaw(false, false); +} + +MessageStyle &ChatStyle::messageInSelected() { + return messageStyleRaw(false, true); +} + +MessageStyle &ChatStyle::messageOut() { + return messageStyleRaw(true, false); +} + +MessageStyle &ChatStyle::messageOutSelected() { + return messageStyleRaw(true, true); +} + +void ChatStyle::messageIcon( + style::icon MessageStyle::*my, + const style::icon &originalIn, + const style::icon &originalInSelected, + const style::icon &originalOut, + const style::icon &originalOutSelected) { + icon(messageIn().*my, originalIn); + icon(messageInSelected().*my, originalInSelected); + icon(messageOut().*my, originalOut); + icon(messageOutSelected().*my, originalOutSelected); +} + +void ChatStyle::messageColor( + style::color MessageStyle::*my, + const style::color &originalIn, + const style::color &originalInSelected, + const style::color &originalOut, + const style::color &originalOutSelected) { + messageIn().*my = originalIn; + messageInSelected().*my = originalInSelected; + messageOut().*my = originalOut; + messageOutSelected().*my = originalOutSelected; +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h new file mode 100644 index 000000000..259cae81c --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -0,0 +1,65 @@ +/* +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/cached_round_corners.h" + +namespace Ui { + +class ChatTheme; + +struct MessageStyle { + CornersPixmaps corners; + style::icon tailLeft = { Qt::Uninitialized }; + style::icon tailRight = { Qt::Uninitialized }; + style::color msgBg; + style::color msgShadow; +}; + +class ChatStyle final : public style::palette { +public: + ChatStyle(); + + void apply(not_null theme); + + [[nodiscard]] const MessageStyle &messageStyle( + bool outbg, + bool selected) const; + +private: + void assignPalette(not_null palette); + + void icon(style::icon &my, const style::icon &original); + + [[nodiscard]] MessageStyle &messageStyleRaw( + bool outbg, + bool selected) const; + [[nodiscard]] MessageStyle &messageIn(); + [[nodiscard]] MessageStyle &messageInSelected(); + [[nodiscard]] MessageStyle &messageOut(); + [[nodiscard]] MessageStyle &messageOutSelected(); + void messageIcon( + style::icon MessageStyle::*my, + const style::icon &originalIn, + const style::icon &originalInSelected, + const style::icon &originalOut, + const style::icon &originalOutSelected); + void messageColor( + style::color MessageStyle::*my, + const style::color &originalIn, + const style::color &originalInSelected, + const style::color &originalOut, + const style::color &originalOutSelected); + + mutable std::array _messageStyles; + + rpl::lifetime _defaultPaletteChangeLifetime; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.cpp b/Telegram/SourceFiles/ui/chat/chat_theme.cpp index 1fa03f2e0..62c5cac8d 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_theme.cpp @@ -30,6 +30,8 @@ constexpr auto kMaxSize = 2960; [[nodiscard]] CacheBackgroundResult CacheBackground( const CacheBackgroundRequest &request) { + Expects(!request.area.isEmpty()); + const auto gradient = request.background.gradientForFill.isNull() ? QImage() : (request.gradientRotationAdd != 0) @@ -69,12 +71,14 @@ constexpr auto kMaxSize = 2960; Qt::KeepAspectRatio, Qt::SmoothTransformation) : request.background.preparedForTiled; - const auto w = tiled.width() / style::DevicePixelRatio(); - const auto h = tiled.height() / style::DevicePixelRatio(); + const auto w = tiled.width() / float(style::DevicePixelRatio()); + const auto h = tiled.height() / float(style::DevicePixelRatio()); const auto cx = int(std::ceil(request.area.width() / w)); const auto cy = int(std::ceil(request.area.height() / h)); const auto rows = cy; - const auto cols = request.background.isPattern ? (((cx / 2) * 2) + 1) : cx; + const auto cols = request.background.isPattern + ? (((cx / 2) * 2) + 1) + : cx; const auto xshift = request.background.isPattern ? (request.area.width() - cols * w) / 2 : 0; @@ -202,13 +206,14 @@ void ChatTheme::setBubblesBackground(QImage image) { }); } if (!_bubblesBackgroundPattern) { - _bubblesBackgroundPattern = PrepareBubblePattern(); + _bubblesBackgroundPattern = PrepareBubblePattern(palette()); } _bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap; _repaintBackgroundRequests.fire({}); } ChatPaintContext ChatTheme::preparePaintContext( + not_null st, QRect viewport, QRect clip) { _bubblesBackground.area = viewport.size(); @@ -223,7 +228,7 @@ ChatPaintContext ChatTheme::preparePaintContext( // _bubblesBackgroundPattern->pixmap = _bubblesBackground.pixmap; //} return { - .st = _palette ? _palette.get() : style::main_palette::get(), + .st = st, .bubblesPattern = _bubblesBackgroundPattern.get(), .viewport = viewport, .clip = clip, @@ -240,6 +245,7 @@ const BackgroundState &ChatTheme::backgroundState(QSize area) { && !background().gradientForFill.isNull()) { // We don't support direct painting of patterned gradients. // So we need to sync-generate cache image here. + _willCacheForArea = area; setCachedBackground(CacheBackground(currentCacheRequest(area))); _cacheBackgroundTimer->cancel(); } else if (_backgroundState.now.area != area) { diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.h b/Telegram/SourceFiles/ui/chat/chat_theme.h index 3f91bfefb..dabf7d457 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.h +++ b/Telegram/SourceFiles/ui/chat/chat_theme.h @@ -13,10 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { +class ChatStyle; struct BubblePattern; struct ChatPaintContext { - not_null st; + not_null st; const BubblePattern *bubblesPattern = nullptr; QRect viewport; QRect clip; @@ -112,22 +113,23 @@ public: ChatTheme(ChatThemeDescriptor &&descriptor); [[nodiscard]] uint64 key() const; - [[nodiscard]] not_null palette() const { + [[nodiscard]] const style::palette *palette() const { return _palette.get(); } void setBackground(ChatThemeBackground &&background); void updateBackgroundImageFrom(ChatThemeBackground &&background); - const ChatThemeBackground &background() const { + [[nodiscard]] const ChatThemeBackground &background() const { return _mutableBackground; } void setBubblesBackground(QImage image); - const BubblePattern *bubblesBackgroundPattern() const { + [[nodiscard]] const BubblePattern *bubblesBackgroundPattern() const { return _bubblesBackgroundPattern.get(); } [[nodiscard]] ChatPaintContext preparePaintContext( + not_null st, QRect viewport, QRect clip); [[nodiscard]] const BackgroundState &backgroundState(QSize area); diff --git a/Telegram/SourceFiles/ui/chat/message_bubble.cpp b/Telegram/SourceFiles/ui/chat/message_bubble.cpp index 84bdf5cf0..91017bee7 100644 --- a/Telegram/SourceFiles/ui/chat/message_bubble.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bubble.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/cached_round_corners.h" #include "ui/image/image_prepare.h" +#include "ui/chat/chat_style.h" #include "styles/style_chat.h" namespace Ui { @@ -79,12 +80,10 @@ void PaintBubbleGeneric( } void PaintPatternBubble(Painter &p, const SimpleBubble &args) { - const auto opacity = st::msgOutBg->c.alphaF(); - const auto shadowOpacity = opacity * st::msgOutShadow->c.alphaF(); + const auto opacity = args.st->msgOutBg()->c.alphaF(); + const auto shadowOpacity = opacity * args.st->msgOutShadow()->c.alphaF(); const auto pattern = args.pattern; - const auto sh = (args.skip & RectPart::Bottom) - ? nullptr - : &st::msgOutShadow; + const auto sh = !(args.skip & RectPart::Bottom); const auto &tail = (args.tailSide == RectPart::Right) ? pattern->tailRight : pattern->tailLeft; @@ -221,30 +220,14 @@ void PaintPatternBubble(Painter &p, const SimpleBubble &args) { } void PaintSolidBubble(Painter &p, const SimpleBubble &args) { - const auto &bg = args.selected - ? (args.outbg ? st::msgOutBgSelected : st::msgInBgSelected) - : (args.outbg ? st::msgOutBg : st::msgInBg); + const auto &st = args.st->messageStyle(args.outbg, args.selected); + const auto &bg = st.msgBg; const auto sh = (args.skip & RectPart::Bottom) ? nullptr - : args.selected - ? &(args.outbg ? st::msgOutShadowSelected : st::msgInShadowSelected) - : &(args.outbg ? st::msgOutShadow : st::msgInShadow); - const auto corners = args.selected - ? (args.outbg - ? MessageOutSelectedCorners - : MessageInSelectedCorners) - : (args.outbg ? MessageOutCorners : MessageInCorners); + : &st.msgShadow; const auto &tail = (args.tailSide == RectPart::Right) - ? (args.selected - ? st::historyBubbleTailOutRightSelected - : st::historyBubbleTailOutRight) - : args.selected - ? (args.outbg - ? st::historyBubbleTailOutLeftSelected - : st::historyBubbleTailInLeftSelected) - : (args.outbg - ? st::historyBubbleTailOutLeft - : st::historyBubbleTailInLeft); + ? st.tailRight + : st.tailLeft; const auto tailShift = (args.tailSide == RectPart::Right) ? QPoint(0, tail.height()) : QPoint(tail.width(), tail.height()); @@ -253,7 +236,7 @@ void PaintSolidBubble(Painter &p, const SimpleBubble &args) { }, [&](const QRect &rect) { p.fillRect(rect, *sh); }, [&](const QRect &rect, RectParts parts) { - Ui::FillRoundRect(p, rect, bg, corners, sh, parts); + Ui::FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, st.corners, sh, parts); }, [&](const QPoint &bottomPosition) { tail.paint(p, bottomPosition - tailShift, args.outerWidth); return tail.width(); @@ -262,7 +245,8 @@ void PaintSolidBubble(Painter &p, const SimpleBubble &args) { } // namespace -std::unique_ptr PrepareBubblePattern() { +std::unique_ptr PrepareBubblePattern( + not_null st) { auto result = std::make_unique(); result->corners = Images::CornersMask(st::historyMessageRadius); const auto addShadow = [&](QImage &bottomCorner) { @@ -274,7 +258,7 @@ std::unique_ptr PrepareBubblePattern() { result.fill(Qt::transparent); result.setDevicePixelRatio(bottomCorner.devicePixelRatio()); auto p = QPainter(&result); - p.setOpacity(st::msgInShadow->c.alphaF()); + p.setOpacity(st->msgInShadow()->c.alphaF()); p.drawImage(0, st::msgShadow, bottomCorner); p.setOpacity(1.); p.drawImage(0, 0, bottomCorner); diff --git a/Telegram/SourceFiles/ui/chat/message_bubble.h b/Telegram/SourceFiles/ui/chat/message_bubble.h index 9bb851ba1..c7f8edb10 100644 --- a/Telegram/SourceFiles/ui/chat/message_bubble.h +++ b/Telegram/SourceFiles/ui/chat/message_bubble.h @@ -13,6 +13,9 @@ class Painter; namespace Ui { +class ChatTheme; +class ChatStyle; + struct BubbleSelectionInterval { int top = 0; int height = 0; @@ -28,9 +31,11 @@ struct BubblePattern { mutable QImage tailCache; }; -[[nodiscard]] std::unique_ptr PrepareBubblePattern(); +[[nodiscard]] std::unique_ptr PrepareBubblePattern( + not_null st); struct SimpleBubble { + not_null st; QRect geometry; const BubblePattern *pattern = nullptr; QRect patternViewport; diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index 9046a0bcf..885481ac7 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -61,22 +61,6 @@ namespace { }); } -[[nodiscard]] auto ChatThemeValueFromPeer( - not_null controller, - not_null peer) --> rpl::producer> { - return MaybeCloudThemeValueFromPeer( - peer - ) | rpl::map([=](std::optional theme) - -> rpl::producer> { - if (!theme) { - return rpl::single(controller->defaultChatTheme()); - } - return controller->cachedChatThemeValue(*theme); - }) | rpl::flatten_latest( - ) | rpl::distinct_until_changed(); -} - } // namespace AbstractSectionWidget::AbstractSectionWidget( @@ -298,4 +282,20 @@ rpl::producer SectionWidget::desiredHeight() const { SectionWidget::~SectionWidget() = default; +auto ChatThemeValueFromPeer( + not_null controller, + not_null peer) +-> rpl::producer> { + return MaybeCloudThemeValueFromPeer( + peer + ) | rpl::map([=](std::optional theme) + -> rpl::producer> { + if (!theme) { + return rpl::single(controller->defaultChatTheme()); + } + return controller->cachedChatThemeValue(*theme); + }) | rpl::flatten_latest( + ) | rpl::distinct_until_changed(); +} + } // namespace Window diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index 6bcbb5411..2ddb96016 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -203,4 +203,9 @@ private: }; +[[nodiscard]] auto ChatThemeValueFromPeer( + not_null controller, + not_null peer) +-> rpl::producer>; + } // namespace Window diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index b18212eb3..3367e1a9a 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_utilities.h" #include "ui/delayed_activation.h" #include "ui/chat/message_bubble.h" +#include "ui/chat/chat_style.h" #include "ui/chat/chat_theme.h" #include "ui/toast/toast.h" #include "ui/toasts/common_toasts.h" @@ -79,6 +80,7 @@ constexpr auto kMaxChatEntryHistorySize = 50; std::optional accent) { return [=](style::palette &palette) { using namespace Theme; + palette.finalize(); if (dark) { const auto &embedded = EmbeddedThemes(); const auto i = ranges::find( @@ -506,9 +508,13 @@ SessionController::SessionController( _window->widget(), this)) , _invitePeekTimer([=] { checkInvitePeek(); }) -, _defaultChatTheme(std::make_shared()) { +, _defaultChatTheme(std::make_shared()) +, _chatStyle(std::make_unique()) { init(); + _chatStyleTheme = _defaultChatTheme; + _chatStyle->apply(_defaultChatTheme.get()); + pushDefaultChatBackground(); Theme::Background()->updates( ) | rpl::start_with_next([=](const Theme::BackgroundUpdate &update) { @@ -1378,6 +1384,15 @@ auto SessionController::cachedChatThemeValue( }) | rpl::take(1)); } +void SessionController::setChatStyleTheme( + const std::shared_ptr &theme) { + if (_chatStyleTheme.lock() == theme) { + return; + } + _chatStyleTheme = theme; + _chatStyle->apply(theme.get()); +} + void SessionController::pushDefaultChatBackground() { const auto background = Theme::Background(); const auto &paper = background->paper(); @@ -1520,7 +1535,10 @@ HistoryView::PaintContext SessionController::preparePaintContext( args.visibleAreaTop - visibleAreaTopLocal, args.visibleAreaWidth, content()->height()); - return args.theme->preparePaintContext(viewport, args.clip); + return args.theme->preparePaintContext( + _chatStyle.get(), + viewport, + args.clip); } SessionController::~SessionController() { diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 082e880b7..8e20b4a51 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -45,6 +45,7 @@ class FormController; namespace Ui { class LayerWidget; enum class ReportReason; +class ChatStyle; class ChatTheme; struct ChatPaintContext; struct ChatThemeBackground; @@ -404,6 +405,7 @@ public: [[nodiscard]] auto cachedChatThemeValue( const Data::CloudTheme &data) -> rpl::producer>; + void setChatStyleTheme(const std::shared_ptr &theme); struct PaintContextArgs { not_null theme; @@ -484,6 +486,8 @@ private: std::shared_ptr _defaultChatTheme; base::flat_map _customChatThemes; rpl::event_stream> _cachedThemesStream; + std::unique_ptr _chatStyle; + std::weak_ptr _chatStyleTheme; rpl::lifetime _lifetime; diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 35a5f2c7d..c04e73fa9 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -135,6 +135,8 @@ PRIVATE ui/chat/attach/attach_single_file_preview.h ui/chat/attach/attach_single_media_preview.cpp ui/chat/attach/attach_single_media_preview.h + ui/chat/chat_style.cpp + ui/chat/chat_style.h ui/chat/chat_theme.cpp ui/chat/chat_theme.h ui/chat/group_call_bar.cpp diff --git a/Telegram/codegen b/Telegram/codegen index 13117d03e..62158ed79 160000 --- a/Telegram/codegen +++ b/Telegram/codegen @@ -1 +1 @@ -Subproject commit 13117d03e5683af00f898a330aa319fd17efe8f7 +Subproject commit 62158ed7955af3f7eabb1156075c1a41c4fff6b3 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 15ffd051d..3c95a9187 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 15ffd051d605be310051645412c54c2b9f87ff01 +Subproject commit 3c95a9187194c07fda409f1ad1e142232bb82cbc