Added AbstractSingleFilePreview.

This commit is contained in:
23rd 2021-07-12 14:02:02 +03:00 committed by John Preston
parent e2a85e3156
commit 9509a00664
5 changed files with 253 additions and 166 deletions

View File

@ -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

View File

@ -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<IconButton> _editMedia = { nullptr };
object_ptr<IconButton> _deleteMedia = { nullptr };
};
} // namespace Ui

View File

@ -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 <QtCore/QFileInfo>
@ -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<PreparedFileInformation::Image>(
&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

View File

@ -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<IconButton> _editMedia = { nullptr };
object_ptr<IconButton> _deleteMedia = { nullptr };
};

View File

@ -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