From 603fb63c91f185f1b77e9c3ce4497280e473d5b0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 11 Dec 2015 21:11:38 +0300 Subject: [PATCH] document new design done with radial progress, ? char added to monospace blocks edges, redraw history item through Notify:: --- Telegram/Resources/style.txt | 54 +-- Telegram/SourceFiles/app.cpp | 8 +- Telegram/SourceFiles/boxes/photosendbox.cpp | 6 +- Telegram/SourceFiles/facades.cpp | 10 +- Telegram/SourceFiles/facades.h | 1 + Telegram/SourceFiles/gui/animation.cpp | 4 +- Telegram/SourceFiles/gui/animation.h | 51 +++ Telegram/SourceFiles/gui/style_core.h | 8 + Telegram/SourceFiles/gui/text.cpp | 17 +- Telegram/SourceFiles/gui/text.h | 2 + Telegram/SourceFiles/history.cpp | 433 +++++++++++++------- Telegram/SourceFiles/history.h | 104 ++++- Telegram/SourceFiles/historywidget.cpp | 111 ++--- Telegram/SourceFiles/historywidget.h | 12 +- Telegram/SourceFiles/mainwidget.cpp | 62 +-- Telegram/SourceFiles/mainwidget.h | 11 +- Telegram/SourceFiles/overviewwidget.cpp | 79 ++-- Telegram/SourceFiles/overviewwidget.h | 7 +- Telegram/SourceFiles/settings.cpp | 2 +- Telegram/SourceFiles/structs.h | 4 + 20 files changed, 649 insertions(+), 337 deletions(-) diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index aa0a0fba38..b364431e91 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1015,25 +1015,25 @@ msgPadding: margins(13px, 7px, 13px, 8px); msgMargin: margins(13px, 4px, 53px, 4px); msgLnkPadding: 2px; // for media open / save links msgBorder: #f0f0f0; -msgOutBg: #effdde; msgInBg: #fff; -msgOutSelectBg: #b7dbdb; -msgInSelectBg: #c2dcf2; // #358cd4 with 30% opacity +msgInBgSelected: #c2dcf2; // #358cd4 with 30% opacity +msgOutBg: #effdde; +msgOutBgSelected: #b7dbdb; msgSelectOverlay: #358cd44c; msgStickerOverlay: #358cd47f; -msgOutServiceColor: #3a8e26; -msgInServiceColor: #0e7acd; -msgOutServiceSelColor: #367570; -msgInServiceSelColor: #0e7acd; +msgInServiceFg: #0e7acd; +msgInServiceFgSelected: #0e7acd; +msgOutServiceFg: #3a8e26; +msgOutServiceFgSelected: #367570; msgShadow: 2px; msgInShadow: #748ea229; +msgInShadowSelected: #548dbb29; msgOutShadow: #3ac34740; -msgInSelectShadow: #548dbb29; -msgOutSelectShadow: #37a78e40; -msgInDateColor: #a0acb6; -msgOutDateColor: #6cc264; -msgInSelectDateColor: #6a9cc5; -msgOutSelectDateColor: #50a79c; +msgOutShadowSelected: #37a78e40; +msgInDateFg: #a0acb6; +msgInDateFgSelected: #6a9cc5; +msgOutDateFg: #6cc264; +msgOutDateFgSelected: #50a79c; msgReplyPadding: margins(6px, 6px, 11px, 6px); msgReplyBarPos: point(1px, 0px); @@ -1086,7 +1086,8 @@ msgDateDelta: point(2px, 5px); msgDateImgDelta: 4px; msgDateImgColor: #fff; msgDateImgBg: #00000054; -msgDateImgSelectBg: #1c4a7187; +msgDateImgBgOver: #00000074; +msgDateImgBgSelected: #1c4a7187; msgDateImgPadding: point(8px, 2px); msgDateImgCheckSpace: 4px; @@ -1117,7 +1118,7 @@ defaultTextStyle: textStyle { linkFg: btnYesColor; linkFgDown: btnYesHover; monoFg: #777; - selectBg: msgInSelectBg; + selectBg: msgInBgSelected; selectOverlay: msgSelectOverlay; lineHeight: 0px; } @@ -1135,12 +1136,12 @@ serviceTextStyle: textStyle(defaultTextStyle) { } inTextStyle: textStyle(defaultTextStyle) { monoFg: #4e7391; - selectBg: msgInSelectBg; + selectBg: msgInBgSelected; selectOverlay: msgSelectOverlay; } outTextStyle: textStyle(defaultTextStyle) { monoFg: #469165; - selectBg: msgOutSelectBg; + selectBg: msgOutBgSelected; selectOverlay: msgSelectOverlay; } medviewSaveAsTextStyle: textStyle(defaultTextStyle) { @@ -1177,14 +1178,14 @@ mediaPlayOutImg: sprite(122px, 341px, 48px, 48px); mediaPlayInImg: sprite(172px, 341px, 48px, 48px); mediaPauseOutImg: sprite(222px, 341px, 48px, 48px); mediaPauseInImg: sprite(272px, 341px, 48px, 48px); -mediaInColor: msgInDateColor; -mediaOutColor: msgOutDateColor; -mediaInSelectColor: msgInSelectDateColor; -mediaOutSelectColor: msgOutSelectDateColor; -mediaOutUnreadColor: #6aad60; -mediaOutUnreadSelectColor: #5aa382; -mediaInUnreadColor: #999; -mediaInUnreadSelectColor: #7b95aa; +mediaInFg: msgInDateFg; +mediaInFgSelected: msgInDateFgSelected; +mediaOutFg: msgOutDateFg; +mediaOutFgSelected: msgOutDateFgSelected; +mediaInUnreadFg: #999; +mediaInUnreadFgSelected: #7b95aa; +mediaOutUnreadFg: #6aad60; +mediaOutUnreadFgSelected: #5aa382; mediaUnreadSize: 4px; mediaUnreadSkip: 5px; @@ -1235,6 +1236,9 @@ msgFileOutPlaySelected: sprite(180px, 146px, 20px, 18px); msgFileInPlay: sprite(160px, 164px, 20px, 18px); msgFileInPlaySelected: sprite(180px, 164px, 20px, 18px); +msgFileOverDuration: 200; +msgFileRadialLine: 4px; + sendPadding: 9px; btnSend: flatButton(btnDefFlat) { color: btnYesColor; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 4b326a5776..7d6663e9fd 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2129,9 +2129,9 @@ namespace App { prepareCorners(ServiceSelectedCorners, st::msgRadius, st::msgServiceSelectBg); prepareCorners(SelectedOverlayCorners, st::msgRadius, st::msgSelectOverlay); prepareCorners(DateCorners, st::msgRadius, st::msgDateImgBg); - prepareCorners(DateSelectedCorners, st::msgRadius, st::msgDateImgSelectBg); + prepareCorners(DateSelectedCorners, st::msgRadius, st::msgDateImgBgSelected); prepareCorners(InShadowCorners, st::msgRadius, st::msgInShadow); - prepareCorners(InSelectedShadowCorners, st::msgRadius, st::msgInSelectShadow); + prepareCorners(InSelectedShadowCorners, st::msgRadius, st::msgInShadowSelected); prepareCorners(ForwardCorners, st::msgRadius, st::forwardBg); prepareCorners(MediaviewSaveCorners, st::msgRadius, st::medviewSaveMsg); prepareCorners(EmojiHoverCorners, st::msgRadius, st::emojiPanHover); @@ -2147,9 +2147,9 @@ namespace App { prepareCorners(DocBlueCorners, st::msgRadius, st::mvDocBlueColor); prepareCorners(MessageInCorners, st::msgRadius, st::msgInBg, &st::msgInShadow); - prepareCorners(MessageInSelectedCorners, st::msgRadius, st::msgInSelectBg, &st::msgInSelectShadow); + prepareCorners(MessageInSelectedCorners, st::msgRadius, st::msgInBgSelected, &st::msgInShadowSelected); prepareCorners(MessageOutCorners, st::msgRadius, st::msgOutBg, &st::msgOutShadow); - prepareCorners(MessageOutSelectedCorners, st::msgRadius, st::msgOutSelectBg, &st::msgOutSelectShadow); + prepareCorners(MessageOutSelectedCorners, st::msgRadius, st::msgOutBgSelected, &st::msgOutShadowSelected); } diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp index e64337b414..c38770a693 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.cpp +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -210,15 +210,15 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) { p.drawPixmap(x + st::mediaPadding.left(), y + st::mediaPadding.top(), userDefPhoto(1)->pix(st::mediaThumbSize)); } - p.setFont(st::normalFont->f); - p.setPen(st::black->c); + p.setFont(st::normalFont); + p.setPen(st::black); if (twidth < _namew) { p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaNameTop + st::normalFont->ascent, st::normalFont->elided(_name, twidth)); } else { p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaNameTop + st::normalFont->ascent, _name); } - p.setPen(st::mediaOutColor->p); + p.setPen(st::mediaOutFg); p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaThumbSize - st::mediaDetailsShift - st::normalFont->descent, _size); } } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index afd723eea7..6cf9731950 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -96,15 +96,19 @@ namespace Ui { namespace Notify { void userIsBotChanged(UserData *user) { - if (MainWidget *m = App::main()) m->notifyUserIsBotChanged(user); + if (MainWidget *m = App::main()) m->notify_userIsBotChanged(user); } void botCommandsChanged(UserData *user) { - if (MainWidget *m = App::main()) m->notifyBotCommandsChanged(user); + if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user); } void migrateUpdated(PeerData *peer) { - if (MainWidget *m = App::main()) m->notifyMigrateUpdated(peer); + if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); + } + + void redrawHistoryItem(const HistoryItem *item) { + if (MainWidget *m = App::main()) m->notify_redrawHistoryItem(item); } } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index cc6cdb6060..790c990de0 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -53,5 +53,6 @@ namespace Notify { void userIsBotChanged(UserData *user); void botCommandsChanged(UserData *user); void migrateUpdated(PeerData *peer); + void redrawHistoryItem(const HistoryItem *item); }; diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp index 333db29bb4..89c28b3a23 100644 --- a/Telegram/SourceFiles/gui/animation.cpp +++ b/Telegram/SourceFiles/gui/animation.cpp @@ -153,8 +153,8 @@ void AnimatedGif::step_frame(float64 ms, bool timer) { if (frame != f) { frame = f; if (timer) { - if (msg && App::main()) { - App::main()->msgUpdated(msg); + if (msg) { + Notify::redrawHistoryItem(msg); } else { emit updated(); } diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h index abb9b2ce4b..e201913872 100644 --- a/Telegram/SourceFiles/gui/animation.h +++ b/Telegram/SourceFiles/gui/animation.h @@ -284,6 +284,57 @@ AnimationCallbacks *animation(Type *obj, typename AnimationCallbacksAbsolute(obj, method); } +template +class AnimationCallbacksRelativeWithParam : public AnimationCallbacks { +public: + typedef void (Type::*Method)(Param, float64, bool); + + AnimationCallbacksRelativeWithParam(Param param, Type *obj, Method method) : _started(0), _param(param), _obj(obj), _method(method) { + } + + void start() { + _started = float64(getms()); + } + + void step(Animation *a, uint64 ms, bool timer) { + (_obj->*_method)(_param, ms - _started, timer); + } + +private: + float64 _started; + Param _param; + Type *_obj; + Method _method; + +}; +template +AnimationCallbacks *animation(Param param, Type *obj, typename AnimationCallbacksRelativeWithParam::Method method) { + return new AnimationCallbacksRelativeWithParam(param, obj, method); +} + +template +class AnimationCallbacksAbsoluteWithParam : public AnimationCallbacks { +public: + typedef void (Type::*Method)(Param, uint64, bool); + + AnimationCallbacksAbsoluteWithParam(Param param, Type *obj, Method method) : _param(param), _obj(obj), _method(method) { + } + + void step(Animation *a, uint64 ms, bool timer) { + (_obj->*_method)(_param, ms, timer); + } + +private: + Param _param; + Type *_obj; + Method _method; + +}; +template +AnimationCallbacks *animation(Param param, Type *obj, typename AnimationCallbacksAbsoluteWithParam::Method method) { + return new AnimationCallbacksAbsoluteWithParam(param, obj, method); +} + class AnimationManager : public QObject { Q_OBJECT diff --git a/Telegram/SourceFiles/gui/style_core.h b/Telegram/SourceFiles/gui/style_core.h index 8939118bc8..8642a701ac 100644 --- a/Telegram/SourceFiles/gui/style_core.h +++ b/Telegram/SourceFiles/gui/style_core.h @@ -304,6 +304,14 @@ namespace style { typedef Font font; typedef Color color; + inline QColor interpolate(const style::color &a, const style::color &b, float64 opacity_b) { + QColor result; + result.setRedF((a->c.redF() * (1. - opacity_b)) + (b->c.redF() * opacity_b)); + result.setGreenF((a->c.greenF() * (1. - opacity_b)) + (b->c.greenF() * opacity_b)); + result.setBlueF((a->c.blueF() * (1. - opacity_b)) + (b->c.blueF() * opacity_b)); + return result; + } + void startManager(); void stopManager(); diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index cddee2412e..aec996a4d1 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -38,8 +38,8 @@ namespace { const QRegularExpression _reHashtag(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{5,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); const QRegularExpression _reBotCommand(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])/[A-Za-z_0-9]{1,64}(@[A-Za-z_0-9]{5,32})?([\\W]|$)")); - const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); - const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); + const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); + const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); QSet _validProtocols, _validTopDomains; const style::textStyle *_textStyle = 0; @@ -103,6 +103,10 @@ const TextLinkPtr &textlnkDown() { return _downLnk; } +bool textlnkDrawOver(const TextLinkPtr &lnk) { + return (_overLnk == lnk) && (!_downLnk || _downLnk == lnk); +} + QString textOneLine(const QString &text, bool trim, bool rich) { QString result(text); const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); @@ -1385,6 +1389,7 @@ public: return true; } + int skipIndex = -1; QVarLengthArray visualOrder(nItems); QVarLengthArray levels(nItems); for (int i = 0; i < nItems; ++i) { @@ -1396,6 +1401,7 @@ public: TextBlockType _type = currentBlock->type(); if (_type == TextBlockTSkip) { levels[i] = si.analysis.bidiLevel = 0; + skipIndex = i; } else { levels[i] = si.analysis.bidiLevel; } @@ -1406,6 +1412,13 @@ public: } } QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + if (rtl() && skipIndex == nItems - 1) { + for (int32 i = nItems; i > 1;) { + --i; + visualOrder[i] = visualOrder[i - 1]; + } + visualOrder[0] = skipIndex; + } blockIndex = _lineStartBlock; currentBlock = _t->_blocks[blockIndex]; diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h index c1ff5a911c..59cb4ad9a7 100644 --- a/Telegram/SourceFiles/gui/text.h +++ b/Telegram/SourceFiles/gui/text.h @@ -680,6 +680,8 @@ const TextLinkPtr &textlnkOver(); void textlnkDown(const TextLinkPtr &lnk); const TextLinkPtr &textlnkDown(); +bool textlnkDrawOver(const TextLinkPtr &lnk); + // textcmd QString textcmdSkipBlock(ushort w, ushort h); QString textcmdStartLink(ushort lnkIndex); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index c7efa4626a..d32537a5d9 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2973,7 +2973,7 @@ void ItemAnimations::step_animate(float64 ms, bool timer) { for (Animations::iterator i = _animations.begin(); i != _animations.end();) { const HistoryItem *item = i.key(); if (item->animating()) { - if (timer) App::main()->msgUpdated(item); + if (timer) Notify::redrawHistoryItem(item); ++i; } else { i = _animations.erase(i); @@ -3100,6 +3100,72 @@ HistoryItem *regItem(HistoryItem *item, bool returnExisting) { return item; } +RadialAnimation::RadialAnimation(int32 thickness, AnimationCallbacks *callbacks) : _thickness(thickness) +, _firstStart(0) +, _lastStart(0) +, _lastTime(0) +, _opacity(0) +, a_arcEnd(0, 0) +, a_arcStart(0, 1) +, _animation(callbacks) { + +} + +void RadialAnimation::start(float64 prg) { + _firstStart = _lastStart = _lastTime = getms(); + a_arcEnd = anim::fvalue(prg, qMax(prg, 0.0001)); + _animation.start(); +} + +void RadialAnimation::update(float64 prg, bool finished, uint64 ms) { + if (prg < 0.0001) prg = 0.0001; + + if (prg != a_arcEnd.to()) { + a_arcEnd.start(prg); + _lastStart = _lastTime; + } + _lastTime = ms; + + float64 dt = float64(ms - _lastStart), fulldt = float64(ms - _firstStart); + _opacity = qMin(fulldt / st::radialDuration, 1.); + if (!finished) { + a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear); + } else if (dt >= st::radialDuration) { + a_arcEnd.update(1, anim::linear); + stop(); + } else { + float64 r = dt / st::radialDuration; + a_arcEnd.update(r, anim::linear); + _opacity *= 1 - r; + } + float64 fromstart = fulldt / st::radialPeriod; + a_arcStart.update(fromstart - qFloor(fromstart), anim::linear); +} + +void RadialAnimation::stop() { + _firstStart = _lastStart = _lastTime = 0; + a_arcEnd = anim::fvalue(0, 0); + _animation.stop(); +} + +void RadialAnimation::draw(Painter &p, const QRect &inner, const style::color &color) { + p.setRenderHint(QPainter::HighQualityAntialiasing); + + float64 o = p.opacity(); + p.setOpacity(o * _opacity); + + QPen pen(color->p), was(p.pen()); + pen.setWidth(_thickness); + p.setPen(pen); + + int32 len = 16 + a_arcEnd.current() * 5744; + p.drawArc(inner, 1440 - a_arcStart.current() * 5760 - len, len); + + p.setPen(was); + p.setOpacity(o); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); +} + HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, const QString &caption, HistoryItem *parent) : HistoryMedia() , _data(App::feedPhoto(photo)) , _openl(new PhotoLink(_data)) @@ -3291,13 +3357,14 @@ void HistoryPhoto::updateFrom(const MTPMessageMedia &media) { } } -void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { +void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; + int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); + bool bubble = parent->hasBubble(); bool fromChannel = parent->fromChannel(), out = parent->out(), outbg = out && !fromChannel; - if (width < 0) width = w; - int skipx = 0, skipy = 0, height = _height; - int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); if (bubble) { skipx = st::mediaPadding.left(); skipy = st::mediaPadding.top(); @@ -3308,7 +3375,7 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, bool selected, in height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom(); } } else { - App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInSelectShadow : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); + App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } _data->full->load(false, false); @@ -3322,7 +3389,7 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, bool selected, in p.drawPixmap(skipx, skipy, pix); if (!full) { - uint64 dt = itemAnimations().animate(parent, getms()); + uint64 dt = itemAnimations().animate(parent, ms); int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta); int32 x = (width - st::photoLoader.width()) / 2, y = (height - st::photoLoader.height()) / 2; @@ -3350,7 +3417,7 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, bool selected, in QString time(parent->timeText()); if (_caption.isEmpty()) { int32 fullRight = skipx + width, fullBottom = skipy + height; - parent->drawInfo(p, fullRight, fullBottom, selected, InfoDisplayOverImage); + parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); } else { p.setPen(st::black); _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw); @@ -3528,16 +3595,9 @@ HistoryMedia *HistoryVideo::clone() const { return new HistoryVideo(*this); } -void HistoryVideo::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - int32 height = _height; - if (width < 0) { - width = w; - } else if (!_caption.isEmpty()) { - height = countHeight(parent, width); - } - if (width < 1) return; - - int skipy = 0, replyFrom = 0, fwdFrom = 0; +void HistoryVideo::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; data->thumb->checkload(); @@ -3546,8 +3606,8 @@ void HistoryVideo::draw(Painter &p, const HistoryItem *parent, bool selected, in width = _maxw; } - style::color bg(selected ? (outbg ? st::msgOutSelectBg : st::msgInSelectBg) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutSelectShadow : st::msgInSelectShadow) : (outbg ? st::msgOutShadow : st::msgInShadow)); + style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg)); + style::color sh(outbg ? (selected ? st::msgOutShadowSelected : st::msgOutShadow) : (selected ? st::msgInShadowSelected : st::msgInShadow)); RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, 0, 0, width, height, bg, cors, &sh); @@ -3570,7 +3630,7 @@ void HistoryVideo::draw(Painter &p, const HistoryItem *parent, bool selected, in QString statusText; - style::color status(selected ? (outbg ? st::mediaOutSelectColor : st::mediaInSelectColor) : (outbg ? st::mediaOutColor : st::mediaInColor)); + style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); p.setPen(status->p); if (data->loader) { @@ -3600,20 +3660,15 @@ void HistoryVideo::draw(Painter &p, const HistoryItem *parent, bool selected, in if (w + st::mediaUnreadSkip + st::mediaUnreadSize <= twidth) { p.setRenderHint(QPainter::HighQualityAntialiasing, true); p.setPen(Qt::NoPen); - p.setBrush((outbg ? (selected ? st::mediaOutUnreadSelectColor : st::mediaOutUnreadColor) : (selected ? st::mediaInUnreadSelectColor : st::mediaInUnreadColor))->b); + p.setBrush((outbg ? (selected ? st::mediaOutUnreadFgSelected : st::mediaOutUnreadFg) : (selected ? st::mediaInUnreadFgSelected : st::mediaInUnreadFg))->b); p.drawEllipse(QRect(tleft + w + st::mediaUnreadSkip, texty + ((st::normalFont->height - st::mediaUnreadSize) / 2), st::mediaUnreadSize, st::mediaUnreadSize)); p.setRenderHint(QPainter::HighQualityAntialiasing, false); } } - p.setFont(st::msgDateFont->f); - if (!_caption.isEmpty()) { p.setPen(st::black->p); _caption.draw(p, st::mediaPadding.left(), skipy + st::mediaPadding.top() + st::mediaThumbSize + st::webPagePhotoSkip, width - st::mediaPadding.left() - st::mediaPadding.right()); } - - int32 fullRight = width, fullBottom = height; - parent->drawInfo(p, fullRight, fullBottom, selected, InfoDisplayDefault); } int32 HistoryVideo::resize(int32 width, const HistoryItem *parent) { @@ -3660,12 +3715,10 @@ void HistoryAudio::initDimensions(const HistoryItem *parent) { _height = _minh; } -void HistoryAudio::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; +void HistoryAudio::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + int32 width = w, skipy = 0, replyFrom = 0, fwdFrom = 0; if (width < 1) return; - int skipy = 0, replyFrom = 0, fwdFrom = 0; - bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel, hovered, pressed; bool already = !data->already().isEmpty(), hasdata = !data->data.isEmpty(); if (width >= _maxw) { @@ -3676,8 +3729,8 @@ void HistoryAudio::draw(Painter &p, const HistoryItem *parent, bool selected, in data->save(QString()); } - style::color bg(selected ? (outbg ? st::msgOutSelectBg : st::msgInSelectBg) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutSelectShadow : st::msgInSelectShadow) : (outbg ? st::msgOutShadow : st::msgInShadow)); + style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg)); + style::color sh(outbg ? (selected ? st::msgOutShadowSelected : st::msgOutShadow) : (selected ? st::msgInShadowSelected : st::msgInShadow)); RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, 0, 0, width, _height, bg, cors, &sh); @@ -3737,7 +3790,7 @@ void HistoryAudio::draw(Painter &p, const HistoryItem *parent, bool selected, in p.setPen(st::black->c); p.drawText(tleft, skipy + st::mediaPadding.top() + st::mediaNameTop + st::normalFont->ascent, lang(lng_media_audio)); - style::color status(selected ? (outbg ? st::mediaOutSelectColor : st::mediaInSelectColor) : (outbg ? st::mediaOutColor : st::mediaInColor)); + style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); p.setPen(status->p); int32 texty = skipy + st::mediaPadding.top() + st::mediaThumbSize - st::mediaDetailsShift - st::normalFont->height; p.drawText(tleft, texty + st::normalFont->ascent, statusText); @@ -3746,18 +3799,11 @@ void HistoryAudio::draw(Painter &p, const HistoryItem *parent, bool selected, in if (w + st::mediaUnreadSkip + st::mediaUnreadSize <= twidth) { p.setRenderHint(QPainter::HighQualityAntialiasing, true); p.setPen(Qt::NoPen); - p.setBrush((outbg ? (selected ? st::mediaOutUnreadSelectColor : st::mediaOutUnreadColor) : (selected ? st::mediaInUnreadSelectColor : st::mediaInUnreadColor))->b); + p.setBrush((outbg ? (selected ? st::mediaOutUnreadFgSelected : st::mediaOutUnreadFg) : (selected ? st::mediaInUnreadFgSelected : st::mediaInUnreadFg))->b); p.drawEllipse(QRect(tleft + w + st::mediaUnreadSkip, texty + ((st::normalFont->height - st::mediaUnreadSize) / 2), st::mediaUnreadSize, st::mediaUnreadSize)); p.setRenderHint(QPainter::HighQualityAntialiasing, false); } } - p.setFont(st::msgDateFont->f); - - style::color date(selected ? (outbg ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (outbg ? st::msgOutDateColor : st::msgInDateColor)); - p.setPen(date->p); - - int32 fullRight = width, fullBottom = _height; - parent->drawInfo(p, fullRight, fullBottom, selected, InfoDisplayDefault); } void HistoryAudio::regItem(HistoryItem *item) { @@ -3848,9 +3894,10 @@ HistoryDocument::HistoryDocument(DocumentData *document) : HistoryMedia() , _savel(new DocumentSaveLink(_data)) , _thumbsavel(new DocumentSaveLink(_data)) , _cancell(new DocumentCancelLink(_data)) -, _name(documentName(_data)) { +, _name(documentName(_data)) +, _animation(0) { if (_name.isEmpty()) _name = qsl("Unknown File"); - _namew = st::normalFont->width(_name); + _namew = st::semiboldFont->width(_name); setStatusSize(FileStatusSizeReady); @@ -3862,10 +3909,8 @@ HistoryDocument::HistoryDocument(DocumentData *document) : HistoryMedia() } else { _thumbw = st::msgFileThumbSize; } - _height = _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); } else { _thumbw = 0; - _height = _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); } } @@ -3946,11 +3991,17 @@ void HistoryDocument::initDimensions(const HistoryItem *parent) { _maxw = qMax(tleft + _namew + tright, _maxw); _maxw = qMin(_maxw, int(st::msgMaxWidth)); + + if (withThumb()) { + _height = _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); + } else { + _height = _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); + } } -void HistoryDocument::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - if (width < 1) return; +void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel; bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty(); @@ -3960,6 +4011,14 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, bool selected, } bool showPause = updateStatusText(parent); + bool radial = _animation && _animation->radial.animating(); + + if (_data->loader) { + ensureAnimation(parent); + if (!_animation->radial.animating()) { + _animation->radial.start(_data->progress()); + } + } int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; bool wthumb = withThumb(); @@ -3981,29 +4040,47 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, bool selected, App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); } - if (already || hasdata) { + if (!radial && (already || hasdata)) { } else { - p.setRenderHint(QPainter::HighQualityAntialiasing); - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); - p.setBrush(selected ? st::msgDateImgSelectBg : st::msgDateImgBg); - p.drawEllipse(inner); + if (selected) { + p.setBrush(st::msgDateImgBgSelected); + } else if (radial && (already || hasdata)) { + p.setOpacity(st::msgDateImgBg->c.alphaF() * _animation->radial.opacity()); + p.setBrush(st::black); + } else if (_animation && _animation->_a_thumbOver.animating()) { + float64 over = _animation->a_thumbOver.current(); + p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); + p.setBrush(st::black); + } else { + bool over = textlnkDrawOver(_thumbsavel); + p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); + } + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); p.setRenderHint(QPainter::HighQualityAntialiasing, false); style::sprite icon; - if (_data->loader) { + if (already || hasdata || _data->loader) { icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); } else { icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); } + p.setOpacity(radial ? _animation->radial.opacity() : 1); p.drawSpriteCenter(inner, icon); + if (radial) { + p.setOpacity(1); + + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + _animation->radial.draw(p, rinner, selected ? st::msgInBgSelected : st::msgInBg); + } } if (_data->status != FileUploadFailed) { const TextLinkPtr &lnk((_data->loader || _data->status == FileUploading) ? _cancell : _savel); - bool over = (textlnkOver() == lnk) && (!textlnkDown() || textlnkDown() == lnk); + bool over = textlnkDrawOver(lnk); p.setFont(over ? st::semiboldFont->underline() : st::semiboldFont); p.setPen(outbg ? (selected ? st::msgFileThumbLinkOutFgSelected : st::msgFileThumbLinkOutFg) : (selected ? st::msgFileThumbLinkInFgSelected : st::msgFileThumbLinkInFg)); p.drawTextLeft(nameleft, linktop, width, _link, _linkw); @@ -4014,15 +4091,28 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, bool selected, nameright = st::msgFilePadding.left(); statustop = st::msgFileStatusTop; - p.setRenderHint(QPainter::HighQualityAntialiasing); - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width)); p.setPen(Qt::NoPen); - p.setBrush(outbg ? (selected ? st::msgFileOutBgSelected : st::msgFileOutBg) : (selected ? st::msgFileInBgSelected : st::msgFileInBg)); - p.drawEllipse(inner); + if (selected) { + p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected); + } else if (_animation && _animation->_a_thumbOver.animating()) { + float64 over = _animation->a_thumbOver.current(); + p.setBrush(style::interpolate(outbg ? st::msgFileOutBg : st::msgFileInBg, outbg ? st::msgFileOutBgOver : st::msgFileInBgOver, over)); + } else { + bool over = textlnkDrawOver(_thumbsavel); + p.setBrush(outbg ? (over ? st::msgFileOutBgOver : st::msgFileOutBg) : (over ? st::msgFileInBgOver : st::msgFileInBg)); + } + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); p.setRenderHint(QPainter::HighQualityAntialiasing, false); + if (radial) { + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg)); + _animation->radial.draw(p, rinner, bg); + } + style::sprite icon; if (showPause) { icon = outbg ? (selected ? st::msgFileOutPauseSelected : st::msgFileOutPause) : (selected ? st::msgFileInPauseSelected : st::msgFileInPause); @@ -4051,7 +4141,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, bool selected, p.drawTextLeft(nameleft, nametop, width, _name, _namew); } - style::color status(selected ? (outbg ? st::mediaOutSelectColor : st::mediaInSelectColor) : (outbg ? st::mediaOutColor : st::mediaInColor)); + style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); p.setFont(st::normalFont); p.setPen(status); p.drawTextLeft(nameleft, statustop, width, _statusText); @@ -4062,7 +4152,7 @@ void HistoryDocument::drawInPlaylist(Painter &p, const HistoryItem *parent, bool bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty(); int32 height = st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom(); - style::color bg(selected ? st::msgInSelectBg : (over ? st::playlistHoverBg : st::msgInBg)); + style::color bg(selected ? st::msgInBgSelected : (over ? st::playlistHoverBg : st::msgInBg)); p.fillRect(0, 0, width, height, bg->b); style::sprite img = st::mediaMusicInImg; @@ -4105,7 +4195,7 @@ void HistoryDocument::drawInPlaylist(Painter &p, const HistoryItem *parent, bool p.drawTextLeft(tleft, st::msgPadding.top() + st::mediaNameTop, width, _name, _namew); } - style::color status(selected ? st::mediaInSelectColor : st::mediaInColor); + style::color status(selected ? st::mediaInFgSelected : st::mediaInFg); p.setPen(status->p); p.drawTextLeft(tleft, st::msgPadding.top() + st::mediaThumbSize - st::mediaDetailsShift - st::normalFont->height, width, _statusText); } @@ -4209,6 +4299,63 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 } } +void HistoryDocument::linkOver(HistoryItem *parent, const TextLinkPtr &lnk) { + if (lnk == _thumbsavel && _data->already().isEmpty() && _data->data.isEmpty()) { + ensureAnimation(parent); + _animation->a_thumbOver.start(1); + _animation->_a_thumbOver.start(); + } +} + +void HistoryDocument::linkOut(HistoryItem *parent, const TextLinkPtr &lnk) { + if (_animation && lnk == _thumbsavel) { + _animation->a_thumbOver.start(0); + _animation->_a_thumbOver.start(); + } +} + +void HistoryDocument::step_thumbOver(const HistoryItem *parent, float64 ms, bool timer) { + float64 dt = ms / st::msgFileOverDuration; + if (dt >= 1) { + _animation->a_thumbOver.finish(); + _animation->_a_thumbOver.stop(); + checkAnimationFinished(); + } else { + _animation->a_thumbOver.update(dt, anim::linear); + } + if (timer) { + Notify::redrawHistoryItem(parent); + } +} + +void HistoryDocument::step_radial(const HistoryItem *parent, uint64 ms, bool timer) { + _animation->radial.update(_data->progress(), !_data->loader, ms); + if (!_animation->radial.animating()) { + checkAnimationFinished(); + } + if (timer) { + Notify::redrawHistoryItem(parent); + } +} + +void HistoryDocument::ensureAnimation(const HistoryItem *parent) const { + if (!_animation) { + _animation = new AnimationData( + animation(parent, const_cast(this), &HistoryDocument::step_thumbOver), + animation(parent, const_cast(this), &HistoryDocument::step_radial) + ); + } +} + +void HistoryDocument::checkAnimationFinished() { + if (_animation && !_animation->_a_thumbOver.animating() && !_animation->radial.animating()) { + if (!_data->already().isEmpty() || !_data->data.isEmpty()) { + delete _animation; + _animation = 0; + } + } +} + HistoryMedia *HistoryDocument::clone() const { return new HistoryDocument(*this); } @@ -4217,6 +4364,11 @@ ImagePtr HistoryDocument::replyPreview() { return _data->makeReplyPreview(); } +HistoryDocument::~HistoryDocument() { + delete _animation; + _animation = 0; +} + HistoryGif::HistoryGif(DocumentData *document) : HistoryMedia() , _data(document) , _openl(new DocumentOpenLink(_data)) @@ -4237,9 +4389,9 @@ void HistoryGif::initDimensions(const HistoryItem *parent) { _height = _minh; } -void HistoryGif::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - if (width < 1) return; +void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel, hovered, pressed; bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty(); @@ -4251,7 +4403,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, bool selected, int3 if (ph < 1) ph = 1; } - App::roundShadow(p, 0, 0, pw, ph, selected ? st::msgInSelectShadow : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); + App::roundShadow(p, 0, 0, pw, ph, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); p.drawPixmap(0, 0, animated.current(pw * cIntRetinaFactor(), ph * cIntRetinaFactor(), true)); if (selected) { @@ -4387,9 +4539,10 @@ void HistorySticker::initDimensions(const HistoryItem *parent) { w = qMin(lastw, _maxw); } -void HistorySticker::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - if (width < 1) return; +void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; + if (width > _maxw) width = _maxw; bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel, hovered, pressed; @@ -4429,7 +4582,7 @@ void HistorySticker::draw(Painter &p, const HistoryItem *parent, bool selected, } } - parent->drawInfo(p, usex + usew, _height, selected, InfoDisplayOverImage); + parent->drawInfo(p, usex + usew, _height, usex * 2 + usew, selected, InfoDisplayOverImage); if (reply) { int32 rw = width - usew - st::msgReplyPadding.left(), rh = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); @@ -4593,19 +4746,17 @@ HistoryMedia *HistoryContact::clone() const { return new HistoryContact(userId, name.original(), phone); } -void HistoryContact::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - if (width < 1) return; - - int skipy = 0, replyFrom = 0, fwdFrom = 0; +void HistoryContact::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel; if (width >= _maxw) { width = _maxw; } - style::color bg(selected ? (outbg ? st::msgOutSelectBg : st::msgInSelectBg) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutSelectShadow : st::msgInSelectShadow) : (outbg ? st::msgOutShadow : st::msgInShadow)); + style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg)); + style::color sh(outbg ? (selected ? st::msgOutShadowSelected : st::msgOutShadow) : (selected ? st::msgInShadowSelected : st::msgInShadow)); RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, 0, 0, width, _height, bg, cors, &sh); @@ -4626,13 +4777,10 @@ void HistoryContact::draw(Painter &p, const HistoryItem *parent, bool selected, p.drawText(tleft, skipy + st::mediaPadding.top() + st::mediaNameTop + st::normalFont->ascent, phone); } - style::color status(selected ? (outbg ? st::mediaOutSelectColor : st::mediaInSelectColor) : (outbg ? st::mediaOutColor : st::mediaInColor)); + style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); p.setPen(status->p); name.drawElided(p, tleft, skipy + st::mediaPadding.top() + st::mediaThumbSize - st::mediaDetailsShift - st::normalFont->height, secondwidth); - - int32 fullRight = width, fullBottom = _height; - parent->drawInfo(p, fullRight, fullBottom, selected, InfoDisplayDefault); } void HistoryContact::updateFrom(const MTPMessageMedia &media) { @@ -4795,9 +4943,9 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) { _height = _minh; } -void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - if (width < 1 || data->pendingTill) return; +void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; int16 animw = 0, animh = 0; if (data->doc && animated.msg == parent) { @@ -4826,8 +4974,8 @@ void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, bool selected, bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel; style::color bar = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); - style::color semibold = (selected ? (outbg ? st::msgOutServiceSelColor : st::msgInServiceSelColor) : (outbg ? st::msgOutServiceColor : st::msgInServiceColor)); - style::color regular = (selected ? (outbg ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (outbg ? st::msgOutDateColor : st::msgInDateColor)); + style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); + style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); p.fillRect(0, 0, st::webPageBar, _height - bottomSkip, bar->b); p.save(); @@ -4911,7 +5059,7 @@ void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, bool selected, } p.drawPixmap(0, 0, pix); if (!full) { - uint64 dt = itemAnimations().animate(parent, getms()); + uint64 dt = itemAnimations().animate(parent, ms); int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta); int32 x = (pixwidth - st::photoLoader.width()) / 2, y = (pixheight - st::photoLoader.height()) / 2; @@ -4947,7 +5095,7 @@ void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, bool selected, int32 dateW = pixwidth - dateX - st::msgDateImgDelta; int32 dateH = pixheight - dateY - st::msgDateImgDelta; - App::roundRect(p, dateX, dateY, dateW, dateH, selected ? st::msgDateImgSelectBg : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); + App::roundRect(p, dateX, dateY, dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); p.setFont(st::msgDateFont->f); p.setPen(st::msgDateImgColor->p); @@ -5044,7 +5192,7 @@ void HistoryWebPage::draw(Painter &p, const HistoryItem *parent, bool selected, p.drawText(tleft, st::mediaNameTop + st::normalFont->ascent, _docName); } - style::color status(selected ? (outbg ? st::mediaOutSelectColor : st::mediaInSelectColor) : (outbg ? st::mediaOutColor : st::mediaInColor)); + style::color status(outbg ? (selected ? st::mediaOutFgSelected : st::mediaOutFg) : (selected ? st::mediaInFgSelected : st::mediaInFg)); p.setPen(status->p); p.drawText(tleft, st::mediaThumbSize - st::mediaDetailsShift - st::normalFont->descent, statusText); @@ -5709,16 +5857,17 @@ void HistoryImageLink::initDimensions(const HistoryItem *parent) { _height = _minh; } -void HistoryImageLink::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const { - if (width < 0) width = w; - int skipx = 0, skipy = 0, height = _height; +void HistoryImageLink::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (w < st::msgPadding.left() + st::msgPadding.right() + 1) return; + int32 width = w, height = _height, skipx = 0, skipy = 0; + bool out = parent->out(), fromChannel = parent->fromChannel(), outbg = out && !fromChannel; if (!_title.isEmpty() || !_description.isEmpty()) { skipx = st::mediaPadding.left(); - style::color bg(selected ? (outbg ? st::msgOutSelectBg : st::msgInSelectBg) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutSelectShadow : st::msgInSelectShadow) : (outbg ? st::msgOutShadow : st::msgInShadow)); + style::color bg(selected ? (outbg ? st::msgOutBgSelected : st::msgInBgSelected) : (outbg ? st::msgOutBg : st::msgInBg)); + style::color sh(selected ? (outbg ? st::msgOutShadowSelected : st::msgInShadowSelected) : (outbg ? st::msgOutShadow : st::msgInShadow)); RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, 0, 0, width, _height, bg, cors, &sh); @@ -5743,7 +5892,7 @@ void HistoryImageLink::draw(Painter &p, const HistoryItem *parent, bool selected } height -= skipy + st::mediaPadding.bottom(); } else { - App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInSelectShadow : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); + App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } data->load(); @@ -5789,7 +5938,7 @@ void HistoryImageLink::draw(Painter &p, const HistoryItem *parent, bool selected } int32 fullRight = skipx + width, fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0); - parent->drawInfo(p, fullRight, fullBottom, selected, InfoDisplayOverImage); + parent->drawInfo(p, fullRight, fullBottom, skipx * 2 + width, selected, InfoDisplayOverImage); } int32 HistoryImageLink::resize(int32 width, const HistoryItem *parent) { @@ -6188,8 +6337,8 @@ bool HistoryMessage::textHasLinks() { return emptyText() ? false : _text.hasLinks(); } -void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, bool selected, InfoDisplayType type) const { - p.setFont(st::msgDateFont->f); +void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const { + p.setFont(st::msgDateFont); bool outbg = out() && !fromChannel(), overimg = (type == InfoDisplayOverImage); int32 infoRight = right, infoBottom = bottom; @@ -6197,7 +6346,7 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, bool select case InfoDisplayDefault: infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); - p.setPen((selected ? (outbg ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (outbg ? st::msgOutDateColor : st::msgInDateColor))->p); + p.setPen((selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg))->p); break; case InfoDisplayOverImage: infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); @@ -6207,11 +6356,13 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, bool select } int32 infoW = HistoryMessage::infoWidth(); + if (rtl()) infoRight = width - infoRight + infoW; + int32 dateX = infoRight - infoW; int32 dateY = infoBottom - st::msgDateFont->height; if (type == InfoDisplayOverImage) { int32 dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); - App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgSelectBg : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); + App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); } dateX += HistoryMessage::timeLeft(); @@ -6265,7 +6416,7 @@ void HistoryMessage::setViewsCount(int32 count) { _viewsText = (_views >= 0) ? formatViewsCount(_views) : QString(); _viewsWidth = _viewsText.isEmpty() ? 0 : st::msgDateFont->width(_viewsText); if (was == _viewsWidth) { - if (App::main()) App::main()->msgUpdated(this); + Notify::redrawHistoryItem(this); } else { if (_text.hasSkipBlock()) { _text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight()); @@ -6281,7 +6432,7 @@ void HistoryMessage::setId(MsgId newId) { bool wasPositive = (id > 0), positive = (newId > 0); HistoryItem::setId(newId); if (wasPositive == positive) { - if (App::main()) App::main()->msgUpdated(this); + Notify::redrawHistoryItem(this); } else { if (_text.hasSkipBlock()) { _text.setSkipBlock(HistoryMessage::skipBlockWidth(), HistoryMessage::skipBlockHeight()); @@ -6293,17 +6444,18 @@ void HistoryMessage::setId(MsgId newId) { } } -void HistoryMessage::draw(Painter &p, uint32 selection) const { - bool outbg = out() && !fromChannel(), bubble = drawBubble(); +void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { + bool outbg = out() && !fromChannel(), bubble = drawBubble(), selected = (selection == FullItemSel); textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); - uint64 ms = App::main() ? App::main()->animActiveTime(this) : 0; - if (ms) { - if (ms > st::activeFadeInDuration + st::activeFadeOutDuration) { + uint64 animms = App::main() ? App::main()->animActiveTimeStart(this) : 0; + if (animms > 0 && animms <= ms) { + animms = ms - animms; + if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { App::main()->stopAnimActive(); } else { - float64 dt = (ms > st::activeFadeInDuration) ? (1 - (ms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (ms / float64(st::activeFadeInDuration)); + float64 dt = (animms > st::activeFadeInDuration) ? (1 - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration)); float64 o = p.opacity(); p.setOpacity(o * dt); p.fillRect(0, 0, _history->width, _height, textstyleCurrent()->selectOverlay->b); @@ -6311,7 +6463,6 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { } } - bool selected = (selection == FullItemSel); if (_from->nameVersion > _fromVersion) { fromNameUpdated(); _fromVersion = _from->nameVersion; @@ -6327,15 +6478,15 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { if (bubble) { QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); - style::color bg(selected ? (outbg ? st::msgOutSelectBg : st::msgInSelectBg) : (outbg ? st::msgOutBg : st::msgInBg)); - style::color sh(selected ? (outbg ? st::msgOutSelectShadow : st::msgInSelectShadow) : (outbg ? st::msgOutShadow : st::msgInShadow)); + style::color bg(selected ? (outbg ? st::msgOutBgSelected : st::msgInBgSelected) : (outbg ? st::msgOutBg : st::msgInBg)); + style::color sh(selected ? (outbg ? st::msgOutShadowSelected : st::msgInShadowSelected) : (outbg ? st::msgOutShadow : st::msgInShadow)); RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners)); App::roundRect(p, r, bg, cors, &sh); if (displayFromName()) { p.setFont(st::msgNameFont->f); if (fromChannel()) { - p.setPen(selected ? st::msgInServiceSelColor : st::msgInServiceColor); + p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg); } else { p.setPen(_from->color); } @@ -6347,19 +6498,21 @@ void HistoryMessage::draw(Painter &p, uint32 selection) const { if (_media && _media->isDisplayed()) { p.save(); - p.translate(left, _height - st::msgMargin.bottom() - _media->height()); - _media->draw(p, this, selected); + int32 top = _height - st::msgMargin.bottom() - _media->height(); + p.translate(left, top); + _media->draw(p, this, r.translated(-left, -top), selected, ms); p.restore(); if (!_media->customInfoLayout()) { - HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), selected, InfoDisplayDefault); + HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); } } else { - HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), selected, InfoDisplayDefault); + HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); } } else { p.save(); - p.translate(left, st::msgMargin.top()); - _media->draw(p, this, selected); + int32 top = st::msgMargin.top(); + p.translate(left, top); + _media->draw(p, this, r.translated(-left, -top), selected, ms); p.restore(); } @@ -6580,8 +6733,7 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const , fwdDate(::date(msg.vfwd_date)) , fwdFrom(App::peer(peerFromMTP(msg.vfwd_from_id))) , fwdFromVersion(fwdFrom->nameVersion) -, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) -{ +, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) { fwdNameUpdated(); } @@ -6589,8 +6741,7 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId , fwdDate(msg->dateForwarded()) , fwdFrom(msg->fromForwarded()) , fwdFromVersion(fwdFrom->nameVersion) -, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) -{ +, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) { fwdNameUpdated(); } @@ -6615,19 +6766,19 @@ void HistoryForwarded::fwdNameUpdated() const { } } -void HistoryForwarded::draw(Painter &p, uint32 selection) const { +void HistoryForwarded::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { if (drawBubble() && fwdFrom->nameVersion > fwdFromVersion) { fwdNameUpdated(); fwdFromVersion = fwdFrom->nameVersion; } - HistoryMessage::draw(p, selection); + HistoryMessage::draw(p, r, selection, ms); } void HistoryForwarded::drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w, bool selected) const { style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont); bool outbg = out() && !fromChannel(); - p.setPen((selected ? (outbg ? st::msgOutServiceSelColor : st::msgInServiceSelColor) : (outbg ? st::msgOutServiceColor : st::msgInServiceColor))->p); + p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p); p.setFont(serviceFont->f); if (w >= fromWidth) { @@ -6845,11 +6996,11 @@ void HistoryReply::replyToReplaced(HistoryItem *oldItem, HistoryItem *newItem) { } } -void HistoryReply::draw(Painter &p, uint32 selection) const { +void HistoryReply::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { if (replyToMsg && replyToMsg->from()->nameVersion > replyToVersion) { replyToNameUpdated(); } - HistoryMessage::draw(p, selection); + HistoryMessage::draw(p, r, selection, ms); } void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService) const { @@ -6881,14 +7032,14 @@ void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selec if (likeService) { p.setPen(st::white->p); } else { - p.setPen((selected ? (outbg ? st::msgOutServiceSelColor : st::msgInServiceSelColor) : (outbg ? st::msgOutServiceColor : st::msgInServiceColor))->p); + p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p); } replyToName.drawElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip); HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage(); if (likeService) { } else if ((replyToAsMsg && replyToAsMsg->emptyText()) || replyToMsg->serviceMsg()) { - style::color date(selected ? (outbg ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (outbg ? st::msgOutDateColor : st::msgInDateColor)); + style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); p.setPen(date->p); } else { p.setPen(st::msgColor->p); @@ -6897,7 +7048,7 @@ void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selec } } else { p.setFont(st::msgDateFont->f); - style::color date(selected ? (outbg ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (outbg ? st::msgOutDateColor : st::msgInDateColor)); + style::color date(outbg ? (selected ? st::msgOutDateFgSelected : st::msgOutDateFg) : (selected ? st::msgInDateFgSelected : st::msgInDateFg)); if (likeService) { p.setPen(st::white->p); } else { @@ -7210,14 +7361,15 @@ void HistoryServiceMsg::setServiceText(const QString &text) { initDimensions(); } -void HistoryServiceMsg::draw(Painter &p, uint32 selection) const { - uint64 ms = App::main() ? App::main()->animActiveTime(this) : 0; - if (ms) { - if (ms > st::activeFadeInDuration + st::activeFadeOutDuration) { +void HistoryServiceMsg::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { + uint64 animms = App::main() ? App::main()->animActiveTimeStart(this) : 0; + if (animms > 0 && animms <= ms) { + animms = ms - animms; + if (animms > st::activeFadeInDuration + st::activeFadeOutDuration) { App::main()->stopAnimActive(); } else { textstyleSet(&st::inTextStyle); - float64 dt = (ms > st::activeFadeInDuration) ? (1 - (ms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (ms / float64(st::activeFadeInDuration)); + float64 dt = (animms > st::activeFadeInDuration) ? (1 - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration)); float64 o = p.opacity(); p.setOpacity(o * dt); p.fillRect(0, 0, _history->width, _height, textstyleCurrent()->selectOverlay->b); @@ -7233,8 +7385,9 @@ void HistoryServiceMsg::draw(Painter &p, uint32 selection) const { if (_media) { height -= st::msgServiceMargin.top() + _media->height(); p.save(); - p.translate(st::msgServiceMargin.left() + (width - _media->maxWidth()) / 2, st::msgServiceMargin.top() + height + st::msgServiceMargin.top()); - _media->draw(p, this, selection == FullItemSel); + int32 left = st::msgServiceMargin.left() + (width - _media->maxWidth()) / 2, top = st::msgServiceMargin.top() + height + st::msgServiceMargin.top(); + p.translate(left, top); + _media->draw(p, this, r.translated(-left, -top), selection == FullItemSel, ms); p.restore(); } @@ -7435,7 +7588,7 @@ HistoryServiceMsg(history, block, clientMsgId(), date, qsl("-")), _wasMinId(wasMinId) { } -void HistoryCollapse::draw(Painter &p, uint32 selection) const { +void HistoryCollapse::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { } void HistoryCollapse::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const { @@ -7471,7 +7624,7 @@ void HistoryUnreadBar::setCount(int32 count) { text = lng_unread_bar(lt_count, count); } -void HistoryUnreadBar::draw(Painter &p, uint32 selection) const { +void HistoryUnreadBar::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { p.fillRect(0, st::lineWidth, _history->width, st::unreadBarHeight - 2 * st::lineWidth, st::unreadBarBG->b); p.fillRect(0, st::unreadBarHeight - st::lineWidth, _history->width, st::lineWidth, st::unreadBarBorder->b); p.setFont(st::unreadBarFont->f); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index e42153c49b..7efe44a1ee 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -845,7 +845,7 @@ public: virtual void initDimensions() = 0; virtual int32 resize(int32 width) = 0; // return new height - virtual void draw(Painter &p, uint32 selection) const = 0; + virtual void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const = 0; History *history() { return _history; @@ -933,6 +933,10 @@ public: virtual uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { return (from << 16) | to; } + virtual void linkOver(const TextLinkPtr &lnk) { + } + virtual void linkOut(const TextLinkPtr &lnk) { + } virtual HistoryItemType type() const { return HistoryItemMsg; } @@ -955,7 +959,7 @@ public: return inDialogsText(); } - virtual void drawInfo(Painter &p, int32 right, int32 bottom, bool selected, InfoDisplayType type) const { + virtual void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const { } virtual void setViewsCount(int32 count) { } @@ -1112,6 +1116,34 @@ private: HistoryItem *regItem(HistoryItem *item, bool returnExisting = false); +class RadialAnimation { +public: + + RadialAnimation(int32 thickness, AnimationCallbacks *callbacks); + + float64 opacity() const { + return _opacity; + } + bool animating() const { + return _animation.animating(); + } + + void start(float64 prg); + void update(float64 prg, bool finished, uint64 ms); + void stop(); + + void draw(Painter &p, const QRect &inner, const style::color &color); + +private: + + int32 _thickness; + uint64 _firstStart, _lastStart, _lastTime; + float64 _opacity; + anim::fvalue a_arcEnd, a_arcStart; + Animation _animation; + +}; + class HistoryMedia : public HistoryElem { public: @@ -1136,7 +1168,11 @@ public: return _height; } virtual void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const = 0; - virtual void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const = 0; + virtual void linkOver(HistoryItem *parent, const TextLinkPtr &lnk) { + } + virtual void linkOut(HistoryItem *parent, const TextLinkPtr &lnk) { + } + virtual void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const = 0; virtual bool uploading() const { return false; } @@ -1196,7 +1232,7 @@ public: void init(); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypePhoto; @@ -1268,7 +1304,7 @@ public: HistoryVideo(const MTPDvideo &video, const QString &caption, HistoryItem *parent); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypeVideo; @@ -1323,7 +1359,7 @@ public: HistoryAudio(const MTPDaudio &audio); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; HistoryMediaType type() const { return MediaTypeAudio; } @@ -1372,7 +1408,7 @@ public: return !_data->song() && !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height(); } - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypeDocument; @@ -1385,6 +1421,8 @@ public: return (_data->status == FileUploading); } void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const; + void linkOver(HistoryItem *parent, const TextLinkPtr &lnk); + void linkOut(HistoryItem *parent, const TextLinkPtr &lnk); HistoryMedia *clone() const; DocumentData *document() { @@ -1414,6 +1452,8 @@ public: return _data->song(); } + ~HistoryDocument(); + private: DocumentData *_data; @@ -1433,6 +1473,25 @@ private: void setStatusSize(int32 newSize, qint64 realDuration = 0) const; bool updateStatusText(const HistoryItem *parent) const; // returns showPause + + void step_thumbOver(const HistoryItem *parent, float64 ms, bool timer); + void step_radial(const HistoryItem *parent, uint64 ms, bool timer); + + void ensureAnimation(const HistoryItem *parent) const; + void checkAnimationFinished(); + + struct AnimationData { + AnimationData(AnimationCallbacks *thumbOverCallbacks, AnimationCallbacks *radialCallbacks) : a_thumbOver(0, 0) + , _a_thumbOver(thumbOverCallbacks) + , radial(st::msgFileRadialLine, radialCallbacks) { + } + anim::fvalue a_thumbOver; + Animation _a_thumbOver; + + RadialAnimation radial; + }; + mutable AnimationData *_animation; + }; class HistoryGif : public HistoryMedia { @@ -1441,7 +1500,7 @@ public: HistoryGif(DocumentData *document); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypeGif; @@ -1500,7 +1559,7 @@ public: HistorySticker(DocumentData *document); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypeSticker; @@ -1544,7 +1603,7 @@ public: HistoryContact(int32 userId, const QString &fullname, const QString &phone); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; HistoryMediaType type() const { return MediaTypeContact; } @@ -1577,7 +1636,7 @@ public: HistoryWebPage(WebPageData *data); void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; bool isDisplayed() const { return !data->pendingTill; } @@ -1691,7 +1750,7 @@ public: int32 fullHeight() const; void initDimensions(const HistoryItem *parent); - void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width = -1) const; + void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; int32 resize(int32 width, const HistoryItem *parent); HistoryMediaType type() const { return MediaTypeImageLink; @@ -1751,10 +1810,11 @@ public: } bool uploading() const; - void drawInfo(Painter &p, int32 right, int32 bottom, bool selected, InfoDisplayType type) const; + void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const; void setViewsCount(int32 count); void setId(MsgId newId); - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; + virtual void drawMessageText(Painter &p, const QRect &trect, uint32 selection) const; int32 resize(int32 width); @@ -1768,6 +1828,12 @@ public: uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { return _text.adjustSelection(from, to, type); } + void linkOver(const TextLinkPtr &lnk) { + if (_media) _media->linkOver(this, lnk); + } + void linkOut(const TextLinkPtr &lnk) { + if (_media) _media->linkOut(this, lnk); + } void drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const; QString notificationHeader() const; @@ -1867,7 +1933,7 @@ public: void initDimensions(); void fwdNameUpdated() const; - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; void drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w, bool selected) const; void drawMessageText(Painter &p, const QRect &trect, uint32 selection) const; int32 resize(int32 width); @@ -1923,7 +1989,7 @@ public: HistoryItem *replyToMessage() const; void replyToReplaced(HistoryItem *oldItem, HistoryItem *newItem); - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const; void drawMessageText(Painter &p, const QRect &trect, uint32 selection) const; int32 resize(int32 width); @@ -1966,7 +2032,7 @@ public: void initDimensions(); - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; int32 resize(int32 width); bool hasPoint(int32 x, int32 y) const; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const; @@ -2077,7 +2143,7 @@ class HistoryCollapse : public HistoryServiceMsg { public: HistoryCollapse(History *history, HistoryBlock *block, MsgId wasMinId, const QDateTime &date); - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const; void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { symbol = 0xFFFF; @@ -2119,7 +2185,7 @@ public: void setCount(int32 count); - void draw(Painter &p, uint32 selection) const; + void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; int32 resize(int32 width); void drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 0da2a49b52..a9a553031d 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -116,11 +116,11 @@ void HistoryInner::messagesReceivedDown(PeerData *peer, const QVectordetached() || !_history) return; - int32 msgy = itemTop(msg); +void HistoryInner::redrawItem(const HistoryItem *item) { + if (!item || item->detached() || !_history) return; + int32 msgy = itemTop(item); if (msgy >= 0) { - update(0, msgy, width(), msg->height()); + update(0, msgy, width(), item->height()); } } @@ -129,13 +129,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) { if (!App::main()) return; + Painter p(this); QRect r(e->rect()); bool trivial = (rect() == r); - - Painter p(this); if (!trivial) { p.setClipRect(r); } + uint64 ms = getms(); if (!_firstLoading && _botInfo && !_botInfo->text.isEmpty() && _botDescHeight > 0) { if (r.y() < _botDescRect.y() + _botDescRect.height() && r.y() + r.height() > _botDescRect.y()) { @@ -189,7 +189,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { sel = i.value(); } } - item->draw(p, sel); + item->draw(p, r.translated(0, -y), sel, ms); if (item->hasViews()) { App::main()->scheduleViewIncrement(item); @@ -233,7 +233,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { sel = i.value(); } } - item->draw(p, sel); + item->draw(p, r.translated(0, -y), sel, ms); if (item->hasViews()) { App::main()->scheduleViewIncrement(item); @@ -475,16 +475,16 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt if (button != Qt::LeftButton) return; if (App::pressedItem() != App::hoveredItem()) { - updateMsg(App::pressedItem()); + redrawItem(App::pressedItem()); App::pressedItem(App::hoveredItem()); - updateMsg(App::pressedItem()); + redrawItem(App::pressedItem()); } if (textlnkDown() != textlnkOver()) { - updateMsg(App::pressedLinkItem()); + redrawItem(App::pressedLinkItem()); textlnkDown(textlnkOver()); App::pressedLinkItem(App::hoveredLinkItem()); - updateMsg(App::pressedLinkItem()); - updateMsg(App::pressedItem()); + redrawItem(App::pressedLinkItem()); + redrawItem(App::pressedItem()); } _dragAction = NoDrag; @@ -512,7 +512,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt uint32 selStatus = (symbol << 16) | symbol; if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { if (!_selected.isEmpty()) { - updateMsg(_selected.cbegin().key()); + redrawItem(_selected.cbegin().key()); _selected.clear(); } _selected.insert(_dragItem, selStatus); @@ -553,12 +553,12 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { if (!_selected.isEmpty()) { - updateMsg(_selected.cbegin().key()); + redrawItem(_selected.cbegin().key()); _selected.clear(); } _selected.insert(_dragItem, selStatus); _dragAction = Selecting; - updateMsg(_dragItem); + redrawItem(_dragItem); } else { _dragAction = PrepareSelect; } @@ -731,7 +731,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but } } if (textlnkDown()) { - updateMsg(App::pressedLinkItem()); + redrawItem(App::pressedLinkItem()); textlnkDown(TextLinkPtr()); App::pressedLinkItem(0); if (!textlnkOver() && _cursor != style::cur_default) { @@ -740,7 +740,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but } } if (App::pressedItem()) { - updateMsg(App::pressedItem()); + redrawItem(App::pressedItem()); App::pressedItem(0); } @@ -764,16 +764,16 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but } else { _selected.erase(i); } - updateMsg(_dragItem); + redrawItem(_dragItem); } else if (_dragAction == PrepareDrag && !_dragWasInactive && button != Qt::RightButton) { SelectedItems::iterator i = _selected.find(_dragItem); if (i != _selected.cend() && i.value() == FullItemSel) { _selected.erase(i); - updateMsg(_dragItem); + redrawItem(_dragItem); } else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { if (_selected.size() < MaxSelectedItems) { _selected.insert(_dragItem, FullItemSel); - updateMsg(_dragItem); + redrawItem(_dragItem); } } else { _selected.clear(); @@ -818,7 +818,7 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { _dragAction = Selecting; uint32 selStatus = (symbol << 16) | symbol; if (!_selected.isEmpty()) { - updateMsg(_selected.cbegin().key()); + redrawItem(_selected.cbegin().key()); _selected.clear(); } _selected.insert(_dragItem, selStatus); @@ -1348,12 +1348,17 @@ void HistoryInner::enterEvent(QEvent *e) { } void HistoryInner::leaveEvent(QEvent *e) { - if (textlnkOver()) { - updateMsg(App::hoveredItem()); - updateMsg(App::hoveredLinkItem()); - textlnkOver(TextLinkPtr()); - App::hoveredLinkItem(0); + if (HistoryItem *item = App::hoveredItem()) { + redrawItem(item); App::hoveredItem(0); + } + if (textlnkOver()) { + if (HistoryItem *item = App::hoveredLinkItem()) { + item->linkOut(textlnkOver()); + redrawItem(item); + App::hoveredLinkItem(0); + } + textlnkOver(TextLinkPtr()); if (!textlnkDown() && _cursor != style::cur_default) { _cursor = style::cur_default; setCursor(_cursor); @@ -1522,11 +1527,11 @@ void HistoryInner::onUpdateSelected() { App::mousedItem(item); m = mapMouseToItem(point, item); if (item->hasPoint(m.x(), m.y())) { - updateMsg(App::hoveredItem()); + redrawItem(App::hoveredItem()); App::hoveredItem(item); - updateMsg(App::hoveredItem()); + redrawItem(App::hoveredItem()); } else if (App::hoveredItem()) { - updateMsg(App::hoveredItem()); + redrawItem(App::hoveredItem()); App::hoveredItem(0); } } @@ -1552,8 +1557,9 @@ void HistoryInner::onUpdateSelected() { if (lnk != textlnkOver()) { lnkChanged = true; if (textlnkOver()) { - if (App::hoveredLinkItem()) { - updateMsg(App::hoveredLinkItem()); + if (HistoryItem *item = App::hoveredLinkItem()) { + item->linkOut(textlnkOver()); + redrawItem(item); } else { update(_botDescRect); } @@ -1562,8 +1568,9 @@ void HistoryInner::onUpdateSelected() { QToolTip::hideText(); App::hoveredLinkItem((lnk && !lnkInDesc) ? item : 0); if (textlnkOver()) { - if (App::hoveredLinkItem()) { - updateMsg(App::hoveredLinkItem()); + if (HistoryItem *item = App::hoveredLinkItem()) { + item->linkOver(textlnkOver()); + redrawItem(item); } else { update(_botDescRect); } @@ -2947,7 +2954,7 @@ void HistoryWidget::updateStickers() { _stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_int(cStickersHash())), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed)); } -void HistoryWidget::notifyBotCommandsChanged(UserData *user) { +void HistoryWidget::notify_botCommandsChanged(UserData *user) { if (_peer && (_peer == user || !_peer->isUser())) { if (_attachMention.clearFilteredCommands()) { checkMentionDropdown(); @@ -2955,7 +2962,7 @@ void HistoryWidget::notifyBotCommandsChanged(UserData *user) { } } -void HistoryWidget::notifyUserIsBotChanged(UserData *user) { +void HistoryWidget::notify_userIsBotChanged(UserData *user) { if (_peer && _peer == user) { _list->notifyIsBotChanged(); _list->updateBotInfo(); @@ -2964,7 +2971,7 @@ void HistoryWidget::notifyUserIsBotChanged(UserData *user) { } } -void HistoryWidget::notifyMigrateUpdated(PeerData *peer) { +void HistoryWidget::notify_migrateUpdated(PeerData *peer) { if (_peer) { if (_peer == peer) { if (peer->migrateTo()) { @@ -5442,7 +5449,7 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadPhoto, 0); } -// msgUpdated(item); +// Notify::redrawHistoryItem(item); } } @@ -5464,7 +5471,7 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadFile, doc ? doc->uploadOffset : 0); } - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -5475,7 +5482,7 @@ void HistoryWidget::onAudioProgress(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadAudio, audio ? audio->uploadOffset : 0); } - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -5486,7 +5493,7 @@ void HistoryWidget::onPhotoFailed(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadPhoto, -1); } -// msgUpdated(item); +// Notify::redrawHistoryItem(item); } } @@ -5497,7 +5504,7 @@ void HistoryWidget::onDocumentFailed(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadFile, -1); } - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -5508,7 +5515,7 @@ void HistoryWidget::onAudioFailed(const FullMsgId &newId) { if (!item->fromChannel()) { updateSendAction(item->history(), SendActionUploadAudio, -1); } - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -5595,9 +5602,9 @@ void HistoryWidget::peerMessagesUpdated() { if (_list) peerMessagesUpdated(_peer->id); } -void HistoryWidget::msgUpdated(const HistoryItem *msg) { - if (_peer && _list && (msg->history() == _history || (_migrated && msg->history() == _migrated))) { - _list->updateMsg(msg); +void HistoryWidget::notify_redrawHistoryItem(const HistoryItem *item) { + if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) { + _list->redrawItem(item); } } @@ -6528,14 +6535,14 @@ void HistoryWidget::onAnimActiveStep() { if (getms() - _animActiveStart > st::activeFadeInDuration + st::activeFadeOutDuration) { stopAnimActive(); } else { - App::main()->msgUpdated(item); + Notify::redrawHistoryItem(item); } } -uint64 HistoryWidget::animActiveTime(const HistoryItem *msg) const { +uint64 HistoryWidget::animActiveTimeStart(const HistoryItem *msg) const { if (!msg) return 0; if ((msg->history() == _history && msg->id == _activeAnimMsgId) || (_migrated && msg->history() == _migrated && msg->id == -_activeAnimMsgId)) { - return _animActiveTimer.isActive() ? (getms() - _animActiveStart) : 0; + return _animActiveTimer.isActive() ? _animActiveStart : 0; } return 0; } @@ -6645,11 +6652,11 @@ void HistoryWidget::drawField(Painter &p) { } p.setPen(st::replyColor->p); _replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); - p.setPen((((drawReplyTo->toHistoryMessage() && drawReplyTo->toHistoryMessage()->emptyText()) || drawReplyTo->serviceMsg()) ? st::msgInDateColor : st::msgColor)->p); + p.setPen((((drawReplyTo->toHistoryMessage() && drawReplyTo->toHistoryMessage()->emptyText()) || drawReplyTo->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p); _replyToText.drawElided(p, replyLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); } else { p.setFont(st::msgDateFont->f); - p.setPen(st::msgInDateColor->p); + p.setPen(st::msgInDateFg->p); p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(lang(lng_profile_loading), width() - replyLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right())); } } @@ -6669,7 +6676,7 @@ void HistoryWidget::drawField(Painter &p) { } p.setPen(st::replyColor->p); from->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top(), width() - forwardLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); - p.setPen((serviceColor ? st::msgInDateColor : st::msgColor)->p); + p.setPen((serviceColor ? st::msgInDateFg : st::msgColor)->p); text->drawElided(p, forwardLeft, backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - forwardLeft - _replyForwardPreviewCancel.width() - st::msgReplyPadding.right()); } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index f01e5fb8b9..9a76a74127 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -69,7 +69,7 @@ public: int32 recountHeight(HistoryItem *resizedItem); void updateSize(); - void updateMsg(const HistoryItem *msg); + void redrawItem(const HistoryItem *item); bool canCopySelected() const; bool canDeleteSelected() const; @@ -430,7 +430,7 @@ public: void peerMessagesUpdated(PeerId peer); void peerMessagesUpdated(); - void msgUpdated(const HistoryItem *msg); + void notify_redrawHistoryItem(const HistoryItem *item); void newUnreadMsg(History *history, HistoryItem *item); void historyToDown(History *history); void historyWasRead(bool force = true); @@ -487,7 +487,7 @@ public: bool touchScroll(const QPoint &delta); - uint64 animActiveTime(const HistoryItem *msg) const; + uint64 animActiveTimeStart(const HistoryItem *msg) const; void stopAnimActive(); void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true); @@ -558,9 +558,9 @@ public: resizeEvent(0); } - void notifyBotCommandsChanged(UserData *user); - void notifyUserIsBotChanged(UserData *user); - void notifyMigrateUpdated(PeerData *peer); + void notify_botCommandsChanged(UserData *user); + void notify_userIsBotChanged(UserData *user); + void notify_migrateUpdated(PeerData *peer); ~HistoryWidget(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 5fc39f7360..e3e5e325bd 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -683,18 +683,6 @@ void MainWidget::updateStickers() { history.updateStickers(); } -void MainWidget::notifyBotCommandsChanged(UserData *bot) { - history.notifyBotCommandsChanged(bot); -} - -void MainWidget::notifyUserIsBotChanged(UserData *bot) { - history.notifyUserIsBotChanged(bot); -} - -void MainWidget::notifyMigrateUpdated(PeerData *peer) { - history.notifyMigrateUpdated(peer); -} - void MainWidget::onUpdateMuted() { App::updateMuted(); } @@ -758,6 +746,27 @@ void MainWidget::ui_hideStickerPreview() { _stickerPreview->hidePreview(); } +void MainWidget::notify_botCommandsChanged(UserData *bot) { + history.notify_botCommandsChanged(bot); +} + +void MainWidget::notify_userIsBotChanged(UserData *bot) { + history.notify_userIsBotChanged(bot); +} + +void MainWidget::notify_migrateUpdated(PeerData *peer) { + history.notify_migrateUpdated(peer); +} + +void MainWidget::notify_redrawHistoryItem(const HistoryItem *msg) { + if (!msg) return; + history.notify_redrawHistoryItem(msg); + if (!msg->history()->dialogs.isEmpty() && msg->history()->lastMsg == msg) { + dialogs.dlgUpdated(msg->history()->dialogs[0]); + } + if (overview) overview->notify_redrawHistoryItem(msg); +} + void MainWidget::noHider(HistoryHider *destroyed) { if (_hider == destroyed) { _hider = 0; @@ -1303,8 +1312,8 @@ void MainWidget::readServerHistory(History *hist, bool force) { } } -uint64 MainWidget::animActiveTime(const HistoryItem *msg) const { - return history.animActiveTime(msg); +uint64 MainWidget::animActiveTimeStart(const HistoryItem *msg) const { + return history.animActiveTimeStart(msg); } void MainWidget::stopAnimActive() { @@ -1474,7 +1483,7 @@ void MainWidget::itemResized(HistoryItem *row, bool scrollToIt) { if (overview) { overview->itemResized(row, scrollToIt); } - if (row) msgUpdated(row); + if (row) Notify::redrawHistoryItem(row); } bool MainWidget::overviewFailed(PeerData *peer, const RPCError &error, mtpRequestId req) { @@ -1624,7 +1633,7 @@ void MainWidget::videoLoadProgress(mtpFileLoader *loader) { VideoItems::const_iterator i = items.constFind(video); if (i != items.cend()) { for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - msgUpdated(j.key()); + Notify::redrawHistoryItem(j.key()); } } } @@ -1701,7 +1710,7 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) { AudioItems::const_iterator i = items.constFind(audio); if (i != items.cend()) { for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - msgUpdated(j.key()); + Notify::redrawHistoryItem(j.key()); } } } @@ -1736,7 +1745,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) { } if (HistoryItem *item = App::histItemById(audioId.msgId)) { - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -1797,7 +1806,7 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) { } if (HistoryItem *item = App::histItemById(songId.msgId)) { - msgUpdated(item); + Notify::redrawHistoryItem(item); } } @@ -1884,7 +1893,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) { DocumentItems::const_iterator i = items.constFind(document); if (i != items.cend()) { for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) { - msgUpdated(j.key()); + Notify::redrawHistoryItem(j.key()); } } App::wnd()->documentUpdated(document); @@ -2630,15 +2639,6 @@ void MainWidget::onActiveChannelUpdateFull() { } } -void MainWidget::msgUpdated(const HistoryItem *msg) { - if (!msg) return; - history.msgUpdated(msg); - if (!msg->history()->dialogs.isEmpty() && msg->history()->lastMsg == msg) { - dialogs.dlgUpdated(msg->history()->dialogs[0]); - } - if (overview) overview->msgUpdated(msg); -} - void MainWidget::historyToDown(History *hist) { history.historyToDown(hist); } @@ -4227,7 +4227,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { msgRow->history()->unregTyping(App::self()); } if (!App::historyRegItem(msgRow)) { - msgUpdated(msgRow); + Notify::redrawHistoryItem(msgRow); } else { History *h = msgRow->history(); bool wasLast = (h->lastMsg == msgRow); @@ -4256,7 +4256,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (HistoryItem *item = App::histItemById(NoChannel, v.at(i).v)) { if (item->isMediaUnread()) { item->markMediaRead(); - msgUpdated(item); + Notify::redrawHistoryItem(item); if (item->out() && item->history()->peer->isUser()) { item->history()->peer->asUser()->madeAction(); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 4d8c638e59..1e143148b4 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -237,7 +237,6 @@ public: return sentUpdatesReceived(0, updates); } void inviteToChannelDone(ChannelData *channel, const MTPUpdates &updates); - void msgUpdated(const HistoryItem *msg); void historyToDown(History *hist); void dialogsToUp(); void newUnreadMsg(History *history, HistoryItem *item); @@ -328,7 +327,7 @@ public: void readServerHistory(History *history, bool force = true); - uint64 animActiveTime(const HistoryItem *msg) const; + uint64 animActiveTimeStart(const HistoryItem *msg) const; void stopAnimActive(); void sendBotCommand(const QString &cmd, MsgId msgId); @@ -386,9 +385,11 @@ public: void updateMutedIn(int32 seconds); void updateStickers(); - void notifyBotCommandsChanged(UserData *bot); - void notifyUserIsBotChanged(UserData *bot); - void notifyMigrateUpdated(PeerData *peer); + + void notify_botCommandsChanged(UserData *bot); + void notify_userIsBotChanged(UserData *bot); + void notify_migrateUpdated(PeerData *peer); + void notify_redrawHistoryItem(const HistoryItem *msg); void choosePeer(PeerId peerId, MsgId showAtMsgId); // does offerPeer or showPeerHistory void clearBotStartToken(PeerData *peer); diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 989fc3d180..a189b99dbd 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -527,13 +527,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32 } } -void OverviewInner::updateMsg(HistoryItem *item) { - if (App::main() && item) { - App::main()->msgUpdated(item); - } -} - -void OverviewInner::updateMsg(MsgId itemId, int32 itemIndex) { +void OverviewInner::redrawItem(MsgId itemId, int32 itemIndex) { fixItemIndex(itemIndex, itemId); if (itemIndex >= 0) { if (_type == OverviewPhotos) { @@ -665,15 +659,15 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but if (button != Qt::LeftButton) return; if (textlnkDown() != textlnkOver()) { - updateMsg(App::pressedLinkItem()); + redrawItem(App::pressedLinkItem()); textlnkDown(textlnkOver()); App::pressedLinkItem(App::hoveredLinkItem()); - updateMsg(App::pressedLinkItem()); + redrawItem(App::pressedLinkItem()); } if (_lnkDownIndex != _lnkOverIndex) { - if (_dragItem) updateMsg(_dragItem, _dragItemIndex); + if (_dragItem) redrawItem(_dragItem, _dragItemIndex); _lnkDownIndex = _lnkOverIndex; - if (_mousedItem) updateMsg(_mousedItem, _mousedItemIndex); + if (_mousedItem) redrawItem(_mousedItem, _mousedItemIndex); } _dragAction = NoDrag; @@ -702,12 +696,12 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { if (!_selected.isEmpty()) { - updateMsg(_selected.cbegin().key(), -1); + redrawItem(_selected.cbegin().key(), -1); _selected.clear(); } _selected.insert(_dragItem, selStatus); _dragAction = Selecting; - updateMsg(_dragItem, _dragItemIndex); + redrawItem(_dragItem, _dragItemIndex); _overview->updateTopBarSelection(); } else { _dragAction = PrepareSelect; @@ -752,7 +746,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu } } if (textlnkDown()) { - updateMsg(App::pressedLinkItem()); + redrawItem(App::pressedLinkItem()); textlnkDown(TextLinkPtr()); App::pressedLinkItem(0); if (!textlnkOver() && _cursor != style::cur_default) { @@ -761,7 +755,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu } } if (_lnkDownIndex) { - updateMsg(_dragItem, _dragItemIndex); + redrawItem(_dragItem, _dragItemIndex); _lnkDownIndex = 0; if (!_lnkOverIndex && _cursor != style::cur_default) { _cursor = style::cur_default; @@ -795,16 +789,16 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu } else { _selected.erase(i); } - updateMsg(_dragItem, _dragItemIndex); + redrawItem(_dragItem, _dragItemIndex); } else if (_dragAction == PrepareDrag && !needClick && !_dragWasInactive && button != Qt::RightButton) { SelectedItems::iterator i = _selected.find(_dragItem); if (i != _selected.cend() && i.value() == FullItemSel) { _selected.erase(i); - updateMsg(_dragItem, _dragItemIndex); + redrawItem(_dragItem, _dragItemIndex); } else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { if (_selected.size() < MaxSelectedItems) { _selected.insert(_dragItem, FullItemSel); - updateMsg(_dragItem, _dragItemIndex); + redrawItem(_dragItem, _dragItemIndex); } } else { _selected.clear(); @@ -1074,7 +1068,11 @@ void OverviewInner::paintEvent(QPaintEvent *e) { Painter p(this); QRect r(e->rect()); - p.setClipRect(r); + bool trivial = (r == rect()); + if (!trivial) { + p.setClipRect(r); + } + uint64 ms = getms(); if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) { QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9); @@ -1144,7 +1142,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { QPoint pos(int32(i * w + st::overviewPhotoSkip), _addToY + row * (_vsize + st::overviewPhotoSkip) + st::overviewPhotoSkip); p.drawPixmap(pos, it->pix); if (!quality) { - uint64 dt = itemAnimations().animate(item, getms()); + uint64 dt = itemAnimations().animate(item, ms); int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta); int32 x = pos.x() + (_vsize - st::overviewLoader.width()) / 2, y = pos.y() + (_vsize - st::overviewLoader.height()) / 2; @@ -1338,7 +1336,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { p.save(); p.translate(left, 0); - media->draw(p, item, (sel == FullItemSel), w); + media->draw(p, item, r.translated(-left, -curY - (st::msgMargin.top() + _addToY)), (sel == FullItemSel), ms); p.restore(); } } else { @@ -1451,9 +1449,9 @@ void OverviewInner::onUpdateSelected() { } } if (newsel != _selectedMsgId) { - if (_selectedMsgId) updateMsg(_selectedMsgId, -1); + if (_selectedMsgId) redrawItem(_selectedMsgId, -1); _selectedMsgId = newsel; - updateMsg(item); + redrawItem(item); } } else if (_type == OverviewLinks) { int32 w = _width - st::msgMargin.left() - st::msgMargin.right(); @@ -1558,19 +1556,19 @@ void OverviewInner::onUpdateSelected() { bool lnkChanged = false; if (lnk != textlnkOver()) { lnkChanged = true; - updateMsg(App::hoveredLinkItem()); + redrawItem(App::hoveredLinkItem()); textlnkOver(lnk); App::hoveredLinkItem(lnk ? item : 0); - updateMsg(App::hoveredLinkItem()); + redrawItem(App::hoveredLinkItem()); QToolTip::hideText(); } else { App::mousedItem(item); } if (lnkIndex != _lnkOverIndex || _mousedItem != oldMousedItem) { lnkChanged = true; - if (oldMousedItem) updateMsg(oldMousedItem, oldMousedItemIndex); + if (oldMousedItem) redrawItem(oldMousedItem, oldMousedItemIndex); _lnkOverIndex = lnkIndex; - if (item) updateMsg(item); + if (item) redrawItem(item); QToolTip::hideText(); } if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) { @@ -1794,11 +1792,11 @@ void OverviewInner::enterEvent(QEvent *e) { void OverviewInner::leaveEvent(QEvent *e) { if (_selectedMsgId) { - updateMsg(_selectedMsgId, -1); + redrawItem(_selectedMsgId, -1); _selectedMsgId = 0; } if (textlnkOver()) { - updateMsg(App::hoveredLinkItem()); + redrawItem(App::hoveredLinkItem()); textlnkOver(TextLinkPtr()); App::hoveredLinkItem(0); if (!textlnkDown() && _cursor != style::cur_default) { @@ -1826,8 +1824,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (_menu) { _menu->deleteLater(); _menu = 0; - updateMsg(App::contextItem()); - if (_selectedMsgId) updateMsg(_selectedMsgId, -1); + redrawItem(App::contextItem()); + if (_selectedMsgId) redrawItem(_selectedMsgId, -1); } if (e->reason() == QContextMenuEvent::Mouse) { dragActionUpdate(e->globalPos()); @@ -1904,8 +1902,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } App::contextItem(App::hoveredLinkItem()); - updateMsg(App::contextItem()); - if (_selectedMsgId) updateMsg(_selectedMsgId, -1); + redrawItem(App::contextItem()); + if (_selectedMsgId) redrawItem(_selectedMsgId, -1); } else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) { _contextMenuUrl = _lnkOverIndex ? urlByIndex(_mousedItem, _mousedItemIndex, _lnkOverIndex) : QString(); _menu = new PopupMenu(); @@ -1944,8 +1942,8 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } App::contextItem(App::mousedItem()); - updateMsg(App::contextItem()); - if (_selectedMsgId) updateMsg(_selectedMsgId, -1); + redrawItem(App::contextItem()); + if (_selectedMsgId) redrawItem(_selectedMsgId, -1); } if (_menu) { connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*))); @@ -2197,8 +2195,8 @@ void OverviewInner::onMenuDestroy(QObject *obj) { if (_menu == obj) { _menu = 0; dragActionUpdate(QCursor::pos()); - updateMsg(App::contextItem()); - if (_selectedMsgId) updateMsg(_selectedMsgId, -1); + redrawItem(App::contextItem()); + if (_selectedMsgId) redrawItem(_selectedMsgId, -1); } } @@ -2570,8 +2568,9 @@ void OverviewInner::itemResized(HistoryItem *item, bool scrollToIt) { } } -void OverviewInner::msgUpdated(const HistoryItem *msg) { +void OverviewInner::redrawItem(const HistoryItem *msg) { if (!msg) return; + History *history = (msg->history() == _history) ? _history : (msg->history() == _migrated ? _migrated : 0); if (!history) return; @@ -2998,9 +2997,9 @@ void OverviewWidget::changingMsgId(HistoryItem *row, MsgId newId) { } } -void OverviewWidget::msgUpdated(const HistoryItem *msg) { +void OverviewWidget::notify_redrawHistoryItem(const HistoryItem *msg) { if (peer() == msg->history()->peer || migratePeer() == msg->history()->peer) { - _inner.msgUpdated(msg); + _inner.redrawItem(msg); } } diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 5955272e4b..91154ef296 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -69,7 +69,7 @@ public: void mediaOverviewUpdated(bool fromResize = false); void changingMsgId(HistoryItem *row, MsgId newId); - void msgUpdated(const HistoryItem *msg); + void redrawItem(const HistoryItem *msg); void itemRemoved(HistoryItem *item); void itemResized(HistoryItem *item, bool scrollToIt); @@ -123,8 +123,7 @@ private: void updateDragSelection(MsgId dragSelFrom, int32 dragSelFromIndex, MsgId dragSelTo, int32 dragSelToIndex, bool dragSelecting); - void updateMsg(HistoryItem *item); - void updateMsg(MsgId itemId, int32 itemIndex); + void redrawItem(MsgId itemId, int32 itemIndex); void touchResetSpeed(); void touchUpdateSpeed(); @@ -314,7 +313,7 @@ public: void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); void changingMsgId(HistoryItem *row, MsgId newId); - void msgUpdated(const HistoryItem *msg); + void notify_redrawHistoryItem(const HistoryItem *msg); void itemRemoved(HistoryItem *item); void itemResized(HistoryItem *row, bool scrollToIt); diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index 65387d7df8..8e02cf416e 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "settings.h" #include "lang.h" -bool gRtl = false; +bool gRtl = true;// false; Qt::LayoutDirection gLangDir = gRtl ? Qt::RightToLeft : Qt::LeftToRight; mtpDcOptions gDcOptions; diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index ba02bc1893..3290ebb586 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -1123,6 +1123,10 @@ struct DocumentData { } void recountIsImage(); + float64 progress() const { + return loader ? loader->currentProgress() : ((status == FileDownloadFailed || (_location.name().isEmpty() && data.isEmpty())) ? 0 : 1); + } + DocumentId id; DocumentType type; QSize dimensions;