Redesign web pages preview.

This commit is contained in:
John Preston 2023-10-17 12:57:35 +04:00
parent b9af4f3cb0
commit f8d5a8a203
10 changed files with 241 additions and 177 deletions

View File

@ -780,9 +780,11 @@ void HistoryMessageReply::paint(
auto replyToTextPosition = QPoint(
x + textLeft,
y + st::historyReplyPadding.top() + st::msgServiceNameFont->height);
const auto replyToTextPalette = &(inBubble
? stm->replyTextPalette
: st->imgReplyTextPalette());
auto replyToTextPalette = &(!inBubble
? st->imgReplyTextPalette()
: _colorIndexPlusOne
? st->coloredTextPalette(selected, _colorIndexPlusOne - 1)
: stm->replyTextPalette);
if (_fields.storyId) {
st::dialogsMiniReplyStory.icon.icon.paint(
p,
@ -794,6 +796,14 @@ void HistoryMessageReply::paint(
+ st::dialogsMiniReplyStory.icon.icon.width(),
0);
}
auto owned = std::optional<style::owned_color>();
auto copy = std::optional<style::TextPalette>();
if (inBubble && _colorIndexPlusOne) {
copy.emplace(*replyToTextPalette);
owned.emplace(cache->outline);
copy->linkFg = owned->color();
replyToTextPalette = &*copy;
}
_text.draw(p, {
.position = replyToTextPosition,
.availableWidth = w,

View File

@ -775,7 +775,7 @@ void FieldHeader::paintWebPage(Painter &p, not_null<PeerData*> context) {
Expects(ShowWebPagePreview(_preview.data));
const auto textTop = st::msgReplyPadding.top();
auto previewLeft = st::historyReplySkip + st::webPageLeft;
auto previewLeft = st::historyReplySkip + st::msgReplyBarSkip;
const QRect to(
previewLeft,

View File

@ -32,9 +32,10 @@ Game::Game(
not_null<GameData*> data,
const TextWithEntities &consumed)
: Media(parent)
, _st(st::historyPagePreview)
, _data(data)
, _title(st::msgMinWidth - st::webPageLeft)
, _description(st::msgMinWidth - st::webPageLeft) {
, _title(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _description(st::msgMinWidth - _st.padding.left() - _st.padding.right()) {
if (!consumed.text.isEmpty()) {
const auto context = Core::MarkedTextContext{
.session = &history()->session(),
@ -47,6 +48,13 @@ Game::Game(
context);
}
history()->owner().registerGameView(_data, _parent);
const auto from = parent->data()->displayFrom();
const auto info = from ? nullptr : parent->data()->hiddenSenderInfo();
Assert(from || info);
_colorIndexPlusOne = !parent->data()->isPost()
? ((from ? from->colorIndex() : info->colorIndex) + 1)
: 0;
}
QSize Game::countOptimalSize() {
@ -126,8 +134,8 @@ QSize Game::countOptimalSize() {
accumulate_max(maxWidth, maxMediaWidth);
minHeight += _attach->minHeight() - bubble.top() - bubble.bottom();
}
maxWidth += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
auto padding = inBubblePadding();
auto padding = inBubblePadding() + innerMargin();
maxWidth += padding.left() + padding.right();
minHeight += padding.top() + padding.bottom();
if (!_gameTagWidth) {
@ -147,7 +155,8 @@ void Game::refreshParentId(not_null<HistoryItem*> realParent) {
QSize Game::countCurrentSize(int newWidth) {
accumulate_min(newWidth, maxWidth());
auto innerWidth = newWidth - st::msgPadding.left() - st::webPageLeft - st::msgPadding.right();
const auto padding = inBubblePadding() + innerMargin();
auto innerWidth = newWidth - padding.left() - padding.right();
// enable any count of lines in game description / message
auto linesMax = 4096;
@ -184,11 +193,7 @@ QSize Game::countCurrentSize(int newWidth) {
_attach->resizeGetHeight(innerWidth + bubble.left() + bubble.right());
newHeight += _attach->height() - bubble.top() - bubble.bottom();
if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > innerWidth + bubble.left() + bubble.right()) {
newHeight += bottomInfoPadding();
}
}
auto padding = inBubblePadding();
newHeight += padding.top() + padding.bottom();
return { newWidth, newHeight };
@ -205,38 +210,41 @@ TextSelection Game::fromDescriptionSelection(
}
void Game::draw(Painter &p, const PaintContext &context) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
auto paintw = width();
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return;
}
const auto st = context.st;
const auto sti = context.imageStyle();
const auto stm = context.messageStyle();
const auto &barfg = stm->msgReplyBarColor;
const auto &semibold = stm->msgServiceFg;
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height());
auto outer = full.marginsRemoved(inBubblePadding());
auto inner = outer.marginsRemoved(innerMargin());
auto tshift = inner.top();
auto paintw = inner.width();
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
auto padding = inBubblePadding();
auto tshift = padding.top();
auto bshift = padding.bottom();
paintw -= padding.left() + padding.right();
if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right()) {
bshift += bottomInfoPadding();
}
QRect bar(style::rtlrect(st::msgPadding.left(), tshift, st::webPageBar, height() - tshift - bshift, width()));
p.fillRect(bar, barfg);
const auto selected = context.selected();
const auto useColorIndex = context.outbg ? 0 : _colorIndexPlusOne;
const auto cache = useColorIndex
? st->coloredReplyCache(selected, useColorIndex - 1).get()
: stm->replyCache.get();
Ui::Text::ValidateQuotePaintCache(*cache, _st);
Ui::Text::FillQuotePaint(p, outer, *cache, _st);
auto lineHeight = UnitedLineHeight();
if (_titleLines) {
p.setPen(semibold);
p.setTextPalette(stm->semiboldPalette);
p.setPen(cache->outline);
p.setTextPalette(useColorIndex
? st->coloredTextPalette(selected, useColorIndex - 1)
: stm->semiboldPalette);
auto endskip = 0;
if (_title.hasSkipBlock()) {
endskip = _parent->skipBlockWidth();
}
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, context.selection);
_title.drawLeftElided(p, inner.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, context.selection);
tshift += _titleLines * lineHeight;
p.setTextPalette(stm->textPalette);
@ -249,7 +257,7 @@ void Game::draw(Painter &p, const PaintContext &context) const {
}
_parent->prepareCustomEmojiPaint(p, context, _description);
_description.draw(p, {
.position = { padding.left(), tshift },
.position = { inner.left(), tshift },
.outerWidth = width(),
.availableWidth = paintw,
.spoiler = Ui::Text::DefaultSpoilerCache(),
@ -266,7 +274,7 @@ void Game::draw(Painter &p, const PaintContext &context) const {
auto attachAtTop = !_titleLines && !_descriptionLines;
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
auto attachLeft = padding.left() - bubble.left();
auto attachLeft = inner.left() - bubble.left();
auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
@ -301,16 +309,13 @@ TextState Game::textState(QPoint point, StateRequest request) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result;
}
auto paintw = width();
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
auto padding = inBubblePadding();
auto tshift = padding.top();
auto bshift = padding.bottom();
if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right()) {
bshift += bottomInfoPadding();
}
paintw -= padding.left() + padding.right();
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height());
auto outer = full.marginsRemoved(inBubblePadding());
auto inner = outer.marginsRemoved(innerMargin());
auto tshift = inner.top();
auto paintw = inner.width();
auto inThumb = false;
auto symbolAdd = 0;
@ -320,7 +325,7 @@ TextState Game::textState(QPoint point, StateRequest request) const {
Ui::Text::StateRequestElided titleRequest = request.forText();
titleRequest.lines = _titleLines;
result = TextState(_parent, _title.getStateElidedLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
titleRequest));
@ -334,7 +339,7 @@ TextState Game::textState(QPoint point, StateRequest request) const {
Ui::Text::StateRequestElided descriptionRequest = request.forText();
descriptionRequest.lines = _descriptionLines;
result = TextState(_parent, _description.getStateElidedLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
descriptionRequest));
@ -351,11 +356,11 @@ TextState Game::textState(QPoint point, StateRequest request) const {
auto attachAtTop = !_titleLines && !_descriptionLines;
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
auto attachLeft = padding.left() - bubble.left();
auto attachLeft = inner.left() - bubble.left();
auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
if (QRect(attachLeft, tshift, _attach->width(), height() - tshift - bshift).contains(point)) {
if (QRect(attachLeft, tshift, _attach->width(), inner.top() + inner.height() - tshift).contains(point)) {
if (_attach->isReadyForOpen()) {
if (_parent->data()->isHistoryEntry()) {
result.link = _openl;
@ -417,15 +422,24 @@ void Game::playAnimation(bool autoplay) {
}
QMargins Game::inBubblePadding() const {
auto lshift = st::msgPadding.left() + st::webPageLeft;
auto rshift = st::msgPadding.right();
auto bshift = isBubbleBottom() ? st::msgPadding.left() : st::mediaInBubbleSkip;
auto tshift = isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip;
return QMargins(lshift, tshift, rshift, bshift);
return {
st::msgPadding.left(),
isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip,
st::msgPadding.right(),
(isBubbleBottom()
? (st::msgPadding.left() + bottomInfoPadding())
: st::mediaInBubbleSkip),
};
}
QMargins Game::innerMargin() const {
return _st.padding;
}
int Game::bottomInfoPadding() const {
if (!isBubbleBottom()) return 0;
if (!isBubbleBottom()) {
return 0;
}
auto result = st::msgDateFont->height;
@ -452,7 +466,9 @@ void Game::parentTextUpdated() {
Ui::ItemTextOptions(_parent->data()),
context);
} else {
_description = Ui::Text::String(st::msgMinWidth - st::webPageLeft);
_description = Ui::Text::String(st::msgMinWidth
- _st.padding.left()
- _st.padding.right());
}
history()->owner().requestViewResize(_parent);
}

View File

@ -87,23 +87,29 @@ public:
private:
void playAnimation(bool autoplay) override;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;
[[nodiscard]] QSize countOptimalSize() override;
[[nodiscard]] QSize countCurrentSize(int newWidth) override;
TextSelection toDescriptionSelection(TextSelection selection) const;
TextSelection fromDescriptionSelection(TextSelection selection) const;
QMargins inBubblePadding() const;
int bottomInfoPadding() const;
[[nodiscard]] TextSelection toDescriptionSelection(
TextSelection selection) const;
[[nodiscard]] TextSelection fromDescriptionSelection(
TextSelection selection) const;
[[nodiscard]] QMargins inBubblePadding() const;
[[nodiscard]] QMargins innerMargin() const;
[[nodiscard]] int bottomInfoPadding() const;
not_null<GameData*> _data;
const style::QuoteStyle &_st;
const not_null<GameData*> _data;
std::shared_ptr<ReplyMarkupClickHandler> _openl;
std::unique_ptr<Media> _attach;
int _titleLines, _descriptionLines;
Ui::Text::String _title, _description;
int _gameTagWidth = 0;
int _descriptionLines = 0;
int _titleLines : 24 = 0;
int _colorIndexPlusOne : 8 = 0;
Ui::Text::String _title;
Ui::Text::String _description;
};

View File

@ -90,26 +90,38 @@ WebPage::WebPage(
not_null<Element*> parent,
not_null<WebPageData*> data)
: Media(parent)
, _st(st::historyPagePreview)
, _data(data)
, _siteName(st::msgMinWidth - st::webPageLeft)
, _title(st::msgMinWidth - st::webPageLeft)
, _description(st::msgMinWidth - st::webPageLeft) {
, _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _title(st::msgMinWidth - _st.padding.left() - _st.padding.right())
, _description(st::msgMinWidth - _st.padding.left() - _st.padding.right()) {
history()->owner().registerWebPageView(_data, _parent);
const auto from = parent->data()->displayFrom();
const auto info = from ? nullptr : parent->data()->hiddenSenderInfo();
Assert(from || info);
_colorIndexPlusOne = !parent->data()->isPost()
? ((from ? from->colorIndex() : info->colorIndex) + 1)
: 0;
}
QSize WebPage::countOptimalSize() {
if (_data->pendingTill) {
return { 0, 0 };
}
const auto padding = inBubblePadding() + innerMargin();
const auto versionChanged = (_dataVersion != _data->version);
if (versionChanged) {
_dataVersion = _data->version;
_openl = nullptr;
_attach = nullptr;
_collage = PrepareCollageMedia(_parent->data(), _data->collage);
_siteName = Ui::Text::String(st::msgMinWidth - st::webPageLeft);
_title = Ui::Text::String(st::msgMinWidth - st::webPageLeft);
_description = Ui::Text::String(st::msgMinWidth - st::webPageLeft);
const auto min = st::msgMinWidth
- _st.padding.left()
- _st.padding.right();
_siteName = Ui::Text::String(min);
_title = Ui::Text::String(min);
_description = Ui::Text::String(min);
}
auto lineHeight = UnitedLineHeight();
@ -201,11 +213,6 @@ QSize WebPage::countOptimalSize() {
_hasViewButton = ViewButton::MediaHasViewButton(_data);
const auto textFloatsAroundInfo = !_asArticle
&& !_attach
&& isBubbleBottom()
&& !_hasViewButton;
// init strings
if (_description.isEmpty() && !_data->description.text.isEmpty()) {
auto text = _data->description;
@ -213,9 +220,8 @@ QSize WebPage::countOptimalSize() {
if (isLogEntryOriginal()) {
// Fix layout for small bubbles (narrow media caption edit log entries).
_description = Ui::Text::String(st::minPhotoSize
- st::msgPadding.left()
- st::msgPadding.right()
- st::webPageLeft);
- padding.left()
- padding.right());
}
using MarkedTextContext = Core::MarkedTextContext;
auto context = MarkedTextContext{
@ -232,11 +238,6 @@ QSize WebPage::countOptimalSize() {
text,
Ui::WebpageTextDescriptionOptions(),
context);
if (textFloatsAroundInfo) {
_description.updateSkipBlock(
_parent->skipBlockWidth(),
_parent->skipBlockHeight());
}
}
if (!displayedSiteName().isEmpty()) {
_siteNameLines = 1;
@ -259,11 +260,6 @@ QSize WebPage::countOptimalSize() {
title,
Ui::WebpageTextTitleOptions());
}
if (textFloatsAroundInfo && _description.isEmpty()) {
_title.updateSkipBlock(
_parent->skipBlockWidth(),
_parent->skipBlockHeight());
}
}
// init dimensions
@ -282,11 +278,7 @@ QSize WebPage::countOptimalSize() {
}
if (!_siteName.isEmpty()) {
if (_title.isEmpty() && _description.isEmpty() && textFloatsAroundInfo) {
accumulate_max(maxWidth, _siteName.maxWidth() + _parent->skipBlockWidth());
} else {
accumulate_max(maxWidth, _siteName.maxWidth() + articlePhotoMaxWidth);
}
accumulate_max(maxWidth, _siteName.maxWidth() + articlePhotoMaxWidth);
minHeight += lineHeight;
}
if (!_title.isEmpty()) {
@ -309,16 +301,12 @@ QSize WebPage::countOptimalSize() {
}
accumulate_max(maxWidth, maxMediaWidth);
minHeight += _attach->minHeight() - bubble.top() - bubble.bottom();
if (!_attach->additionalInfoString().isEmpty()) {
minHeight += bottomInfoPadding();
}
}
if (_data->type == WebPageType::Video && _data->duration) {
_duration = Ui::FormatDurationText(_data->duration);
_durationWidth = st::msgDateFont->width(_duration);
}
maxWidth += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
auto padding = inBubblePadding();
maxWidth += padding.left() + padding.right();
minHeight += padding.top() + padding.bottom();
if (_asArticle) {
@ -332,7 +320,8 @@ QSize WebPage::countCurrentSize(int newWidth) {
return { newWidth, minHeight() };
}
auto innerWidth = newWidth - st::msgPadding.left() - st::webPageLeft - st::msgPadding.right();
auto padding = inBubblePadding() + innerMargin();
auto innerWidth = newWidth - padding.left() - padding.right();
auto newHeight = 0;
auto lineHeight = UnitedLineHeight();
@ -373,7 +362,6 @@ QSize WebPage::countCurrentSize(int newWidth) {
_pixh -= lineHeight;
} while (_pixh > lineHeight);
newHeight += bottomInfoPadding();
} else {
newHeight = siteNameHeight;
@ -410,16 +398,8 @@ QSize WebPage::countCurrentSize(int newWidth) {
_attach->resizeGetHeight(innerWidth + bubble.left() + bubble.right());
newHeight += _attach->height() - bubble.top() - bubble.bottom();
if (!_attach->additionalInfoString().isEmpty()) {
newHeight += bottomInfoPadding();
} else if (isBubbleBottom() && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > innerWidth + bubble.left() + bubble.right()) {
newHeight += bottomInfoPadding();
}
} else if (_hasViewButton) {
newHeight += bottomInfoPadding();
}
}
auto padding = inBubblePadding();
newHeight += padding.top() + padding.bottom();
return { newWidth, newHeight };
@ -476,34 +456,28 @@ void WebPage::unloadHeavyPart() {
}
void WebPage::draw(Painter &p, const PaintContext &context) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
auto paintw = width();
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return;
}
const auto st = context.st;
const auto sti = context.imageStyle();
const auto stm = context.messageStyle();
const auto &barfg = stm->msgReplyBarColor;
const auto &semibold = stm->msgServiceFg;
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
auto padding = inBubblePadding();
auto tshift = padding.top();
auto bshift = padding.bottom();
paintw -= padding.left() + padding.right();
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height());
auto outer = full.marginsRemoved(inBubblePadding());
auto inner = outer.marginsRemoved(innerMargin());
auto tshift = inner.top();
auto paintw = inner.width();
auto attachAdditionalInfoText = _attach ? _attach->additionalInfoString() : QString();
if (asArticle()) {
bshift += bottomInfoPadding();
} else if (!attachAdditionalInfoText.isEmpty()) {
bshift += bottomInfoPadding();
} else if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right()) {
bshift += bottomInfoPadding();
} else if (_hasViewButton) {
bshift += bottomInfoPadding();
}
QRect bar(style::rtlrect(st::msgPadding.left(), tshift, st::webPageBar, height() - tshift - bshift, width()));
p.fillRect(bar, barfg);
const auto selected = context.selected();
const auto useColorIndex = context.outbg ? 0 : _colorIndexPlusOne;
const auto cache = useColorIndex
? st->coloredReplyCache(selected, useColorIndex - 1).get()
: stm->replyCache.get();
Ui::Text::ValidateQuotePaintCache(*cache, _st);
Ui::Text::FillQuotePaint(p, outer, *cache, _st);
auto lineHeight = UnitedLineHeight();
if (asArticle()) {
@ -535,26 +509,28 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
} else if (const auto blurred = _photoMedia->thumbnailInline()) {
pix = blurred->pixSingle(size, args.blurred());
}
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
p.drawPixmapLeft(inner.left() + paintw - pw, tshift, width(), pix);
if (context.selected()) {
const auto st = context.st;
Ui::FillRoundRect(
p,
style::rtlrect(padding.left() + paintw - pw, tshift, pw, _pixh, width()),
style::rtlrect(inner.left() + paintw - pw, tshift, pw, _pixh, width()),
st->msgSelectOverlay(),
st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small));
}
paintw -= pw + st::webPagePhotoDelta;
}
if (_siteNameLines) {
p.setPen(semibold);
p.setTextPalette(stm->semiboldPalette);
p.setPen(cache->outline);
p.setTextPalette(useColorIndex
? st->coloredTextPalette(selected, useColorIndex - 1)
: stm->semiboldPalette);
auto endskip = 0;
if (_siteName.hasSkipBlock()) {
endskip = _parent->skipBlockWidth();
}
_siteName.drawLeftElided(p, padding.left(), tshift, paintw, width(), _siteNameLines, style::al_left, 0, -1, endskip, false, context.selection);
_siteName.drawLeftElided(p, inner.left(), tshift, paintw, width(), _siteNameLines, style::al_left, 0, -1, endskip, false, context.selection);
tshift += lineHeight;
p.setTextPalette(stm->textPalette);
@ -565,7 +541,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
if (_title.hasSkipBlock()) {
endskip = _parent->skipBlockWidth();
}
_title.drawLeftElided(p, padding.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, toTitleSelection(context.selection));
_title.drawLeftElided(p, inner.left(), tshift, paintw, width(), _titleLines, style::al_left, 0, -1, endskip, false, toTitleSelection(context.selection));
tshift += _titleLines * lineHeight;
}
if (_descriptionLines) {
@ -575,7 +551,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
}
_parent->prepareCustomEmojiPaint(p, context, _description);
_description.draw(p, {
.position = { padding.left(), tshift },
.position = { inner.left(), tshift },
.outerWidth = width(),
.availableWidth = paintw,
.spoiler = Ui::Text::DefaultSpoilerCache(),
@ -596,7 +572,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
auto attachAtTop = !_siteNameLines && !_titleLines && !_descriptionLines;
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
auto attachLeft = padding.left() - bubble.left();
auto attachLeft = inner.left() - bubble.left();
auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
@ -641,7 +617,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
if (!attachAdditionalInfoText.isEmpty()) {
p.setFont(st::msgDateFont);
p.setPen(stm->msgDateFg);
p.drawTextLeft(st::msgPadding.left(), bar.y() + bar.height() + st::mediaInBubbleSkip, width(), attachAdditionalInfoText);
p.drawTextLeft(st::msgPadding.left(), outer.y() + outer.height() + st::mediaInBubbleSkip, width(), attachAdditionalInfoText);
}
}
}
@ -656,22 +632,19 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result;
}
auto paintw = width();
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
auto padding = inBubblePadding();
auto tshift = padding.top();
auto bshift = padding.bottom();
if (asArticle() || (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right())) {
bshift += bottomInfoPadding();
}
paintw -= padding.left() + padding.right();
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height());
auto outer = full.marginsRemoved(inBubblePadding());
auto inner = outer.marginsRemoved(innerMargin());
auto tshift = inner.top();
auto paintw = inner.width();
auto attachAdditionalInfoText = _attach ? _attach->additionalInfoString() : QString();
auto lineHeight = UnitedLineHeight();
auto inThumb = false;
if (asArticle()) {
auto pw = qMax(_pixw, lineHeight);
if (style::rtlrect(padding.left() + paintw - pw, tshift, pw, _pixh, width()).contains(point)) {
if (style::rtlrect(inner.left() + paintw - pw, tshift, pw, _pixh, width()).contains(point)) {
inThumb = true;
}
paintw -= pw + st::webPagePhotoDelta;
@ -682,7 +655,7 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
Ui::Text::StateRequestElided siteNameRequest = request.forText();
siteNameRequest.lines = _siteNameLines;
result = TextState(_parent, _siteName.getStateElidedLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
siteNameRequest));
@ -696,7 +669,7 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
Ui::Text::StateRequestElided titleRequest = request.forText();
titleRequest.lines = _titleLines;
result = TextState(_parent, _title.getStateElidedLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
titleRequest));
@ -712,13 +685,13 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
Ui::Text::StateRequestElided descriptionRequest = request.forText();
descriptionRequest.lines = _descriptionLines;
result = TextState(_parent, _description.getStateElidedLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
descriptionRequest));
} else {
result = TextState(_parent, _description.getStateLeft(
point - QPoint(padding.left(), tshift),
point - QPoint(inner.left(), tshift),
paintw,
width(),
request.forText()));
@ -734,14 +707,17 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
auto attachAtTop = !_siteNameLines && !_titleLines && !_descriptionLines;
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
if (QRect(padding.left(), tshift, paintw, height() - tshift - bshift).contains(point)) {
auto attachLeft = padding.left() - bubble.left();
if (QRect(inner.left(), tshift, paintw, inner.top() + inner.height() - tshift).contains(point)) {
auto attachLeft = inner.left() - bubble.left();
auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = width() - attachLeft - _attach->width();
result = _attach->textState(point - QPoint(attachLeft, attachTop), request);
result.link = replaceAttachLink(result.link);
}
}
if (!result.link && inner.contains(point)) {
result.link = _openl;
}
result.symbol += symbolAdd;
return result;
@ -859,11 +835,18 @@ TextForMimeData WebPage::selectedText(TextSelection selection) const {
}
QMargins WebPage::inBubblePadding() const {
auto lshift = st::msgPadding.left() + st::webPageLeft;
auto rshift = st::msgPadding.right();
auto bshift = isBubbleBottom() ? st::msgPadding.left() : st::mediaInBubbleSkip;
auto tshift = isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip;
return QMargins(lshift, tshift, rshift, bshift);
return {
st::msgPadding.left(),
isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip,
st::msgPadding.right(),
(isBubbleBottom()
? (st::msgPadding.left() + bottomInfoPadding())
: st::mediaInBubbleSkip),
};
}
QMargins WebPage::innerMargin() const {
return _st.padding;
}
bool WebPage::isLogEntryOriginal() const {
@ -871,7 +854,9 @@ bool WebPage::isLogEntryOriginal() const {
}
int WebPage::bottomInfoPadding() const {
if (!isBubbleBottom()) return 0;
if (!isBubbleBottom()) {
return 0;
}
auto result = st::msgDateFont->height;

View File

@ -99,19 +99,26 @@ private:
void ensurePhotoMediaCreated() const;
TextSelection toTitleSelection(TextSelection selection) const;
TextSelection fromTitleSelection(TextSelection selection) const;
TextSelection toDescriptionSelection(TextSelection selection) const;
TextSelection fromDescriptionSelection(TextSelection selection) const;
QMargins inBubblePadding() const;
int bottomInfoPadding() const;
bool isLogEntryOriginal() const;
[[nodiscard]] TextSelection toTitleSelection(
TextSelection selection) const;
[[nodiscard]] TextSelection fromTitleSelection(
TextSelection selection) const;
[[nodiscard]] TextSelection toDescriptionSelection(
TextSelection selection) const;
[[nodiscard]] TextSelection fromDescriptionSelection(
TextSelection selection) const;
[[nodiscard]] QMargins inBubblePadding() const;
[[nodiscard]] QMargins innerMargin() const;
[[nodiscard]] int bottomInfoPadding() const;
[[nodiscard]] bool isLogEntryOriginal() const;
QString displayedSiteName() const;
ClickHandlerPtr replaceAttachLink(const ClickHandlerPtr &link) const;
bool asArticle() const;
[[nodiscard]] QString displayedSiteName() const;
[[nodiscard]] ClickHandlerPtr replaceAttachLink(
const ClickHandlerPtr &link) const;
[[nodiscard]] bool asArticle() const;
not_null<WebPageData*> _data;
const style::QuoteStyle &_st;
const not_null<WebPageData*> _data;
std::vector<std::unique_ptr<Data::Media>> _collage;
ClickHandlerPtr _openl;
std::unique_ptr<Media> _attach;
@ -121,8 +128,9 @@ private:
bool _hasViewButton = false;
int _dataVersion = -1;
int _siteNameLines = 0;
int _titleLines = 0;
int _descriptionLines = 0;
int _titleLines : 24 = 0;
int _colorIndexPlusOne : 8 = 0;
Ui::Text::String _siteName, _title, _description;

View File

@ -66,6 +66,9 @@ messageTextStyle: TextStyle(defaultTextStyle) {
iconPosition: point(4px, 2px);
}
}
historyPagePreview: QuoteStyle(messageQuoteStyle) {
padding: margins(10px, 5px, 7px, 7px);
}
msgDateTextStyle: defaultTextStyle;
serviceTextPalette: TextPalette(defaultTextPalette) {
linkFg: msgServiceFg;
@ -563,8 +566,6 @@ historyPsaForwardPalette: TextPalette(defaultTextPalette) {
linkFg: boxTextFgGood;
}
webPageLeft: 10px;
webPageBar: 2px;
webPageTitleFont: semiboldFont;
webPageTitleStyle: semiboldTextStyle;
webPageDescriptionFont: normalFont;

View File

@ -548,6 +548,10 @@ void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
= (stm.textPalette.linkFg->c == stm.historyTextFg->c);
}
for (auto &palette : _coloredTextPalettes) {
palette.inited = false;
}
_paletteChanged.fire({});
}
@ -640,6 +644,26 @@ not_null<Text::QuotePaintCache*> ChatStyle::serviceReplyCache() const {
return _serviceReplyCache.get();
}
const style::TextPalette &ChatStyle::coloredTextPalette(
bool selected,
uint8 colorIndex) const {
Expects(colorIndex >= 0 && colorIndex < kColorIndexCount);
const auto shift = (selected ? kColorIndexCount : 0);
auto &result = _coloredTextPalettes[shift + colorIndex];
if (!result.inited) {
result.inited = true;
make(
result.data,
(selected
? st::inReplyTextPaletteSelected
: st::inReplyTextPalette));
result.data.linkFg = FromNameFg(this, selected, colorIndex);
result.data.selectLinkFg = result.data.linkFg;
}
return result.data;
}
not_null<Text::QuotePaintCache*> ChatStyle::coloredQuoteCache(
bool selected,
uint8 colorIndex) const {

View File

@ -213,6 +213,10 @@ public:
bool selected,
uint8 colorIndex) const;
[[nodiscard]] const style::TextPalette &coloredTextPalette(
bool selected,
uint8 colorIndex) const;
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersSmall() const;
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCornersLarge() const;
[[nodiscard]] const CornersPixmaps &msgSelectOverlayCorners(
@ -301,6 +305,12 @@ private:
using ColoredQuotePaintCaches = std::array<
std::unique_ptr<Text::QuotePaintCache>,
kColorIndexCount * 2>;
struct ColoredPalette {
style::TextPalette data;
bool inited = false;
};
void assignPalette(not_null<const style::palette*> palette);
[[nodiscard]] not_null<Text::QuotePaintCache*> coloredCache(
@ -362,6 +372,9 @@ private:
mutable std::unique_ptr<Text::QuotePaintCache> _serviceReplyCache;
mutable ColoredQuotePaintCaches _coloredQuoteCaches;
mutable ColoredQuotePaintCaches _coloredReplyCaches;
mutable std::array<
ColoredPalette,
2 * kColorIndexCount> _coloredTextPalettes;
style::TextPalette _historyPsaForwardPalette;
style::TextPalette _imgReplyTextPalette;

View File

@ -113,7 +113,8 @@ void InitTextOptions() {
= WebpageDescriptionOptions.maxw
= st::msgMaxWidth
- st::msgPadding.left()
- st::webPageLeft
- st::messageQuoteStyle.padding.left()
- st::messageQuoteStyle.padding.right()
- st::msgPadding.right();
WebpageDescriptionOptions.maxh = st::webPageDescriptionFont->height * 3;
}