From cc004d435bfca04e5e8aaa3cef5776c59281dda6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 20 Dec 2015 17:05:07 +0300 Subject: [PATCH] new layout items structure started --- Telegram/Resources/style.txt | 4 +- Telegram/SourceFiles/app.h | 1 + Telegram/SourceFiles/art/sprite.png | Bin 180183 -> 180054 bytes Telegram/SourceFiles/art/sprite_200x.png | Bin 243094 -> 242692 bytes Telegram/SourceFiles/history.cpp | 175 +++--- Telegram/SourceFiles/history.h | 19 +- Telegram/SourceFiles/historywidget.cpp | 76 +-- Telegram/SourceFiles/layout.cpp | 199 +++++++ Telegram/SourceFiles/layout.h | 277 ++++++++++ Telegram/SourceFiles/mtproto/mtpScheme.cpp | 4 +- Telegram/SourceFiles/mtproto/mtpScheme.h | 24 +- Telegram/SourceFiles/mtproto/scheme.tl | 2 +- Telegram/SourceFiles/overviewwidget.cpp | 613 ++++++++++++--------- Telegram/SourceFiles/overviewwidget.h | 9 +- Telegram/SourceFiles/structs.cpp | 7 + Telegram/SourceFiles/structs.h | 8 +- Telegram/Telegram.vcxproj | 21 + Telegram/Telegram.vcxproj.filters | 6 + 18 files changed, 1056 insertions(+), 389 deletions(-) create mode 100644 Telegram/SourceFiles/layout.cpp create mode 100644 Telegram/SourceFiles/layout.h diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 5e54f0201..df83c214e 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -2185,7 +2185,7 @@ mediaviewLoaderSkip: 9px; minPhotoSize: 104px; maxMediaSize: 420px; maxStickerSize: 256px; -maxGifSize: 256px; +maxGifSize: 320px; downloadPathSkip: 10px; @@ -2196,7 +2196,7 @@ usernameTextStyle: textStyle(defaultTextStyle) { } usernameDefaultFg: #777; -youtubeIcon: sprite(116px, 338px, 90px, 62px); +youtubeIcon: sprite(116px, 338px, 72px, 50px); videoIcon: sprite(0px, 340px, 60px, 60px); locationSize: size(320px, 240px); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index d77bfd846..0582a6b88 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -32,6 +32,7 @@ class Color; class FileUploader; #include "history.h" +#include "layout.h" typedef QMap HistoryItemsMap; typedef QMap VideoItems; diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png index 038a85cbebf215b9d0f0ddb27a29fa640cfbb2aa..f3133aaa38182961ce5449cbfc31108e6313349c 100644 GIT binary patch delta 14830 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 delta 14987 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 diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index c3531eac92cd1c38cb888cbc000e3f71e3e84bc2..39fc0ab8c08cd33c2b99e744460c081b3a14d2ba 100644 GIT binary patch delta 34120 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 diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 176636931..488015252 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -22,7 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "style.h" #include "lang.h" -#include "history.h" #include "mainwidget.h" #include "application.h" #include "fileuploader.h" @@ -35,43 +34,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "audio.h" #include "localstorage.h" -TextParseOptions _textNameOptions = { - 0, // flags - 4096, // maxw - 1, // maxh - Qt::LayoutDirectionAuto, // lang-dependent -}; -TextParseOptions _textDlgOptions = { - 0, // flags - 0, // maxw is style-dependent - 1, // maxh - Qt::LayoutDirectionAuto, // lang-dependent -}; -TextParseOptions _historyTextOptions = { - TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText | TextParseMono, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _historyBotOptions = { - TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText | TextParseMono, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _historyTextNoMonoOptions = { - TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; -TextParseOptions _historyBotNoMonoOptions = { - TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText, // flags - 0, // maxw - 0, // maxh - Qt::LayoutDirectionAuto, // dir -}; - namespace { TextParseOptions _historySrvOptions = { TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags @@ -135,20 +97,6 @@ namespace { } } -const TextParseOptions &itemTextOptions(History *h, PeerData *f) { - if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isMegagroup() && h->peer->asChannel()->mgInfo->botStatus >= 0)) { - return _historyBotOptions; - } - return _historyTextOptions; -} - -const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f) { - if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isMegagroup() && h->peer->asChannel()->mgInfo->botStatus >= 0)) { - return _historyBotNoMonoOptions; - } - return _historyTextNoMonoOptions; -} - void historyInit() { _initTextOptions(); } @@ -4343,6 +4291,97 @@ void HistoryDocument::getState(TextLinkPtr &lnk, HistoryCursorState &state, int3 } void HistoryDocument::drawOverview(Painter &p, int32 width, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { + if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return; + + bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty(); + if (_data->loader) { + ensureAnimation(parent); + if (!_animation->radial.animating()) { + _animation->radial.start(_data->progress()); + } + } + bool showPause = updateStatusText(parent); + bool radial = isRadialAnimation(ms); + + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; + bool wthumb = withThumb(); + + nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); + nametop = st::msgFileThumbNameTop; + nameright = st::msgFileThumbPadding.left(); + statustop = st::msgFileThumbStatusTop; + linktop = st::msgFileThumbLinkTop; + + QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width)); + if (wthumb) { + if (_data->thumb->loaded()) { + QPixmap thumb = (already || hasdata) ? _data->thumb->pixSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); + p.drawPixmap(rthumb.topLeft(), thumb); + } else { + App::roundRect(p, rthumb, st::black, BlackCorners); + } + } else { + } + if (selected) { + App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); + } + + if (!radial && (already || hasdata)) { + } else { + QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + p.setPen(Qt::NoPen); + 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()) { + _animation->_a_thumbOver.step(ms); + 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(_data->loader ? _cancell : _savel); + p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); + } + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + style::sprite icon; + 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); + } + } + + int32 namewidth = width - nameleft - nameright; + + p.setFont(st::semiboldFont); + p.setPen(st::black); + if (namewidth < _namew) { + p.drawTextLeft(nameleft, nametop, width, st::semiboldFont->elided(_name, namewidth)); + } else { + p.drawTextLeft(nameleft, nametop, width, _name, _namew); + } + + style::color status(selected ? st::mediaInFgSelected : st::mediaInFg); + p.setFont(st::normalFont); + p.setPen(status); + + p.drawTextLeft(nameleft, statustop, width, _statusText); + + p.drawTextLeft(nameleft, linktop, width, _link); } void HistoryDocument::getStateOverview(TextLinkPtr &lnk, int32 x, int32 y, const HistoryItem *parent, int32 width) const { @@ -6174,12 +6213,12 @@ bool HistoryMessage::uploading() const { } QString HistoryMessage::selectedText(uint32 selection) const { - if (_media && selection == FullItemSel) { + if (_media && selection == FullSelection) { QString text = _text.original(0, 0xFFFF, Text::ExpandLinksAll), mediaText = _media->inHistoryText(); return text.isEmpty() ? mediaText : (mediaText.isEmpty() ? text : (text + ' ' + mediaText)); } - uint16 selectedFrom = (selection == FullItemSel) ? 0 : ((selection >> 16) & 0xFFFF); - uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF); + uint16 selectedFrom = (selection == FullSelection) ? 0 : ((selection >> 16) & 0xFFFF); + uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); return _text.original(selectedFrom, selectedTo, Text::ExpandLinksAll); } @@ -6356,7 +6395,7 @@ void HistoryMessage::setId(MsgId newId) { } void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { - bool outbg = out() && !fromChannel(), bubble = drawBubble(), selected = (selection == FullItemSel); + bool outbg = out() && !fromChannel(), bubble = drawBubble(), selected = (selection == FullSelection); textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle)); @@ -6433,8 +6472,8 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m void HistoryMessage::drawMessageText(Painter &p, const QRect &trect, uint32 selection) const { p.setPen(st::msgColor->p); p.setFont(st::msgFont->f); - uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullItemSel) ? 0 : selection & 0xFFFF; + uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF; _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo); } @@ -6657,7 +6696,7 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId } QString HistoryForwarded::selectedText(uint32 selection) const { - if (selection != FullItemSel) return HistoryMessage::selectedText(selection); + if (selection != FullSelection) return HistoryMessage::selectedText(selection); QString result, original = HistoryMessage::selectedText(selection); result.reserve(lang(lng_forwarded_from).size() + fwdFrom->name.size() + 4 + original.size()); result.append('[').append(lang(lng_forwarded_from)).append(' ').append(fwdFrom->name).append(qsl("]\n")).append(original); @@ -6705,7 +6744,7 @@ void HistoryForwarded::drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w, void HistoryForwarded::drawMessageText(Painter &p, const QRect &trect, uint32 selection) const { QRect realtrect(trect); if (displayForwardedFrom()) { - drawForwardedFrom(p, realtrect.x(), realtrect.y(), realtrect.width(), (selection == FullItemSel)); + drawForwardedFrom(p, realtrect.x(), realtrect.y(), realtrect.width(), (selection == FullSelection)); realtrect.setY(trect.y() + st::msgServiceNameFont->height); } HistoryMessage::drawMessageText(p, realtrect, selection); @@ -6830,7 +6869,7 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i } QString HistoryReply::selectedText(uint32 selection) const { - if (selection != FullItemSel || !replyToMsg) return HistoryMessage::selectedText(selection); + if (selection != FullSelection || !replyToMsg) return HistoryMessage::selectedText(selection); QString result, original = HistoryMessage::selectedText(selection); result.reserve(lang(lng_in_reply_to).size() + replyToMsg->from()->name.size() + 4 + original.size()); result.append('[').append(lang(lng_in_reply_to)).append(' ').append(replyToMsg->from()->name).append(qsl("]\n")).append(original); @@ -6970,7 +7009,7 @@ void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selec void HistoryReply::drawMessageText(Painter &p, const QRect &trect, uint32 selection) const { int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - drawReplyTo(p, trect.x(), trect.y(), trect.width(), (selection == FullItemSel)); + drawReplyTo(p, trect.x(), trect.y(), trect.width(), (selection == FullSelection)); QRect realtrect(trect); realtrect.setY(trect.y() + h); @@ -7248,8 +7287,8 @@ void HistoryServiceMsg::initDimensions() { } QString HistoryServiceMsg::selectedText(uint32 selection) const { - uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF); + uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); return _text.original(selectedFrom, selectedTo); } @@ -7295,7 +7334,7 @@ void HistoryServiceMsg::draw(Painter &p, const QRect &r, uint32 selection, uint6 p.save(); 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); + _media->draw(p, this, r.translated(-left, -top), selection == FullSelection, ms); p.restore(); } @@ -7305,13 +7344,13 @@ void HistoryServiceMsg::draw(Painter &p, const QRect &r, uint32 selection, uint6 left += (width - _maxw) / 2; width = _maxw; } - App::roundRect(p, left, st::msgServiceMargin.top(), width, height, App::msgServiceBg(), (selection == FullItemSel) ? ServiceSelectedCorners : ServiceCorners); + App::roundRect(p, left, st::msgServiceMargin.top(), width, height, App::msgServiceBg(), (selection == FullSelection) ? ServiceSelectedCorners : ServiceCorners); p.setBrush(Qt::NoBrush); p.setPen(st::msgServiceColor->p); p.setFont(st::msgServiceFont->f); - uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullItemSel) ? 0 : selection & 0xFFFF; + uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; + uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF; _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, selectedFrom, selectedTo); textstyleRestore(); } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index b8d8c94f7..e979289b1 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -24,13 +24,8 @@ void historyInit(); class HistoryItem; -static const uint32 FullItemSel = 0xFFFFFFFF; - typedef QMap SelectedItemSet; -extern TextParseOptions _textNameOptions, _textDlgOptions; -extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions; - #include "structs.h" enum NewMessageType { @@ -765,25 +760,25 @@ public: class HistoryElem { public: - HistoryElem() : _height(0), _maxw(0) { + HistoryElem() : _maxw(0), _minh(0), _height(0) { } - int32 height() const { - return _height; - } int32 maxWidth() const { return _maxw; } int32 minHeight() const { return _minh; } + int32 height() const { + return _height; + } virtual ~HistoryElem() { } protected: - mutable int32 _height, _maxw, _minh; + mutable int32 _maxw, _minh, _height; HistoryElem &operator=(const HistoryElem &); }; @@ -1316,6 +1311,7 @@ QString formatSizeText(qint64 size); QString formatDownloadText(qint64 ready, qint64 total); QString formatDurationText(qint64 duration); QString formatDurationAndSizeText(qint64 duration, qint64 size); +QString formatGifAndSizeText(qint64 size); QString formatPlayedText(qint64 played, qint64 duration); class HistoryFileMedia : public HistoryMedia { @@ -2393,6 +2389,3 @@ protected: QString text; bool freezed; }; - -const TextParseOptions &itemTextOptions(History *h, PeerData *f); -const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 859de6b4f..cb672f977 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -182,7 +182,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { if (r.y() < y + item->height()) while (y < drawToY) { uint32 sel = 0; if (y >= selfromy && y < seltoy) { - sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullItemSel : 0; + sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullSelection : 0; } else if (hasSel) { SelectedItems::const_iterator i = _selected.constFind(item); if (i != selEnd) { @@ -226,7 +226,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { if (r.y() < y + h && hdrawtop < y + h) { uint32 sel = 0; if (y >= selfromy && y < seltoy) { - sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullItemSel : 0; + sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullSelection : 0; } else if (hasSel) { SelectedItems::const_iterator i = _selected.constFind(item); if (i != selEnd) { @@ -495,7 +495,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt if (textlnkDown()) { _dragAction = PrepareDrag; } else if (!_selected.isEmpty()) { - if (_selected.cbegin().value() == FullItemSel) { + if (_selected.cbegin().value() == FullSelection) { if (_selected.constFind(_dragItem) != _selected.cend() && App::hoveredItem()) { _dragAction = PrepareDrag; // start items drag } else if (!_dragWasInactive) { @@ -510,7 +510,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt _dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); if (uponSymbol) { uint32 selStatus = (symbol << 16) | symbol; - if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (!_selected.isEmpty()) { redrawItem(_selected.cbegin().key()); _selected.clear(); @@ -532,7 +532,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt bool uponSelected = uponSymbol; if (uponSelected) { if (_selected.isEmpty() || - _selected.cbegin().value() == FullItemSel || + _selected.cbegin().value() == FullSelection || _selected.cbegin().key() != _dragItem ) { uponSelected = false; @@ -551,7 +551,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt } else { if (afterDragSymbol) ++_dragSymbol; uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; - if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (!_selected.isEmpty()) { redrawItem(_selected.cbegin().key()); _selected.clear(); @@ -593,13 +593,13 @@ void HistoryInner::onDragExec() { if (_dragItem) { bool afterDragSymbol; uint16 symbol; - if (!_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { uponSelected = _selected.contains(_dragItem); } else { _dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); if (uponSelected) { if (_selected.isEmpty() || - _selected.cbegin().value() == FullItemSel || + _selected.cbegin().value() == FullSelection || _selected.cbegin().key() != _dragItem ) { uponSelected = false; @@ -631,7 +631,7 @@ void HistoryInner::onDragExec() { mimeData->setText(sel); if (!urls.isEmpty()) mimeData->setUrls(urls); - if (uponSelected && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel && cWideMode()) { + if (uponSelected && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection && cWideMode()) { mimeData->setData(qsl("application/x-td-forward-selected"), "1"); } drag->setMimeData(mimeData); @@ -723,7 +723,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but lnkAudio = (lnkType == qstr("AudioOpenLink")), lnkDocument = (lnkType == qstr("DocumentOpenLink")), lnkContact = (lnkType == qstr("PeerLink") && dynamic_cast(App::pressedLinkItem() ? App::pressedLinkItem()->getMedia() : 0)); - if (_dragAction == PrepareDrag && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel && button != Qt::RightButton) { + if (_dragAction == PrepareDrag && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection && button != Qt::RightButton) { if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument || lnkContact) { needClick = TextLinkPtr(); } @@ -752,14 +752,14 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but dragActionCancel(); return; } - if (_dragAction == PrepareSelect && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + if (_dragAction == PrepareSelect && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { SelectedItems::iterator i = _selected.find(_dragItem); if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0) { if (_selected.size() < MaxSelectedItems) { - if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { _selected.clear(); } - _selected.insert(_dragItem, FullItemSel); + _selected.insert(_dragItem, FullSelection); } } else { _selected.erase(i); @@ -767,12 +767,12 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but redrawItem(_dragItem); } else if (_dragAction == PrepareDrag && !_dragWasInactive && button != Qt::RightButton) { SelectedItems::iterator i = _selected.find(_dragItem); - if (i != _selected.cend() && i.value() == FullItemSel) { + if (i != _selected.cend() && i.value() == FullSelection) { _selected.erase(i); redrawItem(_dragItem); - } else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + } else if (i == _selected.cend() && !_dragItem->serviceMsg() && _dragItem->id > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { if (_selected.size() < MaxSelectedItems) { - _selected.insert(_dragItem, FullItemSel); + _selected.insert(_dragItem, FullSelection); redrawItem(_dragItem); } } else { @@ -785,7 +785,7 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but _dragSelFrom = _dragSelTo = 0; } else if (!_selected.isEmpty() && !_dragWasInactive) { uint32 sel = _selected.cbegin().value(); - if (sel != FullItemSel && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { + if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { _selected.clear(); if (App::wnd()) App::wnd()->setInnerFocus(); } @@ -807,7 +807,7 @@ void HistoryInner::mouseReleaseEvent(QMouseEvent *e) { void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { if (!_history) return; - if (((_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) || (_dragAction == NoDrag && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel))) && _dragSelType == TextSelectLetters && _dragItem) { + if (((_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) || (_dragAction == NoDrag && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection))) && _dragSelType == TextSelectLetters && _dragItem) { bool afterDragSymbol, uponSelected; uint16 symbol; _dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); @@ -850,7 +850,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { int32 isUponSelected = 0, hasSelected = 0;; if (!_selected.isEmpty()) { isUponSelected = -1; - if (_selected.cbegin().value() == FullItemSel) { + if (_selected.cbegin().value() == FullSelection) { hasSelected = 2; if (App::hoveredItem() && _selected.constFind(App::hoveredItem()) != _selected.cend()) { isUponSelected = 2; @@ -947,7 +947,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { _menu->addAction(lang(doc->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), _widget, SLOT(onStickerPackInfo())); } } - QString contextMenuText = item->selectedText(FullItemSel); + QString contextMenuText = item->selectedText(FullSelection); if (!contextMenuText.isEmpty() && (!msg || !msg->getMedia() || msg->getMedia()->type() != MediaTypeSticker)) { _menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true); } @@ -1098,7 +1098,7 @@ void HistoryInner::copyContextText() { return; } - QString contextMenuText = item->selectedText(FullItemSel); + QString contextMenuText = item->selectedText(FullSelection); if (!contextMenuText.isEmpty()) { QApplication::clipboard()->setText(contextMenuText); } @@ -1116,7 +1116,7 @@ QString HistoryInner::getSelectedText() const { } if (sel.isEmpty()) return QString(); - if (sel.cbegin().value() != FullItemSel) { + if (sel.cbegin().value() != FullSelection) { return sel.cbegin().key()->selectedText(sel.cbegin().value()); } @@ -1127,7 +1127,7 @@ QString HistoryInner::getSelectedText() const { HistoryItem *item = i.key(); if (item->detached()) continue; - QString text, sel = item->selectedText(FullItemSel), time = item->date.toString(timeFormat); + QString text, sel = item->selectedText(FullSelection), time = item->date.toString(timeFormat); int32 size = item->from()->name.size() + time.size() + sel.size(); text.reserve(size); @@ -1449,7 +1449,7 @@ bool HistoryInner::canCopySelected() const { } bool HistoryInner::canDeleteSelected() const { - if (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel) return false; + if (_selected.isEmpty() || _selected.cbegin().value() != FullSelection) return false; int32 selectedForForward, selectedForDelete; getSelectionState(selectedForForward, selectedForDelete); return (selectedForForward == selectedForDelete); @@ -1458,7 +1458,7 @@ bool HistoryInner::canDeleteSelected() const { void HistoryInner::getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const { selectedForForward = selectedForDelete = 0; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { - if (i.key()->type() == HistoryItemMsg && i.value() == FullItemSel) { + if (i.key()->type() == HistoryItemMsg && i.value() == FullSelection) { if (i.key()->canDelete()) { ++selectedForDelete; } @@ -1471,7 +1471,7 @@ void HistoryInner::getSelectionState(int32 &selectedForForward, int32 &selectedF } void HistoryInner::clearSelectedItems(bool onlyTextSelection) { - if (!_selected.isEmpty() && (!onlyTextSelection || _selected.cbegin().value() != FullItemSel)) { + if (!_selected.isEmpty() && (!onlyTextSelection || _selected.cbegin().value() != FullSelection)) { _selected.clear(); _widget->updateTopBarSelection(); _widget->update(); @@ -1479,7 +1479,7 @@ void HistoryInner::clearSelectedItems(bool onlyTextSelection) { } void HistoryInner::fillSelectedItems(SelectedItemSet &sel, bool forDelete) { - if (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel) return; + if (_selected.isEmpty() || _selected.cbegin().value() != FullSelection) return; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { HistoryItem *item = i.key(); @@ -1494,12 +1494,12 @@ void HistoryInner::fillSelectedItems(SelectedItemSet &sel, bool forDelete) { } void HistoryInner::selectItem(HistoryItem *item) { - if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { _selected.clear(); } else if (_selected.size() == MaxSelectedItems && _selected.constFind(item) == _selected.cend()) { return; } - _selected.insert(item, FullItemSel); + _selected.insert(item, FullSelection); _widget->updateTopBarSelection(); _widget->update(); } @@ -1589,7 +1589,7 @@ void HistoryInner::onUpdateSelected() { _dragCursorState = cursorState; if (lnk) { cur = style::cur_pointer; - } else if (_dragCursorState == HistoryInTextCursorState && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + } else if (_dragCursorState == HistoryInTextCursorState && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { cur = style::cur_text; } else if (_dragCursorState == HistoryInDateCursorState) { // cur = style::cur_cross; @@ -1606,14 +1606,14 @@ void HistoryInner::onUpdateSelected() { cur = textlnkDown() ? style::cur_pointer : style::cur_default; if (_dragAction == Selecting) { bool canSelectMany = (_history != 0); - if (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { bool afterSymbol, uponSymbol; uint16 second; _dragItem->getSymbol(second, afterSymbol, uponSymbol, m.x(), m.y()); if (afterSymbol && _dragSelType == TextSelectLetters) ++second; uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType); _selected[_dragItem] = selState; - if (!_wasSelectedText && (selState == FullItemSel || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) { + if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) { _wasSelectedText = true; setFocus(); } @@ -1650,7 +1650,7 @@ void HistoryInner::onUpdateSelected() { } if (dragFirstAffected) { SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected); - dragSelecting = (i == _selected.cend() || i.value() != FullItemSel); + dragSelecting = (i == _selected.cend() || i.value() != FullSelection); } updateDragSelection(dragSelFrom, dragSelTo, dragSelecting); } @@ -1659,7 +1659,7 @@ void HistoryInner::onUpdateSelected() { if (textlnkDown()) { cur = style::cur_pointer; - } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { if (!_dragSelFrom || !_dragSelTo) { cur = style::cur_text; } @@ -1754,9 +1754,9 @@ void HistoryInner::addSelectionRange(SelectedItems *toItems, int32 fromblock, in if (item->id > 0 && !item->serviceMsg()) { if (i == toItems->cend()) { if (toItems->size() >= MaxSelectedItems) break; - toItems->insert(item, FullItemSel); - } else if (i.value() != FullItemSel) { - *i = FullItemSel; + toItems->insert(item, FullSelection); + } else if (i.value() != FullSelection) { + *i = FullSelection; } } else { if (i != toItems->cend()) { @@ -1777,7 +1777,7 @@ void HistoryInner::applyDragSelection(SelectedItems *toItems) const { } seltoy += _dragSelTo->height(); - if (!toItems->isEmpty() && toItems->cbegin().value() != FullItemSel) { + if (!toItems->isEmpty() && toItems->cbegin().value() != FullSelection) { toItems->clear(); } if (_dragSelecting) { diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp new file mode 100644 index 000000000..2a5b0c6ee --- /dev/null +++ b/Telegram/SourceFiles/layout.cpp @@ -0,0 +1,199 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "style.h" +#include "lang.h" + +#include "mainwidget.h" +#include "application.h" +#include "fileuploader.h" +#include "window.h" +#include "gui/filedialog.h" + +#include "boxes/addcontactbox.h" +#include "boxes/confirmbox.h" + +#include "audio.h" +#include "localstorage.h" + +TextParseOptions _textNameOptions = { + 0, // flags + 4096, // maxw + 1, // maxh + Qt::LayoutDirectionAuto, // lang-dependent +}; +TextParseOptions _textDlgOptions = { + 0, // flags + 0, // maxw is style-dependent + 1, // maxh + Qt::LayoutDirectionAuto, // lang-dependent +}; +TextParseOptions _historyTextOptions = { + TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText | TextParseMono, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; +TextParseOptions _historyBotOptions = { + TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText | TextParseMono, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; +TextParseOptions _historyTextNoMonoOptions = { + TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; +TextParseOptions _historyBotNoMonoOptions = { + TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; + +const TextParseOptions &itemTextOptions(History *h, PeerData *f) { + if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isMegagroup() && h->peer->asChannel()->mgInfo->botStatus >= 0)) { + return _historyBotOptions; + } + return _historyTextOptions; +} + +const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f) { + if ((h->peer->isUser() && h->peer->asUser()->botInfo) || (f->isUser() && f->asUser()->botInfo) || (h->peer->isChat() && h->peer->asChat()->botStatus >= 0) || (h->peer->isMegagroup() && h->peer->asChannel()->mgInfo->botStatus >= 0)) { + return _historyBotNoMonoOptions; + } + return _historyTextNoMonoOptions; +} + +void LayoutRadialProgressItem::linkOver(const TextLinkPtr &lnk) { + if (lnk == _savel || lnk == _cancell) { + a_iconOver.start(1); + _a_iconOver.start(); + } +} + +void LayoutRadialProgressItem::linkOut(const TextLinkPtr &lnk) { + if (lnk == _savel || lnk == _cancell) { + a_iconOver.start(0); + _a_iconOver.start(); + } +} + +void LayoutRadialProgressItem::setLinks(ITextLink *openl, ITextLink *savel, ITextLink *cancell) { + _openl.reset(openl); + _savel.reset(savel); + _cancell.reset(cancell); +} + +void LayoutRadialProgressItem::step_iconOver(float64 ms, bool timer) { + float64 dt = ms / st::msgFileOverDuration; + if (dt >= 1) { + a_iconOver.finish(); + _a_iconOver.stop(); + } else { + a_iconOver.update(dt, anim::linear); + } + if (timer && iconAnimated()) { + Ui::redrawHistoryItem(_parent); + } +} + +void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) { + _radial->update(dataProgress(), dataFinished(), ms); + if (!_radial->animating()) { + checkRadialFinished(); + } + if (timer) { + Ui::redrawHistoryItem(_parent); + } +} + +void LayoutRadialProgressItem::ensureRadial() const { + if (!_radial) { + _radial = new RadialAnimation( + st::msgFileRadialLine, + animation(const_cast(this), &LayoutRadialProgressItem::step_radial)); + } +} + +void LayoutRadialProgressItem::checkRadialFinished() { + if (_radial && !_radial->animating() && dataLoaded()) { + delete _radial; + _radial = 0; + } +} + +LayoutRadialProgressItem::~LayoutRadialProgressItem() { + if (_radial) { + delete _radial; + setBadPointer(_radial); + } +} + +void LayoutAbstractFileItem::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const { + _statusSize = newSize; + if (_statusSize == FileStatusSizeReady) { + _statusText = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize)); + } else if (_statusSize == FileStatusSizeLoaded) { + _statusText = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize)); + } else if (_statusSize == FileStatusSizeFailed) { + _statusText = lang(lng_attach_failed); + } else if (_statusSize >= 0) { + _statusText = formatDownloadText(_statusSize, fullSize); + } else { + _statusText = formatPlayedText(-_statusSize - 1, realDuration); + } +} + +LayoutOverviewDate::LayoutOverviewDate(const QDate &date, int32 top) + : _info(top) + , _date(date) + , _text(langDayOfMonth(date)) { +} + +void LayoutOverviewDate::initDimensions() { + _maxw = st::normalFont->width(_text); + _minh = st::linksDateMargin + st::normalFont->height + st::linksDateMargin + st::linksBorder; +} + +void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const { + if (clip.intersects(QRect(0, st::linksDateMargin, _width, st::normalFont->height))) { + p.setPen(st::linksDateColor); + p.setFont(st::normalFont); + p.drawTextLeft(0, st::linksDateMargin, _width, _text); + } +} + +LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent, int32 top) : LayoutAbstractFileItem(parent) +, _info(top) +, _data(document) { +} + +void LayoutOverviewDocument::initDimensions() { + _maxw = st::profileMaxWidth; + _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); +} + +void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const { + +} diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h new file mode 100644 index 000000000..e1e20eb9f --- /dev/null +++ b/Telegram/SourceFiles/layout.h @@ -0,0 +1,277 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org +*/ +#pragma once + +static const uint32 FullSelection = 0xFFFFFFFF; + +extern TextParseOptions _textNameOptions, _textDlgOptions; +extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions; + +const TextParseOptions &itemTextOptions(History *h, PeerData *f); +const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f); + +class LayoutMediaItem; +class OverviewItemInfo; + +class LayoutItem { +public: + LayoutItem() : _maxw(0), _minh(0) { + } + + int32 maxWidth() const { + return _maxw; + } + int32 minHeight() const { + return _minh; + } + virtual void initDimensions() = 0; + virtual int32 resizeGetHeight(int32 width) { + _width = qMin(width, _maxw); + _height = _minh; + return _height; + } + + virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const = 0; + virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { + link = TextLinkPtr(); + cursor = HistoryDefaultCursorState; + } + virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { // from text + upon = hasPoint(x, y); + symbol = upon ? 0xFFFF : 0; + after = false; + } + virtual void linkOver(const TextLinkPtr &lnk) { + } + virtual void linkOut(const TextLinkPtr &lnk) { + } + + int32 width() const { + return _width; + } + int32 height() const { + return _height; + } + + bool hasPoint(int32 x, int32 y) const { + return (x >= 0 && y >= 0 && x < width() && y < height()); + } + + virtual ~LayoutItem() { + } + + virtual LayoutMediaItem *toLayoutMediaItem() { + return 0; + } + virtual const LayoutMediaItem *toLayoutMediaItem() const { + return 0; + } + + virtual HistoryItem *getItem() const { + return 0; + } + virtual DocumentData *getDocument() const { + return 0; + } + virtual OverviewItemInfo *getOverviewItemInfo() { + return 0; + } + virtual const OverviewItemInfo *getOverviewItemInfo() const { + return 0; + } + MsgId msgId() const { + const HistoryItem *item = getItem(); + return item ? item->id : 0; + } + +protected: + int32 _width, _height, _maxw, _minh; + LayoutItem &operator=(const LayoutItem &); + +}; + +class LayoutMediaItem : public LayoutItem { +public: + LayoutMediaItem(HistoryItem *parent) : _parent(parent) { + } + + virtual LayoutMediaItem *toLayoutMediaItem() { + return this; + } + virtual const LayoutMediaItem *toLayoutMediaItem() const { + return this; + } + virtual HistoryItem *getItem() const { + return _parent; + } + +protected: + HistoryItem *_parent; + +}; + +class LayoutRadialProgressItem : public LayoutMediaItem { +public: + LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent) + , _radial(0) + , a_iconOver(0, 0) + , _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) { + } + + void linkOver(const TextLinkPtr &lnk); + void linkOut(const TextLinkPtr &lnk); + + ~LayoutRadialProgressItem(); + +protected: + TextLinkPtr _openl, _savel, _cancell; + void setLinks(ITextLink *openl, ITextLink *savel, ITextLink *cancell); + + void step_iconOver(float64 ms, bool timer); + void step_radial(uint64 ms, bool timer); + + void ensureRadial() const; + void checkRadialFinished(); + + bool isRadialAnimation(uint64 ms) const { + if (!_radial || !_radial->animating()) return false; + + _radial->step(ms); + return _radial && _radial->animating(); + } + + virtual float64 dataProgress() const = 0; + virtual bool dataFinished() const = 0; + virtual bool dataLoaded() const = 0; + virtual bool iconAnimated() const { + return false; + } + + mutable RadialAnimation *_radial; + anim::fvalue a_iconOver; + Animation _a_iconOver; + +private: + LayoutRadialProgressItem(const LayoutRadialProgressItem &other); + +}; + +class LayoutAbstractFileItem : public LayoutRadialProgressItem { +public: + LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) { + } + +protected: + // >= 0 will contain download / upload string, _statusSize = loaded bytes + // < 0 will contain played string, _statusSize = -(seconds + 1) played + // 0x7FFFFFF0 will contain status for not yet downloaded file + // 0x7FFFFFF1 will contain status for already downloaded file + // 0x7FFFFFF2 will contain status for failed to download / upload file + mutable int32 _statusSize; + mutable QString _statusText; + + // duration = -1 - no duration, duration = -2 - "GIF" duration + void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const; + +}; + +class OverviewItemInfo { +public: + OverviewItemInfo(int32 top) : _top(top) { + } + int32 top() const { + return _top; + } + void setTop(int32 top) { + _top = top; + } + +private: + int32 _top; + +}; + +class LayoutOverviewDate : public LayoutItem { +public: + LayoutOverviewDate(const QDate &date, int32 top); + + virtual void initDimensions(); + virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const; + + virtual OverviewItemInfo *getOverviewItemInfo() { + return &_info; + } + virtual const OverviewItemInfo *getOverviewItemInfo() const { + return &_info; + } + +private: + OverviewItemInfo _info; + + QDate _date; + QString _text; + +}; + +class LayoutOverviewDocument : public LayoutAbstractFileItem { +public: + LayoutOverviewDocument(DocumentData *document, HistoryItem *parent, int32 top); + + virtual void initDimensions(); + virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const; + + virtual DocumentData *getDocument() const { + return _data; + } + virtual OverviewItemInfo *getOverviewItemInfo() { + return &_info; + } + virtual const OverviewItemInfo *getOverviewItemInfo() const { + return &_info; + } + +protected: + virtual float64 dataProgress() const { + return _data->progress(); + } + virtual bool dataFinished() const { + return !_data->loader; + } + virtual bool dataLoaded() const { + return !_data->already().isEmpty() || !_data->data.isEmpty(); + } + virtual bool iconAnimated() const { + return !dataLoaded() || (_radial && _radial->animating()); + } + +private: + OverviewItemInfo _info; + DocumentData *_data; + + QString _name, _date; + int32 _namew, _datew; + int32 _thumbw; + + bool withThumb() const { + return !_data->song() && !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height(); + } + +}; diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp index 652a18686..a4b6e8960 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp +++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp @@ -4248,7 +4248,9 @@ void _serialize_webPageExternal(MTPStringLogger &to, int32 stage, int32 lev, Typ case 7: to.add(" content_url: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_content_url) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; case 8: to.add(" w: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_w) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break; case 9: to.add(" h: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_h) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break; - case 10: to.add(" duration: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_duration) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break; + case 10: to.add(" embed_url: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_embed_url) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break; + case 11: to.add(" embed_type: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_embed_type) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break; + case 12: to.add(" duration: "); ++stages.back(); if (flag & MTPDwebPageExternal::flag_duration) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h index 40183195e..910d981af 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.h +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -380,7 +380,7 @@ enum { mtpc_webPageEmpty = 0xeb1477e8, mtpc_webPagePending = 0xc586da1c, mtpc_webPage = 0xca820ed7, - mtpc_webPageExternal = 0xcf73f207, + mtpc_webPageExternal = 0xbb54b77, mtpc_authorization = 0x7bf2e6f6, mtpc_account_authorizations = 0x1250abde, mtpc_account_noPassword = 0x96dabc18, @@ -7606,7 +7606,7 @@ private: friend MTPwebPage MTP_webPageEmpty(const MTPlong &_id); friend MTPwebPage MTP_webPagePending(const MTPlong &_id, MTPint _date); friend MTPwebPage MTP_webPage(MTPint _flags, const MTPlong &_id, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_site_name, const MTPstring &_title, const MTPstring &_description, const MTPPhoto &_photo, const MTPstring &_embed_url, const MTPstring &_embed_type, MTPint _embed_width, MTPint _embed_height, MTPint _duration, const MTPstring &_author, const MTPDocument &_document); - friend MTPwebPage MTP_webPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, MTPint _duration); + friend MTPwebPage MTP_webPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, const MTPstring &_embed_url, const MTPstring &_embed_type, MTPint _duration); mtpTypeId _type; }; @@ -12299,7 +12299,7 @@ class MTPDwebPageExternal : public mtpDataImpl { public: MTPDwebPageExternal() { } - MTPDwebPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, MTPint _duration) : vflags(_flags), vurl(_url), vdisplay_url(_display_url), vtype(_type), vtitle(_title), vdescription(_description), vthumb_url(_thumb_url), vcontent_url(_content_url), vw(_w), vh(_h), vduration(_duration) { + MTPDwebPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, const MTPstring &_embed_url, const MTPstring &_embed_type, MTPint _duration) : vflags(_flags), vurl(_url), vdisplay_url(_display_url), vtype(_type), vtitle(_title), vdescription(_description), vthumb_url(_thumb_url), vcontent_url(_content_url), vw(_w), vh(_h), vembed_url(_embed_url), vembed_type(_embed_type), vduration(_duration) { } MTPint vflags; @@ -12312,6 +12312,8 @@ public: MTPstring vcontent_url; MTPint vw; MTPint vh; + MTPstring vembed_url; + MTPstring vembed_type; MTPint vduration; enum { @@ -12322,7 +12324,9 @@ public: flag_content_url = (1 << 4), flag_w = (1 << 5), flag_h = (1 << 5), - flag_duration = (1 << 6), + flag_embed_url = (1 << 6), + flag_embed_type = (1 << 6), + flag_duration = (1 << 7), }; bool has_type() const { return vflags.v & flag_type; } @@ -12332,6 +12336,8 @@ public: bool has_content_url() const { return vflags.v & flag_content_url; } bool has_w() const { return vflags.v & flag_w; } bool has_h() const { return vflags.v & flag_h; } + bool has_embed_url() const { return vflags.v & flag_embed_url; } + bool has_embed_type() const { return vflags.v & flag_embed_type; } bool has_duration() const { return vflags.v & flag_duration; } }; @@ -28298,7 +28304,7 @@ inline uint32 MTPwebPage::innerLength() const { } case mtpc_webPageExternal: { const MTPDwebPageExternal &v(c_webPageExternal()); - return v.vflags.innerLength() + v.vurl.innerLength() + v.vdisplay_url.innerLength() + (v.has_type() ? v.vtype.innerLength() : 0) + (v.has_title() ? v.vtitle.innerLength() : 0) + (v.has_description() ? v.vdescription.innerLength() : 0) + (v.has_thumb_url() ? v.vthumb_url.innerLength() : 0) + (v.has_content_url() ? v.vcontent_url.innerLength() : 0) + (v.has_w() ? v.vw.innerLength() : 0) + (v.has_h() ? v.vh.innerLength() : 0) + (v.has_duration() ? v.vduration.innerLength() : 0); + return v.vflags.innerLength() + v.vurl.innerLength() + v.vdisplay_url.innerLength() + (v.has_type() ? v.vtype.innerLength() : 0) + (v.has_title() ? v.vtitle.innerLength() : 0) + (v.has_description() ? v.vdescription.innerLength() : 0) + (v.has_thumb_url() ? v.vthumb_url.innerLength() : 0) + (v.has_content_url() ? v.vcontent_url.innerLength() : 0) + (v.has_w() ? v.vw.innerLength() : 0) + (v.has_h() ? v.vh.innerLength() : 0) + (v.has_embed_url() ? v.vembed_url.innerLength() : 0) + (v.has_embed_type() ? v.vembed_type.innerLength() : 0) + (v.has_duration() ? v.vduration.innerLength() : 0); } } return 0; @@ -28354,6 +28360,8 @@ inline void MTPwebPage::read(const mtpPrime *&from, const mtpPrime *end, mtpType if (v.has_content_url()) { v.vcontent_url.read(from, end); } else { v.vcontent_url = MTPstring(); } if (v.has_w()) { v.vw.read(from, end); } else { v.vw = MTPint(); } if (v.has_h()) { v.vh.read(from, end); } else { v.vh = MTPint(); } + if (v.has_embed_url()) { v.vembed_url.read(from, end); } else { v.vembed_url = MTPstring(); } + if (v.has_embed_type()) { v.vembed_type.read(from, end); } else { v.vembed_type = MTPstring(); } if (v.has_duration()) { v.vduration.read(from, end); } else { v.vduration = MTPint(); } } break; default: throw mtpErrorUnexpected(cons, "MTPwebPage"); @@ -28401,6 +28409,8 @@ inline void MTPwebPage::write(mtpBuffer &to) const { if (v.has_content_url()) v.vcontent_url.write(to); if (v.has_w()) v.vw.write(to); if (v.has_h()) v.vh.write(to); + if (v.has_embed_url()) v.vembed_url.write(to); + if (v.has_embed_type()) v.vembed_type.write(to); if (v.has_duration()) v.vduration.write(to); } break; } @@ -28431,8 +28441,8 @@ inline MTPwebPage MTP_webPagePending(const MTPlong &_id, MTPint _date) { inline MTPwebPage MTP_webPage(MTPint _flags, const MTPlong &_id, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_site_name, const MTPstring &_title, const MTPstring &_description, const MTPPhoto &_photo, const MTPstring &_embed_url, const MTPstring &_embed_type, MTPint _embed_width, MTPint _embed_height, MTPint _duration, const MTPstring &_author, const MTPDocument &_document) { return MTPwebPage(new MTPDwebPage(_flags, _id, _url, _display_url, _type, _site_name, _title, _description, _photo, _embed_url, _embed_type, _embed_width, _embed_height, _duration, _author, _document)); } -inline MTPwebPage MTP_webPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, MTPint _duration) { - return MTPwebPage(new MTPDwebPageExternal(_flags, _url, _display_url, _type, _title, _description, _thumb_url, _content_url, _w, _h, _duration)); +inline MTPwebPage MTP_webPageExternal(MTPint _flags, const MTPstring &_url, const MTPstring &_display_url, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_thumb_url, const MTPstring &_content_url, MTPint _w, MTPint _h, const MTPstring &_embed_url, const MTPstring &_embed_type, MTPint _duration) { + return MTPwebPage(new MTPDwebPageExternal(_flags, _url, _display_url, _type, _title, _description, _thumb_url, _content_url, _w, _h, _embed_url, _embed_type, _duration)); } inline MTPauthorization::MTPauthorization() : mtpDataOwner(new MTPDauthorization()) { diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 59bcf2abf..811c9f1d5 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -539,7 +539,7 @@ contactLinkContact#d502c2d0 = ContactLink; webPageEmpty#eb1477e8 id:long = WebPage; webPagePending#c586da1c id:long date:int = WebPage; webPage#ca820ed7 flags:# id:long url:string display_url:string type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document = WebPage; -webPageExternal#cf73f207 flags:# url:string display_url:string type:flags.0?string title:flags.1?string description:flags.2?string thumb_url:flags.3?string content_url:flags.4?string w:flags.5?int h:flags.5?int duration:flags.6?int = WebPage; +webPageExternal#bb54b77 flags:# url:string display_url:string type:flags.0?string title:flags.1?string description:flags.2?string thumb_url:flags.3?string content_url:flags.4?string w:flags.5?int h:flags.5?int embed_url:flags.6?string embed_type:flags.6?string duration:flags.7?int = WebPage; authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 4381571bb..9fe0ec077 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -146,7 +146,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _migrated(_peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0) , _history(App::history(_peer->id)) , _channel(peerToChannel(_peer->id)) -, _rowsLeft(st::msgMargin.left()) +, _rowsLeft(0) , _rowWidth(st::msgMinWidth) , _rowHeight(0) , _photosInRow(1) @@ -154,7 +154,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _selMode(false) , _search(this, st::dlgFilter, lang(lng_dlg_filter)) , _cancelSearch(this, st::btnCancelSearch) -, _itemsToBeLoaded(LinksOverviewPerPage * 2) +, _cachedItemsToBeLoaded(LinksOverviewPerPage * 2) , _inSearch(false) , _searchFull(false) , _searchFullMigrated(false) @@ -307,11 +307,11 @@ void OverviewInner::fixItemIndex(int32 ¤t, MsgId msgId) const { } } } else { - int32 l = _items.size(); - if (current < 0 || current >= l || _items[current].msgid != msgId) { + int32 l = _cachedItems.size(); + if (current < 0 || current >= l || _cachedItems[current].msgid != msgId) { current = -1; for (int32 i = 0; i < l; ++i) { - if (_items[i].msgid == msgId) { + if (_cachedItems[i].msgid == msgId) { current = i; break; } @@ -379,7 +379,7 @@ void OverviewInner::searchReceived(SearchRequestType type, const MTPmessages_Mes if (type == SearchFromStart) { _searchResults.clear(); _lastSearchId = _lastSearchMigratedId = 0; - _itemsToBeLoaded = LinksOverviewPerPage * 2; + _cachedItemsToBeLoaded = LinksOverviewPerPage * 2; } if (type == SearchMigratedFromStart) { _lastSearchMigratedId = 0; @@ -428,18 +428,18 @@ OverviewInner::CachedLink *OverviewInner::cachedLink(HistoryItem *item) { QString OverviewInner::urlByIndex(MsgId msgid, int32 index, int32 lnkIndex, bool *fullShown) const { fixItemIndex(index, msgid); - if (index < 0 || !_items[index].link) return QString(); + if (index < 0 || !_cachedItems[index].link) return QString(); if (lnkIndex < 0) { - if (fullShown) *fullShown = (_items[index].link->urls.size() == 1) && (_items[index].link->urls.at(0).width <= _rowWidth - (st::dlgPhotoSize + st::dlgPhotoPadding)); - if (_items[index].link->page) { - return _items[index].link->page->url; - } else if (!_items[index].link->urls.isEmpty()) { - return _items[index].link->urls.at(0).url; + if (fullShown) *fullShown = (_cachedItems[index].link->urls.size() == 1) && (_cachedItems[index].link->urls.at(0).width <= _rowWidth - (st::dlgPhotoSize + st::dlgPhotoPadding)); + if (_cachedItems[index].link->page) { + return _cachedItems[index].link->page->url; + } else if (!_cachedItems[index].link->urls.isEmpty()) { + return _cachedItems[index].link->urls.at(0).url; } - } else if (lnkIndex > 0 && lnkIndex <= _items[index].link->urls.size()) { - if (fullShown) *fullShown = _items[index].link->urls.at(lnkIndex - 1).width <= _rowWidth - (st::dlgPhotoSize + st::dlgPhotoPadding); - return _items[index].link->urls.at(lnkIndex - 1).url; + } else if (lnkIndex > 0 && lnkIndex <= _cachedItems[index].link->urls.size()) { + if (fullShown) *fullShown = _cachedItems[index].link->urls.at(lnkIndex - 1).width <= _rowWidth - (st::dlgPhotoSize + st::dlgPhotoPadding); + return _cachedItems[index].link->urls.at(lnkIndex - 1).url; } return QString(); } @@ -473,10 +473,12 @@ int32 OverviewInner::itemHeight(MsgId msgId, int32 index) const { } fixItemIndex(index, msgId); - if (_type == OverviewLinks || _type == OverviewDocuments) { - return (index < 0) ? 0 : ((index + 1 < _items.size() ? _items[index + 1].y : (_height - _addToY)) - _items[index].y); + if (_type == OverviewDocuments) { + return (index < 0) ? 0 : _items.at(index)->height(); + } else if (_type == OverviewLinks) { + return (index < 0) ? 0 : ((index + 1 < _cachedItems.size() ? _cachedItems[index + 1].y : (_height - _addToY)) - _cachedItems[index].y); } - return (index < 0) ? 0 : (_items[index].y - (index > 0 ? _items[index - 1].y : 0)); + return (index < 0) ? 0 : (_cachedItems[index].y - (index > 0 ? _cachedItems[index - 1].y : 0)); } void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32 delta) const { @@ -497,14 +499,14 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32 msgId = (index >= indexskip) ? _history->overview[_type][index - indexskip] : (-_migrated->overview[_type][index]); } } else { - while (index >= 0 && index < _items.size() && !_items[index].msgid) { + while (index >= 0 && index < _cachedItems.size() && !_cachedItems[index].msgid) { index += (delta > 0) ? 1 : -1; } - if (index < 0 || index >= _items.size()) { + if (index < 0 || index >= _cachedItems.size()) { msgId = 0; index = -1; } else { - msgId = _items[index].msgid; + msgId = _cachedItems[index].msgid; } } } @@ -519,10 +521,12 @@ void OverviewInner::redrawItem(MsgId itemId, int32 itemIndex) { update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize); } else if (_type == OverviewAudioDocuments) { update(_rowsLeft, _addToY + int32(itemIndex * _rowHeight), _rowWidth, _rowHeight); - } else if (_type == OverviewLinks || _type == OverviewDocuments) { - update(_rowsLeft, _addToY + _items[itemIndex].y, _rowWidth, itemHeight(itemId, itemIndex)); + } else if (_type == OverviewDocuments) { + update(_rowsLeft, _addToY + _items.at(itemIndex)->getOverviewItemInfo()->top(), _rowWidth, _items.at(itemIndex)->height()); + } else if (_type == OverviewLinks) { + update(_rowsLeft, _addToY + _cachedItems[itemIndex].y, _rowWidth, itemHeight(itemId, itemIndex)); } else if (_type == OverviewAudios) { - update(0, _addToY + _height - _items[itemIndex].y, _width, itemHeight(itemId, itemIndex)); + update(0, _addToY + _height - _cachedItems[itemIndex].y, _width, itemHeight(itemId, itemIndex)); } } } @@ -661,7 +665,7 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but if ((textlnkDown() || _lnkDownIndex) && _selected.isEmpty()) { _dragAction = PrepareDrag; } else if (!_selected.isEmpty()) { - if (_selected.cbegin().value() == FullItemSel) { + if (_selected.cbegin().value() == FullSelection) { if (_selected.constFind(_dragItem) != _selected.cend() && (textlnkDown() || _lnkDownIndex)) { _dragAction = PrepareDrag; // start items drag } else { @@ -676,7 +680,7 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but if (textlnkDown() || _lnkDownIndex) { _dragSymbol = symbol; uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; - if (selStatus != FullItemSel && (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel)) { + if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (!_selected.isEmpty()) { redrawItem(_selected.cbegin().key(), -1); _selected.clear(); @@ -759,14 +763,14 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu dragActionCancel(); return; } - if (_dragAction == PrepareSelect && !needClick && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + if (_dragAction == PrepareSelect && !needClick && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { SelectedItems::iterator i = _selected.find(_dragItem); if (i == _selected.cend() && itemMsgId(_dragItem) > 0) { if (_selected.size() < MaxSelectedItems) { - if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { _selected.clear(); } - _selected.insert(_dragItem, FullItemSel); + _selected.insert(_dragItem, FullSelection); } } else { _selected.erase(i); @@ -774,12 +778,12 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu 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) { + if (i != _selected.cend() && i.value() == FullSelection) { _selected.erase(i); redrawItem(_dragItem, _dragItemIndex); - } else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + } else if (i == _selected.cend() && itemMsgId(_dragItem) > 0 && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { if (_selected.size() < MaxSelectedItems) { - _selected.insert(_dragItem, FullItemSel); + _selected.insert(_dragItem, FullSelection); redrawItem(_dragItem, _dragItemIndex); } } else { @@ -791,7 +795,7 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu applyDragSelection(); } else if (!_selected.isEmpty() && !_dragWasInactive) { uint32 sel = _selected.cbegin().value(); - if (sel != FullItemSel && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { + if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { _selected.clear(); App::main()->activate(); } @@ -809,7 +813,7 @@ void OverviewInner::onDragExec() { if (_dragItem) { bool afterDragSymbol; uint16 symbol; - if (!_selected.isEmpty() && _selected.cbegin().value() == FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { uponSelected = _selected.contains(_dragItem); } else { uponSelected = false; @@ -819,7 +823,7 @@ void OverviewInner::onDragExec() { QList urls; bool forwardSelected = false; if (uponSelected) { - forwardSelected = !_selected.isEmpty() && _selected.cbegin().value() == FullItemSel && cWideMode(); + forwardSelected = !_selected.isEmpty() && _selected.cbegin().value() == FullSelection && cWideMode(); } else if (textlnkDown()) { sel = textlnkDown()->encoded(); if (!sel.isEmpty() && sel.at(0) != '/' && sel.at(0) != '@' && sel.at(0) != '#') { @@ -894,7 +898,7 @@ void OverviewInner::addSelectionRange(int32 selFrom, int32 selTo, History *histo if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments) { msgid = ((history == _history) ? 1 : -1) * history->overview[_type][i]; } else { - msgid = _items[i].msgid; + msgid = _cachedItems[i].msgid; } if (!msgid) continue; @@ -902,9 +906,9 @@ void OverviewInner::addSelectionRange(int32 selFrom, int32 selTo, History *histo if (_dragSelecting && itemMsgId(msgid) > 0) { if (j == _selected.cend()) { if (_selected.size() >= MaxSelectedItems) break; - _selected.insert(msgid, FullItemSel); - } else if (j.value() != FullItemSel) { - *j = FullItemSel; + _selected.insert(msgid, FullSelection); + } else if (j.value() != FullSelection) { + *j = FullSelection; } } else { if (j != _selected.cend()) { @@ -917,7 +921,7 @@ void OverviewInner::addSelectionRange(int32 selFrom, int32 selTo, History *histo void OverviewInner::applyDragSelection() { if (_dragSelFromIndex < 0 || _dragSelToIndex < 0) return; - if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { _selected.clear(); } int32 selfrom = _dragSelToIndex, selto = _dragSelFromIndex; @@ -957,10 +961,12 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) { p.setY(p.y() - _addToY - row * (_vsize + st::overviewPhotoSkip) - st::overviewPhotoSkip); } else if (_type == OverviewAudioDocuments) { p.setY(p.y() - _addToY - itemIndex * _rowHeight); - } else if (_type == OverviewLinks || _type == OverviewDocuments) { - p.setY(p.y() - _addToY - _items[itemIndex].y); + } else if (_type == OverviewDocuments) { + p.setY(p.y() - _addToY - _items.at(itemIndex)->getOverviewItemInfo()->top()); + } else if (_type == OverviewLinks) { + p.setY(p.y() - _addToY - _cachedItems[itemIndex].y); } else if (_type == OverviewAudios) { - p.setY(p.y() - _addToY - (_height - _items[itemIndex].y)); + p.setY(p.y() - _addToY - (_height - _cachedItems[itemIndex].y)); } return p; } @@ -1017,8 +1023,8 @@ void OverviewInner::preloadMore() { bool OverviewInner::preloadLocal() { if (_type != OverviewLinks) return false; - if (_itemsToBeLoaded >= migratedIndexSkip() + _history->overview[_type].size()) return false; - _itemsToBeLoaded += LinksOverviewPerPage; + if (_cachedItemsToBeLoaded >= migratedIndexSkip() + _history->overview[_type].size()) return false; + _cachedItemsToBeLoaded += LinksOverviewPerPage; mediaOverviewUpdated(); return true; } @@ -1176,14 +1182,14 @@ void OverviewInner::paintEvent(QPaintEvent *e) { uint32 sel = 0; if (index >= selfrom && index <= selto) { - sel = (_dragSelecting && item->id > 0) ? FullItemSel : 0; + sel = (_dragSelecting && item->id > 0) ? FullSelection : 0; } else if (hasSel) { SelectedItems::const_iterator i = _selected.constFind(migratedindex ? -item->id : item->id); if (i != selEnd) { sel = i.value(); } } - if (sel == FullItemSel) { + if (sel == FullSelection) { p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::overviewPhotoSelectOverlay); p.drawSprite(QPoint(pos.x() + _vsize - st::overviewPhotoCheck.pxWidth(), pos.y() + _vsize - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoChecked); } else if (_selMode/* || (selfrom < count && selfrom <= selto && 0 <= selto)*/) { @@ -1192,7 +1198,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { if (m) { p.translate(pos.x(), pos.y()); - m->drawOverview(p, _vsize, item, r.translated(-pos.x(), -pos.y()), sel == FullItemSel, ms); + m->drawOverview(p, _vsize, item, r.translated(-pos.x(), -pos.y()), sel == FullSelection, ms); p.translate(-pos.x(), -pos.y()); } } @@ -1215,7 +1221,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { if (m) { uint32 sel = 0; if (index >= selfrom && index <= selto) { - sel = (_dragSelecting && item->id > 0) ? FullItemSel : 0; + sel = (_dragSelecting && item->id > 0) ? FullSelection : 0; } else if (hasSel) { SelectedItems::const_iterator i = _selected.constFind(migratedindex ? -item->id : item->id); if (i != selEnd) { @@ -1223,21 +1229,21 @@ void OverviewInner::paintEvent(QPaintEvent *e) { } } - m->drawOverview(p, _rowWidth, item, r.translated(-_rowsLeft, -_addToY - index * _rowHeight), (sel == FullItemSel), ms); + m->drawOverview(p, _rowWidth, item, r.translated(-_rowsLeft, -_addToY - index * _rowHeight), (sel == FullSelection), ms); } p.translate(0, _rowHeight); } } else if (_type == OverviewLinks) { p.translate(_rowsLeft, _addToY); int32 y = 0, w = _rowWidth; - for (int32 i = 0, l = _items.size(); i < l; ++i) { - if (i + 1 == l || _addToY + _items[i + 1].y > r.top()) { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, curY = _items[i].y; + for (int32 i = 0, l = _cachedItems.size(); i < l; ++i) { + if (i + 1 == l || _addToY + _cachedItems[i + 1].y > r.top()) { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, curY = _cachedItems[i].y; if (_addToY + curY >= r.y() + r.height()) break; p.translate(0, curY - y); - if (_items[i].msgid) { // draw item - CachedLink *lnk = _items[i].link; + if (_cachedItems[i].msgid) { // draw item + CachedLink *lnk = _cachedItems[i].link; WebPageData *page = lnk->page; if (page && page->photo) { QPixmap pix; @@ -1269,14 +1275,14 @@ void OverviewInner::paintEvent(QPaintEvent *e) { uint32 sel = 0; if (i >= selfrom && i <= selto) { - sel = (_dragSelecting && itemMsgId(_items[i].msgid) > 0) ? FullItemSel : 0; + sel = (_dragSelecting && itemMsgId(_cachedItems[i].msgid) > 0) ? FullSelection : 0; } else if (hasSel) { - SelectedItems::const_iterator j = _selected.constFind(_items[i].msgid); + SelectedItems::const_iterator j = _selected.constFind(_cachedItems[i].msgid); if (j != selEnd) { sel = j.value(); } } - if (sel == FullItemSel) { + if (sel == FullSelection) { App::roundRect(p, QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); p.drawPixmap(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), App::sprite(), st::linksPhotoChecked); } else if (_selMode/* || (selfrom < count && selfrom <= selto && 0 <= selto)*/) { @@ -1301,15 +1307,15 @@ void OverviewInner::paintEvent(QPaintEvent *e) { p.setPen(st::btnYesColor->p); for (int32 j = 0, c = lnk->urls.size(); j < c; ++j) { - bool sel = (_mousedItem == _items[i].msgid && j + 1 == _lnkOverIndex); + bool sel = (_mousedItem == _cachedItems[i].msgid && j + 1 == _lnkOverIndex); if (sel) p.setFont(st::msgFont->underline()->f); p.drawText(left, top + st::msgFont->ascent, (_rowWidth - left < lnk->urls[j].width) ? st::msgFont->elided(lnk->urls[j].text, _rowWidth - left) : lnk->urls[j].text); if (sel) p.setFont(st::msgFont->f); top += st::msgFont->height; } - p.fillRect(left, _items[i].y - curY, _rowWidth - left, st::linksBorder, st::linksBorderColor->b); + p.fillRect(left, _cachedItems[i].y - curY, _rowWidth - left, st::linksBorder, st::linksBorderColor->b); } else { - QString str = langDayOfMonth(_items[i].date); + QString str = langDayOfMonth(_cachedItems[i].date); p.setPen(st::linksDateColor->p); p.setFont(st::msgFont->f); @@ -1322,65 +1328,55 @@ void OverviewInner::paintEvent(QPaintEvent *e) { p.translate(_rowsLeft, _addToY); int32 y = 0, w = _rowWidth; for (int32 i = 0, l = _items.size(); i < l; ++i) { - if (i + 1 == l || _addToY + _items[i + 1].y > r.top()) { - int32 curY = _items[i].y; + if (i + 1 == l || _addToY + _items.at(i + 1)->getOverviewItemInfo()->top() > r.top()) { + OverviewItemInfo *info = _items.at(i)->getOverviewItemInfo(); + int32 curY = info->top(); if (_addToY + curY >= r.y() + r.height()) break; p.translate(0, curY - y); - if (_items[i].msgid) { // draw item - HistoryItem *item = App::histItemById(itemChannel(_items[i].msgid), itemMsgId(_items[i].msgid)); - HistoryMedia *m = item ? item->getMedia(true) : 0; - if (m) { - uint32 sel = 0; - if (i >= selfrom && i <= selto) { - sel = (_dragSelecting && itemMsgId(_items[i].msgid) > 0) ? FullItemSel : 0; - } else if (hasSel) { - SelectedItems::const_iterator j = _selected.constFind(_items[i].msgid); - if (j != selEnd) { - sel = j.value(); - } + uint32 sel = 0; + if (_items.at(i)->toLayoutMediaItem()) { // draw item + if (i >= selfrom && i <= selto) { + sel = (_dragSelecting && _items.at(i)->msgId() > 0) ? FullSelection : 0; + } else if (hasSel) { + SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(i)->getItem())); + if (j != selEnd) { + sel = j.value(); } - - m->drawOverview(p, _rowWidth, item, r.translated(-_rowsLeft, -_addToY - curY), (sel == FullItemSel), ms); } - } else { - QString str = langDayOfMonth(_items[i].date); - - p.setPen(st::linksDateColor->p); - p.setFont(st::msgFont->f); - p.drawText(0, st::linksDateMargin + st::msgFont->ascent, str); } + _items.at(i)->paint(p, r.translated(-_rowsLeft, -_addToY - curY), sel, ms); y = curY; } } } else if (_type == OverviewAudios) { p.translate(_rowsLeft, _addToY); - int32 y = 0, w = _width - st::msgMargin.left() - st::msgMargin.right(); - for (int32 i = _items.size(); i > 0;) { + int32 y = 0; + for (int32 i = _cachedItems.size(); i > 0;) { --i; - if (!i || (_addToY + _height - _items[i - 1].y > r.top())) { - int32 curY = _height - _items[i].y; + if (!i || (_addToY + _height - _cachedItems[i - 1].y > r.top())) { + int32 curY = _height - _cachedItems[i].y; if (_addToY + curY >= r.y() + r.height()) break; p.translate(0, curY - y); - if (_items[i].msgid) { // draw item - HistoryItem *item = App::histItemById(itemChannel(_items[i].msgid), itemMsgId(_items[i].msgid)); + if (_cachedItems[i].msgid) { // draw item + HistoryItem *item = App::histItemById(itemChannel(_cachedItems[i].msgid), itemMsgId(_cachedItems[i].msgid)); HistoryMedia *m = item ? item->getMedia(true) : 0; if (m) { uint32 sel = 0; if (i >= selfrom && i <= selto) { - sel = (_dragSelecting && itemMsgId(_items[i].msgid) > 0) ? FullItemSel : 0; + sel = (_dragSelecting && itemMsgId(_cachedItems[i].msgid) > 0) ? FullSelection : 0; } else if (hasSel) { - SelectedItems::const_iterator j = _selected.constFind(_items[i].msgid); + SelectedItems::const_iterator j = _selected.constFind(_cachedItems[i].msgid); if (j != selEnd) { sel = j.value(); } } - m->drawOverview(p, _rowWidth, item, r.translated(-_rowsLeft, -_addToY - curY), (sel == FullItemSel), ms); + m->drawOverview(p, _rowWidth, item, r.translated(-_rowsLeft, -_addToY - curY), (sel == FullSelection), ms); } } else { - QString str = langDayOfMonth(_items[i].date); + QString str = langDayOfMonth(_cachedItems[i].date); p.setPen(st::linksDateColor->p); p.setFont(st::msgFont->f); @@ -1480,55 +1476,74 @@ void OverviewInner::onUpdateSelected() { _selectedMsgId = newsel; redrawItem(item); } - } else if (_type == OverviewLinks || _type == OverviewDocuments) { - int32 w = _width - st::msgMargin.left() - st::msgMargin.right(); + } else if (_type == OverviewDocuments) { for (int32 i = 0, l = _items.size(); i < l; ++i) { - if ((i + 1 == l) || (_addToY + _items[i + 1].y > m.y())) { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, y = _addToY + _items[i].y; - if (!_items[i].msgid) { // day item - int32 h = 2 * st::linksDateMargin + st::msgFont->height;// itemHeight(_items[i].msgid, i); - if (i > 0 && ((y + h / 2) >= m.y() || i == _items.size() - 1)) { + if ((i + 1 == l) || (_addToY + _items.at(i + 1)->getOverviewItemInfo()->top() > m.y())) { + int32 top = _addToY + _items.at(i)->getOverviewItemInfo()->top(); + if (!_items.at(i)->toLayoutMediaItem()) { // day item + int32 h = _items.at(i)->height(); + if (i > 0 && ((top + h / 2) >= m.y() || i == _cachedItems.size() - 1)) { --i; - if (!_items[i].msgid) break; // wtf - y = _addToY + _items[i].y; - } else if (i < _items.size() - 1 && ((y + h / 2) < m.y() || !i)) { + if (!_items.at(i)->toLayoutMediaItem()) break; // wtf + top = _addToY + _items.at(i)->getOverviewItemInfo()->top(); + } else if (i < _items.size() - 1 && ((top + h / 2) < m.y() || !i)) { ++i; - if (!_items[i].msgid) break; // wtf - y = _addToY + _items[i].y; + if (!_items.at(i)->toLayoutMediaItem()) break; // wtf + top = _addToY + _items.at(i)->getOverviewItemInfo()->top(); } else { break; // wtf } } - HistoryItem *histItem = App::histItemById(itemChannel(_items[i].msgid), itemMsgId(_items[i].msgid)); + if (LayoutMediaItem *media = _items.at(i)->toLayoutMediaItem()) { + item = media->getItem(); + index = i; + media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - top); + } + break; + } + } + } else if (_type == OverviewLinks) { + for (int32 i = 0, l = _cachedItems.size(); i < l; ++i) { + if ((i + 1 == l) || (_addToY + _cachedItems[i + 1].y > m.y())) { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, y = _addToY + _cachedItems[i].y; + if (!_cachedItems[i].msgid) { // day item + int32 h = 2 * st::linksDateMargin + st::msgFont->height;// itemHeight(_cachedItems[i].msgid, i); + if (i > 0 && ((y + h / 2) >= m.y() || i == _cachedItems.size() - 1)) { + --i; + if (!_cachedItems[i].msgid) break; // wtf + y = _addToY + _cachedItems[i].y; + } else if (i < _cachedItems.size() - 1 && ((y + h / 2) < m.y() || !i)) { + ++i; + if (!_cachedItems[i].msgid) break; // wtf + y = _addToY + _cachedItems[i].y; + } else { + break; // wtf + } + } + + HistoryItem *histItem = App::histItemById(itemChannel(_cachedItems[i].msgid), itemMsgId(_cachedItems[i].msgid)); if (histItem) { item = histItem; index = i; - if (_type == OverviewLinks) { - int32 top = y + st::linksMargin + st::linksBorder, left = _rowsLeft + st::dlgPhotoSize + st::dlgPhotoPadding, w = _rowWidth - st::dlgPhotoSize - st::dlgPhotoPadding; - if (!_items[i].link->title.isEmpty() && _items[i].link->text.isEmpty() && _items[i].link->urls.size() == 1) { - top += (st::dlgPhotoSize - st::webPageTitleFont->height - st::msgFont->height) / 2; - } - if (QRect(_rowsLeft, y + st::linksMargin + st::linksBorder, st::dlgPhotoSize, st::dlgPhotoSize).contains(m)) { - lnkIndex = -1; - } else if (!_items[i].link->title.isEmpty() && QRect(left, top, qMin(w, _items[i].link->titleWidth), st::webPageTitleFont->height).contains(m)) { - lnkIndex = -1; - } else { - if (!_items[i].link->title.isEmpty()) top += st::webPageTitleFont->height; - if (!_items[i].link->text.isEmpty()) top += qMin(st::msgFont->height * 3, _items[i].link->text.countHeight(w)); - for (int32 j = 0, c = _items[i].link->urls.size(); j < c; ++j) { - if (QRect(left, top, qMin(w, _items[i].link->urls[j].width), st::msgFont->height).contains(m)) { - lnkIndex = j + 1; - break; - } - top += st::msgFont->height; + int32 top = y + st::linksMargin + st::linksBorder, left = _rowsLeft + st::dlgPhotoSize + st::dlgPhotoPadding, w = _rowWidth - st::dlgPhotoSize - st::dlgPhotoPadding; + if (!_cachedItems[i].link->title.isEmpty() && _cachedItems[i].link->text.isEmpty() && _cachedItems[i].link->urls.size() == 1) { + top += (st::dlgPhotoSize - st::webPageTitleFont->height - st::msgFont->height) / 2; + } + if (QRect(_rowsLeft, y + st::linksMargin + st::linksBorder, st::dlgPhotoSize, st::dlgPhotoSize).contains(m)) { + lnkIndex = -1; + } else if (!_cachedItems[i].link->title.isEmpty() && QRect(left, top, qMin(w, _cachedItems[i].link->titleWidth), st::webPageTitleFont->height).contains(m)) { + lnkIndex = -1; + } else { + if (!_cachedItems[i].link->title.isEmpty()) top += st::webPageTitleFont->height; + if (!_cachedItems[i].link->text.isEmpty()) top += qMin(st::msgFont->height * 3, _cachedItems[i].link->text.countHeight(w)); + for (int32 j = 0, c = _cachedItems[i].link->urls.size(); j < c; ++j) { + if (QRect(left, top, qMin(w, _cachedItems[i].link->urls[j].width), st::msgFont->height).contains(m)) { + lnkIndex = j + 1; + break; } - } - } else if (_type == OverviewDocuments) { - HistoryMedia *media = item->getMedia(true); - if (media) { - media->getStateOverview(lnk, m.x() - _rowsLeft, m.y() - y, item, _rowWidth); + top += st::msgFont->height; } } } @@ -1536,27 +1551,26 @@ void OverviewInner::onUpdateSelected() { } } } else if (_type == OverviewAudios) { - int32 w = _width - st::msgMargin.left() - st::msgMargin.right(); - for (int32 i = _items.size(); i > 0;) { + for (int32 i = _cachedItems.size(); i > 0;) { --i; - if (!i || (_addToY + _height - _items[i - 1].y > m.y())) { - int32 y = _addToY + _height - _items[i].y; - if (!_items[i].msgid) { // day item - int32 h = st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); // itemHeight(_items[i].msgid, i); - if (i > 0 && ((y + h / 2) < m.y() || i == _items.size() - 1)) { + if (!i || (_addToY + _height - _cachedItems[i - 1].y > m.y())) { + int32 y = _addToY + _height - _cachedItems[i].y; + if (!_cachedItems[i].msgid) { // day item + int32 h = st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); // itemHeight(_cachedItems[i].msgid, i); + if (i > 0 && ((y + h / 2) < m.y() || i == _cachedItems.size() - 1)) { --i; - if (!_items[i].msgid) break; // wtf - y = _addToY + _height - _items[i].y; - } else if (i < _items.size() - 1 && ((y + h / 2) >= m.y() || !i)) { + if (!_cachedItems[i].msgid) break; // wtf + y = _addToY + _height - _cachedItems[i].y; + } else if (i < _cachedItems.size() - 1 && ((y + h / 2) >= m.y() || !i)) { ++i; - if (!_items[i].msgid) break; // wtf - y = _addToY + _height - _items[i].y; + if (!_cachedItems[i].msgid) break; // wtf + y = _addToY + _height - _cachedItems[i].y; } else { break; // wtf } } - HistoryItem *histItem = App::histItemById(itemChannel(_items[i].msgid), itemMsgId(_items[i].msgid)); + HistoryItem *histItem = App::histItemById(itemChannel(_cachedItems[i].msgid), itemMsgId(_cachedItems[i].msgid)); if (histItem) { item = histItem; index = i; @@ -1627,13 +1641,13 @@ void OverviewInner::onUpdateSelected() { cur = (textlnkDown() || _lnkDownIndex) ? style::cur_pointer : style::cur_default; if (_dragAction == Selecting) { bool canSelectMany = (_peer != 0); - if (_mousedItem == _dragItem && (lnk || lnkIndex) && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (_mousedItem == _dragItem && (lnk || lnkIndex) && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { bool afterSymbol = false, uponSymbol = false; uint16 second = 0; _selected[_dragItem] = 0; updateDragSelection(0, -1, 0, -1, false); } else if (canSelectMany) { - bool selectingDown = ((_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments || _type == OverviewLinks) ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y()))); + bool selectingDown = ((_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments || _type == OverviewLinks || _type == OverviewDocuments) ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y()))); MsgId dragSelFrom = _dragItem, dragSelTo = _mousedItem; int32 dragSelFromIndex = _dragItemIndex, dragSelToIndex = _mousedItemIndex; if (!itemHasPoint(dragSelFrom, dragSelFromIndex, _dragStartPos.x(), _dragStartPos.y())) { // maybe exclude dragSelFrom @@ -1644,14 +1658,14 @@ void OverviewInner::onUpdateSelected() { } } else if (_type == OverviewAudioDocuments) { if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) { - moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1); + moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1); } - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) { moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1); } - } else { - if (_dragStartPos.y() >= (itemHeight(dragSelFrom, dragSelFromIndex) - st::msgMargin.bottom()) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) { + } else if (_type == OverviewAudios) { + if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) { moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1); } } @@ -1662,14 +1676,14 @@ void OverviewInner::onUpdateSelected() { } } else if (_type == OverviewAudioDocuments) { if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) { - moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1); + moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1); } - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) { moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1); } - } else { - if (_dragStartPos.y() < st::msgMargin.top() || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) { + } else if (_type == OverviewAudios) { + if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) { moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1); } } @@ -1685,12 +1699,12 @@ void OverviewInner::onUpdateSelected() { if (m.y() < 0) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1); } - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { if (m.y() < 0) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1); } - } else { - if (m.y() < st::msgMargin.top()) { + } else if (_type == OverviewAudios) { + if (m.y() < 0) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1); } } @@ -1703,12 +1717,12 @@ void OverviewInner::onUpdateSelected() { if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1); } - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1); } - } else { - if (m.y() >= itemHeight(dragSelTo, dragSelToIndex) - st::msgMargin.bottom()) { + } else if (_type == OverviewAudios) { + if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) { moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1); } } @@ -1722,7 +1736,7 @@ void OverviewInner::onUpdateSelected() { } if (dragFirstAffectedIndex >= 0) { SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected); - dragSelecting = (i == _selected.cend() || i.value() != FullItemSel); + dragSelecting = (i == _selected.cend() || i.value() != FullSelection); } updateDragSelection(dragSelFrom, dragSelFromIndex, dragSelTo, dragSelToIndex, dragSelecting); } @@ -1731,7 +1745,7 @@ void OverviewInner::onUpdateSelected() { if (textlnkDown() || _lnkDownIndex) { cur = style::cur_pointer; - } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { if (!_dragSelFrom || !_dragSelTo) { cur = style::cur_text; } @@ -1837,11 +1851,6 @@ void OverviewInner::resizeEvent(QResizeEvent *e) { _rowWidth = qMin(_width - st::linksSearchMargin.left() - st::linksSearchMargin.right(), int(st::linksMaxWidth)); } else { _rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), int(st::profileMaxWidth)); - if (_type == OverviewAudioDocuments) { - _rowHeight = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - } else { - _rowHeight = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - } } _rowsLeft = (_width - _rowWidth) / 2; @@ -1879,7 +1888,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { int32 isUponSelected = 0, hasSelected = 0; if (!_selected.isEmpty()) { isUponSelected = -1; - if (_selected.cbegin().value() == FullItemSel) { + if (_selected.cbegin().value() == FullSelection) { hasSelected = 2; if (!ignoreMousedItem && App::mousedItem() && _selected.constFind(App::mousedItem()->history() == _migrated ? -App::mousedItem()->id : App::mousedItem()->id) != _selected.cend()) { isUponSelected = 2; @@ -1990,7 +1999,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh _minHeight = minHeight; if (_type == OverviewAudioDocuments) { _addToY = st::playlistPadding; - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { _addToY = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); } else { _addToY = (_height < _minHeight) ? (_minHeight - _height) : 0; @@ -2030,10 +2039,10 @@ void OverviewInner::switchType(MediaOverviewType type) { _dragItemIndex = _mousedItemIndex = _dragSelFromIndex = _dragSelToIndex = -1; _dragItem = _mousedItem = _dragSelFrom = _dragSelTo = 0; _lnkOverIndex = _lnkDownIndex = 0; - _items.clear(); + _cachedItems.clear(); _cached.clear(); _type = type; - if (_type == OverviewLinks) { + if (_type == OverviewLinks || _type == OverviewDocuments) { _search.show(); } else { _search.hide(); @@ -2095,17 +2104,20 @@ void OverviewInner::deleteMessage() { App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1); } +MsgId OverviewInner::complexMsgId(const HistoryItem *item) const { + return item ? ((item->history() == _migrated) ? -item->id : item->id) : 0; +} + void OverviewInner::selectMessage() { HistoryItem *item = App::contextItem(); if (!item || item->type() != HistoryItemMsg || item->serviceMsg()) return; - MsgId msgid = item->history() == _migrated ? -item->id : item->id; - if (!_selected.isEmpty() && _selected.cbegin().value() != FullItemSel) { + if (!_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { _selected.clear(); - } else if (_selected.size() == MaxSelectedItems && _selected.constFind(msgid) == _selected.cend()) { + } else if (_selected.size() == MaxSelectedItems && _selected.constFind(complexMsgId(item)) == _selected.cend()) { return; } - _selected.insert(msgid, FullItemSel); + _selected.insert(complexMsgId(item), FullSelection); _overview->updateTopBarSelection(); _overview->update(); } @@ -2182,7 +2194,7 @@ void OverviewInner::onNeedSearchMessages() { } void OverviewInner::onSearchUpdate() { - QString filterText = (_type == OverviewLinks) ? _search.text().trimmed() : QString(); + QString filterText = (_type == OverviewLinks || _type == OverviewDocuments) ? _search.text().trimmed() : QString(); bool inSearch = !filterText.isEmpty(), changed = (inSearch != _inSearch); _inSearch = inSearch; @@ -2199,7 +2211,7 @@ void OverviewInner::onSearchUpdate() { } if (changed) { - _itemsToBeLoaded = LinksOverviewPerPage * 2; + _cachedItemsToBeLoaded = LinksOverviewPerPage * 2; mediaOverviewUpdated(); } _overview->scrollReset(); @@ -2236,7 +2248,7 @@ void OverviewInner::onMenuDestroy(QObject *obj) { void OverviewInner::getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const { selectedForForward = selectedForDelete = 0; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { - if (i.value() == FullItemSel) { + if (i.value() == FullSelection) { if (HistoryItem *item = App::histItemById(itemChannel(i.key()), itemMsgId(i.key()))) { if (item->canDelete()) { ++selectedForDelete; @@ -2251,7 +2263,7 @@ void OverviewInner::getSelectionState(int32 &selectedForForward, int32 &selected } void OverviewInner::clearSelectedItems(bool onlyTextSelection) { - if (!_selected.isEmpty() && (!onlyTextSelection || _selected.cbegin().value() != FullItemSel)) { + if (!_selected.isEmpty() && (!onlyTextSelection || _selected.cbegin().value() != FullSelection)) { _selected.clear(); _overview->updateTopBarSelection(); _overview->update(); @@ -2259,7 +2271,7 @@ void OverviewInner::clearSelectedItems(bool onlyTextSelection) { } void OverviewInner::fillSelectedItems(SelectedItemSet &sel, bool forDelete) { - if (_selected.isEmpty() || _selected.cbegin().value() != FullItemSel) return; + if (_selected.isEmpty() || _selected.cbegin().value() != FullSelection) return; for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) { HistoryItem *item = App::histItemById(itemChannel(i.key()), itemMsgId(i.key())); @@ -2300,42 +2312,131 @@ void OverviewInner::onTouchScrollTimer() { } void OverviewInner::mediaOverviewUpdated(bool fromResize) { + if (_type == OverviewAudioDocuments) { + _rowHeight = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); + } else { + _rowHeight = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); + } + int32 oldHeight = _height; - if (_type == OverviewLinks || _type == OverviewDocuments) { + if (_type == OverviewDocuments) { History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0; int32 migrateCount = migratedIndexSkip(); - int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _itemsToBeLoaded); + int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _cachedItemsToBeLoaded); _items.reserve(2 * l); // day items - int32 y = 0, in = 0; + int32 top = 0, in = 0, addtoheight = _addToY + st::linksSearchMargin.top(); bool allGood = true; QDate prevDate; for (int32 i = 0; i < tocheck; ++i) { MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -(*migratedOverview)[l - i - 1] : o.at(l - i - 1 - migrateCount)); if (allGood) { - if (_items.size() > in && _items.at(in).msgid == msgid) { - prevDate = _items.at(in).date; - if (fromResize && _type == OverviewLinks) { - _items[in].y = y; - y += _items[in].link->countHeight(_rowWidth); + if (_items.size() > in && complexMsgId(_items.at(in)->getItem()) == msgid) { + prevDate = _items.at(in)->getItem()->date.date(); + if (fromResize) { + _items.at(in)->getOverviewItemInfo()->setTop(top); + top += _items.at(in)->resizeGetHeight(_rowWidth); } else { - y = (in + 1 < _items.size()) ? _items.at(in + 1).y : _height; + top = (in + 1 < _items.size()) ? _items.at(in + 1)->getOverviewItemInfo()->top() : (_height - addtoheight); } ++in; continue; } - if (_items.size() > in + 1 && !_items.at(in).msgid && _items.at(in + 1).msgid == msgid) { // day item + if (_items.size() > in + 1 && !_items.at(in)->toLayoutMediaItem() && complexMsgId(_items.at(in + 1)->getItem()) == msgid) { // day item + if (fromResize) { + _items.at(in)->getOverviewItemInfo()->setTop(top); + top += _items.at(in)->resizeGetHeight(_rowWidth); + } + ++in; + prevDate = _items.at(in)->getItem()->date.date(); + if (fromResize) { + _items.at(in)->getOverviewItemInfo()->setTop(top); + top += _items.at(in)->resizeGetHeight(_rowWidth); + } else { + top = (in + 1 < _items.size()) ? _items.at(in + 1)->getOverviewItemInfo()->top() : (_height - addtoheight); + } + ++in; + continue; + } + allGood = false; + } + HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); + HistoryMedia *media = item ? item->getMedia(true) : 0; + if (!media) continue; + + QDate date = item->date.date(); + if (!in || (in > 0 && date != prevDate)) { + if (_items.size() > in) { + delete _items.at(in); + _items[in] = new LayoutOverviewDate(date, top); + } else { + _items.push_back(new LayoutOverviewDate(date, top)); + } + _items.at(in)->initDimensions(); + top += _items.at(in)->resizeGetHeight(_rowWidth); + ++in; + prevDate = date; + } + + if (_items.size() > in) { + delete _items.at(in); + _items[in] = new LayoutOverviewDocument(media->getDocument(), item, top); + } else { + _items.push_back(new LayoutOverviewDocument(media->getDocument(), item, top)); + } + _items.at(in)->initDimensions(); + top += _items.at(in)->resizeGetHeight(_rowWidth); + ++in; + } + if (_items.size() > in) { + for (int32 i = in, l = _items.size(); i < l; ++i) { + delete _items.at(i); + } + _items.resize(in); + } + if (_height != top + addtoheight) { + _height = top + addtoheight; + if (!fromResize) { + resize(width(), _minHeight > _height ? _minHeight : _height); + } + } + dragActionUpdate(QCursor::pos()); + update(); + } else if (_type == OverviewLinks) { + History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0; + int32 migrateCount = migratedIndexSkip(); + int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _cachedItemsToBeLoaded); + _cachedItems.reserve(2 * l); // day items + + int32 y = 0, in = 0, addtoheight = _addToY + st::linksSearchMargin.top(); + bool allGood = true; + QDate prevDate; + for (int32 i = 0; i < tocheck; ++i) { + MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -(*migratedOverview)[l - i - 1] : o.at(l - i - 1 - migrateCount)); + if (allGood) { + if (_cachedItems.size() > in && _cachedItems.at(in).msgid == msgid) { + prevDate = _cachedItems.at(in).date; if (fromResize && _type == OverviewLinks) { - _items[in].y = y; + _cachedItems[in].y = y; + y += _cachedItems[in].link->countHeight(_rowWidth); + } else { + y = (in + 1 < _cachedItems.size()) ? _cachedItems.at(in + 1).y : (_height - addtoheight); + } + ++in; + continue; + } + if (_cachedItems.size() > in + 1 && !_cachedItems.at(in).msgid && _cachedItems.at(in + 1).msgid == msgid) { // day item + if (fromResize && _type == OverviewLinks) { + _cachedItems[in].y = y; y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; } ++in; - prevDate = _items.at(in).date; + prevDate = _cachedItems.at(in).date; if (fromResize && _type == OverviewLinks) { - _items[in].y = y; - y += _items[in].link->countHeight(_rowWidth); + _cachedItems[in].y = y; + y += _cachedItems[in].link->countHeight(_rowWidth); } else { - y = (in + 1 < _items.size()) ? _items.at(in + 1).y : _height; + y = (in + 1 < _cachedItems.size()) ? _cachedItems.at(in + 1).y : (_height - addtoheight); } ++in; continue; @@ -2347,12 +2448,12 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { QDate date = item->date.date(); if (!in || (in > 0 && date != prevDate)) { - if (_items.size() > in) { - _items[in].msgid = 0; - _items[in].date = date; - _items[in].y = y; + if (_cachedItems.size() > in) { + _cachedItems[in].msgid = 0; + _cachedItems[in].date = date; + _cachedItems[in].y = y; } else { - _items.push_back(CachedItem(0, date, y)); + _cachedItems.push_back(CachedItem(0, date, y)); } y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; ++in; @@ -2362,30 +2463,30 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { HistoryMedia *media = item ? item->getMedia(true) : 0; if (media) media->initDimensions(item); - if (_items.size() > in) { - _items[in] = CachedItem(msgid, item->date.date(), y); + if (_cachedItems.size() > in) { + _cachedItems[in] = CachedItem(msgid, item->date.date(), y); if (_type == OverviewLinks) { - _items[in].link = cachedLink(item); - y += _items[in].link->countHeight(_rowWidth); + _cachedItems[in].link = cachedLink(item); + y += _cachedItems[in].link->countHeight(_rowWidth); } else { y += _rowHeight; } } else { - _items.push_back(CachedItem(msgid, item->date.date(), y)); + _cachedItems.push_back(CachedItem(msgid, item->date.date(), y)); if (_type == OverviewLinks) { - _items.back().link = cachedLink(item); - y += _items.back().link->countHeight(_rowWidth); + _cachedItems.back().link = cachedLink(item); + y += _cachedItems.back().link->countHeight(_rowWidth); } else { y += _rowHeight; } } ++in; } - if (_items.size() != in) { - _items.resize(in); + if (_cachedItems.size() != in) { + _cachedItems.resize(in); } - if (_height != _addToY + y + st::linksSearchMargin.top()) { - _height = _addToY + y + st::linksSearchMargin.top(); + if (_height != y + addtoheight) { + _height = y + addtoheight; if (!fromResize) { resize(width(), _minHeight > _height ? _minHeight : _height); } @@ -2396,25 +2497,24 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0; int32 migrateCount = migratedIndexSkip(); int32 l = migrateCount + o.size(); - _items.reserve(2 * l); // day items + _cachedItems.reserve(2 * l); // day items int32 y = 0, in = 0; - int32 w = _width - st::msgMargin.left() - st::msgMargin.right(); bool allGood = true; QDate prevDate; for (int32 i = 0; i < l; ++i) { MsgId msgid = (l - i - 1 < migrateCount) ? -(*migratedOverview)[l - i - 1] : o.at(l - i - 1 - migrateCount); if (allGood) { - if (_items.size() > in && _items.at(in).msgid == msgid) { - prevDate = _items.at(in).date; - y = _items.at(in).y; + if (_cachedItems.size() > in && _cachedItems.at(in).msgid == msgid) { + prevDate = _cachedItems.at(in).date; + y = _cachedItems.at(in).y; ++in; continue; } - if (_items.size() > in + 1 && !_items.at(in).msgid && _items.at(in + 1).msgid == msgid) { // day item + if (_cachedItems.size() > in + 1 && !_cachedItems.at(in).msgid && _cachedItems.at(in + 1).msgid == msgid) { // day item ++in; - prevDate = _items.at(in).date; - y = _items.at(in).y; + prevDate = _cachedItems.at(in).date; + y = _cachedItems.at(in).y; ++in; continue; } @@ -2428,12 +2528,12 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { if (in > 0) { if (date != prevDate) { // add day item y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; // day item height - if (_items.size() > in) { - _items[in].msgid = 0; - _items[in].date = prevDate; - _items[in].y = y; + if (_cachedItems.size() > in) { + _cachedItems[in].msgid = 0; + _cachedItems[in].date = prevDate; + _cachedItems[in].y = y; } else { - _items.push_back(CachedItem(0, prevDate, y)); + _cachedItems.push_back(CachedItem(0, prevDate, y)); } ++in; prevDate = date; @@ -2443,25 +2543,25 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { } media->initDimensions(item); y += _rowHeight; - if (_items.size() > in) { - _items[in].msgid = msgid; - _items[in].date = date; - _items[in].y = y; + if (_cachedItems.size() > in) { + _cachedItems[in].msgid = msgid; + _cachedItems[in].date = date; + _cachedItems[in].y = y; } else { - _items.push_back(CachedItem(msgid, date, y)); + _cachedItems.push_back(CachedItem(msgid, date, y)); } ++in; } - if (!_items.isEmpty()) { + if (!_cachedItems.isEmpty()) { y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; // day item height - if (_items.size() > in) { - _items[in].msgid = 0; - _items[in].date = prevDate; - _items[in].y = y; + if (_cachedItems.size() > in) { + _cachedItems[in].msgid = 0; + _cachedItems[in].date = prevDate; + _cachedItems[in].y = y; } else { - _items.push_back(CachedItem(0, prevDate, y)); + _cachedItems.push_back(CachedItem(0, prevDate, y)); } - _items.resize(++in); + _cachedItems.resize(++in); } if (_height != y) { _height = y; @@ -2479,15 +2579,16 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { if (!fromResize) { resizeEvent(0); - if (_height != oldHeight && _type != OverviewLinks) { + if (_height != oldHeight && _type != OverviewLinks && _type != OverviewDocuments) { _overview->scrollBy(_height - oldHeight); } } } void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) { - MsgId oldId = (row->history() == _migrated) ? -row->id : row->id; + MsgId oldId = complexMsgId(row); if (row->history() == _migrated) newId = -newId; + if (_dragSelFrom == oldId) _dragSelFrom = newId; if (_dragSelTo == oldId) _dragSelTo = newId; if (_mousedItem == oldId) _mousedItem = newId; @@ -2503,7 +2604,7 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) { } if (_links.contains(oldId) && oldId != newId) { if (_links.contains(newId)) { - for (CachedItems::iterator i = _items.begin(), e = _items.end(); i != e; ++i) { + for (CachedItems::iterator i = _cachedItems.begin(), e = _cachedItems.end(); i != e; ++i) { if (i->msgid == newId && i->link) { i->link = _links[oldId]; break; @@ -2514,7 +2615,7 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) { _links[newId] = _links[oldId]; _links.remove(oldId); } - for (CachedItems::iterator i = _items.begin(), e = _items.end(); i != e; ++i) { + for (CachedItems::iterator i = _cachedItems.begin(), e = _cachedItems.end(); i != e; ++i) { if (i->msgid == oldId) { i->msgid = newId; break; @@ -2576,19 +2677,27 @@ void OverviewInner::redrawItem(const HistoryItem *msg) { if (history == _history) index += migrateindex; update(_rowsLeft, _addToY + int32(index * _rowHeight), _rowWidth, _rowHeight); } - } else if (_type == OverviewLinks) { + } else if (_type == OverviewDocuments) { if (history == _migrated) msgid = -msgid; for (int32 i = 0, l = _items.size(); i != l; ++i) { - if (_items[i].msgid == msgid) { - update(_rowsLeft, _addToY + _items[i].y, _rowWidth, itemHeight(msgid, i)); + if (complexMsgId(_items.at(i)->getItem()) == msgid) { + update(_rowsLeft, _addToY + _items.at(i)->getOverviewItemInfo()->top(), _rowWidth, _items.at(i)->height()); break; } } - } else { + } else if (_type == OverviewLinks) { if (history == _migrated) msgid = -msgid; - for (int32 i = 0, l = _items.size(); i != l; ++i) { - if (_items[i].msgid == msgid) { - update(0, _addToY + _height - _items[i].y, _width, itemHeight(msgid, i)); + for (int32 i = 0, l = _cachedItems.size(); i != l; ++i) { + if (_cachedItems[i].msgid == msgid) { + update(_rowsLeft, _addToY + _cachedItems[i].y, _rowWidth, itemHeight(msgid, i)); + break; + } + } + } else if (_type == OverviewAudios) { + if (history == _migrated) msgid = -msgid; + for (int32 i = 0, l = _cachedItems.size(); i != l; ++i) { + if (_cachedItems[i].msgid == msgid) { + update(_rowsLeft, _addToY + _height - _cachedItems[i].y, _rowWidth, itemHeight(msgid, i)); break; } } @@ -2618,13 +2727,13 @@ void OverviewInner::showAll(bool recountHeights) { int32 migratedCount = migratedIndexSkip(), count = migratedCount + _history->overview[_type].size(); newHeight = _height = count * _rowHeight + 2 * st::playlistPadding; _addToY = st::playlistPadding; - } else if (_type == OverviewLinks) { + } else if (_type == OverviewLinks || _type == OverviewDocuments) { if (recountHeights) { // recount heights because of texts mediaOverviewUpdated(true); } newHeight = _height; _addToY = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); - } else { + } else if (_type == OverviewAudios) { newHeight = _height; _addToY = (_height < _minHeight) ? (_minHeight - _height) : 0; } @@ -2643,6 +2752,10 @@ OverviewInner::~OverviewInner() { delete i.value(); } _links.clear(); + for (Items::const_iterator i = _items.cbegin(), e = _items.cend(); i != e; ++i) { + delete *i; + } + _items.clear(); } OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent) @@ -2686,7 +2799,7 @@ void OverviewWidget::onScroll() { int32 preloadThreshold = _scroll.height() * 5; bool needToPreload = false; do { - needToPreload = (type() == OverviewLinks) ? (_scroll.scrollTop() + preloadThreshold > _scroll.scrollTopMax()) : (_scroll.scrollTop() < preloadThreshold); + needToPreload = (type() == OverviewLinks || type() == OverviewDocuments) ? (_scroll.scrollTop() + preloadThreshold > _scroll.scrollTopMax()) : (_scroll.scrollTop() < preloadThreshold); if (!needToPreload || !_inner.preloadLocal()) { break; } @@ -2751,7 +2864,7 @@ void OverviewWidget::scrollBy(int32 add) { } void OverviewWidget::scrollReset() { - _scroll.scrollToY((type() == OverviewLinks) ? 0 : _scroll.scrollTopMax()); + _scroll.scrollToY((type() == OverviewLinks || type() == OverviewDocuments) ? 0 : _scroll.scrollTopMax()); } void OverviewWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { @@ -2847,7 +2960,7 @@ int32 OverviewWidget::countBestScroll() const { return snap(top - int(_scroll.height() - (st::msgPadding.top() + st::mediaThumbSize + st::msgPadding.bottom())) / 2, 0, _scroll.scrollTopMax()); } } - } else if (type() == OverviewLinks) { + } else if (type() == OverviewLinks || type() == OverviewDocuments) { return 0; } return _scroll.scrollTopMax(); diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index ec778004a..35c8cfb14 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -110,6 +110,8 @@ public slots: private: + MsgId complexMsgId(const HistoryItem *item) const; + bool itemMigrated(MsgId msgId) const; ChannelId itemChannel(MsgId msgId) const; MsgId itemMsgId(MsgId msgId) const; @@ -185,7 +187,7 @@ private: FlatInput _search; IconedButton _cancelSearch; QVector _results; - int32 _itemsToBeLoaded; + int32 _cachedItemsToBeLoaded; QTimer _searchTimer; QString _searchQuery; @@ -211,6 +213,9 @@ private: CachedLink *cachedLink(HistoryItem *item); + typedef QVector Items; + Items _items; + // other struct CachedItem { CachedItem() : msgid(0), y(0), link(0) { @@ -223,7 +228,7 @@ private: CachedLink *link; }; typedef QVector CachedItems; - CachedItems _items; + CachedItems _cachedItems; int32 _width, _height, _minHeight, _addToY; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 6d3afacc2..af2408a59 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -154,6 +154,13 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, } } +const Text &BotCommand::descriptionText() const { + if (_descriptionText.isEmpty() && !_description.isEmpty()) { + _descriptionText.setText(st::mentionFont, _description, _textNameOptions); + } + return _descriptionText; +} + void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer as well PhotoId newPhotoId = photoId; ImagePtr newPhoto = photo; diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 8fe02f3f5..02a93c0fd 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -301,7 +301,6 @@ private: class BotCommand { public: BotCommand(const QString &command, const QString &description) : command(command), _description(description) { - } QString command; @@ -314,12 +313,7 @@ public: return false; } - const Text &descriptionText() const { - if (_descriptionText.isEmpty() && !_description.isEmpty()) { - _descriptionText.setText(st::mentionFont, _description, _textNameOptions); - } - return _descriptionText; - } + const Text &descriptionText() const; private: QString _description; diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 009ee8e90..6c3f0254c 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1010,6 +1010,7 @@ + @@ -1766,6 +1767,26 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/localstorage.h" + + + + + + + + + + + + + + + + + + + + Moc%27ing mtpConnection.h... diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 5f84eb8b0..ac2f9642c 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -894,6 +894,9 @@ mtproto + + Source Files + @@ -1204,6 +1207,9 @@ gui + + Source Files +