mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Display emoji correctly in folder tags.
This commit is contained in:
parent
51b81dba87
commit
acfd92e2e6
8 changed files with 362 additions and 93 deletions
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/message_field.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "data/data_peer.h"
|
||||
|
@ -443,6 +444,13 @@ void EditFilterBox(
|
|||
nameEditing->settingDefault = false;
|
||||
}
|
||||
};
|
||||
const auto nameWithEntities = [=](bool upper = false) {
|
||||
const auto entered = name->getTextWithTags();
|
||||
return TextWithEntities{
|
||||
(upper ? entered.text.toUpper() : entered.text),
|
||||
TextUtilities::ConvertTextTagsToEntities(entered.tags),
|
||||
};
|
||||
};
|
||||
|
||||
const auto outer = box->getDelegate()->outerContainer();
|
||||
CreateIconSelector(
|
||||
|
@ -546,18 +554,28 @@ void EditFilterBox(
|
|||
colors->width(),
|
||||
h);
|
||||
}, preview->lifetime());
|
||||
const auto previewTag = preview->lifetime().make_state<QImage>();
|
||||
const auto previewAlpha = preview->lifetime().make_state<float64>(1);
|
||||
|
||||
struct TagState {
|
||||
Ui::Animations::Simple animation;
|
||||
Ui::ChatsFilterTagContext context;
|
||||
QImage frame;
|
||||
float64 alpha = 1.;
|
||||
};
|
||||
const auto tag = preview->lifetime().make_state<TagState>();
|
||||
tag->context.textContext = Core::MarkedTextContext{
|
||||
.session = session,
|
||||
.customEmojiRepaint = [] {},
|
||||
};
|
||||
preview->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(preview);
|
||||
p.setOpacity(*previewAlpha);
|
||||
const auto size = previewTag->size() / style::DevicePixelRatio();
|
||||
p.setOpacity(tag->alpha);
|
||||
const auto size = tag->frame.size() / style::DevicePixelRatio();
|
||||
const auto rect = QRect(
|
||||
preview->width() - size.width() - st::boxRowPadding.right(),
|
||||
(st::normalFont->height - size.height()) / 2,
|
||||
size.width(),
|
||||
size.height());
|
||||
p.drawImage(rect.topLeft(), *previewTag);
|
||||
p.drawImage(rect.topLeft(), tag->frame);
|
||||
if (p.opacity() < 1) {
|
||||
p.setOpacity(1. - p.opacity());
|
||||
p.setFont(st::normalFont);
|
||||
|
@ -574,16 +592,14 @@ void EditFilterBox(
|
|||
Ui::CreateSkipWidget(colors, side),
|
||||
st::boxRowPadding);
|
||||
auto buttons = std::vector<not_null<UserpicBuilder::CircleButton*>>();
|
||||
const auto animation
|
||||
= line->lifetime().make_state<Ui::Animations::Simple>();
|
||||
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);
|
||||
tag->context.color = palette(state->colorIndex.current())->c;
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
tag->context);
|
||||
preview->update();
|
||||
}, preview->lifetime());
|
||||
for (auto i = 0; i < kColorsCount; ++i) {
|
||||
|
@ -597,12 +613,12 @@ void EditFilterBox(
|
|||
const auto color = palette(i);
|
||||
button->setBrush(color);
|
||||
if (progress == 1) {
|
||||
*previewTag = Ui::ChatsFilterTag(
|
||||
name->getLastText().toUpper(),
|
||||
color->c,
|
||||
false);
|
||||
tag->context.color = color->c;
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
tag->context);
|
||||
if (i == kNoTag) {
|
||||
*previewAlpha = 0.;
|
||||
tag->alpha = 0.;
|
||||
}
|
||||
}
|
||||
buttons.push_back(button);
|
||||
|
@ -617,17 +633,17 @@ void EditFilterBox(
|
|||
const auto c2 = palette(now);
|
||||
const auto a1 = (was == kNoTag) ? 0. : 1.;
|
||||
const auto a2 = (now == kNoTag) ? 0. : 1.;
|
||||
animation->stop();
|
||||
animation->start([=](float64 progress) {
|
||||
tag->animation.stop();
|
||||
tag->animation.start([=](float64 progress) {
|
||||
if (was >= 0) {
|
||||
buttons[was]->setSelectedProgress(1. - progress);
|
||||
}
|
||||
buttons[now]->setSelectedProgress(progress);
|
||||
*previewTag = Ui::ChatsFilterTag(
|
||||
name->getLastText().toUpper(),
|
||||
anim::color(c1, c2, progress),
|
||||
false);
|
||||
*previewAlpha = anim::interpolateF(a1, a2, progress);
|
||||
tag->context.color = anim::color(c1, c2, progress);
|
||||
tag->frame = Ui::ChatsFilterTag(
|
||||
nameWithEntities(true),
|
||||
tag->context);
|
||||
tag->alpha = anim::interpolateF(a1, a2, progress);
|
||||
preview->update();
|
||||
}, 0., 1., st::universalDuration);
|
||||
}
|
||||
|
@ -673,11 +689,7 @@ void EditFilterBox(
|
|||
}
|
||||
|
||||
const auto collect = [=]() -> std::optional<Data::ChatFilter> {
|
||||
const auto entered = name->getTextWithTags();
|
||||
const auto title = TextWithEntities{
|
||||
entered.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(entered.tags),
|
||||
};
|
||||
const auto title = nameWithEntities();
|
||||
const auto rules = data->current();
|
||||
if (title.empty()) {
|
||||
name->showError();
|
||||
|
|
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ffmpeg/ffmpeg_frame_generator.h"
|
||||
#include "chat_helpers/stickers_lottie.h"
|
||||
#include "storage/file_download.h" // kMaxFileInMemory
|
||||
#include "ui/chat/chats_filter_tag.h"
|
||||
#include "ui/effects/credits_graphics.h"
|
||||
#include "ui/widgets/fields/input_field.h"
|
||||
#include "ui/text/custom_emoji_instance.h"
|
||||
|
@ -104,6 +105,14 @@ private:
|
|||
return u"userpic:"_q;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ScaledSimplePrefix() {
|
||||
return u"scaled-simple:"_q;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString ScaledCustomPrefix() {
|
||||
return u"scaled-custom:"_q;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString InternalPadding(QMargins value) {
|
||||
return value.isNull() ? QString() : QString(",%1,%2,%3,%4"
|
||||
).arg(value.left()
|
||||
|
@ -536,7 +545,16 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
|||
Fn<void()> update,
|
||||
SizeTag tag,
|
||||
int sizeOverride) {
|
||||
if (data.startsWith(InternalPrefix())) {
|
||||
if (data.startsWith(ScaledSimplePrefix())) {
|
||||
const auto text = data.mid(ScaledSimplePrefix().size());
|
||||
const auto emoji = Ui::Emoji::Find(text);
|
||||
Assert(emoji != nullptr);
|
||||
return Ui::MakeScaledSimpleEmoji(emoji);
|
||||
} else if (data.startsWith(ScaledCustomPrefix())) {
|
||||
const auto original = data.mid(ScaledCustomPrefix().size());
|
||||
return Ui::MakeScaledCustomEmoji(
|
||||
create(original, std::move(update), SizeTag::Large));
|
||||
} else if (data.startsWith(InternalPrefix())) {
|
||||
return internal(data);
|
||||
} else if (data.startsWith(UserpicEmojiPrefix())) {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
|
|
|
@ -112,8 +112,10 @@ taggedForumDialogRow: DialogRow(forumDialogRow) {
|
|||
height: 96px;
|
||||
tagTop: 77px;
|
||||
}
|
||||
dialogRowFilterTagSkip : 4px;
|
||||
dialogRowFilterTagFont : font(10px);
|
||||
dialogRowFilterTagSkip: 4px;
|
||||
dialogRowFilterTagStyle: TextStyle(defaultTextStyle) {
|
||||
font: font(10px);
|
||||
}
|
||||
dialogRowOpenBotTextStyle: semiboldTextStyle;
|
||||
dialogRowOpenBotHeight: 20px;
|
||||
dialogRowOpenBotRight: 10px;
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/shortcuts.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
|
@ -220,6 +221,11 @@ struct InnerWidget::PeerSearchResult {
|
|||
BasicRow row;
|
||||
};
|
||||
|
||||
struct InnerWidget::TagCache {
|
||||
Ui::ChatsFilterTagContext context;
|
||||
QImage frame;
|
||||
};
|
||||
|
||||
Key InnerWidget::FilterResult::key() const {
|
||||
return row->key();
|
||||
}
|
||||
|
@ -4161,32 +4167,41 @@ QImage *InnerWidget::cacheChatsFilterTag(
|
|||
return nullptr;
|
||||
}
|
||||
const auto key = SerializeFilterTagsKey(filter.id(), more, active);
|
||||
{
|
||||
const auto it = _chatsFilterTags.find(key);
|
||||
if (it != end(_chatsFilterTags)) {
|
||||
return &it->second;
|
||||
auto &entry = _chatsFilterTags[key];
|
||||
if (!entry.frame.isNull()) {
|
||||
if (!entry.context.loading) {
|
||||
return &entry.frame;
|
||||
}
|
||||
for (const auto &[k, emoji] : entry.context.emoji) {
|
||||
if (!emoji->ready()) {
|
||||
return &entry.frame; // Still waiting for emoji.
|
||||
}
|
||||
}
|
||||
}
|
||||
auto roundedText = QString();
|
||||
auto roundedText = TextWithEntities();
|
||||
auto colorIndex = -1;
|
||||
if (filter.id()) {
|
||||
roundedText = filter.title().text.toUpper(); // todo filter emoji
|
||||
roundedText = filter.title();
|
||||
roundedText.text = roundedText.text.toUpper();
|
||||
if (filter.colorIndex()) {
|
||||
colorIndex = *(filter.colorIndex());
|
||||
}
|
||||
} else if (more > 0) {
|
||||
roundedText = QChar('+') + QString::number(more);
|
||||
roundedText.text = QChar('+') + QString::number(more);
|
||||
colorIndex = st::colorIndexBlue;
|
||||
}
|
||||
if (roundedText.isEmpty() || colorIndex < 0) {
|
||||
if (roundedText.empty() || colorIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_chatsFilterTags.emplace(
|
||||
key,
|
||||
Ui::ChatsFilterTag(
|
||||
std::move(roundedText),
|
||||
Ui::EmptyUserpic::UserpicColor(colorIndex).color2->c,
|
||||
active)).first->second;
|
||||
const auto color = Ui::EmptyUserpic::UserpicColor(colorIndex).color2;
|
||||
entry.context.color = color->c;
|
||||
entry.context.active = active;
|
||||
entry.context.textContext = Core::MarkedTextContext{
|
||||
.session = &session(),
|
||||
.customEmojiRepaint = [] {},
|
||||
};
|
||||
entry.frame = Ui::ChatsFilterTag(roundedText, entry.context);
|
||||
return &entry.frame;
|
||||
}
|
||||
|
||||
bool InnerWidget::chooseHashtag() {
|
||||
|
|
|
@ -221,6 +221,7 @@ private:
|
|||
struct CollapsedRow;
|
||||
struct HashtagResult;
|
||||
struct PeerSearchResult;
|
||||
struct TagCache;
|
||||
|
||||
enum class JumpSkip {
|
||||
PreviousOrBegin,
|
||||
|
@ -579,7 +580,7 @@ private:
|
|||
|
||||
base::flat_map<FilterId, int> _chatsFilterScrollStates;
|
||||
|
||||
std::unordered_map<ChatsFilterTagsKey, QImage> _chatsFilterTags;
|
||||
std::unordered_map<ChatsFilterTagsKey, TagCache> _chatsFilterTags;
|
||||
bool _waitingAllChatListEntryRefreshesForTags = false;
|
||||
rpl::lifetime _handleChatListEntryTagRefreshesLifetime;
|
||||
|
||||
|
|
|
@ -7,59 +7,246 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "ui/chat/chats_filter_tag.h"
|
||||
|
||||
#include "ui/text/text_custom_emoji.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/integration.h"
|
||||
#include "ui/painter.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace {
|
||||
|
||||
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;
|
||||
class ScaledSimpleEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
ScaledSimpleEmoji(EmojiPtr emoji);
|
||||
|
||||
int width() override;
|
||||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
bool readyInDefaultState() override;
|
||||
|
||||
private:
|
||||
const EmojiPtr _emoji;
|
||||
QImage _frame;
|
||||
QPoint _shift;
|
||||
|
||||
};
|
||||
|
||||
class ScaledCustomEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
ScaledCustomEmoji(std::unique_ptr<Ui::Text::CustomEmoji> wrapped);
|
||||
|
||||
int width() override;
|
||||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
bool readyInDefaultState() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<Ui::Text::CustomEmoji> _wrapped;
|
||||
QImage _frame;
|
||||
QPoint _shift;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] int ScaledSize() {
|
||||
return st::dialogRowFilterTagStyle.font->height - 2 * st::lineWidth;
|
||||
}
|
||||
|
||||
ScaledSimpleEmoji::ScaledSimpleEmoji(EmojiPtr emoji)
|
||||
: _emoji(emoji) {
|
||||
}
|
||||
|
||||
int ScaledSimpleEmoji::width() {
|
||||
return ScaledSize();
|
||||
}
|
||||
|
||||
QString ScaledSimpleEmoji::entityData() {
|
||||
return u"scaled-simple:"_q + _emoji->text();
|
||||
}
|
||||
|
||||
void ScaledSimpleEmoji::paint(QPainter &p, const Context &context) {
|
||||
if (_frame.isNull()) {
|
||||
const auto adjusted = Text::AdjustCustomEmojiSize(st::emojiSize);
|
||||
const auto xskip = (st::emojiSize - adjusted) / 2;
|
||||
const auto yskip = xskip + (width() - st::emojiSize) / 2;
|
||||
_shift = { xskip, yskip };
|
||||
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto large = Emoji::GetSizeLarge();
|
||||
const auto size = QSize(large, large);
|
||||
_frame = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
_frame.fill(Qt::transparent);
|
||||
|
||||
auto p = QPainter(&_frame);
|
||||
Emoji::Draw(p, _emoji, large, 0, 0);
|
||||
p.end();
|
||||
|
||||
_frame = _frame.scaled(
|
||||
QSize(width(), width()) * ratio,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
p.drawImage(context.position - _shift, _frame);
|
||||
}
|
||||
|
||||
void ScaledSimpleEmoji::unload() {
|
||||
}
|
||||
|
||||
bool ScaledSimpleEmoji::ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScaledSimpleEmoji::readyInDefaultState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
ScaledCustomEmoji::ScaledCustomEmoji(
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> wrapped)
|
||||
: _wrapped(std::move(wrapped)) {
|
||||
}
|
||||
|
||||
int ScaledCustomEmoji::width() {
|
||||
return ScaledSize();
|
||||
}
|
||||
|
||||
QString ScaledCustomEmoji::entityData() {
|
||||
return u"scaled-custom:"_q + _wrapped->entityData();
|
||||
}
|
||||
|
||||
void ScaledCustomEmoji::paint(QPainter &p, const Context &context) {
|
||||
if (_frame.isNull()) {
|
||||
if (!_wrapped->ready()) {
|
||||
return;
|
||||
}
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto large = Emoji::GetSizeLarge();
|
||||
const auto largeadjust = Text::AdjustCustomEmojiSize(large / ratio);
|
||||
const auto size = QSize(largeadjust, largeadjust) * ratio;
|
||||
_frame = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
_frame.fill(Qt::transparent);
|
||||
|
||||
auto p = QPainter(&_frame);
|
||||
p.translate(-context.position);
|
||||
const auto was = context.internal.forceFirstFrame;
|
||||
context.internal.forceFirstFrame = true;
|
||||
_wrapped->paint(p, context);
|
||||
context.internal.forceFirstFrame = was;
|
||||
p.end();
|
||||
|
||||
const auto smalladjust = Text::AdjustCustomEmojiSize(width());
|
||||
_frame = _frame.scaled(
|
||||
QSize(smalladjust, smalladjust) * ratio,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
_wrapped->unload();
|
||||
|
||||
const auto adjusted = Text::AdjustCustomEmojiSize(st::emojiSize);
|
||||
const auto xskip = (st::emojiSize - adjusted) / 2;
|
||||
const auto yskip = xskip + (width() - st::emojiSize) / 2;
|
||||
|
||||
const auto add = (width() - smalladjust) / 2;
|
||||
_shift = QPoint(xskip, yskip) - QPoint(add, add);
|
||||
}
|
||||
p.drawImage(context.position - _shift, _frame);
|
||||
}
|
||||
|
||||
void ScaledCustomEmoji::unload() {
|
||||
_wrapped->unload();
|
||||
}
|
||||
|
||||
bool ScaledCustomEmoji::ready() {
|
||||
return !_frame.isNull() || _wrapped->ready();
|
||||
}
|
||||
|
||||
bool ScaledCustomEmoji::readyInDefaultState() {
|
||||
return !_frame.isNull() || _wrapped->ready();
|
||||
}
|
||||
|
||||
[[nodiscard]] TextWithEntities PrepareSmallEmojiText(
|
||||
TextWithEntities text,
|
||||
ChatsFilterTagContext &context) {
|
||||
auto i = text.entities.begin();
|
||||
auto ch = text.text.constData();
|
||||
auto &integration = Integration::Instance();
|
||||
context.loading = false;
|
||||
const auto end = text.text.constData() + text.text.size();
|
||||
const auto adjust = [&](EntityInText &entity) {
|
||||
if (entity.type() != EntityType::CustomEmoji) {
|
||||
return;
|
||||
}
|
||||
const auto data = entity.data();
|
||||
if (data.startsWith(u"scaled-simple:"_q)) {
|
||||
return;
|
||||
}
|
||||
auto &emoji = context.emoji[data];
|
||||
if (!emoji) {
|
||||
emoji = integration.createCustomEmoji(
|
||||
data,
|
||||
context.textContext);
|
||||
}
|
||||
if (!emoji->ready()) {
|
||||
context.loading = true;
|
||||
}
|
||||
entity = EntityInText(
|
||||
entity.type(),
|
||||
entity.offset(),
|
||||
entity.length(),
|
||||
u"scaled-custom:"_q + entity.data());
|
||||
};
|
||||
const auto till = [](EntityInText &entity) {
|
||||
return entity.offset() + entity.length();
|
||||
};
|
||||
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.push_back({
|
||||
.pixmap = Ui::Emoji::SinglePixmap(
|
||||
emoji,
|
||||
st::normalFont->height * factor).scaledToHeight(
|
||||
roundedFont->ascent * factor,
|
||||
Qt::SmoothTransformation),
|
||||
.from = int(ch - roundedText.constData()),
|
||||
.length = emojiLength,
|
||||
});
|
||||
const auto f = int(ch - text.text.constData());
|
||||
const auto l = f + emojiLength;
|
||||
while (i != text.entities.end() && till(*i) <= f) {
|
||||
adjust(*i);
|
||||
++i;
|
||||
}
|
||||
|
||||
ch += emojiLength;
|
||||
if (i != text.entities.end() && i->offset() < l) {
|
||||
continue;
|
||||
}
|
||||
i = text.entities.insert(i, EntityInText{
|
||||
EntityType::CustomEmoji,
|
||||
f,
|
||||
emojiLength,
|
||||
u"scaled-simple:"_q + emoji->text(),
|
||||
});
|
||||
} else {
|
||||
ch++;
|
||||
++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;
|
||||
}
|
||||
for (; i != text.entities.end(); ++i) {
|
||||
adjust(*i);
|
||||
}
|
||||
const auto roundedWidth = roundedFont->width(roundedText)
|
||||
+ additionalWidth;
|
||||
return text;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QImage ChatsFilterTag(
|
||||
const TextWithEntities &text,
|
||||
ChatsFilterTagContext &context) {
|
||||
const auto &roundedFont = st::dialogRowFilterTagStyle.font;
|
||||
const auto additionalWidth = roundedFont->spacew * 3;
|
||||
auto rich = Text::String(
|
||||
st::dialogRowFilterTagStyle,
|
||||
PrepareSmallEmojiText(text, context),
|
||||
kMarkupTextOptions,
|
||||
kQFixedMax,
|
||||
context.textContext);
|
||||
const auto roundedWidth = rich.maxWidth() + additionalWidth;
|
||||
const auto rect = QRect(0, 0, roundedWidth, roundedFont->height);
|
||||
auto cache = QImage(
|
||||
rect.size() * style::DevicePixelRatio(),
|
||||
|
@ -68,9 +255,11 @@ QImage ChatsFilterTag(QString roundedText, QColor color, bool active) {
|
|||
cache.fill(Qt::transparent);
|
||||
{
|
||||
auto p = QPainter(&cache);
|
||||
const auto pen = QPen(active ? st::dialogsBgActive->c : color);
|
||||
const auto pen = QPen(context.active
|
||||
? st::dialogsBgActive->c
|
||||
: context.color);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(active
|
||||
p.setBrush(context.active
|
||||
? st::dialogsTextFgActive->c
|
||||
: anim::with_alpha(pen.color(), .15));
|
||||
{
|
||||
|
@ -80,13 +269,23 @@ QImage ChatsFilterTag(QString roundedText, QColor color, bool active) {
|
|||
}
|
||||
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);
|
||||
}
|
||||
const auto dx = (rect.width() - rich.maxWidth()) / 2;
|
||||
const auto dy = (rect.height() - roundedFont->height) / 2;
|
||||
rich.draw(p, {
|
||||
.position = rect.topLeft() + QPoint(dx, dy),
|
||||
.availableWidth = rich.maxWidth(),
|
||||
});
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
std::unique_ptr<Text::CustomEmoji> MakeScaledSimpleEmoji(EmojiPtr emoji) {
|
||||
return std::make_unique<ScaledSimpleEmoji>(emoji);
|
||||
}
|
||||
|
||||
std::unique_ptr<Text::CustomEmoji> MakeScaledCustomEmoji(
|
||||
std::unique_ptr<Text::CustomEmoji> wrapped) {
|
||||
return std::make_unique<ScaledCustomEmoji>(std::move(wrapped));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -7,8 +7,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "emoji.h"
|
||||
|
||||
namespace Ui::Text {
|
||||
class CustomEmoji;
|
||||
} // namespace Ui::Text
|
||||
|
||||
namespace Ui {
|
||||
|
||||
[[nodiscard]] QImage ChatsFilterTag(QString text, QColor color, bool active);
|
||||
struct ChatsFilterTagContext {
|
||||
base::flat_map<QString, std::unique_ptr<Text::CustomEmoji>> emoji;
|
||||
std::any textContext;
|
||||
QColor color;
|
||||
bool active = false;
|
||||
bool loading = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] QImage ChatsFilterTag(
|
||||
const TextWithEntities &text,
|
||||
ChatsFilterTagContext &context);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Text::CustomEmoji> MakeScaledSimpleEmoji(
|
||||
EmojiPtr emoji);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Text::CustomEmoji> MakeScaledCustomEmoji(
|
||||
std::unique_ptr<Text::CustomEmoji> wrapped);
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c1ea8aef5073785ce6e35db9eda830604f81ed62
|
||||
Subproject commit 8cb06a75d981d7a1a2f2a5df420ef20ff4c0b097
|
Loading…
Add table
Reference in a new issue