diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index f90e4ca79..71163b4e9 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -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(); + auto copy = std::optional(); + if (inBubble && _colorIndexPlusOne) { + copy.emplace(*replyToTextPalette); + owned.emplace(cache->outline); + copy->linkFg = owned->color(); + replyToTextPalette = &*copy; + } _text.draw(p, { .position = replyToTextPosition, .availableWidth = w, 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 b5de792b1..151ad9cd3 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -775,7 +775,7 @@ void FieldHeader::paintWebPage(Painter &p, not_null 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, diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.cpp b/Telegram/SourceFiles/history/view/media/history_view_game.cpp index 4767bfcce..8713011c0 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_game.cpp @@ -32,9 +32,10 @@ Game::Game( not_null 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 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); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.h b/Telegram/SourceFiles/history/view/media/history_view_game.h index 062418569..4cd5c613f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.h +++ b/Telegram/SourceFiles/history/view/media/history_view_game.h @@ -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 _data; + const style::QuoteStyle &_st; + const not_null _data; std::shared_ptr _openl; std::unique_ptr _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; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index 454475369..799fe826a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -90,26 +90,38 @@ WebPage::WebPage( not_null parent, not_null 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; diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.h b/Telegram/SourceFiles/history/view/media/history_view_web_page.h index 86005d13e..bbccbd951 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.h +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.h @@ -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 _data; + const style::QuoteStyle &_st; + const not_null _data; std::vector> _collage; ClickHandlerPtr _openl; std::unique_ptr _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; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 059b1dce4..0169149c0 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -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; diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 777e84ec6..8e241d12f 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -548,6 +548,10 @@ void ChatStyle::assignPalette(not_null palette) { = (stm.textPalette.linkFg->c == stm.historyTextFg->c); } + for (auto &palette : _coloredTextPalettes) { + palette.inited = false; + } + _paletteChanged.fire({}); } @@ -640,6 +644,26 @@ not_null 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 ChatStyle::coloredQuoteCache( bool selected, uint8 colorIndex) const { diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 4c9510e07..8482d5936 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -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, kColorIndexCount * 2>; + + struct ColoredPalette { + style::TextPalette data; + bool inited = false; + }; + void assignPalette(not_null palette); [[nodiscard]] not_null coloredCache( @@ -362,6 +372,9 @@ private: mutable std::unique_ptr _serviceReplyCache; mutable ColoredQuotePaintCaches _coloredQuoteCaches; mutable ColoredQuotePaintCaches _coloredReplyCaches; + mutable std::array< + ColoredPalette, + 2 * kColorIndexCount> _coloredTextPalettes; style::TextPalette _historyPsaForwardPalette; style::TextPalette _imgReplyTextPalette; diff --git a/Telegram/SourceFiles/ui/text/text_options.cpp b/Telegram/SourceFiles/ui/text/text_options.cpp index 20e66737e..3c9eb97a6 100644 --- a/Telegram/SourceFiles/ui/text/text_options.cpp +++ b/Telegram/SourceFiles/ui/text/text_options.cpp @@ -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; }