tilde fix in 100%, dialogs repaint fix, markdown (bold, italic, code, pre support) added

This commit is contained in:
John Preston 2015-10-23 18:06:56 +02:00
parent 2b36f4d23a
commit 3df66a7ed3
24 changed files with 1027 additions and 525 deletions

View File

@ -23,6 +23,7 @@ semibold: 'Open Sans Semibold';
fsize: 13px;
normalFont: font(fsize);
semiboldFont: font(fsize semibold);
spriteFile: ':/gui/art/sprite.png' / 2:':/gui/art/sprite_125x.png' / 3:':/gui/art/sprite_150x.png' / 4:':/gui/art/sprite_200x.png';
emojiImgSize: 18px; // exceptional value for retina
@ -680,7 +681,7 @@ btnRedLink: linkButton(btnDefLink) {
}
countryRowHeight: 36px;
countryRowNameFont: font(fsize semibold);
countryRowNameFont: semiboldFont;
countryRowPadding: margins(22px, 9px, 8px, 0px);
countryRowCodeFont: font(fsize);
countryRowBgOver: #f5f8fa;
@ -970,9 +971,9 @@ msgRadius: 3px;
msgMaxWidth: 430px;
msgFont: font(fsize);
msgNameFont: font(fsize semibold);
msgServiceFont: font(fsize semibold);
msgServiceNameFont: font(fsize semibold);
msgNameFont: semiboldFont;
msgServiceFont: semiboldFont;
msgServiceNameFont: semiboldFont;
msgServicePhotoWidth: 100px;
msgDateFont: font(13px);
msgMinWidth: 190px;
@ -1079,10 +1080,11 @@ collapseHideDuration: 200;
collapseShowDuration: 200;
defaultTextStyle: textStyle {
lnkFlags: font(fsize);
lnkOverFlags: font(fsize underline);
lnkColor: btnYesColor;
lnkDownColor: btnYesHover;
linkFlags: font(fsize);
linkFlagsOver: font(fsize underline);
linkFg: btnYesColor;
linkFgDown: btnYesHover;
monoFg: #777;
selectBg: msgInSelectBg;
selectOverlay: msgSelectOverlay;
lineHeight: 0px;
@ -1091,35 +1093,38 @@ boxTextStyle: textStyle(defaultTextStyle) {
lineHeight: 22px;
}
serviceTextStyle: textStyle(defaultTextStyle) {
lnkFlags: msgServiceFont;
lnkOverFlags: font(fsize semibold underline);
lnkColor: msgServiceColor;
lnkDownColor: msgServiceColor;
linkFlags: msgServiceFont;
linkFlagsOver: font(fsize semibold underline);
linkFg: msgServiceColor;
linkFgDown: msgServiceColor;
monoFg: msgServiceColor;
selectBg: msgServiceSelectBg;
selectOverlay: msgServiceSelectBg;
}
inTextStyle: textStyle(defaultTextStyle) {
monoFg: #4e7391;
selectBg: msgInSelectBg;
selectOverlay: msgSelectOverlay;
}
outTextStyle: textStyle(defaultTextStyle) {
monoFg: #469165;
selectBg: msgOutSelectBg;
selectOverlay: msgSelectOverlay;
}
medviewSaveAsTextStyle: textStyle(defaultTextStyle) {
lnkColor: #91d9ff;
lnkDownColor: #91d9ff;
linkFg: #91d9ff;
linkFgDown: #91d9ff;
}
dlgTextStyle: textStyle(defaultTextStyle) {
lnkColor: dlgSystemColor;
lnkDownColor: dlgSystemColor;
lnkOverFlags: font(fsize);
linkFg: dlgSystemColor;
linkFgDown: dlgSystemColor;
linkFlagsOver: font(fsize);
}
dlgActiveTextStyle: textStyle(defaultTextStyle) {
lnkColor: dlgActiveColor;
lnkDownColor: dlgActiveColor;
lnkOverFlags: font(fsize);
linkFg: dlgActiveColor;
linkFgDown: dlgActiveColor;
linkFlagsOver: font(fsize);
}
introLabelTextStyle: textStyle(defaultTextStyle) {
lineHeight: 30px;
@ -1345,7 +1350,7 @@ reportSpamBg: #fffffff0;
newMsgSound: ':/gui/art/newmsg.wav';
unreadBarHeight: 32px;
unreadBarFont: font(fsize semibold);
unreadBarFont: semiboldFont;
unreadBarBG: #fcfbfa;
unreadBarBorder: shadowColor;
unreadBarColor: #538bb4;
@ -1370,7 +1375,7 @@ contactIconTop: 10px;
contactsPhotoSize: 42px;
contactsPadding: margins(16px, 7px, 16px, 7px);
contactsNameTop: 2px;
contactsNameFont: font(fsize semibold);
contactsNameFont: semiboldFont;
contactsStatusTop: 23px;
contactsStatusFont: font(fsize);
contactsStatusFg: #999999;
@ -1481,7 +1486,7 @@ profileListStatusBottom: 6px;
profileHoverBG: #f5f5f5;
profileActiveBG: #6294b9;
profileSubFont: font(fsize);
profileListNameFont: font(fsize semibold);
profileListNameFont: semiboldFont;
profileListNameColor: #000;
profileOnlineColor: titleTypingColor;
profileOfflineColor: titleStatusColor;
@ -1853,7 +1858,7 @@ emojiPanDuration: 200;
emojiPanHover: #f0f4f7;
emojiPanHeader: 42px;
emojiPanHeaderFont: font(fsize semibold);
emojiPanHeaderFont: semiboldFont;
emojiPanHeaderColor: #999;
emojiPanHeaderLeft: 22px;
emojiPanHeaderTop: 12px;
@ -1914,7 +1919,7 @@ botKbScroll: flatScroll(solidScroll) {
mvBgColor: #222;
mvBgOpacity: 0.92;
mvThickFont: font(fsize semibold);
mvThickFont: semiboldFont;
mvFont: font(fsize);
mvTextLeft: 16px;
@ -2172,8 +2177,8 @@ sessionTerminate: iconedButton(notifyClose) {
webPageLeft: 10px;
webPageBar: 2px;
webPageTitleFont: font(fsize semibold);
webPageDescriptionFont: font(fsize);
webPageTitleFont: semiboldFont;
webPageDescriptionFont: normalFont;
webPagePhotoSkip: 5px;
webPagePhotoSize: 100px;
webPagePhotoDelta: 8px;
@ -2193,10 +2198,10 @@ playerLineActive: #6389a8;
playerLineInactive: #bac7d4;
playerSkip: 8px;
playerNameStyle: textStyle(defaultTextStyle) {
lnkColor: #6389a8;
lnkDownColor: #6389a8;
lnkFlags: font(fsize semibold);
lnkOverFlags: font(fsize semibold);
linkFg: #6389a8;
linkFgDown: #6389a8;
linkFlags: semiboldFont;
linkFlagsOver: semiboldFont;
}
playerPlay: sprite(377px, 109px, 19px, 22px);
playerPause: sprite(379px, 131px, 17px, 20px);

View File

@ -19,10 +19,11 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/
textStyle {
lnkFlags: font;
lnkOverFlags: font;
lnkColor: color;
lnkDownColor: color;
linkFlags: font;
linkFlagsOver: font;
linkFg: color;
linkFgDown: color;
monoFg: color;
selectBg: color;
selectOverlay: color;
lineHeight: number;

View File

@ -95,6 +95,7 @@ namespace {
HistoryItem *hoveredItem = 0, *pressedItem = 0, *hoveredLinkItem = 0, *pressedLinkItem = 0, *contextItem = 0, *mousedItem = 0;
QPixmap *sprite = 0, *emoji = 0, *emojiLarge = 0;
style::font monofont;
struct CornersPixmaps {
CornersPixmaps() {
@ -755,7 +756,7 @@ namespace App {
if (HistoryItem *existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
bool hasLinks = m.has_entities() && !m.ventities.c_vector().v.isEmpty();
if ((hasLinks && !existing->hasTextLinks()) || (!hasLinks && existing->textHasLinks())) {
existing->setText(qs(m.vmessage), m.has_entities() ? linksFromMTP(m.ventities.c_vector().v) : LinksInText());
existing->setText(qs(m.vmessage), m.has_entities() ? entitiesFromMTP(m.ventities.c_vector().v) : EntitiesInText());
existing->initDimensions();
if (App::main()) App::main()->itemResized(existing);
if (existing->hasTextLinks() && (!existing->history()->isChannel() || existing->fromChannel())) {
@ -1915,10 +1916,27 @@ namespace App {
}
}
void tryFontFamily(QString &family, const QString &tryFamily) {
if (family.isEmpty()) {
if (!QFontInfo(QFont(tryFamily)).family().trimmed().compare(tryFamily, Qt::CaseInsensitive)) {
family = tryFamily;
}
}
}
void initMedia() {
deinitMedia(false);
audioInit();
if (!::monofont) {
QString family;
tryFontFamily(family, qsl("Consolas"));
tryFontFamily(family, qsl("Liberation Mono"));
tryFontFamily(family, qsl("Menlo"));
tryFontFamily(family, qsl("Courier"));
if (family.isEmpty()) family = QFontDatabase::systemFont(QFontDatabase::FixedFont).family();
::monofont = style::font(st::normalFont->f.pixelSize(), 0, family);
}
if (!::sprite) {
if (rtl()) {
::sprite = new QPixmap(QPixmap::fromImage(QImage(st::spriteFile).mirrored(true, false)));
@ -2060,6 +2078,10 @@ namespace App {
return ::mousedItem;
}
const style::font &monofont() {
return ::monofont;
}
const QPixmap &sprite() {
return *::sprite;
}

View File

@ -204,6 +204,7 @@ namespace App {
void mousedItem(HistoryItem *item);
HistoryItem *mousedItem();
const style::font &monofont();
const QPixmap &sprite();
const QPixmap &emoji();
const QPixmap &emojiLarge();

View File

@ -165,8 +165,8 @@ void AddContactBox::onSubmit() {
void AddContactBox::onSave() {
if (_addRequest) return;
QString firstName = prepareSentText(_first.getLastText());
QString lastName = prepareSentText(_last.getLastText());
QString firstName = prepareText(_first.getLastText());
QString lastName = prepareText(_last.getLastText());
QString phone = _phone.getLastText().trimmed();
if (firstName.isEmpty() && lastName.isEmpty()) {
if (_invertOrder) {
@ -491,7 +491,7 @@ void GroupInfoBox::onNameSubmit() {
void GroupInfoBox::onNext() {
if (_creationRequestId) return;
QString title = prepareSentText(_title.getLastText());
QString title = prepareText(_title.getLastText()), description = prepareText(_description.getLastText(), true);
if (title.isEmpty()) {
_title.setFocus();
_title.showError();
@ -500,7 +500,7 @@ void GroupInfoBox::onNext() {
if (_creating == CreatingGroupGroup) {
App::wnd()->replaceLayer(new ContactsBox(title, _photoBig));
} else {
_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(title), MTP_string(prepareSentText(_description.getLastText())), MTP_vector<MTPInputUser>(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
_creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(title), MTP_string(description), MTP_vector<MTPInputUser>(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail));
}
}
@ -1080,7 +1080,7 @@ void EditNameTitleBox::resizeEvent(QResizeEvent *e) {
void EditNameTitleBox::onSave() {
if (_requestId) return;
QString first = prepareSentText(_first.getLastText()), last = prepareSentText(_last.getLastText());
QString first = prepareText(_first.getLastText()), last = prepareText(_last.getLastText());
if (first.isEmpty() && last.isEmpty()) {
if (_invertOrder) {
_last.setFocus();
@ -1254,7 +1254,7 @@ void EditChannelBox::resizeEvent(QResizeEvent *e) {
void EditChannelBox::onSave() {
if (_saveTitleRequestId || _saveDescriptionRequestId) return;
QString title = prepareSentText(_title.getLastText()), description = prepareSentText(_description.getLastText());
QString title = prepareText(_title.getLastText()), description = prepareText(_description.getLastText(), true);
if (title.isEmpty()) {
_title.setFocus();
_title.showError();

View File

@ -102,7 +102,7 @@ PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : AbstractBox(st::boxWide
}
updateBoxSize();
_caption.setMaxLength(MaxPhotoCaption);
_caption.setCtrlEnterSubmit(false);
_caption.setCtrlEnterSubmit(CtrlEnterSubmitBoth);
connect(&_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange()));
connect(&_caption, SIGNAL(resized()), this, SLOT(onCaptionResized()));
connect(&_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
@ -267,7 +267,7 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) {
}
if (_compressed.isHidden() || _compressed.checked()) {
_img->ctrlShiftEnter = ctrlShiftEnter;
_img->caption = _caption.isHidden() ? QString() : prepareSentText(_caption.getLastText());
_img->caption = _caption.isHidden() ? QString() : prepareText(_caption.getLastText(), true);
if (App::main()) App::main()->confirmSendImage(*_img);
} else {
if (App::main()) App::main()->confirmSendImageUncompressed(ctrlShiftEnter, _replyTo);

View File

@ -440,7 +440,7 @@ void DialogsInner::createDialog(History *history) {
if (creating) {
refresh();
} else if (_state == DefaultState && movedFrom != movedTo) {
update(0, qMin(movedFrom, movedTo) * st::dlgHeight, fullWidth(), (qAbs(movedFrom - movedTo) + 1) * st::dlgHeight);
update(0, qMin(movedFrom, movedTo), fullWidth(), qAbs(movedFrom - movedTo) + st::dlgHeight);
}
}
@ -495,17 +495,12 @@ void DialogsInner::dlgUpdated(History *history, MsgId msgId) {
DialogsList::RowByPeer::iterator i = dialogs.list.rowByPeer.find(history->peer->id);
if (i != dialogs.list.rowByPeer.cend()) {
update(0, i.value()->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
} else {
i = contactsNoDialogs.list.rowByPeer.end();// find(history->peer->id);
if (i != contactsNoDialogs.list.rowByPeer.cend()) {
update(0, (dialogs.list.count + i.value()->pos) * st::dlgHeight, fullWidth(), st::dlgHeight);
}
}
} else if (_state == FilteredState || _state == SearchedState) {
int32 cnt = 0, add = filteredOffset();
for (FilteredDialogs::const_iterator i = filterResults.cbegin(), e = filterResults.cend(); i != e; ++i) {
if ((*i)->history == history) {
update(0, cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
update(0, add + cnt * st::dlgHeight, fullWidth(), st::dlgHeight);
break;
}
++cnt;

View File

@ -147,12 +147,28 @@ inline bool emojiEdge(const QChar *ch) {
return false;
}
inline QString replaceEmojis(const QString &text) {
inline void appendPartToResult(QString &result, const QChar *start, const QChar *from, const QChar *to, EntitiesInText &entities) {
if (to > from) {
for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) {
if (i->offset >= to - start) break;
if (i->offset + i->length < from - start) continue;
if (i->offset >= from - start) {
i->offset -= (from - start - result.size());
i->length += (from - start - result.size());
}
if (i->offset + i->length < to - start) {
i->length -= (from - start - result.size());
}
}
result.append(from, to - from);
}
}
inline QString replaceEmojis(const QString &text, EntitiesInText &entities) {
QString result;
LinksInText links = textParseLinks(text, TextParseLinks | TextParseMentions | TextParseHashtags);
int32 currentLink = 0, lnkCount = links.size();
const QChar *emojiStart = text.unicode(), *emojiEnd = emojiStart, *e = text.cend();
bool canFindEmoji = true, consumePrevious = false;
int32 currentEntity = 0, entitiesCount = entities.size();
const QChar *emojiStart = text.constData(), *emojiEnd = emojiStart, *e = text.constData() + text.size();
bool canFindEmoji = true;
for (const QChar *ch = emojiEnd; ch != e;) {
uint32 emojiCode = 0;
const QChar *newEmojiEnd = 0;
@ -160,20 +176,19 @@ inline QString replaceEmojis(const QString &text) {
emojiFind(ch, e, newEmojiEnd, emojiCode);
}
while (currentLink < lnkCount && ch >= emojiStart + links[currentLink].offset + links[currentLink].length) {
++currentLink;
while (currentEntity < entitiesCount && ch >= emojiStart + entities[currentEntity].offset + entities[currentEntity].length) {
++currentEntity;
}
EmojiPtr emoji = emojiCode ? emojiGet(emojiCode) : 0;
if (emoji && emoji != TwoSymbolEmoji &&
(ch == emojiStart || !ch->isLetterOrNumber() || !(ch - 1)->isLetterOrNumber()) &&
(newEmojiEnd == e || !newEmojiEnd->isLetterOrNumber() || newEmojiEnd == emojiStart || !(newEmojiEnd - 1)->isLetterOrNumber()) &&
(currentLink >= lnkCount || (ch < emojiStart + links[currentLink].offset && newEmojiEnd <= emojiStart + links[currentLink].offset) || (ch >= emojiStart + links[currentLink].offset + links[currentLink].length && newEmojiEnd > emojiStart + links[currentLink].offset + links[currentLink].length))
(currentEntity >= entitiesCount || (ch < emojiStart + entities[currentEntity].offset && newEmojiEnd <= emojiStart + entities[currentEntity].offset) || (ch >= emojiStart + entities[currentEntity].offset + entities[currentEntity].length && newEmojiEnd > emojiStart + entities[currentEntity].offset + entities[currentEntity].length))
) {
// if (newEmojiEnd < e && newEmojiEnd->unicode() == ' ') ++newEmojiEnd;
if (result.isEmpty()) result.reserve(text.size());
if (ch > emojiEnd + (consumePrevious ? 1 : 0)) {
result.append(emojiEnd, ch - emojiEnd - (consumePrevious ? 1 : 0));
}
appendPartToResult(result, emojiStart, emojiEnd, ch, entities);
if (emoji->color) {
EmojiColorVariants::const_iterator it = cEmojiVariants().constFind(emoji->code);
if (it != cEmojiVariants().cend()) {
@ -189,14 +204,9 @@ inline QString replaceEmojis(const QString &text) {
ch = emojiEnd = newEmojiEnd;
canFindEmoji = true;
consumePrevious = false;
} else {
if (false && (ch->unicode() == QChar::Space || ch->unicode() == QChar::Nbsp)) {
if (emojiEdge(ch)) {
canFindEmoji = true;
consumePrevious = true;
} else if (emojiEdge(ch)) {
canFindEmoji = true;
consumePrevious = false;
} else {
canFindEmoji = false;
}
@ -205,20 +215,10 @@ inline QString replaceEmojis(const QString &text) {
}
if (result.isEmpty()) return text;
if (emojiEnd < e) result.append(emojiEnd, e - emojiEnd);
appendPartToResult(result, emojiStart, emojiEnd, e, entities);
return result;
}
inline QString prepareSentText(QString result) {
result = result.replace('\t', qsl(" "));
result = result.replace(" --", QString::fromUtf8(" \xe2\x80\x94"));
result = result.replace("-- ", QString::fromUtf8("\xe2\x80\x94 "));
result = result.replace("<<", QString::fromUtf8("\xc2\xab"));
result = result.replace(">>", QString::fromUtf8("\xc2\xbb"));
return (cReplaceEmojis() ? replaceEmojis(result) : result).trimmed();
}
int emojiPackCount(DBIEmojiTab tab);
EmojiPack emojiPack(DBIEmojiTab tab);

View File

@ -538,7 +538,7 @@ _oldtext(val),
_undoAvailable(false),
_redoAvailable(false),
_inHeightCheck(false),
_ctrlEnterSubmit(true),
_ctrlEnterSubmit(CtrlEnterSubmitCtrlEnter),
_customUpDown(false),
@ -1121,14 +1121,17 @@ void InputArea::customUpDown(bool custom) {
_customUpDown = custom;
}
void InputArea::setCtrlEnterSubmit(bool ctrlEnterSubmit) {
void InputArea::setCtrlEnterSubmit(CtrlEnterSubmit ctrlEnterSubmit) {
_ctrlEnterSubmit = ctrlEnterSubmit;
}
void InputArea::InputAreaInner::keyPressEvent(QKeyEvent *e) {
bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier);
bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier);
bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && f()->_ctrlEnterSubmit) || (!ctrl && !shift && !f()->_ctrlEnterSubmit) || (ctrl && shift);
bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier);
bool ctrlGood = (ctrl && shift) ||
(ctrl && (f()->_ctrlEnterSubmit == CtrlEnterSubmitCtrlEnter || f()->_ctrlEnterSubmit == CtrlEnterSubmitBoth)) ||
(!ctrl && !shift && (f()->_ctrlEnterSubmit == CtrlEnterSubmitEnter || f()->_ctrlEnterSubmit == CtrlEnterSubmitBoth));
bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return);
if (macmeta && e->key() == Qt::Key_Backspace) {

View File

@ -164,6 +164,12 @@ private:
};
enum CtrlEnterSubmit {
CtrlEnterSubmitEnter,
CtrlEnterSubmitCtrlEnter,
CtrlEnterSubmitBoth,
};
class InputArea : public TWidget {
Q_OBJECT
@ -203,7 +209,7 @@ public:
bool isRedoAvailable() const;
void customUpDown(bool isCustom);
void setCtrlEnterSubmit(bool ctrlEnterSubmit);
void setCtrlEnterSubmit(CtrlEnterSubmit ctrlEnterSubmit);
void setTextCursor(const QTextCursor &cursor) {
return _inner.setTextCursor(cursor);
@ -294,7 +300,8 @@ private:
QString _oldtext;
bool _undoAvailable, _redoAvailable, _inHeightCheck, _ctrlEnterSubmit;
CtrlEnterSubmit _ctrlEnterSubmit;
bool _undoAvailable, _redoAvailable, _inHeightCheck;
bool _customUpDown;

View File

@ -60,6 +60,10 @@ namespace style {
return otherFlagsFont(FontUnderline, set);
}
uint32 FontData::size() const {
return _size;
}
uint32 FontData::flags() const {
return _flags;
}
@ -88,7 +92,7 @@ namespace style {
style::_fontFamilies.push_back(family);
i = _fontFamilyMap.insert(family, style::_fontFamilies.size() - 1);
}
init(i.value(), size, flags, 0);
init(size, flags, i.value(), 0);
}
Font::Font(uint32 size, uint32 flags, uint32 family) {

View File

@ -124,6 +124,7 @@ namespace style {
Font italic(bool set = true) const;
Font underline(bool set = true) const;
uint32 size() const;
uint32 flags() const;
uint32 family() const;

File diff suppressed because it is too large Load Diff

View File

@ -20,79 +20,96 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/
#pragma once
enum EntityInTextType {
EntityInTextUrl,
EntityInTextCustomUrl,
EntityInTextEmail,
EntityInTextHashtag,
EntityInTextMention,
EntityInTextBotCommand,
EntityInTextBold,
EntityInTextItalic,
EntityInTextCode, // inline
EntityInTextPre, // block
};
struct EntityInText {
EntityInText(EntityInTextType type, int32 offset, int32 length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) {
}
EntityInTextType type;
int32 offset, length;
QString text;
};
typedef QList<EntityInText> EntitiesInText;
// text preprocess
QString textClean(const QString &text);
QString textRichPrepare(const QString &text);
QString textOneLine(const QString &text, bool trim = true, bool rich = false);
QString textAccentFold(const QString &text);
QString textSearchKey(const QString &text);
bool textSplit(QString &sendingText, QString &leftText, int32 limit);
bool textSplit(QString &sendingText, EntitiesInText &sendingEntities, QString &leftText, EntitiesInText &leftEntities, int32 limit);
enum {
TextParseMultiline = 0x001,
TextParseLinks = 0x002,
TextParseRichText = 0x004,
TextParseMentions = 0x008,
TextParseHashtags = 0x010,
TextParseBotCommands = 0x020,
TextParseMultiline = 0x001,
TextParseLinks = 0x002,
TextParseRichText = 0x004,
TextParseMentions = 0x008,
TextParseHashtags = 0x010,
TextParseBotCommands = 0x020,
TextParseMono = 0x040,
TextTwitterMentions = 0x040,
TextTwitterHashtags = 0x080,
TextInstagramMentions = 0x100,
TextInstagramHashtags = 0x200,
TextTwitterMentions = 0x100,
TextTwitterHashtags = 0x200,
TextInstagramMentions = 0x400,
TextInstagramHashtags = 0x800,
};
enum LinkInTextType {
LinkInTextUrl,
LinkInTextCustomUrl,
LinkInTextEmail,
LinkInTextHashtag,
LinkInTextMention,
LinkInTextBotCommand,
};
struct LinkInText {
LinkInText(LinkInTextType type, int32 offset, int32 length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) {
}
LinkInTextType type;
int32 offset, length;
QString text;
};
typedef QList<LinkInText> LinksInText;
inline LinksInText linksFromMTP(const QVector<MTPMessageEntity> &entities) {
LinksInText result;
inline EntitiesInText entitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
EntitiesInText result;
if (!entities.isEmpty()) {
result.reserve(entities.size());
for (int32 i = 0, l = entities.size(); i != l; ++i) {
const MTPMessageEntity &e(entities.at(i));
switch (e.type()) {
case mtpc_messageEntityUrl: { const MTPDmessageEntityUrl &d(e.c_messageEntityUrl()); result.push_back(LinkInText(LinkInTextUrl, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityTextUrl: { const MTPDmessageEntityTextUrl &d(e.c_messageEntityTextUrl()); result.push_back(LinkInText(LinkInTextCustomUrl, d.voffset.v, d.vlength.v, textClean(qs(d.vurl)))); } break;
case mtpc_messageEntityEmail: { const MTPDmessageEntityEmail &d(e.c_messageEntityEmail()); result.push_back(LinkInText(LinkInTextEmail, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityHashtag: { const MTPDmessageEntityHashtag &d(e.c_messageEntityHashtag()); result.push_back(LinkInText(LinkInTextHashtag, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityMention: { const MTPDmessageEntityMention &d(e.c_messageEntityMention()); result.push_back(LinkInText(LinkInTextMention, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityBotCommand: { const MTPDmessageEntityBotCommand &d(e.c_messageEntityBotCommand()); result.push_back(LinkInText(LinkInTextBotCommand, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityUrl: { const MTPDmessageEntityUrl &d(e.c_messageEntityUrl()); result.push_back(EntityInText(EntityInTextUrl, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityTextUrl: { const MTPDmessageEntityTextUrl &d(e.c_messageEntityTextUrl()); result.push_back(EntityInText(EntityInTextCustomUrl, d.voffset.v, d.vlength.v, textClean(qs(d.vurl)))); } break;
case mtpc_messageEntityEmail: { const MTPDmessageEntityEmail &d(e.c_messageEntityEmail()); result.push_back(EntityInText(EntityInTextEmail, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityHashtag: { const MTPDmessageEntityHashtag &d(e.c_messageEntityHashtag()); result.push_back(EntityInText(EntityInTextHashtag, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityMention: { const MTPDmessageEntityMention &d(e.c_messageEntityMention()); result.push_back(EntityInText(EntityInTextMention, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityBotCommand: { const MTPDmessageEntityBotCommand &d(e.c_messageEntityBotCommand()); result.push_back(EntityInText(EntityInTextBotCommand, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityBold: { const MTPDmessageEntityBold &d(e.c_messageEntityBold()); result.push_back(EntityInText(EntityInTextBold, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityItalic: { const MTPDmessageEntityItalic &d(e.c_messageEntityItalic()); result.push_back(EntityInText(EntityInTextItalic, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityCode: { const MTPDmessageEntityCode &d(e.c_messageEntityCode()); result.push_back(EntityInText(EntityInTextCode, d.voffset.v, d.vlength.v)); } break;
case mtpc_messageEntityPre: { const MTPDmessageEntityPre &d(e.c_messageEntityPre()); result.push_back(EntityInText(EntityInTextPre, d.voffset.v, d.vlength.v, textClean(qs(d.vlanguage)))); } break;
}
}
}
return result;
}
inline MTPVector<MTPMessageEntity> linksToMTP(const LinksInText &links) {
inline MTPVector<MTPMessageEntity> linksToMTP(const EntitiesInText &links, bool sending = false) {
MTPVector<MTPMessageEntity> result(MTP_vector<MTPMessageEntity>(0));
QVector<MTPMessageEntity> &v(result._vector().v);
for (int32 i = 0, s = links.size(); i != s; ++i) {
const LinkInText &l(links.at(i));
const EntityInText &l(links.at(i));
if (l.length <= 0 || (sending && l.type != EntityInTextCode && l.type != EntityInTextPre)) continue;
switch (l.type) {
case LinkInTextUrl: v.push_back(MTP_messageEntityUrl(MTP_int(l.offset), MTP_int(l.length))); break;
case LinkInTextCustomUrl: v.push_back(MTP_messageEntityTextUrl(MTP_int(l.offset), MTP_int(l.length), MTP_string(l.text))); break;
case LinkInTextEmail: v.push_back(MTP_messageEntityEmail(MTP_int(l.offset), MTP_int(l.length))); break;
case LinkInTextHashtag: v.push_back(MTP_messageEntityHashtag(MTP_int(l.offset), MTP_int(l.length))); break;
case LinkInTextMention: v.push_back(MTP_messageEntityMention(MTP_int(l.offset), MTP_int(l.length))); break;
case LinkInTextBotCommand: v.push_back(MTP_messageEntityBotCommand(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextUrl: v.push_back(MTP_messageEntityUrl(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextCustomUrl: v.push_back(MTP_messageEntityTextUrl(MTP_int(l.offset), MTP_int(l.length), MTP_string(l.text))); break;
case EntityInTextEmail: v.push_back(MTP_messageEntityEmail(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextHashtag: v.push_back(MTP_messageEntityHashtag(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextMention: v.push_back(MTP_messageEntityMention(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextBotCommand: v.push_back(MTP_messageEntityBotCommand(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextBold: v.push_back(MTP_messageEntityBold(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextItalic: v.push_back(MTP_messageEntityItalic(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextCode: v.push_back(MTP_messageEntityCode(MTP_int(l.offset), MTP_int(l.length))); break;
case EntityInTextPre: v.push_back(MTP_messageEntityPre(MTP_int(l.offset), MTP_int(l.length), MTP_string(l.text))); break;
}
}
return result;
}
LinksInText textParseLinks(const QString &text, int32 flags, bool rich = false);
EntitiesInText textParseEntities(QString &text, int32 flags, bool rich = false); // changes text if (flags & TextParseMono)
#include "gui/emoji_config.h"
@ -101,16 +118,20 @@ void emojiDraw(QPainter &p, EmojiPtr e, int x, int y);
#include "../../../QtStatic/qtbase/src/gui/text/qfontengine_p.h"
enum TextBlockType {
TextBlockNewline = 0x01,
TextBlockText = 0x02,
TextBlockEmoji = 0x03,
TextBlockSkip = 0x04,
TextBlockTNewline = 0x01,
TextBlockTText = 0x02,
TextBlockTEmoji = 0x03,
TextBlockTSkip = 0x04,
};
enum TextBlockFlags {
TextBlockBold = 0x01,
TextBlockItalic = 0x02,
TextBlockUnderline = 0x04,
TextBlockFBold = 0x01,
TextBlockFItalic = 0x02,
TextBlockFUnderline = 0x04,
TextBlockFTilde = 0x08, // hack for ~ in OpenSans
TextBlockFSemibold = 0x10,
TextBlockFCode = 0x20,
TextBlockFPre = 0x40,
};
class ITextBlock {
@ -195,7 +216,7 @@ public:
private:
NewlineBlock(const style::font &font, const QString &str, uint16 from, uint16 length) : ITextBlock(font, str, from, length, 0, st::transparent, 0), _nextDir(Qt::LayoutDirectionAuto) {
_flags |= ((TextBlockNewline & 0x0F) << 8);
_flags |= ((TextBlockTNewline & 0x0F) << 8);
}
Qt::LayoutDirection _nextDir;
@ -525,17 +546,17 @@ public:
int32 countHeight(int32 width) const;
void setText(style::font font, const QString &text, const TextParseOptions &options = _defaultOptions);
void setRichText(style::font font, const QString &text, TextParseOptions options = _defaultOptions, const TextCustomTagsMap &custom = TextCustomTagsMap());
void setMarkedText(style::font font, const QString &text, const LinksInText &links, const TextParseOptions &options = _defaultOptions);
void setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options = _defaultOptions);
void setLink(uint16 lnkIndex, const TextLinkPtr &lnk);
bool hasLinks() const;
bool hasSkipBlock() const {
return _blocks.isEmpty() ? false : _blocks.back()->type() == TextBlockSkip;
return _blocks.isEmpty() ? false : _blocks.back()->type() == TextBlockTSkip;
}
void setSkipBlock(int32 width, int32 height);
void removeSkipBlock();
LinksInText calcLinksInText() const;
EntitiesInText calcEntitiesInText() const;
int32 maxWidth() const {
return _maxWidth.ceil().toInt();
@ -674,6 +695,15 @@ inline bool chIsBad(QChar ch) {
inline bool chIsTrimmed(QChar ch, bool rich = false) {
return (!rich || ch != TextCommand) && (chIsSpace(ch) || chIsBad(ch));
}
inline bool chReplacedBySpace(QChar ch) {
// \xe2\x80[\xa8 - \xac\xad] // 8232 - 8237
// QString from1 = QString::fromUtf8("\xe2\x80\xa8"), to1 = QString::fromUtf8("\xe2\x80\xad");
// \xcc[\xb3\xbf\x8a] // 819, 831, 778
// QString bad1 = QString::fromUtf8("\xcc\xb3"), bad2 = QString::fromUtf8("\xcc\xbf"), bad3 = QString::fromUtf8("\xcc\x8a");
// [\x00\x01\x02\x07\x08\x0b-\x1f] // '\t' = 0x09
return (/*code >= 0x00 && */ch <= 0x02) || (ch >= 0x07 && ch <= 0x09) || (ch >= 0x0b && ch <= 0x1f) ||
(ch == 819) || (ch == 831) || (ch == 778) || (ch >= 8232 && ch <= 8237);
}
inline bool chIsDiac(QChar ch) { // diac and variation selectors
QChar::Category c = ch.category();
return (c == QChar::Mark_NonSpacing) || (ch.unicode() == 1652);
@ -780,3 +810,90 @@ inline QString myUrlEncode(const QString &str) {
inline QString myUrlDecode(const QString &enc) {
return QUrl::fromPercentEncoding(enc.toUtf8());
}
QString prepareTextWithEntities(QString result, EntitiesInText &entities, int32 flags);
inline QString prepareText(QString result, bool checkLinks = false) {
EntitiesInText entities;
return prepareTextWithEntities(result, entities, checkLinks ? (TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands) : 0);
}
inline void moveStringPart(QChar *start, int32 &to, int32 &from, int32 count, EntitiesInText &entities) {
if (count > 0) {
if (to < from) {
memmove(start + to, start + from, count * sizeof(QChar));
for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) {
if (i->offset >= from + count) break;
if (i->offset + i->length < from) continue;
if (i->offset >= from) {
i->offset -= (from - to);
i->length += (from - to);
}
if (i->offset + i->length < from + count) {
i->length -= (from - to);
}
}
}
to += count;
from += count;
}
}
// replace bad symbols with space and remove \r
inline void cleanTextWithEntities(QString &result, EntitiesInText &entities) {
result = result.replace('\t', qstr(" "));
int32 len = result.size(), to = 0, from = 0;
QChar *start = result.data();
for (QChar *ch = start, *end = start + len; ch < end; ++ch) {
if (ch->unicode() == '\r') {
moveStringPart(start, to, from, (ch - start) - from, entities);
++from;
} else if (chReplacedBySpace(*ch)) {
*ch = ' ';
}
}
moveStringPart(start, to, from, len - from, entities);
if (to < len) result.resize(to);
}
inline void trimTextWithEntities(QString &result, EntitiesInText &entities) {
for (QChar *s = result.data(), *e = s + result.size(), *ch = e; ch != s;) { // rtrim
--ch;
if (!chIsTrimmed(*ch)) {
if (ch + 1 < e) {
int32 l = ch + 1 - s;
for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) {
if (i->offset > l) {
i->offset = l;
i->length = 0;
} else if (i->offset + i->length > l) {
i->length = l - i->offset;
}
}
result.resize(l);
}
break;
}
}
for (QChar *s = result.data(), *ch = s, *e = s + result.size(); ch != e; ++ch) { // ltrim
if (!chIsTrimmed(*ch)) {
if (ch > s) {
int32 l = ch - s;
for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) {
if (i->offset + i->length <= l) {
i->length = 0;
i->offset = 0;
} else if (i->offset < l) {
i->length = i->offset + i->length - l;
i->offset = 0;
} else {
i->offset -= l;
}
}
result = result.mid(l);
}
break;
}
}
}

View File

@ -45,12 +45,24 @@ TextParseOptions _textDlgOptions = {
Qt::LayoutDirectionAuto, // lang-dependent
};
TextParseOptions _historyTextOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText | TextParseMono, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions _historyBotOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText | TextParseMono, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions _historyTextNoMonoOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions _historyBotNoMonoOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText, // flags
0, // maxw
0, // maxh
@ -112,18 +124,28 @@ namespace {
inline const HistoryForwarded *toHistoryForwarded(const HistoryItem *item) {
return item ? item->toHistoryForwarded() : 0;
}
inline const TextParseOptions &itemTextParseOptions(HistoryItem *item) {
return itemTextParseOptions(item->history(), item->from());
inline const TextParseOptions &itemTextOptions(HistoryItem *item) {
return itemTextOptions(item->history(), item->from());
}
inline const TextParseOptions &itemTextNoMonoOptions(HistoryItem *item) {
return itemTextNoMonoOptions(item->history(), item->from());
}
}
const TextParseOptions &itemTextParseOptions(History *h, PeerData *f) {
const TextParseOptions &itemTextOptions(History *h, PeerData *f) {
if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isChannel() && h->peer->asChannel()->botStatus >= 0)) {
return _historyBotOptions;
}
return _historyTextOptions;
}
const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f) {
if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isChannel() && h->peer->asChannel()->botStatus >= 0)) {
return _historyBotNoMonoOptions;
}
return _historyTextNoMonoOptions;
}
void historyInit() {
_initTextOptions();
}
@ -2330,7 +2352,7 @@ void History::setLastMessage(HistoryItem *msg) {
}
void History::setPosInDialogsDate(const QDateTime &date) {
bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amIn()));
bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amIn() || !dialogs.isEmpty()));
if (!lastMsgDate.isNull() && lastMsgDate >= date) {
if (!updateDialog || !dialogs.isEmpty()) {
return;
@ -2785,7 +2807,7 @@ HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, const QString &caption, Histo
, _caption(st::minPhotoSize)
, openl(new PhotoLink(data)) {
if (!caption.isEmpty()) {
_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextParseOptions(parent));
_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextNoMonoOptions(parent));
}
init();
}
@ -3171,7 +3193,7 @@ HistoryVideo::HistoryVideo(const MTPDvideo &video, const QString &caption, Histo
, _uplDone(0)
{
if (!caption.isEmpty()) {
_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextParseOptions(parent));
_caption.setText(st::msgFont, caption + parent->skipBlock(), itemTextNoMonoOptions(parent));
}
_size = formatDurationAndSizeText(data->duration, data->size);
@ -6057,10 +6079,10 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPD
QString text(textClean(qs(msg.vmessage)));
initTime();
initMedia(msg.has_media() ? (&msg.vmedia) : 0, text);
setText(text, msg.has_entities() ? linksFromMTP(msg.ventities.c_vector().v) : LinksInText());
setText(text, msg.has_entities() ? entitiesFromMTP(msg.ventities.c_vector().v) : EntitiesInText());
}
HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const LinksInText &links, HistoryMedia *fromMedia) :
HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *fromMedia) :
HistoryItem(history, block, msgId, flags, date, from)
, _text(st::msgMinWidth)
, _textWidth(0)
@ -6073,7 +6095,7 @@ HistoryItem(history, block, msgId, flags, date, from)
_media = fromMedia->clone();
_media->regItem(this);
}
setText(msg, links);
setText(msg, entities);
}
HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, DocumentData *doc) :
@ -6086,7 +6108,7 @@ HistoryItem(history, block, msgId, flags, date, from)
{
initTime();
initMediaFromDocument(doc);
setText(QString(), LinksInText());
setText(QString(), EntitiesInText());
}
QString formatViewsCount(int32 views) {
@ -6246,8 +6268,8 @@ QString HistoryMessage::selectedText(uint32 selection) const {
return _text.original(selectedFrom, selectedTo);
}
LinksInText HistoryMessage::textLinks() const {
return _text.calcLinksInText();
EntitiesInText HistoryMessage::textEntities() const {
return _text.calcEntitiesInText();
}
QString HistoryMessage::inDialogsText() const {
@ -6283,16 +6305,16 @@ void HistoryMessage::setMedia(const MTPMessageMedia *media, bool allowEmitResize
if (allowEmitResize && App::main()) App::main()->itemResized(this);
}
void HistoryMessage::setText(const QString &text, const LinksInText &links) {
void HistoryMessage::setText(const QString &text, const EntitiesInText &entities) {
if (!_media || !text.isEmpty()) { // !justMedia()
if (_media && _media->isDisplayed()) {
_text.setMarkedText(st::msgFont, text, links, itemTextParseOptions(this));
_text.setMarkedText(st::msgFont, text, entities, itemTextOptions(this));
} else {
_text.setMarkedText(st::msgFont, text + skipBlock(), links, itemTextParseOptions(this));
_text.setMarkedText(st::msgFont, text + skipBlock(), entities, itemTextOptions(this));
}
if (id > 0) {
for (int32 i = 0, l = links.size(); i != l; ++i) {
if (links.at(i).type == LinkInTextUrl || links.at(i).type == LinkInTextCustomUrl || links.at(i).type == LinkInTextEmail) {
for (int32 i = 0, l = entities.size(); i != l; ++i) {
if (entities.at(i).type == EntityInTextUrl || entities.at(i).type == EntityInTextCustomUrl || entities.at(i).type == EntityInTextEmail) {
_flags |= MTPDmessage_flag_HAS_TEXT_LINKS;
break;
}
@ -6303,9 +6325,9 @@ void HistoryMessage::setText(const QString &text, const LinksInText &links) {
}
}
void HistoryMessage::getTextWithLinks(QString &text, LinksInText &links) {
void HistoryMessage::getTextWithEntities(QString &text, EntitiesInText &links) {
if (_text.isEmpty()) return;
links = _text.calcLinksInText();
links = _text.calcEntitiesInText();
text = _text.original();
}
@ -6750,7 +6772,7 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const
fwdNameUpdated();
}
HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg) : HistoryMessage(history, block, id, newMessageFlags(history->peer) | (!history->peer->isChannel() && msg->getMedia() && (msg->getMedia()->type() == MediaTypeAudio/* || msg->getMedia()->type() == MediaTypeVideo*/) ? MTPDmessage_flag_media_unread : 0), date, from, msg->justMedia() ? QString() : msg->HistoryMessage::selectedText(FullItemSel), msg->HistoryMessage::textLinks(), msg->getMedia())
HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, QDateTime date, int32 from, HistoryMessage *msg) : HistoryMessage(history, block, id, newMessageFlags(history->peer) | (!history->peer->isChannel() && msg->getMedia() && (msg->getMedia()->type() == MediaTypeAudio/* || msg->getMedia()->type() == MediaTypeVideo*/) ? MTPDmessage_flag_media_unread : 0), date, from, msg->justMedia() ? QString() : msg->HistoryMessage::selectedText(FullItemSel), msg->HistoryMessage::textEntities(), msg->getMedia())
, fwdDate(msg->dateForwarded())
, fwdFrom(msg->fromForwarded())
, fwdFromVersion(fwdFrom->nameVersion)

View File

@ -33,7 +33,8 @@ static const uint32 FullItemSel = 0xFFFFFFFF;
typedef QMap<int32, HistoryItem*> SelectedItemSet;
extern TextParseOptions _textNameOptions, _textDlgOptions, _historyTextOptions, _historyBotOptions;
extern TextParseOptions _textNameOptions, _textDlgOptions;
extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions;
#include "structs.h"
@ -930,9 +931,9 @@ public:
virtual HistoryMedia *getMedia(bool inOverview = false) const {
return 0;
}
virtual void setText(const QString &text, const LinksInText &links) {
virtual void setText(const QString &text, const EntitiesInText &links) {
}
virtual void getTextWithLinks(QString &text, LinksInText &links) {
virtual void getTextWithEntities(QString &text, EntitiesInText &links) {
}
virtual bool textHasLinks() {
return false;
@ -1502,7 +1503,7 @@ class HistoryMessage : public HistoryItem {
public:
HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg);
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const LinksInText &links, HistoryMedia *media); // local forwarded
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, const QString &msg, const EntitiesInText &entities, HistoryMedia *media); // local forwarded
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, int32 flags, QDateTime date, int32 from, DocumentData *doc); // local sticker and reply sticker
void initTime();
@ -1548,12 +1549,12 @@ public:
}
QString selectedText(uint32 selection) const;
LinksInText textLinks() const;
EntitiesInText textEntities() const;
QString inDialogsText() const;
HistoryMedia *getMedia(bool inOverview = false) const;
void setMedia(const MTPMessageMedia *media, bool allowEmitResize);
void setText(const QString &text, const LinksInText &links);
void getTextWithLinks(QString &text, LinksInText &links);
void setText(const QString &text, const EntitiesInText &entities);
void getTextWithEntities(QString &text, EntitiesInText &entities);
bool textHasLinks();
int32 infoWidth() const {
@ -1897,4 +1898,5 @@ protected:
bool freezed;
};
const TextParseOptions &itemTextParseOptions(History *h, PeerData *f);
const TextParseOptions &itemTextOptions(History *h, PeerData *f);
const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f);

View File

@ -1138,7 +1138,7 @@ void HistoryInner::updateBotInfo(bool recount) {
int32 newh = 0;
if (botInfo && !botInfo->description.isEmpty()) {
if (botInfo->text.isEmpty()) {
botInfo->text.setText(st::msgFont, botInfo->description, _historyBotOptions);
botInfo->text.setText(st::msgFont, botInfo->description, _historyBotNoMonoOptions);
if (recount) {
int32 tw = scrollArea->width() - st::msgMargin.left() - st::msgMargin.right();
if (tw > st::msgMaxWidth) tw = st::msgMaxWidth;
@ -1643,7 +1643,7 @@ bool MessageField::hasSendText() const {
const QString &text(getLastText());
for (const QChar *ch = text.constData(), *e = ch + text.size(); ch != e; ++ch) {
ushort code = ch->unicode();
if (code != ' ' && code != '\n' && code != '\r' && !replaceCharBySpace(code)) {
if (code != ' ' && code != '\n' && code != '\r' && !chReplacedBySpace(code)) {
return true;
}
}
@ -2528,6 +2528,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
_attachDragDocument.hide();
_attachDragPhoto.hide();
_topShadow.hide();
_sideShadow.setVisible(cWideMode());
connect(&_attachDragDocument, SIGNAL(dropped(const QMimeData*)), this, SLOT(onDocumentDrop(const QMimeData*)));
connect(&_attachDragPhoto, SIGNAL(dropped(const QMimeData*)), this, SLOT(onPhotoDrop(const QMimeData*)));
}
@ -2890,20 +2893,24 @@ void HistoryWidget::setKbWasHidden() {
}
void HistoryWidget::fastShowAtEnd(History *h) {
h->getReadyFor(ShowAtTheEndMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
if (h == _history) {
h->getReadyFor(ShowAtTheEndMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop);
if (_history != h) return;
clearAllLoadRequests();
clearAllLoadRequests();
setMsgId(ShowAtUnreadMsgId);
_histInited = false;
setMsgId(ShowAtUnreadMsgId);
_histInited = false;
if (h->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
historyLoaded();
} else {
firstLoadMessages();
doneShow();
if (h->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
historyLoaded();
} else {
firstLoadMessages();
doneShow();
}
} else if (h) {
MsgId fixInScrollMsgId = 0;
int32 fixInScrollMsgTop = 0;
h->getReadyFor(ShowAtTheEndMsgId, fixInScrollMsgId, fixInScrollMsgTop);
}
}
@ -3218,6 +3225,7 @@ void HistoryWidget::updateReportSpamStatus() {
}
void HistoryWidget::updateControlsVisibility() {
_topShadow.setVisible(_peer ? true : false);
if (!_history || _a_show.animating()) {
_reportSpamPanel.hide();
_scroll.hide();
@ -3822,28 +3830,19 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
if (!_history) return;
bool lastKeyboardUsed = lastForceReplyReplied(FullMsgId(_channel, replyTo));
QString text = prepareSentText(_field.getLastText());
if (!text.isEmpty()) {
App::main()->readServerHistory(_history, false);
fastShowAtEnd(_history);
WebPageId webPageId = _previewCancelled ? 0xFFFFFFFFFFFFFFFFULL : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
App::main()->sendPreparedText(_history, text, replyTo, _broadcast.checked(), webPageId);
WebPageId webPageId = _previewCancelled ? 0xFFFFFFFFFFFFFFFFULL : ((_previewData && _previewData->pendingTill >= 0) ? _previewData->id : 0);
App::main()->sendMessage(_history, _field.getLastText(), replyTo, _broadcast.checked(), webPageId);
setFieldText(QString());
_saveDraftText = true;
_saveDraftStart = getms();
onDraftSave();
setFieldText(QString());
_saveDraftText = true;
_saveDraftStart = getms();
onDraftSave();
if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
} else if (readyToForward()) {
App::main()->readServerHistory(_history, false);
fastShowAtEnd(_history);
App::main()->finishForwarding(_history, _broadcast.checked());
}
if (replyTo < 0) cancelReply(lastKeyboardUsed);
if (_previewData && _previewData->pendingTill) previewCancel();
_field.setFocus();
@ -4069,7 +4068,7 @@ bool HistoryWidget::animStep_show(float64 ms) {
if (dt >= 1) {
_a_show.stop();
_sideShadow.setVisible(cWideMode());
_topShadow.show();
_topShadow.setVisible(_peer ? true : false);
res = false;
a_coordUnder.finish();
@ -4110,7 +4109,7 @@ void HistoryWidget::animStop() {
if (!_a_show.animating()) return;
_a_show.stop();
_sideShadow.setVisible(cWideMode());
_topShadow.show();
_topShadow.setVisible(_peer ? true : false);
}
bool HistoryWidget::recordStep(float64 ms) {
@ -4306,9 +4305,6 @@ void HistoryWidget::stopRecording(bool send) {
void HistoryWidget::sendBotCommand(const QString &cmd, MsgId replyTo) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from cmd links
if (!_history) return;
App::main()->readServerHistory(_history, false);
fastShowAtEnd(_history);
bool lastKeyboardUsed = (_keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard.forMsgId() == FullMsgId(_channel, replyTo));
QString toSend = cmd;
@ -4320,7 +4316,7 @@ void HistoryWidget::sendBotCommand(const QString &cmd, MsgId replyTo) { // reply
toSend += '@' + username;
}
App::main()->sendPreparedText(_history, toSend, replyTo ? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/) ? replyTo : -1) : 0, false);
App::main()->sendMessage(_history, toSend, replyTo ? ((!_peer->isUser()/* && (botStatus == 0 || botStatus == 2)*/) ? replyTo : -1) : 0, false);
if (replyTo) {
cancelReply();
if (_keyboard.singleUse() && _keyboard.hasMarkup() && lastKeyboardUsed) {
@ -5724,10 +5720,6 @@ void HistoryWidget::onStickerSend(DocumentData *sticker) {
if (sticker->sticker()) App::main()->incrementSticker(sticker);
App::historyRegRandom(randomId, newId);
App::main()->historyToDown(_history);
App::main()->dialogsToUp();
peerMessagesUpdated(_peer->id);
if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();

View File

@ -197,16 +197,6 @@ public:
bool hasSendText() const;
static bool replaceCharBySpace(ushort code) {
// \xe2\x80[\xa8 - \xac\xad] // 8232 - 8237
// QString from1 = QString::fromUtf8("\xe2\x80\xa8"), to1 = QString::fromUtf8("\xe2\x80\xad");
// \xcc[\xb3\xbf\x8a] // 819, 831, 778
// QString bad1 = QString::fromUtf8("\xcc\xb3"), bad2 = QString::fromUtf8("\xcc\xbf"), bad3 = QString::fromUtf8("\xcc\x8a");
// [\x00\x01\x02\x07\x08\x0b-\x1f] // '\t' = 0x09
return (/*code >= 0x00 && */code <= 0x02) || (code >= 0x07 && code <= 0x09) || (code >= 0x0b && code <= 0x1f) ||
(code == 819) || (code == 831) || (code == 778) || (code >= 8232 && code <= 8237);
}
public slots:
void onEmojiInsert(EmojiPtr emoji);

View File

@ -1203,61 +1203,25 @@ DialogsIndexed &MainWidget::dialogsList() {
return dialogs.dialogsList();
}
QString cleanMessage(const QString &text) {
QString result = text;
QChar *_start = result.data(), *_end = _start + result.size(), *start = _start, *end = _end, *ch = start, *copy = 0;
for (; ch != end; ++ch) {
if (ch->unicode() == '\r') {
copy = ch + 1;
break;
} else if (MessageField::replaceCharBySpace(ch->unicode())) {
*ch = ' ';
}
}
if (copy) {
for (; copy != end; ++copy) {
if (copy->unicode() == '\r') {
continue;
} else if (MessageField::replaceCharBySpace(copy->unicode())) {
*ch++ = ' ';
} else {
*ch++ = *copy;
}
}
end = ch;
void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId) {
readServerHistory(hist, false);
history.fastShowAtEnd(hist);
if (!hist || !history.canSendMessages(hist->peer)) {
return;
}
// PHP trim() removes [ \t\n\r\x00\x0b], we have removed [\t\r\x00\x0b] before, so
for (; start != end; ++start) {
if (start->unicode() != ' ' && start->unicode() != '\n') {
break;
}
}
for (QChar *e = end - 1; start != end; end = e) {
if (e->unicode() != ' ' && e->unicode() != '\n') {
break;
}
--e;
}
if (start == end) {
return QString();
} else if (start > _start) {
return QString(start, end - start);
} else if (end < _end) {
result.resize(end - start);
}
return result;
}
void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId) {
saveRecentHashtags(text);
QString sendingText, leftText = text;
EntitiesInText sendingEntities, leftEntities;
QString sendingText, leftText = prepareTextWithEntities(text, leftEntities, itemTextOptions(hist, App::self()).flags);
if (replyTo < 0) replyTo = history.replyToId();
while (textSplit(sendingText, leftText, MaxMessageSize)) {
while (textSplit(sendingText, sendingEntities, leftText, leftEntities, MaxMessageSize)) {
FullMsgId newId(peerToChannel(hist->peer->id), clientMsgId());
uint64 randomId = MTP::nonce<uint64>();
sendingText = cleanMessage(sendingText);
trimTextWithEntities(sendingText, sendingEntities);
App::historyRegRandom(randomId, newId);
App::historyRegSentData(randomId, hist->peer->id, sendingText);
@ -1284,22 +1248,17 @@ void MainWidget::sendPreparedText(History *hist, const QString &text, MsgId repl
} else {
flags |= MTPDmessage::flag_from_id;
}
MTPVector<MTPMessageEntity> localEntities = linksToMTP(textParseLinks(sendingText, itemTextParseOptions(hist, App::self()).flags));
MTPVector<MTPMessageEntity> localEntities = linksToMTP(sendingEntities), sentEntities = linksToMTP(sendingEntities, true);
if (!sentEntities.c_vector().v.isEmpty()) {
sendFlags |= MTPmessages_SendMessage::flag_entities;
}
hist->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(fromChannelName ? 0 : MTP::authedId()), peerToMTP(hist->peer->id), MTPPeer(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup, localEntities, MTP_int(1)), NewMessageUnread);
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId), MTPnullMarkup, localEntities), rpcDone(&MainWidget::sentUpdatesReceived, randomId), rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId), MTPnullMarkup, sentEntities), rpcDone(&MainWidget::sentUpdatesReceived, randomId), rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
}
finishForwarding(hist, broadcast);
}
void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast) {
MsgId fixInScrollMsgId = 0;
int32 fixInScrollMsgTop = 0;
hist->getReadyFor(ShowAtTheEndMsgId, fixInScrollMsgId, fixInScrollMsgTop);
readServerHistory(hist, false);
sendPreparedText(hist, prepareSentText(text), replyTo, broadcast);
}
void MainWidget::saveRecentHashtags(const QString &text) {
bool found = false;
QRegularExpressionMatch m;
@ -2115,9 +2074,10 @@ void MainWidget::dialogsCancelled() {
void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &media) {
int32 flags = MTPDmessage_flag_unread | MTPDmessage::flag_entities | MTPDmessage::flag_from_id;
QString sendingText, leftText = msg;
EntitiesInText sendingEntities, leftEntities = textParseEntities(leftText, _historyTextNoMonoOptions.flags);
HistoryItem *item = 0;
while (textSplit(sendingText, leftText, MaxMessageSize)) {
MTPVector<MTPMessageEntity> localEntities = linksToMTP(textParseLinks(sendingText, _historyTextOptions.flags));
while (textSplit(sendingText, sendingEntities, leftText, leftEntities, MaxMessageSize)) {
MTPVector<MTPMessageEntity> localEntities = linksToMTP(sendingEntities);
item = App::histories().addNewMessage(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPPeer(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint()), NewMessageUnread);
}
if (item) {
@ -4260,7 +4220,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
if (!text.isEmpty()) {
bool hasLinks = d.has_entities() && !d.ventities.c_vector().v.isEmpty();
if ((hasLinks && !item->hasTextLinks()) || (!hasLinks && item->textHasLinks())) {
item->setText(text, d.has_entities() ? linksFromMTP(d.ventities.c_vector().v) : LinksInText());
item->setText(text, d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText());
item->initDimensions();
itemResized(item);
if (item->hasTextLinks() && (!item->history()->isChannel() || item->fromChannel())) {

View File

@ -328,8 +328,7 @@ public:
DialogsIndexed &contactsList();
DialogsIndexed &dialogsList();
void sendMessage(History *history, const QString &text, MsgId replyTo, bool broadcast);
void sendPreparedText(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId = 0);
void sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast, WebPageId webPageId = 0);
void saveRecentHashtags(const QString &text);
void readServerHistory(History *history, bool force = true);

View File

@ -350,24 +350,24 @@ enum {
static const mtpTypeId mtpc_bytes = mtpc_string;
static const mtpTypeId mtpc_core_message = -1; // undefined type, but is used
static const mtpTypeId mtpLayers[] = {
mtpc_invokeWithLayer1,
mtpc_invokeWithLayer2,
mtpc_invokeWithLayer3,
mtpc_invokeWithLayer4,
mtpc_invokeWithLayer5,
mtpc_invokeWithLayer6,
mtpc_invokeWithLayer7,
mtpc_invokeWithLayer8,
mtpc_invokeWithLayer9,
mtpc_invokeWithLayer10,
mtpc_invokeWithLayer11,
mtpc_invokeWithLayer12,
mtpc_invokeWithLayer13,
mtpc_invokeWithLayer14,
mtpc_invokeWithLayer15,
mtpc_invokeWithLayer16,
mtpc_invokeWithLayer17,
mtpc_invokeWithLayer18,
mtpTypeId(mtpc_invokeWithLayer1),
mtpTypeId(mtpc_invokeWithLayer2),
mtpTypeId(mtpc_invokeWithLayer3),
mtpTypeId(mtpc_invokeWithLayer4),
mtpTypeId(mtpc_invokeWithLayer5),
mtpTypeId(mtpc_invokeWithLayer6),
mtpTypeId(mtpc_invokeWithLayer7),
mtpTypeId(mtpc_invokeWithLayer8),
mtpTypeId(mtpc_invokeWithLayer9),
mtpTypeId(mtpc_invokeWithLayer10),
mtpTypeId(mtpc_invokeWithLayer11),
mtpTypeId(mtpc_invokeWithLayer12),
mtpTypeId(mtpc_invokeWithLayer13),
mtpTypeId(mtpc_invokeWithLayer14),
mtpTypeId(mtpc_invokeWithLayer15),
mtpTypeId(mtpc_invokeWithLayer16),
mtpTypeId(mtpc_invokeWithLayer17),
mtpTypeId(mtpc_invokeWithLayer18),
};
static const uint32 mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
static const mtpPrime mtpCurrentLayer = 38;

View File

@ -32,11 +32,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
OverviewInner::CachedLink::CachedLink(HistoryItem *item) : titleWidth(0), page(0), pixw(0), pixh(0), text(st::msgMinWidth) {
QString msgText;
LinksInText msgLinks;
item->getTextWithLinks(msgText, msgLinks);
EntitiesInText msgLinks;
item->getTextWithEntities(msgText, msgLinks);
int32 from = 0, till = msgText.size(), lnk = msgLinks.size();
for (int32 i = 0; i < lnk; ++i) {
if (msgLinks[i].type != LinkInTextUrl && msgLinks[i].type != LinkInTextCustomUrl && msgLinks[i].type != LinkInTextEmail) {
if (msgLinks[i].type != EntityInTextUrl && msgLinks[i].type != EntityInTextCustomUrl && msgLinks[i].type != EntityInTextEmail) {
continue;
}
QString url = msgLinks[i].text, text = msgText.mid(msgLinks[i].offset, msgLinks[i].length);
@ -44,7 +44,7 @@ OverviewInner::CachedLink::CachedLink(HistoryItem *item) : titleWidth(0), page(0
}
while (lnk > 0 && till > from) {
--lnk;
if (msgLinks[lnk].type != LinkInTextUrl && msgLinks[lnk].type != LinkInTextCustomUrl && msgLinks[lnk].type != LinkInTextEmail) {
if (msgLinks[lnk].type != EntityInTextUrl && msgLinks[lnk].type != EntityInTextCustomUrl && msgLinks[lnk].type != EntityInTextEmail) {
++lnk;
break;
}

View File

@ -165,12 +165,12 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
// about
if (_peerUser && _peerUser->botInfo) {
if (!_peerUser->botInfo->shareText.isEmpty()) {
_about.setText(st::linkFont, _peerUser->botInfo->shareText, _historyBotOptions);
_about.setText(st::linkFont, _peerUser->botInfo->shareText, _historyBotNoMonoOptions);
}
updateBotLinksVisibility();
} else {
if (_peerChannel && !_peerChannel->about.isEmpty()) {
_about.setText(st::linkFont, _peerChannel->about, _historyTextOptions);
_about.setText(st::linkFont, _peerChannel->about, _historyTextNoMonoOptions);
}
_botSettings.hide();
_botHelp.hide();
@ -470,7 +470,7 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
if (_peerUser->botInfo->shareText.isEmpty()) {
_about = Text(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right());
} else {
_about.setText(st::linkFont, _peerUser->botInfo->shareText, _historyBotOptions);
_about.setText(st::linkFont, _peerUser->botInfo->shareText, _historyBotNoMonoOptions);
}
updateBotLinksVisibility();
resizeEvent(0);
@ -487,7 +487,7 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
if (_peerChannel->about.isEmpty()) {
_about = Text(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right());
} else {
_about.setText(st::linkFont, _peerChannel->about, _historyTextOptions);
_about.setText(st::linkFont, _peerChannel->about, _historyTextNoMonoOptions);
}
showAll();
resizeEvent(0);

View File

@ -86,8 +86,7 @@
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;Shlwapi.lib;Gdiplus.lib;imm32.lib;winmm.lib;qtmaind.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Cored.lib;Qt5Guid.lib;qtharfbuzzngd.lib;qtpcred.lib;qtfreetyped.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;Qt5PlatformSupportd.lib;platforms\qwindowsd.lib;imageformats\qwebpd.lib;libeay32.lib;ssleay32.lib;Crypt32.lib;zlibstat.lib;LzmaLib.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;OpenAL32.lib;common.lib;libavformat\libavformat.a;libavcodec\libavcodec.a;libavutil\libavutil.a;libswresample\libswresample.a;opus.lib;celt.lib;silk_common.lib;silk_float.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ImageHasSafeExceptionHandlers />
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
<IgnoreSpecificDefaultLibraries>LIBCMT</IgnoreSpecificDefaultLibraries>
<ImportLibrary>$(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib</ImportLibrary>
</Link>
<CustomBuildStep>