mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Added initial support of simple captions to attach prepared files.
This commit is contained in:
@@ -290,6 +290,7 @@ SendFilesBox::Block::Block(
|
||||
not_null<std::vector<Ui::PreparedFile>*> items,
|
||||
int from,
|
||||
int till,
|
||||
const Ui::Text::MarkedContext &captionContext,
|
||||
Fn<bool()> gifPaused,
|
||||
SendFilesWay way,
|
||||
Fn<bool(const Ui::PreparedFile &, Ui::AttachActionType)> actionAllowed)
|
||||
@@ -309,6 +310,7 @@ SendFilesBox::Block::Block(
|
||||
parent.get(),
|
||||
st,
|
||||
my,
|
||||
captionContext,
|
||||
way,
|
||||
[=](int index, Ui::AttachActionType type) {
|
||||
return actionAllowed((*_items)[from + index], type);
|
||||
@@ -332,7 +334,8 @@ SendFilesBox::Block::Block(
|
||||
_preview.reset(Ui::CreateChild<Ui::SingleFilePreview>(
|
||||
parent.get(),
|
||||
st,
|
||||
first));
|
||||
first,
|
||||
captionContext));
|
||||
}
|
||||
}
|
||||
_preview->show();
|
||||
@@ -530,6 +533,22 @@ bool SendFilesBox::Block::setSingleFileDisplayName(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SendFilesBox::Block::setSingleFileCaption(
|
||||
int index,
|
||||
const TextWithTags &caption) {
|
||||
if (_isSingleMedia || index < _from || index >= _till) {
|
||||
return false;
|
||||
}
|
||||
if (_isAlbum) {
|
||||
const auto album = static_cast<Ui::AlbumPreview*>(_preview.get());
|
||||
album->setCaption(index - _from, caption);
|
||||
return true;
|
||||
}
|
||||
const auto single = static_cast<Ui::SingleFilePreview*>(_preview.get());
|
||||
single->setCaption(caption);
|
||||
return true;
|
||||
}
|
||||
|
||||
SendFilesBox::SendFilesBox(
|
||||
QWidget*,
|
||||
not_null<Window::SessionController*> controller,
|
||||
@@ -1138,12 +1157,16 @@ void SendFilesBox::pushBlock(int from, int till) {
|
||||
const auto gifPaused = [show = _show] {
|
||||
return show->paused(Window::GifPauseReason::Layer);
|
||||
};
|
||||
const auto captionContext = Core::TextContext({
|
||||
.session = &_show->session(),
|
||||
});
|
||||
_blocks.emplace_back(
|
||||
_inner.data(),
|
||||
_st,
|
||||
&_list.files,
|
||||
from,
|
||||
till,
|
||||
captionContext,
|
||||
gifPaused,
|
||||
_sendWay.current(),
|
||||
[=](const Ui::PreparedFile &file, Ui::AttachActionType type) {
|
||||
|
||||
@@ -16,6 +16,10 @@ namespace style {
|
||||
struct ComposeControls;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui::Text {
|
||||
struct MarkedContext;
|
||||
} // namespace Ui::Text
|
||||
|
||||
namespace Window {
|
||||
class SessionController;
|
||||
} // namespace Window
|
||||
@@ -153,6 +157,7 @@ private:
|
||||
not_null<std::vector<Ui::PreparedFile>*> items,
|
||||
int from,
|
||||
int till,
|
||||
const Ui::Text::MarkedContext &captionContext,
|
||||
Fn<bool()> gifPaused,
|
||||
Ui::SendFilesWay way,
|
||||
Fn<bool(
|
||||
@@ -179,6 +184,9 @@ private:
|
||||
[[nodiscard]] QImage generatePriceTagBackground() const;
|
||||
[[nodiscard]] bool setSingleFileDisplayName(
|
||||
const QString &displayName);
|
||||
[[nodiscard]] bool setSingleFileCaption(
|
||||
int index,
|
||||
const TextWithTags &caption);
|
||||
|
||||
private:
|
||||
base::unique_qptr<Ui::RpWidget> _preview;
|
||||
|
||||
@@ -22,12 +22,26 @@ namespace Ui {
|
||||
AbstractSingleFilePreview::AbstractSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type)
|
||||
AttachControls::Type type,
|
||||
const Text::MarkedContext &captionContext)
|
||||
: AbstractSinglePreview(parent)
|
||||
, _st(st)
|
||||
, _type(type)
|
||||
, _captionContext(captionContext)
|
||||
, _editMedia(this, _st.files.buttonFile)
|
||||
, _deleteMedia(this, _st.files.buttonFile) {
|
||||
const auto repaint = _captionContext.repaint;
|
||||
_captionContext.repaint = [=] {
|
||||
if (repaint) {
|
||||
repaint();
|
||||
}
|
||||
const auto rect = captionRect();
|
||||
if (rect.isEmpty()) {
|
||||
update();
|
||||
} else {
|
||||
update(rect);
|
||||
}
|
||||
};
|
||||
|
||||
_editMedia->setIconOverride(&_st.files.buttonFileEdit);
|
||||
_deleteMedia->setIconOverride(&_st.files.buttonFileDelete);
|
||||
@@ -69,9 +83,25 @@ rpl::producer<> AbstractSingleFilePreview::clearCoverRequests() const {
|
||||
}
|
||||
|
||||
void AbstractSingleFilePreview::setDisplayName(const QString &displayName) {
|
||||
auto data = _data;
|
||||
data.name = displayName;
|
||||
setData(data);
|
||||
_data.name = displayName;
|
||||
updateTextWidthFor(_data);
|
||||
updateDataGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractSingleFilePreview::setCaption(const TextWithTags &caption) {
|
||||
auto marked = TextWithEntities{
|
||||
caption.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(caption.tags),
|
||||
};
|
||||
marked = TextUtilities::SingleLine(marked);
|
||||
_data.caption.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
marked,
|
||||
kMarkupTextOptions,
|
||||
_captionContext);
|
||||
updateTextWidthFor(_data);
|
||||
updateDataGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -151,6 +181,23 @@ void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) {
|
||||
width(),
|
||||
_data.statusText,
|
||||
_data.statusWidth);
|
||||
if (!_data.caption.isEmpty()) {
|
||||
p.setPen(_st.files.nameFg);
|
||||
const auto captionTop = y
|
||||
+ st.thumbSize
|
||||
+ st::attachPreviewCaptionTopOffset;
|
||||
_data.caption.draw(p, {
|
||||
.position = {
|
||||
x,
|
||||
captionTop,
|
||||
},
|
||||
.outerWidth = width(),
|
||||
.availableWidth = _data.captionAvailableWidth,
|
||||
.align = style::al_left,
|
||||
.elisionLines = 1,
|
||||
.elisionBreakEverywhere = true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSingleFilePreview::resizeEvent(QResizeEvent *e) {
|
||||
@@ -167,7 +214,7 @@ void AbstractSingleFilePreview::resizeEvent(QResizeEvent *e) {
|
||||
_editMedia->moveToRight(right, top);
|
||||
}
|
||||
|
||||
bool AbstractSingleFilePreview::isThumbedLayout(Data &data) const {
|
||||
bool AbstractSingleFilePreview::isThumbedLayout(const Data &data) const {
|
||||
return (!data.fileThumb.isNull() && !data.fileIsAudio);
|
||||
}
|
||||
|
||||
@@ -187,6 +234,10 @@ void AbstractSingleFilePreview::updateTextWidthFor(Data &data) {
|
||||
- _st.files.buttonFile.width * buttonsCount
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * buttonsCount
|
||||
- st::sendBoxAlbumGroupSkipRight;
|
||||
const auto availableCaptionWidth = st::sendMediaPreviewSize
|
||||
- _st.files.buttonFile.width * buttonsCount
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * buttonsCount
|
||||
- st::sendBoxAlbumGroupSkipRight;
|
||||
data.nameWidth = st::semiboldFont->width(data.name);
|
||||
if (data.nameWidth > availableFileWidth) {
|
||||
data.name = st::semiboldFont->elided(
|
||||
@@ -196,17 +247,44 @@ void AbstractSingleFilePreview::updateTextWidthFor(Data &data) {
|
||||
data.nameWidth = st::semiboldFont->width(data.name);
|
||||
}
|
||||
data.statusWidth = st::normalFont->width(data.statusText);
|
||||
data.captionAvailableWidth = availableCaptionWidth;
|
||||
}
|
||||
|
||||
void AbstractSingleFilePreview::setData(const Data &data) {
|
||||
_data = data;
|
||||
|
||||
updateTextWidthFor(_data);
|
||||
|
||||
void AbstractSingleFilePreview::updateDataGeometry() {
|
||||
const auto &st = !isThumbedLayout(_data)
|
||||
? st::attachPreviewLayout
|
||||
: st::attachPreviewThumbLayout;
|
||||
resize(width(), st.thumbSize);
|
||||
const auto height = st.thumbSize + (_data.caption.isEmpty()
|
||||
? 0
|
||||
: (st::attachPreviewCaptionTopOffset + _data.caption.lineHeight()));
|
||||
resize(width(), height);
|
||||
}
|
||||
|
||||
QRect AbstractSingleFilePreview::captionRect() const {
|
||||
if (_data.caption.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
const auto w = width()
|
||||
- st::boxPhotoPadding.left()
|
||||
- st::boxPhotoPadding.right();
|
||||
const auto &st = !isThumbedLayout(_data)
|
||||
? st::attachPreviewLayout
|
||||
: st::attachPreviewThumbLayout;
|
||||
const auto x = (width() - w) / 2;
|
||||
const auto captionLineHeight = _data.caption.lineHeight();
|
||||
const auto top = st.thumbSize
|
||||
+ st::attachPreviewCaptionTopOffset;
|
||||
return QRect(
|
||||
x,
|
||||
top,
|
||||
_data.captionAvailableWidth,
|
||||
captionLineHeight) + st::attachPreviewCaptionRepaintMargin;
|
||||
}
|
||||
|
||||
void AbstractSingleFilePreview::setData(Data data) {
|
||||
_data = std::move(data);
|
||||
updateTextWidthFor(_data);
|
||||
updateDataGeometry();
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -24,7 +24,8 @@ public:
|
||||
AbstractSingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
AttachControls::Type type);
|
||||
AttachControls::Type type,
|
||||
const Text::MarkedContext &captionContext);
|
||||
~AbstractSingleFilePreview();
|
||||
|
||||
[[nodiscard]] rpl::producer<> deleteRequests() const override;
|
||||
@@ -33,31 +34,40 @@ public:
|
||||
[[nodiscard]] rpl::producer<> editCoverRequests() const override;
|
||||
[[nodiscard]] rpl::producer<> clearCoverRequests() const override;
|
||||
virtual void setDisplayName(const QString &displayName);
|
||||
virtual void setCaption(const TextWithTags &caption);
|
||||
|
||||
protected:
|
||||
struct Data {
|
||||
QPixmap fileThumb;
|
||||
QString name;
|
||||
QString statusText;
|
||||
Text::String caption;
|
||||
int nameWidth = 0;
|
||||
int statusWidth = 0;
|
||||
int captionAvailableWidth = 0;
|
||||
bool fileIsAudio = false;
|
||||
bool fileIsImage = false;
|
||||
};
|
||||
|
||||
void prepareThumbFor(Data &data, const QImage &preview);
|
||||
bool isThumbedLayout(Data &data) const;
|
||||
bool isThumbedLayout(const Data &data) const;
|
||||
[[nodiscard]] const Text::MarkedContext &captionContext() const {
|
||||
return _captionContext;
|
||||
}
|
||||
|
||||
void setData(const Data &data);
|
||||
void setData(Data data);
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
void updateTextWidthFor(Data &data);
|
||||
void updateDataGeometry();
|
||||
[[nodiscard]] QRect captionRect() const;
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
const AttachControls::Type _type;
|
||||
Text::MarkedContext _captionContext;
|
||||
|
||||
Data _data;
|
||||
|
||||
|
||||
@@ -37,10 +37,12 @@ AlbumPreview::AlbumPreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
gsl::span<Ui::PreparedFile> items,
|
||||
const Text::MarkedContext &captionContext,
|
||||
SendFilesWay way,
|
||||
Fn<bool(int, AttachActionType)> actionAllowed)
|
||||
: RpWidget(parent)
|
||||
, _st(st)
|
||||
, _captionContext(captionContext)
|
||||
, _sendWay(way)
|
||||
, _actionAllowed(std::move(actionAllowed))
|
||||
, _dragTimer([=] { switchToDrag(); }) {
|
||||
@@ -62,6 +64,37 @@ void AlbumPreview::setSendWay(SendFilesWay way) {
|
||||
update();
|
||||
}
|
||||
|
||||
void AlbumPreview::setCaption(int index, const TextWithTags &caption) {
|
||||
if (index < 0 || index >= _thumbs.size()) {
|
||||
return;
|
||||
}
|
||||
const auto realIndex = _order[index];
|
||||
const auto oldHeight = _thumbs[realIndex]->fileHeight();
|
||||
_thumbs[realIndex]->setCaption(caption);
|
||||
const auto newHeight = _thumbs[realIndex]->fileHeight();
|
||||
if (oldHeight == newHeight) {
|
||||
return;
|
||||
}
|
||||
const auto firstFileHeight = _thumbs.front()->fileHeight();
|
||||
_hasMixedFileHeights = ranges::any_of(
|
||||
_thumbs,
|
||||
[=](const auto &thumb) {
|
||||
return thumb->fileHeight() != firstFileHeight;
|
||||
});
|
||||
_filesHeight = ranges::accumulate(ranges::views::all(
|
||||
_thumbs
|
||||
) | ranges::views::transform([](const auto &thumb) {
|
||||
return thumb->fileHeight();
|
||||
}), 0) + (int(_thumbs.size()) - 1) * st::sendMediaRowSkip;
|
||||
updateSize();
|
||||
updateFileRows();
|
||||
}
|
||||
|
||||
int AlbumPreview::indexFromPoint(QPoint position) const {
|
||||
const auto thumb = findThumb(position);
|
||||
return thumb ? orderIndex(thumb) : -1;
|
||||
}
|
||||
|
||||
void AlbumPreview::updateFileRows() {
|
||||
Expects(_order.size() == _thumbs.size());
|
||||
|
||||
@@ -148,9 +181,11 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
|
||||
_thumbs.push_back(std::make_unique<AlbumThumbnail>(
|
||||
_st,
|
||||
items[i],
|
||||
_captionContext,
|
||||
layout[i],
|
||||
this,
|
||||
[=] { update(); },
|
||||
[=](QRect rect) { update(rect); },
|
||||
[=] { changeThumbByIndex(orderIndex(thumbUnderCursor())); },
|
||||
[=] { deleteThumbByIndex(orderIndex(thumbUnderCursor())); }));
|
||||
if (_thumbs.back()->isCompressedSticker()) {
|
||||
@@ -164,16 +199,17 @@ void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
|
||||
return thumb->photoHeight();
|
||||
}), 0) + (count - 1) * st::sendMediaRowSkip;
|
||||
|
||||
if (!_hasMixedFileHeights) {
|
||||
_filesHeight = count * _thumbs.front()->fileHeight()
|
||||
+ (count - 1) * st::sendMediaRowSkip;
|
||||
} else {
|
||||
_filesHeight = ranges::accumulate(ranges::views::all(
|
||||
_thumbs
|
||||
) | ranges::views::transform([](const auto &thumb) {
|
||||
return thumb->fileHeight();
|
||||
}), 0) + (count - 1) * st::sendMediaRowSkip;
|
||||
}
|
||||
const auto firstFileHeight = _thumbs.front()->fileHeight();
|
||||
_hasMixedFileHeights = _hasMixedFileHeights || ranges::any_of(
|
||||
_thumbs,
|
||||
[=](const auto &thumb) {
|
||||
return thumb->fileHeight() != firstFileHeight;
|
||||
});
|
||||
_filesHeight = ranges::accumulate(ranges::views::all(
|
||||
_thumbs
|
||||
) | ranges::views::transform([](const auto &thumb) {
|
||||
return thumb->fileHeight();
|
||||
}), 0) + (count - 1) * st::sendMediaRowSkip;
|
||||
}
|
||||
|
||||
int AlbumPreview::contentLeft() const {
|
||||
@@ -375,7 +411,7 @@ void AlbumPreview::paintFiles(Painter &p, QRect clip) const {
|
||||
const auto left = (st::boxWideWidth - st::sendMediaPreviewSize) / 2;
|
||||
const auto outerWidth = width();
|
||||
if (!_hasMixedFileHeights) {
|
||||
const auto fileHeight = st::attachPreviewThumbLayout.thumbSize
|
||||
const auto fileHeight = _thumbs.front()->fileHeight()
|
||||
+ st::sendMediaRowSkip;
|
||||
const auto bottom = clip.y() + clip.height();
|
||||
const auto from = std::clamp(
|
||||
|
||||
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/text/text.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
namespace style {
|
||||
@@ -28,11 +29,14 @@ public:
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
gsl::span<Ui::PreparedFile> items,
|
||||
const Text::MarkedContext &captionContext,
|
||||
SendFilesWay way,
|
||||
Fn<bool(int, AttachActionType)> actionAllowed);
|
||||
~AlbumPreview();
|
||||
|
||||
void setSendWay(SendFilesWay way);
|
||||
void setCaption(int index, const TextWithTags &caption);
|
||||
[[nodiscard]] int indexFromPoint(QPoint position) const;
|
||||
|
||||
[[nodiscard]] base::flat_set<int> collectSpoileredIndices();
|
||||
[[nodiscard]] bool canHaveSpoiler(int index) const;
|
||||
@@ -103,6 +107,7 @@ private:
|
||||
void showContextMenu(not_null<AlbumThumbnail*> thumb, QPoint position);
|
||||
|
||||
const style::ComposeControls &_st;
|
||||
const Text::MarkedContext _captionContext;
|
||||
SendFilesWay _sendWay;
|
||||
Fn<bool(int, AttachActionType)> _actionAllowed;
|
||||
style::cursor _cursor = style::cur_default;
|
||||
|
||||
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/effects/spoiler_mess.h"
|
||||
#include "ui/ui_utility.h"
|
||||
@@ -28,9 +29,11 @@ namespace Ui {
|
||||
AlbumThumbnail::AlbumThumbnail(
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const Text::MarkedContext &captionContext,
|
||||
const GroupMediaLayout &layout,
|
||||
QWidget *parent,
|
||||
Fn<void()> repaint,
|
||||
Fn<void(QRect)> repaintRect,
|
||||
Fn<void()> editCallback,
|
||||
Fn<void()> deleteCallback)
|
||||
: _st(st)
|
||||
@@ -40,7 +43,8 @@ AlbumThumbnail::AlbumThumbnail(
|
||||
, _isPhoto(file.type == PreparedFile::Type::Photo)
|
||||
, _isVideo(file.type == PreparedFile::Type::Video)
|
||||
, _isCompressedSticker(Core::IsMimeSticker(file.information->filemime))
|
||||
, _repaint(std::move(repaint)) {
|
||||
, _repaint(std::move(repaint))
|
||||
, _repaintRect(std::move(repaintRect)) {
|
||||
Expects(!_fullPreview.isNull());
|
||||
|
||||
moveToLayout(layout);
|
||||
@@ -82,13 +86,22 @@ AlbumThumbnail::AlbumThumbnail(
|
||||
- st::sendBoxAlbumGroupButtonFile.width * 2
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * 2
|
||||
- st::sendBoxAlbumGroupSkipRight;
|
||||
const auto availableCaptionWidth = st::sendMediaPreviewSize
|
||||
- st::sendBoxAlbumGroupButtonFile.width * 2
|
||||
- st::sendBoxAlbumGroupEditInternalSkip * 2
|
||||
- st::sendBoxAlbumGroupSkipRight;
|
||||
_captionAvailableWidth = availableCaptionWidth;
|
||||
const auto filepath = file.path;
|
||||
if (filepath.isEmpty()) {
|
||||
_name = "image.png";
|
||||
_name = file.displayName.isEmpty()
|
||||
? "image.png"
|
||||
: file.displayName;
|
||||
_status = FormatImageSizeText(file.originalDimensions);
|
||||
} else {
|
||||
auto fileinfo = QFileInfo(filepath);
|
||||
_name = fileinfo.fileName();
|
||||
_name = file.displayName.isEmpty()
|
||||
? fileinfo.fileName()
|
||||
: file.displayName;
|
||||
_status = FormatSizeText(fileinfo.size());
|
||||
}
|
||||
_nameWidth = st::semiboldFont->width(_name);
|
||||
@@ -100,6 +113,29 @@ AlbumThumbnail::AlbumThumbnail(
|
||||
_nameWidth = st::semiboldFont->width(_name);
|
||||
}
|
||||
_statusWidth = st::normalFont->width(_status);
|
||||
auto caption = TextWithEntities{
|
||||
file.caption.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(file.caption.tags),
|
||||
};
|
||||
caption = TextUtilities::SingleLine(caption);
|
||||
auto context = captionContext;
|
||||
const auto repaintCaption = context.repaint;
|
||||
context.repaint = [=] {
|
||||
if (repaintCaption) {
|
||||
repaintCaption();
|
||||
}
|
||||
if (!_lastRectOfCaption.isEmpty() && _repaintRect) {
|
||||
_repaintRect(_lastRectOfCaption);
|
||||
} else {
|
||||
_repaint();
|
||||
}
|
||||
};
|
||||
_captionContext = context;
|
||||
_caption.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
caption,
|
||||
kMarkupTextOptions,
|
||||
_captionContext);
|
||||
|
||||
_editMedia.create(parent, _st.files.buttonFile);
|
||||
_deleteMedia.create(parent, _st.files.buttonFile);
|
||||
@@ -126,6 +162,20 @@ void AlbumThumbnail::setSpoiler(bool spoiler) {
|
||||
_repaint();
|
||||
}
|
||||
|
||||
void AlbumThumbnail::setCaption(const TextWithTags &caption) {
|
||||
auto marked = TextWithEntities{
|
||||
caption.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(caption.tags),
|
||||
};
|
||||
marked = TextUtilities::SingleLine(marked);
|
||||
_caption.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
marked,
|
||||
kMarkupTextOptions,
|
||||
_captionContext);
|
||||
_repaint();
|
||||
}
|
||||
|
||||
bool AlbumThumbnail::hasSpoiler() const {
|
||||
return _spoiler != nullptr;
|
||||
}
|
||||
@@ -186,7 +236,9 @@ int AlbumThumbnail::photoHeight() const {
|
||||
int AlbumThumbnail::fileHeight() const {
|
||||
return _isCompressedSticker
|
||||
? photoHeight()
|
||||
: st::attachPreviewThumbLayout.thumbSize;
|
||||
: st::attachPreviewThumbLayout.thumbSize + (_caption.isEmpty()
|
||||
? 0
|
||||
: (st::attachPreviewCaptionTopOffset + _caption.lineHeight()));
|
||||
}
|
||||
|
||||
bool AlbumThumbnail::isCompressedSticker() const {
|
||||
@@ -497,6 +549,28 @@ void AlbumThumbnail::paintFile(
|
||||
outerWidth,
|
||||
_status,
|
||||
_statusWidth);
|
||||
if (!_caption.isEmpty()) {
|
||||
p.setPen(_st.files.nameFg);
|
||||
const auto captionLineHeight = _caption.lineHeight();
|
||||
const auto captionTop = top
|
||||
+ st.thumbSize
|
||||
+ st::attachPreviewCaptionTopOffset;
|
||||
_lastRectOfCaption = QRect(
|
||||
left,
|
||||
captionTop,
|
||||
_captionAvailableWidth,
|
||||
captionLineHeight) + st::attachPreviewCaptionRepaintMargin;
|
||||
_caption.draw(p, {
|
||||
.position = { left, captionTop },
|
||||
.outerWidth = outerWidth,
|
||||
.availableWidth = _captionAvailableWidth,
|
||||
.align = style::al_left,
|
||||
.elisionLines = 1,
|
||||
.elisionBreakEverywhere = true,
|
||||
});
|
||||
} else {
|
||||
_lastRectOfCaption = {};
|
||||
}
|
||||
|
||||
_lastRectOfModify = QRect(
|
||||
QPoint(left, top),
|
||||
|
||||
@@ -29,9 +29,11 @@ public:
|
||||
AlbumThumbnail(
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const Text::MarkedContext &captionContext,
|
||||
const GroupMediaLayout &layout,
|
||||
QWidget *parent,
|
||||
Fn<void()> repaint,
|
||||
Fn<void(QRect)> repaintRect,
|
||||
Fn<void()> editCallback,
|
||||
Fn<void()> deleteCallback);
|
||||
|
||||
@@ -40,6 +42,7 @@ public:
|
||||
void resetLayoutAnimation();
|
||||
|
||||
void setSpoiler(bool spoiler);
|
||||
void setCaption(const TextWithTags &caption);
|
||||
[[nodiscard]] bool hasSpoiler() const;
|
||||
|
||||
[[nodiscard]] int photoHeight() const;
|
||||
@@ -101,8 +104,11 @@ private:
|
||||
QPixmap _fileThumb;
|
||||
QString _name;
|
||||
QString _status;
|
||||
Text::String _caption;
|
||||
Text::MarkedContext _captionContext;
|
||||
int _nameWidth = 0;
|
||||
int _statusWidth = 0;
|
||||
int _captionAvailableWidth = 0;
|
||||
float64 _suggestedMove = 0.;
|
||||
Animations::Simple _suggestedMoveAnimation;
|
||||
int _lastShrinkValue = 0;
|
||||
@@ -112,9 +118,11 @@ private:
|
||||
std::unique_ptr<SpoilerAnimation> _spoiler;
|
||||
QImage _cornerCache;
|
||||
Fn<void()> _repaint;
|
||||
Fn<void(QRect)> _repaintRect;
|
||||
|
||||
QRect _lastRectOfModify;
|
||||
QRect _lastRectOfButtons;
|
||||
QRect _lastRectOfCaption;
|
||||
|
||||
object_ptr<IconButton> _editMedia = { nullptr };
|
||||
object_ptr<IconButton> _deleteMedia = { nullptr };
|
||||
|
||||
@@ -40,7 +40,7 @@ ItemSingleFilePreview::ItemSingleFilePreview(
|
||||
const style::ComposeControls &st,
|
||||
not_null<HistoryItem*> item,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleFilePreview(parent, st, CheckControlsType(item, type)) {
|
||||
: AbstractSingleFilePreview(parent, st, CheckControlsType(item, type), {}) {
|
||||
const auto media = item->media();
|
||||
Assert(media != nullptr);
|
||||
const auto document = media->document();
|
||||
@@ -109,7 +109,7 @@ void ItemSingleFilePreview::preparePreview(not_null<DocumentData*> document) {
|
||||
}
|
||||
data.statusText = FormatSizeText(document->size);
|
||||
|
||||
setData(data);
|
||||
setData(std::move(data));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -80,6 +80,7 @@ struct PreparedFile {
|
||||
|
||||
QString path;
|
||||
QString displayName;
|
||||
TextWithTags caption;
|
||||
QByteArray content;
|
||||
int64 size = 0;
|
||||
std::unique_ptr<PreparedFileInformation> information;
|
||||
|
||||
@@ -10,6 +10,7 @@ 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_utilities.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "styles/style_chat.h"
|
||||
@@ -22,15 +23,28 @@ SingleFilePreview::SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const Text::MarkedContext &captionContext,
|
||||
AttachControls::Type type)
|
||||
: AbstractSingleFilePreview(parent, st, type) {
|
||||
: AbstractSingleFilePreview(parent, st, type, captionContext) {
|
||||
preparePreview(file);
|
||||
}
|
||||
|
||||
SingleFilePreview::SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type)
|
||||
: SingleFilePreview(parent, st, file, {}, type) {
|
||||
}
|
||||
|
||||
void SingleFilePreview::setDisplayName(const QString &displayName) {
|
||||
AbstractSingleFilePreview::setDisplayName(displayName);
|
||||
}
|
||||
|
||||
void SingleFilePreview::setCaption(const TextWithTags &caption) {
|
||||
AbstractSingleFilePreview::setCaption(caption);
|
||||
}
|
||||
|
||||
void SingleFilePreview::preparePreview(const PreparedFile &file) {
|
||||
AbstractSingleFilePreview::Data data;
|
||||
|
||||
@@ -82,8 +96,18 @@ void SingleFilePreview::preparePreview(const PreparedFile &file) {
|
||||
.string();
|
||||
data.statusText = FormatSizeText(fileinfo.size());
|
||||
}
|
||||
auto caption = TextWithEntities{
|
||||
file.caption.text,
|
||||
TextUtilities::ConvertTextTagsToEntities(file.caption.tags),
|
||||
};
|
||||
caption = TextUtilities::SingleLine(caption);
|
||||
data.caption.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
caption,
|
||||
kMarkupTextOptions,
|
||||
captionContext());
|
||||
|
||||
setData(data);
|
||||
setData(std::move(data));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
||||
@@ -15,12 +15,19 @@ struct PreparedFile;
|
||||
|
||||
class SingleFilePreview final : public AbstractSingleFilePreview {
|
||||
public:
|
||||
SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
const Text::MarkedContext &captionContext,
|
||||
AttachControls::Type type = AttachControls::Type::Full);
|
||||
SingleFilePreview(
|
||||
QWidget *parent,
|
||||
const style::ComposeControls &st,
|
||||
const PreparedFile &file,
|
||||
AttachControls::Type type = AttachControls::Type::Full);
|
||||
void setDisplayName(const QString &displayName) override;
|
||||
void setCaption(const TextWithTags &caption) override;
|
||||
|
||||
private:
|
||||
void preparePreview(const PreparedFile &file);
|
||||
|
||||
@@ -534,6 +534,8 @@ attachPreviewThumbLayout: HistoryFileLayout {
|
||||
thumbSize: 64px;
|
||||
thumbSkip: 10px;
|
||||
}
|
||||
attachPreviewCaptionTopOffset: 6px;
|
||||
attachPreviewCaptionRepaintMargin: margins(0px, 2px, 0px, 2px);
|
||||
|
||||
msgFileMinWidth: 268px;
|
||||
msgFileTopMinus: 6px;
|
||||
|
||||
Reference in New Issue
Block a user