forwarded display improved

This commit is contained in:
John Preston 2016-02-19 14:53:49 +03:00
parent c3845ead85
commit 6d42350691
8 changed files with 132 additions and 111 deletions

View File

@ -555,7 +555,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_channel_public_link_copied" = "Link copied to clipboard."; "lng_channel_public_link_copied" = "Link copied to clipboard.";
"lng_forwarded_from" = "Forwarded from"; "lng_forwarded" = "Forwarded from {original}";
"lng_forwarded_via" = "Forwarded from {original} via {inline_bot}";
"lng_forwarded_signed" = "{channel} ({user})";
"lng_in_reply_to" = "In reply to"; "lng_in_reply_to" = "In reply to";
"lng_attach_failed" = "Failed"; "lng_attach_failed" = "Failed";

View File

@ -1163,6 +1163,24 @@ outTextStyle: textStyle(defaultTextStyle) {
selectBg: msgOutBgSelected; selectBg: msgOutBgSelected;
selectOverlay: msgSelectOverlay; selectOverlay: msgSelectOverlay;
} }
inFwdTextStyle: textStyle(defaultTextStyle) {
linkFlags: semiboldFont;
linkFlagsOver: semiboldFont;
linkFg: msgInServiceFg;
linkFgDown: msgInServiceFg;
}
outFwdTextStyle: textStyle(inFwdTextStyle) {
linkFg: msgOutServiceFg;
linkFgDown: msgOutServiceFg;
}
inFwdTextStyleSelected: textStyle(inFwdTextStyle) {
linkFg: msgInServiceFgSelected;
linkFgDown: msgInServiceFgSelected;
}
outFwdTextStyleSelected: textStyle(inFwdTextStyle) {
linkFg: msgOutServiceFgSelected;
linkFgDown: msgOutServiceFgSelected;
}
medviewSaveAsTextStyle: textStyle(defaultTextStyle) { medviewSaveAsTextStyle: textStyle(defaultTextStyle) {
linkFg: #91d9ff; linkFg: #91d9ff;
linkFgDown: #91d9ff; linkFgDown: #91d9ff;

View File

@ -994,7 +994,7 @@ public:
return _blockEnd(t, i, e) - (*i)->from(); return _blockEnd(t, i, e) - (*i)->from();
} }
TextPainter(QPainter *p, const Text *t) : _p(p), _t(t), _elideLast(false), _elideRemoveFromEnd(0), _str(0), _elideSavedBlock(0), _lnkResult(0), _inTextFlag(0), _getSymbol(0), _getSymbolAfter(0), _getSymbolUpon(0) { TextPainter(QPainter *p, const Text *t) : _p(p), _t(t), _elideLast(false), _breakEverywhere(false), _elideRemoveFromEnd(0), _str(0), _elideSavedBlock(0), _lnkResult(0), _inTextFlag(0), _getSymbol(0), _getSymbolAfter(0), _getSymbolUpon(0) {
} }
void initNextParagraph(Text::TextBlocks::const_iterator i) { void initNextParagraph(Text::TextBlocks::const_iterator i) {
@ -1192,7 +1192,7 @@ public:
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide); bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide);
if (elidedLine) { if (elidedLine) {
_lineHeight = elidedLineHeight; _lineHeight = elidedLineHeight;
} else if (f != j) { } else if (f != j && !_breakEverywhere) {
// word did not fit completely, so we roll back the state to the beginning of this long word // word did not fit completely, so we roll back the state to the beginning of this long word
j = f; j = f;
_wLeft = f_wLeft; _wLeft = f_wLeft;
@ -1251,7 +1251,7 @@ public:
} }
} }
void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd) { void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere) {
if (lines <= 0 || _t->isNull()) return; if (lines <= 0 || _t->isNull()) return;
if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) { if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) {
@ -1259,6 +1259,7 @@ public:
_elideLast = true; _elideLast = true;
_elideRemoveFromEnd = removeFromEnd; _elideRemoveFromEnd = removeFromEnd;
} }
_breakEverywhere = breakEverywhere;
draw(left, top, w, align, yFrom, yTo); draw(left, top, w, align, yFrom, yTo);
} }
@ -1272,7 +1273,7 @@ public:
return *_lnkResult; return *_lnkResult;
} }
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 w, style::align align) { void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 w, style::align align, bool breakEverywhere) {
lnk = TextLinkPtr(); lnk = TextLinkPtr();
inText = false; inText = false;
@ -1281,6 +1282,7 @@ public:
_lnkY = y; _lnkY = y;
_lnkResult = &lnk; _lnkResult = &lnk;
_inTextFlag = &inText; _inTextFlag = &inText;
_breakEverywhere = breakEverywhere;
draw(0, 0, w, align, _lnkY, _lnkY + 1); draw(0, 0, w, align, _lnkY, _lnkY + 1);
lnk = *_lnkResult; lnk = *_lnkResult;
} }
@ -2437,7 +2439,7 @@ private:
QPainter *_p; QPainter *_p;
const Text *_t; const Text *_t;
bool _elideLast; bool _elideLast, _breakEverywhere;
int32 _elideRemoveFromEnd; int32 _elideRemoveFromEnd;
style::align _align; style::align _align;
QPen _originalPen; QPen _originalPen;
@ -2984,10 +2986,10 @@ void Text::draw(QPainter &painter, int32 left, int32 top, int32 w, style::align
p.draw(left, top, w, align, yFrom, yTo, selectedFrom, selectedTo); p.draw(left, top, w, align, yFrom, yTo, selectedFrom, selectedTo);
} }
void Text::drawElided(QPainter &painter, int32 left, int32 top, int32 w, int32 lines, style::align align, int32 yFrom, int32 yTo, int32 removeFromEnd) const { void Text::drawElided(QPainter &painter, int32 left, int32 top, int32 w, int32 lines, style::align align, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere) const {
// painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug // painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug
TextPainter p(&painter, this); TextPainter p(&painter, this);
p.drawElided(left, top, w, align, lines, yFrom, yTo, removeFromEnd); p.drawElided(left, top, w, align, lines, yFrom, yTo, removeFromEnd, breakEverywhere);
} }
const TextLinkPtr &Text::link(int32 x, int32 y, int32 width, style::align align) const { const TextLinkPtr &Text::link(int32 x, int32 y, int32 width, style::align align) const {
@ -2995,9 +2997,9 @@ const TextLinkPtr &Text::link(int32 x, int32 y, int32 width, style::align align)
return p.link(x, y, width, align); return p.link(x, y, width, align);
} }
void Text::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align) const { void Text::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align, bool breakEverywhere) const {
TextPainter p(0, this); TextPainter p(0, this);
p.getState(lnk, inText, x, y, width, align); p.getState(lnk, inText, x, y, width, align, breakEverywhere);
} }
void Text::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align) const { void Text::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align) const {

View File

@ -604,27 +604,27 @@ public:
void replaceFont(style::font f); // does not recount anything, use at your own risk! void replaceFont(style::font f); // does not recount anything, use at your own risk!
void draw(QPainter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const; void draw(QPainter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const;
void drawElided(QPainter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0) const; void drawElided(QPainter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const;
void drawLeft(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const { void drawLeft(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const {
draw(p, rtl() ? (outerw - left - width) : left, top, width, align, yFrom, yTo, selectedFrom, selectedTo); draw(p, rtl() ? (outerw - left - width) : left, top, width, align, yFrom, yTo, selectedFrom, selectedTo);
} }
void drawLeftElided(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0) const { void drawLeftElided(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const {
drawElided(p, rtl() ? (outerw - left - width) : left, top, width, lines, align, yFrom, yTo, removeFromEnd); drawElided(p, rtl() ? (outerw - left - width) : left, top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere);
} }
void drawRight(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const { void drawRight(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const {
draw(p, rtl() ? right : (outerw - right - width), top, width, align, yFrom, yTo, selectedFrom, selectedTo); draw(p, rtl() ? right : (outerw - right - width), top, width, align, yFrom, yTo, selectedFrom, selectedTo);
} }
void drawRightElided(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0) const { void drawRightElided(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const {
drawElided(p, rtl() ? right : (outerw - right - width), top, width, lines, align, yFrom, yTo, removeFromEnd); drawElided(p, rtl() ? right : (outerw - right - width), top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere);
} }
const TextLinkPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const; const TextLinkPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const;
const TextLinkPtr &linkLeft(int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const { const TextLinkPtr &linkLeft(int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const {
return link(rtl() ? (outerw - x - width) : x, y, width, align); return link(rtl() ? (outerw - x - width) : x, y, width, align);
} }
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left) const; void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left, bool breakEverywhere = false) const;
void getStateLeft(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const { void getStateLeft(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left, bool breakEverywhere = false) const {
return getState(lnk, inText, rtl() ? (outerw - x - width) : x, y, width, align); return getState(lnk, inText, rtl() ? (outerw - x - width) : x, y, width, align, breakEverywhere);
} }
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align = style::al_left) const; void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align = style::al_left) const;
void getSymbolLeft(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const { void getSymbolLeft(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const {

View File

@ -6018,14 +6018,30 @@ int32 HistoryMessageSigned::maxWidth() const {
HistoryMessageForwarded::HistoryMessageForwarded(Interfaces *) HistoryMessageForwarded::HistoryMessageForwarded(Interfaces *)
: _authorOriginal(0) : _authorOriginal(0)
, _fromOriginal(0) , _fromOriginal(0)
, _authorOriginalVersion(0) , _originalId(0)
, _fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) { , _text(1) {
} }
void HistoryMessageForwarded::authorNameUpdated(bool hasVia) const { void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
QString name((hasVia && _authorOriginal->isUser()) ? _authorOriginal->asUser()->firstName : App::peerName(_authorOriginal)); QString text;
_authorOriginalName.setText(st::msgServiceNameFont, name, _textNameOptions); if (_authorOriginal != _fromOriginal) {
_authorOriginalVersion = _authorOriginal->nameVersion; text = lng_forwarded_signed(lt_channel, App::peerName(_authorOriginal), lt_user, App::peerName(_fromOriginal));
} else {
text = App::peerName(_authorOriginal);
}
if (via) {
text = lng_forwarded_via(lt_original, textcmdLink(1, text), lt_inline_bot, textcmdLink(2, '@' + via->_bot->username));
} else {
text = lng_forwarded(lt_original, textcmdLink(1, text));
}
TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto };
textstyleSet(&st::inFwdTextStyle);
_text.setText(st::msgServiceNameFont, text, opts);
textstyleRestore();
_text.setLink(1, (_originalId && _authorOriginal->isChannel()) ? TextLinkPtr(new MessageLink(_authorOriginal->id, _originalId)) : _authorOriginal->lnk);
if (via) {
_text.setLink(2, via->_lnk);
}
} }
HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg) : HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg) :
@ -6034,15 +6050,17 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPD
, _textWidth(0) , _textWidth(0)
, _textHeight(0) , _textHeight(0)
, _media(0) { , _media(0) {
PeerId fwdAuthorId = 0, fwdFromId = 0; PeerId authorOriginalId = 0, fromOriginalId = 0;
MsgId originalId = 0;
if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) { if (msg.has_fwd_from() && msg.vfwd_from.type() == mtpc_messageFwdHeader) {
const MTPDmessageFwdHeader &f(msg.vfwd_from.c_messageFwdHeader()); const MTPDmessageFwdHeader &f(msg.vfwd_from.c_messageFwdHeader());
if (f.has_from_id() || f.has_channel_id()) { if (f.has_from_id() || f.has_channel_id()) {
fwdAuthorId = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id); authorOriginalId = f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id);
fwdFromId = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id); fromOriginalId = f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id);
if (f.has_channel_post()) originalId = f.vchannel_post.v;
} }
} }
create(msg.has_via_bot_id() ? msg.vvia_bot_id.v : 0, msg.has_views() ? msg.vviews.v : -1, fwdAuthorId, fwdFromId); create(msg.has_via_bot_id() ? msg.vvia_bot_id.v : 0, msg.has_views() ? msg.vviews.v : -1, authorOriginalId, fromOriginalId, originalId);
QString text(textClean(qs(msg.vmessage))); QString text(textClean(qs(msg.vmessage)));
initMedia(msg.has_media() ? (&msg.vmedia) : 0, text); initMedia(msg.has_media() ? (&msg.vmedia) : 0, text);
@ -6058,7 +6076,7 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId id,
UserData *fwdViaBot = fwd->viaBot(); UserData *fwdViaBot = fwd->viaBot();
int32 viaBotId = fwdViaBot ? peerToUser(fwdViaBot->id) : 0; int32 viaBotId = fwdViaBot ? peerToUser(fwdViaBot->id) : 0;
int32 fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1); int32 fwdViewsCount = fwd->viewsCount(), views = (fwdViewsCount > 0) ? fwdViewsCount : (isPost() ? 1 : -1);
create(viaBotId, views, fwd->authorOriginal()->id, fwd->fromOriginal()->id); create(viaBotId, views, fwd->authorOriginal()->id, fwd->fromOriginal()->id, fwd->authorOriginal()->isChannel() ? fwd->id : 0);
if (HistoryMedia *mediaOriginal = fwd->getMedia()) { if (HistoryMedia *mediaOriginal = fwd->getMedia()) {
_media = mediaOriginal->clone(); _media = mediaOriginal->clone();
@ -6073,7 +6091,7 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId id,
, _textWidth(0) , _textWidth(0)
, _textHeight(0) , _textHeight(0)
, _media(0) { , _media(0) {
create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1, 0, 0); create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1);
setText(msg, entities); setText(msg, entities);
} }
@ -6084,7 +6102,7 @@ HistoryItem(history, block, msgId, flags, date, (flags & MTPDmessage::flag_from_
, _textWidth(0) , _textWidth(0)
, _textHeight(0) , _textHeight(0)
, _media(0) { , _media(0) {
create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1, 0, 0); create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1);
initMediaFromDocument(doc, caption); initMediaFromDocument(doc, caption);
setText(QString(), EntitiesInText()); setText(QString(), EntitiesInText());
@ -6096,14 +6114,14 @@ HistoryItem(history, block, msgId, flags, date, (flags & MTPDmessage::flag_from_
, _textWidth(0) , _textWidth(0)
, _textHeight(0) , _textHeight(0)
, _media(0) { , _media(0) {
create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1, 0, 0); create((flags & MTPDmessage::flag_via_bot_id) ? viaBotId : 0, isPost() ? 1 : -1);
_media = new HistoryPhoto(photo, caption, this); _media = new HistoryPhoto(photo, caption, this);
_media->regItem(this); _media->regItem(this);
setText(QString(), EntitiesInText()); setText(QString(), EntitiesInText());
} }
void HistoryMessage::create(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal) { void HistoryMessage::create(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal, MsgId originalId) {
uint64 mask = 0; uint64 mask = 0;
if (viaBotId) { if (viaBotId) {
mask |= HistoryMessageVia::Bit(); mask |= HistoryMessageVia::Bit();
@ -6116,9 +6134,6 @@ void HistoryMessage::create(int32 viaBotId, int32 viewsCount, const PeerId &auth
} }
if (authorIdOriginal && fromIdOriginal) { if (authorIdOriginal && fromIdOriginal) {
mask |= HistoryMessageForwarded::Bit(); mask |= HistoryMessageForwarded::Bit();
if (authorIdOriginal != fromIdOriginal) {
mask |= HistoryMessageSigned::Bit();
}
} }
UpdateInterfaces(mask); UpdateInterfaces(mask);
if (HistoryMessageVia *via = Get<HistoryMessageVia>()) { if (HistoryMessageVia *via = Get<HistoryMessageVia>()) {
@ -6133,6 +6148,7 @@ void HistoryMessage::create(int32 viaBotId, int32 viewsCount, const PeerId &auth
if (HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
fwd->_authorOriginal = App::peer(authorIdOriginal); fwd->_authorOriginal = App::peer(authorIdOriginal);
fwd->_fromOriginal = App::peer(fromIdOriginal); fwd->_fromOriginal = App::peer(fromIdOriginal);
fwd->_originalId = originalId;
} }
initTime(); initTime();
} }
@ -6239,7 +6255,7 @@ void HistoryMessage::initDimensions() {
HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>(); HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>();
HistoryMessageVia *via = Get<HistoryMessageVia>(); HistoryMessageVia *via = Get<HistoryMessageVia>();
if (fwd) { if (fwd) {
fwd->authorNameUpdated(via != 0); fwd->create(via);
} }
if (_media) { if (_media) {
@ -6281,7 +6297,7 @@ void HistoryMessage::initDimensions() {
} }
} }
if (fwd) { if (fwd) {
int32 _namew = st::msgPadding.left() + fwd->_fromWidth + fwd->_authorOriginalName.maxWidth() + st::msgPadding.right(); int32 _namew = st::msgPadding.left() + fwd->_text.maxWidth() + st::msgPadding.right();
if (via) { if (via) {
_namew += st::msgServiceFont->spacew + via->_maxWidth; _namew += st::msgServiceFont->spacew + via->_maxWidth;
} }
@ -6374,9 +6390,9 @@ QString HistoryMessage::selectedText(uint32 selection) const {
} }
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
if (selection == FullSelection) { if (selection == FullSelection) {
QString wrapped; QString fwdinfo = fwd->_text.original(0, 0xFFFF, Text::ExpandLinksAll), wrapped;
wrapped.reserve(lang(lng_forwarded_from).size() + fwd->_authorOriginal->name.size() + 4 + result.size()); wrapped.reserve(fwdinfo.size() + 4 + result.size());
wrapped.append('[').append(lang(lng_forwarded_from)).append(' ').append(fwd->_authorOriginal->name).append(qsl("]\n")).append(result); wrapped.append('[').append(fwdinfo).append(qsl("]\n")).append(result);
result = wrapped; result = wrapped;
} }
} }
@ -6592,12 +6608,6 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
if (displayFromName() && author()->nameVersion > _authorNameVersion) { if (displayFromName() && author()->nameVersion > _authorNameVersion) {
fromNameUpdated(width); fromNameUpdated(width);
} }
if (fwd && fwd->_authorOriginal->nameVersion > fwd->_authorOriginalVersion) {
fwd->authorNameUpdated(via != 0);
if (via) {
via->resize(width - st::msgPadding.left() - st::msgPadding.right() - fwd->_fromWidth - fwd->_authorOriginalName.maxWidth() - st::msgServiceFont->spacew);
}
}
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
@ -6649,8 +6659,19 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const { void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const {
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
paintForwardedInfo(p, trect.x(), trect.y(), trect.width(), (selection == FullSelection)); style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont);
trect.setY(trect.y() + st::msgServiceNameFont->height);
bool outbg = out() && !isPost();
p.setPen((selection == FullSelection) ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
p.setFont(serviceFont);
const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>();
bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * serviceFont->height);
textstyleSet(&((selection == FullSelection) ? (outbg ? st::outFwdTextStyleSelected : st::inFwdTextStyleSelected) : (outbg ? st::outFwdTextStyle : st::inFwdTextStyle)));
fwd->_text.drawElided(p, trect.x(), trect.y(), trect.width(), 2, style::al_left, 0, -1, 0, breakEverywhere);
textstyleRestore();
trect.setY(trect.y() + (((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * serviceFont->height));
} }
bool outbg = out() && !isPost(), selected = (selection == FullSelection); bool outbg = out() && !isPost(), selected = (selection == FullSelection);
@ -6729,15 +6750,14 @@ int32 HistoryMessage::resize(int32 width) {
} }
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
int32 l = 0, w = 0;
countPositionAndSize(l, w);
int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height;
if (emptyText() && !displayFromName()) { if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgServiceNameFont->height + st::mediaHeaderSkip; _height += st::msgPadding.top() + fwdheight + st::mediaHeaderSkip;
} else { } else {
_height += st::msgServiceNameFont->height; _height += fwdheight;
}
if (via) {
int32 l = 0, w = 0;
countPositionAndSize(l, w);
via->resize(w - st::msgPadding.left() - st::msgPadding.right() - fwd->_fromWidth - fwd->_authorOriginalName.maxWidth() - st::msgServiceFont->spacew);
} }
} }
} else { } else {
@ -6753,10 +6773,6 @@ bool HistoryMessage::hasPoint(int32 x, int32 y) const {
if (width < 1) return false; if (width < 1) return false;
if (drawBubble()) { if (drawBubble()) {
if (displayForwardedFrom()) {
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
return r.contains(x, y);
}
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
return r.contains(x, y); return r.contains(x, y);
} else { } else {
@ -6817,18 +6833,20 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32
} }
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
QRect trect(r.marginsAdded(-st::msgPadding)); QRect trect(r.marginsAdded(-st::msgPadding));
if (y >= trect.top() && y < trect.top() + st::msgServiceNameFont->height) { int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
if (x >= trect.left() + fwd->_fromWidth && x < trect.right() && x < trect.left() + fwd->_fromWidth + fwd->_authorOriginalName.maxWidth()) { if (y >= trect.top() && y < trect.top() + fwdheight) {
lnk = fwd->_authorOriginal->lnk; bool inText = false;
} else if (via && x >= trect.left() + fwd->_fromWidth + fwd->_authorOriginalName.maxWidth() + st::msgServiceFont->spacew && x < trect.right() && x < trect.left() + fwd->_fromWidth + fwd->_authorOriginalName.maxWidth() + st::msgServiceFont->spacew + via->_maxWidth) { bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * st::semiboldFont->height);
lnk = via->_lnk; textstyleSet(&st::inFwdTextStyle);
} else { fwd->_text.getState(lnk, inText, x - trect.left(), y - trect.top(), trect.right() - trect.left(), style::al_left, breakEverywhere);
lnk = TextLinkPtr(); textstyleRestore();
if (breakEverywhere) {
state = HistoryInForwardedCursorState;
} }
return; return;
} }
y -= st::msgServiceNameFont->height; y -= fwdheight;
r.setHeight(r.height() - st::msgServiceNameFont->height); r.setHeight(r.height() - fwdheight);
} }
getStateFromMessageText(lnk, state, x, y, r); getStateFromMessageText(lnk, state, x, y, r);
} else { } else {
@ -6899,11 +6917,12 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x,
} else if (via && !fwd) { } else if (via && !fwd) {
r.setTop(r.top() + st::msgNameFont->height); r.setTop(r.top() + st::msgNameFont->height);
} }
if (displayForwardedFrom()) {
y -= st::msgServiceNameFont->height;
r.setHeight(r.height() - st::msgServiceNameFont->height);
}
QRect trect(r.marginsAdded(-st::msgPadding)); QRect trect(r.marginsAdded(-st::msgPadding));
if (displayForwardedFrom()) {
int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
y -= fwdheight;
r.setHeight(r.height() - fwdheight);
}
if (_media && _media->isDisplayed()) { if (_media && _media->isDisplayed()) {
trect.setBottom(trect.bottom() - _media->height()); trect.setBottom(trect.bottom() - _media->height());
} }
@ -6956,32 +6975,6 @@ HistoryMessage::~HistoryMessage() {
} }
} }
void HistoryMessage::paintForwardedInfo(Painter &p, int32 x, int32 y, int32 w, bool selected) const {
style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont);
bool outbg = out() && !isPost();
p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p);
p.setFont(serviceFont);
const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>();
const HistoryMessageVia *via = Get<HistoryMessageVia>();
if (via && w > fwd->_fromWidth + fwd->_authorOriginalName.maxWidth() + serviceFont->spacew) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
p.setFont(serviceName);
fwd->_authorOriginalName.draw(p, x + fwd->_fromWidth, y, w - fwd->_fromWidth);
p.drawText(x + fwd->_fromWidth + fwd->_authorOriginalName.maxWidth() + serviceFont->spacew, y + serviceFont->ascent, via->_text);
} else if (w > fwd->_fromWidth) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
p.setFont(serviceName);
fwd->_authorOriginalName.drawElided(p, x + fwd->_fromWidth, y, w - fwd->_fromWidth);
} else {
p.drawText(x, y + serviceFont->ascent, serviceFont->elided(lang(lng_forwarded_from), w));
}
}
HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmessage &msg) : HistoryMessage(history, block, msg) HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmessage &msg) : HistoryMessage(history, block, msg)
, replyToMsgId(msg.vreply_to_msg_id.v) , replyToMsgId(msg.vreply_to_msg_id.v)
, replyToMsg(0) , replyToMsg(0)

View File

@ -769,7 +769,8 @@ class HistoryMessage; // dynamic_cast optimize
enum HistoryCursorState { enum HistoryCursorState {
HistoryDefaultCursorState, HistoryDefaultCursorState,
HistoryInTextCursorState, HistoryInTextCursorState,
HistoryInDateCursorState HistoryInDateCursorState,
HistoryInForwardedCursorState,
}; };
enum InfoDisplayType { enum InfoDisplayType {
@ -819,13 +820,12 @@ struct HistoryMessageSigned : public BasicInterface<HistoryMessageSigned> {
struct HistoryMessageForwarded : public BasicInterface<HistoryMessageForwarded> { struct HistoryMessageForwarded : public BasicInterface<HistoryMessageForwarded> {
HistoryMessageForwarded(Interfaces *); HistoryMessageForwarded(Interfaces *);
void authorNameUpdated(bool hasVia) const; void create(const HistoryMessageVia *via) const;
bool display(bool hasVia) const; bool display(bool hasVia) const;
PeerData *_authorOriginal, *_fromOriginal; PeerData *_authorOriginal, *_fromOriginal;
mutable Text _authorOriginalName; MsgId _originalId;
mutable int32 _authorOriginalVersion; mutable Text _text;
int32 _fromWidth;
}; };
class HistoryMedia; class HistoryMedia;
@ -2116,7 +2116,7 @@ public:
protected: protected:
void create(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal, const PeerId &fromIdOriginal); void create(int32 viaBotId, int32 viewsCount, const PeerId &authorIdOriginal = 0, const PeerId &fromIdOriginal = 0, MsgId originalId = 0);
bool displayForwardedFrom() const { bool displayForwardedFrom() const {
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) { if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {

View File

@ -1610,10 +1610,10 @@ void HistoryInner::onUpdateSelected() {
} }
} }
} }
if (_dragCursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) { if (cursorState != _dragCursorState) {
PopupTooltip::Hide(); PopupTooltip::Hide();
} }
if (lnk || cursorState == HistoryInDateCursorState) { if (lnk || cursorState == HistoryInDateCursorState || cursorState == HistoryInForwardedCursorState) {
PopupTooltip::Show(1000, this); PopupTooltip::Show(1000, this);
} }
@ -1859,6 +1859,12 @@ QString HistoryInner::tooltipText() const {
if (App::hoveredItem()) { if (App::hoveredItem()) {
return App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); return App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat));
} }
} else if (_dragCursorState == HistoryInForwardedCursorState && _dragAction == NoDrag) {
if (App::hoveredItem()) {
if (HistoryMessageForwarded *fwd = App::hoveredItem()->Get<HistoryMessageForwarded>()) {
return fwd->_text.original(0, 0xFFFF, Text::ExpandLinksNone);
}
}
} }
return QString(); return QString();
} }
@ -5532,14 +5538,14 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
flags |= MTPDmessage::flag_from_id; flags |= MTPDmessage::flag_from_id;
} }
if (file->type == PreparePhoto) { if (file->type == PreparePhoto) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread); h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
} else if (file->type == PrepareDocument) { } else if (file->type == PrepareDocument) {
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread); h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
} else if (file->type == PrepareAudio) { } else if (file->type == PrepareAudio) {
if (!h->peer->isChannel()) { if (!h->peer->isChannel()) {
flags |= MTPDmessage::flag_media_unread; flags |= MTPDmessage::flag_media_unread;
} }
h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread); h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
} }
if (_peer && file->to.peer == _peer->id) { if (_peer && file->to.peer == _peer->id) {

View File

@ -700,7 +700,7 @@ void LayoutOverviewVoice::getState(TextLinkPtr &link, HistoryCursorState &cursor
void LayoutOverviewVoice::updateName() const { void LayoutOverviewVoice::updateName() const {
int32 version = 0; int32 version = 0;
if (const HistoryMessageForwarded *fwd = _parent->Get<HistoryMessageForwarded>()) { if (const HistoryMessageForwarded *fwd = _parent->Get<HistoryMessageForwarded>()) {
_name.setText(st::semiboldFont, lang(lng_forwarded_from) + ' ' + App::peerName(_parent->fromOriginal()), _textNameOptions); _name.setText(st::semiboldFont, lng_forwarded(lt_original, App::peerName(_parent->fromOriginal())), _textNameOptions);
} else { } else {
_name.setText(st::semiboldFont, App::peerName(_parent->from()), _textNameOptions); _name.setText(st::semiboldFont, App::peerName(_parent->from()), _textNameOptions);
} }