Show nice replies with quotes.

This commit is contained in:
John Preston 2023-10-17 10:19:58 +04:00
parent 4b6107fa56
commit b9af4f3cb0
15 changed files with 285 additions and 241 deletions

View File

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

View File

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

View File

@ -3305,6 +3305,7 @@ void HistoryItem::createComponentsHelper(
config.reply.topicPost = LookupReplyIsTopicPost(to)
|| (to && to->Has<HistoryServiceTopicInfo>())
|| (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;

View File

@ -570,31 +570,32 @@ void HistoryMessageReply::updateName(
std::optional<PeerData*> 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 &quoteSt = 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()));
}
}
}

View File

@ -273,7 +273,9 @@ struct HistoryMessageReply
void updateName(
not_null<HistoryItem*> holder,
std::optional<PeerData*> 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<HistoryItem*> holder,
not_null<HistoryItem*> removed);
@ -325,7 +327,6 @@ struct HistoryMessageReply
ReplyToStoryPointer resolvedStory;
std::unique_ptr<HistoryMessageVia> originalVia;
std::unique_ptr<Ui::SpoilerAnimation> spoiler;
int toWidth = 0;
struct {
mutable std::unique_ptr<Ui::RippleAnimation> 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;
};

View File

@ -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<HistoryItem*> 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()

View File

@ -776,23 +776,14 @@ void FieldHeader::paintWebPage(Painter &p, not_null<PeerData*> 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) {

View File

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

View File

@ -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<QImage, 4>{{
((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<Ui::RippleAnimation>(
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<TextState*> 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<HistoryMessageReply>()) {
auto h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
trect.setTop(trect.top() + h);
if (const auto reply = item->Get<HistoryMessageReply>()) {
trect.setTop(trect.top() + reply->height());
}
if (const auto via = item->Get<HistoryMessageVia>()) {
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);

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Text::QuotePaintCache>(
*result.replyCache);
}
const auto preBgOverride = [&] {
const auto withBg = [&](const QColor &color) {

View File

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