Files
tdesktop/Telegram/lib_ui/ui/text/custom_emoji_helper.cpp
allhaileris afb81b8278
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
init
2026-02-16 15:50:16 +03:00

158 lines
4.1 KiB
C++

// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include "ui/text/custom_emoji_helper.h"
#include "ui/text/custom_emoji_instance.h"
#include "ui/text/text_custom_emoji.h"
#include "ui/text/text_utilities.h"
namespace Ui::Text {
namespace {
[[nodiscard]] QString Prefix(int counter) {
return u"helper%1:"_q.arg(counter);
}
[[nodiscard]] QString PaddingPostfix(QMargins padding) {
if (padding.isNull()) {
return QString();
}
return u":%1,%2,%3,%4"_q
.arg(padding.left())
.arg(padding.top())
.arg(padding.right())
.arg(padding.bottom());
}
[[nodiscard]] QMargins PaddingFromPostfix(QStringView postfix) {
const auto parts = postfix.split(u',');
if (parts.size() != 4) {
return {};
}
return QMargins(
parts[0].toInt(),
parts[1].toInt(),
parts[2].toInt(),
parts[3].toInt());
}
} // namespace
CustomEmojiHelper::CustomEmojiHelper() = default;
CustomEmojiHelper::CustomEmojiHelper(MarkedContext parent)
: _parent(std::move(parent)) {
}
QString CustomEmojiHelper::imageData(ImageEmoji emoji) {
Expects(!emoji.image.isNull());
const auto data = ensureData();
const auto result = data->prefix
+ u"image%1"_q.arg(data->images.size())
+ (emoji.margin.isNull() ? QString() : PaddingPostfix(emoji.margin))
+ (emoji.textColor
? (emoji.margin.isNull() ? u"::1"_q : u":1"_q)
: QString());
data->images.push_back(std::move(emoji.image));
return result;
}
TextWithEntities CustomEmojiHelper::image(ImageEmoji emoji){
return SingleCustomEmoji(imageData(std::move(emoji)));
}
QString CustomEmojiHelper::paletteDependentData(
PaletteDependentEmoji emoji) {
Expects(emoji.factory != nullptr);
const auto data = ensureData();
const auto result = data->prefix
+ u"factory%1"_q.arg(data->paletteDependent.size())
+ (emoji.margin.isNull() ? QString() : PaddingPostfix(emoji.margin));
data->paletteDependent.push_back(std::move(emoji.factory));
return result;
}
TextWithEntities CustomEmojiHelper::paletteDependent(
PaletteDependentEmoji emoji) {
return SingleCustomEmoji(paletteDependentData(std::move(emoji)));
}
MarkedContext CustomEmojiHelper::context(Fn<void()> repaint) {
auto result = _parent;
if (repaint) {
result.repaint = std::move(repaint);
}
if (!_data) {
return result;
}
auto factory = [map = _data](
QStringView data,
const MarkedContext &context
) -> std::unique_ptr<CustomEmoji> {
if (!data.startsWith(map->prefix)) {
return nullptr;
}
const auto id = data.mid(map->prefix.size());
const auto parts = id.split(':');
if (parts.empty()) {
return nullptr;
}
const auto type = parts[0];
const auto postfix = (parts.size() > 1) ? parts[1] : QStringView();
const auto padding = PaddingFromPostfix(postfix);
if (type.startsWith(u"image"_q)) {
const auto index = type.mid(u"image"_q.size()).toInt();
if (index >= 0 && index < map->images.size()) {
return std::make_unique<Ui::CustomEmoji::Internal>(
data.toString(),
base::duplicate(map->images[index]),
padding,
(parts.size() > 2) && parts[2] == u"1"_q);
}
} else if (type.startsWith(u"factory"_q)) {
const auto index = type.mid(u"factory"_q.size()).toInt();
if (index >= 0 && index < map->paletteDependent.size()) {
return std::make_unique<PaletteDependentCustomEmoji>(
map->paletteDependent[index],
data.toString(),
padding);
}
}
return nullptr;
};
if (auto old = _parent.customEmojiFactory) {
result.customEmojiFactory = [
factory = std::move(factory),
old = std::move(old)
](
QStringView data,
const MarkedContext &context
) -> std::unique_ptr<CustomEmoji> {
if (auto result = factory(data, context)) {
return result;
}
return old(data, context);
};
} else {
result.customEmojiFactory = factory;
}
return result;
}
auto CustomEmojiHelper::ensureData() -> not_null<Data*> {
if (!_data) {
static auto counter = std::atomic<int>();
_data = std::make_shared<Data>();
_data->prefix = Prefix(counter++);
}
return _data.get();
}
} // namespace Ui::Text