diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 7cf1536c3..754713062 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -398,6 +398,18 @@ void SendFilesBox::Block::applyChanges() { } } +QImage SendFilesBox::Block::generatePriceTagBackground() const { + const auto preview = _preview.get(); + if (_isAlbum) { + const auto album = static_cast(preview); + return album->generatePriceTagBackground(); + } else if (_isSingleMedia) { + const auto media = static_cast(preview); + return media->generatePriceTagBackground(); + } + return QImage(); +} + SendFilesBox::SendFilesBox( QWidget*, not_null controller, @@ -737,18 +749,17 @@ void SendFilesBox::refreshPriceTag() { } if (!hasPrice()) { _priceTag = nullptr; + _priceTagBg = QImage(); } else if (!_priceTag) { _priceTag = std::make_unique(_inner.data()); const auto raw = _priceTag.get(); raw->show(); raw->paintRequest() | rpl::start_with_next([=] { - auto p = QPainter(raw); - auto hq = PainterHighQualityEnabler(p); - p.setBrush(st::toastBg); - p.setPen(Qt::NoPen); - const auto radius = std::min(raw->width(), raw->height()) / 2.; - p.drawRoundedRect(raw->rect(), radius, radius); + if (_priceTagBg.isNull()) { + _priceTagBg = preparePriceTagBg(raw->size()); + } + QPainter(raw).drawImage(0, 0, _priceTagBg); }, raw->lifetime()); const auto session = &_show->session(); @@ -785,9 +796,44 @@ void SendFilesBox::refreshPriceTag() { }, raw->lifetime()); } else { _priceTag->raise(); + _priceTag->update(); + _priceTagBg = QImage(); } } +QImage SendFilesBox::preparePriceTagBg(QSize size) const { + const auto ratio = style::DevicePixelRatio(); + const auto outer = _blocks.empty() + ? size + : _inner->widgetAt(0)->geometry().size(); + auto bg = _blocks.empty() + ? QImage() + : _blocks.front().generatePriceTagBackground(); + if (bg.isNull()) { + bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied); + bg.fill(Qt::black); + } + const auto bgSize = bg.size() / bg.devicePixelRatio(); + + auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); + result.fill(Qt::black); + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + p.drawImage( + QRect( + (size.width() - outer.width()) / 2, + (size.height() - outer.height()) / 2, + outer.width(), + outer.height()), + bg); + p.fillRect(QRect(QPoint(), size), st::msgDateImgBg); + p.end(); + + const auto radius = std::min(size.width(), size.height()) / 2; + return Images::Round(std::move(result), Images::CornersMask(radius)); +} + void SendFilesBox::addMenuButton() { const auto details = _sendMenuDetails(); if (!hasSendMenu(details)) { diff --git a/Telegram/SourceFiles/boxes/send_files_box.h b/Telegram/SourceFiles/boxes/send_files_box.h index f16dffb8f..7ba1a8070 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.h +++ b/Telegram/SourceFiles/boxes/send_files_box.h @@ -166,6 +166,8 @@ private: void toggleSpoilers(bool enabled); void applyChanges(); + [[nodiscard]] QImage generatePriceTagBackground() const; + private: base::unique_qptr _preview; not_null*> _items; @@ -196,6 +198,7 @@ private: [[nodiscard]] bool canChangePrice() const; [[nodiscard]] bool hasPrice() const; void refreshPriceTag(); + [[nodiscard]] QImage preparePriceTagBg(QSize size) const; bool validateLength(const QString &text) const; void refreshButtons(); @@ -259,6 +262,7 @@ private: Fn _cancelledCallback; rpl::variable _price = 0; std::unique_ptr _priceTag; + QImage _priceTagBg; bool _confirmed = false; bool _invertCaption = false; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 6d634073a..2485552d8 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -383,7 +383,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const { } } else if (preview) { drawPriceTag(p, rthumb, context, [&] { - return _spoiler ? _spoiler->background : QImage(); + return priceTagBackground(); }); } if (showEnlarge) { @@ -447,9 +447,10 @@ void Photo::drawPriceTag( || _priceTag->darken != darken || _priceTag->fg != fg || _priceTag->star != star) { + const auto ratio = style::DevicePixelRatio(); auto bg = generateBackground(); if (bg.isNull()) { - bg = QImage(2, 2, QImage::Format_ARGB32_Premultiplied); + bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied); bg.fill(Qt::black); } @@ -474,7 +475,6 @@ void Photo::drawPriceTag( const auto outer = inner.marginsAdded(st::paidTagPadding); const auto size = outer.size(); const auto radius = std::min(size.width(), size.height()) / 2; - const auto ratio = style::DevicePixelRatio(); auto cache = QImage( size * ratio, QImage::Format_ARGB32_Premultiplied); diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp index b142a61c1..b1a211e49 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp @@ -84,6 +84,10 @@ rpl::producer AbstractSingleMediaPreview::spoileredChanges() const { return _spoileredChanges.events(); } +QImage AbstractSingleMediaPreview::generatePriceTagBackground() const { + return (_previewBlurred.isNull() ? _preview : _previewBlurred).toImage(); +} + void AbstractSingleMediaPreview::preparePreview(QImage preview) { auto maxW = 0; auto maxH = 0; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.h index fd72facf1..ba9595f28 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.h @@ -44,6 +44,8 @@ public: [[nodiscard]] bool canHaveSpoiler() const; [[nodiscard]] rpl::producer spoileredChanges() const; + [[nodiscard]] QImage generatePriceTagBackground() const; + protected: virtual bool supportsSpoilers() const = 0; virtual bool drawBackground() const = 0; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp index 76ff1ab2b..94d3b6286 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.cpp @@ -20,6 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include +namespace Media::Streaming { + +[[nodiscard]] QImage PrepareBlurredBackground(QSize outer, QImage frame); + +} // namespace Media::Streaming + namespace Ui { namespace { @@ -610,8 +616,47 @@ void AlbumPreview::switchToDrag() { update(); } -rpl::producer AlbumPreview::thumbModified() const { - return _thumbModified.events(); +QImage AlbumPreview::generatePriceTagBackground() const { + auto wmax = 0; + auto hmax = 0; + for (auto &thumb : _thumbs) { + const auto geometry = thumb->geometry(); + accumulate_max(wmax, geometry.x() + geometry.width()); + accumulate_max(hmax, geometry.y() + geometry.height()); + } + const auto size = QSize(wmax, hmax); + if (size.isEmpty()) { + return {}; + } + const auto ratio = style::DevicePixelRatio(); + const auto full = size * ratio; + const auto skip = st::historyGroupSkip; + auto result = QImage(full, QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); + result.fill(Qt::black); + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + for (auto &thumb : _thumbs) { + const auto geometry = thumb->geometry(); + if (geometry.isEmpty()) { + continue; + } + const auto w = geometry.width(); + const auto h = geometry.height(); + const auto wscale = (w + skip) / float64(w); + const auto hscale = (h + skip) / float64(h); + p.save(); + p.translate(geometry.center()); + p.scale(wscale, hscale); + p.translate(-geometry.center()); + thumb->paintInAlbum(p, 0, 0, 0., 0.); + p.restore(); + } + p.end(); + + return ::Media::Streaming::PrepareBlurredBackground( + full, + std::move(result)); } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h index f51eb26e9..9a4b8bc05 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_preview.h @@ -47,7 +47,11 @@ public: return _thumbChanged.events(); } - rpl::producer thumbModified() const; + [[nodiscard]] rpl::producer thumbModified() const { + return _thumbModified.events(); + } + + [[nodiscard]] QImage generatePriceTagBackground() const; protected: void paintEvent(QPaintEvent *e) override; diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp index adf38109b..92025e3cc 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp @@ -503,6 +503,10 @@ void AlbumThumbnail::paintFile( _fileThumb.size() / style::DevicePixelRatio()); } +QRect AlbumThumbnail::geometry() const { + return _layout.geometry; +} + bool AlbumThumbnail::containsPoint(QPoint position) const { return _layout.geometry.contains(position); } diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h index 1bfd8fc62..209f864cd 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.h @@ -42,8 +42,8 @@ public: void setSpoiler(bool spoiler); [[nodiscard]] bool hasSpoiler() const; - int photoHeight() const; - int fileHeight() const; + [[nodiscard]] int photoHeight() const; + [[nodiscard]] int fileHeight() const; void paintInAlbum( QPainter &p, @@ -54,20 +54,22 @@ public: void paintPhoto(Painter &p, int left, int top, int outerWidth); void paintFile(Painter &p, int left, int top, int outerWidth); - bool containsPoint(QPoint position) const; - bool buttonsContainPoint(QPoint position) const; - AttachButtonType buttonTypeFromPoint(QPoint position) const; - int distanceTo(QPoint position) const; - bool isPointAfter(QPoint position) const; + [[nodiscard]] QRect geometry() const; + [[nodiscard]] bool containsPoint(QPoint position) const; + [[nodiscard]] bool buttonsContainPoint(QPoint position) const; + [[nodiscard]] AttachButtonType buttonTypeFromPoint( + QPoint position) const; + [[nodiscard]] int distanceTo(QPoint position) const; + [[nodiscard]] bool isPointAfter(QPoint position) const; void moveInAlbum(QPoint to); - QPoint center() const; + [[nodiscard]] QPoint center() const; void suggestMove(float64 delta, Fn callback); void finishAnimations(); void setButtonVisible(bool value); void moveButtons(int thumbTop); - bool isCompressedSticker() const; + [[nodiscard]] bool isCompressedSticker() const; static constexpr auto kShrinkDuration = crl::time(150);