From b9af4f3cb061ce183cd4f3e6c3c2f04dc9be8a31 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 17 Oct 2023 10:19:58 +0400 Subject: [PATCH] Show nice replies with quotes. --- Telegram/SourceFiles/data/data_peer.cpp | 1 + .../SourceFiles/data/data_reply_preview.cpp | 10 +- Telegram/SourceFiles/history/history_item.cpp | 1 + .../history/history_item_components.cpp | 203 ++++++++++-------- .../history/history_item_components.h | 9 +- .../SourceFiles/history/history_widget.cpp | 41 ++-- .../history_view_compose_controls.cpp | 38 ++-- .../controls/history_view_forward_panel.cpp | 11 +- .../history/view/history_view_message.cpp | 78 +++---- .../history/view/media/history_view_gif.cpp | 52 +++-- .../media/history_view_media_unwrapped.cpp | 56 +++-- .../view/media/history_view_media_unwrapped.h | 3 +- Telegram/SourceFiles/ui/chat/chat.style | 8 +- Telegram/SourceFiles/ui/chat/chat_style.cpp | 4 + Telegram/SourceFiles/ui/chat/message_bar.cpp | 11 +- 15 files changed, 285 insertions(+), 241 deletions(-) diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 76652a672..66e693c13 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "window/main_window.h" // Window::LogoNoMargin. #include "ui/image/image.h" +#include "ui/chat/chat_style.h" #include "ui/empty_userpic.h" #include "ui/text/text_options.h" #include "ui/painter.h" diff --git a/Telegram/SourceFiles/data/data_reply_preview.cpp b/Telegram/SourceFiles/data/data_reply_preview.cpp index 2bf667be4..e31f30f38 100644 --- a/Telegram/SourceFiles/data/data_reply_preview.cpp +++ b/Telegram/SourceFiles/data/data_reply_preview.cpp @@ -40,14 +40,14 @@ void ReplyPreview::prepare( if (h <= 0) h = 1; auto thumbSize = (w > h) ? QSize( - w * st::msgReplyBarSize.height() / h, - st::msgReplyBarSize.height()) + w * st::historyReplyPreview / h, + st::historyReplyPreview) : QSize( - st::msgReplyBarSize.height(), - h * st::msgReplyBarSize.height() / w); + st::historyReplyPreview, + h * st::historyReplyPreview / w); thumbSize *= style::DevicePixelRatio(); options |= Option::TransparentBackground; - auto outerSize = st::msgReplyBarSize.height(); + auto outerSize = st::historyReplyPreview; auto original = spoiler ? image->original().scaled( { 40, 40 }, diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 5ac0a761c..55ff76fa2 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -3305,6 +3305,7 @@ void HistoryItem::createComponentsHelper( config.reply.topicPost = LookupReplyIsTopicPost(to) || (to && to->Has()) || (forum && forum->creating(config.reply.topMessageId)); + config.reply.quote = std::move(replyTo.quote); } config.markup = std::move(markup); if (flags & MessageFlag::HasPostAuthor) config.postAuthor = postAuthor; diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 11fcddf29..f90e4ca79 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -570,31 +570,32 @@ void HistoryMessageReply::updateName( std::optional resolvedSender) const { const auto peer = resolvedSender.value_or(sender(holder)); const auto name = peer ? senderName(peer) : senderName(holder); + const auto hasPreview = (resolvedStory + && resolvedStory->hasReplyPreview()) + || (resolvedMessage + && resolvedMessage->media() + && resolvedMessage->media()->hasReplyPreview()); + const auto textLeft = hasPreview + ? (st::messageQuoteStyle.outline + + st::historyReplyPreviewMargin.left() + + st::historyReplyPreview + + st::historyReplyPreviewMargin.right()) + : st::historyReplyPadding.left(); if (!name.isEmpty()) { _name.setText(st::fwdTextStyle, name, Ui::NameTextOptions()); if (peer) { _nameVersion = peer->nameVersion(); } - bool hasPreview = (resolvedStory - && resolvedStory->hasReplyPreview()) - || (resolvedMessage - && resolvedMessage->media() - && resolvedMessage->media()->hasReplyPreview()); - int32 previewSkip = hasPreview - ? (st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x()) - : 0; - int32 w = _name.maxWidth(); - if (originalVia) { - w += st::msgServiceFont->spacew + originalVia->maxWidth; - } - - _maxWidth = previewSkip - + std::max( - w, - std::min(_text.maxWidth(), st::maxSignatureSize)) + const auto w = _name.maxWidth() + + (originalVia + ? (st::msgServiceFont->spacew + originalVia->maxWidth) + : 0) + + (_fields.quote.empty() + ? 0 + : st::messageTextStyle.blockquote.icon.width()); + _maxWidth = std::max( + w, + std::min(_text.maxWidth(), st::maxSignatureSize)) + (_fields.storyId ? (st::dialogsMiniReplyStory.skipText + st::dialogsMiniReplyStory.icon.icon.width()) @@ -602,31 +603,48 @@ void HistoryMessageReply::updateName( } else { _maxWidth = st::msgDateFont->width(statePhrase()); } - _maxWidth = st::msgReplyPadding.left() - + st::msgReplyBarSkip + _maxWidth = textLeft + _maxWidth - + st::msgReplyPadding.right(); + + st::historyReplyPadding.right(); + _minHeight = st::historyReplyPadding.top() + + st::msgServiceNameFont->height + + st::normalFont->height + + st::historyReplyPadding.bottom(); } -void HistoryMessageReply::resize(int width) const { +int HistoryMessageReply::resizeToWidth(int width) const { + const auto hasPreview = (resolvedStory + && resolvedStory->hasReplyPreview()) + || (resolvedMessage + && resolvedMessage->media() + && resolvedMessage->media()->hasReplyPreview()); + const auto textLeft = hasPreview + ? (st::messageQuoteStyle.outline + + st::historyReplyPreviewMargin.left() + + st::historyReplyPreview + + st::historyReplyPreviewMargin.right()) + : st::historyReplyPadding.left(); if (originalVia) { - bool hasPreview = (resolvedStory - && resolvedStory->hasReplyPreview()) - || (resolvedMessage - && resolvedMessage->media() - && resolvedMessage->media()->hasReplyPreview()); - int previewSkip = hasPreview - ? (st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x()) - : 0; originalVia->resize(width - - st::msgReplyBarSkip - - previewSkip + - textLeft + - st::historyReplyPadding.right() - _name.maxWidth() - st::msgServiceFont->spacew); } + if (width >= _maxWidth) { + _height = _minHeight; + return height(); + } + _height = _minHeight; + return height(); +} + +int HistoryMessageReply::height() const { + return _height + st::historyReplyTop + st::historyReplyBottom; +} + +QMargins HistoryMessageReply::margins() const { + return QMargins(0, st::historyReplyTop, 0, st::historyReplyBottom); } void HistoryMessageReply::itemRemoved( @@ -658,58 +676,66 @@ void HistoryMessageReply::paint( const auto st = context.st; const auto stm = context.messageStyle(); - { - const auto opacity = p.opacity(); - const auto outerWidth = w + 2 * x; - const auto &bar = !inBubble - ? st->msgImgReplyBarColor() - : _colorIndexPlusOne - ? HistoryView::FromNameFg(context, _colorIndexPlusOne - 1) - : stm->msgReplyBarColor; - const auto rbar = style::rtlrect( - x + st::msgReplyBarPos.x(), - y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), - st::msgReplyBarSize.width(), - st::msgReplyBarSize.height(), - outerWidth); - - if (ripple.animation) { - const auto colorOverride = &stm->msgWaveformInactive->c; - p.setOpacity(st::historyPollRippleOpacity); - ripple.animation->paint( - p, - x - st::msgReplyPadding.left(), - y, - outerWidth, - colorOverride); - if (ripple.animation->empty()) { - ripple.animation.reset(); - } - } - - p.setOpacity(opacity * kBarAlpha); - p.fillRect(rbar, bar); - p.setOpacity(opacity); + y += st::historyReplyTop; + const auto rect = QRect(x, y, w, _height); + const auto hasQuote = !_fields.quote.empty(); + const auto selected = context.selected(); + const auto cache = !inBubble + ? (hasQuote + ? st->serviceQuoteCache() + : st->serviceReplyCache()).get() + : _colorIndexPlusOne + ? (hasQuote + ? st->coloredQuoteCache(selected, _colorIndexPlusOne - 1) + : st->coloredReplyCache(selected, _colorIndexPlusOne - 1)).get() + : (hasQuote ? stm->quoteCache : stm->replyCache).get(); + const auto "eSt = hasQuote + ? st::messageTextStyle.blockquote + : st::messageQuoteStyle; + const auto rippleColor = cache->bg; + if (!inBubble) { + cache->bg = QColor(0, 0, 0, 0); + } + Ui::Text::ValidateQuotePaintCache(*cache, quoteSt); + Ui::Text::FillQuotePaint(p, rect, *cache, quoteSt); + if (!inBubble) { + cache->bg = rippleColor; } + if (ripple.animation) { + ripple.animation->paint(p, x, y, w, &rippleColor); + if (ripple.animation->empty()) { + ripple.animation.reset(); + } + } + + const auto withPreviewLeft = st::messageQuoteStyle.outline + + st::historyReplyPreviewMargin.left() + + st::historyReplyPreview + + st::historyReplyPreviewMargin.right(); + auto textLeft = st::historyReplyPadding.left(); const auto pausedSpoiler = context.paused || On(PowerSaving::kChatSpoiler); - if (w > st::msgReplyBarSkip) { + if (w > textLeft) { if (resolvedMessage || resolvedStory || !_text.isEmpty()) { const auto media = resolvedMessage ? resolvedMessage->media() : nullptr; auto hasPreview = (media && media->hasReplyPreview()) || (resolvedStory && resolvedStory->hasReplyPreview()); - if (hasPreview && w < st::msgReplyBarSkip + st::msgReplyBarSize.height()) { + if (hasPreview && w <= withPreviewLeft) { hasPreview = false; } - auto previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; - if (hasPreview) { + textLeft = withPreviewLeft; const auto image = media ? media->replyPreview() : resolvedStory->replyPreview(); if (image) { - auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x); + auto to = style::rtlrect( + x + st::historyReplyPreviewMargin.left(), + y + st::historyReplyPreviewMargin.top(), + st::historyReplyPreview, + st::historyReplyPreview, + w + 2 * x); const auto preview = image->pixSingle( image->size() / style::DevicePixelRatio(), { @@ -732,7 +758,8 @@ void HistoryMessageReply::paint( } } } - if (w > st::msgReplyBarSkip + previewSkip) { + if (w > textLeft + st::historyReplyPadding.right()) { + w -= textLeft + st::historyReplyPadding.right(); p.setPen(!inBubble ? st->msgImgReplyBarColor() : _colorIndexPlusOne @@ -740,10 +767,10 @@ void HistoryMessageReply::paint( context, _colorIndexPlusOne - 1) : stm->msgServiceFg); - _name.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x); - if (originalVia && w > st::msgReplyBarSkip + previewSkip + _name.maxWidth() + st::msgServiceFont->spacew) { + _name.drawLeftElided(p, x + textLeft, y + st::historyReplyPadding.top(), w, w + 2 * x + 2 * textLeft); + if (originalVia && w > _name.maxWidth() + st::msgServiceFont->spacew) { p.setFont(st::msgServiceFont); - p.drawText(x + st::msgReplyBarSkip + previewSkip + _name.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, originalVia->text); + p.drawText(x + textLeft + _name.maxWidth() + st::msgServiceFont->spacew, y + st::historyReplyPadding.top() + st::msgServiceFont->ascent, originalVia->text); } p.setPen(inBubble @@ -751,8 +778,8 @@ void HistoryMessageReply::paint( : st->msgImgReplyBarColor()); holder->prepareCustomEmojiPaint(p, context, _text); auto replyToTextPosition = QPoint( - x + st::msgReplyBarSkip + previewSkip, - y + st::msgReplyPadding.top() + st::msgServiceNameFont->height); + x + textLeft, + y + st::historyReplyPadding.top() + st::msgServiceNameFont->height); const auto replyToTextPalette = &(inBubble ? stm->replyTextPalette : st->imgReplyTextPalette()); @@ -760,7 +787,7 @@ void HistoryMessageReply::paint( st::dialogsMiniReplyStory.icon.icon.paint( p, replyToTextPosition, - w - st::msgReplyBarSkip - previewSkip, + w + 2 * x + 2 * textLeft, replyToTextPalette->linkFg->c); replyToTextPosition += QPoint( st::dialogsMiniReplyStory.skipText @@ -769,7 +796,7 @@ void HistoryMessageReply::paint( } _text.draw(p, { .position = replyToTextPosition, - .availableWidth = w - st::msgReplyBarSkip - previewSkip, + .availableWidth = w, .palette = replyToTextPalette, .spoiler = Ui::Text::DefaultSpoilerCache(), .now = context.now, @@ -782,10 +809,14 @@ void HistoryMessageReply::paint( } } else { p.setFont(st::msgDateFont); - p.setPen(inBubble - ? stm->msgDateFg - : st->msgDateImgFg()); - p.drawTextLeft(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2, w + 2 * x, st::msgDateFont->elided(statePhrase(), w - st::msgReplyBarSkip)); + p.setPen(cache->outline); + p.drawTextLeft( + x + textLeft, + (y + (_height - st::msgDateFont->height) / 2), + w + 2 * x + 2 * textLeft, + st::msgDateFont->elided( + statePhrase(), + w - textLeft - st::historyReplyPadding.right())); } } } diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 1f10c733d..c632b5b07 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -273,7 +273,9 @@ struct HistoryMessageReply void updateName( not_null holder, std::optional resolvedSender = std::nullopt) const; - void resize(int width) const; + [[nodiscard]] int resizeToWidth(int width) const; + [[nodiscard]] int height() const; + [[nodiscard]] QMargins margins() const; void itemRemoved( not_null holder, not_null removed); @@ -325,7 +327,6 @@ struct HistoryMessageReply ReplyToStoryPointer resolvedStory; std::unique_ptr originalVia; std::unique_ptr spoiler; - int toWidth = 0; struct { mutable std::unique_ptr animation; @@ -339,8 +340,10 @@ private: mutable Ui::Text::String _text; mutable PeerData *_externalSender = nullptr; mutable int _maxWidth = 0; + mutable int _minHeight = 0; + mutable int _height = 0; mutable int _nameVersion = 0; - uint8 _colorIndexPlusOne : 7 = 0; + uint8 _colorIndexPlusOne : 6 = 0; uint8 _unavailable : 1 = 0; }; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c8d72b6e1..d53cdbd8a 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -4352,9 +4352,11 @@ void HistoryWidget::updateOverStates(QPoint pos) { && _photoEditMedia && QRect( replyEditForwardInfoRect.x(), - replyEditForwardInfoRect.y() + st::msgReplyPadding.top(), - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()).contains(pos); + (replyEditForwardInfoRect.y() + + (replyEditForwardInfoRect.height() + - st::historyReplyPreview) / 2), + st::historyReplyPreview, + st::historyReplyPreview).contains(pos); auto inClickable = inReplyEditForward; if (_inPhotoEdit != inPhotoEdit) { _inPhotoEdit = inPhotoEdit; @@ -7809,7 +7811,9 @@ void HistoryWidget::updateReplyEditText(not_null item) { }; _replyEditMsgText.setMarkedText( st::defaultTextStyle, - item->inReplyText(), + ((_editMsgId || _replyTo.quote.empty()) + ? item->inReplyText() + : _replyTo.quote), Ui::DialogTextOptions(), context); if (fieldOrDisabledShown() || isRecording()) { @@ -7956,7 +7960,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { const auto overEdit = _photoEditMedia ? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.) : 0.; - auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); + auto to = QRect( + replyLeft, + backy + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); p.drawPixmap(to.x(), to.y(), preview->pixSingle( preview->size() / style::DevicePixelRatio(), { @@ -7980,7 +7988,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { p.setOpacity(1.); } } - replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); + replyLeft += st::historyReplyPreview + st::msgReplyBarSkip; } p.setPen(st::historyReplyNameFg); if (_editMsgId) { @@ -8004,7 +8012,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { } else { p.setFont(st::msgDateFont); p.setPen(st::historyComposeAreaFgService); - p.drawText(replyLeft, backy + st::msgReplyPadding.top() + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right())); + p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right())); } } } else if (hasForward) { @@ -8020,24 +8028,15 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { } if (drawWebPagePreview) { const auto textTop = backy + st::msgReplyPadding.top(); - auto previewLeft = st::historyReplySkip + st::webPageLeft; - p.fillRect( - st::historyReplySkip, - textTop, - st::webPageBar, - st::msgReplyBarSize.height(), - st::msgInReplyBarColor); + auto previewLeft = st::historyReplySkip; const auto to = QRect( previewLeft, - textTop, - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()); + backy + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); if (HistoryView::DrawWebPageDataPreview(p, _previewData, _peer, to)) { - previewLeft += st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x(); + previewLeft += st::historyReplyPreview + st::msgReplyBarSkip; } p.setPen(st::historyReplyNameFg); const auto elidedWidth = width() diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 0e793b955..b5de792b1 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -776,23 +776,14 @@ void FieldHeader::paintWebPage(Painter &p, not_null context) { const auto textTop = st::msgReplyPadding.top(); auto previewLeft = st::historyReplySkip + st::webPageLeft; - p.fillRect( - st::historyReplySkip, - textTop, - st::webPageBar, - st::msgReplyBarSize.height(), - st::msgInReplyBarColor); const QRect to( previewLeft, - textTop, - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()); + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); if (HistoryView::DrawWebPageDataPreview(p, _preview.data, context, to)) { - previewLeft += st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x(); + previewLeft += st::historyReplyPreview + st::msgReplyBarSkip; } const auto elidedWidth = width() - previewLeft @@ -826,8 +817,7 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) { if (!_shownMessage) { p.setFont(st::msgDateFont); p.setPen(st::historyComposeAreaFgService); - const auto top = (st::msgReplyPadding.top() - + (st::msgReplyBarSize.height() - st::msgDateFont->height) / 2); + const auto top = (st::historyReplyHeight - st::msgDateFont->height) / 2; p.drawText( replySkip, top + st::msgDateFont->ascent, @@ -863,10 +853,8 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) { update(); }); } - const auto previewSkipValue = st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x(); + const auto previewSkipValue = st::historyReplyPreview + + st::msgReplyBarSkip; const auto previewSkip = _shownMessageHasPreview ? previewSkipValue : 0; const auto textLeft = replySkip + previewSkip; const auto textAvailableWidth = availableWidth - previewSkip; @@ -876,9 +864,9 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) { : 0.; const auto to = QRect( replySkip, - st::msgReplyPadding.top(), - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()); + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); p.drawPixmap(to.x(), to.y(), preview->pixSingle( preview->size() / style::DevicePixelRatio(), { @@ -999,9 +987,9 @@ void FieldHeader::updateControlsGeometry(QSize size) { height()); _shownMessagePreviewRect = QRect( st::historyReplySkip, - st::msgReplyPadding.top(), - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()); + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); } void FieldHeader::editMessage(FullMsgId id, bool photoEditAllowed) { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp index 6e9bb5903..f89cfa9e1 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_forward_panel.cpp @@ -362,9 +362,9 @@ void ForwardPanel::paint( if (preview) { auto to = QRect( x, - y + st::msgReplyPadding.top(), - st::msgReplyBarSize.height(), - st::msgReplyBarSize.height()); + y + (st::historyReplyHeight - st::historyReplyPreview) / 2, + st::historyReplyPreview, + st::historyReplyPreview); p.drawPixmap(to.x(), to.y(), preview->pixSingle( preview->size() / style::DevicePixelRatio(), { @@ -375,10 +375,7 @@ void ForwardPanel::paint( Ui::FillSpoilerRect(p, to, Ui::DefaultImageSpoiler().frame( _spoiler->index(now, pausedSpoiler))); } - const auto skip = st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x(); + const auto skip = st::historyReplyPreview + st::msgReplyBarSkip; x += skip; available -= skip; } diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 60d18d46a..384c8bae6 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -776,9 +776,12 @@ QSize Message::performCountOptimalSize() { accumulate_max(maxWidth, namew); } if (reply) { - auto replyw = st::msgPadding.left() + reply->maxWidth() - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); + auto replyw = st::msgPadding.left() + + reply->maxWidth() + + st::msgPadding.right(); if (reply->originalVia) { - replyw += st::msgServiceFont->spacew + reply->originalVia->maxWidth; + replyw += st::msgServiceFont->spacew + + reply->originalVia->maxWidth; } accumulate_max(maxWidth, replyw); } @@ -1558,9 +1561,8 @@ void Message::paintReplyInfo( QRect &trect, const PaintContext &context) const { if (const auto reply = displayedReply()) { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); reply->paint(p, this, context, trect.x(), trect.y(), trect.width(), true); - trect.setY(trect.y() + h); + trect.setY(trect.y() + reply->height()); } } @@ -1761,41 +1763,18 @@ void Message::toggleReplyRipple(bool pressed) { if (pressed) { if (!reply->ripple.animation && !unwrapped()) { - const auto smallTop = displayFromName() - || displayedTopicButton() - || displayForwardedFrom(); - const auto rounding = countBubbleRounding(); - - using Corner = Ui::BubbleCornerRounding; - using Radius = Ui::CachedCornerRadius; - const auto &small = Ui::CachedCornersMasks(Radius::ThumbSmall); - const auto &large = Ui::CachedCornersMasks(Radius::ThumbLarge); - const auto corners = std::array{{ - ((smallTop || (rounding.topLeft == Corner::Small)) - ? small - : large)[0], - ((smallTop || (rounding.topRight == Corner::Small)) - ? small - : large)[1], - small[2], - small[3], - }}; - - const auto &padding = st::msgReplyPadding; + const auto &padding = st::msgPadding; const auto geometry = countGeometry(); const auto item = data(); + const auto margins = reply->margins(); const auto size = QSize( - geometry.width() - - padding.left() / 2 - - padding.right(), - st::msgReplyBarSize.height() - + padding.top() - + padding.bottom()); + geometry.width() - padding.left() - padding.right(), + reply->height() - margins.top() - margins.bottom()); reply->ripple.animation = std::make_unique( st::defaultRippleAnimation, - Images::Round( - Ui::RippleAnimation::MaskByDrawer(size, true, nullptr), - corners), + Ui::RippleAnimation::RoundRectMask( + size, + st::messageQuoteStyle.radius), [=] { item->history()->owner().requestItemRepaint(item); }); } if (reply->ripple.animation) { @@ -2436,14 +2415,15 @@ bool Message::getStateReplyInfo( QPoint point, QRect &trect, not_null outResult) const { - if (auto reply = displayedReply()) { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - if (point.y() >= trect.top() && point.y() < trect.top() + h) { + if (const auto reply = displayedReply()) { + const auto margins = reply->margins(); + const auto height = reply->height(); + if (point.y() >= trect.top() && point.y() < trect.top() + height) { const auto g = QRect( trect.x(), - trect.y() + st::msgReplyPadding.top(), + trect.y() + margins.top(), trect.width(), - st::msgReplyBarSize.height()); + height - margins.top() - margins.bottom()); if (g.contains(point)) { if (const auto link = reply->link()) { outResult->link = reply->link(); @@ -2452,7 +2432,7 @@ bool Message::getStateReplyInfo( } return true; } - trect.setTop(trect.top() + h); + trect.setTop(trect.top() + height); } return false; } @@ -2530,9 +2510,8 @@ void Message::updatePressed(QPoint point) { auto fwdheight = ((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; trect.setTop(trect.top() + fwdheight); } - if (item->Get()) { - auto h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - trect.setTop(trect.top() + h); + if (const auto reply = item->Get()) { + trect.setTop(trect.top() + reply->height()); } if (const auto via = item->Get()) { if (!displayFromName() && !displayForwardedFrom()) { @@ -3642,13 +3621,9 @@ QRect Message::innerGeometry() const { + st::topicButtonSkip); } // Skip displayForwardedFrom() until there are no animations for it. - if (displayedReply()) { + if (const auto reply = displayedReply()) { // See paintReplyInfo(). - result.translate( - 0, - st::msgReplyPadding.top() - + st::msgReplyBarSize.height() - + st::msgReplyPadding.bottom()); + result.translate(0, reply->height()); } if (!displayFromName() && !displayForwardedFrom()) { // See paintViaBotIdInfo(). @@ -3900,9 +3875,10 @@ int Message::resizeContentGetHeight(int newWidth) { } if (reply) { - reply->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right()); + newHeight += reply->resizeToWidth(contentWidth + - st::msgPadding.left() + - st::msgPadding.right()); reply->ripple.animation = nullptr; - newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); } if (needInfoDisplay()) { newHeight += (bottomInfoHeight - st::msgDateFont->height); diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 04a168852..f30a8d550 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -286,7 +286,7 @@ QSize Gif::countCurrentSize(int newWidth) { via->resize(availw); } if (reply) { - reply->resize(availw); + [[maybe_unused]] int height = reply->resizeToWidth(availw); } } } @@ -652,16 +652,21 @@ void Gif::draw(Painter &p, const PaintContext &context) const { if (via || reply || forwarded) { auto rectw = width() - usew - st::msgReplyPadding.left(); auto innerw = rectw - (st::msgReplyPadding.left() + st::msgReplyPadding.right()); - auto recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); + auto recth = 0; auto forwardedHeightReal = forwarded ? forwarded->text.countHeight(innerw) : 0; auto forwardedHeight = qMin(forwardedHeightReal, kMaxGifForwardedBarLines * st::msgServiceNameFont->height); if (forwarded) { - recth += forwardedHeight; + recth += st::msgReplyPadding.top() + forwardedHeight; } else if (via) { - recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); + recth += st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); } if (reply) { - recth += st::msgReplyBarSize.height(); + const auto replyMargins = reply->margins(); + recth += reply->height() + - ((forwarded || via) ? 0 : replyMargins.top()) + - replyMargins.bottom(); + } else { + recth += st::msgReplyPadding.bottom(); } int rectx = rightAligned ? 0 : (usew + st::msgReplyPadding.left()); int recty = painty; @@ -669,25 +674,31 @@ void Gif::draw(Painter &p, const PaintContext &context) const { Ui::FillRoundRect(p, rectx, recty, rectw, recth, sti->msgServiceBg, sti->msgServiceBgCornersSmall); p.setPen(st->msgServiceFg()); - rectx += st::msgReplyPadding.left(); - rectw = innerw; + const auto textx = rectx + st::msgReplyPadding.left(); + const auto textw = rectw - st::msgReplyPadding.left() - st::msgReplyPadding.right(); if (forwarded) { p.setTextPalette(st->serviceTextPalette()); auto breakEverywhere = (forwardedHeightReal > forwardedHeight); - forwarded->text.drawElided(p, rectx, recty + st::msgReplyPadding.top(), rectw, kMaxGifForwardedBarLines, style::al_left, 0, -1, 0, breakEverywhere); + forwarded->text.drawElided(p, textx, recty + st::msgReplyPadding.top(), textw, kMaxGifForwardedBarLines, style::al_left, 0, -1, 0, breakEverywhere); p.restoreTextPalette(); const auto skip = std::min( - forwarded->text.countHeight(rectw), + forwarded->text.countHeight(textw), kMaxGifForwardedBarLines * st::msgServiceNameFont->height); recty += skip; } else if (via) { p.setFont(st::msgServiceNameFont); - p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * rectx + rectw, via->text); + p.drawTextLeft(textx, recty + st::msgReplyPadding.top(), 2 * textx + textw, via->text); int skip = st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); recty += skip; } if (reply) { + if (forwarded || via) { + recty += st::msgReplyPadding.top(); + recth -= st::msgReplyPadding.top(); + } else { + recty -= reply->margins().top(); + } reply->paint(p, _parent, context, rectx, recty, rectw, false); } } @@ -1019,16 +1030,21 @@ TextState Gif::textState(QPoint point, StateRequest request) const { if (via || reply || forwarded) { auto rectw = paintw - usew - st::msgReplyPadding.left(); auto innerw = rectw - (st::msgReplyPadding.left() + st::msgReplyPadding.right()); - auto recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); + auto recth = 0; auto forwardedHeightReal = forwarded ? forwarded->text.countHeight(innerw) : 0; auto forwardedHeight = qMin(forwardedHeightReal, kMaxGifForwardedBarLines * st::msgServiceNameFont->height); if (forwarded) { - recth += forwardedHeight; + recth += st::msgReplyPadding.top() + forwardedHeight; } else if (via) { - recth += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); + recth += st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); } if (reply) { - recth += st::msgReplyBarSize.height(); + const auto replyMargins = reply->margins(); + recth += reply->height() + - ((forwarded || via) ? 0 : replyMargins.top()) + - replyMargins.bottom(); + } else { + recth += st::msgReplyPadding.bottom(); } auto rectx = rightAligned ? 0 : (usew + st::msgReplyPadding.left()); auto recty = painty; @@ -1067,6 +1083,12 @@ TextState Gif::textState(QPoint point, StateRequest request) const { recth -= skip; } if (reply) { + if (forwarded || via) { + recty += st::msgReplyPadding.top(); + recth -= st::msgReplyPadding.top() + reply->margins().top(); + } else { + recty -= reply->margins().top(); + } const auto replyRect = QRect(rectx, recty, rectw, recth); if (replyRect.contains(point)) { result.link = reply->link(); @@ -1076,7 +1098,7 @@ TextState Gif::textState(QPoint point, StateRequest request) const { st::defaultRippleAnimation, Ui::RippleAnimation::RoundRectMask( replyRect.size(), - st::roundRadiusSmall), + st::messageQuoteStyle.radius), [=] { item->history()->owner().requestItemRepaint(item); }); } return result; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp index 4f5e9a5c5..413046ed3 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.cpp @@ -123,7 +123,7 @@ QSize UnwrappedMedia::countCurrentSize(int newWidth) { via->resize(availw); } if (reply) { - reply->resize(availw); + [[maybe_unused]] int height = reply->resizeToWidth(availw); } } return { newWidth, newHeight }; @@ -211,11 +211,16 @@ UnwrappedMedia::SurroundingInfo UnwrappedMedia::surroundingInfo( panelHeight += st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); } - if (reply) { - panelHeight += st::msgReplyBarSize.height(); - } if (panelHeight) { - panelHeight += st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); + panelHeight += st::msgReplyPadding.top(); + } + if (reply) { + const auto replyMargins = reply->margins(); + panelHeight += reply->height() + - ((forwarded || via) ? 0 : replyMargins.top()) + - replyMargins.bottom(); + } else { + panelHeight += st::msgReplyPadding.bottom(); } const auto total = (topicSize.isEmpty() ? 0 : topicSize.height()) + ((panelHeight || !topicSize.height()) ? st::topicButtonSkip : 0) @@ -303,26 +308,32 @@ void UnwrappedMedia::drawSurrounding( Ui::FillRoundRect(p, rectx, recty, rectw, recth, sti->msgServiceBg, sti->msgServiceBgCornersSmall); p.setPen(st->msgServiceFg()); - rectx += st::msgReplyPadding.left(); - rectw -= st::msgReplyPadding.left() + st::msgReplyPadding.right(); + const auto textx = rectx + st::msgReplyPadding.left(); + const auto textw = rectw - st::msgReplyPadding.left() - st::msgReplyPadding.right(); if (forwarded) { p.setTextPalette(st->serviceTextPalette()); - forwarded->text.drawElided(p, rectx, recty + st::msgReplyPadding.top(), rectw, kMaxForwardedBarLines, style::al_left, 0, -1, 0, surrounding.forwardedBreakEverywhere); + forwarded->text.drawElided(p, textx, recty + st::msgReplyPadding.top(), textw, kMaxForwardedBarLines, style::al_left, 0, -1, 0, surrounding.forwardedBreakEverywhere); p.restoreTextPalette(); const auto skip = std::min( - forwarded->text.countHeight(rectw), + forwarded->text.countHeight(textw), kMaxForwardedBarLines * st::msgServiceNameFont->height); recty += skip; } else if (via) { p.setFont(st::msgDateFont); - p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * rectx + rectw, via->text); + p.drawTextLeft(rectx, recty + st::msgReplyPadding.top(), 2 * textx + textw, via->text); const auto skip = st::msgServiceNameFont->height + (reply ? st::msgReplyPadding.top() : 0); recty += skip; } if (reply) { + if (forwarded || via) { + recty += st::msgReplyPadding.top(); + recth -= st::msgReplyPadding.top(); + } else { + recty -= reply->margins().top(); + } reply->paint(p, _parent, context, rectx, recty, rectw, false); } replyRight = rectx + rectw; @@ -330,8 +341,9 @@ void UnwrappedMedia::drawSurrounding( } if (rightActionSize) { const auto position = calculateFastActionPosition( - fullBottom, replyRight, + reply ? reply->height() : 0, + fullBottom, fullRight, *rightActionSize); const auto outer = 2 * inner.x() + inner.width(); @@ -462,6 +474,12 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const { recth -= skip; } if (reply) { + if (forwarded || via) { + recty += st::msgReplyPadding.top(); + recth -= st::msgReplyPadding.top() + reply->margins().top(); + } else { + recty -= reply->margins().top(); + } const auto replyRect = QRect(rectx, recty, rectw, recth); if (replyRect.contains(point)) { result.link = reply->link(); @@ -471,7 +489,7 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const { st::defaultRippleAnimation, Ui::RippleAnimation::RoundRectMask( replyRect.size(), - st::roundRadiusSmall), + st::messageQuoteStyle.radius), [=] { item->history()->owner().requestItemRepaint(item); }); } return result; @@ -495,8 +513,9 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const { } if (rightActionSize) { const auto position = calculateFastActionPosition( - fullBottom, replyRight, + reply ? reply->height() : 0, + fullBottom, fullRight, *rightActionSize); if (QRect(position.x(), position.y(), rightActionSize->width(), rightActionSize->height()).contains(point)) { @@ -598,17 +617,16 @@ int UnwrappedMedia::calculateFullRight(const QRect &inner) const { } QPoint UnwrappedMedia::calculateFastActionPosition( - int fullBottom, int replyRight, + int replyHeight, + int fullBottom, int fullRight, QSize size) const { const auto fastShareTop = (fullBottom - st::historyFastShareBottom - size.height()); - const auto doesRightActionHitReply = replyRight && (fastShareTop < - st::msgReplyBarSize.height() - + st::msgReplyPadding.top() - + st::msgReplyPadding.bottom()); + const auto doesRightActionHitReply = replyRight + && (fastShareTop < replyHeight); const auto fastShareLeft = ((doesRightActionHitReply ? replyRight : fullRight) + st::historyFastShareLeft); @@ -641,7 +659,7 @@ int UnwrappedMedia::additionalWidth( accumulate_max(result, 2 * st::msgReplyPadding.left() + via->maxWidth + st::msgReplyPadding.right()); } if (reply) { - accumulate_max(result, st::msgReplyPadding.left() + reply->maxWidth()); + accumulate_max(result, reply->maxWidth()); } return result; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.h b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.h index ca80a80c1..9932c0521 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_unwrapped.h @@ -145,8 +145,9 @@ private: int calculateFullRight(const QRect &inner) const; QPoint calculateFastActionPosition( - int fullBottom, int replyRight, + int replyHeight, + int fullBottom, int fullRight, QSize size) const; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index acb0af9a9..059b1dce4 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -22,11 +22,17 @@ msgDateFont: font(13px); msgMinWidth: 160px; msgPhotoSize: 33px; msgPhotoSkip: 40px; -msgPadding: margins(13px, 7px, 13px, 8px); +msgPadding: margins(10px, 8px, 10px, 8px); msgMargin: margins(16px, 6px, 56px, 2px); msgMarginTopAttached: 0px; msgShadow: 2px; +historyReplyTop: 2px; +historyReplyBottom: 2px; +historyReplyPreview: 32px; +historyReplyPreviewMargin: margins(7px, 4px, 4px, 4px); +historyReplyPadding: margins(11px, 2px, 6px, 2px); + msgReplyPadding: margins(6px, 6px, 11px, 6px); msgReplyBarPos: point(1px, 0px); msgReplyBarSize: size(2px, 36px); diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 6c1510116..777e84ec6 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -583,6 +583,10 @@ const MessageStyle &ChatStyle::messageStyle(bool outbg, bool selected) const { EnsureBlockquoteCache( result.replyCache, result.msgReplyBarColor); + if (!result.quoteCache) { + result.quoteCache = std::make_unique( + *result.replyCache); + } const auto preBgOverride = [&] { const auto withBg = [&](const QColor &color) { diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index 9050e59a7..d6b441771 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -222,8 +222,8 @@ void MessageBar::updateFromContent(MessageBarContent &&content) { QRect MessageBar::imageRect() const { const auto left = st::msgReplyBarSkip + st::msgReplyBarSkip; - const auto top = st::msgReplyPadding.top(); - const auto size = st::msgReplyBarSize.height(); + const auto top = (st::historyReplyHeight - st::historyReplyPreview) / 2; + const auto size = st::historyReplyPreview; return QRect(left, top, size, size); } @@ -243,14 +243,11 @@ QRect MessageBar::titleRangeRect(int from, int till) const { QRect MessageBar::bodyRect(bool withImage) const { const auto innerLeft = st::msgReplyBarSkip + st::msgReplyBarSkip; - const auto imageSkip = st::msgReplyBarSize.height() - + st::msgReplyBarSkip - - st::msgReplyBarSize.width() - - st::msgReplyBarPos.x(); + const auto imageSkip = st::historyReplyPreview + st::msgReplyBarSkip; const auto left = innerLeft + (withImage ? imageSkip : 0); const auto top = st::msgReplyPadding.top(); const auto width = _widget.width() - left - st::msgReplyPadding.right(); - const auto height = st::msgReplyBarSize.height(); + const auto height = (st::historyReplyHeight - 2 * top); return QRect(left, top, width, height) - _content.margins; }