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 9f48402eb..18fe7c92f 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -237,7 +237,10 @@ InnerWidget::InnerWidget( , _channel(channel) , _history(channel->owner().history(channel)) , _api(&_channel->session().mtp()) -, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); })) +, _pathGradient( + HistoryView::MakePathShiftGradient( + controller->chatStyle(), + [=] { update(); })) , _scrollDateCheck([=] { scrollDateCheck(); }) , _emptyText( st::historyAdminLogEmptyWidth @@ -906,8 +909,14 @@ void InnerWidget::paintEvent(QPaintEvent *e) { Painter p(this); auto clip = e->rect(); + auto context = _controller->preparePaintContext({ + .theme = _theme.get(), + .visibleAreaTop = _visibleTop, + .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), + .clip = clip, + }); if (_items.empty() && _upLoaded && _downLoaded) { - paintEmpty(p); + paintEmpty(p, context.st); } else { _pathGradient->startFrame( 0, @@ -923,12 +932,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { }); if (from != end) { auto top = itemTop(from->get()); - auto context = _controller->preparePaintContext({ - .theme = _theme.get(), - .visibleAreaTop = _visibleTop, - .visibleAreaTopGlobal = mapToGlobal(QPoint(0, _visibleTop)).y(), - .clip = clip, - }).translated(0, -top); + context.translate(0, -top); p.translate(0, top); for (auto i = from; i != to; ++i) { const auto view = i->get(); @@ -1000,10 +1004,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) { const auto chatWide = _controller->adaptive().isChatWide(); if (const auto date = view->Get()) { - date->paint(p, dateY, width, chatWide); + date->paint(p, context.st, dateY, width, chatWide); } else { - HistoryView::ServiceMessagePainter::paintDate( + HistoryView::ServiceMessagePainter::PaintDate( p, + context.st, view->dateTime(), dateY, width, @@ -1043,19 +1048,14 @@ auto InnerWidget::viewForItem(const HistoryItem *item) -> Element* { return nullptr; } -void InnerWidget::paintEmpty(Painter &p) { +void InnerWidget::paintEmpty(Painter &p, not_null st) { auto rectWidth = st::historyAdminLogEmptyWidth; auto innerWidth = rectWidth - st::historyAdminLogEmptyPadding.left() - st::historyAdminLogEmptyPadding.right(); auto rectHeight = st::historyAdminLogEmptyPadding.top() + _emptyText.countHeight(innerWidth) + st::historyAdminLogEmptyPadding.bottom(); auto rect = QRect((width() - rectWidth) / 2, (height() - rectHeight) / 3, rectWidth, rectHeight); - HistoryView::ServiceMessagePainter::paintBubble( - p, - rect.x(), - rect.y(), - rect.width(), - rect.height()); + HistoryView::ServiceMessagePainter::PaintBubble(p, st, rect); - p.setPen(st::msgServiceFg); + p.setPen(st->msgServiceFg()); _emptyText.draw(p, rect.x() + st::historyAdminLogEmptyPadding.left(), rect.y() + st::historyAdminLogEmptyPadding.top(), innerWidth, style::al_top); } 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 732bbcc80..ff11d6f04 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -36,6 +36,7 @@ enum class PointState : char; namespace Ui { class PopupMenu; +class ChatStyle; } // namespace Ui namespace Window { @@ -213,7 +214,7 @@ private: void updateSize(); void updateMinMaxIds(); void updateEmptyText(); - void paintEmpty(Painter &p); + void paintEmpty(Painter &p, not_null st); void clearAfterFilterChange(); void clearAndRequestLog(); void addEvents(Direction direction, const QVector &events); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 92f957c3e..ef1354868 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -159,7 +159,10 @@ HistoryInner::HistoryInner( , _peer(history->peer) , _history(history) , _migrated(history->migrateFrom()) -, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); })) +, _pathGradient( + HistoryView::MakePathShiftGradient( + controller->chatStyle(), + [=] { update(); })) , _scrollDateCheck([this] { scrollDateCheck(); }) , _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) { Instance = this; @@ -543,12 +546,16 @@ TextSelection HistoryInner::itemRenderSelection( return TextSelection(); } -void HistoryInner::paintEmpty(Painter &p, int width, int height) { +void HistoryInner::paintEmpty( + Painter &p, + not_null st, + int width, + int height) { if (!_emptyPainter) { _emptyPainter = std::make_unique( _history); } - _emptyPainter->paint(p, width, height); + _emptyPainter->paint(p, st, width, height); } void HistoryInner::paintEvent(QPaintEvent *e) { @@ -563,37 +570,47 @@ void HistoryInner::paintEvent(QPaintEvent *e) { _userpicsCache.clear(); }); + Painter p(this); + auto clip = e->rect(); + + const auto visibleAreaTopGlobal = mapToGlobal( + QPoint(0, _visibleAreaTop)).y(); + auto context = _controller->preparePaintContext({ + .theme = _theme.get(), + .visibleAreaTop = _visibleAreaTop, + .visibleAreaTopGlobal = visibleAreaTopGlobal, + .clip = clip, + }); _pathGradient->startFrame( 0, width(), std::min(st::msgMaxWidth / 2, width() / 2)); - Painter p(this); - auto clip = e->rect(); - const auto historyDisplayedEmpty = _history->isDisplayedEmpty() && (!_migrated || _migrated->isDisplayedEmpty()); bool noHistoryDisplayed = _firstLoading || historyDisplayedEmpty; if (!_firstLoading && _botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) { + const auto st = context.st; + const auto stm = &st->messageStyle(false, false); if (clip.y() < _botAbout->rect.y() + _botAbout->rect.height() && clip.y() + clip.height() > _botAbout->rect.y()) { - p.setTextPalette(st::inTextPalette); - Ui::FillRoundRect(p, _botAbout->rect, st::msgInBg, Ui::MessageInCorners, &st::msgInShadow); + p.setTextPalette(stm->textPalette); + Ui::FillRoundRect(p, _botAbout->rect, stm->msgBg, stm->corners, &stm->msgShadow); auto top = _botAbout->rect.top() + st::msgPadding.top(); if (!_history->peer->isRepliesChat()) { p.setFont(st::msgNameFont); - p.setPen(st::dialogsNameFg); + p.setPen(st->dialogsNameFg()); p.drawText(_botAbout->rect.left() + st::msgPadding.left(), top + st::msgNameFont->ascent, tr::lng_bot_description(tr::now)); top += +st::msgNameFont->height + st::botDescSkip; } - p.setPen(st::historyTextInFg); + p.setPen(stm->historyTextFg); _botAbout->info->text.draw(p, _botAbout->rect.left() + st::msgPadding.left(), top, _botAbout->width); p.restoreTextPalette(); } } else if (historyDisplayedEmpty) { - paintEmpty(p, width(), height()); + paintEmpty(p, context.st, width(), height()); } else { _emptyPainter = nullptr; } @@ -611,8 +628,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else { seltoy += _dragSelTo->height(); } - const auto visibleAreaTopGlobal = mapToGlobal( - QPoint(0, _visibleAreaTop)).y(); auto mtop = migratedTop(); auto htop = historyTop(); @@ -625,12 +640,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto item = view->data(); auto top = mtop + block->y() + view->y(); - auto context = _controller->preparePaintContext({ - .theme = _theme.get(), - .visibleAreaTop = _visibleAreaTop, - .visibleAreaTopGlobal = visibleAreaTopGlobal, - .clip = clip, - }).translated(0, -top); + context.translate(0, -top); p.translate(0, top); if (context.clip.y() < view->height()) while (top < drawToY) { context.outbg = view->hasOutLayout(); @@ -666,6 +676,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { item = view->data(); } p.translate(0, -top); + context.translate(0, top); } if (htop >= 0) { auto iBlock = (_curHistory == _history ? _curBlock : 0); @@ -675,15 +686,9 @@ void HistoryInner::paintEvent(QPaintEvent *e) { auto item = view->data(); auto readTill = (HistoryItem*)nullptr; auto top = htop + block->y() + view->y(); - auto context = _controller->preparePaintContext({ - .theme = _theme.get(), - .visibleAreaTop = _visibleAreaTop, - .visibleAreaTopGlobal = visibleAreaTopGlobal, - .visibleAreaWidth = width(), - .clip = clip.intersected( - QRect(0, hdrawtop, width(), clip.top() + clip.height()) - ), - }).translated(0, -top); + context.clip = clip.intersected( + QRect(0, hdrawtop, width(), clip.top() + clip.height())); + context.translate(0, -top); p.translate(0, top); while (top < drawToY) { const auto height = view->height(); @@ -812,10 +817,11 @@ void HistoryInner::paintEvent(QPaintEvent *e) { ? itemtop : (dateTop - st::msgServiceMargin.top()); if (const auto date = view->Get()) { - date->paint(p, dateY, _contentWidth, _isChatWide); + date->paint(p, context.st, dateY, _contentWidth, _isChatWide); } else { - HistoryView::ServiceMessagePainter::paintDate( + HistoryView::ServiceMessagePainter::PaintDate( p, + context.st, view->dateTime(), dateY, _contentWidth, diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index c3c72ca5c..483a694f6 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -35,6 +35,7 @@ class SessionController; namespace Ui { class ChatTheme; +class ChatStyle; class PopupMenu; enum class ReportReason; class PathShiftGradient; @@ -246,7 +247,11 @@ private: std::unique_ptr prepareDrag(); void performDrag(); - void paintEmpty(Painter &p, int width, int height); + void paintEmpty( + Painter &p, + not_null st, + int width, + int height); QPoint mapPointToItem(QPoint p, const Element *view) const; QPoint mapPointToItem(QPoint p, const HistoryItem *item) const; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 6810fcbc8..907eb243c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -107,6 +107,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/pinned_bar.h" #include "ui/chat/group_call_bar.h" #include "ui/chat/chat_theme.h" +#include "ui/chat/chat_style.h" #include "ui/widgets/popup_menu.h" #include "ui/item_text_options.h" #include "ui/unread_badge.h" @@ -7058,9 +7059,10 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { - st::msgServiceMargin.bottom()) / 2, w, h); - HistoryView::ServiceMessagePainter::paintBubble(p, tr.x(), tr.y(), tr.width(), tr.height()); + const auto st = controller()->chatStyle(); + HistoryView::ServiceMessagePainter::PaintBubble(p, st, tr); - p.setPen(st::msgServiceFg); + p.setPen(st->msgServiceFg()); p.setFont(st::msgServiceFont->f); p.drawTextLeft(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top(), width(), tr::lng_willbe_history(tr::now)); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 3678ac8a5..c8af38808 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -23,13 +23,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_emoji_pack.h" #include "window/window_session_controller.h" #include "ui/effects/path_shift_gradient.h" +#include "ui/chat/chat_style.h" #include "ui/toast/toast.h" #include "ui/toasts/common_toasts.h" #include "data/data_session.h" #include "data/data_groups.h" #include "data/data_media_types.h" #include "lang/lang_keys.h" -#include "layout/layout_selection.h" #include "app.h" #include "styles/style_chat.h" @@ -62,10 +62,11 @@ bool IsAttachedToPreviousInSavedMessages( } // namespace std::unique_ptr MakePathShiftGradient( + not_null st, Fn update) { return std::make_unique( - st::msgServiceBg, - st::msgServiceBgSelected, + st->msgServiceBg(), + st->msgServiceBgSelected(), std::move(update)); } @@ -73,7 +74,10 @@ SimpleElementDelegate::SimpleElementDelegate( not_null controller, Fn update) : _controller(controller) -, _pathGradient(MakePathShiftGradient(std::move(update))) { +, _pathGradient( + MakePathShiftGradient( + controller->chatStyle(), + std::move(update))) { } SimpleElementDelegate::~SimpleElementDelegate() = default; @@ -259,7 +263,13 @@ int UnreadBar::marginTop() { return st::lineWidth + st::historyUnreadBarMargin; } -void UnreadBar::paint(Painter &p, int y, int w, bool chatWide) const { +void UnreadBar::paint( + Painter &p, + const PaintContext &context, + int y, + int w, + bool chatWide) const { + const auto st = context.st; const auto bottom = y + height(); y += marginTop(); p.fillRect( @@ -267,15 +277,15 @@ void UnreadBar::paint(Painter &p, int y, int w, bool chatWide) const { y, w, height() - marginTop() - st::lineWidth, - st::historyUnreadBarBg); + st->historyUnreadBarBg()); p.fillRect( 0, bottom - st::lineWidth, w, st::lineWidth, - st::historyUnreadBarBorder); + st->historyUnreadBarBorder()); p.setFont(st::historyUnreadBarFont); - p.setPen(st::historyUnreadBarFg); + p.setPen(st->historyUnreadBarFg()); int maxwidth = w; if (chatWide) { @@ -310,8 +320,13 @@ int DateBadge::height() const { + st::msgServiceMargin.bottom(); } -void DateBadge::paint(Painter &p, int y, int w, bool chatWide) const { - ServiceMessagePainter::paintDate(p, text, width, y, w, chatWide); +void DateBadge::paint( + Painter &p, + not_null st, + int y, + int w, + bool chatWide) const { + ServiceMessagePainter::PaintDate(p, st, text, width, y, w, chatWide); } Element::Element( @@ -367,6 +382,7 @@ void Element::refreshDataIdHook() { void Element::paintHighlight( Painter &p, + const PaintContext &context, int geometryHeight) const { const auto top = marginTop(); const auto bottom = marginBottom(); @@ -374,7 +390,7 @@ void Element::paintHighlight( const auto skiptop = top - fill; const auto fillheight = fill + geometryHeight + fill; - paintCustomHighlight(p, skiptop, fillheight, data()); + paintCustomHighlight(p, context, skiptop, fillheight, data()); } float64 Element::highlightOpacity(not_null item) const { @@ -392,6 +408,7 @@ float64 Element::highlightOpacity(not_null item) const { void Element::paintCustomHighlight( Painter &p, + const PaintContext &context, int y, int height, not_null item) const { @@ -406,7 +423,7 @@ void Element::paintCustomHighlight( y, width(), height, - st::defaultTextPalette.selectOverlay); + context.st->msgSelectOverlay()); p.setOpacity(o); } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 470d1f244..081a4cbfb 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -26,6 +26,7 @@ namespace Ui { class PathShiftGradient; struct BubblePattern; struct ChatPaintContext; +class ChatStyle; } // namespace Ui namespace HistoryView { @@ -36,6 +37,8 @@ struct StateRequest; struct TextState; class Media; +using PaintContext = Ui::ChatPaintContext; + enum class Context : char { History, Replies, @@ -94,6 +97,7 @@ public: }; [[nodiscard]] std::unique_ptr MakePathShiftGradient( + not_null st, Fn update); class SimpleElementDelegate : public ElementDelegate { @@ -177,7 +181,12 @@ struct UnreadBar : public RuntimeComponent { static int height(); static int marginTop(); - void paint(Painter &p, int y, int w, bool chatWide) const; + void paint( + Painter &p, + const PaintContext &context, + int y, + int w, + bool chatWide) const; QString text; int width = 0; @@ -191,15 +200,18 @@ struct DateBadge : public RuntimeComponent { void init(const QString &date); int height() const; - void paint(Painter &p, int y, int w, bool chatWide) const; + void paint( + Painter &p, + not_null st, + int y, + int w, + bool chatWide) const; QString text; int width = 0; }; -using PaintContext = Ui::ChatPaintContext; - class Element : public Object , public RuntimeComposer @@ -347,6 +359,7 @@ public: void paintCustomHighlight( Painter &p, + const PaintContext &context, int y, int height, not_null item) const; @@ -376,6 +389,7 @@ public: protected: void paintHighlight( Painter &p, + const PaintContext &context, int geometryHeight) const; [[nodiscard]] ClickHandlerPtr fromLink() const; diff --git a/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.cpp b/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.cpp index 5e189791b..b1668f529 100644 --- a/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.cpp +++ b/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.cpp @@ -7,17 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/view/history_view_empty_list_bubble.h" -#include "history/view/history_view_list_widget.h" +#include "ui/chat/chat_style.h" #include "history/view/history_view_service_message.h" namespace HistoryView { EmptyListBubbleWidget::EmptyListBubbleWidget( - not_null parent, + not_null parent, + not_null st, const style::margins &padding) : RpWidget(parent) -, _padding(padding) { - +, _padding(padding) +, _st(st) { parent->sizeValue( ) | rpl::start_with_next([=](const QSize &s) { updateGeometry(s); @@ -42,14 +43,9 @@ void EmptyListBubbleWidget::paintEvent(QPaintEvent *e) { Painter p(this); const auto r = rect(); - HistoryView::ServiceMessagePainter::paintBubble( - p, - r.x(), - r.y(), - r.width(), - r.height()); + HistoryView::ServiceMessagePainter::PaintBubble(p, _st, r); - p.setPen(st::msgServiceFg); + p.setPen(_st->msgServiceFg()); _text.draw( p, r.x() + _padding.left(), diff --git a/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.h b/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.h index 9a789b828..4488f52b7 100644 --- a/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.h +++ b/Telegram/SourceFiles/history/view/history_view_empty_list_bubble.h @@ -9,14 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" -namespace HistoryView { +namespace Ui { +class ChatStyle; +} // namespace Ui -class ListWidget; +namespace HistoryView { class EmptyListBubbleWidget : public Ui::RpWidget { public: EmptyListBubbleWidget( - not_null parent, + not_null parent, + not_null st, const style::margins &padding); void setText(const TextWithEntities &textWithEntities); @@ -29,6 +32,7 @@ private: void updateGeometry(const QSize &size); const style::margins &_padding; + const not_null _st; Ui::Text::String _text; int _innerWidth = 0; int _forceWidth = 0; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 051b83477..7a629d9c2 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -256,7 +256,10 @@ ListWidget::ListWidget( , _controller(controller) , _context(_delegate->listContext()) , _itemAverageHeight(itemMinimalHeight()) -, _pathGradient(MakePathShiftGradient([=] { update(); })) +, _pathGradient( + MakePathShiftGradient( + controller->chatStyle(), + [=] { update(); })) , _scrollDateCheck([this] { scrollDateCheck(); }) , _applyUpdatedScrollState([this] { applyUpdatedScrollState(); }) , _selectEnabled(_delegate->listAllowsMultiSelect()) @@ -1700,11 +1703,14 @@ void ListWidget::paintEvent(QPaintEvent *e) { int dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top()); int width = view->width(); if (const auto date = view->Get()) { - date->paint(p, dateY, width, _isChatWide); + date->paint(p, context.st, dateY, width, _isChatWide); } else { - ServiceMessagePainter::paintDate( + ServiceMessagePainter::PaintDate( p, - ItemDateText(view->data(), IsItemScheduledUntilOnline(view->data())), + context.st, + ItemDateText( + view->data(), + IsItemScheduledUntilOnline(view->data())), dateY, width, _isChatWide); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 58fdbe172..904d21a21 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -498,7 +498,12 @@ void Message::draw(Painter &p, const PaintContext &context) const { auto unreadbarh = bar->height(); if (context.clip.intersects(QRect(0, dateh, width(), unreadbarh))) { p.translate(0, dateh); - bar->paint(p, 0, width(), delegate()->elementIsChatWide()); + bar->paint( + p, + context, + 0, + width(), + delegate()->elementIsChatWide()); p.translate(0, -dateh); } } @@ -537,9 +542,9 @@ void Message::draw(Painter &p, const PaintContext &context) const { } if (customHighlight) { - media->drawHighlight(p, localMediaTop); + media->drawHighlight(p, context, localMediaTop); } else { - paintHighlight(p, g.height()); + paintHighlight(p, context, g.height()); } const auto roll = media ? media->bubbleRoll() : Media::BubbleRoll(); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 5d18bfa6f..c37f757b1 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -163,6 +163,7 @@ ScheduledWidget::ScheduledWidget( { auto emptyInfo = base::make_unique_q( _inner, + controller->chatStyle(), st::msgServicePadding); const auto emptyText = Ui::Text::Semibold( tr::lng_scheduled_messages_empty(tr::now)); diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index 4987adcb8..df4200119 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -41,98 +41,6 @@ enum CornerHorizontalSide { CornerRight = 0x01, }; -class ServiceMessageStyleData : public Data::AbstractStructure { -public: - ServiceMessageStyleData() { - style::PaletteChanged( - ) | rpl::start_with_next([=] { - for (auto &corner : corners) { - corner = QPixmap(); - } - }, _lifetime); - } - - // circle[CircleMask value] - QImage circle[2]; - - // corners[(CircleMask value) * MaskMultiplier | (CornerVerticalSide value) | (CornerHorizontalSide value)] - QPixmap corners[8]; - - base::flat_map, QPixmap> overridenCorners; - -private: - rpl::lifetime _lifetime; - -}; -Data::GlobalStructurePointer serviceMessageStyle; - -int historyServiceMsgRadius() { - static int HistoryServiceMsgRadius = ([]() { - auto minMsgHeight = (st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom()); - return minMsgHeight / 2; - })(); - return HistoryServiceMsgRadius; -} - -int historyServiceMsgInvertedRadius() { - static int HistoryServiceMsgInvertedRadius = ([]() { - auto minRowHeight = st::msgServiceFont->height; - return minRowHeight - historyServiceMsgRadius(); - })(); - return HistoryServiceMsgInvertedRadius; -} - -int historyServiceMsgInvertedShrink() { - static int HistoryServiceMsgInvertedShrink = ([]() { - return (historyServiceMsgInvertedRadius() * 2) / 3; - })(); - return HistoryServiceMsgInvertedShrink; -} - -void createCircleMasks() { - serviceMessageStyle.createIfNull(); - if (!serviceMessageStyle->circle[NormalMask].isNull()) return; - - int size = historyServiceMsgRadius() * 2; - serviceMessageStyle->circle[NormalMask] = style::createCircleMask(size); - int sizeInverted = historyServiceMsgInvertedRadius() * 2; - serviceMessageStyle->circle[InvertedMask] = style::createInvertedCircleMask(sizeInverted); -} - -uint32 ColorToUint(const style::color &bg) { - const auto &c = bg->c; - return c.red() << 24 | c.green() << 16 | c.blue() << 8 | c.alpha(); -} - -QPixmap circleCorner(int corner, const style::color &bg) { - auto ¤tCorner = (bg == st::msgServiceBg) - ? serviceMessageStyle->corners[corner] - : serviceMessageStyle->overridenCorners[{ corner, ColorToUint(bg) }]; - if (currentCorner.isNull()) { - int maskType = corner / MaskMultiplier; - int radius = (maskType == NormalMask - ? historyServiceMsgRadius() - : historyServiceMsgInvertedRadius()); - int size = radius * cIntRetinaFactor(); - - int xoffset = 0, yoffset = 0; - if (corner & CornerRight) { - xoffset = size; - } - if (corner & CornerBottom) { - yoffset = size; - } - auto part = QRect(xoffset, yoffset, size, size); - auto result = style::colorizeImage( - serviceMessageStyle->circle[maskType], - bg, - part); - result.setDevicePixelRatio(cRetinaFactor()); - currentCorner = Ui::PixmapFromImage(std::move(result)); - } - return currentCorner; -} - enum class SideStyle { Rounded, Plain, @@ -140,96 +48,97 @@ enum class SideStyle { }; // Returns amount of pixels already painted vertically (so you can skip them in the complex rect shape). -int paintBubbleSide( +int PaintBubbleSide( Painter &p, + not_null st, int x, int y, int width, SideStyle style, - CornerVerticalSide side, - const style::color &bg) { + CornerVerticalSide side) { if (style == SideStyle::Rounded) { - const auto corner = (int(NormalMask) * MaskMultiplier) | side; - auto left = circleCorner(corner | CornerLeft, bg); - int leftWidth = left.width() / cIntRetinaFactor(); + const auto &corners = st->serviceBgCornersNormal(); + const auto left = corners.p[(side == CornerTop) ? 0 : 2]; + const auto leftWidth = left.width() / cIntRetinaFactor(); p.drawPixmap(x, y, left); - auto right = circleCorner(corner | CornerRight, bg); - int rightWidth = right.width() / cIntRetinaFactor(); + const auto right = corners.p[(side == CornerTop) ? 1 : 3]; + const auto rightWidth = right.width() / cIntRetinaFactor(); p.drawPixmap(x + width - rightWidth, y, right); - int cornerHeight = left.height() / cIntRetinaFactor(); + const auto cornerHeight = left.height() / cIntRetinaFactor(); p.fillRect( x + leftWidth, y, width - leftWidth - rightWidth, cornerHeight, - bg); + st->msgServiceBg()); return cornerHeight; } else if (style == SideStyle::Inverted) { - // CornerLeft and CornerRight are inverted for SideStyle::Inverted sprites. - const auto corner = (int(InvertedMask) * MaskMultiplier) | side; - auto left = circleCorner(corner | CornerRight, bg); - int leftWidth = left.width() / cIntRetinaFactor(); + // CornerLeft and CornerRight are inverted in the top part. + const auto &corners = st->serviceBgCornersInverted(); + const auto left = corners.p[(side == CornerTop) ? 1 : 2]; + const auto leftWidth = left.width() / cIntRetinaFactor(); p.drawPixmap(x - leftWidth, y, left); - auto right = circleCorner(corner | CornerLeft, bg); + const auto right = corners.p[(side == CornerTop) ? 0 : 3]; p.drawPixmap(x + width, y, right); } return 0; } -void paintBubblePart( +void PaintBubblePart( Painter &p, + not_null st, int x, int y, int width, int height, SideStyle topStyle, SideStyle bottomStyle, - const style::color &bg, bool forceShrink = false) { if ((topStyle == SideStyle::Inverted) || (bottomStyle == SideStyle::Inverted) || forceShrink) { - width -= historyServiceMsgInvertedShrink() * 2; - x += historyServiceMsgInvertedShrink(); + width -= Ui::HistoryServiceMsgInvertedShrink() * 2; + x += Ui::HistoryServiceMsgInvertedShrink(); } - if (int skip = paintBubbleSide(p, x, y, width, topStyle, CornerTop, bg)) { + if (int skip = PaintBubbleSide(p, st, x, y, width, topStyle, CornerTop)) { y += skip; height -= skip; } int bottomSize = 0; if (bottomStyle == SideStyle::Rounded) { - bottomSize = historyServiceMsgRadius(); + bottomSize = Ui::HistoryServiceMsgRadius(); } else if (bottomStyle == SideStyle::Inverted) { - bottomSize = historyServiceMsgInvertedRadius(); + bottomSize = Ui::HistoryServiceMsgInvertedRadius(); } - const auto skip = paintBubbleSide( + const auto skip = PaintBubbleSide( p, + st, x, y + height - bottomSize, width, bottomStyle, - CornerBottom, - bg); + CornerBottom); if (skip) { height -= skip; } - p.fillRect(x, y, width, height, bg); + p.fillRect(x, y, width, height, st->msgServiceBg()); } -void paintPreparedDate( +void PaintPreparedDate( Painter &p, + const style::color &bg, + const Ui::CornersPixmaps &corners, + const style::color &fg, const QString &dateText, int dateTextWidth, int y, int w, - bool chatWide, - const style::color &bg, - const style::color &fg) { + bool chatWide) { int left = st::msgServiceMargin.left(); const auto maxwidth = chatWide ? std::min(w, WideChatWidth()) @@ -238,19 +147,27 @@ void paintPreparedDate( left += (w - dateTextWidth - st::msgServicePadding.left() - st::msgServicePadding.right()) / 2; int height = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom(); - ServiceMessagePainter::paintBubble( + ServiceMessagePainter::PaintBubble( p, - left, - y + st::msgServiceMargin.top(), - dateTextWidth - + st::msgServicePadding.left() - + st::msgServicePadding.left(), - height, - bg); + bg, + corners, + QRect( + left, + y + st::msgServiceMargin.top(), + dateTextWidth + + st::msgServicePadding.left() + + st::msgServicePadding.left(), + height)); p.setFont(st::msgServiceFont); p.setPen(fg); - p.drawText(left + st::msgServicePadding.left(), y + st::msgServiceMargin.top() + st::msgServicePadding.top() + st::msgServiceFont->ascent, dateText); + p.drawText( + left + st::msgServicePadding.left(), + (y + + st::msgServiceMargin.top() + + st::msgServicePadding.top() + + st::msgServiceFont->ascent), + dateText); } bool NeedAboutGroup(not_null history) { @@ -268,88 +185,112 @@ int WideChatWidth() { return st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left(); } -void ServiceMessagePainter::paintDate( +void ServiceMessagePainter::PaintDate( Painter &p, + not_null st, const QDateTime &date, int y, int w, - bool chatWide, - const style::color &bg, - const style::color &fg) { - const auto dateText = langDayOfMonthFull(date.date()); - const auto dateTextWidth = st::msgServiceFont->width(dateText); - paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg); + bool chatWide) { + PaintDate( + p, + st, + langDayOfMonthFull(date.date()), + y, + w, + chatWide); } -void ServiceMessagePainter::paintDate( +void ServiceMessagePainter::PaintDate( Painter &p, + not_null st, const QString &dateText, int y, int w, - bool chatWide, - const style::color &bg, - const style::color &fg) { - paintPreparedDate( + bool chatWide) { + PaintDate( p, + st, dateText, st::msgServiceFont->width(dateText), y, w, - chatWide, - bg, - fg); + chatWide); } -void ServiceMessagePainter::paintDate( +void ServiceMessagePainter::PaintDate( Painter &p, + not_null st, const QString &dateText, int dateTextWidth, int y, int w, - bool chatWide, - const style::color &bg, - const style::color &fg) { - paintPreparedDate(p, dateText, dateTextWidth, y, w, chatWide, bg, fg); -} - -void ServiceMessagePainter::paintBubble( - Painter &p, - int x, - int y, - int w, - int h, - const style::color &bg) { - createCircleMasks(); - - paintBubblePart( + bool chatWide) { + PaintPreparedDate( p, - x, + st->msgServiceBg(), + st->serviceBgCornersNormal(), + st->msgServiceFg(), + dateText, + dateTextWidth, y, w, - h, - SideStyle::Rounded, - SideStyle::Rounded, - bg); + chatWide); } -void ServiceMessagePainter::paintComplexBubble( +void ServiceMessagePainter::PaintDate( Painter &p, + const style::color &bg, + const Ui::CornersPixmaps &corners, + const style::color &fg, + const QString &dateText, + int dateTextWidth, + int y, + int w, + bool chatWide) { + PaintPreparedDate( + p, + bg, + corners, + fg, + dateText, + dateTextWidth, + y, + w, + chatWide); +} + +void ServiceMessagePainter::PaintBubble( + Painter &p, + not_null st, + QRect rect) { + PaintBubble(p, st->msgServiceBg(), st->serviceBgCornersNormal(), rect); +} + +void ServiceMessagePainter::PaintBubble( + Painter &p, + const style::color &bg, + const Ui::CornersPixmaps &corners, + QRect rect) { + Ui::FillRoundRect(p, rect, bg, corners); +} + +void ServiceMessagePainter::PaintComplexBubble( + Painter &p, + not_null st, int left, int width, const Ui::Text::String &text, - const QRect &textRect, - const style::color &bg) { - createCircleMasks(); - - auto lineWidths = countLineWidths(text, textRect); + const QRect &textRect) { + const auto lineWidths = CountLineWidths(text, textRect); int y = st::msgServiceMargin.top(), previousRichWidth = 0; bool previousShrink = false, forceShrink = false; SideStyle topStyle = SideStyle::Rounded, bottomStyle; for (int i = 0, count = lineWidths.size(); i < count; ++i) { - auto lineWidth = lineWidths.at(i); + const auto lineWidth = lineWidths[i]; if (i + 1 < count) { - auto nextLineWidth = lineWidths.at(i + 1); + const auto nextLineWidth = lineWidths[i + 1]; if (nextLineWidth > lineWidth) { bottomStyle = SideStyle::Inverted; } else if (nextLineWidth < lineWidth) { @@ -374,15 +315,15 @@ void ServiceMessagePainter::paintComplexBubble( richHeight -= st::msgServicePadding.top(); } forceShrink = previousShrink && (richWidth == previousRichWidth); - paintBubblePart( + PaintBubblePart( p, + st, left + ((width - richWidth) / 2), y, richWidth, richHeight, topStyle, bottomStyle, - bg, forceShrink); y += richHeight; @@ -399,38 +340,46 @@ void ServiceMessagePainter::paintComplexBubble( } } -QVector ServiceMessagePainter::countLineWidths(const Ui::Text::String &text, const QRect &textRect) { - int linesCount = qMax(textRect.height() / st::msgServiceFont->height, 1); - QVector lineWidths; - lineWidths.reserve(linesCount); - text.countLineWidths(textRect.width(), &lineWidths); +QVector ServiceMessagePainter::CountLineWidths( + const Ui::Text::String &text, + const QRect &textRect) { + const auto linesCount = qMax( + textRect.height() / st::msgServiceFont->height, + 1); + auto result = QVector(); + result.reserve(linesCount); + text.countLineWidths(textRect.width(), &result); - int minDelta = 2 * (historyServiceMsgRadius() + historyServiceMsgInvertedRadius() - historyServiceMsgInvertedShrink()); - for (int i = 0, count = lineWidths.size(); i < count; ++i) { - int width = qMax(lineWidths.at(i), 0); + const auto minDelta = 2 * (Ui::HistoryServiceMsgRadius() + + Ui::HistoryServiceMsgInvertedRadius() + - Ui::HistoryServiceMsgInvertedShrink()); + for (int i = 0, count = result.size(); i != count; ++i) { + auto width = qMax(result[i], 0); if (i > 0) { - int widthBefore = lineWidths.at(i - 1); + const auto widthBefore = result[i - 1]; if (width < widthBefore && width + minDelta > widthBefore) { width = widthBefore; } } if (i + 1 < count) { - int widthAfter = lineWidths.at(i + 1); + const auto widthAfter = result[i + 1]; if (width < widthAfter && width + minDelta > widthAfter) { width = widthAfter; } } - if (width > lineWidths.at(i)) { - lineWidths[i] = width; + if (width > result[i]) { + result[i] = width; if (i > 0) { - int widthBefore = lineWidths.at(i - 1); - if (widthBefore != width && widthBefore < width + minDelta && widthBefore + minDelta > width) { + int widthBefore = result[i - 1]; + if (widthBefore != width + && widthBefore < width + minDelta + && widthBefore + minDelta > width) { i -= 2; } } } } - return lineWidths; + return result; } Service::Service( @@ -527,7 +476,10 @@ void Service::draw(Painter &p, const PaintContext &context) const { return; } - auto height = this->height() - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); + const auto st = context.st; + auto height = this->height() + - st::msgServiceMargin.top() + - st::msgServiceMargin.bottom(); auto dateh = 0; auto unreadbarh = 0; auto clip = context.clip; @@ -540,7 +492,12 @@ void Service::draw(Painter &p, const PaintContext &context) const { if (const auto bar = Get()) { unreadbarh = bar->height(); if (clip.intersects(QRect(0, 0, width(), unreadbarh))) { - bar->paint(p, 0, width(), delegate()->elementIsChatWide()); + bar->paint( + p, + context, + 0, + width(), + delegate()->elementIsChatWide()); } p.translate(0, unreadbarh); clip.translate(0, -unreadbarh); @@ -554,9 +511,9 @@ void Service::draw(Painter &p, const PaintContext &context) const { return; } - paintHighlight(p, height); + paintHighlight(p, context, height); - p.setTextPalette(st::serviceTextPalette); + p.setTextPalette(st->serviceTextPalette()); if (auto media = this->media()) { height -= st::msgServiceMargin.top() + media->height(); @@ -568,10 +525,16 @@ void Service::draw(Painter &p, const PaintContext &context) const { auto trect = QRect(g.left(), st::msgServiceMargin.top(), g.width(), height).marginsAdded(-st::msgServicePadding); - ServiceMessagePainter::paintComplexBubble(p, g.left(), g.width(), item->_text, trect); + ServiceMessagePainter::PaintComplexBubble( + p, + context.st, + g.left(), + g.width(), + item->_text, + trect); p.setBrush(Qt::NoBrush); - p.setPen(st::msgServiceFg); + p.setPen(st->msgServiceFg()); p.setFont(st::msgServiceFont); item->_text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, context.selection, false); @@ -694,7 +657,11 @@ void EmptyPainter::fillAboutGroup() { } } -void EmptyPainter::paint(Painter &p, int width, int height) { +void EmptyPainter::paint( + Painter &p, + not_null st, + int width, + int height) { if (_phrases.empty()) { return; } @@ -731,15 +698,14 @@ void EmptyPainter::paint(Painter &p, int width, int height) { const auto bubbleLeft = (width - bubbleWidth) / 2; const auto bubbleTop = (height - bubbleHeight) / 2; - ServiceMessagePainter::paintBubble( + ServiceMessagePainter::PaintBubble( p, - bubbleLeft, - bubbleTop, - bubbleWidth, - bubbleHeight); + st->msgServiceBg(), + st->serviceBgCornersNormal(), + QRect(bubbleLeft, bubbleTop, bubbleWidth, bubbleHeight)); - p.setPen(st::msgServiceFg); - p.setBrush(st::msgServiceFg); + p.setPen(st->msgServiceFg()); + p.setBrush(st->msgServiceFg()); const auto left = bubbleLeft + padding.left(); auto top = bubbleTop + padding.top(); @@ -762,7 +728,7 @@ void EmptyPainter::paint(Painter &p, int width, int height) { top += textHeight(_text) + st::historyGroupAboutTextSkip; for (const auto &text : _phrases) { - p.setPen(st::msgServiceFg); + p.setPen(st->msgServiceFg()); text.drawElided( p, left + st::historyGroupAboutBulletSkip, diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index 4d26eecb7..b620dee66 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class HistoryService; +namespace Ui { +class ChatStyle; +struct CornersPixmaps; +} // namespace Ui + namespace HistoryView { class Service : public Element { @@ -48,50 +53,61 @@ int WideChatWidth(); class ServiceMessagePainter { public: - static void paintDate( + static void PaintDate( Painter &p, + not_null st, const QDateTime &date, int y, int w, - bool chatWide, - const style::color &bg = st::msgServiceBg, - const style::color &fg = st::msgServiceFg); - static void paintDate( + bool chatWide); + static void PaintDate( Painter &p, + not_null st, const QString &dateText, int y, int w, - bool chatWide, - const style::color &bg = st::msgServiceBg, - const style::color &fg = st::msgServiceFg); - static void paintDate( + bool chatWide); + static void PaintDate( Painter &p, + not_null st, const QString &dateText, int dateTextWidth, int y, int w, - bool chatWide, - const style::color &bg = st::msgServiceBg, - const style::color &fg = st::msgServiceFg); - - static void paintBubble( + bool chatWide); + static void PaintDate( Painter &p, - int x, + const style::color &bg, + const Ui::CornersPixmaps &corners, + const style::color &fg, + const QString &dateText, + int dateTextWidth, int y, int w, - int h, - const style::color &bg = st::msgServiceBg); + bool chatWide); - static void paintComplexBubble( + static void PaintBubble( Painter &p, + not_null st, + QRect rect); + static void PaintBubble( + Painter &p, + const style::color &bg, + const Ui::CornersPixmaps &corners, + QRect rect); + + static void PaintComplexBubble( + Painter &p, + not_null st, int left, int width, const Ui::Text::String &text, - const QRect &textRect, - const style::color &bg = st::msgServiceBg); + const QRect &textRect); private: - static QVector countLineWidths(const Ui::Text::String &text, const QRect &textRect); + static QVector CountLineWidths( + const Ui::Text::String &text, + const QRect &textRect); }; @@ -99,7 +115,11 @@ class EmptyPainter { public: explicit EmptyPainter(not_null history); - void paint(Painter &p, int width, int height); + void paint( + Painter &p, + not_null st, + int width, + int height); private: void fillAboutGroup(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index 9d5d1738e..3d8e57498 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -86,7 +86,10 @@ public: } virtual void refreshParentId(not_null realParent) { } - virtual void drawHighlight(Painter &p, int top) const { + virtual void drawHighlight( + Painter &p, + const PaintContext &context, + int top) const { } virtual void draw(Painter &p, const PaintContext &context) const = 0; [[nodiscard]] virtual PointState pointState(QPoint point) const; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 88e7982ea..960709a9a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -270,7 +270,10 @@ QMargins GroupedMedia::groupedPadding() const { (normal.bottom() - grouped.bottom()) + addToBottom); } -void GroupedMedia::drawHighlight(Painter &p, int top) const { +void GroupedMedia::drawHighlight( + Painter &p, + const PaintContext &context, + int top) const { if (_mode != Mode::Column) { return; } @@ -278,7 +281,12 @@ void GroupedMedia::drawHighlight(Painter &p, int top) const { for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; const auto rect = part.geometry.translated(0, skip); - _parent->paintCustomHighlight(p, rect.y(), rect.height(), part.item); + _parent->paintCustomHighlight( + p, + context, + rect.y(), + rect.height(), + part.item); } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h index 48be7e2be..c5131dc93 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -31,7 +31,10 @@ public: void refreshParentId(not_null realParent) override; - void drawHighlight(Painter &p, int top) const override; + void drawHighlight( + Painter &p, + const PaintContext &context, + int top) const override; void draw(Painter &p, const PaintContext &context) const override; PointState pointState(QPoint point) const override; TextState textState( diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 85cd6dafa..00b38329c 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_peer_menu.h" #include "ui/widgets/popup_menu.h" #include "ui/controls/delete_message_context_action.h" +#include "ui/chat/chat_style.h" +#include "ui/cached_round_corners.h" #include "ui/ui_utility.h" #include "ui/inactive_press.h" #include "lang/lang_keys.h" @@ -94,6 +96,20 @@ struct ListWidget::Context { DragSelectAction dragSelectAction; }; +struct ListWidget::DateBadge { + DateBadge(Type type, Fn checkCallback, Fn hideCallback); + + SingleQueuedInvokation check; + base::Timer hideTimer; + Ui::Animations::Simple opacity; + Ui::CornersPixmaps corners; + bool goodType = false; + bool shown = false; + QString text; + int textWidth = 0; + QRect rect; +}; + class ListWidget::Section { public: Section(Type type) @@ -228,6 +244,17 @@ ListWidget::CachedItem &ListWidget::CachedItem::operator=( ListWidget::CachedItem::~CachedItem() = default; +ListWidget::DateBadge::DateBadge( + Type type, + Fn checkCallback, + Fn hideCallback) +: check(std::move(checkCallback)) +, hideTimer(std::move(hideCallback)) +, goodType(type == Type::Photo + || type == Type::Video + || type == Type::GIF) { +} + bool ListWidget::Section::addItem(not_null item) { if (_items.empty() || belongsHere(item)) { if (_items.empty()) setHeader(item); @@ -664,13 +691,10 @@ ListWidget::ListWidget( , _migrated(_controller->migrated()) , _type(_controller->section().mediaType()) , _slice(sliceKey(_universalAroundId)) -, _dateBadge(DateBadge{ - .check = SingleQueuedInvokation([=] { scrollDateCheck(); }), - .hideTimer = base::Timer([=] { scrollDateHide(); }), - .goodType = (_type == Type::Photo - || _type == Type::Video - || _type == Type::GIF), -}) { +, _dateBadge(std::make_unique( + _type, + [=] { scrollDateCheck(); }, + [=] { scrollDateHide(); })) { setMouseTracking(true); start(); } @@ -1204,16 +1228,16 @@ void ListWidget::visibleTopBottomUpdated( checkMoveToOtherViewer(); clearHeavyItems(); - if (_dateBadge.goodType) { + if (_dateBadge->goodType) { updateDateBadgeFor(_visibleTop); if (!_visibleTop) { - if (_dateBadge.shown) { + if (_dateBadge->shown) { scrollDateHide(); } else { - update(_dateBadge.rect); + update(_dateBadge->rect); } } else { - _dateBadge.check.call(); + _dateBadge->check.call(); } } } @@ -1228,29 +1252,30 @@ void ListWidget::updateDateBadgeFor(int top) { + st::msgServiceFont->height + st::msgServicePadding.bottom(); - _dateBadge.text = ItemDateText(layout->getItem(), false); - _dateBadge.rect = QRect(0, top, width(), rectHeight); + _dateBadge->text = ItemDateText(layout->getItem(), false); + _dateBadge->textWidth = st::msgServiceFont->width(_dateBadge->text); + _dateBadge->rect = QRect(0, top, width(), rectHeight); } void ListWidget::scrollDateCheck() { - if (!_dateBadge.shown) { + if (!_dateBadge->shown) { toggleScrollDateShown(); } - _dateBadge.hideTimer.callOnce(st::infoScrollDateHideTimeout); + _dateBadge->hideTimer.callOnce(st::infoScrollDateHideTimeout); } void ListWidget::scrollDateHide() { - if (_dateBadge.shown) { + if (_dateBadge->shown) { toggleScrollDateShown(); } } void ListWidget::toggleScrollDateShown() { - _dateBadge.shown = !_dateBadge.shown; - _dateBadge.opacity.start( - [=] { update(_dateBadge.rect); }, - _dateBadge.shown ? 0. : 1., - _dateBadge.shown ? 1. : 0., + _dateBadge->shown = !_dateBadge->shown; + _dateBadge->opacity.start( + [=] { update(_dateBadge->rect); }, + _dateBadge->shown ? 0. : 1., + _dateBadge->shown ? 1. : 0., st::infoDateFadeDuration); } @@ -1403,19 +1428,27 @@ void ListWidget::paintEvent(QPaintEvent *e) { fromSectionIt->paintFloatingHeader(p, _visibleTop, outerWidth); } - if (_dateBadge.goodType && clip.intersects(_dateBadge.rect)) { + if (_dateBadge->goodType && clip.intersects(_dateBadge->rect)) { const auto scrollDateOpacity = - _dateBadge.opacity.value(_dateBadge.shown ? 1. : 0.); + _dateBadge->opacity.value(_dateBadge->shown ? 1. : 0.); if (scrollDateOpacity > 0.) { p.setOpacity(scrollDateOpacity); - HistoryView::ServiceMessagePainter::paintDate( + if (_dateBadge->corners.p[0].isNull()) { + _dateBadge->corners = Ui::PrepareCornerPixmaps( + Ui::HistoryServiceMsgRadius(), + st::roundedBg, + nullptr); + } + HistoryView::ServiceMessagePainter::PaintDate( p, - _dateBadge.text, + st::roundedBg, + _dateBadge->corners, + st::roundedFg, + _dateBadge->text, + _dateBadge->textWidth, _visibleTop, outerWidth, - false, - st::roundedBg, - st::roundedFg); + false); } } } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 6498c062e..926354533 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -90,6 +90,7 @@ public: private: struct Context; + struct DateBadge; class Section; using CursorState = HistoryView::CursorState; using TextState = HistoryView::TextState; @@ -331,15 +332,7 @@ private: DragSelectAction _dragSelectAction = DragSelectAction::None; bool _wasSelectedText = false; // was some text selected in current drag action - struct DateBadge { - SingleQueuedInvokation check; - base::Timer hideTimer; - Ui::Animations::Simple opacity; - bool goodType = false; - bool shown = false; - QString text; - QRect rect; - } _dateBadge; + const std::unique_ptr _dateBadge; base::unique_qptr _contextMenu; rpl::event_stream<> _checkForHide; diff --git a/Telegram/SourceFiles/ui/cached_round_corners.cpp b/Telegram/SourceFiles/ui/cached_round_corners.cpp index 5fee309b5..07c3e0901 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.cpp +++ b/Telegram/SourceFiles/ui/cached_round_corners.cpp @@ -95,9 +95,6 @@ void CreatePaletteCorners() { PrepareCorners(Doc4Corners, st::roundRadiusSmall, st::msgFile4Bg); PrepareCorners(MessageInCorners, st::historyMessageRadius, st::msgInBg, &st::msgInShadow); - PrepareCorners(MessageInSelectedCorners, st::historyMessageRadius, st::msgInBgSelected, &st::msgInShadowSelected); - PrepareCorners(MessageOutCorners, st::historyMessageRadius, st::msgOutBg, &st::msgOutShadow); - PrepareCorners(MessageOutSelectedCorners, st::historyMessageRadius, st::msgOutBgSelected, &st::msgOutShadowSelected); } } // namespace diff --git a/Telegram/SourceFiles/ui/cached_round_corners.h b/Telegram/SourceFiles/ui/cached_round_corners.h index c6bb3cc8e..cd3e70570 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.h +++ b/Telegram/SourceFiles/ui/cached_round_corners.h @@ -43,9 +43,6 @@ enum CachedRoundCorners : int { InSelectedShadowCorners, MessageInCorners, // with shadow - MessageInSelectedCorners, - MessageOutCorners, - MessageOutSelectedCorners, RoundCornersCount }; diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index d51cb99a7..58e0f37e6 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/chat_style.h" #include "ui/chat/chat_theme.h" +#include "ui/ui_utility.h" #include "styles/style_chat.h" #include "styles/style_dialogs.h" @@ -30,10 +31,36 @@ not_null ChatPaintContext::messageStyle() const { return &st->messageStyle(outbg, selected()); } +int HistoryServiceMsgRadius() { + static const auto result = [] { + const auto minMessageHeight = st::msgServicePadding.top() + + st::msgServiceFont->height + + st::msgServicePadding.bottom(); + return minMessageHeight / 2; + }(); + return result; +} + +int HistoryServiceMsgInvertedRadius() { + static const auto result = [] { + const auto minRowHeight = st::msgServiceFont->height; + return minRowHeight - HistoryServiceMsgRadius(); + }(); + return result; +} + +int HistoryServiceMsgInvertedShrink() { + static const auto result = [] { + return (HistoryServiceMsgInvertedRadius() * 2) / 3; + }(); + return result; +} + ChatStyle::ChatStyle() { finalize(); make(_historyPsaForwardPalette, st::historyPsaForwardPalette); make(_imgReplyTextPalette, st::imgReplyTextPalette); + make(_serviceTextPalette, st::serviceTextPalette); make(_historyRepliesInvertedIcon, st::historyRepliesInvertedIcon); make(_historyViewsInvertedIcon, st::historyViewsInvertedIcon); make(_historyViewsSendingIcon, st::historyViewsSendingIcon); @@ -212,9 +239,41 @@ void ChatStyle::assignPalette(not_null palette) { for (auto &style : _messageStyles) { style.corners = {}; } + _serviceBgCornersNormal = {}; + _serviceBgCornersInverted = {}; _msgServiceBgCorners = {}; _msgServiceBgSelectedCorners = {}; _msgBotKbOverBgAddCorners = {}; + _msgDateImgBgCorners = {}; + _msgDateImgBgSelectedCorners = {}; +} + +const CornersPixmaps &ChatStyle::serviceBgCornersNormal() const { + EnsureCorners( + _serviceBgCornersNormal, + HistoryServiceMsgRadius(), + msgServiceBg()); + return _serviceBgCornersNormal; +} + +const CornersPixmaps &ChatStyle::serviceBgCornersInverted() const { + if (_serviceBgCornersInverted.p[0].isNull()) { + const auto radius = HistoryServiceMsgInvertedRadius(); + const auto size = radius * style::DevicePixelRatio(); + auto circle = style::colorizeImage( + style::createInvertedCircleMask(radius * 2), + msgServiceBg()); + circle.setDevicePixelRatio(style::DevicePixelRatio()); + const auto fill = [&](int index, int xoffset, int yoffset) { + _serviceBgCornersInverted.p[index] = PixmapFromImage( + circle.copy(QRect(xoffset, yoffset, size, size))); + }; + fill(0, 0, 0); + fill(1, size, 0); + fill(2, size, size); + fill(3, 0, size); + } + return _serviceBgCornersInverted; } const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const { diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 1b65b6a2d..e899f4d00 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -83,12 +83,19 @@ struct ChatPaintContext { }; +[[nodiscard]] int HistoryServiceMsgRadius(); +[[nodiscard]] int HistoryServiceMsgInvertedRadius(); +[[nodiscard]] int HistoryServiceMsgInvertedShrink(); + class ChatStyle final : public style::palette { public: ChatStyle(); void apply(not_null theme); + [[nodiscard]] const CornersPixmaps &serviceBgCornersNormal() const; + [[nodiscard]] const CornersPixmaps &serviceBgCornersInverted() const; + [[nodiscard]] const MessageStyle &messageStyle( bool outbg, bool selected) const; @@ -105,6 +112,9 @@ public: [[nodiscard]] const style::TextPalette &imgReplyTextPalette() const { return _imgReplyTextPalette; } + [[nodiscard]] const style::TextPalette &serviceTextPalette() const { + return _serviceTextPalette; + } [[nodiscard]] const style::icon &historyRepliesInvertedIcon() const { return _historyRepliesInvertedIcon; } @@ -174,6 +184,9 @@ private: const Type &originalOut, const Type &originalOutSelected); + mutable CornersPixmaps _serviceBgCornersNormal; + mutable CornersPixmaps _serviceBgCornersInverted; + mutable std::array _messageStyles; mutable CornersPixmaps _msgServiceBgCorners; @@ -184,6 +197,7 @@ private: style::TextPalette _historyPsaForwardPalette; style::TextPalette _imgReplyTextPalette; + style::TextPalette _serviceTextPalette; style::icon _historyRepliesInvertedIcon = { Qt::Uninitialized }; style::icon _historyViewsInvertedIcon = { Qt::Uninitialized }; style::icon _historyViewsSendingIcon = { Qt::Uninitialized }; diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 8e20b4a51..dce1eac2a 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -416,6 +416,9 @@ public: }; [[nodiscard]] Ui::ChatPaintContext preparePaintContext( PaintContextArgs &&args); + [[nodiscard]] not_null chatStyle() const { + return _chatStyle.get(); + } rpl::lifetime &lifetime() { return _lifetime; @@ -486,7 +489,7 @@ private: std::shared_ptr _defaultChatTheme; base::flat_map _customChatThemes; rpl::event_stream> _cachedThemesStream; - std::unique_ptr _chatStyle; + const std::unique_ptr _chatStyle; std::weak_ptr _chatStyleTheme; rpl::lifetime _lifetime;