diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp index 0edbba1e9..3ada6e408 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_box.cpp @@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/settings_common.h" +#include "ui/chat/chats_filter_tag.h" #include "ui/effects/animation_value_f.h" #include "ui/effects/animations.h" #include "ui/effects/panel_animation.h" @@ -544,31 +545,18 @@ void EditFilterBox( colors->width(), h); }, preview->lifetime()); - const auto previewColor = preview->lifetime().make_state<QColor>(); + const auto previewTag = preview->lifetime().make_state<QImage>(); const auto previewAlpha = preview->lifetime().make_state<float64>(1); preview->paintRequest() | rpl::start_with_next([=] { auto p = QPainter(preview); - p.fillRect(preview->rect(), Qt::transparent); - const auto &font = st::dialogRowFilterTagFont; - const auto text = name->getLastText().toUpper(); - p.setFont(font); p.setOpacity(*previewAlpha); - const auto roundedWidth = font->width(text) + font->spacew * 3; + const auto size = previewTag->size() / style::DevicePixelRatio(); const auto rect = QRect( - preview->width() - roundedWidth - st::boxRowPadding.right(), - (st::normalFont->height - font->height) / 2, - roundedWidth, - font->height); - const auto pen = QPen(*previewColor); - p.setPen(Qt::NoPen); - p.setBrush(anim::with_alpha(pen.color(), .15)); - { - auto hq = PainterHighQualityEnabler(p); - const auto radius = font->height / 3.; - p.drawRoundedRect(rect, radius, radius); - } - p.setPen(pen); - p.drawText(rect, text, style::al_center); + preview->width() - size.width() - st::boxRowPadding.right(), + (st::normalFont->height - size.height()) / 2, + size.width(), + size.height()); + p.drawImage(rect.topLeft(), *previewTag); if (p.opacity() < 1) { p.setOpacity(1. - p.opacity()); p.setFont(st::normalFont); @@ -580,10 +568,6 @@ void EditFilterBox( } }, preview->lifetime()); - name->changes() | rpl::start_with_next([=] { - preview->update(); - }, preview->lifetime()); - const auto side = st::userpicBuilderEmojiAccentColorSize; const auto line = colors->add( Ui::CreateSkipWidget(colors, side), @@ -594,6 +578,13 @@ void EditFilterBox( const auto palette = [](int i) { return Ui::EmptyUserpic::UserpicColor(i).color2; }; + name->changes() | rpl::start_with_next([=] { + *previewTag = Ui::ChatsFilterTag( + name->getLastText().toUpper(), + palette(state->colorIndex.current())->c, + false); + preview->update(); + }, preview->lifetime()); for (auto i = 0; i < kColorsCount; ++i) { const auto button = Ui::CreateChild<UserpicBuilder::CircleButton>( line); @@ -605,7 +596,10 @@ void EditFilterBox( const auto color = palette(i); button->setBrush(color); if (progress == 1) { - *previewColor = color->c; + *previewTag = Ui::ChatsFilterTag( + name->getLastText().toUpper(), + color->c, + false); if (i == kNoTag) { *previewAlpha = 0.; } @@ -628,7 +622,10 @@ void EditFilterBox( buttons[was]->setSelectedProgress(1. - progress); } buttons[now]->setSelectedProgress(progress); - *previewColor = anim::color(c1, c2, progress); + *previewTag = Ui::ChatsFilterTag( + name->getLastText().toUpper(), + anim::color(c1, c2, progress), + false); *previewAlpha = anim::interpolateF(a1, a2, progress); preview->update(); }, 0., 1., st::universalDuration); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d5572a026..6fa18f356 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_controller.h" #include "window/window_session_controller.h" #include "window/window_peer_menu.h" +#include "ui/chat/chats_filter_tag.h" #include "ui/effects/ripple_animation.h" #include "ui/effects/loading_element.h" #include "ui/widgets/multi_select.h" @@ -315,6 +316,9 @@ InnerWidget::InnerWidget( session().settings().archiveCollapsedChanges() | rpl::map_to(false), session().data().chatsFilters().changed() | rpl::map_to(true) ) | rpl::start_with_next([=](bool refreshHeight) { + if (refreshHeight) { + _chatsFilterTags.clear(); + } if (refreshHeight && _filterId) { // Height of the main list will be refreshed in other way. _shownList->updateHeights(_narrowRatio); @@ -4274,34 +4278,12 @@ QImage *InnerWidget::cacheChatsFilterTag( if (roundedText.isEmpty() || colorIndex < 0) { return nullptr; } - const auto &roundedFont = st::dialogRowFilterTagFont; - const auto roundedWidth = roundedFont->width(roundedText) - + roundedFont->spacew * 3; - const auto rect = QRect(0, 0, roundedWidth, roundedFont->height); - auto cache = QImage( - rect.size() * style::DevicePixelRatio(), - QImage::Format_ARGB32_Premultiplied); - cache.setDevicePixelRatio(style::DevicePixelRatio()); - cache.fill(Qt::transparent); - { - auto p = QPainter(&cache); - const auto pen = QPen(active - ? st::dialogsBgActive - : Ui::EmptyUserpic::UserpicColor(colorIndex).color2); - p.setPen(Qt::NoPen); - p.setBrush(active - ? st::dialogsTextFgActive->c - : anim::with_alpha(pen.color(), .15)); - { - auto hq = PainterHighQualityEnabler(p); - const auto radius = roundedFont->height / 3.; - p.drawRoundedRect(rect, radius, radius); - } - p.setPen(pen); - p.setFont(roundedFont); - p.drawText(rect, roundedText, style::al_center); - } - return &_chatsFilterTags.emplace(key, std::move(cache)).first->second; + return &_chatsFilterTags.emplace( + key, + Ui::ChatsFilterTag( + std::move(roundedText), + Ui::EmptyUserpic::UserpicColor(colorIndex).color2->c, + active)).first->second; } bool InnerWidget::chooseHashtag() { diff --git a/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp b/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp new file mode 100644 index 000000000..3e799aa02 --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp @@ -0,0 +1,91 @@ +/* +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/chats_filter_tag.h" + +#include "ui/emoji_config.h" +#include "ui/painter.h" +#include "styles/style_dialogs.h" + +namespace Ui { + +QImage ChatsFilterTag(QString roundedText, QColor color, bool active) { + const auto &roundedFont = st::dialogRowFilterTagFont; + const auto additionalWidth = roundedFont->spacew * 3; + struct EmojiReplacement final { + QPixmap pixmap; + int from = -1; + int length = 0; + float64 x = -1; + }; + auto emojiReplacements = std::vector<EmojiReplacement>(); + auto ch = roundedText.constData(); + const auto end = ch + roundedText.size(); + while (ch != end) { + auto emojiLength = 0; + if (const auto emoji = Ui::Emoji::Find(ch, end, &emojiLength)) { + const auto factor = style::DevicePixelRatio(); + emojiReplacements.emplace_back( + Ui::Emoji::SinglePixmap( + emoji, + st::normalFont->height * factor).scaledToHeight( + roundedFont->ascent * factor, + Qt::SmoothTransformation), + ch - roundedText.constData(), + emojiLength); + ch += emojiLength; + } else { + ch++; + } + } + if (!emojiReplacements.empty()) { + auto addedChars = 0; + for (auto &e : emojiReplacements) { + const auto pixmapWidth = e.pixmap.width() + / style::DevicePixelRatio(); + const auto spaces = 1 + pixmapWidth / roundedFont->spacew; + const auto placeholder = QString(spaces, ' '); + const auto from = e.from + addedChars; + e.x = roundedFont->width(roundedText.mid(0, from)) + + additionalWidth / 2. + + (roundedFont->width(placeholder) - pixmapWidth) / 2.; + roundedText.replace(from, e.length, placeholder); + addedChars += spaces - e.length; + } + } + const auto roundedWidth = roundedFont->width(roundedText) + + additionalWidth; + const auto rect = QRect(0, 0, roundedWidth, roundedFont->height); + auto cache = QImage( + rect.size() * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + cache.setDevicePixelRatio(style::DevicePixelRatio()); + cache.fill(Qt::transparent); + { + auto p = QPainter(&cache); + const auto pen = QPen(active ? st::dialogsBgActive->c : color); + p.setPen(Qt::NoPen); + p.setBrush(active + ? st::dialogsTextFgActive->c + : anim::with_alpha(pen.color(), .15)); + { + auto hq = PainterHighQualityEnabler(p); + const auto radius = roundedFont->height / 3.; + p.drawRoundedRect(rect, radius, radius); + } + p.setPen(pen); + p.setFont(roundedFont); + p.drawText(rect, roundedText, style::al_center); + for (const auto &e : emojiReplacements) { + const auto h = e.pixmap.height() / style::DevicePixelRatio(); + p.drawPixmap(QPointF(e.x, (rect.height() - h) / 2), e.pixmap); + } + } + return cache; +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/chats_filter_tag.h b/Telegram/SourceFiles/ui/chat/chats_filter_tag.h new file mode 100644 index 000000000..aa07bf4c5 --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/chats_filter_tag.h @@ -0,0 +1,14 @@ +/* +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 + +namespace Ui { + +[[nodiscard]] QImage ChatsFilterTag(QString text, QColor color, bool active); + +} // namespace Ui diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index fa35b57d9..5b281f1cf 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -334,6 +334,8 @@ PRIVATE ui/chat/chat_style_radius.h ui/chat/chat_theme.cpp ui/chat/chat_theme.h + ui/chat/chats_filter_tag.cpp + ui/chat/chats_filter_tag.h ui/chat/continuous_scroll.cpp ui/chat/continuous_scroll.h ui/chat/forward_options_box.cpp