From c11a7589e2e76614f35b0b80ab4eafd7418282f5 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 18 Mar 2025 12:57:05 +0300 Subject: [PATCH] Added initial ability to trigger quick dialog action with middle click. --- .../dialogs/dialogs_inner_widget.cpp | 50 ++++++++++++--- .../dialogs/dialogs_quick_action.cpp | 61 +++++++++++++++++++ .../dialogs/dialogs_quick_action.h | 10 +++ .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 57 ++++++++--------- .../dialogs/ui/dialogs_quick_action_context.h | 1 + 5 files changed, 141 insertions(+), 38 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 28ac0119fa..fbb41c763c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -1956,16 +1956,40 @@ bool InnerWidget::addQuickActionRipple( .sizeOverride = Size(st::dialogsQuickActionSize), }); context->action = action; - const auto size = QSize( - st::dialogsQuickActionRippleSize, - row->height()); - if (!context->ripple) { - context->ripple = std::make_unique( - st::defaultRippleAnimation, - Ui::RippleAnimation::RectMask(size), - std::move(updateCallback)); - } - context->ripple->add(QPoint(size.width() / 2, size.height() / 2)); + context->icon->jumpTo(context->icon->framesCount() - 1, [=] { + const auto size = QSize( + st::dialogsQuickActionRippleSize, + row->height()); + if (!context->ripple) { + context->ripple = std::make_unique( + st::defaultRippleAnimation, + Ui::RippleAnimation::RectMask(size), + updateCallback); + } + if (!context->rippleFg) { + context->rippleFg = std::make_unique( + st::defaultRippleAnimation, + Ui::RippleAnimation::MaskByDrawer( + size, + true, + [&](QPainter &p) { + p.setCompositionMode( + QPainter::CompositionMode_Source); + p.fillRect(Rect(size), Qt::transparent); + DrawQuickAction( + p, + Rect(size), + context->icon.get(), + ResolveQuickDialogLabel( + row->history(), + action, + _filterId)); + }), + std::move(updateCallback)); + } + context->ripple->add(QPoint(size.width() / 2, size.height() / 2)); + context->rippleFg->add(QPoint(size.width() / 2, size.height() / 2)); + }); return true; } @@ -2281,7 +2305,13 @@ void InnerWidget::mousePressReleased( if (it != _quickActions.end()) { if (it->second->ripple) { it->second->ripple->lastStop(); + it->second->rippleFg->lastStop(); } + PerformQuickDialogAction( + _controller, + history->peer, + it->second->action, + _filterId); } } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp b/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp index 8bafb68690..1d5f16e107 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_quick_action.cpp @@ -14,13 +14,55 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "dialogs/dialogs_entry.h" #include "history/history.h" +#include "lang/lang_instance.h" #include "lang/lang_keys.h" +#include "lottie/lottie_icon.h" #include "main/main_session.h" #include "menu/menu_mute.h" #include "window/window_peer_menu.h" #include "window/window_session_controller.h" +#include "styles/style_dialogs.h" namespace Dialogs { +namespace { + +const style::font &SwipeActionFont( + Dialogs::Ui::QuickDialogActionLabel action, + int availableWidth) { + struct Entry final { + Dialogs::Ui::QuickDialogActionLabel action; + QString langId; + style::font font; + }; + static auto Fonts = std::vector(); + for (auto &entry : Fonts) { + if (entry.action == action) { + if (entry.langId == Lang::GetInstance().id()) { + return entry.font; + } + } + } + constexpr auto kNormalFontSize = 13; + constexpr auto kMinFontSize = 5; + for (auto i = kNormalFontSize; i >= kMinFontSize; --i) { + auto font = style::font( + style::ConvertScale(i, style::Scale()), + st::semiboldFont->flags(), + st::semiboldFont->family()); + if (font->width(ResolveQuickDialogLabel(action)) <= availableWidth + || i == kMinFontSize) { + Fonts.emplace_back(Entry{ + .action = action, + .langId = Lang::GetInstance().id(), + .font = std::move(font), + }); + return Fonts.back().font; + } + } + Unexpected("SwipeActionFont: can't find font."); +} + +} // namespace void PerformQuickDialogAction( not_null controller, @@ -163,4 +205,23 @@ const style::color &ResolveQuickActionBgActive( return st::windowSubTextFgOver; } +void DrawQuickAction( + QPainter &p, + const QRect &rect, + not_null icon, + Ui::QuickDialogActionLabel label) { + const auto iconSize = st::dialogsQuickActionSize; + const auto innerHeight = iconSize * 2; + const auto top = (rect.height() - innerHeight) / 2; + icon->paint(p, rect.x() + (rect.width() - iconSize) / 2, top); + p.setPen(st::premiumButtonFg); + p.setBrush(Qt::NoBrush); + const auto availableWidth = rect.width(); + p.setFont(SwipeActionFont(label, availableWidth)); + p.drawText( + QRect(rect.x(), top, availableWidth, innerHeight), + ResolveQuickDialogLabel(label), + style::al_bottom); +} + } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_quick_action.h b/Telegram/SourceFiles/dialogs/dialogs_quick_action.h index e425cd08dc..3d5cb80ddf 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_quick_action.h +++ b/Telegram/SourceFiles/dialogs/dialogs_quick_action.h @@ -15,6 +15,10 @@ enum class QuickDialogAction; enum class QuickDialogActionLabel; } // namespace Dialogs::Ui +namespace Lottie { +class Icon; +} // namespace Lottie + namespace Window { class SessionController; } // namespace Window @@ -44,4 +48,10 @@ void PerformQuickDialogAction( [[nodiscard]] const style::color &ResolveQuickActionBgActive( Ui::QuickDialogActionLabel); +void DrawQuickAction( + QPainter &p, + const QRect &rect, + not_null icon, + Ui::QuickDialogActionLabel label); + } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 793de8b605..c559693051 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -878,7 +878,7 @@ void PaintRow( if (swipeTranslation) { p.translate(swipeTranslation, 0); const auto swipeActionRect = QRect( - geometry.x() + geometry.width() - swipeTranslation, + rect::right(geometry) - swipeTranslation, geometry.y(), swipeTranslation, geometry.height()); @@ -897,35 +897,36 @@ void PaintRow( + st::dialogsQuickActionSize / 2.; p.drawEllipse(QPointF(geometry.width() - offset, offset), r, r); } - const auto iconOffset = (geometry.height() - - st::dialogsQuickActionSize) / 2; - const auto topTranslation = iconOffset / 2.; - p.translate(0, -topTranslation); - if (context.quickActionContext->icon) { - context.quickActionContext->icon->paint( - p, - rect::right(geometry) - - iconOffset - - st::dialogsQuickActionSize, - iconOffset, - st::premiumButtonFg->c); - } - { - p.setPen(st::premiumButtonFg); - p.setBrush(Qt::NoBrush); - const auto left = rect::right(geometry) - - iconOffset * 2 - - st::dialogsQuickActionSize; - const auto availableWidth = geometry.width() - left; - p.setFont(SwipeActionFont(labelType, availableWidth)); - p.drawText( - QRect(left, 0, availableWidth, geometry.height()), - ResolveQuickDialogLabel(labelType), - style::al_bottom); - } - p.translate(0, topTranslation); + const auto quickWidth = st::dialogsQuickActionSize * 3; + DrawQuickAction( + p, + QRect( + rect::right(geometry) - quickWidth, + geometry.y(), + quickWidth, + geometry.height()), + context.quickActionContext->icon.get(), + labelType); p.setClipping(false); } + if (const auto quick = context.quickActionContext; + quick && quick->ripple && quick->rippleFg) { + const auto labelType = ResolveQuickDialogLabel( + history, + context.quickActionContext->action, + context.filter); + const auto ripple = ResolveQuickActionBg(labelType); + const auto size = st::dialogsQuickActionRippleSize; + const auto x = geometry.width() - size; + quick->ripple->paint(p, x, 0, size, &ripple->c); + quick->rippleFg->paint(p, x, 0, size, &st::premiumButtonFg->c); + if (quick->ripple->empty()) { + quick->ripple.reset(); + } + if (quick->rippleFg->empty()) { + quick->rippleFg.reset(); + } + } } } // namespace diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_quick_action_context.h b/Telegram/SourceFiles/dialogs/ui/dialogs_quick_action_context.h index fbd0c363cf..d60b6974f5 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_quick_action_context.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_quick_action_context.h @@ -39,6 +39,7 @@ struct QuickActionContext { ::Ui::Controls::SwipeContextData data; std::unique_ptr icon; std::unique_ptr ripple; + std::unique_ptr rippleFg; QuickDialogAction action; };