From baf1e31b76136ab96a0e15a45776403547650d58 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 18 Mar 2016 13:18:30 +0300 Subject: [PATCH] circled profile images --- Telegram/SourceFiles/boxes/contactsbox.cpp | 10 +-- Telegram/SourceFiles/boxes/photosendbox.cpp | 12 +-- Telegram/SourceFiles/dialogswidget.cpp | 19 ++-- Telegram/SourceFiles/dropdown.cpp | 10 +-- Telegram/SourceFiles/facades.cpp | 4 + Telegram/SourceFiles/facades.h | 3 + Telegram/SourceFiles/gui/images.cpp | 96 +++++++++++++++++---- Telegram/SourceFiles/gui/images.h | 13 ++- Telegram/SourceFiles/history.cpp | 29 +++---- Telegram/SourceFiles/historywidget.cpp | 2 +- Telegram/SourceFiles/layout.cpp | 18 ++-- Telegram/SourceFiles/localstorage.cpp | 6 +- Telegram/SourceFiles/mainwidget.cpp | 2 +- Telegram/SourceFiles/mediaview.cpp | 10 +-- Telegram/SourceFiles/profilewidget.cpp | 6 +- Telegram/SourceFiles/pspecific_wnd.cpp | 12 +-- Telegram/SourceFiles/settingswidget.cpp | 6 +- Telegram/SourceFiles/structs.cpp | 54 +++++++++--- Telegram/SourceFiles/structs.h | 23 +++-- Telegram/SourceFiles/window.cpp | 9 +- 20 files changed, 224 insertions(+), 120 deletions(-) diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index 833054800..72d9397c2 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -362,7 +362,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) { preloadFrom != _contacts->list.end && (_newItemHeight + preloadFrom->pos * _rowHeight) < yTo; preloadFrom = preloadFrom->next ) { - preloadFrom->history->peer->photo->load(); + preloadFrom->history->peer->loadUserpic(); } } } else if (!_filtered.isEmpty()) { @@ -373,7 +373,7 @@ void ContactsInner::loadProfilePhotos(int32 yFrom) { if (to > _filtered.size()) to = _filtered.size(); for (; from < to; ++from) { - _filtered[from]->history->peer->photo->load(); + _filtered[from]->history->peer->loadUserpic(); } } } @@ -445,7 +445,7 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b } p.fillRect(0, 0, width(), _rowHeight, inverse ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white)); p.setPen(inverse ? st::white : st::black); - p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize)); + peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width()); int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(); int32 iconw = (_chat || _creating != CreatingGroupNone) ? (st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth()) : 0; @@ -1909,7 +1909,7 @@ void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, boo UserData *user = peer->asUser(); p.fillRect(0, 0, width(), _rowHeight, (sel ? st::contactsBgOver : st::white)->b); - p.drawPixmapLeft(st::contactsPadding.left(), st::contactsPadding.top(), width(), peer->photo->pix(st::contactsPhotoSize)); + peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width()); p.setPen(st::black); @@ -1994,7 +1994,7 @@ void MembersInner::loadProfilePhotos(int32 yFrom) { if (to > _rows.size()) to = _rows.size(); for (; from < to; ++from) { - _rows[from]->photo->load(); + _rows[from]->loadUserpic(); } } } diff --git a/Telegram/SourceFiles/boxes/photosendbox.cpp b/Telegram/SourceFiles/boxes/photosendbox.cpp index 487e2d537..cfe7664f3 100644 --- a/Telegram/SourceFiles/boxes/photosendbox.cpp +++ b/Telegram/SourceFiles/boxes/photosendbox.cpp @@ -82,7 +82,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW maxH = limitH; } } - _thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), true, true, false, maxW, maxH); + _thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH); } else { for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) { if (i->width() >= maxW && i->height() >= maxH) { @@ -124,7 +124,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW } else { _thumbw = st::msgFileThumbSize; } - _thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, true, false, true, st::msgFileThumbSize, st::msgFileThumbSize); + _thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRounded, st::msgFileThumbSize, st::msgFileThumbSize); } _name.setText(st::semiboldFont, _file->filename, _textNameOptions); @@ -274,7 +274,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) { p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile); } else { - p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixRounded(st::msgFileSize)); + p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixCircled(st::msgFileSize)); } p.setFont(st::semiboldFont); p.setPen(st::black); @@ -428,7 +428,7 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) } else { _thumbw = st::msgFileThumbSize; } - _thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, true, false, true, st::msgFileThumbSize, st::msgFileThumbSize); + _thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRounded, st::msgFileThumbSize, st::msgFileThumbSize); } if (doc) { @@ -459,11 +459,11 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth) maxH = limitH; } } - _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), true, true, false, maxW, maxH); + _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH); } else { maxW = dimensions.width(); maxH = dimensions.height(); - _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), true, false, false, maxW, maxH); + _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixRounded, maxW, maxH); } int32 tw = _thumb.width(), th = _thumb.height(); if (!tw || !th) { diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index a90b299a7..0b7aa9d19 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -247,11 +247,8 @@ void DialogsInner::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool a History *history = App::history(peer->id); - if (peer->migrateTo()) { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->migrateTo()->photo->pix(st::dlgPhotoSize)); - } else { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->photo->pix(st::dlgPhotoSize)); - } + PeerData *userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer); + userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth()); int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; int32 namewidth = w - nameleft - st::dlgPaddingHor; @@ -299,7 +296,7 @@ void DialogsInner::searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) c p.fillRect(fullRect, st::dlgBG->b); if (onlyBackground) return; - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, _searchInPeer->photo->pix(st::dlgPhotoSize)); + _searchInPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, fullWidth()); int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; int32 namewidth = w - nameleft - st::dlgPaddingHor * 2 - st::btnCancelSearch.width; @@ -1373,7 +1370,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { if (yFrom < otherStart) { dialogs.list.adjustCurrent(yFrom, st::dlgHeight); for (DialogRow *row = dialogs.list.current; row != dialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { - row->history->peer->photo->load(); + row->history->peer->loadUserpic(); } yFrom = 0; } else { @@ -1383,7 +1380,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { if (yTo > 0) { contactsNoDialogs.list.adjustCurrent(yFrom, st::dlgHeight); for (DialogRow *row = contactsNoDialogs.list.current; row != contactsNoDialogs.list.end && (row->pos * st::dlgHeight) < yTo; row = row->next) { - row->history->peer->photo->load(); + row->history->peer->loadUserpic(); } } } else if (_state == FilteredState || _state == SearchedState) { @@ -1394,7 +1391,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { if (to > _filterResults.size()) to = _filterResults.size(); for (; from < to; ++from) { - _filterResults[from]->history->peer->photo->load(); + _filterResults[from]->history->peer->loadUserpic(); } } @@ -1405,7 +1402,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { if (to > _peopleResults.size()) to = _peopleResults.size(); for (; from < to; ++from) { - _peopleResults[from]->photo->load(); + _peopleResults[from]->loadUserpic(); } } from = (yFrom > filteredOffset() + ((_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peopleResults.isEmpty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dlgHeight)) : 0) - _filterResults.size() - _peopleResults.size(); @@ -1415,7 +1412,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) { if (to > _searchResults.size()) to = _searchResults.size(); for (; from < to; ++from) { - _searchResults[from]->_item->history()->peer->photo->load(); + _searchResults[from]->_item->history()->peer->loadUserpic(); } } } diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 5a4823d1c..02b8e4f5e 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -3944,8 +3944,8 @@ void MentionsInner::paintEvent(QPaintEvent *e) { second = st::mentionFont->elided(second, unamewidth - firstwidth); } } - user->photo->load(); - p.drawPixmap(st::mentionPadding.left(), i * st::mentionHeight + st::mentionPadding.top(), user->photo->pixRounded(st::mentionPhotoSize)); + user->loadUserpic(); + user->paintUserpicLeft(p, st::mentionPhotoSize, st::mentionPadding.left(), i * st::mentionHeight + st::mentionPadding.top(), width()); user->nameText.drawElided(p, 2 * st::mentionPadding.left() + st::mentionPhotoSize, i * st::mentionHeight + st::mentionTop, namewidth); p.setFont(st::mentionFont->f); @@ -3986,10 +3986,8 @@ void MentionsInner::paintEvent(QPaintEvent *e) { if (hasUsername || botStatus == 0 || botStatus == 2) { toHighlight += '@' + user->username; } - if (true || _parent->chat() || botStatus == 0 || botStatus == 2) { - user->photo->load(); - p.drawPixmap(st::mentionPadding.left(), i * st::mentionHeight + st::mentionPadding.top(), user->photo->pixRounded(st::mentionPhotoSize)); - } + user->loadUserpic(); + user->paintUserpicLeft(p, st::mentionPhotoSize, st::mentionPadding.left(), i * st::mentionHeight + st::mentionPadding.top(), width()); int32 addleft = 0, widthleft = mentionwidth; QString first = (_parent->filter().size() < 2) ? QString() : ('/' + toHighlight.mid(0, _parent->filter().size() - 1)), second = (_parent->filter().size() < 2) ? ('/' + toHighlight) : toHighlight.mid(_parent->filter().size() - 1); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 63b8df37c..e26e44f52 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -375,6 +375,8 @@ struct GlobalDataStruct { int32 EditTimeLimit = 172800; Global::HiddenPinnedMessagesMap HiddenPinnedMessages; + + Global::CircleMasksMap CircleMasks; }; GlobalDataStruct *GlobalData = 0; @@ -421,4 +423,6 @@ namespace Global { DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages); + DefineRefVar(Global, CircleMasksMap, CircleMasks); + }; diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 26bcf391d..d0f2737d2 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -170,6 +170,9 @@ namespace Global { typedef QMap HiddenPinnedMessagesMap; DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); + typedef QMap CircleMasksMap; + DeclareRefVar(CircleMasksMap, CircleMasks); + }; namespace Adaptive { diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp index eda121103..9da1f933a 100644 --- a/Telegram/SourceFiles/gui/images.cpp +++ b/Telegram/SourceFiles/gui/images.cpp @@ -47,6 +47,7 @@ namespace { static const uint64 ColoredCacheSkip = 0x2000000000000000LLU; static const uint64 BlurredColoredCacheSkip = 0x3000000000000000LLU; static const uint64 RoundedCacheSkip = 0x4000000000000000LLU; + static const uint64 CircledCacheSkip = 0x5000000000000000LLU; } StorageImageLocation StorageImageLocation::Null; @@ -106,7 +107,7 @@ const QPixmap &Image::pix(int32 w, int32 h) const { uint64 k = (uint64(w) << 32) | uint64(h); Sizes::const_iterator i = _sizesCache.constFind(k); if (i == _sizesCache.cend()) { - QPixmap p(pixNoCache(w, h, true)); + QPixmap p(pixNoCache(w, h, ImagePixSmooth)); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); i = _sizesCache.insert(k, p); if (!p.isNull()) { @@ -128,7 +129,29 @@ const QPixmap &Image::pixRounded(int32 w, int32 h) const { uint64 k = RoundedCacheSkip | (uint64(w) << 32) | uint64(h); Sizes::const_iterator i = _sizesCache.constFind(k); if (i == _sizesCache.cend()) { - QPixmap p(pixNoCache(w, h, true, false, true)); + QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixRounded)); + if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); + i = _sizesCache.insert(k, p); + if (!p.isNull()) { + globalAcquiredSize += int64(p.width()) * p.height() * 4; + } + } + return i.value(); +} + +const QPixmap &Image::pixCircled(int32 w, int32 h) const { + checkload(); + + if (w <= 0 || !width() || !height()) { + w = width(); + } else if (cRetina()) { + w *= cIntRetinaFactor(); + h *= cIntRetinaFactor(); + } + uint64 k = CircledCacheSkip | (uint64(w) << 32) | uint64(h); + Sizes::const_iterator i = _sizesCache.constFind(k); + if (i == _sizesCache.cend()) { + QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixCircled)); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); i = _sizesCache.insert(k, p); if (!p.isNull()) { @@ -150,7 +173,7 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const { uint64 k = BlurredCacheSkip | (uint64(w) << 32) | uint64(h); Sizes::const_iterator i = _sizesCache.constFind(k); if (i == _sizesCache.cend()) { - QPixmap p(pixNoCache(w, h, true, true)); + QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred)); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); i = _sizesCache.insert(k, p); if (!p.isNull()) { @@ -219,7 +242,7 @@ const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) co if (i != _sizesCache.cend()) { globalAcquiredSize -= int64(i->width()) * i->height() * 4; } - QPixmap p(pixNoCache(w, h, true, false, true, outerw, outerh)); + QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixRounded, outerw, outerh)); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); i = _sizesCache.insert(k, p); if (!p.isNull()) { @@ -229,7 +252,7 @@ const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) co return i.value(); } -const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh) const { +const QPixmap &Image::pixBlurredSingle(int w, int h, int32 outerw, int32 outerh) const { checkload(); if (w <= 0 || !width() || !height()) { @@ -244,7 +267,7 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 out if (i != _sizesCache.cend()) { globalAcquiredSize -= int64(i->width()) * i->height() * 4; } - QPixmap p(pixNoCache(w, h, true, true, true, outerw, outerh)); + QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred | ImagePixRounded, outerw, outerh)); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); i = _sizesCache.insert(k, p); if (!p.isNull()) { @@ -375,6 +398,42 @@ yi += stride; return img; } +const QPixmap &circleMask(int width, int height) { + t_assert(Global::started()); + + uint64 key = uint64(uint32(width)) << 32 | uint64(uint32(height)); + + Global::CircleMasksMap &masks(Global::RefCircleMasks()); + auto i = masks.constFind(key); + if (i == masks.cend()) { + QImage mask(width, height, QImage::Format_ARGB32_Premultiplied); + mask.fill(st::transparent); + { + Painter p(&mask); + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + p.setBrush(st::white); + p.setPen(Qt::NoPen); + p.drawEllipse(0, 0, width, height); + } + i = masks.insert(key, QPixmap::fromImage(mask)); + } + return i.value(); +} + +void imageCircle(QImage &img) { + t_assert(!img.isNull()); + + img.setDevicePixelRatio(cRetinaFactor()); + img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); + t_assert(!img.isNull()); + + QPixmap mask = circleMask(img.width(), img.height()); + Painter p(&img); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.drawPixmap(0, 0, mask); +} + void imageRound(QImage &img) { t_assert(!img.isNull()); @@ -435,18 +494,18 @@ QImage imageColored(const style::color &add, QImage img) { return img; } -QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh) { +QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 outerw, int32 outerh) { t_assert(!img.isNull()); - if (blurred) { + if (options.testFlag(ImagePixBlurred)) { img = imageBlur(img); t_assert(!img.isNull()); } if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) { } else if (h <= 0) { - img = img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation); + img = img.scaledToWidth(w, options.testFlag(ImagePixSmooth) ? Qt::SmoothTransformation : Qt::FastTransformation); t_assert(!img.isNull()); } else { - img = img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation); + img = img.scaled(w, h, Qt::IgnoreAspectRatio, options.testFlag(ImagePixSmooth) ? Qt::SmoothTransformation : Qt::FastTransformation); t_assert(!img.isNull()); } if (outerw > 0 && outerh > 0) { @@ -467,7 +526,10 @@ QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool r t_assert(!img.isNull()); } } - if (rounded) { + if (options.testFlag(ImagePixCircled)) { + imageCircle(img); + t_assert(!img.isNull()); + } else if (options.testFlag(ImagePixRounded)) { imageRound(img); t_assert(!img.isNull()); } @@ -475,7 +537,7 @@ QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool r return QPixmap::fromImage(img, Qt::ColorOnly); } -QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh) const { +QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int outerh) const { if (!loading()) const_cast(this)->load(); restore(); @@ -483,7 +545,7 @@ QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool roun if (h <= 0 && height() > 0) { h = qRound(width() * w / float64(height())); } - return blank()->pixNoCache(w, h, smooth, blurred, rounded, outerw, outerh); + return blank()->pixNoCache(w, h, options, outerw, outerh); } if (isNull() && outerw > 0 && outerh > 0) { @@ -506,11 +568,15 @@ QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool roun p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::white); } - if (rounded) imageRound(result); + if (options.testFlag(ImagePixCircled)) { + imageCircle(result); + } else if (options.testFlag(ImagePixRounded)) { + imageRound(result); + } return QPixmap::fromImage(result, Qt::ColorOnly); } - return imagePix(_data.toImage(), w, h, smooth, blurred, rounded, outerw, outerh); + return imagePix(_data.toImage(), w, h, options, outerw, outerh); } QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const { diff --git a/Telegram/SourceFiles/gui/images.h b/Telegram/SourceFiles/gui/images.h index 63c771379..0622dca27 100644 --- a/Telegram/SourceFiles/gui/images.h +++ b/Telegram/SourceFiles/gui/images.h @@ -107,7 +107,15 @@ inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation return !(a == b); } -QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh); +enum ImagePixOption { + ImagePixSmooth = 0x01, + ImagePixBlurred = 0x02, + ImagePixRounded = 0x04, + ImagePixCircled = 0x08, +}; +Q_DECLARE_FLAGS(ImagePixOptions, ImagePixOption); +Q_DECLARE_OPERATORS_FOR_FLAGS(ImagePixOptions); +QPixmap imagePix(QImage img, int w, int h, ImagePixOptions options, int outerw, int outerh); class DelayedStorageImage; @@ -145,12 +153,13 @@ public: const QPixmap &pix(int32 w = 0, int32 h = 0) const; const QPixmap &pixRounded(int32 w = 0, int32 h = 0) const; + const QPixmap &pixCircled(int32 w = 0, int32 h = 0) const; const QPixmap &pixBlurred(int32 w = 0, int32 h = 0) const; const QPixmap &pixColored(const style::color &add, int32 w = 0, int32 h = 0) const; const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const; const QPixmap &pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) const; const QPixmap &pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh) const; - QPixmap pixNoCache(int32 w = 0, int32 h = 0, bool smooth = false, bool blurred = false, bool rounded = false, int32 outerw = -1, int32 outerh = -1) const; + QPixmap pixNoCache(int w = 0, int h = 0, ImagePixOptions options = 0, int outerw = -1, int outerh = -1) const; QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const; QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 846ae6e76..5eb4d1c4e 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -98,11 +98,8 @@ void DialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBackgrou p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b); if (onlyBackground) return; - if (history->peer->migrateTo()) { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->migrateTo()->photo->pix(st::dlgPhotoSize)); - } else { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->photo->pix(st::dlgPhotoSize)); - } + PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer); + userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w); int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; int32 namewidth = w - nameleft - st::dlgPaddingHor; @@ -205,11 +202,8 @@ void FakeDialogRow::paint(Painter &p, int32 w, bool act, bool sel, bool onlyBack if (onlyBackground) return; History *history = _item->history(); - if (history->peer->migrateTo()) { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->migrateTo()->photo->pix(st::dlgPhotoSize)); - } else { - p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->photo->pix(st::dlgPhotoSize)); - } + PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer); + userpicPeer->paintUserpicLeft(p, st::dlgPhotoSize, st::dlgPaddingHor, st::dlgPaddingVer, w); int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding; int32 namewidth = w - nameleft - st::dlgPaddingHor; @@ -1506,7 +1500,7 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo } else if (peer->isChannel()) { peer->asChannel()->setPhoto(MTP_chatPhoto(*smallLoc, *bigLoc), photo ? photo->id : 0); } - peer->photo->load(); + peer->loadUserpic(); } } } @@ -5054,7 +5048,7 @@ void HistoryContact::initDimensions(const HistoryItem *parent) { _contact = _userId ? App::userLoaded(_userId) : 0; if (_contact) { - _contact->photo->load(); + _contact->loadUserpic(); } if (_contact && _contact->contact > 0) { _linkl.reset(new SendMessageLink(_contact)); @@ -5106,11 +5100,10 @@ void HistoryContact::draw(Painter &p, const HistoryItem *parent, const QRect &r, linktop = st::msgFileThumbLinkTop; QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width)); - if (_contact && _contact->photo->loaded()) { - QPixmap thumb = _contact->photo->pixRounded(st::msgFileThumbSize, st::msgFileThumbSize); - p.drawPixmap(rthumb.topLeft(), thumb); + if (_contact) { + _contact->paintUserpic(p, st::msgFileThumbSize, rthumb.x(), rthumb.y()); } else { - p.drawPixmap(rthumb.topLeft(), userDefPhoto(_contact ? _contact->colorIndex : (qAbs(_userId) % UserColorsCount))->pixRounded(st::msgFileThumbSize, st::msgFileThumbSize)); + p.drawPixmap(rthumb.topLeft(), userDefPhoto(qAbs(_userId) % UserColorsCount)->pixCircled(st::msgFileThumbSize, st::msgFileThumbSize)); } if (selected) { App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); @@ -5127,7 +5120,7 @@ void HistoryContact::draw(Painter &p, const HistoryItem *parent, const QRect &r, statustop = st::msgFileStatusTop; QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width)); - p.drawPixmap(inner.topLeft(), userDefPhoto(qAbs(parent->id) % UserColorsCount)->pixRounded(st::msgFileSize, st::msgFileSize)); + p.drawPixmap(inner.topLeft(), userDefPhoto(qAbs(parent->id) % UserColorsCount)->pixCircled(st::msgFileSize, st::msgFileSize)); } int32 namewidth = width - nameleft - nameright; @@ -6705,7 +6698,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m if (displayFromPhoto()) { int32 photoleft = left + ((outbg && !Adaptive::Wide()) ? (width + (st::msgPhotoSkip - st::msgPhotoSize)) : (-st::msgPhotoSkip)); - p.drawPixmap(photoleft, _height - st::msgMargin.bottom() - st::msgPhotoSize, author()->photo->pixRounded(st::msgPhotoSize)); + author()->paintUserpic(p, st::msgPhotoSize, photoleft, _height - st::msgMargin.bottom() - st::msgPhotoSize); } if (width < 1) return; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 0b8b34fb8..ecbdfcb6a 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -6744,7 +6744,7 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) { th = 90; } thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(tw), MTP_int(th), MTP_int(0)); - thumb = result->thumb->pixNoCache(tw, th, true, false, false); + thumb = result->thumb->pixNoCache(tw, th, ImagePixSmooth); } else { tw = th = 0; thumbSize = MTP_photoSizeEmpty(MTP_string("")); diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index b7bfc4ab0..ab7c34696 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -866,7 +866,9 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti if (_data->thumb->loaded()) { if (_thumb.isNull() || loaded != _thumbForLoaded) { _thumbForLoaded = loaded; - _thumb = _data->thumb->pixNoCache(_thumbw, 0, true, !_thumbForLoaded, false, st::overviewFileSize, st::overviewFileSize); + ImagePixOptions options = ImagePixSmooth; + if (!_thumbForLoaded) options |= ImagePixBlurred; + _thumb = _data->thumb->pixNoCache(_thumbw, 0, options, st::overviewFileSize, st::overviewFileSize); } p.drawPixmap(rthumb.topLeft(), _thumb); } else { @@ -1574,7 +1576,7 @@ void LayoutInlineGif::prepareThumb(int32 width, int32 height, const QSize &frame if (doc && !doc->thumb->isNull()) { if (doc->thumb->loaded()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { - _thumb = doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + _thumb = doc->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); } } else { doc->thumb->load(); @@ -1582,7 +1584,7 @@ void LayoutInlineGif::prepareThumb(int32 width, int32 height, const QSize &frame } else if (_result && !_result->thumb_url.isEmpty()) { if (_result->thumb->loaded()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { - _thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + _thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); } } else { _result->thumb->load(); @@ -1792,13 +1794,13 @@ void LayoutInlinePhoto::prepareThumb(int32 width, int32 height, const QSize &fra if (photo) { if (photo->medium->loaded()) { if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { - _thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + _thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); } _thumbLoaded = true; } else { if (photo->thumb->loaded()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { - _thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + _thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); } } photo->medium->load(); @@ -1806,7 +1808,7 @@ void LayoutInlinePhoto::prepareThumb(int32 width, int32 height, const QSize &fra } else { if (_result->thumb->loaded()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { - _thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), true, false, false, width, height); + _thumb = _result->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); } } else { _result->thumb->load(); @@ -1933,7 +1935,7 @@ void LayoutInlineWebVideo::prepareThumb(int32 width, int32 height) const { w = width; } } - _thumb = _result->thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), true, false, false, width, height); + _thumb = _result->thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); } } else { _result->thumb->load(); @@ -2081,7 +2083,7 @@ void LayoutInlineArticle::prepareThumb(int32 width, int32 height) const { w = width; } } - _thumb = _result->thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), true, false, false, width, height); + _thumb = _result->thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); } } else { _result->thumb->load(); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 118ba1c92..4eba35bfe 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3616,7 +3616,7 @@ namespace Local { user->inputUser = MTP_inputUser(MTP_int(peerToUser(user->id)), MTP_long((user->access == UserNoAccess) ? 0 : user->access)); } - user->photo = photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc); + user->setUserpic(photoLoc.isNull() ? ImagePtr(userDefPhoto(user->colorIndex)) : ImagePtr(photoLoc)); } } else if (result->isChat()) { ChatData *chat = result->asChat(); @@ -3644,7 +3644,7 @@ namespace Local { chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id))); chat->inputChat = MTP_int(peerToChat(chat->id)); - chat->photo = photoLoc.isNull() ? ImagePtr(chatDefPhoto(chat->colorIndex)) : ImagePtr(photoLoc); + chat->setUserpic(photoLoc.isNull() ? ImagePtr(chatDefPhoto(chat->colorIndex)) : ImagePtr(photoLoc)); } } else if (result->isChannel()) { ChannelData *channel = result->asChannel(); @@ -3666,7 +3666,7 @@ namespace Local { channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); - channel->photo = photoLoc.isNull() ? ImagePtr((channel->isMegagroup() ? chatDefPhoto(channel->colorIndex) : channelDefPhoto(channel->colorIndex))) : ImagePtr(photoLoc); + channel->setUserpic(photoLoc.isNull() ? ImagePtr((channel->isMegagroup() ? chatDefPhoto(channel->colorIndex) : channelDefPhoto(channel->colorIndex))) : ImagePtr(photoLoc)); } } if (!wasLoaded) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index fb337c85b..5c02a99e4 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4414,7 +4414,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { UserData *user = App::userLoaded(d.vuser_id.v); if (user) { user->setPhoto(d.vphoto); - user->photo->load(); + user->loadUserpic(); if (mtpIsTrue(d.vprevious)) { user->photosCount = -1; user->photos.clear(); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index fc1734194..853603304 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -967,7 +967,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty if (!_doc->data().isEmpty() && _doc->isAnimation()) { if (!_gif) { if (_doc->dimensions.width() && _doc->dimensions.height()) { - _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), true, true, false, _doc->dimensions.width(), _doc->dimensions.height()); + _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); } _gif = new ClipReader(location, _doc->data(), func(this, &MediaView::clipCallback)); } @@ -975,7 +975,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty if (_doc->isAnimation()) { if (!_gif) { if (_doc->dimensions.width() && _doc->dimensions.height()) { - _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), true, true, false, _doc->dimensions.width(), _doc->dimensions.height()); + _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); } _gif = new ClipReader(location, _doc->data(), func(this, &MediaView::clipCallback)); } @@ -1116,17 +1116,17 @@ void MediaView::paintEvent(QPaintEvent *e) { int32 w = _width * cIntRetinaFactor(); if (_full <= 0 && _photo->loaded()) { int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); - _current = _photo->full->pixNoCache(w, h, true); + _current = _photo->full->pixNoCache(w, h, ImagePixSmooth); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); _full = 1; } else if (_full < 0 && _photo->medium->loaded()) { int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); - _current = _photo->medium->pixNoCache(w, h, true, true); + _current = _photo->medium->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); _full = 0; } else if (_current.isNull() && _photo->thumb->loaded()) { int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); - _current = _photo->thumb->pixNoCache(w, h, true, true); + _current = _photo->thumb->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); } else if (_current.isNull()) { _current = _photo->thumb->pix(); diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index c28c5fba1..95dc8911b 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -282,7 +282,7 @@ void ProfileInner::loadProfilePhotos(int32 yFrom) { if (yFrom >= _participants.size()) return; if (yTo > _participants.size()) yTo = _participants.size(); for (int32 i = yFrom; i < yTo; ++i) { - _participants[i]->photo->load(); + _participants[i]->loadUserpic(); } } @@ -832,7 +832,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) { // profile top += st::profilePadding.top(); if (_photoLink || _peerUser || (_peerChat && !_peerChat->canEdit()) || (_peerChannel && !_amCreator)) { - p.drawPixmap(_left, top, _peer->photo->pix(st::profilePhotoSize)); + _peer->paintUserpic(p, st::profilePhotoSize, _left, top); } else { if (a_photoOver.current() < 1) { p.drawPixmap(QPoint(_left, top), App::sprite(), st::setPhotoImg); @@ -1019,7 +1019,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) { } UserData *user = *i; - p.drawPixmap(_left, top + st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize)); + user->paintUserpic(p, st::profileListPhotoSize, _left, top + st::profileListPadding.height()); ParticipantData *data = _participantsData[cnt]; if (!data) { data = _participantsData[cnt] = new ParticipantData(); diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index 898ac1cee..82304ce54 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -3247,10 +3247,8 @@ QString toastImage(const StorageKey &key, PeerData *peer) { v.until = 0; } v.path = cWorkingDir() + qsl("tdata/temp/") + QString::number(MTP::nonce(), 16) + qsl(".png"); - if (peer->photo->loaded() && (key.first || key.second)) { - peer->photo->pix().save(v.path, "PNG"); - } else if (!key.first && key.second) { - (peer->isUser() ? userDefPhoto : chatDefPhoto)(peer->colorIndex)->pix().save(v.path, "PNG"); + if (key.first || key.second) { + peer->saveUserpic(v.path); } else { App::wnd()->iconLarge().save(v.path, "PNG"); } @@ -3275,11 +3273,7 @@ bool CreateToast(PeerData *peer, int32 msgId, bool showpix, const QString &title StorageKey key; QString imagePath; if (showpix) { - if (peer->photoLoc.isNull() || !peer->photo->loaded()) { - key = StorageKey(0, (peer->isUser() ? 0x1000 : 0x2000) | peer->colorIndex); - } else { - key = storageKey(peer->photoLoc); - } + key = peer->userpicUniqueKey(); } else { key = StorageKey(0, 0); } diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index a21faec32..330d39d24 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -208,7 +208,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent) , _logOut(this, lang(lng_settings_logout), st::btnLogout) , _supportGetRequest(0) { if (self()) { - self()->photo->load(); + self()->loadUserpic(); connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); @@ -382,7 +382,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) { updateChatBackground(); } - QPainter p(this); + Painter p(this); p.setClipRect(e->rect()); @@ -399,7 +399,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) { } if (_photoLink) { - p.drawPixmap(_left, top, self()->photo->pix(st::setPhotoSize)); + self()->paintUserpicLeft(p, st::setPhotoSize, _left, top, st::setWidth); } else { if (a_photoOver.current() < 1) { p.drawPixmap(QPoint(_left, top), App::sprite(), st::setPhotoImg); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index ce45404dd..ed5ef5585 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -103,10 +103,10 @@ PeerData::PeerData(const PeerId &id) : id(id) , loaded(false) , colorIndex(peerColorIndex(id)) , color(peerColor(colorIndex)) -, photo((isChat() || isMegagroup()) ? chatDefPhoto(colorIndex) : (isChannel() ? channelDefPhoto(colorIndex) : userDefPhoto(colorIndex))) , photoId(UnknownPeerPhotoId) , nameVersion(0) -, notify(UnknownNotifySettings) { +, notify(UnknownNotifySettings) +, _userpic(isUser() ? userDefPhoto(colorIndex) : ((isChat() || isMegagroup()) ? chatDefPhoto(colorIndex) : channelDefPhoto(colorIndex))) { if (!peerIsUser(id) && !peerIsChannel(id)) updateName(QString(), QString(), QString()); } @@ -154,6 +154,36 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, } } +void PeerData::setUserpic(ImagePtr userpic) { + _userpic = userpic; +} + +ImagePtr PeerData::currentUserpic() const { + if (_userpic->loaded()) { + return _userpic; + } else if (isUser()) { + return userDefPhoto(colorIndex); + } else if (isMegagroup() || isChat()) { + return chatDefPhoto(colorIndex); + } + return channelDefPhoto(colorIndex); +} + +void PeerData::paintUserpic(Painter &p, int size, int x, int y) const { + p.drawPixmap(x, y, currentUserpic()->pixCircled(size, size)); +} + +StorageKey PeerData::userpicUniqueKey() const { + if (photoLoc.isNull() || !_userpic->loaded()) { + return StorageKey(0, (isUser() ? 0x1000 : ((isChat() || isMegagroup()) ? 0x2000 : 0x3000)) | colorIndex); + } + return storageKey(photoLoc); +} + +void PeerData::saveUserpic(const QString &path) const { + currentUserpic()->pixCircled().save(path, "PNG"); +} + const Text &BotCommand::descriptionText() const { if (_descriptionText.isEmpty() && !_description.isEmpty()) { _descriptionText.setText(st::mentionFont, _description, _textNameOptions); @@ -163,7 +193,7 @@ const Text &BotCommand::descriptionText() const { void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer as well PhotoId newPhotoId = photoId; - ImagePtr newPhoto = photo; + ImagePtr newPhoto = _userpic; StorageImageLocation newPhotoLoc = photoLoc; switch (p.type()) { case mtpc_userProfilePhoto: { @@ -176,7 +206,7 @@ void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer a default: { newPhotoId = 0; if (id == ServiceUserId) { - if (photo->isNull()) { + if (_userpic->isNull()) { newPhoto = ImagePtr(QPixmap::fromImage(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation), Qt::ColorOnly), "PNG"); } } else { @@ -185,9 +215,9 @@ void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer a newPhotoLoc = StorageImageLocation(); } break; } - if (newPhotoId != photoId || newPhoto.v() != photo.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { photoId = newPhotoId; - photo = newPhoto; + setUserpic(newPhoto); photoLoc = newPhotoLoc; if (App::main()) { emit App::main()->peerPhotoChanged(this); @@ -338,7 +368,7 @@ void UserData::madeAction() { void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Local::readPeer as well PhotoId newPhotoId = photoId; - ImagePtr newPhoto = photo; + ImagePtr newPhoto = _userpic; StorageImageLocation newPhotoLoc = photoLoc; switch (p.type()) { case mtpc_chatPhoto: { @@ -357,9 +387,9 @@ void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Loc // photoFull = ImagePtr(); } break; } - if (newPhotoId != photoId || newPhoto.v() != photo.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { photoId = newPhotoId; - photo = newPhoto; + setUserpic(newPhoto); photoLoc = newPhotoLoc; emit App::main()->peerPhotoChanged(this); } @@ -367,7 +397,7 @@ void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Loc void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Local::readPeer as well PhotoId newPhotoId = photoId; - ImagePtr newPhoto = photo; + ImagePtr newPhoto = _userpic; StorageImageLocation newPhotoLoc = photoLoc; switch (p.type()) { case mtpc_chatPhoto: { @@ -386,9 +416,9 @@ void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see // photoFull = ImagePtr(); } break; } - if (newPhotoId != photoId || newPhoto.v() != photo.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { photoId = newPhotoId; - photo = newPhoto; + setUserpic(newPhoto); photoLoc = newPhotoLoc; if (App::main()) emit App::main()->peerPhotoChanged(this); } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 23616afcd..d8630ccc0 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -272,7 +272,18 @@ public: int32 colorIndex; style::color color; - ImagePtr photo; + + void setUserpic(ImagePtr userpic); + void paintUserpic(Painter &p, int size, int x, int y) const; + void paintUserpicLeft(Painter &p, int size, int x, int y, int w) const { + paintUserpic(p, size, rtl() ? (w - x - size) : x, y); + } + void loadUserpic(bool loadFirst = false, bool prior = true) { + _userpic->load(loadFirst, prior); + } + StorageKey userpicUniqueKey() const; + void saveUserpic(const QString &path) const; + PhotoId photoId; StorageImageLocation photoLoc; @@ -280,12 +291,14 @@ public: NotifySettingsPtr notify; -private: + PeerData(const PeerData &other) = delete; + PeerData &operator=(const PeerData &other) = delete; + +protected: PeerData(const PeerId &id); - friend class UserData; - friend class ChatData; - friend class ChannelData; + ImagePtr _userpic; + ImagePtr currentUserpic() const; }; static const uint64 UserNoAccess = 0xFFFFFFFFFFFFFFFFULL; diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index aad3a11f0..ab36c4734 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -172,13 +172,8 @@ void NotifyWindow::updateNotifyDisplay() { p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b); if (!App::passcoded() && cNotifyView() <= dbinvShowName) { - if (history->peer->photo->loaded()) { - p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), history->peer->photo->pix(st::notifyPhotoSize)); - } else { - MTP::clearLoaderPriorities(); - peerPhoto = history->peer->photo; - peerPhoto->load(true, true); - } + history->peer->loadUserpic(true, true); + history->peer->paintUserpicLeft(p, st::notifyPhotoSize, st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), width()); } else { static QPixmap icon = QPixmap::fromImage(App::wnd()->iconLarge().scaled(st::notifyPhotoSize, st::notifyPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), icon);