mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 09:41:41 -05:00
Use single emoji sprite and scale + cache it.
This commit is contained in:
parent
59a97ffb99
commit
b847c8424a
39 changed files with 549 additions and 179 deletions
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 3.2 MiB |
|
@ -1,8 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/emoji.webp">../art/emoji.webp</file>
|
||||
<file alias="art/emoji_125x.webp">../art/emoji_125x.webp</file>
|
||||
<file alias="art/emoji_150x.webp">../art/emoji_150x.webp</file>
|
||||
<file alias="art/emoji_200x.webp">../art/emoji_200x.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
5
Telegram/Resources/qrc/telegram_emoji_1.qrc
Normal file
5
Telegram/Resources/qrc/telegram_emoji_1.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_1.webp">../emoji/emoji_1.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
5
Telegram/Resources/qrc/telegram_emoji_2.qrc
Normal file
5
Telegram/Resources/qrc/telegram_emoji_2.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_2.webp">../emoji/emoji_2.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
5
Telegram/Resources/qrc/telegram_emoji_3.qrc
Normal file
5
Telegram/Resources/qrc/telegram_emoji_3.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_3.webp">../emoji/emoji_3.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
5
Telegram/Resources/qrc/telegram_emoji_4.qrc
Normal file
5
Telegram/Resources/qrc/telegram_emoji_4.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_4.webp">../emoji/emoji_4.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
5
Telegram/Resources/qrc/telegram_emoji_5.qrc
Normal file
5
Telegram/Resources/qrc/telegram_emoji_5.qrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="emoji/emoji_5.webp">../emoji/emoji_5.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -1,5 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/gui">
|
||||
<file alias="art/emoji_250x.webp">../art/emoji_250x.webp</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "storage/localimageloader.h"
|
||||
#include "storage/file_download.h"
|
||||
#include "storage/file_upload.h"
|
||||
|
|
|
@ -77,7 +77,6 @@ namespace {
|
|||
*pressedLinkItem = nullptr,
|
||||
*mousedItem = nullptr;
|
||||
|
||||
QPixmap *emoji = nullptr, *emojiLarge = nullptr;
|
||||
style::font monofont;
|
||||
|
||||
struct CornersPixmaps {
|
||||
|
@ -88,10 +87,6 @@ namespace {
|
|||
CornersMap cornersMap;
|
||||
QImage cornersMaskLarge[4], cornersMaskSmall[4];
|
||||
|
||||
using EmojiImagesMap = QMap<int, QPixmap>;
|
||||
EmojiImagesMap MainEmojiMap;
|
||||
QMap<int, EmojiImagesMap> OtherEmojiMap;
|
||||
|
||||
int32 serviceImageCacheSize = 0;
|
||||
|
||||
} // namespace
|
||||
|
@ -1440,15 +1435,6 @@ namespace App {
|
|||
if (family.isEmpty()) family = QFontDatabase::systemFont(QFontDatabase::FixedFont).family();
|
||||
::monofont = style::font(st::normalFont->f.pixelSize(), 0, family);
|
||||
}
|
||||
Ui::Emoji::Init();
|
||||
if (!::emoji) {
|
||||
::emoji = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index()));
|
||||
if (cRetina()) ::emoji->setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
if (!::emojiLarge) {
|
||||
::emojiLarge = new QPixmap(Ui::Emoji::Filename(Ui::Emoji::Index() + 1));
|
||||
if (cRetina()) ::emojiLarge->setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
createCorners();
|
||||
|
||||
|
@ -1491,16 +1477,8 @@ namespace App {
|
|||
}
|
||||
|
||||
void deinitMedia() {
|
||||
delete ::emoji;
|
||||
::emoji = nullptr;
|
||||
delete ::emojiLarge;
|
||||
::emojiLarge = nullptr;
|
||||
|
||||
clearCorners();
|
||||
|
||||
MainEmojiMap.clear();
|
||||
OtherEmojiMap.clear();
|
||||
|
||||
Data::clearGlobalStructures();
|
||||
|
||||
clearAllImages();
|
||||
|
@ -1558,30 +1536,6 @@ namespace App {
|
|||
return ::monofont;
|
||||
}
|
||||
|
||||
const QPixmap &emoji() {
|
||||
return *::emoji;
|
||||
}
|
||||
|
||||
const QPixmap &emojiLarge() {
|
||||
return *::emojiLarge;
|
||||
}
|
||||
|
||||
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight) {
|
||||
auto &map = (fontHeight == st::msgFont->height) ? MainEmojiMap : OtherEmojiMap[fontHeight];
|
||||
auto i = map.constFind(emoji->index());
|
||||
if (i == map.cend()) {
|
||||
auto image = QImage(Ui::Emoji::Size() + st::emojiPadding * cIntRetinaFactor() * 2, fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
if (cRetina()) image.setDevicePixelRatio(cRetinaFactor());
|
||||
image.fill(Qt::transparent);
|
||||
{
|
||||
QPainter p(&image);
|
||||
emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - Ui::Emoji::Size()) / 2);
|
||||
}
|
||||
i = map.insert(emoji->index(), App::pixmapFromImageInPlace(std::move(image)));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
void checkImageCacheSize() {
|
||||
int64 nowImageCacheSize = imageCacheSize();
|
||||
if (nowImageCacheSize > serviceImageCacheSize + MemoryForImageCache) {
|
||||
|
|
|
@ -186,9 +186,6 @@ namespace App {
|
|||
void clearMousedItems();
|
||||
|
||||
const style::font &monofont();
|
||||
const QPixmap &emoji();
|
||||
const QPixmap &emojiLarge();
|
||||
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight);
|
||||
|
||||
void clearHistories();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_chat_helpers.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "auth_session.h"
|
||||
#include "messenger.h"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "calls/calls_emoji_fingerprint.h"
|
||||
|
||||
#include "calls/calls_call.h"
|
||||
#include "ui/emoji_config.h"
|
||||
|
||||
namespace Calls {
|
||||
namespace {
|
||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "messenger.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -725,12 +726,12 @@ void Panel::paintEvent(QPaintEvent *e) {
|
|||
if (!_fingerprint.empty()) {
|
||||
App::roundRect(p, _fingerprintArea, st::callFingerprintBg, ImageRoundRadius::Small);
|
||||
|
||||
auto realSize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
auto size = realSize / cIntRetinaFactor();
|
||||
const auto realSize = Ui::Emoji::GetSizeLarge();
|
||||
const auto size = realSize / cIntRetinaFactor();
|
||||
auto left = _fingerprintArea.left() + st::callFingerprintPadding.left();
|
||||
auto top = _fingerprintArea.top() + st::callFingerprintPadding.top();
|
||||
for (auto emoji : _fingerprint) {
|
||||
p.drawPixmap(QPoint(left, top), App::emojiLarge(), QRect(emoji->x() * realSize, emoji->y() * realSize, realSize, realSize));
|
||||
const auto top = _fingerprintArea.top() + st::callFingerprintPadding.top();
|
||||
for (const auto emoji : _fingerprint) {
|
||||
Ui::Emoji::Draw(p, emoji, realSize, left, top);
|
||||
left += st::callFingerprintSkip + size;
|
||||
}
|
||||
}
|
||||
|
@ -868,7 +869,7 @@ void Panel::fillFingerprint() {
|
|||
Expects(_call != nullptr);
|
||||
_fingerprint = ComputeEmojiFingerprint(_call);
|
||||
|
||||
auto realSize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
auto realSize = Ui::Emoji::GetSizeLarge();
|
||||
auto size = realSize / cIntRetinaFactor();
|
||||
auto count = _fingerprint.size();
|
||||
auto rectWidth = count * size + (count - 1) * st::callFingerprintSkip;
|
||||
|
|
|
@ -8,12 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/emoji_list_widget.h"
|
||||
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "emoji_suggestions_data.h"
|
||||
#include "emoji_suggestions_helper.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
namespace ChatHelpers {
|
||||
|
||||
|
@ -319,18 +320,26 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
|||
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
|
||||
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
|
||||
}
|
||||
auto esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
p.drawPixmapLeft(w.x() + (_singleSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (_singleSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_variants[variant]->x() * esize, _variants[variant]->y() * esize, esize, esize));
|
||||
const auto esize = Ui::Emoji::GetSizeLarge();
|
||||
Ui::Emoji::Draw(
|
||||
p,
|
||||
_variants[variant],
|
||||
esize,
|
||||
w.x() + (_singleSize.width() - (esize / cIntRetinaFactor())) / 2,
|
||||
w.y() + (_singleSize.height() - (esize / cIntRetinaFactor())) / 2);
|
||||
}
|
||||
|
||||
EmojiListWidget::EmojiListWidget(QWidget *parent, not_null<Window::Controller*> controller) : Inner(parent, controller)
|
||||
EmojiListWidget::EmojiListWidget(
|
||||
QWidget *parent,
|
||||
not_null<Window::Controller*> controller)
|
||||
: Inner(parent, controller)
|
||||
, _picker(this) {
|
||||
setMouseTracking(true);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
_picker->hide();
|
||||
|
||||
_esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
_esize = Ui::Emoji::GetSizeLarge();
|
||||
|
||||
for (auto i = 0; i != kEmojiSectionCount; ++i) {
|
||||
_counts[i] = Ui::Emoji::GetSectionCount(static_cast<Section>(i));
|
||||
|
@ -482,10 +491,12 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
|
||||
App::roundRect(p, QRect(tl, _singleSize), st::emojiPanHover, StickerHoverCorners);
|
||||
}
|
||||
auto sourceRect = QRect(_emoji[info.section][index]->x() * _esize, _emoji[info.section][index]->y() * _esize, _esize, _esize);
|
||||
auto imageLeft = w.x() + (_singleSize.width() - (_esize / cIntRetinaFactor())) / 2;
|
||||
auto imageTop = w.y() + (_singleSize.height() - (_esize / cIntRetinaFactor())) / 2;
|
||||
p.drawPixmapLeft(imageLeft, imageTop, width(), App::emojiLarge(), sourceRect);
|
||||
Ui::Emoji::Draw(
|
||||
p,
|
||||
_emoji[info.section][index],
|
||||
_esize,
|
||||
w.x() + (_singleSize.width() - (_esize / cIntRetinaFactor())) / 2,
|
||||
w.y() + (_singleSize.height() - (_esize / cIntRetinaFactor())) / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace Emoji {
|
||||
enum class Section;
|
||||
} // namespace Emoji
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
|
|
@ -10,9 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/emoji_suggestions_helper.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace Emoji {
|
||||
|
@ -176,24 +177,29 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
|
|||
if (clip.intersects(topskip)) p.fillRect(clip.intersected(topskip), _st->itemBg);
|
||||
if (clip.intersects(bottomskip)) p.fillRect(clip.intersected(bottomskip), _st->itemBg);
|
||||
|
||||
auto top = _st->skip;
|
||||
const auto top = _st->skip;
|
||||
p.setFont(_st->itemFont);
|
||||
auto from = floorclamp(clip.top() - top, _rowHeight, 0, _rows.size());
|
||||
auto to = ceilclamp(clip.top() + clip.height() - top, _rowHeight, 0, _rows.size());
|
||||
const auto from = floorclamp(clip.top() - top, _rowHeight, 0, _rows.size());
|
||||
const auto to = ceilclamp(clip.top() + clip.height() - top, _rowHeight, 0, _rows.size());
|
||||
p.translate(0, top + from * _rowHeight);
|
||||
for (auto i = from; i != to; ++i) {
|
||||
auto &row = _rows[i];
|
||||
auto selected = (i == _selected || i == _pressed);
|
||||
const auto selected = (i == _selected || i == _pressed);
|
||||
p.fillRect(0, 0, width(), _rowHeight, selected ? _st->itemBgOver : _st->itemBg);
|
||||
if (auto ripple = row.ripple()) {
|
||||
if (const auto ripple = row.ripple()) {
|
||||
ripple->paint(p, 0, 0, width(), ms);
|
||||
if (ripple->empty()) {
|
||||
row.resetRipple();
|
||||
}
|
||||
}
|
||||
auto emoji = row.emoji();
|
||||
auto esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
p.drawPixmapLeft((_st->itemPadding.left() - (esize / cIntRetinaFactor())) / 2, (_rowHeight - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(emoji->x() * esize, emoji->y() * esize, esize, esize));
|
||||
const auto emoji = row.emoji();
|
||||
const auto esize = Ui::Emoji::GetSizeLarge();
|
||||
Ui::Emoji::Draw(
|
||||
p,
|
||||
emoji,
|
||||
esize,
|
||||
(_st->itemPadding.left() - (esize / cIntRetinaFactor())) / 2,
|
||||
(_rowHeight - (esize / cIntRetinaFactor())) / 2);
|
||||
p.setPen(selected ? _st->itemFgOver : _st->itemFg);
|
||||
p.drawTextLeft(_st->itemPadding.left(), _st->itemPadding.top(), width(), row.label());
|
||||
p.translate(0, _rowHeight);
|
||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "auth_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
namespace Stickers {
|
||||
|
|
|
@ -321,7 +321,7 @@ bool Generator::writeImages() {
|
|||
bool Generator::writeSource() {
|
||||
source_ = std::make_unique<common::CppFile>(outputPath_ + ".cpp", project_);
|
||||
|
||||
source_->include("emoji_suggestions_data.h").newline();
|
||||
source_->include("emoji_suggestions_data.h").include("ui/emoji_config.h").newline();
|
||||
source_->pushNamespace("Ui").pushNamespace("Emoji").pushNamespace();
|
||||
source_->stream() << "\
|
||||
\n\
|
||||
|
@ -342,6 +342,10 @@ std::vector<One> Items;\n\
|
|||
source_->popNamespace().newline().pushNamespace("internal");
|
||||
source_->stream() << "\
|
||||
\n\
|
||||
int FullCount() {\n\
|
||||
return Items.size();\n\
|
||||
}\n\
|
||||
\n\
|
||||
EmojiPtr ByIndex(int index) {\n\
|
||||
return (index >= 0 && index < Items.size()) ? &Items[index] : nullptr;\n\
|
||||
}\n\
|
||||
|
@ -370,7 +374,13 @@ void Init() {\n\
|
|||
\n\
|
||||
Items.reserve(base::array_size(Data));\n\
|
||||
for (auto &data : Data) {\n\
|
||||
Items.emplace_back(takeString(data.idSize), uint16(data.column), uint16(data.row), bool(data.postfixed), bool(data.variated), data.original ? &Items[data.original - 1] : nullptr, One::CreationTag());\n\
|
||||
Items.emplace_back(\n\
|
||||
takeString(data.idSize),\n\
|
||||
data.original ? &Items[data.original - 1] : nullptr,\n\
|
||||
uint32(Items.size()),\n\
|
||||
data.postfixed ? true : false,\n\
|
||||
data.variated ? true : false,\n\
|
||||
One::CreationTag());\n\
|
||||
}\n\
|
||||
InitReplacements();\n\
|
||||
}\n\
|
||||
|
@ -391,6 +401,7 @@ bool Generator::writeHeader() {
|
|||
\n\
|
||||
void Init();\n\
|
||||
\n\
|
||||
int FullCount();\n\
|
||||
EmojiPtr ByIndex(int index);\n\
|
||||
\n\
|
||||
EmojiPtr Find(const QChar *ch, const QChar *end, int *outLength = nullptr);\n\
|
||||
|
@ -414,6 +425,8 @@ EmojiPtr FindReplace(const QChar *ch, const QChar *end, int *outLength = nullptr
|
|||
\n";
|
||||
header->popNamespace().stream() << "\
|
||||
\n\
|
||||
constexpr auto kPostfix = static_cast<ushort>(0xFE0F);\n\
|
||||
\n\
|
||||
enum class Section {\n\
|
||||
Recent,\n\
|
||||
People,\n\
|
||||
|
@ -425,8 +438,6 @@ enum class Section {\n\
|
|||
Symbols,\n\
|
||||
};\n\
|
||||
\n\
|
||||
int Index();\n\
|
||||
\n\
|
||||
int GetSectionCount(Section section);\n\
|
||||
EmojiPack GetSection(Section section);\n\
|
||||
\n";
|
||||
|
@ -435,13 +446,11 @@ EmojiPack GetSection(Section section);\n\
|
|||
|
||||
template <typename Callback>
|
||||
bool Generator::enumerateWholeList(Callback callback) {
|
||||
auto column = 0;
|
||||
auto row = 0;
|
||||
auto index = 0;
|
||||
auto variated = -1;
|
||||
auto coloredCount = 0;
|
||||
for (auto &item : data_.list) {
|
||||
if (!callback(item.id, column, row, item.postfixed, item.variated, item.colored, variated)) {
|
||||
if (!callback(item.id, item.postfixed, item.variated, item.colored, variated)) {
|
||||
return false;
|
||||
}
|
||||
if (coloredCount > 0 && (item.variated || !item.colored)) {
|
||||
|
@ -464,10 +473,6 @@ bool Generator::enumerateWholeList(Callback callback) {
|
|||
} else if (variated >= 0) {
|
||||
variated = -1;
|
||||
}
|
||||
if (++column == kEmojiInRow) {
|
||||
column = 0;
|
||||
++row;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return true;
|
||||
|
@ -476,17 +481,15 @@ bool Generator::enumerateWholeList(Callback callback) {
|
|||
bool Generator::writeInitCode() {
|
||||
source_->stream() << "\
|
||||
struct DataStruct {\n\
|
||||
ushort original : " << kOriginalBits << ";\n\
|
||||
uchar idSize : " << kIdSizeBits << ";\n\
|
||||
uchar column : " << kColumnBits << ";\n\
|
||||
uchar row : " << kRowBits << ";\n\
|
||||
bool postfixed : 1;\n\
|
||||
bool variated : 1;\n\
|
||||
uint32 original : " << kOriginalBits << ";\n\
|
||||
uint32 idSize : " << kIdSizeBits << ";\n\
|
||||
uint32 postfixed : 1;\n\
|
||||
uint32 variated : 1;\n\
|
||||
};\n\
|
||||
\n\
|
||||
const ushort IdData[] = {";
|
||||
startBinary();
|
||||
if (!enumerateWholeList([this](Id id, int column, int row, bool isPostfixed, bool isVariated, bool isColored, int original) {
|
||||
if (!enumerateWholeList([this](Id id, bool isPostfixed, bool isVariated, bool isColored, int original) {
|
||||
return writeStringBinary(source_.get(), id);
|
||||
})) {
|
||||
return false;
|
||||
|
@ -498,7 +501,7 @@ const ushort IdData[] = {";
|
|||
source_->stream() << " };\n\
|
||||
\n\
|
||||
const DataStruct Data[] = {\n";
|
||||
if (!enumerateWholeList([this](Id id, int column, int row, bool isPostfixed, bool isVariated, bool isColored, int original) {
|
||||
if (!enumerateWholeList([this](Id id, bool isPostfixed, bool isVariated, bool isColored, int original) {
|
||||
if (original + 1 >= (1 << kOriginalBits)) {
|
||||
logDataError() << "Too many entries.";
|
||||
return false;
|
||||
|
@ -507,12 +510,8 @@ const DataStruct Data[] = {\n";
|
|||
logDataError() << "Too large id.";
|
||||
return false;
|
||||
}
|
||||
if (column >= (1 << kColumnBits) || row >= (1 << kRowBits)) {
|
||||
logDataError() << "Bad row-column.";
|
||||
return false;
|
||||
}
|
||||
source_->stream() << "\
|
||||
{ ushort(" << (isColored ? (original + 1) : 0) << "), uchar(" << id.size() << "), uchar(" << column << "), uchar(" << row << "), " << (isPostfixed ? "true" : "false") << ", " << (isVariated ? "true" : "false") << " },\n";
|
||||
{ uint32(" << (isColored ? (original + 1) : 0) << "), uint32(" << id.size() << "), uint32(" << (isPostfixed ? "1" : "0") << "), uint32(" << (isVariated ? "1" : "0") << ") },\n";
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_location_manager.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "storage/storage_shared_media.h"
|
||||
#include "storage/localstorage.h"
|
||||
#include "data/data_session.h"
|
||||
|
|
|
@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/empty_userpic.h"
|
||||
#include "ui/grouped_layout.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_types.h"
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/file_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/special_buttons.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
|
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/focus_persister.h"
|
||||
#include "ui/resize_area.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
|
|
|
@ -43,6 +43,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_location_manager.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "ui/text_options.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "storage/serialize_common.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
|
@ -118,6 +119,7 @@ Messenger::Messenger(not_null<Core::Launcher*> launcher)
|
|||
style::startManager();
|
||||
anim::startManager();
|
||||
Ui::InitTextOptions();
|
||||
Ui::Emoji::Init();
|
||||
Media::Player::start();
|
||||
|
||||
DEBUG_LOG(("Application Info: inited..."));
|
||||
|
@ -1025,6 +1027,8 @@ Messenger::~Messenger() {
|
|||
|
||||
Shortcuts::finish();
|
||||
|
||||
Ui::Emoji::Clear();
|
||||
|
||||
anim::stopManager();
|
||||
|
||||
stopWebLoadManager();
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/send_files_box.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "export/export_settings.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/update_checker.h"
|
||||
|
|
|
@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "emoji_config.h"
|
||||
|
||||
#include "chat_helpers/emoji_suggestions_helper.h"
|
||||
#include "base/bytes.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -18,8 +20,210 @@ namespace Emoji {
|
|||
namespace {
|
||||
|
||||
constexpr auto kSaveRecentEmojiTimeout = 3000;
|
||||
constexpr auto kUniversalSize = 72;
|
||||
constexpr auto kImagesPerRow = 32;
|
||||
constexpr auto kImageRowsPerSprite = 16;
|
||||
|
||||
auto WorkingIndex = -1;
|
||||
constexpr auto kVersion = 1;
|
||||
|
||||
class UniversalImages {
|
||||
public:
|
||||
void ensureLoaded();
|
||||
void clear();
|
||||
|
||||
void draw(QPainter &p, EmojiPtr emoji, int size, int x, int y) const;
|
||||
|
||||
QImage generate(int size, int index) const;
|
||||
|
||||
private:
|
||||
std::vector<QImage> _sprites;
|
||||
|
||||
};
|
||||
|
||||
auto Scale = -1.;
|
||||
auto SizeNormal = -1;
|
||||
auto SizeLarge = -1;
|
||||
auto SpritesCount = -1;
|
||||
|
||||
std::unique_ptr<Instance> InstanceNormal;
|
||||
std::unique_ptr<Instance> InstanceLarge;
|
||||
UniversalImages Universal;
|
||||
|
||||
std::map<int, QPixmap> MainEmojiMap;
|
||||
std::map<int, std::map<int, QPixmap>> OtherEmojiMap;
|
||||
|
||||
int RowsCount(int index) {
|
||||
if (index + 1 < SpritesCount) {
|
||||
return kImageRowsPerSprite;
|
||||
}
|
||||
const auto count = internal::FullCount()
|
||||
- (index * kImagesPerRow * kImageRowsPerSprite);
|
||||
return (count / kImagesPerRow)
|
||||
+ ((count % kImagesPerRow) ? 1 : 0);
|
||||
}
|
||||
|
||||
QString CacheFileFolder() {
|
||||
return cWorkingDir() + "tdata/emoji";
|
||||
}
|
||||
|
||||
QString CacheFilePath(int size, int index) {
|
||||
return CacheFileFolder()
|
||||
+ "/cache_"
|
||||
+ QString::number(size)
|
||||
+ '_'
|
||||
+ QString::number(index);
|
||||
}
|
||||
|
||||
void SaveToFile(const QImage &image, int size, int index) {
|
||||
Expects(image.bytesPerLine() == image.width() * 4);
|
||||
|
||||
QFile f(CacheFilePath(size, index));
|
||||
if (!f.open(QIODevice::WriteOnly)) {
|
||||
if (!QDir::current().mkpath(CacheFileFolder())
|
||||
|| !f.open(QIODevice::WriteOnly)) {
|
||||
LOG(("App Error: Could not open emoji cache '%1' for size %2_%3"
|
||||
).arg(f.fileName()
|
||||
).arg(size
|
||||
).arg(index));
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto write = [&](bytes::const_span data) {
|
||||
return f.write(
|
||||
reinterpret_cast<const char*>(data.data()),
|
||||
data.size()
|
||||
) == data.size();
|
||||
};
|
||||
const uint32 header[] = {
|
||||
uint32(kVersion),
|
||||
uint32(size),
|
||||
uint32(image.width()),
|
||||
uint32(image.height()),
|
||||
};
|
||||
const auto data = bytes::const_span(
|
||||
reinterpret_cast<const bytes::type*>(image.bits()),
|
||||
image.width() * image.height() * 4);
|
||||
if (!write(bytes::make_span(header))
|
||||
|| !write(data)
|
||||
|| !write(openssl::Sha256(bytes::make_span(header), data))
|
||||
|| false) {
|
||||
LOG(("App Error: Could not write emoji cache '%1' for size %2"
|
||||
).arg(f.fileName()
|
||||
).arg(size));
|
||||
}
|
||||
}
|
||||
|
||||
QImage LoadFromFile(int size, int index) {
|
||||
const auto rows = RowsCount(index);
|
||||
const auto width = kImagesPerRow * size;
|
||||
const auto height = rows * size;
|
||||
const auto fileSize = 4 * sizeof(uint32)
|
||||
+ (width * height * 4)
|
||||
+ openssl::kSha256Size;
|
||||
QFile f(CacheFilePath(size, index));
|
||||
if (!f.exists()
|
||||
|| f.size() != fileSize
|
||||
|| !f.open(QIODevice::ReadOnly)) {
|
||||
return QImage();
|
||||
}
|
||||
const auto read = [&](bytes::span data) {
|
||||
return f.read(
|
||||
reinterpret_cast<char*>(data.data()),
|
||||
data.size()
|
||||
) == data.size();
|
||||
};
|
||||
uint32 header[4] = { 0 };
|
||||
if (!read(bytes::make_span(header))
|
||||
|| header[0] != kVersion
|
||||
|| header[1] != size
|
||||
|| header[2] != width
|
||||
|| header[3] != height) {
|
||||
return QImage();
|
||||
}
|
||||
auto result = QImage(
|
||||
width,
|
||||
height,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
Assert(result.bytesPerLine() == width * 4);
|
||||
auto data = bytes::make_span(
|
||||
reinterpret_cast<bytes::type*>(result.bits()),
|
||||
width * height * 4);
|
||||
bytes::type signature[openssl::kSha256Size] = { bytes::type() };
|
||||
if (!read(data)
|
||||
|| !read(signature)
|
||||
|| (bytes::compare(
|
||||
signature,
|
||||
openssl::Sha256(bytes::make_span(header), data)) != 0)
|
||||
|| false) {
|
||||
return QImage();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void UniversalImages::ensureLoaded() {
|
||||
Expects(SpritesCount > 0);
|
||||
|
||||
if (!_sprites.empty()) {
|
||||
return;
|
||||
}
|
||||
_sprites.reserve(SpritesCount);
|
||||
const auto base = qsl(":/gui/emoji/emoji_");
|
||||
for (auto i = 0; i != SpritesCount; ++i) {
|
||||
auto image = QImage();
|
||||
image.load(base + QString::number(i + 1) + ".webp", "WEBP");
|
||||
_sprites.push_back(std::move(image));
|
||||
}
|
||||
}
|
||||
|
||||
void UniversalImages::clear() {
|
||||
_sprites.clear();
|
||||
}
|
||||
|
||||
void UniversalImages::draw(
|
||||
QPainter &p,
|
||||
EmojiPtr emoji,
|
||||
int size,
|
||||
int x,
|
||||
int y) const {
|
||||
Expects(emoji->sprite() < _sprites.size());
|
||||
|
||||
const auto factored = (size / p.device()->devicePixelRatio());
|
||||
const auto large = kUniversalSize;
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawImage(
|
||||
QRect(x, y, factored, factored),
|
||||
_sprites[emoji->sprite()],
|
||||
QRect(emoji->column() * large, emoji->row() * large, large, large));
|
||||
}
|
||||
|
||||
QImage UniversalImages::generate(int size, int index) const {
|
||||
Expects(size > 0);
|
||||
Expects(index < _sprites.size());
|
||||
|
||||
const auto rows = RowsCount(index);
|
||||
const auto large = kUniversalSize;
|
||||
const auto &original = _sprites[index];
|
||||
auto result = QImage(
|
||||
size * kImagesPerRow,
|
||||
size * rows,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
QPainter p(&result);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
for (auto y = 0; y != rows; ++y) {
|
||||
for (auto x = 0; x != kImagesPerRow; ++x) {
|
||||
p.drawImage(
|
||||
QRect(x * size, y * size, size, size),
|
||||
original,
|
||||
QRect(x * large, y * large, large, large));
|
||||
}
|
||||
}
|
||||
}
|
||||
SaveToFile(result, size, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
void AppendPartToResult(TextWithEntities &result, const QChar *start, const QChar *from, const QChar *to) {
|
||||
if (to <= from) {
|
||||
|
@ -62,23 +266,65 @@ EmojiPtr FindReplacement(const QChar *start, const QChar *end, int *outLength) {
|
|||
return internal::FindReplace(start, end, outLength);
|
||||
}
|
||||
|
||||
void ClearUniversalChecked() {
|
||||
Expects(InstanceNormal != nullptr && InstanceLarge != nullptr);
|
||||
|
||||
if (InstanceNormal->cached() && InstanceLarge->cached()) {
|
||||
Universal.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Init() {
|
||||
auto scaleForEmoji = cRetina() ? dbisTwo : cScale();
|
||||
|
||||
switch (scaleForEmoji) {
|
||||
case dbisOne: WorkingIndex = 0; break;
|
||||
case dbisOneAndQuarter: WorkingIndex = 1; break;
|
||||
case dbisOneAndHalf: WorkingIndex = 2; break;
|
||||
case dbisTwo: WorkingIndex = 3; break;
|
||||
};
|
||||
|
||||
internal::Init();
|
||||
|
||||
Scale = [] {
|
||||
if (cRetina()) {
|
||||
return 2.;
|
||||
}
|
||||
switch (cScale()) {
|
||||
case dbisOne: return 1.;
|
||||
case dbisOneAndQuarter: return 1.25;
|
||||
case dbisOneAndHalf: return 1.5;
|
||||
case dbisTwo: return 2.;
|
||||
}
|
||||
Unexpected("cScale() in Ui::Emoji::Init.");
|
||||
}();
|
||||
SizeNormal = int(std::round(Scale * 18));
|
||||
SizeLarge = int(std::round(Scale * 18 * 4 / 3.));
|
||||
const auto count = internal::FullCount();
|
||||
const auto persprite = kImagesPerRow * kImageRowsPerSprite;
|
||||
SpritesCount = (count / persprite) + ((count % persprite) ? 1 : 0);
|
||||
|
||||
InstanceNormal = std::make_unique<Instance>(SizeNormal);
|
||||
InstanceLarge = std::make_unique<Instance>(SizeLarge);
|
||||
}
|
||||
|
||||
int Index() {
|
||||
return WorkingIndex;
|
||||
void Clear() {
|
||||
MainEmojiMap.clear();
|
||||
OtherEmojiMap.clear();
|
||||
|
||||
InstanceNormal = nullptr;
|
||||
InstanceLarge = nullptr;
|
||||
}
|
||||
|
||||
int GetSizeNormal() {
|
||||
Expects(SizeNormal > 0);
|
||||
|
||||
return SizeNormal;
|
||||
}
|
||||
|
||||
int GetSizeLarge() {
|
||||
Expects(SizeLarge > 0);
|
||||
|
||||
return SizeLarge;
|
||||
}
|
||||
|
||||
float64 GetScale() {
|
||||
Expects(Scale > 0.);
|
||||
|
||||
return Scale;
|
||||
}
|
||||
|
||||
int One::variantsCount() const {
|
||||
|
@ -93,10 +339,6 @@ EmojiPtr One::variant(int index) const {
|
|||
return (index >= 0 && index <= variantsCount()) ? (original() + index) : this;
|
||||
}
|
||||
|
||||
int One::index() const {
|
||||
return (this - internal::ByIndex(0));
|
||||
}
|
||||
|
||||
QString IdFromOldKey(uint64 oldKey) {
|
||||
auto code = uint32(oldKey >> 32);
|
||||
auto code2 = uint32(oldKey & 0xFFFFFFFFLLU);
|
||||
|
@ -307,5 +549,110 @@ void AddRecent(EmojiPtr emoji) {
|
|||
}
|
||||
}
|
||||
|
||||
const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight) {
|
||||
auto &map = (fontHeight == st::msgFont->height)
|
||||
? MainEmojiMap
|
||||
: OtherEmojiMap[fontHeight];
|
||||
auto i = map.find(emoji->index());
|
||||
if (i == end(map)) {
|
||||
auto image = QImage(
|
||||
SizeNormal + st::emojiPadding * cIntRetinaFactor() * 2,
|
||||
fontHeight * cIntRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
if (cRetina()) {
|
||||
image.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
image.fill(Qt::transparent);
|
||||
{
|
||||
QPainter p(&image);
|
||||
Draw(
|
||||
p,
|
||||
emoji,
|
||||
SizeNormal,
|
||||
st::emojiPadding * cIntRetinaFactor(),
|
||||
(fontHeight * cIntRetinaFactor() - SizeNormal) / 2);
|
||||
}
|
||||
i = map.emplace(
|
||||
emoji->index(),
|
||||
App::pixmapFromImageInPlace(std::move(image))).first;
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
void Draw(QPainter &p, EmojiPtr emoji, int size, int x, int y) {
|
||||
if (size == SizeNormal) {
|
||||
InstanceNormal->draw(p, emoji, x, y);
|
||||
} else if (size == SizeLarge) {
|
||||
InstanceLarge->draw(p, emoji, x, y);
|
||||
} else {
|
||||
Unexpected("Size in Ui::Emoji::Draw.");
|
||||
}
|
||||
}
|
||||
|
||||
Instance::Instance(int size) : _size(size) {
|
||||
readCache();
|
||||
if (!cached()) {
|
||||
Universal.ensureLoaded();
|
||||
generateCache();
|
||||
}
|
||||
}
|
||||
|
||||
bool Instance::cached() const {
|
||||
return (_sprites.size() == SpritesCount);
|
||||
}
|
||||
|
||||
void Instance::draw(QPainter &p, EmojiPtr emoji, int x, int y) {
|
||||
const auto sprite = emoji->sprite();
|
||||
if (sprite >= _sprites.size()) {
|
||||
Universal.draw(p, emoji, _size, x, y);
|
||||
return;
|
||||
}
|
||||
p.drawPixmap(
|
||||
QPoint(x, y),
|
||||
_sprites[sprite],
|
||||
QRect(emoji->column() * _size, emoji->row() * _size, _size, _size));
|
||||
}
|
||||
|
||||
void Instance::readCache() {
|
||||
for (auto i = 0; i != SpritesCount; ++i) {
|
||||
auto image = LoadFromFile(_size, i);
|
||||
if (image.isNull()) {
|
||||
return;
|
||||
}
|
||||
pushSprite(std::move(image));
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::generateCache() {
|
||||
const auto size = _size;
|
||||
const auto index = _sprites.size();
|
||||
auto [left, right] = base::make_binary_guard();
|
||||
_generating = std::move(left);
|
||||
crl::async([=, guard = std::move(right)]() mutable {
|
||||
crl::on_main([
|
||||
this,
|
||||
image = Universal.generate(size, index),
|
||||
guard = std::move(guard)
|
||||
]() mutable {
|
||||
if (!guard.alive()) {
|
||||
return;
|
||||
}
|
||||
pushSprite(std::move(image));
|
||||
if (cached()) {
|
||||
ClearUniversalChecked();
|
||||
} else {
|
||||
generateCache();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::pushSprite(QImage &&data) {
|
||||
_sprites.push_back(App::pixmapFromImageInPlace(std::move(data)));
|
||||
if (cRetina()) {
|
||||
_sprites.back().setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Emoji
|
||||
} // namespace Ui
|
||||
|
|
|
@ -7,16 +7,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/text/text.h"
|
||||
#include "base/binary_guard.h"
|
||||
#include "emoji.h"
|
||||
|
||||
namespace Ui {
|
||||
namespace Emoji {
|
||||
|
||||
constexpr auto kPostfix = static_cast<ushort>(0xFE0F);
|
||||
constexpr auto kRecentLimit = 42;
|
||||
|
||||
void Init();
|
||||
void Clear();
|
||||
|
||||
int GetSizeNormal();
|
||||
int GetSizeLarge();
|
||||
float64 GetScale();
|
||||
|
||||
class One {
|
||||
struct CreationTag {
|
||||
|
@ -24,13 +28,12 @@ class One {
|
|||
|
||||
public:
|
||||
One(One &&other) = default;
|
||||
One(const QString &id, uint16 x, uint16 y, bool hasPostfix, bool colorizable, EmojiPtr original, const CreationTag &)
|
||||
One(const QString &id, EmojiPtr original, uint32 index, bool hasPostfix, bool colorizable, const CreationTag &)
|
||||
: _id(id)
|
||||
, _x(x)
|
||||
, _y(y)
|
||||
, _original(original)
|
||||
, _index(index)
|
||||
, _hasPostfix(hasPostfix)
|
||||
, _colorizable(colorizable)
|
||||
, _original(original) {
|
||||
, _colorizable(colorizable) {
|
||||
Expects(!_colorizable || !colored());
|
||||
}
|
||||
|
||||
|
@ -62,25 +65,29 @@ public:
|
|||
int variantIndex(EmojiPtr variant) const;
|
||||
EmojiPtr variant(int index) const;
|
||||
|
||||
int index() const;
|
||||
int index() const {
|
||||
return _index;
|
||||
}
|
||||
int sprite() const {
|
||||
return int(_index >> 9);
|
||||
}
|
||||
int row() const {
|
||||
return int((_index >> 5) & 0x0FU);
|
||||
}
|
||||
int column() const {
|
||||
return int(_index & 0x1FU);
|
||||
}
|
||||
|
||||
QString toUrl() const {
|
||||
return qsl("emoji://e.") + QString::number(index());
|
||||
}
|
||||
|
||||
int x() const {
|
||||
return _x;
|
||||
}
|
||||
int y() const {
|
||||
return _y;
|
||||
}
|
||||
|
||||
private:
|
||||
const QString _id;
|
||||
const uint16 _x = 0;
|
||||
const uint16 _y = 0;
|
||||
const EmojiPtr _original = nullptr;
|
||||
const uint32 _index = 0;
|
||||
const bool _hasPostfix = false;
|
||||
const bool _colorizable = false;
|
||||
const EmojiPtr _original = nullptr;
|
||||
|
||||
friend void internal::Init();
|
||||
|
||||
|
@ -123,25 +130,30 @@ inline int ColorIndexFromOldKey(uint64 oldKey) {
|
|||
return ColorIndexFromCode(uint32(oldKey & 0xFFFFFFFFLLU));
|
||||
}
|
||||
|
||||
inline int Size(int index = Index()) {
|
||||
int sizes[] = { 18, 22, 27, 36, 45 };
|
||||
return sizes[index];
|
||||
}
|
||||
|
||||
inline QString Filename(int index = Index()) {
|
||||
const char *EmojiNames[] = {
|
||||
":/gui/art/emoji.webp",
|
||||
":/gui/art/emoji_125x.webp",
|
||||
":/gui/art/emoji_150x.webp",
|
||||
":/gui/art/emoji_200x.webp",
|
||||
":/gui/art/emoji_250x.webp",
|
||||
};
|
||||
return QString::fromLatin1(EmojiNames[index]);
|
||||
}
|
||||
|
||||
void ReplaceInText(TextWithEntities &result);
|
||||
RecentEmojiPack &GetRecent();
|
||||
void AddRecent(EmojiPtr emoji);
|
||||
|
||||
const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight);
|
||||
void Draw(QPainter &p, EmojiPtr emoji, int size, int x, int y);
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
explicit Instance(int size);
|
||||
|
||||
bool cached() const;
|
||||
void draw(QPainter &p, EmojiPtr emoji, int x, int y);
|
||||
|
||||
private:
|
||||
void readCache();
|
||||
void generateCache();
|
||||
void pushSprite(QImage &&data);
|
||||
|
||||
int _size = 0;
|
||||
std::vector<QPixmap> _sprites;
|
||||
base::binary_guard _generating;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Emoji
|
||||
} // namespace Ui
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/empty_userpic.h"
|
||||
|
||||
#include "data/data_peer.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
namespace Ui {
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/click_handler_types.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "ui/text/text_block.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "boxes/confirm_box.h"
|
||||
|
@ -1441,7 +1442,12 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
emojiDraw(*_p, static_cast<EmojiBlock*>(currentBlock)->emoji, (glyphX + st::emojiPadding).toInt(), _y + _yDelta + emojiY);
|
||||
Ui::Emoji::Draw(
|
||||
*_p,
|
||||
static_cast<EmojiBlock*>(currentBlock)->emoji,
|
||||
Ui::Emoji::GetSizeNormal(),
|
||||
(glyphX + st::emojiPadding).toInt(),
|
||||
_y + _yDelta + emojiY);
|
||||
// } else if (_p && currentBlock->type() == TextBlockSkip) { // debug
|
||||
// _p->fillRect(QRect(x.toInt(), _y, currentBlock->width(), static_cast<SkipBlock*>(currentBlock)->height()), QColor(0, 0, 0, 32));
|
||||
}
|
||||
|
@ -3124,8 +3130,3 @@ void Text::clearFields() {
|
|||
}
|
||||
|
||||
Text::~Text() = default;
|
||||
|
||||
void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) {
|
||||
auto size = Ui::Emoji::Size();
|
||||
p.drawPixmap(QPoint(x, y), App::emoji(), QRect(e->x() * size, e->y() * size, size, size));
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "core/click_handler.h"
|
||||
#include "ui/text/text_entity.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "base/flags.h"
|
||||
|
||||
static const QChar TextCommand(0x0010);
|
||||
|
@ -376,5 +375,3 @@ inline bool chIsParagraphSeparator(QChar ch) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void emojiDraw(QPainter &p, EmojiPtr e, int x, int y);
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "auth_session.h"
|
||||
#include "lang/lang_tag.h"
|
||||
#include "base/qthelp_url.h"
|
||||
#include "ui/emoji_config.h"
|
||||
|
||||
namespace TextUtilities {
|
||||
namespace {
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/countryinput.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "emoji_suggestions_data.h"
|
||||
#include "chat_helpers/emoji_suggestions_helper.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
|
@ -529,7 +530,8 @@ QString AccumulateText(Iterator begin, Iterator end) {
|
|||
|
||||
QTextImageFormat PrepareEmojiFormat(EmojiPtr emoji, const QFont &font) {
|
||||
const auto factor = cIntRetinaFactor();
|
||||
const auto width = Ui::Emoji::Size() + st::emojiPadding * factor * 2;
|
||||
const auto width = Ui::Emoji::GetSizeNormal()
|
||||
+ st::emojiPadding * factor * 2;
|
||||
const auto height = QFontMetrics(font).height() * factor;
|
||||
auto result = QTextImageFormat();
|
||||
result.setWidth(width / factor);
|
||||
|
@ -1236,7 +1238,7 @@ bool InputField::viewportEventInner(QEvent *e) {
|
|||
QVariant InputField::loadResource(int type, const QUrl &name) {
|
||||
const auto imageName = name.toDisplayString();
|
||||
if (const auto emoji = Ui::Emoji::FromUrl(imageName)) {
|
||||
return QVariant(App::emojiSingle(emoji, _st.font->height));
|
||||
return QVariant(Ui::Emoji::SinglePixmap(emoji, _st.font->height));
|
||||
}
|
||||
return _inner->QTextEdit::loadResource(type, name);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "window/window_main_menu.h"
|
||||
#include "auth_session.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
|
@ -834,7 +835,7 @@ LayerStackWidget::~LayerStackWidget() {
|
|||
|
||||
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent, not_null<Window::Controller*> controller) : TWidget(parent)
|
||||
, _controller(controller)
|
||||
, _emojiSize(Ui::Emoji::Size(Ui::Emoji::Index() + 1) / cIntRetinaFactor()) {
|
||||
, _emojiSize(Ui::Emoji::GetSizeLarge() / cIntRetinaFactor()) {
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
|
||||
}
|
||||
|
@ -860,12 +861,17 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
|
|||
p.fillRect(r, st::stickerPreviewBg);
|
||||
p.drawPixmap((width() - w) / 2, (height() - h) / 2, image);
|
||||
if (!_emojiList.empty()) {
|
||||
auto emojiCount = _emojiList.size();
|
||||
auto emojiWidth = (emojiCount * _emojiSize) + (emojiCount - 1) * st::stickerEmojiSkip;
|
||||
const auto emojiCount = _emojiList.size();
|
||||
const auto emojiWidth = (emojiCount * _emojiSize) + (emojiCount - 1) * st::stickerEmojiSkip;
|
||||
auto emojiLeft = (width() - emojiWidth) / 2;
|
||||
auto esize = Ui::Emoji::Size(Ui::Emoji::Index() + 1);
|
||||
for (auto emoji : _emojiList) {
|
||||
p.drawPixmapLeft(emojiLeft, (height() - h) / 2 - (_emojiSize * 2), width(), App::emojiLarge(), QRect(emoji->x() * esize, emoji->y() * esize, esize, esize));
|
||||
const auto esize = Ui::Emoji::GetSizeLarge();
|
||||
for (const auto emoji : _emojiList) {
|
||||
Ui::Emoji::Draw(
|
||||
p,
|
||||
emoji,
|
||||
esize,
|
||||
emojiLeft,
|
||||
(height() - h) / 2 - (_emojiSize * 2));
|
||||
emojiLeft += _emojiSize + st::stickerEmojiSkip;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/themes/window_theme_preview.h"
|
||||
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "platform/platform_window_title.h"
|
||||
#include "ui/text_options.h"
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
'variables': {
|
||||
'qrc_files': [
|
||||
'<(res_loc)/qrc/telegram.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_large.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_1.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_2.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_3.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_4.qrc',
|
||||
'<(res_loc)/qrc/telegram_emoji_5.qrc',
|
||||
'<(res_loc)/qrc/telegram_sounds.qrc',
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue