1 // This file is part of Desktop App Toolkit,
2 // a set of libraries for developing nice desktop applications.
3 //
4 // For license and copyright information please follow this link:
5 // https://github.com/desktop-app/legal/blob/master/LEGAL
6 //
7 #pragma once
8
9 #include "base/basic_types.h"
10 #include "base/binary_guard.h"
11 #include "base/qt_adapters.h"
12 #include "emoji.h"
13
14 #include <QtGui/QPainter>
15 #include <QtGui/QPixmap>
16
17 #include <rpl/producer.h>
18
19 namespace Ui {
20 namespace Emoji {
21 namespace internal {
22
23 [[nodiscard]] QString CacheFileFolder();
24 [[nodiscard]] QString SetDataPath(int id);
25
26 } // namespace internal
27
28 void Init();
29 void Clear();
30
31 void ClearIrrelevantCache();
32
33 // Thread safe, callback is called on main thread.
34 void SwitchToSet(int id, Fn<void(bool)> callback);
35
36 [[nodiscard]] int CurrentSetId();
37 [[nodiscard]] int NeedToSwitchBackToId();
38 void ClearNeedSwitchToId();
39 [[nodiscard]] bool SetIsReady(int id);
40 [[nodiscard]] rpl::producer<> Updated();
41
42 [[nodiscard]] int GetSizeNormal();
43 [[nodiscard]] int GetSizeLarge();
44 #ifdef Q_OS_MAC
45 [[nodiscard]] int GetSizeTouchbar();
46 #endif
47
48 class One {
49 struct CreationTag {
50 };
51
52 public:
53 One(One &&other) = default;
One(const QString & id,EmojiPtr original,uint32 index,bool hasPostfix,bool colorizable,const CreationTag &)54 One(const QString &id, EmojiPtr original, uint32 index, bool hasPostfix, bool colorizable, const CreationTag &)
55 : _id(id)
56 , _original(original)
57 , _index(index)
58 , _hasPostfix(hasPostfix)
59 , _colorizable(colorizable) {
60 Expects(!_colorizable || !colored());
61 }
62
id()63 QString id() const {
64 return _id;
65 }
text()66 QString text() const {
67 return hasPostfix() ? (_id + QChar(kPostfix)) : _id;
68 }
69
colored()70 bool colored() const {
71 return (_original != nullptr);
72 }
original()73 EmojiPtr original() const {
74 return _original ? _original : this;
75 }
nonColoredId()76 QString nonColoredId() const {
77 return original()->id();
78 }
79
hasPostfix()80 bool hasPostfix() const {
81 return _hasPostfix;
82 }
83
hasVariants()84 bool hasVariants() const {
85 return _colorizable || colored();
86 }
87 int variantsCount() const;
88 int variantIndex(EmojiPtr variant) const;
89 EmojiPtr variant(int index) const;
90
index()91 int index() const {
92 return _index;
93 }
sprite()94 int sprite() const {
95 return int(_index >> 9);
96 }
row()97 int row() const {
98 return int((_index >> 5) & 0x0FU);
99 }
column()100 int column() const {
101 return int(_index & 0x1FU);
102 }
103
toUrl()104 QString toUrl() const {
105 return "emoji://e." + QString::number(index());
106 }
107
108 private:
109 const QString _id;
110 const EmojiPtr _original = nullptr;
111 const uint32 _index = 0;
112 const bool _hasPostfix = false;
113 const bool _colorizable = false;
114
115 friend void internal::Init();
116
117 };
118
FromUrl(const QString & url)119 [[nodiscard]] inline EmojiPtr FromUrl(const QString &url) {
120 auto start = qstr("emoji://e.");
121 if (url.startsWith(start)) {
122 return internal::ByIndex(base::StringViewMid(url, start.size()).toInt()); // skip emoji://e.
123 }
124 return nullptr;
125 }
126
127 [[nodiscard]] inline EmojiPtr Find(const QChar *start, const QChar *end, int *outLength = nullptr) {
128 return internal::Find(start, end, outLength);
129 }
130
131 [[nodiscard]] inline EmojiPtr Find(const QString &text, int *outLength = nullptr) {
132 return Find(text.constBegin(), text.constEnd(), outLength);
133 }
134
135 [[nodiscard]] QString IdFromOldKey(uint64 oldKey);
136
FromOldKey(uint64 oldKey)137 [[nodiscard]] inline EmojiPtr FromOldKey(uint64 oldKey) {
138 return Find(IdFromOldKey(oldKey));
139 }
140
ColorIndexFromCode(uint32 code)141 [[nodiscard]] inline int ColorIndexFromCode(uint32 code) {
142 switch (code) {
143 case 0xD83CDFFBU: return 1;
144 case 0xD83CDFFCU: return 2;
145 case 0xD83CDFFDU: return 3;
146 case 0xD83CDFFEU: return 4;
147 case 0xD83CDFFFU: return 5;
148 }
149 return 0;
150 }
151
ColorIndexFromOldKey(uint64 oldKey)152 [[nodiscard]] inline int ColorIndexFromOldKey(uint64 oldKey) {
153 return ColorIndexFromCode(uint32(oldKey & 0xFFFFFFFFLLU));
154 }
155
156 QVector<EmojiPtr> GetDefaultRecent();
157
158 const QPixmap &SinglePixmap(EmojiPtr emoji, int fontHeight);
159 void Draw(QPainter &p, EmojiPtr emoji, int size, int x, int y);
160
161 class UniversalImages {
162 public:
163 explicit UniversalImages(int id);
164
165 int id() const;
166 bool ensureLoaded();
167 void clear();
168
169 void draw(QPainter &p, EmojiPtr emoji, int size, int x, int y) const;
170
171 // This method must be thread safe and so it is called after
172 // the _id value is fixed and all _sprites are loaded.
173 QImage generate(int size, int index) const;
174
175 private:
176 const int _id = 0;
177 std::vector<QImage> _sprites;
178
179 };
180
181 [[nodiscard]] const std::shared_ptr<UniversalImages> &SourceImages();
182 void ClearSourceImages(const std::shared_ptr<UniversalImages> &images);
183
184 } // namespace Emoji
185 } // namespace Ui
186