mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 21:27:07 +02:00
Use message text rendering for media captions.
This commit is contained in:
parent
d219bccf2b
commit
924d80ecba
18 changed files with 225 additions and 628 deletions
|
@ -775,6 +775,10 @@ void Element::refreshMedia(Element *replacing) {
|
|||
}
|
||||
}
|
||||
|
||||
HistoryItem *Element::textItem() const {
|
||||
return _textItem;
|
||||
}
|
||||
|
||||
Ui::Text::IsolatedEmoji Element::isolatedEmoji() const {
|
||||
return _text.toIsolatedEmoji();
|
||||
}
|
||||
|
@ -952,11 +956,11 @@ auto Element::contextDependentServiceText() -> TextWithLinks {
|
|||
|
||||
void Element::validateText() {
|
||||
const auto item = data();
|
||||
const auto &text = item->_text;
|
||||
const auto media = item->media();
|
||||
const auto storyMention = media && media->storyMention();
|
||||
if (media && media->storyExpired()) {
|
||||
_media = nullptr;
|
||||
_textItem = item;
|
||||
if (!storyMention) {
|
||||
if (_text.isEmpty()) {
|
||||
setTextWithLinks(Ui::Text::Italic(
|
||||
|
@ -965,6 +969,16 @@ void Element::validateText() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Albums may show text of a different item than the parent one.
|
||||
_textItem = _media ? _media->itemForText() : item.get();
|
||||
if (!_textItem) {
|
||||
if (!_text.isEmpty()) {
|
||||
setTextWithLinks({});
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto &text = _textItem->_text;
|
||||
if (_text.isEmpty() == text.empty()) {
|
||||
} else if (_flags & Flag::ServiceMessage) {
|
||||
const auto contextDependentText = contextDependentServiceText();
|
||||
|
@ -972,11 +986,11 @@ void Element::validateText() {
|
|||
? text
|
||||
: contextDependentText.text;
|
||||
const auto &customLinks = contextDependentText.text.empty()
|
||||
? item->customTextLinks()
|
||||
? _textItem->customTextLinks()
|
||||
: contextDependentText.links;
|
||||
setTextWithLinks(markedText, customLinks);
|
||||
} else {
|
||||
setTextWithLinks(item->translatedTextWithLocalEntities());
|
||||
setTextWithLinks(_textItem->translatedTextWithLocalEntities());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1407,6 +1421,12 @@ bool Element::hasVisibleText() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
int Element::textualMaxWidth() const {
|
||||
return st::msgPadding.left()
|
||||
+ (hasVisibleText() ? text().maxWidth() : 0)
|
||||
+ st::msgPadding.right();
|
||||
}
|
||||
|
||||
auto Element::verticalRepaintRange() const -> VerticalRepaintRange {
|
||||
return {
|
||||
.top = 0,
|
||||
|
|
|
@ -373,6 +373,7 @@ public:
|
|||
&& _text.isOnlyCustomEmoji();
|
||||
}
|
||||
|
||||
[[nodiscard]] HistoryItem *textItem() const;
|
||||
[[nodiscard]] Ui::Text::IsolatedEmoji isolatedEmoji() const;
|
||||
[[nodiscard]] Ui::Text::OnlyCustomEmoji onlyCustomEmoji() const;
|
||||
|
||||
|
@ -476,6 +477,7 @@ public:
|
|||
std::optional<QPoint> pressPoint) const;
|
||||
[[nodiscard]] virtual TimeId displayedEditDate() const;
|
||||
[[nodiscard]] virtual bool hasVisibleText() const;
|
||||
[[nodiscard]] int textualMaxWidth() const;
|
||||
virtual void applyGroupAdminChanges(
|
||||
const base::flat_set<UserId> &changes) {
|
||||
}
|
||||
|
@ -633,6 +635,7 @@ private:
|
|||
mutable ClickHandlerPtr _fromLink;
|
||||
const QDateTime _dateTime;
|
||||
|
||||
HistoryItem *_textItem = nullptr;
|
||||
mutable Ui::Text::String _text;
|
||||
mutable int _textWidth = -1;
|
||||
mutable int _textHeight = 0;
|
||||
|
|
|
@ -406,7 +406,6 @@ Message::Message(
|
|||
not_null<HistoryItem*> data,
|
||||
Element *replacing)
|
||||
: Element(delegate, data, replacing, Flag(0))
|
||||
, _invertMedia(data->invertMedia() && !data->emptyText())
|
||||
, _hideReply(delegate->elementHideReply(this))
|
||||
, _bottomInfo(
|
||||
&data->history()->owner().reactions(),
|
||||
|
@ -826,6 +825,15 @@ QSize Message::performCountOptimalSize() {
|
|||
validateInlineKeyboard(markup);
|
||||
updateViewButtonExistence();
|
||||
refreshTopicButton();
|
||||
|
||||
const auto media = this->media();
|
||||
const auto textItem = this->textItem();
|
||||
const auto defaultInvert = media && media->aboveTextByDefault();
|
||||
const auto invertDefault = textItem
|
||||
&& textItem->invertMedia()
|
||||
&& !textItem->emptyText();
|
||||
_invertMedia = invertDefault ? !defaultInvert : defaultInvert;
|
||||
|
||||
updateMediaInBubbleState();
|
||||
if (oldKey != reactionsKey()) {
|
||||
refreshReactions();
|
||||
|
@ -833,7 +841,6 @@ QSize Message::performCountOptimalSize() {
|
|||
refreshRightBadge();
|
||||
refreshInfoSkipBlock();
|
||||
|
||||
const auto media = this->media();
|
||||
const auto botTop = item->isFakeAboutView()
|
||||
? Get<FakeBotAboutTop>()
|
||||
: nullptr;
|
||||
|
@ -877,9 +884,10 @@ QSize Message::performCountOptimalSize() {
|
|||
|
||||
// Entry page is always a bubble bottom.
|
||||
const auto withVisibleText = hasVisibleText();
|
||||
const auto textualWidth = textualMaxWidth();
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || check || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
maxWidth = plainMaxWidth();
|
||||
maxWidth = textualWidth;
|
||||
if (context() == Context::Replies && item->isDiscussionPost()) {
|
||||
maxWidth = std::max(maxWidth, st::msgMaxWidth);
|
||||
}
|
||||
|
@ -930,7 +938,7 @@ QSize Message::performCountOptimalSize() {
|
|||
if (botTop) {
|
||||
minHeight += botTop->height;
|
||||
}
|
||||
if (maxWidth < plainMaxWidth()) {
|
||||
if (maxWidth < textualWidth) {
|
||||
minHeight -= text().minHeight();
|
||||
minHeight += text().countHeight(innerWidth);
|
||||
}
|
||||
|
@ -3432,12 +3440,6 @@ void Message::refreshDataIdHook() {
|
|||
}
|
||||
}
|
||||
|
||||
int Message::plainMaxWidth() const {
|
||||
return st::msgPadding.left()
|
||||
+ (hasVisibleText() ? text().maxWidth() : 0)
|
||||
+ st::msgPadding.right();
|
||||
}
|
||||
|
||||
int Message::monospaceMaxWidth() const {
|
||||
return st::msgPadding.left()
|
||||
+ (hasVisibleText() ? text().countMaxMonospaceWidth() : 0)
|
||||
|
@ -4189,7 +4191,7 @@ QRect Message::countGeometry() const {
|
|||
accumulate_min(contentWidth, maxWidth());
|
||||
accumulate_min(contentWidth, int(_bubbleWidthLimit));
|
||||
if (mediaWidth < contentWidth) {
|
||||
const auto textualWidth = plainMaxWidth();
|
||||
const auto textualWidth = textualMaxWidth();
|
||||
if (mediaWidth < textualWidth
|
||||
&& (!media || !media->enforceBubbleWidth())) {
|
||||
accumulate_min(contentWidth, textualWidth);
|
||||
|
@ -4300,7 +4302,7 @@ int Message::resizeContentGetHeight(int newWidth) {
|
|||
if (mediaDisplayed) {
|
||||
media->resizeGetHeight(contentWidth);
|
||||
if (media->width() < contentWidth) {
|
||||
const auto textualWidth = plainMaxWidth();
|
||||
const auto textualWidth = textualMaxWidth();
|
||||
if (media->width() < textualWidth
|
||||
&& !media->enforceBubbleWidth()) {
|
||||
accumulate_min(contentWidth, textualWidth);
|
||||
|
@ -4474,8 +4476,11 @@ bool Message::invertMedia() const {
|
|||
}
|
||||
|
||||
bool Message::hasVisibleText() const {
|
||||
if (data()->emptyText()) {
|
||||
if (const auto media = data()->media()) {
|
||||
const auto textItem = this->textItem();
|
||||
if (!textItem) {
|
||||
return false;
|
||||
} else if (textItem->emptyText()) {
|
||||
if (const auto media = textItem->media()) {
|
||||
return media->storyExpired();
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -287,7 +287,6 @@ private:
|
|||
void ensureRightAction() const;
|
||||
void refreshTopicButton();
|
||||
void refreshInfoSkipBlock();
|
||||
[[nodiscard]] int plainMaxWidth() const;
|
||||
[[nodiscard]] int monospaceMaxWidth() const;
|
||||
|
||||
void validateInlineKeyboard(HistoryMessageReplyMarkup *markup);
|
||||
|
|
|
@ -300,9 +300,7 @@ Document::Document(
|
|||
_transcribedRound = entry.shown;
|
||||
}
|
||||
|
||||
auto caption = createCaption();
|
||||
|
||||
createComponents(!caption.isEmpty());
|
||||
createComponents();
|
||||
if (const auto named = Get<HistoryDocumentNamed>()) {
|
||||
fillNamedFromData(named);
|
||||
_tooltipFilename.setTooltipText(named->name);
|
||||
|
@ -346,10 +344,6 @@ Document::Document(
|
|||
}
|
||||
|
||||
setStatusSize(Ui::FileStatusSizeReady);
|
||||
|
||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
captioned->caption = std::move(caption);
|
||||
}
|
||||
}
|
||||
|
||||
Document::~Document() {
|
||||
|
@ -374,7 +368,7 @@ bool Document::dataLoaded() const {
|
|||
return _dataMedia->loaded();
|
||||
}
|
||||
|
||||
void Document::createComponents(bool caption) {
|
||||
void Document::createComponents() {
|
||||
uint64 mask = 0;
|
||||
if (_data->isVoiceMessage() || _transcribedRound) {
|
||||
mask |= HistoryDocumentVoice::Bit();
|
||||
|
@ -385,9 +379,6 @@ void Document::createComponents(bool caption) {
|
|||
mask |= HistoryDocumentThumbed::Bit();
|
||||
}
|
||||
}
|
||||
if (caption) {
|
||||
mask |= HistoryDocumentCaptioned::Bit();
|
||||
}
|
||||
UpdateComponents(mask);
|
||||
if (const auto thumbed = Get<HistoryDocumentThumbed>()) {
|
||||
thumbed->linksavel = std::make_shared<DocumentSaveClickHandler>(
|
||||
|
@ -421,18 +412,6 @@ void Document::fillNamedFromData(not_null<HistoryDocumentNamed*> named) {
|
|||
}
|
||||
|
||||
QSize Document::countOptimalSize() {
|
||||
auto captioned = Get<HistoryDocumentCaptioned>();
|
||||
if (_parent->media() != this && !_realParent->groupId()) {
|
||||
if (captioned) {
|
||||
RemoveComponents(HistoryDocumentCaptioned::Bit());
|
||||
captioned = nullptr;
|
||||
}
|
||||
} else if (captioned && captioned->caption.hasSkipBlock()) {
|
||||
captioned->caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
}
|
||||
|
||||
auto hasTranscribe = false;
|
||||
const auto voice = Get<HistoryDocumentVoice>();
|
||||
if (voice) {
|
||||
|
@ -481,7 +460,7 @@ QSize Document::countOptimalSize() {
|
|||
st::messageTextStyle,
|
||||
text);
|
||||
hasTranscribe = true;
|
||||
if (const auto skipBlockWidth = captioned
|
||||
if (const auto skipBlockWidth = _parent->hasVisibleText()
|
||||
? 0
|
||||
: _parent->skipBlockWidth()) {
|
||||
voice->transcribeText.updateSkipBlock(
|
||||
|
@ -528,7 +507,7 @@ QSize Document::countOptimalSize() {
|
|||
}
|
||||
|
||||
auto minHeight = st.padding.top() + st.thumbSize + st.padding.bottom();
|
||||
if (!captioned && !hasTranscribe && _parent->bottomInfoIsWide()) {
|
||||
if (isBubbleBottom() && !hasTranscribe && _parent->bottomInfoIsWide()) {
|
||||
minHeight += st::msgDateFont->height - st::msgDateDelta.y();
|
||||
}
|
||||
if (!isBubbleTop()) {
|
||||
|
@ -540,17 +519,6 @@ QSize Document::countOptimalSize() {
|
|||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
minHeight += voice->transcribeText.countHeight(captionw);
|
||||
if (captioned) {
|
||||
minHeight += st::mediaCaptionSkip;
|
||||
} else if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
if (captioned) {
|
||||
auto captionw = maxWidth
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
minHeight += captioned->caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
|
@ -1521,10 +1489,32 @@ QMargins Document::bubbleMargins() const {
|
|||
return QMargins(padding.left(), padding.top(), padding.right(), padding.bottom());
|
||||
}
|
||||
|
||||
QSize Document::sizeForGroupingOptimal(int maxWidth) const {
|
||||
void Document::refreshCaption(bool last) {
|
||||
auto caption = createCaption();
|
||||
if (!caption.isEmpty()) {
|
||||
AddComponents(HistoryDocumentCaptioned::Bit());
|
||||
auto captioned = Get<HistoryDocumentCaptioned>();
|
||||
captioned->caption = std::move(caption);
|
||||
const auto skip = last ? _parent->skipBlockWidth() : 0;
|
||||
if (skip) {
|
||||
captioned->caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
} else {
|
||||
captioned->caption.removeSkipBlock();
|
||||
}
|
||||
} else {
|
||||
RemoveComponents(HistoryDocumentCaptioned::Bit());
|
||||
}
|
||||
}
|
||||
|
||||
QSize Document::sizeForGroupingOptimal(int maxWidth, bool last) const {
|
||||
const auto thumbed = Get<HistoryDocumentThumbed>();
|
||||
const auto &st = (thumbed ? st::msgFileThumbLayoutGrouped : st::msgFileLayoutGrouped);
|
||||
auto height = st.padding.top() + st.thumbSize + st.padding.bottom();
|
||||
|
||||
const_cast<Document*>(this)->refreshCaption(last);
|
||||
|
||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
auto captionw = maxWidth
|
||||
- st::msgPadding.left()
|
||||
|
@ -1647,33 +1637,16 @@ void Document::refreshParentId(not_null<HistoryItem*> realParent) {
|
|||
}
|
||||
|
||||
void Document::parentTextUpdated() {
|
||||
auto caption = (_parent->media() == this || _realParent->groupId())
|
||||
? createCaption()
|
||||
: Ui::Text::String();
|
||||
if (!caption.isEmpty()) {
|
||||
AddComponents(HistoryDocumentCaptioned::Bit());
|
||||
auto captioned = Get<HistoryDocumentCaptioned>();
|
||||
captioned->caption = std::move(caption);
|
||||
} else {
|
||||
RemoveComponents(HistoryDocumentCaptioned::Bit());
|
||||
}
|
||||
history()->owner().requestViewResize(_parent);
|
||||
}
|
||||
|
||||
TextWithEntities Document::getCaption() const {
|
||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
return captioned->caption.toTextWithEntities();
|
||||
}
|
||||
return TextWithEntities();
|
||||
}
|
||||
|
||||
void Document::hideSpoilers() {
|
||||
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
captioned->caption.setSpoilerRevealed(false, anim::type::instant);
|
||||
}
|
||||
}
|
||||
|
||||
Ui::Text::String Document::createCaption() {
|
||||
Ui::Text::String Document::createCaption() const {
|
||||
return File::createCaption(_realParent);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,10 @@ public:
|
|||
not_null<DocumentData*> document);
|
||||
~Document();
|
||||
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
void updatePressed(QPoint point) override;
|
||||
|
@ -56,7 +60,6 @@ public:
|
|||
return _data;
|
||||
}
|
||||
|
||||
TextWithEntities getCaption() const override;
|
||||
void hideSpoilers() override;
|
||||
bool needsBubble() const override {
|
||||
return true;
|
||||
|
@ -66,7 +69,7 @@ public:
|
|||
}
|
||||
QMargins bubbleMargins() const override;
|
||||
|
||||
QSize sizeForGroupingOptimal(int maxWidth) const override;
|
||||
QSize sizeForGroupingOptimal(int maxWidth, bool last) const override;
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
|
@ -117,12 +120,13 @@ private:
|
|||
LayoutMode mode) const;
|
||||
void ensureDataMediaCreated() const;
|
||||
|
||||
[[nodiscard]] Ui::Text::String createCaption();
|
||||
[[nodiscard]] Ui::Text::String createCaption() const;
|
||||
|
||||
QSize countOptimalSize() override;
|
||||
QSize countCurrentSize(int newWidth) override;
|
||||
|
||||
void createComponents(bool caption);
|
||||
void refreshCaption(bool last);
|
||||
void createComponents();
|
||||
void fillNamedFromData(not_null<HistoryDocumentNamed*> named);
|
||||
|
||||
[[nodiscard]] Ui::BubbleRounding thumbRounding(
|
||||
|
|
|
@ -57,10 +57,8 @@ ExtendedPreview::ExtendedPreview(
|
|||
not_null<Element*> parent,
|
||||
not_null<Data::Invoice*> invoice)
|
||||
: Media(parent)
|
||||
, _invoice(invoice)
|
||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||
, _invoice(invoice) {
|
||||
const auto item = parent->data();
|
||||
_caption = createCaption(item);
|
||||
_spoiler.link = MakeInvoiceLink(item);
|
||||
resolveButtonText();
|
||||
}
|
||||
|
@ -113,17 +111,9 @@ void ExtendedPreview::unloadHeavyPart() {
|
|||
= _spoiler.cornerCache
|
||||
= _buttonBackground = QImage();
|
||||
_spoiler.animation = nullptr;
|
||||
_caption.unloadPersistentAnimation();
|
||||
}
|
||||
|
||||
QSize ExtendedPreview::countOptimalSize() {
|
||||
if (_parent->media() != this) {
|
||||
_caption = Ui::Text::String();
|
||||
} else if (_caption.hasSkipBlock()) {
|
||||
_caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
}
|
||||
const auto &preview = _invoice->extendedPreview;
|
||||
const auto dimensions = preview.dimensions;
|
||||
const auto minWidth = std::min(
|
||||
|
@ -141,15 +131,6 @@ QSize ExtendedPreview::countOptimalSize() {
|
|||
if (preview.videoDuration < 0) {
|
||||
accumulate_max(maxWidth, scaled.height());
|
||||
}
|
||||
if (_parent->hasBubble() && !_caption.isEmpty()) {
|
||||
maxWidth = qMax(maxWidth, st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right());
|
||||
minHeight += st::mediaCaptionSkip + _caption.minHeight();
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
return { maxWidth, minHeight };
|
||||
}
|
||||
|
||||
|
@ -157,7 +138,7 @@ QSize ExtendedPreview::countCurrentSize(int newWidth) {
|
|||
const auto &preview = _invoice->extendedPreview;
|
||||
const auto dimensions = preview.dimensions;
|
||||
const auto thumbMaxWidth = std::min(newWidth, st::maxMediaSize);
|
||||
const auto minWidth = std::min(
|
||||
const auto minWidth = std::min(
|
||||
std::max({
|
||||
_parent->minWidthForMedia(),
|
||||
(_parent->hasBubble()
|
||||
|
@ -176,20 +157,11 @@ QSize ExtendedPreview::countCurrentSize(int newWidth) {
|
|||
maxWidth());
|
||||
newWidth = qMax(scaled.width(), minWidth);
|
||||
auto newHeight = qMax(scaled.height(), st::minPhotoSize);
|
||||
if (_parent->hasBubble() && !_caption.isEmpty()) {
|
||||
if (_parent->hasBubble()) {
|
||||
const auto maxWithCaption = qMin(
|
||||
st::msgMaxWidth,
|
||||
(st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right()));
|
||||
_parent->textualMaxWidth());
|
||||
newWidth = qMin(qMax(newWidth, maxWithCaption), thumbMaxWidth);
|
||||
const auto captionw = newWidth
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
newHeight += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
newHeight += st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
|
@ -210,16 +182,8 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
|
|||
const auto inWebPage = (_parent->media() != this);
|
||||
const auto rounding = inWebPage
|
||||
? std::optional<Ui::BubbleRounding>()
|
||||
: adjustedBubbleRoundingWithCaption(_caption);
|
||||
if (bubble) {
|
||||
if (!_caption.isEmpty()) {
|
||||
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||
}
|
||||
} else {
|
||||
: adjustedBubbleRounding();
|
||||
if (!bubble) {
|
||||
Assert(rounding.has_value());
|
||||
fillImageShadow(p, rthumb, *rounding, context);
|
||||
}
|
||||
|
@ -232,27 +196,7 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
|
|||
}
|
||||
|
||||
// date
|
||||
if (!_caption.isEmpty()) {
|
||||
p.setPen(stm->historyTextFg);
|
||||
_parent->prepareCustomEmojiPaint(p, context, _caption);
|
||||
auto highlightRequest = context.computeHighlightCache();
|
||||
_caption.draw(p, {
|
||||
.position = QPoint(
|
||||
st::msgPadding.left(),
|
||||
painty + painth + st::mediaCaptionSkip),
|
||||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->contentColorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
.pausedEmoji = context.paused || On(PowerSaving::kEmojiChat),
|
||||
.pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler),
|
||||
.selection = context.selection,
|
||||
.highlight = highlightRequest ? &*highlightRequest : nullptr,
|
||||
});
|
||||
} else if (!inWebPage) {
|
||||
if (!inWebPage) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
if (needInfoDisplay()) {
|
||||
|
@ -349,28 +293,10 @@ TextState ExtendedPreview::textState(QPoint point, StateRequest request) const {
|
|||
}
|
||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
|
||||
if (bubble && !_caption.isEmpty()) {
|
||||
const auto captionw = paintw
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
painth -= _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
|
||||
result = TextState(_parent, _caption.getState(
|
||||
point - QPoint(st::msgPadding.left(), painth),
|
||||
captionw,
|
||||
request.forText()));
|
||||
return result;
|
||||
}
|
||||
painth -= st::mediaCaptionSkip;
|
||||
}
|
||||
if (QRect(paintx, painty, paintw, painth).contains(point)) {
|
||||
result.link = _spoiler.link;
|
||||
}
|
||||
if (_caption.isEmpty() && _parent->media() == this) {
|
||||
if (!bubble && _parent->media() == this) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
const auto bottomInfoResult = _parent->bottomInfoTextState(
|
||||
|
@ -412,23 +338,13 @@ bool ExtendedPreview::needInfoDisplay() const {
|
|||
|| _parent->isLastAndSelfMessage();
|
||||
}
|
||||
|
||||
TextForMimeData ExtendedPreview::selectedText(TextSelection selection) const {
|
||||
return _caption.toTextForMimeData(selection);
|
||||
}
|
||||
|
||||
void ExtendedPreview::hideSpoilers() {
|
||||
_caption.setSpoilerRevealed(false, anim::type::instant);
|
||||
}
|
||||
|
||||
bool ExtendedPreview::needsBubble() const {
|
||||
if (!_caption.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
const auto item = _parent->data();
|
||||
return !item->isService()
|
||||
&& (item->repliesAreComments()
|
||||
|| item->externalReply()
|
||||
|| item->viaBot()
|
||||
|| !item->emptyText()
|
||||
|| _parent->displayReply()
|
||||
|| _parent->displayForwardedFrom()
|
||||
|| _parent->displayFromName()
|
||||
|
@ -441,11 +357,4 @@ QPoint ExtendedPreview::resolveCustomInfoRightBottom() const {
|
|||
return QPoint(width() - skipx, height() - skipy);
|
||||
}
|
||||
|
||||
void ExtendedPreview::parentTextUpdated() {
|
||||
_caption = (_parent->media() == this)
|
||||
? createCaption(_parent->data())
|
||||
: Ui::Text::String();
|
||||
history()->owner().requestViewResize(_parent);
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -31,6 +31,10 @@ public:
|
|||
not_null<Data::Invoice*> invoice);
|
||||
~ExtendedPreview();
|
||||
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
|
@ -39,35 +43,15 @@ public:
|
|||
[[nodiscard]] bool dragItemByHandler(
|
||||
const ClickHandlerPtr &p) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
TextSelection selection,
|
||||
TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
|
||||
TextForMimeData selectedText(TextSelection selection) const override;
|
||||
|
||||
TextWithEntities getCaption() const override {
|
||||
return _caption.toTextWithEntities();
|
||||
}
|
||||
void hideSpoilers() override;
|
||||
bool needsBubble() const override;
|
||||
bool customInfoLayout() const override {
|
||||
return _caption.isEmpty();
|
||||
return true;
|
||||
}
|
||||
QPoint resolveCustomInfoRightBottom() const override;
|
||||
bool skipBubbleTail() const override {
|
||||
return isRoundedInBubbleBottom() && _caption.isEmpty();
|
||||
return isRoundedInBubbleBottom();
|
||||
}
|
||||
|
||||
void parentTextUpdated() override;
|
||||
|
||||
bool hasHeavyPart() const override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
|
@ -90,7 +74,6 @@ private:
|
|||
const PaintContext &context) const;
|
||||
|
||||
const not_null<Data::Invoice*> _invoice;
|
||||
Ui::Text::String _caption;
|
||||
mutable MediaSpoiler _spoiler;
|
||||
mutable QImage _inlineThumbnail;
|
||||
mutable QImage _buttonBackground;
|
||||
|
|
|
@ -135,8 +135,6 @@ Gif::Gif(
|
|||
, _storyId(realParent->media()
|
||||
? realParent->media()->storyId()
|
||||
: FullStoryId())
|
||||
, _caption(
|
||||
st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
||||
, _spoiler((spoiler || IsHiddenRoundMessage(_parent))
|
||||
? std::make_unique<MediaSpoiler>()
|
||||
: nullptr)
|
||||
|
@ -184,7 +182,6 @@ Gif::Gif(
|
|||
createSpoilerLink(_spoiler.get());
|
||||
}
|
||||
|
||||
refreshCaption();
|
||||
if ((_dataMedia = _data->activeMediaView())) {
|
||||
dataMediaCreated();
|
||||
} else {
|
||||
|
@ -240,13 +237,6 @@ QSize Gif::countThumbSize(int &inOutWidthMax) const {
|
|||
}
|
||||
|
||||
QSize Gif::countOptimalSize() {
|
||||
if (_parent->media() != this) {
|
||||
_caption = Ui::Text::String();
|
||||
} else if (_caption.hasSkipBlock()) {
|
||||
_caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
}
|
||||
if (_data->isVideoMessage() && _transcribe) {
|
||||
const auto &entry = _data->session().api().transcribes().entry(
|
||||
_realParent);
|
||||
|
@ -271,21 +261,16 @@ QSize Gif::countOptimalSize() {
|
|||
accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
|
||||
}
|
||||
if (_parent->hasBubble()) {
|
||||
if (!_caption.isEmpty()) {
|
||||
maxWidth = qMax(maxWidth, st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right());
|
||||
minHeight = adjustHeightForLessCrop(
|
||||
scaled,
|
||||
{ maxWidth, minHeight });
|
||||
if (const auto botTop = _parent->Get<FakeBotAboutTop>()) {
|
||||
accumulate_max(maxWidth, botTop->maxWidth);
|
||||
minHeight += botTop->height;
|
||||
}
|
||||
minHeight += st::mediaCaptionSkip + _caption.minHeight();
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
maxWidth = qMax(maxWidth, _parent->textualMaxWidth());
|
||||
minHeight = adjustHeightForLessCrop(
|
||||
scaled,
|
||||
{ maxWidth, minHeight });
|
||||
if (const auto botTop = _parent->Get<FakeBotAboutTop>()) {
|
||||
accumulate_max(maxWidth, botTop->maxWidth);
|
||||
minHeight += botTop->height;
|
||||
}
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
} else if (isUnwrapped()) {
|
||||
const auto item = _parent->data();
|
||||
|
@ -318,29 +303,18 @@ QSize Gif::countCurrentSize(int newWidth) {
|
|||
}
|
||||
if (_parent->hasBubble()) {
|
||||
accumulate_max(newWidth, _parent->minWidthForMedia());
|
||||
if (!_caption.isEmpty()) {
|
||||
auto captionMaxWidth = st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right();
|
||||
const auto botTop = _parent->Get<FakeBotAboutTop>();
|
||||
if (botTop) {
|
||||
accumulate_max(captionMaxWidth, botTop->maxWidth);
|
||||
}
|
||||
const auto maxWithCaption = qMin(st::msgMaxWidth, captionMaxWidth);
|
||||
newWidth = qMin(qMax(newWidth, maxWithCaption), thumbMaxWidth);
|
||||
newHeight = adjustHeightForLessCrop(
|
||||
scaled,
|
||||
{ newWidth, newHeight });
|
||||
const auto captionw = newWidth
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
if (botTop) {
|
||||
newHeight += botTop->height;
|
||||
}
|
||||
newHeight += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
newHeight += st::msgPadding.bottom();
|
||||
}
|
||||
auto captionMaxWidth = _parent->textualMaxWidth();
|
||||
const auto botTop = _parent->Get<FakeBotAboutTop>();
|
||||
if (botTop) {
|
||||
accumulate_max(captionMaxWidth, botTop->maxWidth);
|
||||
}
|
||||
const auto maxWithCaption = qMin(st::msgMaxWidth, captionMaxWidth);
|
||||
newWidth = qMin(qMax(newWidth, maxWithCaption), thumbMaxWidth);
|
||||
newHeight = adjustHeightForLessCrop(
|
||||
scaled,
|
||||
{ newWidth, newHeight });
|
||||
if (botTop) {
|
||||
newHeight += botTop->height;
|
||||
}
|
||||
} else if (isUnwrapped()) {
|
||||
accumulate_max(newWidth, _parent->reactionsOptimalWidth());
|
||||
|
@ -433,7 +407,6 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
|||
const auto activeRoundPlaying = activeRoundStreamed();
|
||||
|
||||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
|
||||
const bool bubble = _parent->hasBubble();
|
||||
const auto rightLayout = _parent->hasRightLayout();
|
||||
const auto inWebPage = (_parent->media() != this);
|
||||
|
@ -442,16 +415,10 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
|||
|
||||
const auto rounding = inWebPage
|
||||
? std::optional<Ui::BubbleRounding>()
|
||||
: adjustedBubbleRoundingWithCaption(_caption);
|
||||
: adjustedBubbleRounding();
|
||||
if (bubble) {
|
||||
if (!_caption.isEmpty()) {
|
||||
if (botTop) {
|
||||
painth -= botTop->height;
|
||||
}
|
||||
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
if (botTop) {
|
||||
painth -= botTop->height;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,11 +759,13 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!unwrapped && !_caption.isEmpty()) {
|
||||
if (!unwrapped && bubble) {
|
||||
p.setPen(stm->historyTextFg);
|
||||
_parent->prepareCustomEmojiPaint(p, context, _caption);
|
||||
auto top = painty + painth + st::mediaCaptionSkip;
|
||||
if (botTop) {
|
||||
auto captionw = paintw
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
botTop->text.drawLeftElided(
|
||||
p,
|
||||
st::msgPadding.left(),
|
||||
|
@ -805,21 +774,6 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
|
|||
_parent->width());
|
||||
top += botTop->height;
|
||||
}
|
||||
auto highlightRequest = context.computeHighlightCache();
|
||||
_caption.draw(p, {
|
||||
.position = QPoint(st::msgPadding.left(), top),
|
||||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->contentColorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
.pausedEmoji = context.paused || On(PowerSaving::kEmojiChat),
|
||||
.pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler),
|
||||
.selection = context.selection,
|
||||
.highlight = highlightRequest ? &*highlightRequest : nullptr,
|
||||
});
|
||||
} else if (!inWebPage && !skipDrawingSurrounding) {
|
||||
auto fullRight = paintx + usex + usew;
|
||||
auto fullBottom = painty + painth;
|
||||
|
@ -1081,23 +1035,10 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
|
|||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
|
||||
if (bubble && !_caption.isEmpty()) {
|
||||
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
|
||||
painth -= _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
|
||||
result = TextState(_parent, _caption.getState(
|
||||
point - QPoint(st::msgPadding.left(), painth),
|
||||
captionw,
|
||||
request.forText()));
|
||||
return result;
|
||||
}
|
||||
if (bubble) {
|
||||
if (const auto botTop = _parent->Get<FakeBotAboutTop>()) {
|
||||
painth -= botTop->height;
|
||||
}
|
||||
painth -= st::mediaCaptionSkip;
|
||||
}
|
||||
const auto rightLayout = _parent->hasRightLayout();
|
||||
const auto inWebPage = (_parent->media() != this);
|
||||
|
@ -1212,7 +1153,7 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
|
|||
? _cancell
|
||||
: _savel;
|
||||
}
|
||||
if (unwrapped || _caption.isEmpty()) {
|
||||
if (unwrapped || !bubble) {
|
||||
auto fullRight = usex + paintx + usew;
|
||||
auto fullBottom = painty + painth;
|
||||
auto maxRight = _parent->width() - st::msgMargin.left();
|
||||
|
@ -1289,23 +1230,11 @@ void Gif::clickHandlerPressedChanged(
|
|||
}
|
||||
}
|
||||
|
||||
TextForMimeData Gif::selectedText(TextSelection selection) const {
|
||||
return _caption.toTextForMimeData(selection);
|
||||
}
|
||||
|
||||
SelectedQuote Gif::selectedQuote(TextSelection selection) const {
|
||||
return Element::FindSelectedQuote(_caption, selection, _realParent);
|
||||
}
|
||||
|
||||
TextSelection Gif::selectionFromQuote(const SelectedQuote "e) const {
|
||||
return Element::FindSelectionFromQuote(_caption, quote);
|
||||
}
|
||||
|
||||
bool Gif::fullFeaturedGrouped(RectParts sides) const {
|
||||
return (sides & RectPart::Left) && (sides & RectPart::Right);
|
||||
}
|
||||
|
||||
QSize Gif::sizeForGroupingOptimal(int maxWidth) const {
|
||||
QSize Gif::sizeForGroupingOptimal(int maxWidth, bool last) const {
|
||||
return sizeForAspectRatio();
|
||||
}
|
||||
|
||||
|
@ -1588,7 +1517,6 @@ bool Gif::uploading() const {
|
|||
}
|
||||
|
||||
void Gif::hideSpoilers() {
|
||||
_caption.setSpoilerRevealed(false, anim::type::instant);
|
||||
if (_spoiler) {
|
||||
_spoiler->revealed = false;
|
||||
}
|
||||
|
@ -1599,13 +1527,12 @@ bool Gif::needsBubble() const {
|
|||
return true;
|
||||
} else if (_data->isVideoMessage()) {
|
||||
return false;
|
||||
} else if (!_caption.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
const auto item = _parent->data();
|
||||
return item->repliesAreComments()
|
||||
|| item->externalReply()
|
||||
|| item->viaBot()
|
||||
|| !item->emptyText()
|
||||
|| _parent->displayReply()
|
||||
|| _parent->displayForwardedFrom()
|
||||
|| _parent->displayFromName()
|
||||
|
@ -1810,13 +1737,6 @@ bool Gif::isReadyForOpen() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Gif::parentTextUpdated() {
|
||||
if (_parent->media() == this) {
|
||||
refreshCaption();
|
||||
history()->owner().requestViewResize(_parent);
|
||||
}
|
||||
}
|
||||
|
||||
bool Gif::hasHeavyPart() const {
|
||||
return (_spoiler && _spoiler->animation) || _streamed || _dataMedia;
|
||||
}
|
||||
|
@ -1830,19 +1750,11 @@ void Gif::unloadHeavyPart() {
|
|||
}
|
||||
_thumbCache = QImage();
|
||||
_videoThumbnailFrame = nullptr;
|
||||
_caption.unloadPersistentAnimation();
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
void Gif::refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
File::refreshParentId(realParent);
|
||||
if (_parent->media() == this) {
|
||||
refreshCaption();
|
||||
}
|
||||
}
|
||||
|
||||
void Gif::refreshCaption() {
|
||||
_caption = createCaption(_parent->data());
|
||||
bool Gif::enforceBubbleWidth() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
int Gif::additionalWidth(
|
||||
|
|
|
@ -54,6 +54,10 @@ public:
|
|||
bool spoiler);
|
||||
~Gif();
|
||||
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
|
@ -61,23 +65,6 @@ public:
|
|||
const ClickHandlerPtr &p,
|
||||
bool pressed) override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
TextSelection selection,
|
||||
TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
|
||||
TextForMimeData selectedText(TextSelection selection) const override;
|
||||
SelectedQuote selectedQuote(TextSelection selection) const override;
|
||||
TextSelection selectionFromQuote(
|
||||
const SelectedQuote "e) const override;
|
||||
|
||||
bool uploading() const override;
|
||||
|
||||
DocumentData *getDocument() const override {
|
||||
|
@ -85,7 +72,7 @@ public:
|
|||
}
|
||||
|
||||
bool fullFeaturedGrouped(RectParts sides) const;
|
||||
QSize sizeForGroupingOptimal(int maxWidth) const override;
|
||||
QSize sizeForGroupingOptimal(int maxWidth, bool last) const override;
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
|
@ -105,14 +92,11 @@ public:
|
|||
void stopAnimation() override;
|
||||
void checkAnimation() override;
|
||||
|
||||
TextWithEntities getCaption() const override {
|
||||
return _caption.toTextWithEntities();
|
||||
}
|
||||
void hideSpoilers() override;
|
||||
bool needsBubble() const override;
|
||||
bool unwrapped() const override;
|
||||
bool customInfoLayout() const override {
|
||||
return _caption.isEmpty();
|
||||
return true;
|
||||
}
|
||||
QRect contentRectForReactions() const override;
|
||||
std::optional<int> reactionButtonCenterOverride() const override;
|
||||
|
@ -120,16 +104,13 @@ public:
|
|||
QString additionalInfoString() const override;
|
||||
|
||||
bool skipBubbleTail() const override {
|
||||
return isRoundedInBubbleBottom() && _caption.isEmpty();
|
||||
return isRoundedInBubbleBottom();
|
||||
}
|
||||
bool isReadyForOpen() const override;
|
||||
|
||||
void parentTextUpdated() override;
|
||||
|
||||
bool hasHeavyPart() const override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
bool enforceBubbleWidth() const override;
|
||||
|
||||
[[nodiscard]] static bool CanPlayInline(not_null<DocumentData*> document);
|
||||
|
||||
|
@ -148,7 +129,6 @@ private:
|
|||
|
||||
void ensureDataMediaCreated() const;
|
||||
void dataMediaCreated() const;
|
||||
void refreshCaption();
|
||||
|
||||
[[nodiscard]] bool autoplayEnabled() const;
|
||||
|
||||
|
@ -223,7 +203,6 @@ private:
|
|||
|
||||
const not_null<DocumentData*> _data;
|
||||
const FullStoryId _storyId;
|
||||
Ui::Text::String _caption;
|
||||
std::unique_ptr<Streamed> _streamed;
|
||||
const std::unique_ptr<MediaSpoiler> _spoiler;
|
||||
mutable std::unique_ptr<TranscribeButton> _transcribe;
|
||||
|
|
|
@ -30,6 +30,9 @@ public:
|
|||
return _title.toString();
|
||||
}
|
||||
|
||||
bool aboveTextByDefault() const override {
|
||||
return false;
|
||||
}
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -391,10 +391,8 @@ Ui::BubbleRounding Media::adjustedBubbleRounding(RectParts square) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
Ui::BubbleRounding Media::adjustedBubbleRoundingWithCaption(
|
||||
const Ui::Text::String &caption) const {
|
||||
return adjustedBubbleRounding(
|
||||
caption.isEmpty() ? RectParts() : RectPart::FullBottom);
|
||||
HistoryItem *Media::itemForText() const {
|
||||
return _parent->data();
|
||||
}
|
||||
|
||||
bool Media::isRoundedInBubbleBottom() const {
|
||||
|
|
|
@ -104,6 +104,10 @@ public:
|
|||
[[nodiscard]] virtual bool hasTextForCopy() const {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool aboveTextByDefault() const {
|
||||
return true;
|
||||
}
|
||||
[[nodiscard]] virtual HistoryItem *itemForText() const;
|
||||
[[nodiscard]] virtual bool hideMessageText() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -194,7 +198,9 @@ public:
|
|||
virtual void checkAnimation() {
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual QSize sizeForGroupingOptimal(int maxWidth) const {
|
||||
[[nodiscard]] virtual QSize sizeForGroupingOptimal(
|
||||
int maxWidth,
|
||||
bool last) const {
|
||||
Unexpected("Grouping method call.");
|
||||
}
|
||||
[[nodiscard]] virtual QSize sizeForGrouping(int width) const {
|
||||
|
@ -221,9 +227,6 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual TextWithEntities getCaption() const {
|
||||
return TextWithEntities();
|
||||
}
|
||||
virtual void hideSpoilers() {
|
||||
}
|
||||
[[nodiscard]] virtual bool needsBubble() const = 0;
|
||||
|
@ -273,8 +276,6 @@ public:
|
|||
}
|
||||
[[nodiscard]] Ui::BubbleRounding adjustedBubbleRounding(
|
||||
RectParts square = {}) const;
|
||||
[[nodiscard]] Ui::BubbleRounding adjustedBubbleRoundingWithCaption(
|
||||
const Ui::Text::String &caption) const;
|
||||
[[nodiscard]] bool isBubbleTop() const {
|
||||
return (_inBubbleState == MediaInBubbleState::Top)
|
||||
|| (_inBubbleState == MediaInBubbleState::None);
|
||||
|
|
|
@ -65,8 +65,7 @@ GroupedMedia::Part::Part(
|
|||
GroupedMedia::GroupedMedia(
|
||||
not_null<Element*> parent,
|
||||
const std::vector<std::unique_ptr<Data::Media>> &medias)
|
||||
: Media(parent)
|
||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||
: Media(parent) {
|
||||
const auto truncated = ranges::views::all(
|
||||
medias
|
||||
) | ranges::views::transform([](const std::unique_ptr<Data::Media> &v) {
|
||||
|
@ -80,8 +79,7 @@ GroupedMedia::GroupedMedia(
|
|||
GroupedMedia::GroupedMedia(
|
||||
not_null<Element*> parent,
|
||||
const std::vector<not_null<HistoryItem*>> &items)
|
||||
: Media(parent)
|
||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||
: Media(parent) {
|
||||
const auto medias = ranges::views::all(
|
||||
items
|
||||
) | ranges::views::transform([](not_null<HistoryItem*> item) {
|
||||
|
@ -97,6 +95,31 @@ GroupedMedia::~GroupedMedia() {
|
|||
base::take(_parts);
|
||||
}
|
||||
|
||||
HistoryItem *GroupedMedia::itemForText() const {
|
||||
if (_mode == Mode::Column) {
|
||||
return Media::itemForText();
|
||||
} else if (!_captionItem) {
|
||||
_captionItem = [&]() -> HistoryItem* {
|
||||
auto result = (HistoryItem*)nullptr;
|
||||
for (const auto &part : _parts) {
|
||||
if (!part.item->emptyText()) {
|
||||
if (result) {
|
||||
return nullptr;
|
||||
} else {
|
||||
result = part.item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
}
|
||||
return *_captionItem;
|
||||
}
|
||||
|
||||
bool GroupedMedia::hideMessageText() const {
|
||||
return (_mode == Mode::Column);
|
||||
}
|
||||
|
||||
GroupedMedia::Mode GroupedMedia::DetectMode(not_null<Data::Media*> media) {
|
||||
const auto document = media->document();
|
||||
return (document && !document->isVideoFile())
|
||||
|
@ -105,12 +128,6 @@ GroupedMedia::Mode GroupedMedia::DetectMode(not_null<Data::Media*> media) {
|
|||
}
|
||||
|
||||
QSize GroupedMedia::countOptimalSize() {
|
||||
if (_caption.hasSkipBlock()) {
|
||||
_caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
}
|
||||
|
||||
std::vector<QSize> sizes;
|
||||
const auto partsCount = _parts.size();
|
||||
sizes.reserve(partsCount);
|
||||
|
@ -123,8 +140,11 @@ QSize GroupedMedia::countOptimalSize() {
|
|||
accumulate_max(maxWidth, media->maxWidth());
|
||||
}
|
||||
}
|
||||
auto index = 0;
|
||||
for (const auto &part : _parts) {
|
||||
sizes.push_back(part.content->sizeForGroupingOptimal(maxWidth));
|
||||
const auto last = (++index == _parts.size());
|
||||
sizes.push_back(
|
||||
part.content->sizeForGroupingOptimal(maxWidth, last));
|
||||
}
|
||||
|
||||
const auto layout = (_mode == Mode::Grid)
|
||||
|
@ -145,13 +165,7 @@ QSize GroupedMedia::countOptimalSize() {
|
|||
_parts[i].sides = item.sides;
|
||||
}
|
||||
|
||||
if (!_caption.isEmpty()) {
|
||||
auto captionw = maxWidth - st::msgPadding.left() - st::msgPadding.right();
|
||||
minHeight += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
} else if (_mode == Mode::Column && _parts.back().item->emptyText()) {
|
||||
if (_mode == Mode::Column && _parts.back().item->emptyText()) {
|
||||
const auto item = _parent->data();
|
||||
const auto msgsigned = item->Get<HistoryMessageSigned>();
|
||||
const auto views = item->Get<HistoryMessageViews>();
|
||||
|
@ -215,13 +229,7 @@ QSize GroupedMedia::countCurrentSize(int newWidth) {
|
|||
accumulate_max(newHeight, top + height);
|
||||
}
|
||||
}
|
||||
if (!_caption.isEmpty()) {
|
||||
const auto captionw = newWidth - st::msgPadding.left() - st::msgPadding.right();
|
||||
newHeight += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
newHeight += st::msgPadding.bottom();
|
||||
}
|
||||
} else if (_mode == Mode::Column && _parts.back().item->emptyText()) {
|
||||
if (_mode == Mode::Column && _parts.back().item->emptyText()) {
|
||||
const auto item = _parent->data();
|
||||
const auto msgsigned = item->Get<HistoryMessageSigned>();
|
||||
const auto views = item->Get<HistoryMessageViews>();
|
||||
|
@ -341,7 +349,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
|
|||
constexpr auto kSmall = Ui::BubbleCornerRounding::Small;
|
||||
const auto rounding = inWebPage
|
||||
? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall }
|
||||
: adjustedBubbleRoundingWithCaption(_caption);
|
||||
: adjustedBubbleRounding();
|
||||
auto highlight = context.highlight.range;
|
||||
const auto subpartHighlight = IsSubGroupSelection(highlight);
|
||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||
|
@ -388,33 +396,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
|
|||
}
|
||||
|
||||
// date
|
||||
if (!_caption.isEmpty()) {
|
||||
const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right();
|
||||
const auto captiony = height()
|
||||
- groupPadding.bottom()
|
||||
- (isBubbleBottom() ? st::msgPadding.bottom() : 0)
|
||||
- _caption.countHeight(captionw);
|
||||
const auto stm = context.messageStyle();
|
||||
p.setPen(stm->historyTextFg);
|
||||
_parent->prepareCustomEmojiPaint(p, context, _caption);
|
||||
auto highlightRequest = context.computeHighlightCache();
|
||||
_caption.draw(p, {
|
||||
.position = QPoint(
|
||||
st::msgPadding.left(),
|
||||
captiony),
|
||||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->contentColorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
.pausedEmoji = context.paused || On(PowerSaving::kEmojiChat),
|
||||
.pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler),
|
||||
.selection = context.selection,
|
||||
.highlight = highlightRequest ? &*highlightRequest : nullptr,
|
||||
});
|
||||
} else if (_parent->media() == this) {
|
||||
if (_parent->media() == this) {
|
||||
auto fullRight = width();
|
||||
auto fullBottom = height();
|
||||
if (needInfoDisplay()) {
|
||||
|
@ -473,23 +455,7 @@ PointState GroupedMedia::pointState(QPoint point) const {
|
|||
TextState GroupedMedia::textState(QPoint point, StateRequest request) const {
|
||||
const auto groupPadding = groupedPadding();
|
||||
auto result = getPartState(point - QPoint(0, groupPadding.top()), request);
|
||||
if (!result.link && !_caption.isEmpty()) {
|
||||
const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right();
|
||||
const auto captiony = height()
|
||||
- groupPadding.bottom()
|
||||
- (isBubbleBottom() ? st::msgPadding.bottom() : 0)
|
||||
- _caption.countHeight(captionw);
|
||||
if (QRect(st::msgPadding.left(), captiony, captionw, height() - captiony).contains(point)) {
|
||||
return TextState(
|
||||
_captionItem
|
||||
? _captionItem
|
||||
: _parent->data().get(),
|
||||
_caption.getState(
|
||||
point - QPoint(st::msgPadding.left(), captiony),
|
||||
captionw,
|
||||
request.forText()));
|
||||
}
|
||||
} else if (_parent->media() == this) {
|
||||
if (_parent->media() == this) {
|
||||
auto fullRight = width();
|
||||
auto fullBottom = height();
|
||||
const auto bottomInfoResult = _parent->bottomInfoTextState(
|
||||
|
@ -539,7 +505,7 @@ TextSelection GroupedMedia::adjustSelection(
|
|||
TextSelection selection,
|
||||
TextSelectType type) const {
|
||||
if (_mode != Mode::Column) {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
return {};
|
||||
}
|
||||
auto checked = 0;
|
||||
for (const auto &part : _parts) {
|
||||
|
@ -563,7 +529,7 @@ TextSelection GroupedMedia::adjustSelection(
|
|||
|
||||
uint16 GroupedMedia::fullSelectionLength() const {
|
||||
if (_mode != Mode::Column) {
|
||||
return _caption.length();
|
||||
return {};
|
||||
}
|
||||
auto result = 0;
|
||||
for (const auto &part : _parts) {
|
||||
|
@ -574,7 +540,7 @@ uint16 GroupedMedia::fullSelectionLength() const {
|
|||
|
||||
bool GroupedMedia::hasTextForCopy() const {
|
||||
if (_mode != Mode::Column) {
|
||||
return !_caption.isEmpty();
|
||||
return {};
|
||||
}
|
||||
for (const auto &part : _parts) {
|
||||
if (part.content->hasTextForCopy()) {
|
||||
|
@ -587,7 +553,7 @@ bool GroupedMedia::hasTextForCopy() const {
|
|||
TextForMimeData GroupedMedia::selectedText(
|
||||
TextSelection selection) const {
|
||||
if (_mode != Mode::Column) {
|
||||
return _caption.toTextForMimeData(selection);
|
||||
return {};
|
||||
}
|
||||
auto result = TextForMimeData();
|
||||
for (const auto &part : _parts) {
|
||||
|
@ -606,9 +572,7 @@ TextForMimeData GroupedMedia::selectedText(
|
|||
|
||||
SelectedQuote GroupedMedia::selectedQuote(TextSelection selection) const {
|
||||
if (_mode != Mode::Column) {
|
||||
return _captionItem
|
||||
? Element::FindSelectedQuote(_caption, selection, _captionItem)
|
||||
: SelectedQuote();
|
||||
return {};
|
||||
}
|
||||
for (const auto &part : _parts) {
|
||||
const auto next = part.content->skipSelection(selection);
|
||||
|
@ -630,9 +594,7 @@ TextSelection GroupedMedia::selectionFromQuote(
|
|||
Expects(quote.item != nullptr);
|
||||
|
||||
if (_mode != Mode::Column) {
|
||||
return (_captionItem == quote.item)
|
||||
? Element::FindSelectionFromQuote(_caption, quote)
|
||||
: TextSelection();
|
||||
return {};
|
||||
}
|
||||
const auto i = ranges::find(_parts, not_null(quote.item), &Part::item);
|
||||
if (i == end(_parts)) {
|
||||
|
@ -730,7 +692,6 @@ bool GroupedMedia::applyGroup(const DataMediaRange &medias) {
|
|||
if (_parts.empty()) {
|
||||
return false;
|
||||
}
|
||||
refreshCaption();
|
||||
|
||||
Ensures(_parts.size() <= kMaxSize);
|
||||
return true;
|
||||
|
@ -750,43 +711,13 @@ bool GroupedMedia::validateGroupParts(
|
|||
return (i == count);
|
||||
}
|
||||
|
||||
void GroupedMedia::refreshCaption() {
|
||||
const auto part = [&]() -> const Part* {
|
||||
if (_mode == Mode::Column) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = (const Part*)nullptr;
|
||||
for (const auto &part : _parts) {
|
||||
if (!part.item->emptyText()) {
|
||||
if (result) {
|
||||
return nullptr;
|
||||
} else {
|
||||
result = ∂
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
if (part) {
|
||||
_caption = createCaption(part->item);
|
||||
_captionItem = part->item;
|
||||
} else {
|
||||
_captionItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
not_null<Media*> GroupedMedia::main() const {
|
||||
Expects(!_parts.empty());
|
||||
|
||||
return _parts.back().content.get();
|
||||
}
|
||||
|
||||
TextWithEntities GroupedMedia::getCaption() const {
|
||||
return main()->getCaption();
|
||||
}
|
||||
|
||||
void GroupedMedia::hideSpoilers() {
|
||||
_caption.setSpoilerRevealed(false, anim::type::instant);
|
||||
for (const auto &part : _parts) {
|
||||
part.content->hideSpoilers();
|
||||
}
|
||||
|
@ -846,13 +777,11 @@ void GroupedMedia::unloadHeavyPart() {
|
|||
part.cacheKey = 0;
|
||||
part.cache = QPixmap();
|
||||
}
|
||||
_caption.unloadPersistentAnimation();
|
||||
}
|
||||
|
||||
void GroupedMedia::parentTextUpdated() {
|
||||
if (_parent->media() == this) {
|
||||
refreshCaption();
|
||||
history()->owner().requestViewResize(_parent);
|
||||
_captionItem = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -867,7 +796,9 @@ QPoint GroupedMedia::resolveCustomInfoRightBottom() const {
|
|||
}
|
||||
|
||||
bool GroupedMedia::computeNeedBubble() const {
|
||||
if (!_caption.isEmpty() || _mode == Mode::Column) {
|
||||
Expects(_mode == Mode::Column || _captionItem.has_value());
|
||||
|
||||
if (_mode == Mode::Column || *_captionItem) {
|
||||
return true;
|
||||
}
|
||||
if (const auto item = _parent->data()) {
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
HistoryItem *itemForText() const override;
|
||||
bool hideMessageText() const override;
|
||||
|
||||
void drawHighlight(
|
||||
Painter &p,
|
||||
const PaintContext &context,
|
||||
|
@ -69,7 +72,6 @@ public:
|
|||
const ClickHandlerPtr &p,
|
||||
bool pressed) override;
|
||||
|
||||
TextWithEntities getCaption() const override;
|
||||
void hideSpoilers() override;
|
||||
Storage::SharedMediaTypesMask sharedMediaTypes() const override;
|
||||
|
||||
|
@ -79,14 +81,12 @@ public:
|
|||
HistoryMessageEdited *displayedEditBadge() const override;
|
||||
|
||||
bool skipBubbleTail() const override {
|
||||
return (_mode == Mode::Grid)
|
||||
&& isRoundedInBubbleBottom()
|
||||
&& _caption.isEmpty();
|
||||
return (_mode == Mode::Grid) && isRoundedInBubbleBottom();
|
||||
}
|
||||
void updateNeedBubbleState() override;
|
||||
bool needsBubble() const override;
|
||||
bool customInfoLayout() const override {
|
||||
return _caption.isEmpty() && (_mode != Mode::Column);
|
||||
return (_mode != Mode::Column);
|
||||
}
|
||||
QPoint resolveCustomInfoRightBottom() const override;
|
||||
|
||||
|
@ -143,15 +143,12 @@ private:
|
|||
QPoint point,
|
||||
StateRequest request) const;
|
||||
|
||||
void refreshCaption();
|
||||
|
||||
[[nodiscard]] Ui::BubbleRounding applyRoundingSides(
|
||||
Ui::BubbleRounding already,
|
||||
RectParts sides) const;
|
||||
[[nodiscard]] QMargins groupedPadding() const;
|
||||
|
||||
Ui::Text::String _caption;
|
||||
HistoryItem *_captionItem = nullptr;
|
||||
mutable std::optional<HistoryItem*> _captionItem;
|
||||
std::vector<Part> _parts;
|
||||
Mode _mode = Mode::Grid;
|
||||
bool _needBubble = false;
|
||||
|
|
|
@ -73,9 +73,7 @@ Photo::Photo(
|
|||
, _storyId(realParent->media()
|
||||
? realParent->media()->storyId()
|
||||
: FullStoryId())
|
||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
|
||||
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr) {
|
||||
_caption = createCaption(realParent);
|
||||
create(realParent->fullId());
|
||||
}
|
||||
|
||||
|
@ -161,7 +159,6 @@ void Photo::unloadHeavyPart() {
|
|||
_spoiler->animation = nullptr;
|
||||
}
|
||||
_imageCache = QImage();
|
||||
_caption.unloadPersistentAnimation();
|
||||
togglePollingStory(false);
|
||||
}
|
||||
|
||||
|
@ -184,15 +181,6 @@ QSize Photo::countOptimalSize() {
|
|||
if (_serviceWidth > 0) {
|
||||
return { int(_serviceWidth), int(_serviceWidth) };
|
||||
}
|
||||
|
||||
if (_parent->media() != this) {
|
||||
_caption = Ui::Text::String();
|
||||
} else if (_caption.hasSkipBlock()) {
|
||||
_caption.updateSkipBlock(
|
||||
_parent->skipBlockWidth(),
|
||||
_parent->skipBlockHeight());
|
||||
}
|
||||
|
||||
const auto dimensions = photoSize();
|
||||
const auto scaled = CountDesiredMediaSize(dimensions);
|
||||
const auto minWidth = std::clamp(
|
||||
|
@ -204,12 +192,7 @@ QSize Photo::countOptimalSize() {
|
|||
const auto maxActualWidth = qMax(scaled.width(), minWidth);
|
||||
auto maxWidth = qMax(maxActualWidth, scaled.height());
|
||||
auto minHeight = qMax(scaled.height(), st::minPhotoSize);
|
||||
if (_parent->hasBubble() && !_caption.isEmpty()) {
|
||||
maxWidth = qMax(
|
||||
maxWidth,
|
||||
(st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right()));
|
||||
if (_parent->hasBubble()) {
|
||||
minHeight = adjustHeightForLessCrop(
|
||||
dimensions,
|
||||
{ maxWidth, minHeight });
|
||||
|
@ -217,10 +200,6 @@ QSize Photo::countOptimalSize() {
|
|||
accumulate_max(maxWidth, botTop->maxWidth);
|
||||
minHeight += botTop->height;
|
||||
}
|
||||
minHeight += st::mediaCaptionSkip + _caption.minHeight();
|
||||
if (isBubbleBottom()) {
|
||||
minHeight += st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
return { maxWidth, minHeight };
|
||||
}
|
||||
|
@ -244,10 +223,8 @@ QSize Photo::countCurrentSize(int newWidth) {
|
|||
newWidth = qMax(pix.width(), minWidth);
|
||||
auto newHeight = qMax(pix.height(), st::minPhotoSize);
|
||||
auto imageHeight = newHeight;
|
||||
if (_parent->hasBubble() && !_caption.isEmpty()) {
|
||||
auto captionMaxWidth = st::msgPadding.left()
|
||||
+ _caption.maxWidth()
|
||||
+ st::msgPadding.right();
|
||||
if (_parent->hasBubble()) {
|
||||
auto captionMaxWidth = _parent->textualMaxWidth();
|
||||
const auto botTop = _parent->Get<FakeBotAboutTop>();
|
||||
if (botTop) {
|
||||
accumulate_max(captionMaxWidth, botTop->maxWidth);
|
||||
|
@ -257,16 +234,9 @@ QSize Photo::countCurrentSize(int newWidth) {
|
|||
imageHeight = newHeight = adjustHeightForLessCrop(
|
||||
dimensions,
|
||||
{ newWidth, newHeight });
|
||||
const auto captionw = newWidth
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
if (botTop) {
|
||||
newHeight += botTop->height;
|
||||
}
|
||||
newHeight += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
newHeight += st::msgPadding.bottom();
|
||||
}
|
||||
}
|
||||
const auto enlargeInner = st::historyPageEnlargeSize;
|
||||
const auto enlargeOuter = 2 * st::historyPageEnlargeSkip + enlargeInner;
|
||||
|
@ -309,8 +279,6 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
|
|||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
|
||||
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
|
||||
|
||||
if (displayLoading) {
|
||||
ensureAnimation();
|
||||
if (!_animation->radial.animating()) {
|
||||
|
@ -326,19 +294,8 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
|
|||
} else {
|
||||
const auto rounding = inWebPage
|
||||
? std::optional<Ui::BubbleRounding>()
|
||||
: adjustedBubbleRoundingWithCaption(_caption);
|
||||
if (bubble) {
|
||||
if (!_caption.isEmpty()) {
|
||||
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||
if (botTop) {
|
||||
painth -= botTop->height;
|
||||
}
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
|
||||
}
|
||||
} else {
|
||||
: adjustedBubbleRounding();
|
||||
if (!bubble) {
|
||||
Assert(rounding.has_value());
|
||||
fillImageShadow(p, rthumb, *rounding, context);
|
||||
}
|
||||
|
@ -414,35 +371,7 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
|
|||
}
|
||||
|
||||
// date
|
||||
if (!_caption.isEmpty()) {
|
||||
p.setPen(stm->historyTextFg);
|
||||
_parent->prepareCustomEmojiPaint(p, context, _caption);
|
||||
auto top = painty + painth + st::mediaCaptionSkip;
|
||||
if (botTop) {
|
||||
botTop->text.drawLeftElided(
|
||||
p,
|
||||
st::msgPadding.left(),
|
||||
top,
|
||||
captionw,
|
||||
_parent->width());
|
||||
top += botTop->height;
|
||||
}
|
||||
auto highlightRequest = context.computeHighlightCache();
|
||||
_caption.draw(p, {
|
||||
.position = QPoint(st::msgPadding.left(), top),
|
||||
.availableWidth = captionw,
|
||||
.palette = &stm->textPalette,
|
||||
.pre = stm->preCache.get(),
|
||||
.blockquote = context.quoteCache(parent()->contentColorIndex()),
|
||||
.colors = context.st->highlightColors(),
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = context.now,
|
||||
.pausedEmoji = context.paused || On(PowerSaving::kEmojiChat),
|
||||
.pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler),
|
||||
.selection = context.selection,
|
||||
.highlight = highlightRequest ? &*highlightRequest : nullptr,
|
||||
});
|
||||
} else if (!inWebPage) {
|
||||
if (isBubbleBottom() && !inWebPage) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
if (needInfoDisplay()) {
|
||||
|
@ -682,21 +611,7 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
|
|||
auto paintx = 0, painty = 0, paintw = width(), painth = height();
|
||||
auto bubble = _parent->hasBubble();
|
||||
|
||||
if (bubble && !_caption.isEmpty()) {
|
||||
const auto captionw = paintw
|
||||
- st::msgPadding.left()
|
||||
- st::msgPadding.right();
|
||||
painth -= _caption.countHeight(captionw);
|
||||
if (isBubbleBottom()) {
|
||||
painth -= st::msgPadding.bottom();
|
||||
}
|
||||
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
|
||||
result = TextState(_parent, _caption.getState(
|
||||
point - QPoint(st::msgPadding.left(), painth),
|
||||
captionw,
|
||||
request.forText()));
|
||||
return result;
|
||||
}
|
||||
if (bubble) {
|
||||
if (const auto botTop = _parent->Get<FakeBotAboutTop>()) {
|
||||
painth -= botTop->height;
|
||||
}
|
||||
|
@ -719,7 +634,7 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
|
|||
result.cursor = CursorState::Enlarge;
|
||||
}
|
||||
}
|
||||
if (_caption.isEmpty() && _parent->media() == this) {
|
||||
if (isBubbleBottom() && _parent->media() == this) {
|
||||
auto fullRight = paintx + paintw;
|
||||
auto fullBottom = painty + painth;
|
||||
const auto bottomInfoResult = _parent->bottomInfoTextState(
|
||||
|
@ -746,13 +661,13 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
QSize Photo::sizeForGroupingOptimal(int maxWidth) const {
|
||||
QSize Photo::sizeForGroupingOptimal(int maxWidth, bool last) const {
|
||||
const auto size = photoSize();
|
||||
return { std::max(size.width(), 1), std::max(size.height(), 1)};
|
||||
}
|
||||
|
||||
QSize Photo::sizeForGrouping(int width) const {
|
||||
return sizeForGroupingOptimal(width);
|
||||
return sizeForGroupingOptimal(width, false);
|
||||
}
|
||||
|
||||
void Photo::drawGrouped(
|
||||
|
@ -1094,27 +1009,14 @@ bool Photo::videoAutoplayEnabled() const {
|
|||
_data);
|
||||
}
|
||||
|
||||
TextForMimeData Photo::selectedText(TextSelection selection) const {
|
||||
return _caption.toTextForMimeData(selection);
|
||||
}
|
||||
|
||||
SelectedQuote Photo::selectedQuote(TextSelection selection) const {
|
||||
return Element::FindSelectedQuote(_caption, selection, _realParent);
|
||||
}
|
||||
|
||||
TextSelection Photo::selectionFromQuote(const SelectedQuote "e) const {
|
||||
return Element::FindSelectionFromQuote(_caption, quote);
|
||||
}
|
||||
|
||||
void Photo::hideSpoilers() {
|
||||
_caption.setSpoilerRevealed(false, anim::type::instant);
|
||||
if (_spoiler) {
|
||||
_spoiler->revealed = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Photo::needsBubble() const {
|
||||
if (_storyId || !_caption.isEmpty()) {
|
||||
if (_storyId) {
|
||||
return true;
|
||||
}
|
||||
const auto item = _parent->data();
|
||||
|
@ -1122,6 +1024,7 @@ bool Photo::needsBubble() const {
|
|||
&& (item->repliesAreComments()
|
||||
|| item->externalReply()
|
||||
|| item->viaBot()
|
||||
|| !item->emptyText()
|
||||
|| _parent->displayReply()
|
||||
|| _parent->displayForwardedFrom()
|
||||
|| _parent->displayFromName()
|
||||
|
@ -1139,13 +1042,6 @@ bool Photo::isReadyForOpen() const {
|
|||
return _dataMedia->loaded();
|
||||
}
|
||||
|
||||
void Photo::parentTextUpdated() {
|
||||
_caption = (_parent->media() == this)
|
||||
? createCaption(_parent->data())
|
||||
: Ui::Text::String();
|
||||
history()->owner().requestViewResize(_parent);
|
||||
}
|
||||
|
||||
void Photo::showPhoto(FullMsgId id) {
|
||||
_parent->delegate()->elementOpenPhoto(_data, id);
|
||||
}
|
||||
|
|
|
@ -41,26 +41,13 @@ public:
|
|||
int width);
|
||||
~Photo();
|
||||
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
[[nodiscard]] TextSelection adjustSelection(
|
||||
TextSelection selection,
|
||||
TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
|
||||
TextForMimeData selectedText(TextSelection selection) const override;
|
||||
SelectedQuote selectedQuote(TextSelection selection) const override;
|
||||
TextSelection selectionFromQuote(
|
||||
const SelectedQuote "e) const override;
|
||||
|
||||
PhotoData *getPhoto() const override {
|
||||
return _data;
|
||||
}
|
||||
|
@ -71,7 +58,7 @@ public:
|
|||
QPoint photoPosition,
|
||||
bool markFrameShown) const;
|
||||
|
||||
QSize sizeForGroupingOptimal(int maxWidth) const override;
|
||||
QSize sizeForGroupingOptimal(int maxWidth, bool last) const override;
|
||||
QSize sizeForGrouping(int width) const override;
|
||||
void drawGrouped(
|
||||
Painter &p,
|
||||
|
@ -88,22 +75,17 @@ public:
|
|||
QPoint point,
|
||||
StateRequest request) const override;
|
||||
|
||||
TextWithEntities getCaption() const override {
|
||||
return _caption.toTextWithEntities();
|
||||
}
|
||||
void hideSpoilers() override;
|
||||
bool needsBubble() const override;
|
||||
bool customInfoLayout() const override {
|
||||
return _caption.isEmpty();
|
||||
return true;
|
||||
}
|
||||
QPoint resolveCustomInfoRightBottom() const override;
|
||||
bool skipBubbleTail() const override {
|
||||
return isRoundedInBubbleBottom() && _caption.isEmpty();
|
||||
return isRoundedInBubbleBottom();
|
||||
}
|
||||
bool isReadyForOpen() const override;
|
||||
|
||||
void parentTextUpdated() override;
|
||||
|
||||
bool hasHeavyPart() const override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
|
@ -168,7 +150,6 @@ private:
|
|||
|
||||
const not_null<PhotoData*> _data;
|
||||
const FullStoryId _storyId;
|
||||
Ui::Text::String _caption;
|
||||
mutable std::shared_ptr<Data::PhotoMedia> _dataMedia;
|
||||
mutable std::unique_ptr<Streamed> _streamed;
|
||||
const std::unique_ptr<MediaSpoiler> _spoiler;
|
||||
|
|
|
@ -35,6 +35,9 @@ public:
|
|||
void draw(Painter &p, const PaintContext &context) const override;
|
||||
TextState textState(QPoint point, StateRequest request) const override;
|
||||
|
||||
bool aboveTextByDefault() const override {
|
||||
return false;
|
||||
}
|
||||
bool hideMessageText() const override {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue