Improved code style in HistoryView::WebPage.

This commit is contained in:
23rd 2023-12-23 02:38:46 +03:00
parent 4e3c1460f6
commit fc50d5c30f

View file

@ -9,35 +9,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "core/ui_integration.h" #include "core/ui_integration.h"
#include "lang/lang_keys.h" #include "data/data_file_click_handler.h"
#include "history/history_item_components.h" #include "data/data_photo_media.h"
#include "history/history_item.h" #include "data/data_session.h"
#include "data/data_sponsored_messages.h"
#include "data/data_web_page.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item_components.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_sponsored_click_handler.h"
#include "history/view/history_view_reply.h" #include "history/view/history_view_reply.h"
#include "history/view/history_view_sponsored_click_handler.h"
#include "history/view/media/history_view_media_common.h" #include "history/view/media/history_view_media_common.h"
#include "history/view/media/history_view_theme_document.h" #include "lang/lang_keys.h"
#include "ui/image/image.h" #include "main/main_session.h"
#include "ui/chat/chat_style.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/power_saving.h"
#include "ui/text/format_values.h"
#include "ui/text/text_options.h" #include "ui/text/text_options.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/text/format_values.h"
#include "ui/chat/chat_style.h"
#include "ui/cached_round_corners.h"
#include "ui/effects/ripple_animation.h"
#include "ui/painter.h"
#include "ui/power_saving.h"
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_wall_paper.h"
#include "data/data_media_types.h"
#include "data/data_web_page.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_click_handler.h"
#include "data/data_file_origin.h"
#include "data/data_sponsored_messages.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
namespace HistoryView { namespace HistoryView {
@ -45,27 +36,29 @@ namespace {
constexpr auto kMaxOriginalEntryLines = 8192; constexpr auto kMaxOriginalEntryLines = 8192;
int articleThumbWidth(not_null<PhotoData*> thumb, int height) { [[nodiscard]] int ArticleThumbWidth(not_null<PhotoData*> thumb, int height) {
const auto size = thumb->location(Data::PhotoSize::Thumbnail); const auto size = thumb->location(Data::PhotoSize::Thumbnail);
return size.height() return size.height()
? qMax(qMin(height * size.width() / size.height(), height), 1) ? std::max(std::min(height * size.width() / size.height(), height), 1)
: 1; : 1;
} }
int articleThumbHeight(not_null<Data::PhotoMedia*> thumb, int width) { [[nodiscard]] int ArticleThumbHeight(
not_null<Data::PhotoMedia*> thumb,
int width) {
const auto size = thumb->size(Data::PhotoSize::Thumbnail); const auto size = thumb->size(Data::PhotoSize::Thumbnail);
return size.width() return size.width()
? std::max(size.height() * width / size.width(), 1) ? std::max(size.height() * width / size.width(), 1)
: 1; : 1;
} }
std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia( [[nodiscard]] std::vector<std::unique_ptr<Data::Media>> PrepareCollageMedia(
not_null<HistoryItem*> parent, not_null<HistoryItem*> parent,
const WebPageCollage &data) { const WebPageCollage &data) {
auto result = std::vector<std::unique_ptr<Data::Media>>(); auto result = std::vector<std::unique_ptr<Data::Media>>();
result.reserve(data.items.size()); result.reserve(data.items.size());
const auto spoiler = false;
for (const auto &item : data.items) { for (const auto &item : data.items) {
const auto spoiler = false;
if (const auto document = std::get_if<DocumentData*>(&item)) { if (const auto document = std::get_if<DocumentData*>(&item)) {
const auto skipPremiumEffect = false; const auto skipPremiumEffect = false;
result.push_back(std::make_unique<Data::MediaFile>( result.push_back(std::make_unique<Data::MediaFile>(
@ -206,14 +199,12 @@ QSize WebPage::countOptimalSize() {
_openl = nullptr; _openl = nullptr;
_attach = nullptr; _attach = nullptr;
_collage = PrepareCollageMedia(_parent->data(), _data->collage); _collage = PrepareCollageMedia(_parent->data(), _data->collage);
const auto min = st::msgMinWidth const auto min = st::msgMinWidth - rect::m::sum::h(_st.padding);
- _st.padding.left()
- _st.padding.right();
_siteName = Ui::Text::String(min); _siteName = Ui::Text::String(min);
_title = Ui::Text::String(min); _title = Ui::Text::String(min);
_description = Ui::Text::String(min); _description = Ui::Text::String(min);
} }
auto lineHeight = UnitedLineHeight(); const auto lineHeight = UnitedLineHeight();
if (!_openl && (!_data->url.isEmpty() || _sponsoredData)) { if (!_openl && (!_data->url.isEmpty() || _sponsoredData)) {
const auto previewOfHiddenUrl = [&] { const auto previewOfHiddenUrl = [&] {
@ -273,7 +264,7 @@ QSize WebPage::countOptimalSize() {
} }
// init layout // init layout
auto title = TextUtilities::SingleLine(_data->title.isEmpty() const auto title = TextUtilities::SingleLine(_data->title.isEmpty()
? _data->author ? _data->author
: _data->title); : _data->title);
using Flag = MediaWebPageFlag; using Flag = MediaWebPageFlag;
@ -297,13 +288,13 @@ QSize WebPage::countOptimalSize() {
// init strings // init strings
if (_description.isEmpty() && !_data->description.text.isEmpty()) { if (_description.isEmpty() && !_data->description.text.isEmpty()) {
auto text = _data->description; const auto &text = _data->description;
if (isLogEntryOriginal()) { if (isLogEntryOriginal()) {
// Fix layout for small bubbles (narrow media caption edit log entries). // Fix layout for small bubbles
// (narrow media caption edit log entries).
_description = Ui::Text::String(st::minPhotoSize _description = Ui::Text::String(st::minPhotoSize
- padding.left() - rect::m::sum::h(padding));
- padding.right());
} }
using MarkedTextContext = Core::MarkedTextContext; using MarkedTextContext = Core::MarkedTextContext;
auto context = MarkedTextContext{ auto context = MarkedTextContext{
@ -330,11 +321,10 @@ QSize WebPage::countOptimalSize() {
Ui::WebpageTextTitleOptions()); Ui::WebpageTextTitleOptions());
} }
if (_title.isEmpty() && !title.isEmpty()) { if (_title.isEmpty() && !title.isEmpty()) {
auto titleWithEntities = Ui::Text::Link(title, _data->url);
if (!_siteNameLines && !_data->url.isEmpty()) { if (!_siteNameLines && !_data->url.isEmpty()) {
_title.setMarkedText( _title.setMarkedText(
st::webPageTitleStyle, st::webPageTitleStyle,
std::move(titleWithEntities), Ui::Text::Link(title, _data->url),
Ui::WebpageTextTitleOptions()); Ui::WebpageTextTitleOptions());
} else { } else {
@ -346,19 +336,27 @@ QSize WebPage::countOptimalSize() {
} }
// init dimensions // init dimensions
auto skipBlockWidth = _parent->skipBlockWidth(); const auto skipBlockWidth = _parent->skipBlockWidth();
auto maxWidth = skipBlockWidth; auto maxWidth = skipBlockWidth;
auto minHeight = 0; auto minHeight = 0;
auto siteNameHeight = _siteName.isEmpty() ? 0 : lineHeight; const auto siteNameHeight = _siteName.isEmpty() ? 0 : lineHeight;
auto titleMinHeight = _title.isEmpty() ? 0 : lineHeight; const auto titleMinHeight = _title.isEmpty() ? 0 : lineHeight;
auto descMaxLines = isLogEntryOriginal() ? kMaxOriginalEntryLines : (3 + (siteNameHeight ? 0 : 1) + (titleMinHeight ? 0 : 1)); const auto descMaxLines = isLogEntryOriginal()
auto descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * lineHeight); ? kMaxOriginalEntryLines
auto articleMinHeight = siteNameHeight + titleMinHeight + descriptionMinHeight; : (3 + (siteNameHeight ? 0 : 1) + (titleMinHeight ? 0 : 1));
auto articlePhotoMaxWidth = 0; const auto descriptionMinHeight = _description.isEmpty()
if (_asArticle) { ? 0
articlePhotoMaxWidth = st::webPagePhotoDelta + qMax(articleThumbWidth(_data->photo, articleMinHeight), lineHeight); : std::min(_description.minHeight(), descMaxLines * lineHeight);
} const auto articleMinHeight = siteNameHeight
+ titleMinHeight
+ descriptionMinHeight;
const auto articlePhotoMaxWidth = _asArticle
? st::webPagePhotoDelta
+ std::max(
ArticleThumbWidth(_data->photo, articleMinHeight),
lineHeight)
: 0;
if (!_siteName.isEmpty()) { if (!_siteName.isEmpty()) {
accumulate_max(maxWidth, _siteName.maxWidth() + articlePhotoMaxWidth); accumulate_max(maxWidth, _siteName.maxWidth() + articlePhotoMaxWidth);
@ -369,32 +367,38 @@ QSize WebPage::countOptimalSize() {
minHeight += titleMinHeight; minHeight += titleMinHeight;
} }
if (!_description.isEmpty()) { if (!_description.isEmpty()) {
accumulate_max(maxWidth, _description.maxWidth() + articlePhotoMaxWidth); accumulate_max(
maxWidth,
_description.maxWidth() + articlePhotoMaxWidth);
minHeight += descriptionMinHeight; minHeight += descriptionMinHeight;
} }
if (_attach) { if (_attach) {
auto attachAtTop = _siteName.isEmpty() && _title.isEmpty() && _description.isEmpty(); const auto attachAtTop = _siteName.isEmpty()
if (!attachAtTop) minHeight += st::mediaInBubbleSkip; && _title.isEmpty()
&& _description.isEmpty();
if (!attachAtTop) {
minHeight += st::mediaInBubbleSkip;
}
_attach->initDimensions(); _attach->initDimensions();
auto bubble = _attach->bubbleMargins(); const auto bubble = _attach->bubbleMargins();
auto maxMediaWidth = _attach->maxWidth() - bubble.left() - bubble.right(); auto maxMediaWidth = _attach->maxWidth() - rect::m::sum::h(bubble);
if (isBubbleBottom() && _attach->customInfoLayout()) { if (isBubbleBottom() && _attach->customInfoLayout()) {
maxMediaWidth += skipBlockWidth; maxMediaWidth += skipBlockWidth;
} }
accumulate_max(maxWidth, maxMediaWidth); accumulate_max(maxWidth, maxMediaWidth);
minHeight += _attach->minHeight() - bubble.top() - bubble.bottom(); minHeight += _attach->minHeight() - rect::m::sum::v(bubble);
} }
if (_data->type == WebPageType::Video && _data->duration) { if (_data->type == WebPageType::Video && _data->duration) {
_duration = Ui::FormatDurationText(_data->duration); _duration = Ui::FormatDurationText(_data->duration);
_durationWidth = st::msgDateFont->width(_duration); _durationWidth = st::msgDateFont->width(_duration);
} }
if (_openButtonWidth) { if (_openButtonWidth) {
const auto &margins = st::historyPageButtonPadding; maxWidth += rect::m::sum::h(st::historyPageButtonPadding)
maxWidth += margins.left() + _openButtonWidth + margins.right(); + _openButtonWidth;
} }
maxWidth += padding.left() + padding.right(); maxWidth += rect::m::sum::h(padding);
minHeight += padding.top() + padding.bottom(); minHeight += rect::m::sum::v(padding);
if (_asArticle) { if (_asArticle) {
minHeight = resizeGetHeight(maxWidth); minHeight = resizeGetHeight(maxWidth);
@ -407,46 +411,51 @@ QSize WebPage::countCurrentSize(int newWidth) {
return { newWidth, minHeight() }; return { newWidth, minHeight() };
} }
auto padding = inBubblePadding() + innerMargin(); const auto padding = inBubblePadding() + innerMargin();
auto innerWidth = newWidth - padding.left() - padding.right(); const auto innerWidth = newWidth - rect::m::sum::h(padding);
auto newHeight = 0; auto newHeight = 0;
auto lineHeight = UnitedLineHeight(); const auto lineHeight = UnitedLineHeight();
auto linesMax = (_sponsoredData || isLogEntryOriginal()) const auto linesMax = (_sponsoredData || isLogEntryOriginal())
? kMaxOriginalEntryLines ? kMaxOriginalEntryLines
: 5; : 5;
auto siteNameHeight = _siteNameLines ? lineHeight : 0; const auto siteNameHeight = _siteNameLines ? lineHeight : 0;
const auto twoTitleLines = 2 * st::webPageTitleFont->height;
const auto descriptionLineHeight = st::webPageDescriptionFont->height;
const auto asSponsored = (!!_sponsoredData); const auto asSponsored = (!!_sponsoredData);
if (asArticle() || asSponsored) { if (asArticle() || asSponsored) {
const auto sponsoredUserpic = (asSponsored && _sponsoredData->peer); const auto sponsoredUserpic = (asSponsored && _sponsoredData->peer);
constexpr auto kSponsoredUserpicLines = 2; constexpr auto kSponsoredUserpicLines = 2;
_pixh = (asSponsored ? kSponsoredUserpicLines : linesMax) * lineHeight; _pixh = lineHeight
* (asSponsored ? kSponsoredUserpicLines : linesMax);
do { do {
_pixw = asSponsored ? _pixh : articleThumbWidth(_data->photo, _pixh); _pixw = asSponsored
auto wleft = innerWidth - st::webPagePhotoDelta - qMax(_pixw, lineHeight); ? _pixh
: ArticleThumbWidth(_data->photo, _pixh);
const auto wleft = innerWidth
- st::webPagePhotoDelta
- std::max(_pixw, lineHeight);
newHeight = siteNameHeight; newHeight = siteNameHeight;
if (_title.isEmpty()) { if (_title.isEmpty()) {
_titleLines = 0; _titleLines = 0;
} else { } else {
if (_title.countHeight(wleft) < 2 * st::webPageTitleFont->height) { _titleLines = (_title.countHeight(wleft) < twoTitleLines)
_titleLines = 1; ? 1
} else { : 2;
_titleLines = 2;
}
newHeight += _titleLines * lineHeight; newHeight += _titleLines * lineHeight;
} }
auto descriptionHeight = _description.countHeight(sponsoredUserpic const auto descriptionHeight = _description.countHeight(
? innerWidth sponsoredUserpic ? innerWidth : wleft);
: wleft); const auto restLines = (linesMax - _siteNameLines - _titleLines);
if (descriptionHeight < (linesMax - _siteNameLines - _titleLines) * st::webPageDescriptionFont->height) { if (descriptionHeight < restLines * descriptionLineHeight) {
// We have height for all the lines. // We have height for all the lines.
_descriptionLines = -1; _descriptionLines = -1;
newHeight += descriptionHeight; newHeight += descriptionHeight;
} else { } else {
_descriptionLines = (linesMax - _siteNameLines - _titleLines); _descriptionLines = restLines;
newHeight += _descriptionLines * lineHeight; newHeight += _descriptionLines * lineHeight;
} }
@ -462,55 +471,55 @@ QSize WebPage::countCurrentSize(int newWidth) {
if (_title.isEmpty()) { if (_title.isEmpty()) {
_titleLines = 0; _titleLines = 0;
} else { } else {
if (_title.countHeight(innerWidth) < 2 * st::webPageTitleFont->height) { _titleLines = (_title.countHeight(innerWidth) < twoTitleLines)
_titleLines = 1; ? 1
} else { : 2;
_titleLines = 2;
}
newHeight += _titleLines * lineHeight; newHeight += _titleLines * lineHeight;
} }
if (_description.isEmpty()) { if (_description.isEmpty()) {
_descriptionLines = 0; _descriptionLines = 0;
} else { } else {
auto descriptionHeight = _description.countHeight(innerWidth); const auto restLines = (linesMax - _siteNameLines - _titleLines);
if (descriptionHeight < (linesMax - _siteNameLines - _titleLines) * st::webPageDescriptionFont->height) { const auto descriptionHeight = _description.countHeight(
innerWidth);
if (descriptionHeight < restLines * descriptionLineHeight) {
// We have height for all the lines. // We have height for all the lines.
_descriptionLines = -1; _descriptionLines = -1;
newHeight += descriptionHeight; newHeight += descriptionHeight;
} else { } else {
_descriptionLines = (linesMax - _siteNameLines - _titleLines); _descriptionLines = restLines;
newHeight += _descriptionLines * lineHeight; newHeight += _descriptionLines * lineHeight;
} }
} }
if (_attach) { if (_attach) {
auto attachAtTop = !_siteNameLines && !_titleLines && !_descriptionLines; const auto attachAtTop = !_siteNameLines
if (!attachAtTop) newHeight += st::mediaInBubbleSkip; && !_titleLines
&& !_descriptionLines;
if (!attachAtTop) {
newHeight += st::mediaInBubbleSkip;
}
auto bubble = _attach->bubbleMargins(); const auto bubble = _attach->bubbleMargins();
_attach->resizeGetHeight(innerWidth + rect::m::sum::h(bubble));
_attach->resizeGetHeight(innerWidth + bubble.left() + bubble.right()); newHeight += _attach->height() - rect::m::sum::v(bubble);
newHeight += _attach->height() - bubble.top() - bubble.bottom();
} }
} }
newHeight += padding.top() + padding.bottom(); newHeight += rect::m::sum::v(padding);
return { newWidth, newHeight }; return { newWidth, newHeight };
} }
TextSelection WebPage::toTitleSelection( TextSelection WebPage::toTitleSelection(TextSelection selection) const {
TextSelection selection) const {
return UnshiftItemSelection(selection, _siteName); return UnshiftItemSelection(selection, _siteName);
} }
TextSelection WebPage::fromTitleSelection( TextSelection WebPage::fromTitleSelection(TextSelection selection) const {
TextSelection selection) const {
return ShiftItemSelection(selection, _siteName); return ShiftItemSelection(selection, _siteName);
} }
TextSelection WebPage::toDescriptionSelection( TextSelection WebPage::toDescriptionSelection(TextSelection selection) const {
TextSelection selection) const {
return UnshiftItemSelection(toTitleSelection(selection), _title); return UnshiftItemSelection(toTitleSelection(selection), _title);
} }
@ -555,7 +564,7 @@ void WebPage::unloadHeavyPart() {
} }
void WebPage::draw(Painter &p, const PaintContext &context) const { void WebPage::draw(Painter &p, const PaintContext &context) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < rect::m::sum::h(st::msgPadding) + 1) {
return; return;
} }
const auto st = context.st; const auto st = context.st;
@ -563,12 +572,14 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
const auto stm = context.messageStyle(); const auto stm = context.messageStyle();
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins(); const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height()); const auto full = Rect(currentSize());
auto outer = full.marginsRemoved(inBubblePadding()); const auto outer = full - inBubblePadding();
auto inner = outer.marginsRemoved(innerMargin()); const auto inner = outer - innerMargin();
const auto attachAdditionalInfoText = _attach
? _attach->additionalInfoString()
: QString();
auto tshift = inner.top(); auto tshift = inner.top();
auto paintw = inner.width(); auto paintw = inner.width();
auto attachAdditionalInfoText = _attach ? _attach->additionalInfoString() : QString();
const auto selected = context.selected(); const auto selected = context.selected();
const auto view = parent(); const auto view = parent();
@ -617,28 +628,30 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
if (asArticle()) { if (asArticle()) {
ensurePhotoMediaCreated(); ensurePhotoMediaCreated();
QPixmap pix; auto pix = QPixmap();
auto pw = qMax(_pixw, lineHeight); const auto pw = qMax(_pixw, lineHeight);
auto ph = _pixh; const auto ph = _pixh;
auto pixw = _pixw, pixh = articleThumbHeight(_photoMedia.get(), _pixw); auto pixw = _pixw;
auto pixh = ArticleThumbHeight(_photoMedia.get(), _pixw);
const auto maxsize = _photoMedia->size(Data::PhotoSize::Thumbnail); const auto maxsize = _photoMedia->size(Data::PhotoSize::Thumbnail);
const auto maxw = style::ConvertScale(maxsize.width()); const auto maxw = style::ConvertScale(maxsize.width());
const auto maxh = style::ConvertScale(maxsize.height()); const auto maxh = style::ConvertScale(maxsize.height());
if (pixw * ph != pixh * pw) { if (pixw * ph != pixh * pw) {
float64 coef = (pixw * ph > pixh * pw) ? qMin(ph / float64(pixh), maxh / float64(pixh)) : qMin(pw / float64(pixw), maxw / float64(pixw)); const auto coef = (pixw * ph > pixh * pw)
pixh = qRound(pixh * coef); ? std::min(ph / float64(pixh), maxh / float64(pixh))
pixw = qRound(pixw * coef); : std::min(pw / float64(pixw), maxw / float64(pixw));
pixh = std::round(pixh * coef);
pixw = std::round(pixw * coef);
} }
const auto size = QSize(pixw, pixh); const auto size = QSize(pixw, pixh);
const auto args = Images::PrepareArgs{ const auto args = Images::PrepareArgs{
.options = Images::Option::RoundSmall, .options = Images::Option::RoundSmall,
.outer = { pw, ph }, .outer = { pw, ph },
}; };
if (const auto thumbnail = _photoMedia->image( using namespace Data;
Data::PhotoSize::Thumbnail)) { if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) {
pix = thumbnail->pixSingle(size, args); pix = thumbnail->pixSingle(size, args);
} else if (const auto small = _photoMedia->image( } else if (const auto small = _photoMedia->image(PhotoSize::Small)) {
Data::PhotoSize::Small)) {
pix = small->pixSingle(size, args.blurred()); pix = small->pixSingle(size, args.blurred());
} else if (const auto blurred = _photoMedia->thumbnailInline()) { } else if (const auto blurred = _photoMedia->thumbnailInline()) {
pix = blurred->pixSingle(size, args.blurred()); pix = blurred->pixSingle(size, args.blurred());
@ -648,7 +661,12 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
const auto st = context.st; const auto st = context.st;
Ui::FillRoundRect( Ui::FillRoundRect(
p, p,
style::rtlrect(inner.left() + paintw - pw, tshift, pw, _pixh, width()), style::rtlrect(
inner.left() + paintw - pw,
tshift,
pw,
_pixh,
width()),
st->msgSelectOverlay(), st->msgSelectOverlay(),
st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small)); st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small));
} }
@ -679,32 +697,53 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
? stm->semiboldPalette ? stm->semiboldPalette
: st->coloredTextPalette(selected, colorIndex)); : st->coloredTextPalette(selected, colorIndex));
auto endskip = 0; const auto endskip = _siteName.hasSkipBlock()
if (_siteName.hasSkipBlock()) { ? _parent->skipBlockWidth()
endskip = _parent->skipBlockWidth(); : 0;
} _siteName.drawLeftElided(
_siteName.drawLeftElided(p, inner.left(), tshift, paintw, width(), _siteNameLines, style::al_left, 0, -1, endskip, false, context.selection); p,
inner.left(),
tshift,
paintw,
width(),
_siteNameLines,
style::al_left,
0,
-1,
endskip,
false,
context.selection);
tshift += lineHeight; tshift += lineHeight;
p.setTextPalette(stm->textPalette); p.setTextPalette(stm->textPalette);
} }
p.setPen(stm->historyTextFg); p.setPen(stm->historyTextFg);
if (_titleLines) { if (_titleLines) {
auto endskip = 0; const auto endskip = _title.hasSkipBlock()
if (_title.hasSkipBlock()) { ? _parent->skipBlockWidth()
endskip = _parent->skipBlockWidth(); : 0;
}
const auto titleWidth = asSponsored const auto titleWidth = asSponsored
? (paintw - _pixh - st::webPagePhotoDelta) ? (paintw - _pixh - st::webPagePhotoDelta)
: paintw; : paintw;
_title.drawLeftElided(p, inner.left(), tshift, titleWidth, width(), _titleLines, style::al_left, 0, -1, endskip, false, toTitleSelection(context.selection)); _title.drawLeftElided(
p,
inner.left(),
tshift,
titleWidth,
width(),
_titleLines,
style::al_left,
0,
-1,
endskip,
false,
toTitleSelection(context.selection));
tshift += _titleLines * lineHeight; tshift += _titleLines * lineHeight;
} }
if (_descriptionLines) { if (_descriptionLines) {
auto endskip = 0; const auto endskip = _description.hasSkipBlock()
if (_description.hasSkipBlock()) { ? _parent->skipBlockWidth()
endskip = _parent->skipBlockWidth(); : 0;
}
_parent->prepareCustomEmojiPaint(p, context, _description); _parent->prepareCustomEmojiPaint(p, context, _description);
_description.draw(p, { _description.draw(p, {
.position = { inner.left(), tshift }, .position = { inner.left(), tshift },
@ -725,12 +764,17 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
: _description.countHeight(paintw); : _description.countHeight(paintw);
} }
if (_attach) { if (_attach) {
auto attachAtTop = !_siteNameLines && !_titleLines && !_descriptionLines; const auto attachAtTop = !_siteNameLines
if (!attachAtTop) tshift += st::mediaInBubbleSkip; && !_titleLines
&& !_descriptionLines;
if (!attachAtTop) {
tshift += st::mediaInBubbleSkip;
}
auto attachLeft = inner.left() - bubble.left(); const auto attachLeft = rtl()
auto attachTop = tshift - bubble.top(); ? (width() - (inner.left() - bubble.left()) - _attach->width())
if (rtl()) attachLeft = width() - attachLeft - _attach->width(); : (inner.left() - bubble.left());
const auto attachTop = tshift - bubble.top();
p.translate(attachLeft, attachTop); p.translate(attachLeft, attachTop);
@ -740,8 +784,8 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
).withSelection(context.selected() ).withSelection(context.selected()
? FullSelection ? FullSelection
: TextSelection())); : TextSelection()));
auto pixwidth = _attach->width(); const auto pixwidth = _attach->width();
auto pixheight = _attach->height(); const auto pixheight = _attach->height();
if (_data->type == WebPageType::Video if (_data->type == WebPageType::Video
&& _collage.empty() && _collage.empty()
@ -749,22 +793,47 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
&& !_data->document) { && !_data->document) {
if (_attach->isReadyForOpen()) { if (_attach->isReadyForOpen()) {
if (_data->siteName == u"YouTube"_q) { if (_data->siteName == u"YouTube"_q) {
st->youtubeIcon().paint(p, (pixwidth - st::youtubeIcon.width()) / 2, (pixheight - st::youtubeIcon.height()) / 2, width()); st->youtubeIcon().paint(
p,
(pixwidth - st::youtubeIcon.width()) / 2,
(pixheight - st::youtubeIcon.height()) / 2,
width());
} else { } else {
st->videoIcon().paint(p, (pixwidth - st::videoIcon.width()) / 2, (pixheight - st::videoIcon.height()) / 2, width()); st->videoIcon().paint(
p,
(pixwidth - st::videoIcon.width()) / 2,
(pixheight - st::videoIcon.height()) / 2,
width());
} }
} }
if (_durationWidth) { if (_durationWidth) {
auto dateX = pixwidth - _durationWidth - st::msgDateImgDelta - 2 * st::msgDateImgPadding.x(); const auto dateX = pixwidth
auto dateY = pixheight - st::msgDateFont->height - 2 * st::msgDateImgPadding.y() - st::msgDateImgDelta; - _durationWidth
auto dateW = pixwidth - dateX - st::msgDateImgDelta; - st::msgDateImgDelta
auto dateH = pixheight - dateY - st::msgDateImgDelta; - 2 * st::msgDateImgPadding.x();
const auto dateY = pixheight
- st::msgDateFont->height
- 2 * st::msgDateImgPadding.y()
- st::msgDateImgDelta;
const auto dateW = pixwidth - dateX - st::msgDateImgDelta;
const auto dateH = pixheight - dateY - st::msgDateImgDelta;
Ui::FillRoundRect(p, dateX, dateY, dateW, dateH, sti->msgDateImgBg, sti->msgDateImgBgCorners); Ui::FillRoundRect(
p,
dateX,
dateY,
dateW,
dateH,
sti->msgDateImgBg,
sti->msgDateImgBgCorners);
p.setFont(st::msgDateFont); p.setFont(st::msgDateFont);
p.setPen(st->msgDateImgFg()); p.setPen(st->msgDateImgFg());
p.drawTextLeft(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y(), pixwidth, _duration); p.drawTextLeft(
dateX + st::msgDateImgPadding.x(),
dateY + st::msgDateImgPadding.y(),
pixwidth,
_duration);
} }
} }
@ -773,7 +842,11 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
if (!attachAdditionalInfoText.isEmpty()) { if (!attachAdditionalInfoText.isEmpty()) {
p.setFont(st::msgDateFont); p.setFont(st::msgDateFont);
p.setPen(stm->msgDateFg); p.setPen(stm->msgDateFg);
p.drawTextLeft(st::msgPadding.left(), outer.y() + outer.height() + st::mediaInBubbleSkip, width(), attachAdditionalInfoText); p.drawTextLeft(
st::msgPadding.left(),
outer.y() + outer.height() + st::mediaInBubbleSkip,
width(),
attachAdditionalInfoText);
} }
} }
@ -800,74 +873,91 @@ bool WebPage::asArticle() const {
TextState WebPage::textState(QPoint point, StateRequest request) const { TextState WebPage::textState(QPoint point, StateRequest request) const {
auto result = TextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < rect::m::sum::h(st::msgPadding) + 1) {
return result; return result;
} }
const auto bubble = _attach ? _attach->bubbleMargins() : QMargins(); const auto bubble = _attach ? _attach->bubbleMargins() : QMargins();
const auto full = QRect(0, 0, width(), height()); const auto full = Rect(currentSize());
auto outer = full.marginsRemoved(inBubblePadding()); auto outer = full - inBubblePadding();
if (_sponsoredData) { if (_sponsoredData) {
outer.translate(0, st::msgDateFont->height); outer.translate(0, st::msgDateFont->height);
} }
auto inner = outer.marginsRemoved(innerMargin()); const auto inner = outer - innerMargin();
auto tshift = inner.top(); auto tshift = inner.top();
auto paintw = inner.width(); auto paintw = inner.width();
auto lineHeight = UnitedLineHeight(); const auto lineHeight = UnitedLineHeight();
auto inThumb = false; auto inThumb = false;
if (asArticle()) { if (asArticle()) {
auto pw = qMax(_pixw, lineHeight); const auto pw = std::max(_pixw, lineHeight);
if (style::rtlrect(inner.left() + paintw - pw, tshift, pw, _pixh, width()).contains(point)) { inThumb = style::rtlrect(
inThumb = true; inner.left() + paintw - pw,
} tshift,
pw,
_pixh,
width()).contains(point);
paintw -= pw + st::webPagePhotoDelta; paintw -= pw + st::webPagePhotoDelta;
} }
int symbolAdd = 0; auto symbolAdd = int(0);
if (_siteNameLines) { if (_siteNameLines) {
if (point.y() >= tshift && point.y() < tshift + lineHeight) { if (point.y() >= tshift && point.y() < tshift + lineHeight) {
Ui::Text::StateRequestElided siteNameRequest = request.forText(); auto siteNameRequest = Ui::Text::StateRequestElided(
request.forText());
siteNameRequest.lines = _siteNameLines; siteNameRequest.lines = _siteNameLines;
result = TextState(_parent, _siteName.getStateElidedLeft( result = TextState(
point - QPoint(inner.left(), tshift), _parent,
paintw, _siteName.getStateElidedLeft(
width(), point - QPoint(inner.left(), tshift),
siteNameRequest)); paintw,
width(),
siteNameRequest));
} else if (point.y() >= tshift + lineHeight) { } else if (point.y() >= tshift + lineHeight) {
symbolAdd += _siteName.length(); symbolAdd += _siteName.length();
} }
tshift += lineHeight; tshift += lineHeight;
} }
if (_titleLines) { if (_titleLines) {
if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { if (point.y() >= tshift
Ui::Text::StateRequestElided titleRequest = request.forText(); && point.y() < tshift + _titleLines * lineHeight) {
auto titleRequest = Ui::Text::StateRequestElided(
request.forText());
titleRequest.lines = _titleLines; titleRequest.lines = _titleLines;
result = TextState(_parent, _title.getStateElidedLeft( result = TextState(
point - QPoint(inner.left(), tshift), _parent,
paintw, _title.getStateElidedLeft(
width(), point - QPoint(inner.left(), tshift),
titleRequest)); paintw,
width(),
titleRequest));
} else if (point.y() >= tshift + _titleLines * lineHeight) { } else if (point.y() >= tshift + _titleLines * lineHeight) {
symbolAdd += _title.length(); symbolAdd += _title.length();
} }
tshift += _titleLines * lineHeight; tshift += _titleLines * lineHeight;
} }
if (_descriptionLines) { if (_descriptionLines) {
auto descriptionHeight = (_descriptionLines > 0) ? _descriptionLines * lineHeight : _description.countHeight(paintw); const auto descriptionHeight = (_descriptionLines > 0)
? _descriptionLines * lineHeight
: _description.countHeight(paintw);
if (point.y() >= tshift && point.y() < tshift + descriptionHeight) { if (point.y() >= tshift && point.y() < tshift + descriptionHeight) {
if (_descriptionLines > 0) { if (_descriptionLines > 0) {
Ui::Text::StateRequestElided descriptionRequest = request.forText(); auto descriptionRequest = Ui::Text::StateRequestElided(
request.forText());
descriptionRequest.lines = _descriptionLines; descriptionRequest.lines = _descriptionLines;
result = TextState(_parent, _description.getStateElidedLeft( result = TextState(
point - QPoint(inner.left(), tshift), _parent,
paintw, _description.getStateElidedLeft(
width(), point - QPoint(inner.left(), tshift),
descriptionRequest)); paintw,
width(),
descriptionRequest));
} else { } else {
result = TextState(_parent, _description.getStateLeft( result = TextState(
point - QPoint(inner.left(), tshift), _parent,
paintw, _description.getStateLeft(
width(), point - QPoint(inner.left(), tshift),
request.forText())); paintw,
width(),
request.forText()));
} }
} else if (point.y() >= tshift + descriptionHeight) { } else if (point.y() >= tshift + descriptionHeight) {
symbolAdd += _description.length(); symbolAdd += _description.length();
@ -877,14 +967,26 @@ TextState WebPage::textState(QPoint point, StateRequest request) const {
if (inThumb) { if (inThumb) {
result.link = _openl; result.link = _openl;
} else if (_attach) { } else if (_attach) {
auto attachAtTop = !_siteNameLines && !_titleLines && !_descriptionLines; const auto attachAtTop = !_siteNameLines
if (!attachAtTop) tshift += st::mediaInBubbleSkip; && !_titleLines
&& !_descriptionLines;
if (!attachAtTop) {
tshift += st::mediaInBubbleSkip;
}
if (QRect(inner.left(), tshift, paintw, inner.top() + inner.height() - tshift).contains(point)) { const auto rect = QRect(
auto attachLeft = inner.left() - bubble.left(); inner.left(),
auto attachTop = tshift - bubble.top(); tshift,
if (rtl()) attachLeft = width() - attachLeft - _attach->width(); paintw,
result = _attach->textState(point - QPoint(attachLeft, attachTop), request); inner.top() + inner.height() - tshift);
if (rect.contains(point)) {
const auto attachLeft = rtl()
? width() - (inner.left() - bubble.left()) - _attach->width()
: (inner.left() - bubble.left());
const auto attachTop = tshift - bubble.top();
result = _attach->textState(
point - QPoint(attachLeft, attachTop),
request);
if (result.cursor == CursorState::Enlarge) { if (result.cursor == CursorState::Enlarge) {
result.cursor = CursorState::None; result.cursor = CursorState::None;
} else { } else {
@ -916,27 +1018,37 @@ ClickHandlerPtr WebPage::replaceAttachLink(
return _openl; return _openl;
} }
TextSelection WebPage::adjustSelection(TextSelection selection, TextSelectType type) const { TextSelection WebPage::adjustSelection(
if ((!_titleLines && !_descriptionLines) || selection.to <= _siteName.length()) { TextSelection selection,
TextSelectType type) const {
if ((!_titleLines && !_descriptionLines)
|| selection.to <= _siteName.length()) {
return _siteName.adjustSelection(selection, type); return _siteName.adjustSelection(selection, type);
} }
auto titlesLength = _siteName.length() + _title.length(); const auto titlesLength = _siteName.length() + _title.length();
auto titleSelection = _title.adjustSelection(toTitleSelection(selection), type); const auto titleSelection = _title.adjustSelection(
if ((!_siteNameLines && !_descriptionLines) || (selection.from >= _siteName.length() && selection.to <= titlesLength)) { toTitleSelection(selection),
type);
if ((!_siteNameLines && !_descriptionLines)
|| (selection.from >= _siteName.length()
&& selection.to <= titlesLength)) {
return fromTitleSelection(titleSelection); return fromTitleSelection(titleSelection);
} }
auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); const auto descriptionSelection = _description.adjustSelection(
toDescriptionSelection(selection),
type);
if ((!_siteNameLines && !_titleLines) || selection.from >= titlesLength) { if ((!_siteNameLines && !_titleLines) || selection.from >= titlesLength) {
return fromDescriptionSelection(descriptionSelection); return fromDescriptionSelection(descriptionSelection);
} }
auto siteNameSelection = _siteName.adjustSelection(selection, type); return {
if (!_descriptionLines || selection.to <= titlesLength) { _siteName.adjustSelection(selection, type).from,
return { siteNameSelection.from, fromTitleSelection(titleSelection).to }; (!_descriptionLines || selection.to <= titlesLength)
} ? fromTitleSelection(titleSelection).to
return { siteNameSelection.from, fromDescriptionSelection(descriptionSelection).to }; : fromDescriptionSelection(descriptionSelection).to,
};
} }
uint16 WebPage::fullSelectionLength() const { uint16 WebPage::fullSelectionLength() const {
@ -957,8 +1069,8 @@ void WebPage::clickHandlerPressedChanged(
if (p == _openl) { if (p == _openl) {
if (pressed) { if (pressed) {
if (!_ripple) { if (!_ripple) {
const auto full = QRect(0, 0, width(), height()); const auto full = Rect(currentSize());
const auto outer = full.marginsRemoved(inBubblePadding()); const auto outer = full - inBubblePadding();
const auto owner = &parent()->history()->owner(); const auto owner = &parent()->history()->owner();
_ripple = std::make_unique<Ui::RippleAnimation>( _ripple = std::make_unique<Ui::RippleAnimation>(
st::defaultRippleAnimation, st::defaultRippleAnimation,
@ -994,23 +1106,20 @@ void WebPage::playAnimation(bool autoplay) {
} }
bool WebPage::isDisplayed() const { bool WebPage::isDisplayed() const {
const auto item = _parent->data();
return !_data->pendingTill return !_data->pendingTill
&& !_data->failed && !_data->failed
&& !item->Has<HistoryMessageLogEntryOriginal>(); && !_parent->data()->Has<HistoryMessageLogEntryOriginal>();
} }
QString WebPage::additionalInfoString() const { QString WebPage::additionalInfoString() const {
return _attach ? _attach->additionalInfoString() : QString(); return _attach ? _attach->additionalInfoString() : QString();
} }
bool WebPage::toggleSelectionByHandlerClick( bool WebPage::toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const {
const ClickHandlerPtr &p) const {
return _attach && _attach->toggleSelectionByHandlerClick(p); return _attach && _attach->toggleSelectionByHandlerClick(p);
} }
bool WebPage::allowTextSelectionByHandler( bool WebPage::allowTextSelectionByHandler(const ClickHandlerPtr &p) const {
const ClickHandlerPtr &p) const {
return (p == _openl); return (p == _openl);
} }
@ -1020,8 +1129,7 @@ bool WebPage::dragItemByHandler(const ClickHandlerPtr &p) const {
TextForMimeData WebPage::selectedText(TextSelection selection) const { TextForMimeData WebPage::selectedText(TextSelection selection) const {
auto siteNameResult = _siteName.toTextForMimeData(selection); auto siteNameResult = _siteName.toTextForMimeData(selection);
auto titleResult = _title.toTextForMimeData( auto titleResult = _title.toTextForMimeData(toTitleSelection(selection));
toTitleSelection(selection));
auto descriptionResult = _description.toTextForMimeData( auto descriptionResult = _description.toTextForMimeData(
toDescriptionSelection(selection)); toDescriptionSelection(selection));
if (titleResult.empty() && descriptionResult.empty()) { if (titleResult.empty() && descriptionResult.empty()) {
@ -1033,12 +1141,18 @@ TextForMimeData WebPage::selectedText(TextSelection selection) const {
} else if (siteNameResult.empty()) { } else if (siteNameResult.empty()) {
return titleResult.append('\n').append(std::move(descriptionResult)); return titleResult.append('\n').append(std::move(descriptionResult));
} else if (titleResult.empty()) { } else if (titleResult.empty()) {
return siteNameResult.append('\n').append(std::move(descriptionResult)); return siteNameResult
.append('\n')
.append(std::move(descriptionResult));
} else if (descriptionResult.empty()) { } else if (descriptionResult.empty()) {
return siteNameResult.append('\n').append(std::move(titleResult)); return siteNameResult.append('\n').append(std::move(titleResult));
} }
return siteNameResult.append('\n').append(std::move(titleResult)).append('\n').append(std::move(descriptionResult)); return siteNameResult
.append('\n')
.append(std::move(titleResult))
.append('\n')
.append(std::move(descriptionResult));
} }
QMargins WebPage::inBubblePadding() const { QMargins WebPage::inBubblePadding() const {