This commit is contained in:
John Preston 2015-05-08 16:08:36 +03:00
commit 62e85b1cf0
42 changed files with 5919 additions and 6431 deletions

View File

@ -515,7 +515,7 @@
6DB9C3763D02B1415CD9D565 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
LastUpgradeCheck = 0630;
};
buildConfigurationList = DAC4C1AA5EDEA1C85E9CA5E6 /* Build configuration list for PBXProject "MetaEmoji" */;
compatibilityVersion = "Xcode 3.2";
@ -589,6 +589,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
@ -677,6 +678,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;

View File

@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_media_video" = "Video file";
"lng_media_audio" = "Voice message";
"lng_emoji_category0" = "Frequently used";
"lng_emoji_category1" = "People";
"lng_emoji_category2" = "Nature";
"lng_emoji_category3" = "Food & Drink";
"lng_emoji_category4" = "Celebration";
"lng_emoji_category5" = "Activity";
"lng_emoji_category6" = "Travel & Places";
"lng_emoji_category7" = "Objects & Symbols";
"lng_emoji_category8" = "Stickers";
"lng_in_dlg_photo" = "Photo";
"lng_in_dlg_video" = "Video";
"lng_in_dlg_contact" = "Contact";

View File

@ -21,7 +21,6 @@ semibold: 'Open Sans Semibold';
fsize: 13px;
spriteFile: ':/gui/art/sprite.png' / 2:':/gui/art/sprite_125x.png' / 3:':/gui/art/sprite_150x.png' / 4:':/gui/art/sprite_200x.png';
emojisFile: ':/gui/art/emoji.png' / 2:':/gui/art/emoji_125x.png' / 3:':/gui/art/emoji_150x.png' / 4:':/gui/art/emoji_200x.png';
emojiImgSize: 18px; // exceptional value for retina
emojiSize: 18px;
emojiPadding: 0px;
@ -123,9 +122,9 @@ sysUnlock: sysButton(sysUpd) {
img: sprite(207px, 22px, 19px, 19px);
}
titleBackButton: iconedButton(btnDefIconed) {
icon: sprite(133px, 197px, 13px, 20px);
icon: sprite(113px, 108px, 13px, 20px);
iconPos: point(5px, 9px);
downIcon: sprite(133px, 197px, 13px, 20px);
downIcon: sprite(113px, 108px, 13px, 20px);
downIconPos: point(5px, 10px);
bgColor: #c4d8e9;
@ -998,7 +997,7 @@ replyHeight: 49px;
replyTop: 8px;
replyBottom: 6px;
replyIconPos: point(13px, 13px);
replyIcon: sprite(174px, 195px, 24px, 24px);
replyIcon: sprite(343px, 197px, 24px, 24px);
replyCancel: iconedButton(btnDefIconed) {
icon: sprite(165px, 24px, 14px, 14px);
iconPos: point(17px, 17px);
@ -1009,7 +1008,7 @@ replyCancel: iconedButton(btnDefIconed) {
width: 49px;
height: 49px;
}
forwardIcon: sprite(368px, 173px, 24px, 24px);
forwardIcon: sprite(368px, 197px, 24px, 24px);
historyScroll: flatScroll(scrollDef) {
barColor: #89a0b47a;
@ -1460,33 +1459,39 @@ emojiScroll: flatScroll(scrollDef) {
topsh: 0px;
bottomsh: 0px;
}
emojiRecentActive: sprite(290px, 287px, 20px, 20px);
emojiRecentOver: sprite(311px, 287px, 20px, 20px);
emojiRecent: sprite(6px, 197px, 20px, 20px);
emojiPeopleActive: sprite(290px, 221px, 20px, 20px);
emojiPeopleOver: sprite(311px, 221px, 20px, 20px);
emojiRecentOver: sprite(290px, 221px, 20px, 20px);
emojiRecentActive: sprite(290px, 242px, 20px, 20px);
emojiPeople: sprite(27px, 197px, 20px, 20px);
emojiNatureActive: sprite(245px, 266px, 20px, 20px);
emojiNatureOver: sprite(266px, 266px, 20px, 20px);
emojiPeopleOver: sprite(311px, 221px, 20px, 20px);
emojiPeopleActive: sprite(311px, 242px, 20px, 20px);
emojiNature: sprite(48px, 197px, 20px, 20px);
emojiObjectsActive: sprite(290px, 242px, 20px, 20px);
emojiObjectsOver: sprite(311px, 242px, 20px, 20px);
emojiObjects: sprite(69px, 197px, 20px, 20px);
emojiPlacesActive: sprite(245px, 287px, 20px, 20px);
emojiPlacesOver: sprite(266px, 287px, 20px, 20px);
emojiPlaces: sprite(90px, 197px, 20px, 20px);
emojiSymbolsActive: sprite(290px, 266px, 20px, 20px);
emojiSymbolsOver: sprite(311px, 266px, 20px, 20px);
emojiSymbols: sprite(111px, 197px, 20px, 20px);
emojiStickersActive: sprite(311px, 308px, 20px, 20px);
emojiStickersOver: sprite(354px, 200px, 20px, 20px);
emojiStickers: sprite(375px, 200px, 20px, 20px);
emojiNatureOver: sprite(245px, 266px, 20px, 20px);
emojiNatureActive: sprite(245px, 287px, 20px, 20px);
emojiFood: sprite(69px, 197px, 20px, 20px);
emojiFoodOver: sprite(266px, 266px, 20px, 20px);
emojiFoodActive: sprite(266px, 287px, 20px, 20px);
emojiCelebration: sprite(90px, 197px, 20px, 20px);
emojiCelebrationOver: sprite(290px, 266px, 20px, 20px);
emojiCelebrationActive: sprite(290px, 287px, 20px, 20px);
emojiActivity: sprite(111px, 197px, 20px, 20px);
emojiActivityOver: sprite(311px, 266px, 20px, 20px);
emojiActivityActive: sprite(311px, 287px, 20px, 20px);
emojiTravel: sprite(132px, 197px, 20px, 20px);
emojiTravelOver: sprite(321px, 344px, 20px, 20px);
emojiTravelActive: sprite(321px, 365px, 20px, 20px);
emojiObjects: sprite(153px, 197px, 20px, 20px);
emojiObjectsOver: sprite(342px, 344px, 20px, 20px);
emojiObjectsActive: sprite(342px, 365px, 20px, 20px);
emojiStickers: sprite(174px, 197px, 20px, 20px);
emojiStickersOver: sprite(363px, 344px, 20px, 20px);
emojiStickersActive: sprite(363px, 365px, 20px, 20px);
rbEmoji: flatCheckbox {
textColor: transparent;
bgColor: transparent;
disColor: transparent;
width: 29px;
width: 28px;
height: 36px;
textTop: 0px;
@ -1523,6 +1528,38 @@ rbEmojiNature: flatCheckbox(rbEmoji) {
disImageRect: emojiNature;
chkDisImageRect: emojiNatureActive;
}
rbEmojiFood: flatCheckbox(rbEmoji) {
imageRect: emojiFood;
chkImageRect: emojiFoodActive;
overImageRect: emojiFoodOver;
chkOverImageRect: emojiFoodActive;
disImageRect: emojiFood;
chkDisImageRect: emojiFoodActive;
}
rbEmojiCelebration: flatCheckbox(rbEmoji) {
imageRect: emojiCelebration;
chkImageRect: emojiCelebrationActive;
overImageRect: emojiCelebrationOver;
chkOverImageRect: emojiCelebrationActive;
disImageRect: emojiCelebration;
chkDisImageRect: emojiCelebrationActive;
}
rbEmojiActivity: flatCheckbox(rbEmoji) {
imageRect: emojiActivity;
chkImageRect: emojiActivityActive;
overImageRect: emojiActivityOver;
chkOverImageRect: emojiActivityActive;
disImageRect: emojiActivity;
chkDisImageRect: emojiActivityActive;
}
rbEmojiTravel: flatCheckbox(rbEmoji) {
imageRect: emojiTravel;
chkImageRect: emojiTravelActive;
overImageRect: emojiTravelOver;
chkOverImageRect: emojiTravelActive;
disImageRect: emojiTravel;
chkDisImageRect: emojiTravelActive;
}
rbEmojiObjects: flatCheckbox(rbEmoji) {
imageRect: emojiObjects;
chkImageRect: emojiObjectsActive;
@ -1531,22 +1568,6 @@ rbEmojiObjects: flatCheckbox(rbEmoji) {
disImageRect: emojiObjects;
chkDisImageRect: emojiObjectsActive;
}
rbEmojiPlaces: flatCheckbox(rbEmoji) {
imageRect: emojiPlaces;
chkImageRect: emojiPlacesActive;
overImageRect: emojiPlacesOver;
chkOverImageRect: emojiPlacesActive;
disImageRect: emojiPlaces;
chkDisImageRect: emojiPlacesActive;
}
rbEmojiSymbols: flatCheckbox(rbEmoji) {
imageRect: emojiSymbols;
chkImageRect: emojiSymbolsActive;
overImageRect: emojiSymbolsOver;
chkOverImageRect: emojiSymbolsActive;
disImageRect: emojiSymbols;
chkDisImageRect: emojiSymbolsActive;
}
rbEmojiStickers: flatCheckbox(rbEmojiRecent) {
imageRect: emojiStickers;
chkImageRect: emojiStickersActive;
@ -1556,15 +1577,25 @@ rbEmojiStickers: flatCheckbox(rbEmojiRecent) {
chkDisImageRect: emojiStickersActive;
}
emojiPanPadding: margins(5px, 0px, 0px, 5px);
emojiPanSize: size(28px, 28px);
emojiPanSub: 0px;
emojiPanSize: size(35px, 35px);
emojiPanDuration: 200;
emojiPanHover: #f0f0f0;
emojiPanRound: 2px;
emojiPanHeader: 25px;
emojiPanHeaderFont: font(fsize semibold);
emojiPanHeaderColor: #999;
emojiPanHeaderLeft: 5px;
emojiPanHeaderTop: 5px;
emojiPanHeaderBg: #fffd;
emojiColorsPadding: 5px;
emojiColorsSep: 1px;
emojiColorsSepColor: #d5d5d5;
stickerPanRound: 3px;
stickerPanPadding: 2px;
stickerPanDelete: sprite(158px, 197px, 12px, 12px);
stickerPanDelete: sprite(123px, 132px, 12px, 12px);
stickerPanDeleteOpacity: 0.5;
mvBgColor: #222;
@ -1654,7 +1685,7 @@ mvDocLink: linkButton(btnDefLink) {
mvDeltaFromLastAction: 5px;
mvSwipeDistance: 80px;
medviewSaveMsgCheck: sprite(341px, 174px, 22px, 18px);
medviewSaveMsgCheck: sprite(311px, 309px, 22px, 18px);
medviewSaveMsgFont: font(16px);
medviewSaveMsgPadding: margins(55px, 19px, 29px, 20px);
medviewSaveMsgCheckPos: point(23px, 21px);
@ -1664,7 +1695,7 @@ medviewSaveMsgShown: 2000;
medviewSaveMsgHiding: 2500;
medviewSaveMsg: #000000b2;
mvTransparentBrush: sprite(148px, 197px, 8px, 8px);
mvTransparentBrush: sprite(113px, 128px, 8px, 8px);
overviewPhotoSkip: 10px;
overviewPhotoMinSize: 100px;

File diff suppressed because it is too large Load Diff

View File

@ -132,7 +132,7 @@ int main(int argc, const char * argv[]) {
}
if (update) {
writeLog(@"Starting update files iteration!");
writeLog([@"Starting update files iteration, path: " stringByAppendingString: [workDir stringByAppendingString:@"tupdates/ready"]]);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *srcDir = [workDir stringByAppendingString:@"tupdates/ready/"];
@ -142,6 +142,7 @@ int main(int argc, const char * argv[]) {
includingPropertiesForKeys:keys
options:0
errorHandler:^(NSURL *url, NSError *error) {
writeLog([[[@"Error in enumerating " stringByAppendingString:[url absoluteString]] stringByAppendingString: @" error is: "] stringByAppendingString: [error description]]);
return NO;
}];
for (NSURL *url in enumerator) {

View File

@ -73,9 +73,9 @@ namespace {
HistoryItem *hoveredItem = 0, *pressedItem = 0, *hoveredLinkItem = 0, *pressedLinkItem = 0, *contextItem = 0, *mousedItem = 0;
QPixmap *sprite = 0, *emojis = 0;
QPixmap *sprite = 0, *emojis = 0, *emojisLarge = 0;
typedef QMap<uint32, QPixmap> EmojisMap;
typedef QMap<uint64, QPixmap> EmojisMap;
EmojisMap mainEmojisMap;
QMap<int32, EmojisMap> otherEmojisMap;
@ -1528,11 +1528,15 @@ namespace App {
}
if (cRetina()) ::sprite->setDevicePixelRatio(cRetinaFactor());
}
emojiInit();
if (!::emojis) {
::emojis = new QPixmap(st::emojisFile);
::emojis = new QPixmap(QLatin1String(EName));
if (cRetina()) ::emojis->setDevicePixelRatio(cRetinaFactor());
}
initEmoji();
if (!::emojisLarge) {
::emojisLarge = new QPixmap(QLatin1String(EmojiNames[EIndex + 1]));
if (cRetina()) ::emojisLarge->setDevicePixelRatio(cRetinaFactor());
}
}
void deinitMedia(bool completely) {
@ -1548,6 +1552,8 @@ namespace App {
::sprite = 0;
delete ::emojis;
::emojis = 0;
delete ::emojisLarge;
::emojisLarge = 0;
mainEmojisMap.clear();
otherEmojisMap.clear();
@ -1616,19 +1622,25 @@ namespace App {
return *::emojis;
}
const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight) {
const QPixmap &emojisLarge() {
return *::emojisLarge;
}
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight) {
EmojisMap *map = &(fontHeight == st::taDefFlat.font->height ? mainEmojisMap : otherEmojisMap[fontHeight]);
EmojisMap::const_iterator i = map->constFind(emoji->code);
EmojisMap::const_iterator i = map->constFind(emojiKey(emoji));
if (i == map->cend()) {
QImage img(st::emojiImgSize + st::emojiPadding * cIntRetinaFactor() * 2, fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
QImage img(ESize + st::emojiPadding * cIntRetinaFactor() * 2, fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
if (cRetina()) img.setDevicePixelRatio(cRetinaFactor());
{
QPainter p(&img);
QPainter::CompositionMode m = p.compositionMode();
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(0, 0, img.width(), img.height(), Qt::transparent);
p.drawPixmap(QPoint(st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - st::emojiImgSize) / 2), App::emojis(), QRect(emoji->x, emoji->y, st::emojiImgSize, st::emojiImgSize));
p.setCompositionMode(m);
emojiDraw(p, emoji, st::emojiPadding * cIntRetinaFactor(), (fontHeight * cIntRetinaFactor() - ESize) / 2);
}
i = map->insert(emoji->code, QPixmap::fromImage(img, Qt::ColorOnly));
i = map->insert(emojiKey(emoji), QPixmap::fromImage(img, Qt::ColorOnly));
}
return i.value();
}

View File

@ -156,7 +156,8 @@ namespace App {
const QPixmap &sprite();
const QPixmap &emojis();
const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight);
const QPixmap &emojisLarge();
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight);
void initMedia();
void deinitMedia(bool completely = true);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 956 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 219 KiB

View File

@ -84,7 +84,7 @@ void EmojiBox::fillBlocks() {
BlockRow currentRow;
currentRow.reserve(replacesInRow);
for (uint32 i = 0; i < replacesCount; ++i) {
Block block(getEmoji(replaces[i].code), QString::fromUtf8(replaces[i].replace));
Block block(emojiGet(replaces[i].code), QString::fromUtf8(replaces[i].replace));
currentRow.push_back(block);
if (uint32(currentRow.size()) == replacesInRow) {
_blocks.push_back(currentRow);
@ -125,8 +125,7 @@ void EmojiBox::paintEvent(QPaintEvent *e) {
int32 rowSize = i->size(), left = (width() - rowSize * st::emojiReplaceWidth) / 2;
for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) {
if (j->emoji) {
QPoint pos(left + (st::emojiReplaceWidth - st::emojiSize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2);
p.drawPixmap(pos, App::emojis(), QRect(j->emoji->x, j->emoji->y, st::emojiImgSize, st::emojiImgSize));
emojiDraw(p, j->emoji, left + (st::emojiReplaceWidth - st::emojiSize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2);
}
QRect trect(left, top + (st::emojiReplaceHeight + _blockHeight) / 2 - st::emojiTextFont->height, st::emojiReplaceWidth, st::emojiTextFont->height);
p.drawText(trect, j->text, QTextOption(Qt::AlignHCenter | Qt::AlignTop));

File diff suppressed because it is too large Load Diff

View File

@ -132,7 +132,68 @@ private:
};
class EmojiPanInner : public QWidget, public Animated {
static const int EmojiColorsCount = 5;
class EmojiColorPicker : public TWidget, public Animated {
Q_OBJECT
public:
EmojiColorPicker(QWidget *parent);
void showEmoji(uint32 code);
void paintEvent(QPaintEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
bool animStep(float64 ms);
void showStart();
void clearSelection(bool fast = false);
public slots:
void hideStart(bool fast = false);
signals:
void emojiSelected(EmojiPtr emoji);
void hidden();
private:
void drawVariant(Painter &p, int variant);
void updateSelected();
bool _ignoreShow;
EmojiPtr _variants[EmojiColorsCount + 1];
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
EmojiAnimations _emojiAnimations;
float64 _hovers[EmojiColorsCount + 1];
int32 _selected, _pressedSel;
QPoint _lastMousePos;
bool _hiding;
QPixmap _cache;
anim::fvalue a_opacity;
QTimer _hideTimer;
BoxShadow _shadow;
};
class EmojiPanInner : public TWidget, public Animated {
Q_OBJECT
public:
@ -145,39 +206,67 @@ public:
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void leaveEvent(QEvent *e);
void leaveToChildEvent(QEvent *e);
void enterFromChildEvent(QEvent *e);
bool animStep(float64 ms);
void hideFinish();
void showEmojiPack(DBIEmojiTab packIndex);
void clearSelection(bool fast = false);
DBIEmojiTab currentTab(int yOffset) const;
void refreshStickers();
void refreshRecent();
void setScrollTop(int top);
public slots:
void updateSelected();
void onSaveConfig();
void onShowPicker();
void onPickerHidden();
void onColorSelected(EmojiPtr emoji);
signals:
void emojiSelected(EmojiPtr emoji);
void stickerSelected(DocumentData *sticker);
void scrollToY(int y);
void disableScroll(bool dis);
private:
int countHeight();
void selectEmoji(EmojiPtr emoji);
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
EmojiAnimations _emojiAnimations;
int _top;
int _counts[emojiTabCount], _count;
StickerPack _stickers;
QVector<bool> _isUserGen;
QVector<EmojiPtr> _emojis;
QVector<float64> _hovers;
QVector<EmojiPtr> _emojis[emojiTabCount];
QVector<float64> _hovers[emojiTabCount + 1]; // + stickers hovers and stickers-x hovers
DBIEmojiTab _tab;
int32 _selected, _xSelected, _pressedSel, _xPressedSel;
float64 _stickerWidth;
int32 _esize, _stickerSize;
int32 _selected, _pressedSel, _pickerSel;
QPoint _lastMousePos;
QTimer _saveConfigTimer;
EmojiColorPicker _picker;
QTimer _showPickerTimer;
};
class EmojiPan : public TWidget, public Animated {
@ -203,6 +292,8 @@ public:
bool eventFilter(QObject *obj, QEvent *e);
void refreshStickers();
public slots:
void hideStart();
@ -212,6 +303,7 @@ public slots:
void onWndActiveChanged();
void onTabChange();
void onScroll();
signals:
@ -224,6 +316,8 @@ private:
void showAll();
void hideAll();
bool _noTabUpdate;
int32 _width, _height;
bool _hiding;
QPixmap _cache;
@ -234,7 +328,7 @@ private:
BoxShadow _shadow;
FlatRadiobutton _recent, _people, _nature, _objects, _places, _symbols, _stickers;
FlatRadiobutton _recent, _people, _nature, _food, _celebration, _activity, _travel, _objects, _stickers;
int32 _emojiPack;
ScrollArea _scroll;

File diff suppressed because it is too large Load Diff

View File

@ -19,10 +19,94 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "gui/text.h"
void initEmoji();
EmojiPtr getEmoji(uint32 code);
void emojiInit();
EmojiPtr emojiGet(uint32 code);
EmojiPtr emojiGet(uint32 code, uint32 code2);
EmojiPtr emojiGet(EmojiPtr emoji, uint32 color);
EmojiPtr emojiGet(const QChar *from, const QChar *end);
QString emojiGetSequence(int index);
void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint32 &emojiCode);
inline uint64 emojiKey(EmojiPtr emoji) {
uint64 key = emoji->code;
if (emoji->code2) {
key = (key << 32) | uint64(emoji->code2);
} else if (emoji->color && ((emoji->color & 0xFFFF0000U) != 0xFFFF0000U)) {
key = (key << 32) | uint64(emoji->color);
}
return key;
}
inline EmojiPtr emojiFromKey(uint64 key) {
uint32 code = uint32(key >> 32), code2 = uint32(key & 0xFFFFFFFFLLU);
if (!code && code2) {
code = code2;
code2 = 0;
}
EmojiPtr emoji = emojiGet(code);
if (emoji == TwoSymbolEmoji) {
return emojiGet(code, code2);
} else if (emoji && emoji->color && code2) {
return emojiGet(emoji, code2);
}
return emoji;
}
inline EmojiPtr emojiFromUrl(const QString &url) {
return emojiFromKey(url.midRef(10).toULongLong(0, 16)); // skip emoji://e.
}
inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
QString tmp(ch, e - ch);
QByteArray tmp2 = tmp.toUtf8();
const char *tmp3 = tmp2.constData();
EmojiPtr emoji = 0;
if (ch + 1 < e && ((ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) || (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3))) {
uint32 code = (ch->unicode() << 16) | (ch + 1)->unicode();
emoji = emojiGet(code);
if (emoji) {
if (emoji == TwoSymbolEmoji) { // check two symbol
if (ch + 3 >= e) {
emoji = 0;
} else {
uint32 code2 = ((uint32((ch + 2)->unicode()) << 16) | uint32((ch + 3)->unicode()));
emoji = emojiGet(code, code2);
}
} else {
if (ch + 2 < e && (ch + 2)->unicode() == 0x200D) { // check sequence
EmojiPtr seq = emojiGet(ch, e);
if (seq) {
emoji = seq;
}
}
}
}
} else if (ch < e) {
emoji = emojiGet(ch->unicode());
Q_ASSERT(emoji != TwoSymbolEmoji);
}
if (emoji) {
len = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
if (emoji->color && (ch + len + 1 < e && (ch + len)->isHighSurrogate() && (ch + len + 1)->isLowSurrogate())) { // color
uint32 color = ((uint32((ch + len)->unicode()) << 16) | uint32((ch + len + 1)->unicode()));
EmojiPtr col = emojiGet(emoji, color);
if (col && col != emoji) {
len += col->len - emoji->len;
emoji = col;
if (ch + len < e && (ch + len)->unicode() == 0xFE0F) {
++len;
}
}
}
}
return emoji;
}
extern int EmojiSizes[5], EIndex, ESize;
extern const char *EmojiNames[5], *EName;
void emojiFind(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint32 &emojiCode);
inline bool emojiEdge(const QChar *ch) {
return true;
@ -48,7 +132,7 @@ inline QString replaceEmojis(const QString &text) {
uint32 emojiCode = 0;
const QChar *newEmojiEnd = 0;
if (canFindEmoji) {
findEmoji(ch, e, newEmojiEnd, emojiCode);
emojiFind(ch, e, newEmojiEnd, emojiCode);
}
while (currentLink < lnkCount && ch >= lnkRanges[currentLink].from + lnkRanges[currentLink].len) {
@ -91,4 +175,5 @@ inline QString replaceEmojis(const QString &text) {
return result;
}
int emojiPackCount(DBIEmojiTab tab);
EmojiPack emojiPack(DBIEmojiTab tab);

View File

@ -174,8 +174,7 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
if (!text.isEmpty()) {
QTextCharFormat format = fragment.charFormat();
QString imageName = static_cast<const QTextImageFormat*>(&format)->name();
return getEmoji(imageName.mid(8).toUInt(0, 16));
return emojiFromUrl(static_cast<const QTextImageFormat*>(&format)->name());
}
return 0;
}
@ -288,7 +287,7 @@ void FlatTextarea::getSingleEmojiFragment(QString &text, QTextFragment &fragment
}
if (f.isImageFormat() && !t.isEmpty() && t.at(0).unicode() == QChar::ObjectReplacementCharacter) {
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
if (imageName.midRef(0, 8) == qsl("emoji://")) {
if (imageName.startsWith(QLatin1String("emoji://e."))) {
fragment = fr;
text = t;
return;
@ -372,10 +371,8 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
case QChar::ObjectReplacementCharacter:
if (emojiText.isEmpty() && f.isImageFormat()) {
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
if (imageName.midRef(0, 8) == qsl("emoji://")) {
uint32 index = imageName.mid(8).toUInt(0, 16);
const EmojiData *emoji = getEmoji(index);
if (emoji) {
if (imageName.startsWith(QLatin1String("emoji://e."))) {
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
emojiText = textEmojiString(emoji);
}
}
@ -520,7 +517,7 @@ void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) {
c.removeSelectedText();
QPixmap img(App::emojiSingle(emoji, _st.font->height));
QString url = qsl("emoji://") + QString::number(emoji->code, 16);
QString url = qsl("emoji://e.") + QString::number(emojiKey(emoji), 16);
document()->addResource(QTextDocument::ImageResource, QUrl(url), QVariant(img));
QTextImageFormat imageFormat;
imageFormat.setWidth(img.width() / cIntRetinaFactor());
@ -546,33 +543,20 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
QTextFragment fragment(iter.fragment());
if (!fragment.isValid()) continue;
int32 p = fragment.position(), e = p + fragment.length();
if (p >= end || e <= start) {
int32 fp = fragment.position(), fe = fp + fragment.length();
if (fp >= end || fe <= start) {
continue;
}
QString t(fragment.text());
for (const QChar *ch = t.constData(), *e = ch + t.size(); ch != e; ++ch) {
if (ch + 1 < e && (ch->isHighSurrogate() || (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3))) {
emoji = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
if (emoji) {
if (emoji->len == 4 && (ch + 3 >= e || ((uint32((ch + 2)->unicode()) << 16) | uint32((ch + 3)->unicode())) != emoji->code2)) {
emoji = 0;
} else {
emojiPosition = p + (ch - t.constData());
emojiLen = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
break;
}
}
++ch;
} else {
emoji = getEmoji(ch->unicode());
if (emoji) {
emojiPosition = p + (ch - t.constData());
emojiLen = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
break;
}
const QChar *ch = t.constData(), *e = ch + t.size();
for (; ch != e; ++ch) {
emoji = emojiFromText(ch, e, emojiLen);
if (emoji) {
emojiPosition = fp + (ch - t.constData());
break;
}
if (ch + 1 < e && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
}
if (emoji) break;
}

View File

@ -94,7 +94,7 @@ void ScrollBar::updateBar(bool force) {
}
if (newBar != _bar) {
_bar = newBar;
update();
parentWidget()->update(geometry());
}
if (_vertical) {
bool newTopSh = (_st->topsh < 0) || (_area->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (_area->scrollTop() < _area->scrollTopMax() - _st->bottomsh);
@ -143,7 +143,7 @@ bool ScrollBar::animStep(float64 ms) {
a_bg.update(dt, anim::linear);
a_bar.update(dt, anim::linear);
}
update();
parentWidget()->update(geometry());
return res;
}
@ -253,19 +253,16 @@ void ScrollBar::resizeEvent(QResizeEvent *e) {
}
ScrollArea::ScrollArea(QWidget *parent, const style::flatScroll &st, bool handleTouch) : QScrollArea(parent),
_st(st),
_disabled(false), _st(st),
hor(this, false, &_st), vert(this, true, &_st), topSh(this, &_st), bottomSh(this, &_st),
_touchEnabled(handleTouch), _touchScroll(false), _touchPress(false), _touchRightButton(false),
_touchScrollState(TouchScrollManual), _touchPrevPosValid(false), _touchWaitingAcceleration(false),
_touchSpeedTime(0), _touchAccelerationTime(0), _touchTime(0), _widgetAcceptsTouch(false) {
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrolled()));
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrolled()));
connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onScrolled()));
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onScrolled()));
connect(&vert, SIGNAL(topShadowVisibility(bool)), &topSh, SLOT(changeVisibility(bool)));
connect(&vert, SIGNAL(bottomShadowVisibility(bool)), &bottomSh, SLOT(changeVisibility(bool)));
vert.updateBar(true);
if (_st.hiding) {
connect(this, SIGNAL(scrolled()), this, SLOT(onScrolled()));
}
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -292,19 +289,31 @@ void ScrollArea::touchDeaccelerate(int32 elapsed) {
}
void ScrollArea::onScrolled() {
bool em = false;
int32 horValue = horizontalScrollBar()->value(), vertValue = verticalScrollBar()->value();
if (_horValue != horValue) {
_horValue = horValue;
if (_st.hiding) {
hor.hideTimeout(_st.hiding);
if (_disabled) {
horizontalScrollBar()->setValue(_horValue);
} else {
_horValue = horValue;
if (_st.hiding) {
hor.hideTimeout(_st.hiding);
}
em = true;
}
}
if (_vertValue != vertValue) {
_vertValue = vertValue;
if (_st.hiding) {
vert.hideTimeout(_st.hiding);
if (_disabled) {
verticalScrollBar()->setValue(_vertValue);
} else {
_vertValue = vertValue;
if (_st.hiding) {
vert.hideTimeout(_st.hiding);
}
em = true;
}
}
if (em) emit scrolled();
}
int ScrollArea::scrollWidth() const {
@ -528,6 +537,21 @@ void ScrollArea::touchScrollUpdated(const QPoint &screenPos) {
touchUpdateSpeed();
}
void ScrollArea::disableScroll(bool dis) {
_disabled = dis;
if (_disabled) {
hor.hideTimeout(0);
vert.hideTimeout(0);
}
}
void ScrollArea::scrollContentsBy(int dx, int dy) {
if (_disabled) {
return;
}
QScrollArea::scrollContentsBy(dx, dy);
}
bool ScrollArea::touchScroll(const QPoint &delta) {
int32 scTop = scrollTop(), scMax = scrollTopMax(), scNew = snap(scTop - delta.y(), 0, scMax);
if (scNew == scTop) return false;
@ -559,6 +583,7 @@ void ScrollArea::keyPressEvent(QKeyEvent *e) {
}
void ScrollArea::enterEvent(QEvent *e) {
if (_disabled) return;
if (_st.hiding) {
hor.hideTimeout(_st.hiding);
vert.hideTimeout(_st.hiding);

View File

@ -134,6 +134,7 @@ public:
public slots:
void scrollToY(int toTop, int toBottom = -1);
void disableScroll(bool dis);
void onScrolled();
void onTouchTimer();
@ -146,6 +147,10 @@ signals:
void scrollFinished();
void geometryChanged();
protected:
void scrollContentsBy(int dx, int dy);
private:
bool touchScroll(const QPoint &delta);
@ -156,6 +161,8 @@ private:
void touchUpdateSpeed();
void touchDeaccelerate(int32 elapsed);
bool _disabled;
style::flatScroll _st;
ScrollBar hor, vert;
ScrollShadow topSh, bottomSh;

View File

@ -240,20 +240,25 @@ const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink)
}
QString textEmojiString(EmojiPtr emoji) {
if ((emoji->code & 0xFFFF0000U) == 0xFFFF0000U) { // sequence
return emojiGetSequence(emoji->code & 0xFFFFU);
}
QString result;
result.reserve(emoji->len + (emoji->postfix ? 1 : 0));
switch (emoji->len) {
case 1: result.append(QChar(emoji->code & 0xFFFF)); break;
case 2:
if (!(emoji->code >> 16)) {
result.append(QChar(emoji->code & 0xFFFF));
} else {
result.append(QChar((emoji->code >> 16) & 0xFFFF));
result.append(QChar(emoji->code & 0xFFFF));
break;
case 4:
result.append(QChar((emoji->code >> 16) & 0xFFFF));
result.append(QChar(emoji->code & 0xFFFF));
result.append(QChar((emoji->code2 >> 16) & 0xFFFF));
result.append(QChar(emoji->code2 & 0xFFFF));
break;
if (emoji->code2) {
result.append(QChar((emoji->code2 >> 16) & 0xFFFF));
result.append(QChar(emoji->code2 & 0xFFFF));
}
}
if (emoji->color && ((emoji->color & 0xFFFF0000U) != 0xFFFF0000U)) {
result.append(QChar((emoji->color >> 16) & 0xFFFF));
result.append(QChar(emoji->color & 0xFFFF));
}
if (emoji->postfix) result.append(QChar(emoji->postfix));
return result;
@ -515,24 +520,15 @@ public:
}
void parseEmojiFromCurrent() {
const EmojiData *e = getEmoji(chInt);
int len = 0, skipped = (chInt > 0xFFFFU) ? 1 : 0;
EmojiPtr e = emojiFromText(ptr - skipped, end, len);
if (!e) return;
if (e->len > 2) {
if (ptr + 2 >= end || e->code2 != ((uint32((ptr + 1)->unicode()) << 16) | uint32((ptr + 2)->unicode()))) {
return;
} else {
_t->_text.push_back(*++ptr);
_t->_text.push_back(*++ptr);
}
}
int emojiLen = e->len;
if (ptr + 1 < end && (ptr + 1)->unicode() == 0xFE0F) {
for (int l = len - skipped - 1; l > 0; --l) {
_t->_text.push_back(*++ptr);
++emojiLen;
}
createBlock(-emojiLen);
createBlock(-len);
emoji = e;
}
@ -1326,7 +1322,7 @@ public:
}
}
}
_p->drawPixmap(QPoint((glyphX + int(st::emojiPadding)).toInt(), _y + _yDelta + emojiY), App::emojis(), QRect(static_cast<EmojiBlock*>(currentBlock)->emoji->x, static_cast<EmojiBlock*>(currentBlock)->emoji->y, st::emojiImgSize, st::emojiImgSize));
emojiDraw(*_p, static_cast<EmojiBlock*>(currentBlock)->emoji, (glyphX + int(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));
}
@ -4050,29 +4046,19 @@ bool textSplit(QString &sendingText, QString &leftText, int32 limit) {
}
}
}
EmojiPtr e = 0;
if (ch->isHighSurrogate()) {
if (ch + 1 < end && (ch + 1)->isLowSurrogate()) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
if (!e) {
++ch;
}
}
} else {
if (ch + 1 < end) {
if (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
} else if ((ch + 1)->unicode() == 0xFE0F) {
e = getEmoji(ch->unicode());
}
}
}
int elen = 0;
EmojiPtr e = emojiFromText(ch, end, elen);
if (e) {
ch += (e->len - 1);
if (ch + 1 < end && (ch + 1)->unicode() == 0xFE0F) {
++ch;
++s;
for (int i = 0; i < elen; ++i, ++ch, ++s) {
if (ch->isHighSurrogate() && i + 1 < elen && (ch + 1)->isLowSurrogate()) {
++ch;
++i;
}
}
--ch;
--s;
} else if (ch->isHighSurrogate() && ch + 1 < end && (ch + 1)->isLowSurrogate()) {
++ch;
}
if (s >= limit) {
sendingText = leftText.mid(0, good - start);
@ -4250,3 +4236,7 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich) { // some
return lnkRanges;
}
void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) {
p.drawPixmap(QPoint(x, y), App::emojis(), QRect(e->x * ESize, e->y * ESize, ESize, ESize));
}

View File

@ -49,6 +49,8 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich = false);
#include "gui/emoji_config.h"
void emojiDraw(QPainter &p, EmojiPtr e, int x, int y);
#include "../../../QtStatic/qtbase/src/gui/text/qfontengine_p.h"
enum TextBlockType {

View File

@ -3448,9 +3448,9 @@ void HistoryWebPage::draw(QPainter &p, const HistoryItem *parent, bool selected,
p.fillRect(QRect(width - pixwidth, 0, pixwidth, pixheight), st::black->b);
}
if (_pixw > pixwidth) {
p.drawPixmap(QRect(width - pixwidth, (pixheight - _pixh) / 2, pixwidth, _pixh), pix, QRect((_pixw - pixwidth) / 2, 0, pixwidth, _pixh));
p.drawPixmap(QRect(width - pixwidth, (pixheight - _pixh) / 2, pixwidth, _pixh), pix, QRect(cIntRetinaFactor() * (_pixw - pixwidth) / 2, 0, cIntRetinaFactor() * pixwidth, cIntRetinaFactor() * _pixh));
} else if (_pixh > pixheight) {
p.drawPixmap(QRect(width - pixwidth + (pixwidth - _pixw) / 2, 0, _pixw, pixheight), pix, QRect(0, (_pixh - pixheight) / 2, _pixw, pixheight));
p.drawPixmap(QRect(width - pixwidth + (pixwidth - _pixw) / 2, 0, _pixw, pixheight), pix, QRect(0, cIntRetinaFactor() * (_pixh - pixheight) / 2, cIntRetinaFactor() * _pixw, cIntRetinaFactor() * pixheight));
} else {
p.drawPixmap(QPoint(width - pixwidth + (pixwidth - _pixw) / 2, (pixheight - _pixh) / 2), pix);
}

View File

@ -1763,9 +1763,7 @@ void HistoryWidget::updateTyping(bool typing) {
//}
void HistoryWidget::updateRecentStickers() {
if (cEmojiTab() == dbietStickers) {
_emojiPan.onTabChange();
}
_emojiPan.refreshStickers();
}
void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) {
@ -1852,7 +1850,6 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
}
cSetRecentStickers(add);
Local::writeRecentStickers();
_emojiPan.onTabChange();
}
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
@ -1862,23 +1859,11 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
QString emoticon(qs(p.vemoticon));
EmojiPtr e = 0;
for (const QChar *ch = emoticon.constData(), *end = emoticon.constEnd(); ch != end; ++ch) {
if (ch->isHighSurrogate()) {
if (ch + 1 < end && (ch + 1)->isLowSurrogate()) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
if (!e) {
++ch;
}
}
} else {
if (ch + 1 < end) {
if (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
} else if ((ch + 1)->unicode() == 0xFE0F) {
e = getEmoji(ch->unicode());
}
}
}
int len = 0;
e = emojiFromText(ch, end, len);
if (e) break;
if (ch + 1 < end && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
}
if (e) {
const QVector<MTPlong> docs(p.vdocuments.c_vector().v);
@ -1912,7 +1897,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
}
// updateStickerPan();
_emojiPan.onTabChange();
_emojiPan.refreshStickers();
}
}

View File

@ -905,24 +905,62 @@ namespace {
if (!_checkStreamStatus(stream)) return false;
switch (v) {
case dbietRecent: cSetEmojiTab(dbietRecent); break;
case dbietPeople: cSetEmojiTab(dbietPeople); break;
case dbietNature: cSetEmojiTab(dbietNature); break;
case dbietObjects: cSetEmojiTab(dbietObjects); break;
case dbietPlaces: cSetEmojiTab(dbietPlaces); break;
case dbietSymbols: cSetEmojiTab(dbietSymbols); break;
case dbietStickers: cSetEmojiTab(dbietStickers); break;
case dbietRecent : cSetEmojiTab(dbietRecent ); break;
case dbietPeople : cSetEmojiTab(dbietPeople ); break;
case dbietNature : cSetEmojiTab(dbietNature ); break;
case dbietFood : cSetEmojiTab(dbietFood ); break;
case dbietCelebration: cSetEmojiTab(dbietCelebration); break;
case dbietActivity : cSetEmojiTab(dbietActivity ); break;
case dbietTravel : cSetEmojiTab(dbietTravel ); break;
case dbietObjects : cSetEmojiTab(dbietObjects ); break;
case dbietStickers : cSetEmojiTab(dbietStickers ); break;
}
} break;
case dbiRecentEmojisOld: {
RecentEmojisPreloadOld v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
if (!v.isEmpty()) {
RecentEmojisPreload p;
p.reserve(v.size());
for (int i = 0; i < v.size(); ++i) {
uint64 e(v.at(i).first);
switch (e) {
case 0xD83CDDEFLLU: e = 0xD83CDDEFD83CDDF5LLU; break;
case 0xD83CDDF0LLU: e = 0xD83CDDF0D83CDDF7LLU; break;
case 0xD83CDDE9LLU: e = 0xD83CDDE9D83CDDEALLU; break;
case 0xD83CDDE8LLU: e = 0xD83CDDE8D83CDDF3LLU; break;
case 0xD83CDDFALLU: e = 0xD83CDDFAD83CDDF8LLU; break;
case 0xD83CDDEBLLU: e = 0xD83CDDEBD83CDDF7LLU; break;
case 0xD83CDDEALLU: e = 0xD83CDDEAD83CDDF8LLU; break;
case 0xD83CDDEELLU: e = 0xD83CDDEED83CDDF9LLU; break;
case 0xD83CDDF7LLU: e = 0xD83CDDF7D83CDDFALLU; break;
case 0xD83CDDECLLU: e = 0xD83CDDECD83CDDE7LLU; break;
}
p.push_back(qMakePair(e, v.at(i).second));
}
cSetRecentEmojisPreload(p);
}
} break;
case dbiRecentEmojis: {
RecentEmojiPreload v;
RecentEmojisPreload v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetRecentEmojisPreload(v);
} break;
case dbiEmojiVariants: {
EmojiColorVariants v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
cSetEmojiVariants(v);
} break;
case dbiDialogLastPath: {
QString path;
stream >> path;
@ -1140,7 +1178,8 @@ namespace {
uint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
size += sizeof(quint32) + sizeof(qint32) + cGetRecentEmojis().size() * (sizeof(uint32) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cGetRecentEmojis().size() * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
size += sizeof(quint32) + _stringSize(cDialogLastPath());
EncryptedDescriptor data(size);
@ -1158,13 +1197,15 @@ namespace {
data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
RecentEmojiPreload v;
RecentEmojisPreload v;
v.reserve(cGetRecentEmojis().size());
for (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) {
v.push_back(qMakePair(i->first->code, i->second));
v.push_back(qMakePair(emojiKey(i->first), i->second));
}
data.stream << quint32(dbiRecentEmojis) << v;
data.stream << quint32(dbiEmojiVariants) << cEmojiVariants();
FileWriteDescriptor file(_userSettingsKey);
file.writeEncrypted(data);
}

View File

@ -86,7 +86,8 @@ bool gHasPasscode = false;
DBIEmojiTab gEmojiTab = dbietRecent;
RecentEmojiPack gRecentEmojis;
RecentEmojiPreload gRecentEmojisPreload;
RecentEmojisPreload gRecentEmojisPreload;
EmojiColorVariants gEmojiVariants;
AllStickers gStickers;
QByteArray gStickersHash;
@ -185,22 +186,22 @@ void settingsParseArgs(int argc, char *argv[]) {
}
}
const RecentEmojiPack &cGetRecentEmojis() {
RecentEmojiPack &cGetRecentEmojis() {
if (cRecentEmojis().isEmpty()) {
RecentEmojiPack r;
if (!cRecentEmojisPreload().isEmpty()) {
RecentEmojiPreload p(cRecentEmojisPreload());
cSetRecentEmojisPreload(RecentEmojiPreload());
RecentEmojisPreload p(cRecentEmojisPreload());
cSetRecentEmojisPreload(RecentEmojisPreload());
r.reserve(p.size());
for (RecentEmojiPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
uint32 code = ((i->first & 0xFFFFU) == 0xFE0FU) ? ((i->first >> 16) & 0xFFFFU) : i->first;
EmojiPtr ep(getEmoji(code));
for (RecentEmojisPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
uint64 code = ((!(i->first & 0xFFFFFFFF00000000LLU) && (i->first & 0xFFFFU) == 0xFE0FU)) ? ((i->first >> 16) & 0xFFFFU) : i->first;
EmojiPtr ep(emojiFromKey(code));
if (!ep) continue;
if (ep->postfix) {
int32 j = 0, l = r.size();
for (; j < l; ++j) {
if (r[j].first->code == code) {
if (emojiKey(r[j].first) == code) {
break;
}
}
@ -211,47 +212,47 @@ const RecentEmojiPack &cGetRecentEmojis() {
r.push_back(qMakePair(ep, i->second));
}
}
uint32 defaultRecent[] = {
0xD83DDE02U,
0xD83DDE18U,
0x2764U,
0xD83DDE0DU,
0xD83DDE0AU,
0xD83DDE01U,
0xD83DDC4DU,
0x263AU,
0xD83DDE14U,
0xD83DDE04U,
0xD83DDE2DU,
0xD83DDC8BU,
0xD83DDE12U,
0xD83DDE33U,
0xD83DDE1CU,
0xD83DDE48U,
0xD83DDE09U,
0xD83DDE03U,
0xD83DDE22U,
0xD83DDE1DU,
0xD83DDE31U,
0xD83DDE21U,
0xD83DDE0FU,
0xD83DDE1EU,
0xD83DDE05U,
0xD83DDE1AU,
0xD83DDE4AU,
0xD83DDE0CU,
0xD83DDE00U,
0xD83DDE0BU,
0xD83DDE06U,
0xD83DDC4CU,
0xD83DDE10U,
0xD83DDE15U,
uint64 defaultRecent[] = {
0xD83DDE02LLU,
0xD83DDE18LLU,
0x2764LLU,
0xD83DDE0DLLU,
0xD83DDE0ALLU,
0xD83DDE01LLU,
0xD83DDC4DLLU,
0x263ALLU,
0xD83DDE14LLU,
0xD83DDE04LLU,
0xD83DDE2DLLU,
0xD83DDC8BLLU,
0xD83DDE12LLU,
0xD83DDE33LLU,
0xD83DDE1CLLU,
0xD83DDE48LLU,
0xD83DDE09LLU,
0xD83DDE03LLU,
0xD83DDE22LLU,
0xD83DDE1DLLU,
0xD83DDE31LLU,
0xD83DDE21LLU,
0xD83DDE0FLLU,
0xD83DDE1ELLU,
0xD83DDE05LLU,
0xD83DDE1ALLU,
0xD83DDE4ALLU,
0xD83DDE0CLLU,
0xD83DDE00LLU,
0xD83DDE0BLLU,
0xD83DDE06LLU,
0xD83DDC4CLLU,
0xD83DDE10LLU,
0xD83DDE15LLU,
};
for (int32 i = 0, s = sizeof(defaultRecent) / sizeof(defaultRecent[0]); i < s; ++i) {
if (r.size() >= EmojiPadPerRow * EmojiPadRowsPerPage) break;
EmojiPtr ep(getEmoji(defaultRecent[i]));
if (!ep) continue;
EmojiPtr ep(emojiGet(defaultRecent[i]));
if (!ep || ep == TwoSymbolEmoji) continue;
int32 j = 0, l = r.size();
for (; j < l; ++j) {
@ -265,5 +266,5 @@ const RecentEmojiPack &cGetRecentEmojis() {
}
cSetRecentEmojis(r);
}
return cRecentEmojis();
return cRefRecentEmojis();
}

View File

@ -41,6 +41,11 @@ inline void cSet##Name(const Type &Name) { \
g##Name = Name; \
}
#define DeclareRefSetting(Type, Name) DeclareSetting(Type, Name) \
inline Type &cRef##Name() { \
return g##Name; \
}
DeclareSetting(bool, Rtl);
DeclareSetting(Qt::LayoutDirection, LangDir);
inline bool rtl() {
@ -153,23 +158,28 @@ T convertScale(T v) {
DeclareSetting(DBIEmojiTab, EmojiTab);
struct EmojiData {
EmojiData(uint16 x, uint16 y, uint32 code, uint32 code2, uint16 len, uint16 postfix = 0) : x(x), y(y), code(code), code2(code2), len(len), postfix(postfix) {
EmojiData(uint16 x, uint16 y, uint32 code, uint32 code2, uint16 len, uint16 postfix, uint32 color) : x(x), y(y), code(code), code2(code2), len(len), postfix(postfix), color(color) {
}
uint16 x, y;
uint32 code, code2;
uint16 len;
uint16 postfix;
uint32 color;
};
typedef const EmojiData *EmojiPtr;
static EmojiPtr TwoSymbolEmoji = EmojiPtr(0x01);
typedef QVector<EmojiPtr> EmojiPack;
typedef QVector<QPair<uint32, ushort> > RecentEmojiPreload;
typedef QVector<QPair<uint32, ushort> > RecentEmojisPreloadOld;
typedef QVector<QPair<uint64, ushort> > RecentEmojisPreload;
typedef QVector<QPair<EmojiPtr, ushort> > RecentEmojiPack;
DeclareSetting(RecentEmojiPack, RecentEmojis);
DeclareSetting(RecentEmojiPreload, RecentEmojisPreload);
typedef QMap<uint32, uint64> EmojiColorVariants;
DeclareRefSetting(RecentEmojiPack, RecentEmojis);
DeclareSetting(RecentEmojisPreload, RecentEmojisPreload);
DeclareRefSetting(EmojiColorVariants, EmojiVariants);
const RecentEmojiPack &cGetRecentEmojis();
RecentEmojiPack &cGetRecentEmojis();
struct DocumentData;
typedef QVector<DocumentData*> StickerPack;

View File

@ -10,10 +10,11 @@
<file>art/sprite_125x.png</file>
<file>art/sprite_150x.png</file>
<file>art/sprite_200x.png</file>
<file>art/emoji.png</file>
<file>art/emoji_125x.png</file>
<file>art/emoji_150x.png</file>
<file>art/emoji_200x.png</file>
<file>art/emoji.webp</file>
<file>art/emoji_125x.webp</file>
<file>art/emoji_150x.webp</file>
<file>art/emoji_200x.webp</file>
<file>art/emoji_250x.webp</file>
<file>art/blank.gif</file>
<file>art/icon256.png</file>
<file>art/iconbig256.png</file>

View File

@ -10,10 +10,11 @@
<file>art/sprite_125x.png</file>
<file>art/sprite_150x.png</file>
<file>art/sprite_200x.png</file>
<file>art/emoji.png</file>
<file>art/emoji_125x.png</file>
<file>art/emoji_150x.png</file>
<file>art/emoji_200x.png</file>
<file>art/emoji.webp</file>
<file>art/emoji_125x.webp</file>
<file>art/emoji_150x.webp</file>
<file>art/emoji_200x.webp</file>
<file>art/emoji_250x.webp</file>
<file>art/blank.gif</file>
<file>art/icon256.png</file>
</qresource>

View File

@ -249,7 +249,7 @@ enum DataBlockId {
dbiDownloadPath = 21,
dbiScale = 22,
dbiEmojiTab = 23,
dbiRecentEmojis = 24,
dbiRecentEmojisOld = 24,
dbiLoggedPhoneNumber = 25,
dbiMutedPeers = 26,
// 27 reserved
@ -261,6 +261,8 @@ enum DataBlockId {
dbiTileBackground = 33,
dbiAutoLock = 34,
dbiDialogLastPath = 35,
dbiRecentEmojis = 36,
dbiEmojiVariants = 37,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,
@ -318,14 +320,21 @@ enum DBIScale {
};
enum DBIEmojiTab {
dbietRecent = -1,
dbietPeople = 0,
dbietNature = 1,
dbietObjects = 2,
dbietPlaces = 3,
dbietSymbols = 4,
dbietStickers = 666,
dbietRecent = -1,
dbietPeople = 0,
dbietNature = 1,
dbietFood = 2,
dbietCelebration = 3,
dbietActivity = 4,
dbietTravel = 5,
dbietObjects = 6,
dbietStickers = 666,
};
static const int emojiTabCount = 8;
static const int emojiTabShift = 100000;
inline DBIEmojiTab emojiTabAtIndex(int index) {
return (index < 0 || index >= emojiTabCount) ? dbietRecent : DBIEmojiTab(index - 1);
}
enum DBIPlatform {
dbipWindows = 0,

View File

@ -61,18 +61,19 @@ compiler_rcc_make_all: GeneratedFiles/qrc_telegram.cpp
compiler_rcc_clean:
-$(DEL_FILE) GeneratedFiles/qrc_telegram.cpp
GeneratedFiles/qrc_telegram.cpp: SourceFiles/telegram.qrc \
SourceFiles/art/emoji.png \
SourceFiles/art/emoji.webp \
SourceFiles/art/blank.gif \
SourceFiles/art/bg.jpg \
SourceFiles/art/sprite_150x.png \
SourceFiles/art/sprite.png \
SourceFiles/art/icon256.png \
SourceFiles/art/emoji_150x.png \
SourceFiles/art/emoji_150x.webp \
SourceFiles/art/sprite_200x.png \
SourceFiles/art/newmsg.wav \
SourceFiles/art/sprite_125x.png \
SourceFiles/art/emoji_200x.png \
SourceFiles/art/emoji_125x.png \
SourceFiles/art/emoji_200x.webp \
SourceFiles/art/emoji_250x.webp \
SourceFiles/art/emoji_125x.webp \
SourceFiles/art/fonts/OpenSans-Regular.ttf \
SourceFiles/art/fonts/OpenSans-Bold.ttf \
SourceFiles/art/fonts/OpenSans-Semibold.ttf \