From 3ceaefc3331d5332ff798d60b87f86b14f1e1d6f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 3 Jul 2026 21:06:29 +0300 Subject: [PATCH] Added outline to selected theme card. --- Telegram/SourceFiles/settings/settings.style | 3 + .../themes/window_themes_cloud_list.cpp | 120 +++++++++--------- .../window/themes/window_themes_cloud_list.h | 4 +- 3 files changed, 67 insertions(+), 60 deletions(-) diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 771ea8cddd..4bdcaa2fcf 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -289,6 +289,9 @@ settingsThemeBubbleRadius: 2px; settingsThemeBubblePosition: point(6px, 8px); settingsThemeBubbleSkip: 6px; settingsThemeRadioBottom: 12px; +settingsThemeOutlineWidth: 2px; +settingsThemeOutlineSkip: 4px; +settingsThemeOutlineRadius: 8px; settingsThemeMinSkip: 4px; settingsThemeNotSupportedBg: windowBgOver; diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index 4515e7437c..cf405e7229 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "ui/chat/chat_theme.h" #include "ui/image/image_prepare.h" +#include "ui/rect.h" #include "ui/widgets/popup_menu.h" #include "ui/toast/toast.h" #include "ui/style/style_palette_colorizer.h" @@ -138,7 +139,7 @@ constexpr auto kShowPerRow = 4; result.received = dark ? QColor(24, 24, 25) : QColor(255, 255, 255); result.radiobuttonActive = result.radiobuttonInactive - = (dark ? QColor(255, 255, 255) : settings.accentColor); + = settings.accentColor; const auto paperColors = settings.paper ? settings.paper->backgroundColors() : std::vector(); @@ -165,7 +166,7 @@ constexpr auto kShowPerRow = 4; result.received = st::msgInBg->c; result.radiobuttonActive = result.radiobuttonInactive - = st::msgServiceFg->c; + = st::activeButtonBg->c; return result; } @@ -175,8 +176,9 @@ CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme) { auto result = CloudListColors(); result.sent = scheme.sent; result.received = scheme.received; - result.radiobuttonActive = scheme.radiobuttonActive; - result.radiobuttonInactive = scheme.radiobuttonInactive; + result.radiobuttonActive + = result.radiobuttonInactive + = scheme.accentColor; result.background = QImage( QSize(1, 1) * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); @@ -192,6 +194,9 @@ CloudListColors ColorsFromScheme( } auto copy = scheme; Colorize(copy, colorizer); + if (const auto accent = style::colorize(copy.accentColor, colorizer)) { + copy.accentColor = *accent; + } return ColorsFromScheme(copy); } @@ -201,8 +206,7 @@ CloudListCheck::CloudListCheck(const Colors &colors, bool checked) } CloudListCheck::CloudListCheck(bool checked) -: AbstractCheckView(st::defaultRadio.duration, checked, nullptr) -, _radio(st::defaultRadio, checked, [=] { update(); }) { +: AbstractCheckView(st::defaultRadio.duration, checked, nullptr) { } void CloudListCheck::setColors(const Colors &colors) { @@ -218,35 +222,10 @@ void CloudListCheck::setColors(const Colors &colors) { Qt::SmoothTransformation); _backgroundCacheWidth = -1; - ensureContrast(); - _radio.setToggledOverride(_colors->radiobuttonActive); - _radio.setUntoggledOverride(_colors->radiobuttonInactive); } update(); } -void CloudListCheck::ensureContrast() { - const auto radio = _radio.getSize(); - const auto x = (getSize().width() - radio.width()) / 2; - const auto y = getSize().height() - - radio.height() - - st::settingsThemeRadioBottom; - const auto under = QRect( - QPoint(x, y) * style::DevicePixelRatio(), - radio * style::DevicePixelRatio()); - const auto image = _backgroundFull.copy(under).convertToFormat( - QImage::Format_ARGB32_Premultiplied); - const auto active = style::internal::EnsureContrast( - _colors->radiobuttonActive, - Ui::CountAverageColor(image)); - _colors->radiobuttonInactive = _colors->radiobuttonActive = QColor( - active.red(), - active.green(), - active.blue(), - 255); - _colors->radiobuttonInactive.setAlpha(192); -} - QSize CloudListCheck::getSize() const { return st::settingsThemePreviewSize; } @@ -256,14 +235,15 @@ void CloudListCheck::validateBackgroundCache(int width) { return; } _backgroundCacheWidth = width; + const auto skip = st::settingsThemeOutlineSkip; const auto imageWidth = width * style::DevicePixelRatio(); - _backgroundCache = (width == st::settingsThemePreviewSize.width()) - ? _backgroundFull - : _backgroundFull.copy( - (_backgroundFull.width() - imageWidth) / 2, - 0, - imageWidth, - _backgroundFull.height()); + const auto imageHeight = (st::settingsThemePreviewSize.height() + - 2 * skip) * style::DevicePixelRatio(); + _backgroundCache = _backgroundFull.copy( + (_backgroundFull.width() - imageWidth) / 2, + (_backgroundFull.height() - imageHeight) / 2, + imageWidth, + imageHeight); _backgroundCache = Images::Round( std::move(_backgroundCache), ImageRoundRadius::Large); @@ -289,11 +269,13 @@ void CloudListCheck::paintNotSupported( p.setPen(Qt::NoPen); p.setBrush(st::settingsThemeNotSupportedBg); + const auto skip = st::settingsThemeOutlineSkip; const auto height = st::settingsThemePreviewSize.height(); - const auto rect = QRect(0, 0, outerWidth, height); + const auto rect = QRect(0, 0, outerWidth, height) - Margins(skip); const auto radius = st::roundRadiusLarge; p.drawRoundedRect(rect, radius, radius); st::settingsThemeNotSupportedIcon.paintInCenter(p, rect); + paintOutline(p, outerWidth); } void CloudListCheck::paintWithColors( @@ -303,35 +285,63 @@ void CloudListCheck::paintWithColors( int outerWidth) { Expects(_colors.has_value()); - validateBackgroundCache(outerWidth); - p.drawImage( - QRect(0, 0, outerWidth, st::settingsThemePreviewSize.height()), - _backgroundCache); + auto hq = PainterHighQualityEnabler(p); + + const auto skip = st::settingsThemeOutlineSkip; + const auto card = QRect( + 0, + 0, + outerWidth, + st::settingsThemePreviewSize.height() + ) - Margins(skip); + validateBackgroundCache(card.width()); + p.drawImage(card, _backgroundCache); const auto received = QRect( - st::settingsThemeBubblePosition, + card.topLeft() + st::settingsThemeBubblePosition, st::settingsThemeBubbleSize); const auto sent = QRect( - outerWidth - received.width() - st::settingsThemeBubblePosition.x(), + card.x() + card.width() + - received.width() + - st::settingsThemeBubblePosition.x(), received.y() + received.height() + st::settingsThemeBubbleSkip, received.width(), received.height()); const auto radius = st::settingsThemeBubbleRadius; - PainterHighQualityEnabler hq(p); p.setPen(Qt::NoPen); - p.setBrush(_colors->received); p.drawRoundedRect(style::rtlrect(received, outerWidth), radius, radius); p.setBrush(_colors->sent); p.drawRoundedRect(style::rtlrect(sent, outerWidth), radius, radius); - const auto radio = _radio.getSize(); - _radio.paint( - p, - (outerWidth - radio.width()) / 2, - getSize().height() - radio.height() - st::settingsThemeRadioBottom, - outerWidth); + paintOutline(p, outerWidth); +} + +void CloudListCheck::paintOutline(QPainter &p, int outerWidth) { + const auto toggled = currentAnimationValue(); + if (toggled <= 0.) { + return; + } + const auto width = float64(st::settingsThemeOutlineWidth); + const auto inset = width / 2. + + st::settingsThemeOutlineSkip * (1. - toggled); + const auto radius = st::settingsThemeOutlineRadius + - (inset - width / 2.); + auto pen = QPen(_colors->radiobuttonActive); + pen.setWidthF(width); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + p.setOpacity(toggled); + p.drawRoundedRect( + QRectF(0, 0, outerWidth, getSize().height()).adjusted( + inset, + inset, + -inset, + -inset), + radius, + radius); + p.setOpacity(1.); } QImage CloudListCheck::prepareRippleMask() const { @@ -342,10 +352,6 @@ bool CloudListCheck::checkRippleStartPosition(QPoint position) const { return false; } -void CloudListCheck::checkedChangedHook(anim::type animated) { - _radio.setChecked(checked(), animated); -} - CloudList::CloudList( not_null parent, not_null window) diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h index 49f3602d82..a5b6b015bc 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h @@ -63,12 +63,10 @@ public: private: void paintNotSupported(QPainter &p, int left, int top, int outerWidth); void paintWithColors(QPainter &p, int left, int top, int outerWidth); - void checkedChangedHook(anim::type animated) override; + void paintOutline(QPainter &p, int outerWidth); void validateBackgroundCache(int width); - void ensureContrast(); std::optional _colors; - Ui::RadioView _radio; QImage _backgroundFull; QImage _backgroundCache; int _backgroundCacheWidth = -1;