diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.cpp new file mode 100644 index 000000000..ca4807706 --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.cpp @@ -0,0 +1,180 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "ui/chat/attach/attach_abstract_single_file_preview.h" + +#include "ui/text/text_options.h" +#include "ui/widgets/buttons.h" +#include "ui/image/image_prepare.h" +#include "base/timer_rpl.h" +#include "styles/style_chat.h" +#include "styles/style_boxes.h" + +namespace Ui { + +AbstractSingleFilePreview::AbstractSingleFilePreview(QWidget *parent) +: RpWidget(parent) +, _editMedia(this, st::sendBoxAlbumGroupButtonFile) +, _deleteMedia(this, st::sendBoxAlbumGroupButtonFile) { + + _editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile); + _deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile); +} + +AbstractSingleFilePreview::~AbstractSingleFilePreview() = default; + +rpl::producer<> AbstractSingleFilePreview::editRequests() const { + return _editMedia->clicks() | rpl::map([] { + return base::timer_once(st::historyAttach.ripple.hideDuration); + }) | rpl::flatten_latest(); +} + +rpl::producer<> AbstractSingleFilePreview::deleteRequests() const { + return _deleteMedia->clicks() | rpl::to_empty; +} + +void AbstractSingleFilePreview::prepareThumbFor( + Data &data, + const QImage &preview) { + if (preview.isNull()) { + return; + } + + auto originalWidth = preview.width(); + auto originalHeight = preview.height(); + const auto &st = st::attachPreviewThumbLayout; + auto thumbWidth = st.thumbSize; + if (originalWidth > originalHeight) { + thumbWidth = (originalWidth * st.thumbSize) / originalHeight; + } + auto options = Images::Option::Smooth + | Images::Option::RoundedSmall + | Images::Option::RoundedTopLeft + | Images::Option::RoundedTopRight + | Images::Option::RoundedBottomLeft + | Images::Option::RoundedBottomRight; + data.fileThumb = PixmapFromImage(Images::prepare( + preview, + thumbWidth * style::DevicePixelRatio(), + 0, + options, + st.thumbSize, + st.thumbSize)); +} + +void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) { + Painter p(this); + + const auto w = width() + - st::boxPhotoPadding.left() + - st::boxPhotoPadding.right(); + const auto h = height(); + const auto &st = !isThumbedLayout(_data) + ? st::attachPreviewLayout + : st::attachPreviewThumbLayout; + const auto nameleft = st.thumbSize + st.padding.right(); + const auto nametop = st.nameTop; + const auto statustop = st.statusTop; + const auto x = (width() - w) / 2, y = 0; + + if (!isThumbedLayout(_data)) { + QRect inner( + style::rtlrect(x, y, st.thumbSize, st.thumbSize, width())); + p.setPen(Qt::NoPen); + + if (_data.fileIsAudio && !_data.fileThumb.isNull()) { + p.drawPixmap(inner.topLeft(), _data.fileThumb); + } else { + p.setBrush(st::msgFileInBg); + PainterHighQualityEnabler hq(p); + p.drawEllipse(inner); + } + + auto &icon = _data.fileIsAudio + ? (_data.fileThumb.isNull() + ? st::historyFileInPlay + : st::historyFileSongPlay) + : _data.fileIsImage + ? st::historyFileInImage + : st::historyFileInDocument; + icon.paintInCenter(p, inner); + } else { + QRect rthumb( + style::rtlrect(x, y, st.thumbSize, st.thumbSize, width())); + p.drawPixmap(rthumb.topLeft(), _data.fileThumb); + } + p.setFont(st::semiboldFont); + p.setPen(st::historyFileNameInFg); + p.drawTextLeft( + x + nameleft, + y + nametop, width(), + _data.name, + _data.nameWidth); + + p.setFont(st::normalFont); + p.setPen(st::mediaInFg); + p.drawTextLeft( + x + nameleft, + y + statustop, + width(), + _data.statusText, + _data.statusWidth); +} + +void AbstractSingleFilePreview::resizeEvent(QResizeEvent *e) { + const auto w = width() + - st::boxPhotoPadding.left() + - st::boxPhotoPadding.right(); + const auto x = (width() - w) / 2; + const auto top = st::sendBoxFileGroupSkipTop; + auto right = st::sendBoxFileGroupSkipRight + x; + _deleteMedia->moveToRight(right, top); + right += st::sendBoxFileGroupEditInternalSkip + _deleteMedia->width(); + _editMedia->moveToRight(right, top); +} + +bool AbstractSingleFilePreview::isThumbedLayout(Data &data) const { + return (!data.fileThumb.isNull() && !data.fileIsAudio); +} + +void AbstractSingleFilePreview::updateTextWidthFor(Data &data) { + const auto &st = !isThumbedLayout(data) + ? st::attachPreviewLayout + : st::attachPreviewThumbLayout; + const auto nameleft = st.thumbSize + st.padding.right(); + const auto nametop = st.nameTop; + const auto statustop = st.statusTop; + const auto availableFileWidth = st::sendMediaPreviewSize + - st.thumbSize + - st.padding.right() + // Right buttons. + - st::sendBoxAlbumGroupButtonFile.width * 2 + - st::sendBoxAlbumGroupEditInternalSkip * 2 + - st::sendBoxAlbumGroupSkipRight; + data.nameWidth = st::semiboldFont->width(data.name); + if (data.nameWidth > availableFileWidth) { + data.name = st::semiboldFont->elided( + data.name, + availableFileWidth, + Qt::ElideMiddle); + data.nameWidth = st::semiboldFont->width(data.name); + } + data.statusWidth = st::normalFont->width(data.statusText); +} + +void AbstractSingleFilePreview::setData(const Data &data) { + _data = data; + + updateTextWidthFor(_data); + + const auto &st = !isThumbedLayout(_data) + ? st::attachPreviewLayout + : st::attachPreviewThumbLayout; + resize(width(), st.thumbSize); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.h new file mode 100644 index 000000000..bb3aa14cc --- /dev/null +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_file_preview.h @@ -0,0 +1,54 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "ui/rp_widget.h" +#include "base/object_ptr.h" + +namespace Ui { + +class IconButton; + +class AbstractSingleFilePreview : public RpWidget { +public: + AbstractSingleFilePreview(QWidget *parent); + ~AbstractSingleFilePreview(); + + [[nodiscard]] rpl::producer<> deleteRequests() const; + [[nodiscard]] rpl::producer<> editRequests() const; + +protected: + struct Data { + QPixmap fileThumb; + QString name; + QString statusText; + int nameWidth = 0; + int statusWidth = 0; + bool fileIsAudio = false; + bool fileIsImage = false; + }; + + void prepareThumbFor(Data &data, const QImage &preview); + bool isThumbedLayout(Data &data) const; + + void setData(const Data &data); + +private: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + + void updateTextWidthFor(Data &data); + + Data _data; + + object_ptr _editMedia = { nullptr }; + object_ptr _deleteMedia = { nullptr }; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp index 28fded211..c2354833a 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.cpp @@ -10,13 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/chat/attach/attach_prepare.h" #include "ui/text/format_song_name.h" #include "ui/text/format_values.h" -#include "ui/text/text_options.h" -#include "ui/widgets/buttons.h" -#include "ui/image/image_prepare.h" -#include "base/timer_rpl.h" #include "core/mime_type.h" #include "styles/style_chat.h" -#include "styles/style_boxes.h" #include @@ -25,60 +20,13 @@ namespace Ui { SingleFilePreview::SingleFilePreview( QWidget *parent, const PreparedFile &file) -: RpWidget(parent) -, _editMedia(this, st::sendBoxAlbumGroupButtonFile) -, _deleteMedia(this, st::sendBoxAlbumGroupButtonFile) { +: AbstractSingleFilePreview(parent) { preparePreview(file); - - _editMedia->setIconOverride(&st::sendBoxAlbumGroupEditButtonIconFile); - _deleteMedia->setIconOverride(&st::sendBoxAlbumGroupDeleteButtonIconFile); - - const auto &st = !isThumbedLayout() - ? st::attachPreviewLayout - : st::attachPreviewThumbLayout; - resize(width(), st.thumbSize); -} - -SingleFilePreview::~SingleFilePreview() = default; - -rpl::producer<> SingleFilePreview::editRequests() const { - return _editMedia->clicks() | rpl::map([] { - return base::timer_once(st::historyAttach.ripple.hideDuration); - }) | rpl::flatten_latest(); -} - -rpl::producer<> SingleFilePreview::deleteRequests() const { - return _deleteMedia->clicks() | rpl::to_empty; -} - -void SingleFilePreview::prepareThumb(const QImage &preview) { - if (preview.isNull()) { - return; - } - - auto originalWidth = preview.width(); - auto originalHeight = preview.height(); - const auto &st = st::attachPreviewThumbLayout; - auto thumbWidth = st.thumbSize; - if (originalWidth > originalHeight) { - thumbWidth = (originalWidth * st.thumbSize) / originalHeight; - } - auto options = Images::Option::Smooth - | Images::Option::RoundedSmall - | Images::Option::RoundedTopLeft - | Images::Option::RoundedTopRight - | Images::Option::RoundedBottomLeft - | Images::Option::RoundedBottomRight; - _fileThumb = PixmapFromImage(Images::prepare( - preview, - thumbWidth * style::DevicePixelRatio(), - 0, - options, - st.thumbSize, - st.thumbSize)); } void SingleFilePreview::preparePreview(const PreparedFile &file) { + AbstractSingleFilePreview::Data data; + auto preview = QImage(); if (const auto image = std::get_if( &file.information->media)) { @@ -87,18 +35,20 @@ void SingleFilePreview::preparePreview(const PreparedFile &file) { &file.information->media)) { preview = video->thumbnail; } - prepareThumb(preview); + prepareThumbFor(data, preview); const auto filepath = file.path; if (filepath.isEmpty()) { auto filename = "image.png"; - _name = filename; - _statusText = FormatImageSizeText(preview.size() + data.name = filename; + data.statusText = FormatImageSizeText(preview.size() / preview.devicePixelRatio()); - _fileIsImage = true; + data.fileIsImage = true; } else { auto fileinfo = QFileInfo(filepath); auto filename = fileinfo.fileName(); - _fileIsImage = Core::FileIsImage(filename, Core::MimeTypeForFile(fileinfo).name()); + data.fileIsImage = Core::FileIsImage( + filename, + Core::MimeTypeForFile(fileinfo).name()); auto songTitle = QString(); auto songPerformer = QString(); @@ -107,98 +57,22 @@ void SingleFilePreview::preparePreview(const PreparedFile &file) { &file.information->media)) { songTitle = song->title; songPerformer = song->performer; - _fileIsAudio = true; + data.fileIsAudio = true; if (auto cover = song->cover; !cover.isNull()) { - _fileThumb = Ui::PrepareSongCoverForThumbnail( + data.fileThumb = Ui::PrepareSongCoverForThumbnail( cover, st::attachPreviewLayout.thumbSize); } } } - _name = Text::FormatSongName(filename, songTitle, songPerformer) + data.name = Text::FormatSongName(filename, songTitle, songPerformer) .string(); - _statusText = FormatSizeText(fileinfo.size()); + data.statusText = FormatSizeText(fileinfo.size()); } - const auto &st = !isThumbedLayout() - ? st::attachPreviewLayout - : st::attachPreviewThumbLayout; - const auto availableFileWidth = st::sendMediaPreviewSize - - st.thumbSize - - st.padding.right() - // Right buttons. - - st::sendBoxAlbumGroupButtonFile.width * 2 - - st::sendBoxAlbumGroupEditInternalSkip * 2 - - st::sendBoxAlbumGroupSkipRight; - _nameWidth = st::semiboldFont->width(_name); - if (_nameWidth > availableFileWidth) { - _name = st::semiboldFont->elided( - _name, - availableFileWidth, - Qt::ElideMiddle); - _nameWidth = st::semiboldFont->width(_name); - } - _statusWidth = st::normalFont->width(_statusText); -} -void SingleFilePreview::paintEvent(QPaintEvent *e) { - Painter p(this); - - auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - const auto &st = !isThumbedLayout() - ? st::attachPreviewLayout - : st::attachPreviewThumbLayout; - const auto nameleft = st.thumbSize + st.padding.right(); - const auto nametop = st.nameTop; - const auto statustop = st.statusTop; - const auto x = (width() - w) / 2, y = 0; - - if (!isThumbedLayout()) { - QRect inner(style::rtlrect(x, y, st.thumbSize, st.thumbSize, width())); - p.setPen(Qt::NoPen); - - if (_fileIsAudio && !_fileThumb.isNull()) { - p.drawPixmap(inner.topLeft(), _fileThumb); - } else { - p.setBrush(st::msgFileInBg); - PainterHighQualityEnabler hq(p); - p.drawEllipse(inner); - } - - auto &icon = _fileIsAudio - ? (_fileThumb.isNull() - ? st::historyFileInPlay - : st::historyFileSongPlay) - : _fileIsImage - ? st::historyFileInImage - : st::historyFileInDocument; - icon.paintInCenter(p, inner); - } else { - QRect rthumb(style::rtlrect(x, y, st.thumbSize, st.thumbSize, width())); - p.drawPixmap(rthumb.topLeft(), _fileThumb); - } - p.setFont(st::semiboldFont); - p.setPen(st::historyFileNameInFg); - p.drawTextLeft(x + nameleft, y + nametop, width(), _name, _nameWidth); - - p.setFont(st::normalFont); - p.setPen(st::mediaInFg); - p.drawTextLeft(x + nameleft, y + statustop, width(), _statusText, _statusWidth); -} - -void SingleFilePreview::resizeEvent(QResizeEvent *e) { - const auto w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(); - const auto x = (width() - w) / 2; - const auto top = st::sendBoxFileGroupSkipTop; - auto right = st::sendBoxFileGroupSkipRight + x; - _deleteMedia->moveToRight(right, top); - right += st::sendBoxFileGroupEditInternalSkip + _deleteMedia->width(); - _editMedia->moveToRight(right, top); -} - -bool SingleFilePreview::isThumbedLayout() const { - return (!_fileThumb.isNull() && !_fileIsAudio); + setData(data); } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h index 630e5e807..695061d90 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_single_file_preview.h @@ -7,43 +7,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "ui/rp_widget.h" -#include "base/object_ptr.h" +#include "ui/chat/attach/attach_abstract_single_file_preview.h" namespace Ui { struct PreparedFile; -class IconButton; -class SingleFilePreview final : public RpWidget { +class SingleFilePreview final : public AbstractSingleFilePreview { public: SingleFilePreview( QWidget *parent, const PreparedFile &file); - ~SingleFilePreview(); - - [[nodiscard]] rpl::producer<> deleteRequests() const; - [[nodiscard]] rpl::producer<> editRequests() const; private: - void paintEvent(QPaintEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - void preparePreview(const PreparedFile &file); - void prepareThumb(const QImage &preview); - - bool isThumbedLayout() const; - - QPixmap _fileThumb; - QString _name; - QString _statusText; - int _nameWidth = 0; - int _statusWidth = 0; - bool _fileIsAudio = false; - bool _fileIsImage = false; - - object_ptr _editMedia = { nullptr }; - object_ptr _deleteMedia = { nullptr }; }; diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index a8c161a23..002bff38d 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -106,6 +106,8 @@ PRIVATE ui/boxes/report_box.h ui/boxes/single_choice_box.cpp ui/boxes/single_choice_box.h + ui/chat/attach/attach_abstract_single_file_preview.cpp + ui/chat/attach/attach_abstract_single_file_preview.h ui/chat/attach/attach_album_preview.cpp ui/chat/attach/attach_album_preview.h ui/chat/attach/attach_album_thumbnail.cpp