diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 27ff4c9e9..d1ff8b108 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -2315,36 +2315,45 @@ namespace App { if (!format) { format = &tmpFormat; } - QImageReader reader(&buffer, *format); - if (animated) *animated = reader.supportsAnimation() && reader.imageCount() > 1; - if (!reader.read(&result)) { - return QImage(); + { + QImageReader reader(&buffer, *format); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + reader.setAutoTransform(true); +#endif + if (animated) *animated = reader.supportsAnimation() && reader.imageCount() > 1; + QByteArray fmt = reader.format(); + if (!fmt.isEmpty()) *format = fmt; + if (!reader.read(&result)) { + return QImage(); + } + fmt = reader.format(); + if (!fmt.isEmpty()) *format = fmt; } - buffer.seek(0); - *format = reader.format(); - QString fmt = QString::fromUtf8(*format).toLower() ; + QString fmt = QString::fromUtf8(*format).toLower(); if (fmt == "jpg" || fmt == "jpeg") { - //ExifData *exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size()); - //if (exifData) { - // ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); - // ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); - // if (exifEntry) { - // QTransform orientationFix; - // int orientation = exif_get_short(exifEntry->data, byteOrder); - // switch (orientation) { - // case 2: orientationFix = QTransform(-1, 0, 0, 1, 0, 0); break; - // case 3: orientationFix = QTransform(-1, 0, 0, -1, 0, 0); break; - // case 4: orientationFix = QTransform(1, 0, 0, -1, 0, 0); break; - // case 5: orientationFix = QTransform(0, -1, -1, 0, 0, 0); break; - // case 6: orientationFix = QTransform(0, 1, -1, 0, 0, 0); break; - // case 7: orientationFix = QTransform(0, 1, 1, 0, 0, 0); break; - // case 8: orientationFix = QTransform(0, -1, 1, 0, 0, 0); break; - // } - // result = result.transformed(orientationFix); - // } - // exif_data_free(exifData); - //} +#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) + ExifData *exifData = exif_data_new_from_data((const uchar*)(data.constData()), data.size()); + if (exifData) { + ExifByteOrder byteOrder = exif_data_get_byte_order(exifData); + ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION); + if (exifEntry) { + QTransform orientationFix; + int orientation = exif_get_short(exifEntry->data, byteOrder); + switch (orientation) { + case 2: orientationFix = QTransform(-1, 0, 0, 1, 0, 0); break; + case 3: orientationFix = QTransform(-1, 0, 0, -1, 0, 0); break; + case 4: orientationFix = QTransform(1, 0, 0, -1, 0, 0); break; + case 5: orientationFix = QTransform(0, -1, -1, 0, 0, 0); break; + case 6: orientationFix = QTransform(0, 1, -1, 0, 0, 0); break; + case 7: orientationFix = QTransform(0, 1, 1, 0, 0, 0); break; + case 8: orientationFix = QTransform(0, -1, 1, 0, 0, 0); break; + } + result = result.transformed(orientationFix); + } + exif_data_free(exifData); + } +#endif } else if (opaque && result.hasAlphaChannel()) { QImage solid(result.width(), result.height(), QImage::Format_ARGB32_Premultiplied); solid.fill(st::white->c); diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp index 20f5cf3a7..d1d3f859d 100644 --- a/Telegram/SourceFiles/gui/animation.cpp +++ b/Telegram/SourceFiles/gui/animation.cpp @@ -363,6 +363,9 @@ private: delete _reader; initDevice(); _reader = new QImageReader(_device); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + _reader->setAutoTransform(true); +#endif if (!_reader->canRead() || !_reader->supportsAnimation()) { return false; } diff --git a/Telegram/SourceFiles/gui/images.h b/Telegram/SourceFiles/gui/images.h index be2576bfd..83359821b 100644 --- a/Telegram/SourceFiles/gui/images.h +++ b/Telegram/SourceFiles/gui/images.h @@ -138,6 +138,9 @@ protected: void doRestore() const { QBuffer buffer(&saved); QImageReader reader(&buffer, format); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + reader.setAutoTransform(true); +#endif data = QPixmap::fromImageReader(&reader, Qt::ColorOnly); } @@ -206,6 +209,9 @@ protected: void doRestore() const { QBuffer buffer(&saved); QImageReader reader(&buffer, format); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + reader.setAutoTransform(true); +#endif data = QPixmap::fromImageReader(&reader, Qt::ColorOnly); } diff --git a/Telegram/SourceFiles/gui/text.h b/Telegram/SourceFiles/gui/text.h index 59cb4ad9a..bd95be316 100644 --- a/Telegram/SourceFiles/gui/text.h +++ b/Telegram/SourceFiles/gui/text.h @@ -323,6 +323,8 @@ public: virtual bool fullDisplayed() const { return true; } + virtual void setFullDisplayed(bool full) { + } virtual QString encoded() const { return QString(); } @@ -364,6 +366,10 @@ public: return _fullDisplayed; } + void setFullDisplayed(bool full) { + _fullDisplayed = full; + } + QString encoded() const { QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString()); QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 08b277218..54c9cd473 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -5350,6 +5350,15 @@ void HistoryWebPage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); _attach->getState(lnk, state, x - attachLeft, y - attachTop, parent); + if (lnk && _data->photo) { + if (_data->type == WebPageProfile || _data->type == WebPageVideo) { + lnk = _openl; + } else if (_data->type == WebPagePhoto || _data->siteName == qstr("Twitter") || _data->siteName == qstr("Facebook")) { + // leave photo link + } else { + lnk = _openl; + } + } } } } @@ -5538,6 +5547,9 @@ void ImageLinkManager::onFinished(QNetworkReply *reply) { { QBuffer buffer(&data); QImageReader reader(&buffer); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + reader.setAutoTransform(true); +#endif thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly); format = reader.format(); thumb.setDevicePixelRatio(cRetinaFactor()); diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index 503a02d45..4e81b245d 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -534,8 +534,9 @@ void LayoutOverviewVideo::updateStatusText() const { LayoutOverviewAudio::LayoutOverviewAudio(AudioData *audio, HistoryItem *parent) : LayoutAbstractFileItem(parent) , _data(audio) { + setLinks(new AudioOpenLink(_data), new AudioSaveLink(_data), new AudioCancelLink(_data)); updateName(); - _details.setText(st::normalFont, lng_date_and_duration(lt_date, textcmdLink(1, langDateTime(date(_data->date))), lt_duration, formatDurationText(_data->duration)), _textNameOptions); + _details.setText(st::normalFont, lng_date_and_duration(lt_date, textcmdLink(1, langDateTime(date(_data->date))), lt_duration, formatDurationText(_data->duration)), _defaultOptions); _details.setLink(1, TextLinkPtr(new MessageLink(parent))); } @@ -547,6 +548,11 @@ void LayoutOverviewAudio::initDimensions() { void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { bool selected = (selection == FullSelection); bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty(); + + if (!_data->loader && _data->status == FileReady && !already && !hasdata && _data->size < AudioVoiceMsgInMemory) { + _data->save(QString()); + } + if (_data->loader) { ensureRadial(); if (!_radial->animating()) { @@ -563,11 +569,16 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection, int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; - nameleft = st::msgFileSize + st::msgFilePadding.right(); + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); nametop = st::msgFileNameTop; statustop = st::msgFileStatusTop; - QRect inner(rtlrect(0, st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (selected) { + p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); + } + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -576,7 +587,7 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection, float64 over = a_iconOver.current(); p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); } else { - bool over = textlnkDrawOver(already ? _openl : (_data->loader ? _cancell : _savel)); + bool over = textlnkDrawOver((already || hasdata) ? _openl : (_data->loader ? _cancell : _savel)); p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); } @@ -611,7 +622,7 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection, } if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { - p.setPen(st::mediaInFg); + p.setPen(selected ? st::msgInDateFgSelected : st::mediaInFg); _details.drawLeftElided(p, nameleft, statustop, namewidth, _width); } } @@ -623,15 +634,21 @@ void LayoutOverviewAudio::getState(TextLinkPtr &link, HistoryCursorState &cursor int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - nameleft = st::msgFileSize + st::msgFilePadding.right(); + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); nametop = st::msgFileNameTop; statustop = st::msgFileStatusTop; - QRect inner(rtlrect(0, st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); if (inner.contains(x, y)) { link = (already || hasdata) ? _openl : ((_data->loader || _data->status == FileUploading) ? _cancell : _savel); return; } + if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) { + bool inText = false; + _details.getStateLeft(link, inText, x - nameleft, y - statustop, _width, _width); + cursor = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; + } } void LayoutOverviewAudio::updateName() const { @@ -672,8 +689,6 @@ bool LayoutOverviewAudio::updateStatusText() const { } if (statusSize != _statusSize) { setStatusSize(statusSize, _data->size, _data->duration, realDuration); - _details.setText(st::normalFont, lng_date_and_duration(lt_date, textcmdLink(1, langDateTime(date(_data->date))), lt_duration, formatDurationText(_data->duration)), _textNameOptions); - _details.setLink(1, TextLinkPtr(new MessageLink(_parent))); } return showPause; } @@ -734,11 +749,16 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti bool wthumb = withThumb(); if (_data->song()) { - nameleft = st::msgFileSize + st::msgFilePadding.right(); + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); nametop = st::msgFileNameTop; statustop = st::msgFileStatusTop; - QRect inner(rtlrect(0, st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (selected) { + p.fillRect(QRect(0, 0, _width, _height), st::msgInBgSelected); + } + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -890,11 +910,12 @@ void LayoutOverviewDocument::getState(TextLinkPtr &link, HistoryCursorState &cur bool wthumb = withThumb(); if (_data->song()) { - nameleft = st::msgFileSize + st::msgFilePadding.right(); + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); nametop = st::msgFileNameTop; statustop = st::msgFileStatusTop; - QRect inner(rtlrect(0, st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); if (inner.contains(x, y)) { link = (already || hasdata) ? _openl : ((_data->loader || _data->status == FileUploading) ? _cancell : _savel); return; @@ -972,3 +993,265 @@ bool LayoutOverviewDocument::updateStatusText() const { } return showPause; } + +namespace { + ITextLink *linkFromUrl(const QString &url) { + int32 at = url.indexOf('@'), slash = url.indexOf('/'); + if ((at > 0) && (slash < 0 || slash > at)) { + return new EmailLink(url); + } + return new TextLink(url); + } +} + +LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItem(parent) +, _titlew(0) +, _page(0) +, _pixw(0) +, _pixh(0) +, _text(st::msgMinWidth) { + QString text = _parent->originalText(); + EntitiesInText entities = _parent->originalEntities(); + + int32 from = 0, till = text.size(), lnk = entities.size(); + for (int32 i = 0; i < lnk; ++i) { + if (entities[i].type != EntityInTextUrl && entities[i].type != EntityInTextCustomUrl && entities[i].type != EntityInTextEmail) { + continue; + } + QString u = entities[i].text, t = text.mid(entities[i].offset, entities[i].length); + _links.push_back(Link(u.isEmpty() ? t : u, t)); + } + while (lnk > 0 && till > from) { + --lnk; + if (entities[lnk].type != EntityInTextUrl && entities[lnk].type != EntityInTextCustomUrl && entities[lnk].type != EntityInTextEmail) { + ++lnk; + break; + } + int32 afterLinkStart = entities[lnk].offset + entities[lnk].length; + if (till > afterLinkStart) { + if (!QRegularExpression(qsl("^[,.\\s_=+\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(afterLinkStart, till - afterLinkStart)).hasMatch()) { + ++lnk; + break; + } + } + till = entities[lnk].offset; + } + if (!lnk) { + if (QRegularExpression(qsl("^[,.\\s\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(from, till - from)).hasMatch()) { + till = from; + } + } + + _page = (media && media->type() == MediaTypeWebPage) ? static_cast(media)->webpage() : 0; + if (_page) { + if (_page->doc) { + _photol = TextLinkPtr(new DocumentOpenLink(_page->doc)); + } else if (_page->photo) { + if (_page->type == WebPageProfile || _page->type == WebPageVideo) { + _photol = TextLinkPtr(linkFromUrl(_page->url)); + } else if (_page->type == WebPagePhoto || _page->siteName == qstr("Twitter") || _page->siteName == qstr("Facebook")) { + _photol = TextLinkPtr(new PhotoLink(_page->photo)); + } else { + _photol = TextLinkPtr(linkFromUrl(_page->url)); + } + } else { + _photol = TextLinkPtr(linkFromUrl(_page->url)); + } + } else if (!_links.isEmpty()) { + _photol = TextLinkPtr(linkFromUrl(_links.at(0).lnk->text())); + } + if (from >= till && _page) { + text = _page->description; + from = 0; + till = text.size(); + } + if (till > from) { + TextParseOptions opts = { TextParseMultiline, int32(st::linksMaxWidth), 3 * st::normalFont->height, Qt::LayoutDirectionAuto }; + _text.setText(st::normalFont, text.mid(from, till - from), opts); + } + int32 tw = 0, th = 0; + if (_page && _page->photo) { + if (!_page->photo->full->loaded()) _page->photo->thumb->load(false, false); + + tw = convertScale(_page->photo->thumb->width()); + th = convertScale(_page->photo->thumb->height()); + } else if (_page && _page->doc) { + if (!_page->doc->thumb->loaded()) _page->doc->thumb->load(false, false); + + tw = convertScale(_page->doc->thumb->width()); + th = convertScale(_page->doc->thumb->height()); + } + if (tw > st::dlgPhotoSize) { + if (th > tw) { + th = th * st::dlgPhotoSize / tw; + tw = st::dlgPhotoSize; + } else if (th > st::dlgPhotoSize) { + tw = tw * st::dlgPhotoSize / th; + th = st::dlgPhotoSize; + } + } + _pixw = qMax(tw, 1); + _pixh = qMax(th, 1); + + if (_page) { + _title = _page->title; + } + QVector parts = (_page ? _page->url : (_links.isEmpty() ? QString() : _links.at(0).lnk->text())).splitRef('/'); + if (!parts.isEmpty()) { + QStringRef domain = parts.at(0); + if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others + domain = parts.at(2); + } + + parts = domain.split('@').back().split('.'); + if (parts.size() > 1) { + _letter = parts.at(parts.size() - 2).at(0).toUpper(); + if (_title.isEmpty()) { + _title.reserve(parts.at(parts.size() - 2).size()); + _title.append(_letter).append(parts.at(parts.size() - 2).mid(1)); + } + } + } + _titlew = st::semiboldFont->width(_title); +} + +void LayoutOverviewLink::initDimensions() { + _maxw = st::linksMaxWidth; + _minh = 0; + if (!_title.isEmpty()) { + _minh += st::semiboldFont->height; + } + if (!_text.isEmpty()) { + _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding)); + } + _minh += _links.size() * st::normalFont->height; + _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder; +} + +int32 LayoutOverviewLink::resizeGetHeight(int32 width) { + _width = qMin(width, _maxw); + int32 w = _width - st::dlgPhotoSize - st::dlgPhotoPadding; + for (int32 i = 0, l = _links.size(); i < l; ++i) { + _links.at(i).lnk->setFullDisplayed(w >= _links.at(i).width); + } + + _height = 0; + if (!_title.isEmpty()) { + _height += st::semiboldFont->height; + } + if (!_text.isEmpty()) { + _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding)); + } + _height += _links.size() * st::normalFont->height; + _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder; + return _height; +} + +void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left; + if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { + if (_page && _page->photo) { + QPixmap pix; + if (_page->photo->full->loaded()) { + pix = _page->photo->full->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } else if (_page->photo->medium->loaded()) { + pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } else { + pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } + p.drawPixmapLeft(0, top, _width, pix); + } else if (_page && _page->doc && !_page->doc->thumb->isNull()) { + p.drawPixmapLeft(0, top, _width, _page->doc->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize)); + } else { + int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); + switch (index) { + case 0: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileRedColor, DocRedCorners); break; + case 1: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileYellowColor, DocYellowCorners); break; + case 2: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileGreenColor, DocGreenCorners); break; + case 3: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileBlueColor, DocBlueCorners); break; + } + + if (!_letter.isEmpty()) { + p.setFont(st::linksLetterFont->f); + p.setPen(st::white->p); + p.drawText(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), _letter, style::al_center); + } + } + + if (selection == FullSelection) { + App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); + p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoChecked); + } else if (context->selecting) { + p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoCheck); + } + } + + if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { + top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + } + + p.setPen(st::black); + p.setFont(st::semiboldFont); + if (!_title.isEmpty()) { + if (clip.intersects(rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width))) { + p.drawTextLeft(left, top, _width, (w < _titlew) ? st::semiboldFont->elided(_title, w) : _title); + } + top += st::semiboldFont->height; + } + p.setFont(st::msgFont->f); + if (!_text.isEmpty()) { + int32 h = qMin(st::normalFont->height * 3, _text.countHeight(w)); + if (clip.intersects(rtlrect(left, top, w, h, _width))) { + _text.drawLeftElided(p, left, top, w, _width, 3); + } + top += h; + } + + p.setPen(st::btnYesColor); + for (int32 i = 0, l = _links.size(); i < l; ++i) { + if (clip.intersects(rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width))) { + p.setFont(textlnkDrawOver(_links.at(i).lnk) ? st::normalFont->underline() : st::normalFont); + p.drawTextLeft(left, top, _width, (w < _links.at(i).width) ? st::normalFont->elided(_links.at(i).text, w) : _links.at(i).text); + } + top += st::normalFont->height; + } + + if (clip.intersects(rtlrect(left, 0, w, st::linksBorder, _width))) { + p.fillRect(clip.intersected(rtlrect(left, 0, w, st::linksBorder, _width)), st::linksBorderColor); + } +} + +void LayoutOverviewLink::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left; + if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) { + link = _photol; + return; + } + + if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { + top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + } + if (!_title.isEmpty()) { + if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(x, y)) { + link = _photol; + return; + } + top += st::webPageTitleFont->height; + } + if (!_text.isEmpty()) { + top += qMin(st::normalFont->height * 3, _text.countHeight(w)); + } + for (int32 i = 0, l = _links.size(); i < l; ++i) { + if (rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width).contains(x, y)) { + link = _links.at(i).lnk; + return; + } + top += st::normalFont->height; + } +} + +LayoutOverviewLink::Link::Link(const QString &url, const QString &text) +: text(text) +, width(st::normalFont->width(text)) +, lnk(linkFromUrl(url)) { +} \ No newline at end of file diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 439fe15a9..d4cebb35a 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -369,7 +369,7 @@ protected: return !_data->already().isEmpty() || !_data->data.isEmpty(); } virtual bool iconAnimated() const { - return !dataLoaded() || (_radial && _radial->animating()); + return true; } private: @@ -434,9 +434,10 @@ private: class LayoutOverviewLink : public LayoutMediaItem { public: - LayoutOverviewLink(HistoryItem *parent); + LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent); virtual void initDimensions(); + virtual int32 resizeGetHeight(int32 width); virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const; @@ -449,26 +450,22 @@ public: private: OverviewItemInfo _info; - TextLinkPtr _msgl; + TextLinkPtr _photol; - QString title, letter; - int32 titleWidth; - WebPageData *page; - int32 pixw, pixh; - Text text; + QString _title, _letter; + int32 _titlew; + WebPageData *_page; + int32 _pixw, _pixh; + Text _text; struct Link { Link() : width(0) { } - Link(const QString &url, const QString &text) - : text(text) - , width(st::normalFont->width(text)) - , lnk(new TextLink(url)) { - } + Link(const QString &url, const QString &text); QString text; int32 width; TextLinkPtr lnk; }; - QVector urls; + QVector _links; }; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 362798d5e..ad7b2cc25 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -2886,6 +2886,9 @@ namespace Local { QImage img; QBuffer buf(&pngData); QImageReader reader(&buf); +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + reader.setAutoTransform(true); +#endif if (reader.read(&img)) { App::initBackground(id, img, true); return true; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 9ab74fb8c..14e06c5ee 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1522,7 +1522,7 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many if (history->overviewLoaded(type)) return; MsgId minId = history->overviewMinId(type); - int32 limit = many ? SearchManyPerPage : (history->overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage; + int32 limit = (many || history->overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage; MTPMessagesFilter filter = typeToMediaFilter(type); if (type == OverviewCount) return; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 59c62e63b..465d3a6e4 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -465,8 +465,7 @@ void MediaView::step_state(uint64 ms, bool timer) { if (!_doc->already().isEmpty() && _doc->size < MediaViewImageSizeLimit) { const FileLocation &location(_doc->location(true)); if (location.accessEnable()) { - QImageReader reader(location.name()); - if (reader.canRead()) { + if (QImageReader(location.name()).canRead()) { displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid)); } location.accessDisable(); @@ -962,8 +961,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty _gif = new ClipReader(location, _doc->data); } } else { - QImageReader reader(location.name()); - if (reader.canRead()) { + if (QImageReader(location.name()).canRead()) { _current = QPixmap::fromImage(App::readImage(location.name(), 0, false), Qt::ColorOnly); } } diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index f670eba65..bd61ab203 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -30,110 +30,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "application.h" #include "gui/filedialog.h" -OverviewInner::CachedLink::CachedLink(HistoryItem *item) : titleWidth(0), page(0), pixw(0), pixh(0), text(st::msgMinWidth) { - QString msgText = item->originalText(); - EntitiesInText msgEntities = item->originalEntities(); - - int32 from = 0, till = msgText.size(), lnk = msgEntities.size(); - for (int32 i = 0; i < lnk; ++i) { - if (msgEntities[i].type != EntityInTextUrl && msgEntities[i].type != EntityInTextCustomUrl && msgEntities[i].type != EntityInTextEmail) { - continue; - } - QString url = msgEntities[i].text, text = msgText.mid(msgEntities[i].offset, msgEntities[i].length); - urls.push_back(Link(url.isEmpty() ? text : url, text)); - } - while (lnk > 0 && till > from) { - --lnk; - if (msgEntities[lnk].type != EntityInTextUrl && msgEntities[lnk].type != EntityInTextCustomUrl && msgEntities[lnk].type != EntityInTextEmail) { - ++lnk; - break; - } - int32 afterLinkStart = msgEntities[lnk].offset + msgEntities[lnk].length; - if (till > afterLinkStart) { - if (!QRegularExpression(qsl("^[,.\\s_=+\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(msgText.mid(afterLinkStart, till - afterLinkStart)).hasMatch()) { - ++lnk; - break; - } - } - till = msgEntities[lnk].offset; - } - if (!lnk) { - if (QRegularExpression(qsl("^[,.\\s\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(msgText.mid(from, till - from)).hasMatch()) { - till = from; - } - } - - HistoryMedia *media = item->getMedia(); - page = (media && media->type() == MediaTypeWebPage) ? static_cast(media)->webpage() : 0; - if (from >= till && page) { - msgText = page->description; - from = 0; - till = msgText.size(); - } - if (till > from) { - TextParseOptions opts = { TextParseMultiline, int32(st::linksMaxWidth), 3 * st::msgFont->height, Qt::LayoutDirectionAuto }; - text.setText(st::msgFont, msgText.mid(from, till - from), opts); - } - int32 tw = 0, th = 0; - if (page && page->photo) { - if (!page->photo->full->loaded()) page->photo->medium->load(false, false); - - tw = convertScale(page->photo->medium->width()); - th = convertScale(page->photo->medium->height()); - } else if (page && page->doc) { - if (!page->doc->thumb->loaded()) page->doc->thumb->load(false, false); - - tw = convertScale(page->doc->thumb->width()); - th = convertScale(page->doc->thumb->height()); - } - if (tw > st::dlgPhotoSize) { - if (th > tw) { - th = th * st::dlgPhotoSize / tw; - tw = st::dlgPhotoSize; - } else if (th > st::dlgPhotoSize) { - tw = tw * st::dlgPhotoSize / th; - th = st::dlgPhotoSize; - } - } - pixw = tw; - pixh = th; - if (pixw < 1) pixw = 1; - if (pixh < 1) pixh = 1; - - if (page) { - title = page->title; - } - QVector parts = (page ? page->url : (urls.isEmpty() ? QString() : urls.at(0).url)).splitRef('/'); - if (!parts.isEmpty()) { - QStringRef domain = parts.at(0); - if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others - domain = parts.at(2); - } - - parts = domain.split('@').back().split('.'); - if (parts.size() > 1) { - letter = parts.at(parts.size() - 2).at(0).toUpper(); - if (title.isEmpty()) { - title.reserve(parts.at(parts.size() - 2).size()); - title.append(letter).append(parts.at(parts.size() - 2).mid(1)); - } - } - } - titleWidth = st::webPageTitleFont->width(title); -} - -int32 OverviewInner::CachedLink::countHeight(int32 w) { - int32 result = 0; - if (!title.isEmpty()) { - result += st::webPageTitleFont->height; - } - if (!text.isEmpty()) { - result += qMin(3 * st::msgFont->height, text.countHeight(w - st::dlgPhotoSize - st::dlgPhotoPadding)); - } - result += urls.size() * st::msgFont->height; - return qMax(result, int(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder; -} - // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerData *peer, MediaOverviewType type) : QWidget(0) @@ -150,11 +46,11 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _selMode(false) , _rowsLeft(0) , _rowWidth(st::msgMinWidth) -, _photosInRow(1) -, _photosToAdd(0) , _search(this, st::dlgFilter, lang(lng_dlg_filter)) , _cancelSearch(this, st::btnCancelSearch) -, _cachedItemsToBeLoaded(LinksOverviewPerPage * 2) +, _itemsToBeLoaded(LinksOverviewPerPage * 2) +, _photosInRow(1) +, _photosToAdd(0) , _inSearch(false) , _searchFull(false) , _searchFullMigrated(false) @@ -165,7 +61,8 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _width(st::wndMinWidth) , _height(0) , _minHeight(0) -, _addToY(0) +, _marginTop(0) +, _marginBottom(0) , _cursor(style::cur_default) , _cursorState(HistoryDefaultCursorState) , _dragAction(NoDrag) @@ -174,8 +71,6 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _dragItemIndex(-1) , _mousedItem(0) , _mousedItemIndex(-1) -, _lnkOverIndex(0) -, _lnkDownIndex(0) , _dragWasInactive(false) , _dragSelFrom(0) , _dragSelTo(0) @@ -192,7 +87,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD , _menu(0) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); - resize(_width, height()); + resize(_width, st::wndMinHeight); App::contextItem(0); @@ -292,17 +187,6 @@ int32 OverviewInner::migratedIndexSkip() const { void OverviewInner::fixItemIndex(int32 ¤t, MsgId msgId) const { if (!msgId) { current = -1; - } else if (_type == OverviewLinks) { - int32 l = _cachedItems.size(); - if (current < 0 || current >= l || _cachedItems[current].msgid != msgId) { - current = -1; - for (int32 i = 0; i < l; ++i) { - if (_cachedItems[i].msgid == msgId) { - current = i; - break; - } - } - } } else { int32 l = _items.size(); if (current < 0 || current >= l || complexMsgId(_items.at(current)->getItem()) != msgId) { @@ -376,7 +260,7 @@ void OverviewInner::searchReceived(SearchRequestType type, const MTPmessages_Mes if (type == SearchFromStart) { _searchResults.clear(); _lastSearchId = _lastSearchMigratedId = 0; - _cachedItemsToBeLoaded = LinksOverviewPerPage * 2; + _itemsToBeLoaded = LinksOverviewPerPage * 2; } if (type == SearchMigratedFromStart) { _lastSearchMigratedId = 0; @@ -416,36 +300,6 @@ bool OverviewInner::searchFailed(SearchRequestType type, const RPCError &error, return true; } -OverviewInner::CachedLink *OverviewInner::cachedLink(HistoryItem *item) { - MsgId msgId = (item->history() == _migrated) ? -item->id : item->id; - CachedLinks::const_iterator i = _links.constFind(msgId); - if (i == _links.cend()) i = _links.insert(msgId, new CachedLink(item)); - return i.value(); -} - -QString OverviewInner::urlByIndex(MsgId msgid, int32 index, int32 lnkIndex, bool *fullShown) const { - fixItemIndex(index, msgid); - if (index < 0 || !_cachedItems[index].link) return QString(); - - if (lnkIndex < 0) { - 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 <= _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(); -} - -bool OverviewInner::urlIsEmail(const QString &url) const { - int32 at = url.indexOf('@'), slash = url.indexOf('/'); - return (at > 0) && (slash < 0 || slash > at); -} - bool OverviewInner::itemHasPoint(MsgId msgId, int32 index, int32 x, int32 y) const { fixItemIndex(index, msgId); if (index < 0) return false; @@ -468,9 +322,6 @@ int32 OverviewInner::itemHeight(MsgId msgId, int32 index) const { } fixItemIndex(index, msgId); - 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.at(index)->height(); } @@ -483,26 +334,14 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32 } index += delta; - if (_type == OverviewLinks) { - while (index >= 0 && index < _cachedItems.size() && !_cachedItems[index].msgid) { - index += (delta > 0) ? 1 : -1; - } - if (index < 0 || index >= _cachedItems.size()) { - msgId = 0; - index = -1; - } else { - msgId = _cachedItems[index].msgid; - } + while (index >= 0 && index < _items.size() && !_items.at(index)->toLayoutMediaItem()) { + index += (delta > 0) ? 1 : -1; + } + if (index < 0 || index >= _items.size()) { + msgId = 0; + index = -1; } else { - while (index >= 0 && index < _items.size() && !_items.at(index)->toLayoutMediaItem()) { - index += (delta > 0) ? 1 : -1; - } - if (index < 0 || index >= _items.size()) { - msgId = 0; - index = -1; - } else { - msgId = complexMsgId(_items.at(index)->getItem()); - } + msgId = complexMsgId(_items.at(index)->getItem()); } } @@ -514,13 +353,11 @@ void OverviewInner::redrawItem(MsgId itemId, int32 itemIndex) { float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow); int32 vsize = (_rowWidth + st::overviewPhotoSkip); int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow; - update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize); - } else if (_type == OverviewLinks) { - update(_rowsLeft, _addToY + _cachedItems[itemIndex].y, _rowWidth, itemHeight(itemId, itemIndex)); + update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize); } else { int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); if (_reversed) top = _height - top; - update(_rowsLeft, _addToY + top, _rowWidth, _items.at(itemIndex)->height()); + update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(itemIndex)->height()); } } } @@ -644,11 +481,6 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but App::pressedLinkItem(App::hoveredLinkItem()); redrawItem(App::pressedLinkItem()); } - if (_lnkDownIndex != _lnkOverIndex) { - if (_dragItem) redrawItem(_dragItem, _dragItemIndex); - _lnkDownIndex = _lnkOverIndex; - if (_mousedItem) redrawItem(_mousedItem, _mousedItemIndex); - } _dragAction = NoDrag; _dragItem = _mousedItem; @@ -656,11 +488,11 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but _dragStartPos = mapMouseToItem(mapFromGlobal(screenPos), _dragItem, _dragItemIndex); _dragWasInactive = App::wnd()->inactivePress(); if (_dragWasInactive) App::wnd()->inactivePress(false); - if ((textlnkDown() || _lnkDownIndex) && _selected.isEmpty()) { + if (textlnkDown() && _selected.isEmpty()) { _dragAction = PrepareDrag; } else if (!_selected.isEmpty()) { if (_selected.cbegin().value() == FullSelection) { - if (_selected.constFind(_dragItem) != _selected.cend() && (textlnkDown() || _lnkDownIndex)) { + if (_selected.constFind(_dragItem) != _selected.cend() && textlnkDown()) { _dragAction = PrepareDrag; // start items drag } else { _dragAction = PrepareSelect; // start items select @@ -671,7 +503,7 @@ void OverviewInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton but bool afterDragSymbol = false , uponSymbol = false; uint16 symbol = 0; if (!_dragWasInactive) { - if (textlnkDown() || _lnkDownIndex) { + if (textlnkDown()) { _dragSymbol = symbol; uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { @@ -711,7 +543,6 @@ void OverviewInner::dragActionCancel() { void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton button) { TextLinkPtr needClick; - int32 needClickIndex = 0; dragActionUpdate(screenPos); @@ -720,11 +551,6 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu needClick = textlnkDown(); } } - if (_lnkOverIndex) { - if (_lnkDownIndex == _lnkOverIndex && _dragAction != Dragging && !_selMode) { - needClickIndex = _lnkDownIndex; - } - } if (textlnkDown()) { redrawItem(App::pressedLinkItem()); textlnkDown(TextLinkPtr()); @@ -734,29 +560,11 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu setCursor(_cursor); } } - if (_lnkDownIndex) { - redrawItem(_dragItem, _dragItemIndex); - _lnkDownIndex = 0; - if (!_lnkOverIndex && _cursor != style::cur_default) { - _cursor = style::cur_default; - setCursor(_cursor); - } - } if (needClick) { needClick->onClick(button); dragActionCancel(); return; } - if (needClickIndex) { - QString url = urlByIndex(_dragItem, _dragItemIndex, needClickIndex); - if (urlIsEmail(url)) { - EmailLink(url).onClick(button); - } else { - TextLink(url).onClick(button); - } - dragActionCancel(); - return; - } if (_dragAction == PrepareSelect && !needClick && !_dragWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { SelectedItems::iterator i = _selected.find(_dragItem); if (i == _selected.cend() && itemMsgId(_dragItem) > 0) { @@ -821,16 +629,6 @@ void OverviewInner::onDragExec() { } else if (textlnkDown()) { sel = textlnkDown()->encoded(); if (!sel.isEmpty() && sel.at(0) != '/' && sel.at(0) != '@' && sel.at(0) != '#') { -// urls.push_back(QUrl::fromEncoded(sel.toUtf8())); // Google Chrome crashes in Mac OS X O_o - } - } else if (_lnkDownIndex) { - QString url = urlByIndex(_dragItem, _dragItemIndex, _lnkDownIndex); - if (urlIsEmail(url)) { - sel = EmailLink(url).encoded(); - } else { - sel = TextLink(url).encoded(); - } - if (!sel.isEmpty() && sel.at(0) != '/' && sel.at(0) != '@' && sel.at(0) != '#') { // urls.push_back(QUrl::fromEncoded(sel.toUtf8())); // Google Chrome crashes in Mac OS X O_o } } @@ -888,12 +686,7 @@ void OverviewInner::touchScrollUpdated(const QPoint &screenPos) { void OverviewInner::addSelectionRange(int32 selFrom, int32 selTo, History *history) { if (selFrom < 0 || selTo < 0) return; for (int32 i = selFrom; i <= selTo; ++i) { - MsgId msgid = 0; - if (_type == OverviewLinks) { - msgid = _cachedItems[i].msgid; - } else { - msgid = complexMsgId(_items.at(i)->getItem()); - } + MsgId msgid = complexMsgId(_items.at(i)->getItem()); if (!msgid) continue; SelectedItems::iterator j = _selected.find(msgid); @@ -934,13 +727,11 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) { int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow; float64 w = (_width - st::overviewPhotoSkip) / float64(_photosInRow); p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip); - p.setY(p.y() - _addToY - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip); - } else if (_type == OverviewLinks) { - p.setY(p.y() - _addToY - _cachedItems[itemIndex].y); - } else if (_reversed) { + p.setY(p.y() - _marginTop - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip); + } else { int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); if (_reversed) top = _height - top; - p.setY(p.y() - _addToY - top); + p.setY(p.y() - _marginTop - top); } return p; } @@ -957,12 +748,16 @@ void OverviewInner::clear() { _selected.clear(); _dragItemIndex = _mousedItemIndex = _dragSelFromIndex = _dragSelToIndex = -1; _dragItem = _mousedItem = _dragSelFrom = _dragSelTo = 0; - _lnkOverIndex = _lnkDownIndex = 0; - for (int32 i = 0, l = _items.size(); i != l; ++i) { - delete _items.at(i); + _dragAction = NoDrag; + for (LayoutItems::const_iterator i = _layoutItems.cbegin(), e = _layoutItems.cend(); i != e; ++i) { + delete i.value(); } + _layoutItems.clear(); + for (LayoutDates::const_iterator i = _layoutDates.cbegin(), e = _layoutDates.cend(); i != e; ++i) { + delete i.value(); + } + _layoutDates.clear(); _items.clear(); - _cachedItems.clear(); } int32 OverviewInner::itemTop(const FullMsgId &msgId) const { @@ -972,7 +767,7 @@ int32 OverviewInner::itemTop(const FullMsgId &msgId) const { if (itemIndex >= 0) { int32 top = _items.at(itemIndex)->getOverviewItemInfo()->top(); if (_reversed) top = _height - top; - return _addToY + top; + return _marginTop + top; } } return -1; @@ -995,17 +790,16 @@ void OverviewInner::preloadMore() { } } else if (App::main()) { if (_migrated && _history->overviewLoaded(_type)) { - App::main()->loadMediaBack(_migrated->peer, _type, false); + App::main()->loadMediaBack(_migrated->peer, _type, true); } else { - App::main()->loadMediaBack(_history->peer, _type, false); + App::main()->loadMediaBack(_history->peer, _type, true); } } } bool OverviewInner::preloadLocal() { - if (_type != OverviewLinks && _type != OverviewDocuments && _type != OverviewPhotos && _type != OverviewVideos) return false; - if (_cachedItemsToBeLoaded >= migratedIndexSkip() + _history->overview[_type].size()) return false; - _cachedItemsToBeLoaded += LinksOverviewPerPage; + if (_itemsToBeLoaded >= migratedIndexSkip() + _history->overview[_type].size()) return false; + _itemsToBeLoaded += LinksOverviewPerPage; mediaOverviewUpdated(); return true; } @@ -1049,7 +843,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { } else if (_inSearch && _searchResults.isEmpty() && _searchFull && (!_migrated || _searchFullMigrated) && !_searchTimer.isActive()) { p.setFont(st::noContactsFont->f); p.setPen(st::noContactsColor->p); - p.drawText(QRect(_rowsLeft, _addToY, _rowWidth, _addToY), lng_search_found_results(lt_count, 0), style::al_center); + p.drawText(QRect(_rowsLeft, _marginTop, _rowWidth, _marginTop), lng_search_found_results(lt_count, 0), style::al_center); return; } @@ -1064,8 +858,8 @@ void OverviewInner::paintEvent(QPaintEvent *e) { if (_type == OverviewPhotos || _type == OverviewVideos) { int32 count = _items.size(), rowsCount = (_photosToAdd + count) / _photosInRow + (((_photosToAdd + count) % _photosInRow) ? 1 : 0); - int32 rowFrom = floorclamp(r.y() - _addToY - st::overviewPhotoSkip, _rowWidth + st::overviewPhotoSkip, 0, rowsCount); - int32 rowTo = ceilclamp(r.y() + r.height() - _addToY - st::overviewPhotoSkip, _rowWidth + st::overviewPhotoSkip, 0, rowsCount); + int32 rowFrom = floorclamp(r.y() - _marginTop - st::overviewPhotoSkip, _rowWidth + st::overviewPhotoSkip, 0, rowsCount); + int32 rowTo = ceilclamp(r.y() + r.height() - _marginTop - st::overviewPhotoSkip, _rowWidth + st::overviewPhotoSkip, 0, rowsCount); float64 w = float64(_width - st::overviewPhotoSkip) / _photosInRow; for (int32 row = rowFrom; row < rowTo; ++row) { if (row * _photosInRow >= _photosToAdd + count) break; @@ -1074,118 +868,27 @@ void OverviewInner::paintEvent(QPaintEvent *e) { if (i < 0) continue; if (i >= count) break; - QPoint pos(int32(col * w + st::overviewPhotoSkip), _addToY + row * (_rowWidth + st::overviewPhotoSkip) + st::overviewPhotoSkip); + QPoint pos(int32(col * w + st::overviewPhotoSkip), _marginTop + row * (_rowWidth + st::overviewPhotoSkip) + st::overviewPhotoSkip); p.translate(pos.x(), pos.y()); _items.at(i)->paint(p, r.translated(-pos.x(), -pos.y()), itemSelectedValue(i), &context); p.translate(-pos.x(), -pos.y()); } } - } else if (_type == OverviewLinks) { - p.translate(_rowsLeft, _addToY); - int32 y = 0, w = _rowWidth; - 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 (_cachedItems[i].msgid) { // draw item - CachedLink *lnk = _cachedItems[i].link; - WebPageData *page = lnk->page; - if (page && page->photo) { - QPixmap pix; - if (page->photo->full->loaded()) { - pix = page->photo->full->pixSingle(lnk->pixw, lnk->pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } else if (page->photo->medium->loaded()) { - pix = page->photo->medium->pixSingle(lnk->pixw, lnk->pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } else { - pix = page->photo->thumb->pixBlurredSingle(lnk->pixw, lnk->pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } - p.drawPixmap(0, top, pix); - } else if (page && page->doc && !page->doc->thumb->isNull()) { - p.drawPixmap(0, top, page->doc->thumb->pixSingle(lnk->pixw, lnk->pixh, st::dlgPhotoSize, st::dlgPhotoSize)); - } else { - int32 index = lnk->letter.isEmpty() ? 0 : (lnk->letter.at(0).unicode() % 4); - switch (index) { - case 0: App::roundRect(p, QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), st::msgFileRedColor, DocRedCorners); break; - case 1: App::roundRect(p, QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), st::msgFileYellowColor, DocYellowCorners); break; - case 2: App::roundRect(p, QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), st::msgFileGreenColor, DocGreenCorners); break; - case 3: App::roundRect(p, QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), st::msgFileBlueColor, DocBlueCorners); break; - } - - if (!lnk->letter.isEmpty()) { - p.setFont(st::linksLetterFont->f); - p.setPen(st::white->p); - p.drawText(QRect(0, top, st::dlgPhotoSize, st::dlgPhotoSize), lnk->letter, style::al_center); - } - } - - uint32 sel = 0; - if (i >= selfrom && i <= selto) { - sel = (_dragSelecting && itemMsgId(_cachedItems[i].msgid) > 0) ? FullSelection : 0; - } else if (hasSel) { - SelectedItems::const_iterator j = _selected.constFind(_cachedItems[i].msgid); - if (j != selEnd) { - sel = j.value(); - } - } - 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)*/) { - p.drawPixmap(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), App::sprite(), st::linksPhotoCheck); - } - - if (!lnk->title.isEmpty() && lnk->text.isEmpty() && lnk->urls.size() == 1) { - top += (st::dlgPhotoSize - st::webPageTitleFont->height - st::msgFont->height) / 2; - } - - p.setPen(st::black->p); - p.setFont(st::webPageTitleFont->f); - if (!lnk->title.isEmpty()) { - p.drawText(left, top + st::webPageTitleFont->ascent, (_rowWidth - left < lnk->titleWidth) ? st::webPageTitleFont->elided(lnk->title, _rowWidth - left) : lnk->title); - top += st::webPageTitleFont->height; - } - p.setFont(st::msgFont->f); - if (!lnk->text.isEmpty()) { - lnk->text.drawElided(p, left, top, _rowWidth - left, 3); - top += qMin(st::msgFont->height * 3, lnk->text.countHeight(_rowWidth - left)); - } - - p.setPen(st::btnYesColor->p); - for (int32 j = 0, c = lnk->urls.size(); j < c; ++j) { - 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, _cachedItems[i].y - curY, _rowWidth - left, st::linksBorder, st::linksBorderColor->b); - } else { - QString str = langDayOfMonthFull(_cachedItems[i].date); - - p.setPen(st::linksDateColor->p); - p.setFont(st::msgFont->f); - p.drawText(0, st::linksDateMargin + st::msgFont->ascent, str); - } - y = curY; - } - } } else { - p.translate(_rowsLeft, _addToY); + p.translate(_rowsLeft, _marginTop); int32 y = 0, w = _rowWidth; for (int32 j = 0, l = _items.size(); j < l; ++j) { int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->getOverviewItemInfo()->top(); if (_reversed) nextItemTop = _height - nextItemTop; - if (_addToY + nextItemTop > r.top()) { + if (_marginTop + nextItemTop > r.top()) { OverviewItemInfo *info = _items.at(i)->getOverviewItemInfo(); int32 curY = info->top(); if (_reversed) curY = _height - curY; - if (_addToY + curY >= r.y() + r.height()) break; + if (_marginTop + curY >= r.y() + r.height()) break; p.translate(0, curY - y); - _items.at(i)->paint(p, r.translated(-_rowsLeft, -_addToY - curY), itemSelectedValue(i), &context); + _items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context); y = curY; } } @@ -1206,7 +909,6 @@ void OverviewInner::onUpdateSelected() { QPoint m(_overview->clampMousePosition(mousePos)); TextLinkPtr lnk; - int32 lnkIndex = 0; // for OverviewLinks HistoryItem *item = 0; int32 index = -1; int32 newsel = 0; @@ -1214,7 +916,7 @@ void OverviewInner::onUpdateSelected() { if (_type == OverviewPhotos || _type == OverviewVideos) { float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow); int32 col = int32((m.x() - (st::overviewPhotoSkip / 2)) / w), vsize = (_rowWidth + st::overviewPhotoSkip); - int32 row = int32((m.y() - _addToY - (st::overviewPhotoSkip / 2)) / vsize); + int32 row = int32((m.y() - _marginTop - (st::overviewPhotoSkip / 2)) / vsize); if (col < 0) col = 0; if (row < 0) row = 0; bool upon = true; @@ -1233,69 +935,22 @@ void OverviewInner::onUpdateSelected() { item = media->getItem(); index = i; if (upon) { - media->getState(lnk, cursorState, m.x() - col * w - st::overviewPhotoSkip, m.y() - _addToY - row * vsize - st::overviewPhotoSkip); + media->getState(lnk, cursorState, m.x() - col * w - st::overviewPhotoSkip, m.y() - _marginTop - row * vsize - st::overviewPhotoSkip); } } } - } 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; - - 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; - } - top += st::msgFont->height; - } - } - } - break; - } - } } else { for (int32 j = 0, l = _items.size(); j < l; ++j) { + bool lastItem = (j + 1 == l); int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); - int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->getOverviewItemInfo()->top(); + int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->getOverviewItemInfo()->top(); if (_reversed) nextItemTop = _height - nextItemTop; - if (_addToY + nextItemTop > m.y()) { + if (_marginTop + nextItemTop > m.y() || lastItem) { int32 top = _items.at(i)->getOverviewItemInfo()->top(); if (_reversed) top = _height - top; - top += _addToY; if (!_items.at(i)->toLayoutMediaItem()) { // day item int32 h = _items.at(i)->height(); - bool beforeItem = (_addToY + top + h / 2) >= m.y(); + bool beforeItem = (_marginTop + top + h / 2) >= m.y(); if (_reversed) beforeItem = !beforeItem; if (i > 0 && (beforeItem || i == _items.size() - 1)) { --i; @@ -1315,7 +970,7 @@ void OverviewInner::onUpdateSelected() { if (LayoutMediaItem *media = _items.at(i)->toLayoutMediaItem()) { item = media->getItem(); index = i; - media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - top); + media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top); } break; } @@ -1334,16 +989,12 @@ void OverviewInner::onUpdateSelected() { lnkChanged = true; if (textlnkOver()) { if (HistoryItem *item = App::hoveredLinkItem()) { - if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) { - MsgId itemId = complexMsgId(item); - int32 itemIndex = oldMousedItemIndex; - fixItemIndex(itemIndex, itemId); - if (itemIndex >= 0) { - _items.at(itemIndex)->linkOut(textlnkOver()); - redrawItem(itemId, itemIndex); - } - } else { - redrawItem(item); + MsgId itemId = complexMsgId(item); + int32 itemIndex = oldMousedItemIndex; + fixItemIndex(itemIndex, itemId); + if (itemIndex >= 0) { + _items.at(itemIndex)->linkOut(textlnkOver()); + redrawItem(itemId, itemIndex); } } } @@ -1352,19 +1003,16 @@ void OverviewInner::onUpdateSelected() { App::hoveredLinkItem(lnk ? item : 0); if (textlnkOver()) { if (item && index >= 0) { - if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) { - _items.at(index)->linkOver(textlnkOver()); - } + _items.at(index)->linkOver(textlnkOver()); redrawItem(complexMsgId(item), index); } } } else { App::mousedItem(item); } - if (lnkIndex != _lnkOverIndex || _mousedItem != oldMousedItem) { + if (_mousedItem != oldMousedItem) { lnkChanged = true; if (oldMousedItem) redrawItem(oldMousedItem, oldMousedItemIndex); - _lnkOverIndex = lnkIndex; if (item) redrawItem(item); QToolTip::hideText(); } @@ -1374,14 +1022,14 @@ void OverviewInner::onUpdateSelected() { if (cursorState != _cursorState) { _cursorState = cursorState; } - if (lnk || lnkIndex || cursorState == HistoryInDateCursorState) { + if (lnk || cursorState == HistoryInDateCursorState) { _linkTipTimer.start(1000); } fixItemIndex(_dragItemIndex, _dragItem); fixItemIndex(_mousedItemIndex, _mousedItem); if (_dragAction == NoDrag) { - if (lnk || lnkIndex) { + if (lnk) { cur = style::cur_pointer; } } else { @@ -1397,10 +1045,10 @@ void OverviewInner::onUpdateSelected() { _dragAction = Selecting; } } - cur = (textlnkDown() || _lnkDownIndex) ? style::cur_pointer : style::cur_default; + cur = textlnkDown() ? style::cur_pointer : style::cur_default; if (_dragAction == Selecting) { bool canSelectMany = (_peer != 0); - if (_mousedItem == _dragItem && (lnk || lnkIndex) && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { + if (_mousedItem == _dragItem && lnk && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { bool afterSymbol = false, uponSymbol = false; uint16 second = 0; _selected[_dragItem] = 0; @@ -1470,7 +1118,7 @@ void OverviewInner::onUpdateSelected() { } else if (_dragAction == Dragging) { } - if (textlnkDown() || _lnkDownIndex) { + if (textlnkDown()) { cur = style::cur_pointer; } else if (_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { if (!_dragSelFrom || !_dragSelTo) { @@ -1498,12 +1146,6 @@ void OverviewInner::showLinkTip() { QRect r(dp.x() - dd, dp.y() - dd, 2 * dd, 2 * dd); if (lnk && !lnk->fullDisplayed()) { QToolTip::showText(_dragPos, lnk->readable(), this, r); - } else if (_lnkOverIndex) { - bool fullLink = false; - QString url = urlByIndex(_mousedItem, _mousedItemIndex, _lnkOverIndex, &fullLink); - if (!fullLink) { - QToolTip::showText(_dragPos, url, this, r); - } } else if (_cursorState == HistoryInDateCursorState && _dragAction == NoDrag && _mousedItem) { if (HistoryItem *item = App::histItemById(itemChannel(_mousedItem), itemMsgId(_mousedItem))) { QToolTip::showText(_dragPos, item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)), this, r); @@ -1573,18 +1215,9 @@ void OverviewInner::leaveEvent(QEvent *e) { } void OverviewInner::resizeEvent(QResizeEvent *e) { - _width = width(); - if (_type == OverviewLinks) { - _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)); - } - _rowsLeft = (_width - _rowWidth) / 2; - _search.setGeometry(_rowsLeft, st::linksSearchMargin.top(), _rowWidth, _search.height()); _cancelSearch.moveToLeft(_rowsLeft + _rowWidth - _cancelSearch.width(), _search.y()); - showAll(true); onUpdateSelected(); update(); } @@ -1674,12 +1307,11 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { redrawItem(App::contextItem()); if (_selectedMsgId) redrawItem(_selectedMsgId, -1); } else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) { - _contextMenuUrl = _lnkOverIndex ? urlByIndex(_mousedItem, _mousedItemIndex, _lnkOverIndex) : QString(); _menu = new PopupMenu(); - if ((_contextMenuLnk && dynamic_cast(_contextMenuLnk.data())) || (!_contextMenuUrl.isEmpty() && !urlIsEmail(_contextMenuUrl))) { + if ((_contextMenuLnk && dynamic_cast(_contextMenuLnk.data()))) { _menu->addAction(lang(lng_context_open_link), this, SLOT(openContextUrl()))->setEnabled(true); _menu->addAction(lang(lng_context_copy_link), this, SLOT(copyContextUrl()))->setEnabled(true); - } else if ((_contextMenuLnk && dynamic_cast(_contextMenuLnk.data())) || (!_contextMenuUrl.isEmpty() && urlIsEmail(_contextMenuUrl))) { + } else if ((_contextMenuLnk && dynamic_cast(_contextMenuLnk.data()))) { _menu->addAction(lang(lng_context_open_email), this, SLOT(openContextUrl()))->setEnabled(true); _menu->addAction(lang(lng_context_copy_email), this, SLOT(copyContextUrl()))->setEnabled(true); } else if (_contextMenuLnk && dynamic_cast(_contextMenuLnk.data())) { @@ -1721,24 +1353,45 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } -int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight) { - if (width() == nwidth && minHeight == _minHeight) return scrollTop; - _minHeight = minHeight; - if (_type == OverviewAudioDocuments) { - _addToY = st::playlistPadding; - } else if (_type == OverviewLinks || _type == OverviewDocuments) { - _addToY = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); - } else { - _addToY = (_height < _minHeight) ? (_minHeight - _height) : 0; - } +int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight, bool force) { + if (!force && _width == nwidth && minHeight == _minHeight) return scrollTop; + if ((_type == OverviewPhotos || _type == OverviewVideos) && _resizeIndex < 0) { - if (_resizeIndex < 0) { - _resizeIndex = _photosInRow * ((scrollTop + minHeight) / int32(_rowWidth + st::overviewPhotoSkip)) + _photosInRow - 1; - _resizeSkip = (scrollTop + minHeight) - ((scrollTop + minHeight) / int32(_rowWidth + st::overviewPhotoSkip)) * int32(_rowWidth + st::overviewPhotoSkip); + _resizeIndex = _photosInRow * ((scrollTop + minHeight) / int32(_rowWidth + st::overviewPhotoSkip)) + _photosInRow - 1; + _resizeSkip = (scrollTop + minHeight) - ((scrollTop + minHeight) / int32(_rowWidth + st::overviewPhotoSkip)) * int32(_rowWidth + st::overviewPhotoSkip); + } + + _width = nwidth; + _minHeight = minHeight; + if (_type == OverviewPhotos || _type == OverviewVideos) { + _photosInRow = int32(_width - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip); + _rowWidth = (int32(_width - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip; + } else if (_type == OverviewLinks) { + _rowWidth = qMin(_width - st::linksSearchMargin.left() - st::linksSearchMargin.right(), int32(st::linksMaxWidth)); + } else { + _rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), int32(st::profileMaxWidth)); + } + _rowsLeft = (_width - _rowWidth) / 2; + if (_type == OverviewPhotos || _type == OverviewVideos) { + for (int32 i = 0, l = _items.size(); i < l; ++i) { + _items.at(i)->resizeGetHeight(_rowWidth); + } + _height = countHeight(); + } else { + bool resize = (_type == OverviewLinks); + if (resize) _height = 0; + for (int32 i = 0, l = _items.size(); i < l; ++i) { + int32 h = _items.at(i)->resizeGetHeight(_rowWidth); + if (resize) { + _items.at(i)->getOverviewItemInfo()->setTop(_height + (_reversed ? h : 0)); + _height += h; + } } } - resize(nwidth, qMax(height(), _minHeight)); - showAll(); + recountMargins(); + + resize(_width, _marginTop + _height + _marginBottom); + if (_type == OverviewPhotos || _type == OverviewVideos) { int32 newRow = _resizeIndex / _photosInRow; return newRow * int32(_rowWidth + st::overviewPhotoSkip) + _resizeSkip - minHeight; @@ -1772,12 +1425,15 @@ void OverviewInner::switchType(MediaOverviewType type) { } else { _search.hide(); } + if (!_search.getLastText().isEmpty()) { _search.setText(QString()); _search.updatePlaceholder(); onSearchUpdate(); } _cancelSearch.hide(); + + resizeToWidth(_width, 0, _minHeight, true); } mediaOverviewUpdated(); if (App::wnd()) App::wnd()->update(); @@ -1793,15 +1449,11 @@ void OverviewInner::openContextUrl() { App::hoveredLinkItem(App::contextItem()); _contextMenuLnk->onClick(Qt::LeftButton); App::hoveredLinkItem(was); - } else if (urlIsEmail(_contextMenuUrl)) { - EmailLink(_contextMenuUrl).onClick(Qt::LeftButton); - } else { - TextLink(_contextMenuUrl).onClick(Qt::LeftButton); } } void OverviewInner::copyContextUrl() { - QString enc = _contextMenuLnk ? _contextMenuLnk->encoded() : _contextMenuUrl; + QString enc = _contextMenuLnk ? _contextMenuLnk->encoded() : QString(); if (!enc.isEmpty()) { QApplication::clipboard()->setText(enc); } @@ -1926,7 +1578,7 @@ void OverviewInner::onSearchUpdate() { onNeedSearchMessages(); - if (filterText.isEmpty()) { + if (!_inSearch) { _searchCache.clear(); _searchQueries.clear(); _searchQuery = QString(); @@ -1937,7 +1589,7 @@ void OverviewInner::onSearchUpdate() { } if (changed) { - _cachedItemsToBeLoaded = LinksOverviewPerPage * 2; + _itemsToBeLoaded = LinksOverviewPerPage * 2; mediaOverviewUpdated(); } _overview->scrollReset(); @@ -2037,13 +1689,12 @@ void OverviewInner::onTouchScrollTimer() { } } -void OverviewInner::mediaOverviewUpdated(bool fromResize) { - int32 oldHeight = _height; +void OverviewInner::mediaOverviewUpdated() { if (_type == OverviewPhotos || _type == OverviewVideos) { History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0; int32 migrateCount = migratedIndexSkip(); int32 wasCount = _items.size(), fullCount = (migrateCount + o.size()); - int32 tocheck = qMin(fullCount, _cachedItemsToBeLoaded); + int32 tocheck = qMin(fullCount, _itemsToBeLoaded); _items.reserve(tocheck); int32 index = 0; @@ -2065,98 +1716,16 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { setLayoutItem(index, layout, 0); ++index; } - for (int32 l = _items.size(); l > index;) { - if (!_items.at(--l)->toLayoutMediaItem()) { - delete _items.at(--l); - } - } - _items.resize(index); + if (_items.size() > index) _items.resize(index); - _height = recountHeight(); - } 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 * tocheck); // 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->at(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) { - _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) { - _cachedItems[in].y = y; - y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; - } - ++in; - prevDate = _cachedItems.at(in).date; - if (fromResize) { - _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; - } - allGood = false; - } - HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); - if (!item) continue; - - QDate date = item->date.date(); - if (!in || (in > 0 && date != prevDate)) { - if (_cachedItems.size() > in) { - _cachedItems[in].msgid = 0; - _cachedItems[in].date = date; - _cachedItems[in].y = y; - } else { - _cachedItems.push_back(CachedItem(0, date, y)); - } - y += st::msgFont->height + st::linksDateMargin * 2 + st::linksBorder; - ++in; - prevDate = date; - } - - HistoryMedia *media = item ? item->getMedia(true) : 0; - if (media) media->initDimensions(item); - - if (_cachedItems.size() > in) { - _cachedItems[in] = CachedItem(msgid, item->date.date(), y); - _cachedItems[in].link = cachedLink(item); - y += _cachedItems[in].link->countHeight(_rowWidth); - } else { - _cachedItems.push_back(CachedItem(msgid, item->date.date(), y)); - _cachedItems.back().link = cachedLink(item); - y += _cachedItems.back().link->countHeight(_rowWidth); - } - ++in; - } - if (_cachedItems.size() != in) { - _cachedItems.resize(in); - } - - _height = y; + _height = countHeight(); } else { bool dateEveryMonth = (_type == OverviewDocuments), dateEveryDay = (_type == OverviewLinks); bool withDates = (dateEveryMonth || dateEveryDay); 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); + int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _itemsToBeLoaded); _items.reserve(withDates * tocheck); // day items int32 top = 0, index = 0; @@ -2201,31 +1770,26 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) { top += setLayoutItem(index, layout, top); ++index; } - for (int32 l = _items.size(); l > index;) { - if (!_items.at(--l)->toLayoutMediaItem()) { - delete _items.at(--l); - } - } - _items.resize(index); + if (_items.size() > index) _items.resize(index); _height = top; } - dragActionUpdate(QCursor::pos()); - update(); - fixItemIndex(_dragSelFromIndex, _dragSelFrom); fixItemIndex(_dragSelToIndex, _dragSelTo); fixItemIndex(_mousedItemIndex, _mousedItem); fixItemIndex(_dragItemIndex, _dragItem); - if (!fromResize) { - if (_height != oldHeight) { - resize(width(), qMax(_addToY + _height, _minHeight)); - if (_type != OverviewLinks && _type != OverviewDocuments) { - _overview->scrollBy(_height - oldHeight); - } + recountMargins(); + int32 newHeight = _marginTop + _height + _marginBottom, deltaHeight = newHeight - height(); + if (deltaHeight) { + resize(_width, newHeight); + if (_type != OverviewLinks && _type != OverviewDocuments) { + _overview->scrollBy(deltaHeight); } + } else { + onUpdateSelected(); + update(); } } @@ -2246,25 +1810,6 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) { break; } } - if (_links.contains(oldId) && oldId != newId) { - if (_links.contains(newId)) { - for (CachedItems::iterator i = _cachedItems.begin(), e = _cachedItems.end(); i != e; ++i) { - if (i->msgid == newId && i->link) { - i->link = _links[oldId]; - break; - } - } - } - delete _links[newId]; - _links[newId] = _links[oldId]; - _links.remove(oldId); - } - for (CachedItems::iterator i = _cachedItems.begin(), e = _cachedItems.end(); i != e; ++i) { - if (i->msgid == oldId) { - i->msgid = newId; - break; - } - } } void OverviewInner::itemRemoved(HistoryItem *item) { @@ -2314,15 +1859,7 @@ void OverviewInner::redrawItem(const HistoryItem *msg) { float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow); int32 vsize = (_rowWidth + st::overviewPhotoSkip); int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow; - update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize); - break; - } - } - } else if (_type == OverviewLinks) { - if (history == _migrated) msgid = -msgid; - 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)); + update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize); break; } } @@ -2332,7 +1869,7 @@ void OverviewInner::redrawItem(const HistoryItem *msg) { if (complexMsgId(_items.at(i)->getItem()) == msgid) { int32 top = _items.at(i)->getOverviewItemInfo()->top(); if (_reversed) top = _height - top; - update(_rowsLeft, _addToY + top, _rowWidth, _items.at(i)->height()); + update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(i)->height()); break; } } @@ -2340,7 +1877,7 @@ void OverviewInner::redrawItem(const HistoryItem *msg) { } } -int32 OverviewInner::recountHeight() { +int32 OverviewInner::countHeight() { int32 result = _height; if (_type == OverviewPhotos || _type == OverviewVideos) { int32 count = _items.size(); @@ -2355,11 +1892,26 @@ int32 OverviewInner::recountHeight() { } int32 rows = ((_photosToAdd + count) / _photosInRow) + (((_photosToAdd + count) % _photosInRow) ? 1 : 0); result = (_rowWidth + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip; - _addToY = (result < _minHeight) ? (_minHeight - result) : 0; } return result; } +void OverviewInner::recountMargins() { + if (_type == OverviewPhotos || _type == OverviewVideos) { + _marginBottom = 0; + _marginTop = qMax(_minHeight - _height - _marginBottom, 0); + } else if (_type == OverviewAudioDocuments) { + _marginTop = st::playlistPadding; + _marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding)); + } else if (_type == OverviewLinks || _type == OverviewDocuments) { + _marginTop = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); + _marginBottom = qMax(_minHeight - _height - _marginTop, int32(st::playlistPadding)); + } else { + _marginBottom = st::playlistPadding; + _marginTop = qMax(_minHeight - _height - _marginBottom, int32(st::playlistPadding)); + } +} + LayoutMediaItem *OverviewInner::getItemLayout(HistoryItem *item) { if (!item) return 0; @@ -2393,21 +1945,28 @@ LayoutMediaItem *OverviewInner::getItemLayout(HistoryItem *item) { i.value()->initDimensions(); } } + } else if (_type == OverviewLinks) { + if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { + i = _layoutItems.insert(item, new LayoutOverviewLink(media, item)); + i.value()->initDimensions(); + } } return (i == _layoutItems.cend()) ? 0 : i.value(); } LayoutItem *OverviewInner::getDateLayout(const QDate &date, bool month) { - LayoutItem *result = new LayoutOverviewDate(date, month); - result->initDimensions(); - return result; + int32 key = date.year() * 100 + date.month(); + if (!month) key = key * 100 + date.day(); + LayoutDates::const_iterator i = _layoutDates.constFind(key); + if (i == _layoutDates.cend()) { + i = _layoutDates.insert(key, new LayoutOverviewDate(date, month)); + i.value()->initDimensions(); + } + return i.value(); } int32 OverviewInner::setLayoutItem(int32 index, LayoutItem *item, int32 top) { if (_items.size() > index) { - if (!_items.at(index)->toLayoutMediaItem()) { // delete date - delete _items.at(index); - } _items[index] = item; } else { _items.push_back(item); @@ -2419,53 +1978,8 @@ int32 OverviewInner::setLayoutItem(int32 index, LayoutItem *item, int32 top) { return h; } -void OverviewInner::showAll(bool recountHeights) { - if (_type == OverviewPhotos || _type == OverviewVideos) { - _photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip); - _rowWidth = (int32(width() - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip; - for (int32 i = 0, l = _items.size(); i < l; ++i) { - _items.at(i)->resizeGetHeight(_rowWidth); - } - _height = recountHeight(); - } else if (_type == OverviewLinks) { - if (recountHeights) { // recount heights because of texts - mediaOverviewUpdated(true); - } - _addToY = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); - } else { - if (_type == OverviewLinks) { - _height = 0; - for (int32 i = 0, l = _items.size(); i < l; ++i) { - int32 h = _items.at(i)->resizeGetHeight(_rowWidth); - _items.at(i)->getOverviewItemInfo()->setTop(_height + (_reversed ? h : 0)); - _height += h; - } - } - if (_type == OverviewAudioDocuments) { - _addToY = st::playlistPadding; - } else if (_type == OverviewLinks || _type == OverviewDocuments) { - _addToY = st::linksSearchMargin.top() + _search.height() + st::linksSearchMargin.bottom(); - } else { - _addToY = (_height < _minHeight) ? (_minHeight - _height) : 0; - } - } - - int32 newHeight = qMax(_addToY + _height, _minHeight); - if (height() != newHeight) { - resize(width(), newHeight); - } -} - OverviewInner::~OverviewInner() { - _dragAction = NoDrag; - for (CachedLinks::const_iterator i = _links.cbegin(), e = _links.cend(); i != e; ++i) { - delete i.value(); - } - _links.clear(); - for (Items::const_iterator i = _items.cbegin(), e = _items.cend(); i != e; ++i) { - delete *i; - } - _items.clear(); + clear(); } OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent) @@ -2677,7 +2191,6 @@ int32 OverviewWidget::countBestScroll() const { } void OverviewWidget::fastShow(bool back, int32 lastScrollTop) { -// App::stopGifItems(); resizeEvent(0); _scrollSetAfterShow = (lastScrollTop < 0 ? countBestScroll() : lastScrollTop); show(); @@ -2690,8 +2203,6 @@ void OverviewWidget::fastShow(bool back, int32 lastScrollTop) { void OverviewWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) { if (App::app()) App::app()->mtpPause(); -// App::stopGifItems(); - (back ? _cacheOver : _cacheUnder) = bgAnimCache; (back ? _cacheTopBarOver : _cacheTopBarUnder) = bgAnimTopBarCache; resizeEvent(0); diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 4eb601538..b2a0ef107 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -57,7 +57,7 @@ public: void touchScrollUpdated(const QPoint &screenPos); QPoint mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex); - int32 resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight); // returns new scroll top + int32 resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight, bool force = false); // returns new scroll top void dropResizeIndex(); PeerData *peer() const; @@ -67,7 +67,7 @@ public: void setSelectMode(bool enabled); - void mediaOverviewUpdated(bool fromResize = false); + void mediaOverviewUpdated(); void changingMsgId(HistoryItem *row, MsgId newId); void redrawItem(const HistoryItem *msg); void itemRemoved(HistoryItem *item); @@ -133,8 +133,8 @@ private: void applyDragSelection(); void addSelectionRange(int32 selFrom, int32 selTo, History *history); - void showAll(bool recountHeights = false); - int32 recountHeight(); + void recountMargins(); + int32 countHeight(); OverviewWidget *_overview; ScrollArea *_scroll; @@ -149,40 +149,25 @@ private: bool _selMode; uint32 itemSelectedValue(int32 index) const; - // for audio files, files, voice messages and links int32 _rowsLeft, _rowWidth; - // photos - int32 _photosInRow, _photosToAdd; + typedef QVector Items; + Items _items; + typedef QMap LayoutItems; + LayoutItems _layoutItems; + typedef QMap LayoutDates; + LayoutDates _layoutDates; + LayoutMediaItem *getItemLayout(HistoryItem *item); + LayoutItem *getDateLayout(const QDate &date, bool month); + int32 setLayoutItem(int32 index, LayoutItem *item, int32 top); - // shared links - struct Link { - Link() : width(0) { - } - Link(const QString &url, const QString &text) : url(url), text(text), width(st::msgFont->width(text)) { - } - QString url, text; - int32 width; - }; - struct CachedLink { - CachedLink() : titleWidth(0), page(0), pixw(0), pixh(0), text(st::msgMinWidth) { - } - CachedLink(HistoryItem *item); - int32 countHeight(int32 w); - - QString title, letter; - int32 titleWidth; - WebPageData *page; - int32 pixw, pixh; - Text text; - QVector urls; - }; - typedef QMap CachedLinks; - CachedLinks _links; FlatInput _search; IconedButton _cancelSearch; QVector _results; - int32 _cachedItemsToBeLoaded; + int32 _itemsToBeLoaded; + + // photos + int32 _photosInRow, _photosToAdd; QTimer _searchTimer; QString _searchQuery; @@ -206,31 +191,7 @@ private: typedef QMap SearchQueries; SearchQueries _searchQueries; - CachedLink *cachedLink(HistoryItem *item); - - typedef QVector Items; - Items _items; - typedef QMap LayoutItems; - LayoutItems _layoutItems; - LayoutMediaItem *getItemLayout(HistoryItem *item); - LayoutItem *getDateLayout(const QDate &date, bool month); - int32 setLayoutItem(int32 index, LayoutItem *item, int32 top); - - // other - struct CachedItem { - CachedItem() : msgid(0), y(0), link(0) { - } - CachedItem(MsgId msgid, const QDate &date, int32 y) : msgid(msgid), date(date), y(y), link(0) { - } - MsgId msgid; - QDate date; - int32 y; - CachedLink *link; - }; - typedef QVector CachedItems; - CachedItems _cachedItems; - - int32 _width, _height, _minHeight, _addToY; + int32 _width, _height, _minHeight, _marginTop, _marginBottom; QTimer _linkTipTimer; @@ -252,14 +213,9 @@ private: int32 _dragItemIndex; MsgId _mousedItem; int32 _mousedItemIndex; - int32 _lnkOverIndex, _lnkDownIndex; // for OverviewLinks, 0 - none, -1 - photo or title, > 0 - lnk index uint16 _dragSymbol; bool _dragWasInactive; - QString urlByIndex(MsgId msgid, int32 index, int32 lnkIndex, bool *fullShown = 0) const; - bool urlIsEmail(const QString &url) const; - - QString _contextMenuUrl; TextLinkPtr _contextMenuLnk; MsgId _dragSelFrom, _dragSelTo;