From 8fffe7d12811880eab932097d6cdd41f571c195d Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 9 Jan 2021 22:52:55 +0300 Subject: [PATCH] Added ability to show song cover in HistoryView and Overview::Layout. --- Telegram/SourceFiles/data/data_document.cpp | 4 ++ Telegram/SourceFiles/data/data_document.h | 1 + .../view/media/history_view_document.cpp | 60 ++++++++++++++++--- .../view/media/history_view_document.h | 6 ++ .../SourceFiles/overview/overview_layout.cpp | 29 ++++++--- Telegram/SourceFiles/ui/image/image.cpp | 8 ++- Telegram/SourceFiles/ui/image/image.h | 3 +- 7 files changed, 93 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index b7c8d16ca7..dc14957915 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -1488,6 +1488,10 @@ bool DocumentData::isSong() const { return (type == SongDocument); } +bool DocumentData::isSongWithCover() const { + return isSong() && hasThumbnail(); +} + bool DocumentData::isAudioFile() const { if (isVoiceMessage()) { return false; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 35b998d12d..7ee523c0dd 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -139,6 +139,7 @@ public: [[nodiscard]] bool isVoiceMessage() const; [[nodiscard]] bool isVideoMessage() const; [[nodiscard]] bool isSong() const; + [[nodiscard]] bool isSongWithCover() const; [[nodiscard]] bool isAudioFile() const; [[nodiscard]] bool isVideoFile() const; [[nodiscard]] bool isAnimation() const; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index df58d562a7..a28aabf316 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/image/image.h" #include "ui/text/format_values.h" #include "ui/cached_round_corners.h" +#include "ui/ui_utility.h" #include "layout.h" // FullSelection #include "data/data_session.h" #include "data/data_document.h" @@ -442,14 +443,14 @@ void Document::draw( } } else { p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected); - } else { - p.setBrush(outbg ? st::msgFileOutBg : st::msgFileInBg); - } - { + const auto coverDrawn = _data->isSongWithCover() + && DrawThumbnailAsSongCover(p, _dataMedia, inner, selected); + if (!coverDrawn) { PainterHighQualityEnabler hq(p); + p.setBrush(selected + ? (outbg ? st::msgFileOutBgSelected : st::msgFileInBgSelected) + : (outbg ? st::msgFileOutBg : st::msgFileInBg)); p.drawEllipse(inner); } @@ -581,7 +582,7 @@ void Document::ensureDataMediaCreated() const { return; } _dataMedia = _data->createMediaView(); - if (Get()) { + if (Get() || _data->isSongWithCover()) { _dataMedia->thumbnailWanted(_realParent->fullId()); } history()->owner().registerHeavyViewPart(_parent); @@ -1072,4 +1073,49 @@ Ui::Text::String Document::createCaption() { timestampLinkBase); } +bool DrawThumbnailAsSongCover( + Painter &p, + const std::shared_ptr &dataMedia, + const QRect &rect, + const bool selected) { + if (!dataMedia) { + return false; + } + + QPixmap cover; + + const auto ow = rect.width(); + const auto oh = rect.height(); + const auto r = ImageRoundRadius::Ellipse; + const auto c = RectPart::AllCorners; + const auto color = &st::songCoverOverlayFg; + const auto aspectRatio = Qt::KeepAspectRatioByExpanding; + + const auto scaled = [&](not_null image) -> std::pair { + const auto size = image->size().scaled(ow, oh, aspectRatio); + return { size.width(), size.height() }; + }; + + if (const auto normal = dataMedia->thumbnail()) { + const auto &[w, h] = scaled(normal); + cover = normal->pixSingle(w, h, ow, oh, r, c, color); + } else if (const auto blurred = dataMedia->thumbnailInline()) { + const auto &[w, h] = scaled(blurred); + cover = blurred->pixBlurredSingle(w, h, ow, oh, r, c, color); + } else { + return false; + } + if (selected) { + auto selectedCover = Images::prepareColored( + p.textPalette().selectOverlay, + cover.toImage()); + cover = QPixmap::fromImage( + std::move(selectedCover), + Qt::ColorOnly); + } + p.drawPixmap(rect.topLeft(), cover); + + return true; +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index 150c47684f..e438d30ec1 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -143,4 +143,10 @@ private: }; +bool DrawThumbnailAsSongCover( + Painter &p, + const std::shared_ptr &dataMedia, + const QRect &rect, + const bool selected = false); + } // namespace HistoryView diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 4c68b7d7a2..d9ee1a862a 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/history_item_components.h" #include "history/view/history_view_cursor_state.h" +#include "history/view/media/history_view_document.h" // DrawThumbnailAsSongCover #include "base/unixtime.h" #include "base/qt_adapters.h" #include "ui/effects/round_checkbox.h" @@ -1008,21 +1009,33 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con auto inner = style::rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); if (clip.intersects(inner)) { + const auto isLoading = (!cornerDownload + && (_data->loading() || _data->uploading())); p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgFileInBgSelected); - } else { - auto over = ClickHandler::showAsActive((!cornerDownload && (_data->loading() || _data->uploading())) ? _cancell : (loaded || _dataMedia->canBePlayed()) ? _openl : _savel); - p.setBrush(anim::brush(_st.songIconBg, _st.songOverBg, _a_iconOver.value(over ? 1. : 0.))); - } - { + using namespace HistoryView; + const auto coverDrawn = _data->isSongWithCover() + && DrawThumbnailAsSongCover(p, _dataMedia, inner, selected); + if (!coverDrawn) { + if (selected) { + p.setBrush(st::msgFileInBgSelected); + } else { + const auto over = ClickHandler::showAsActive(isLoading + ? _cancell + : (loaded || _dataMedia->canBePlayed()) + ? _openl + : _savel); + p.setBrush(anim::brush( + _st.songIconBg, + _st.songOverBg, + _a_iconOver.value(over ? 1. : 0.))); + } PainterHighQualityEnabler hq(p); p.drawEllipse(inner); } const auto icon = [&] { - if (!cornerDownload && (_data->loading() || _data->uploading())) { + if (isLoading) { return &(selected ? _st.songCancelSelected : _st.songCancel); } else if (showPause) { return &(selected ? _st.songPauseSelected : _st.songPause); diff --git a/Telegram/SourceFiles/ui/image/image.cpp b/Telegram/SourceFiles/ui/image/image.cpp index ceeff11252..0dad5e9edd 100644 --- a/Telegram/SourceFiles/ui/image/image.cpp +++ b/Telegram/SourceFiles/ui/image/image.cpp @@ -343,7 +343,8 @@ const QPixmap &Image::pixBlurredSingle( int outerw, int outerh, ImageRoundRadius radius, - RectParts corners) const { + RectParts corners, + const style::color *colored) const { if (w <= 0 || !width() || !height()) { w = width() * cIntRetinaFactor(); } else { @@ -365,11 +366,14 @@ const QPixmap &Image::pixBlurredSingle( } else if (radius == ImageRoundRadius::Ellipse) { options |= Option::Circled | cornerOptions(corners); } + if (colored) { + options |= Option::Colored; + } auto k = SinglePixKey(options); auto i = _cache.find(k); if (i == _cache.cend() || i->second.width() != (outerw * cIntRetinaFactor()) || i->second.height() != (outerh * cIntRetinaFactor())) { - auto p = pixNoCache(w, h, options, outerw, outerh); + auto p = pixNoCache(w, h, options, outerw, outerh, colored); p.setDevicePixelRatio(cRetinaFactor()); i = _cache.emplace_or_assign(k, p).first; } diff --git a/Telegram/SourceFiles/ui/image/image.h b/Telegram/SourceFiles/ui/image/image.h index 16bba2b1b4..07f5a6a4d3 100644 --- a/Telegram/SourceFiles/ui/image/image.h +++ b/Telegram/SourceFiles/ui/image/image.h @@ -70,7 +70,8 @@ public: int outerw, int outerh, ImageRoundRadius radius, - RectParts corners = RectPart::AllCorners) const; + RectParts corners = RectPart::AllCorners, + const style::color *colored = nullptr) const; [[nodiscard]] const QPixmap &pixCircled(int w = 0, int h = 0) const; [[nodiscard]] const QPixmap &pixBlurredCircled(int w = 0, int h = 0) const; [[nodiscard]] QPixmap pixNoCache(