From 01b7d4ffba7e61d558480d0533a2d6949482a13a Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 18 Jan 2019 12:11:15 +0400 Subject: [PATCH] Use Text to display empty group state. --- .../history/history_inner_widget.cpp | 46 ++-- .../history/history_inner_widget.h | 7 +- Telegram/SourceFiles/history/history_item.h | 2 +- .../SourceFiles/history/history_widget.cpp | 5 +- .../view/history_view_service_message.cpp | 216 ++++++++++-------- .../view/history_view_service_message.h | 20 +- .../SourceFiles/overview/overview_layout.h | 2 +- 7 files changed, 175 insertions(+), 123 deletions(-) diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 25473430c..13d522d2a 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -180,7 +180,7 @@ HistoryInner::HistoryInner( void HistoryInner::messagesReceived( PeerData *peer, const QVector &messages) { - if (_history && _history->peer == peer) { + if (_history->peer == peer) { _history->addOlderSlice(messages); } else if (_migrated && _migrated->peer == peer) { const auto newLoaded = _migrated @@ -194,7 +194,7 @@ void HistoryInner::messagesReceived( } void HistoryInner::messagesReceivedDown(PeerData *peer, const QVector &messages) { - if (_history && _history->peer == peer) { + if (_history->peer == peer) { const auto oldLoaded = _migrated && _history->isEmpty() && !_migrated->isEmpty(); @@ -523,6 +523,14 @@ TextSelection HistoryInner::itemRenderSelection( return TextSelection(); } +void HistoryInner::paintEmpty(Painter &p, int width, int height) { + if (!_emptyPainter) { + _emptyPainter = std::make_unique( + _history); + } + _emptyPainter->paint(p, width, height); +} + void HistoryInner::paintEvent(QPaintEvent *e) { if (Ui::skipPaintEvent(this, e)) { return; @@ -552,7 +560,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { p.restoreTextPalette(); } } else if (historyDisplayedEmpty) { - HistoryView::paintEmpty(p, _history, width(), height()); + paintEmpty(p, width(), height()); } if (!noHistoryDisplayed) { auto readMentions = base::flat_set>(); @@ -1371,8 +1379,6 @@ void HistoryInner::mouseReleaseEvent(QMouseEvent *e) { } void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { - if (!_history) return; - mouseActionStart(e->globalPos(), e->button()); const auto mouseActionView = _mouseActionItem @@ -2101,8 +2107,6 @@ bool HistoryInner::displayScrollDate() const { } void HistoryInner::scrollDateCheck() { - if (!_history) return; - auto newScrollDateItem = _history->scrollTopItem ? _history->scrollTopItem : (_migrated ? _migrated->scrollTopItem : nullptr); auto newScrollDateItemTop = _history->scrollTopItem ? _history->scrollTopOffset : (_migrated ? _migrated->scrollTopOffset : 0); //if (newScrollDateItem && !displayScrollDate()) { @@ -2282,7 +2286,6 @@ auto HistoryInner::nextItem(Element *view) -> Element* { } else if (const auto result = view->nextInBlocks()) { return result; } else if (view->data()->history() == _migrated - && _history && _migrated->loadedAtBottom() && _history->loadedAtTop() && !_history->isEmpty()) { @@ -2380,7 +2383,7 @@ void HistoryInner::onTouchSelect() { } void HistoryInner::mouseActionUpdate() { - if (!_history || hasPendingResizedItems()) { + if (hasPendingResizedItems()) { return; } @@ -2553,7 +2556,6 @@ void HistoryInner::mouseActionUpdate() { } } else if (item) { if (_mouseAction == MouseAction::Selecting) { - auto canSelectMany = (_history != nullptr); if (selectingText) { uint16 second = dragState.symbol; if (dragState.afterSymbol && _mouseSelectType == TextSelectType::Letters) { @@ -2573,8 +2575,8 @@ void HistoryInner::mouseActionUpdate() { _wasSelectedText = true; setFocus(); } - updateDragSelection(0, 0, false); - } else if (canSelectMany) { + updateDragSelection(nullptr, nullptr, false); + } else { auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y()); auto dragSelFrom = _mouseActionItem->mainView(); auto dragSelTo = view; @@ -2680,7 +2682,7 @@ void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo, int HistoryInner::historyHeight() const { int result = 0; - if (!_history || _history->isEmpty()) { + if (_history->isEmpty()) { result += _migrated ? _migrated->height() : 0; } else { result += _history->height() - _historySkipHeight + (_migrated ? _migrated->height() : 0); @@ -2706,7 +2708,11 @@ int HistoryInner::migratedTop() const { int HistoryInner::historyTop() const { int mig = migratedTop(); - return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height() - _historySkipHeight) : _historyPaddingTop) : -1; + return !_history->isEmpty() + ? (mig >= 0 + ? (mig + _migrated->height() - _historySkipHeight) + : _historyPaddingTop) + : -1; } int HistoryInner::historyDrawTop() const { @@ -2736,7 +2742,7 @@ int HistoryInner::itemTop(const Element *view) const { } void HistoryInner::notifyIsBotChanged() { - const auto newinfo = (_peer && _peer->isUser()) + const auto newinfo = _peer->isUser() ? _peer->asUser()->botInfo.get() : nullptr; if ((!newinfo && !_botAbout) @@ -2918,7 +2924,7 @@ void HistoryInner::deleteItem(not_null item) { } bool HistoryInner::hasPendingResizedItems() const { - return (_history && _history->hasPendingResizedItems()) + return _history->hasPendingResizedItems() || (_migrated && _migrated->hasPendingResizedItems()); } @@ -3007,12 +3013,12 @@ void HistoryInner::applyDragSelection( addSelectionRange(toItems, _history, fromblock, fromitem, toblock, toitem); } else { auto toRemove = std::vector>(); - for (auto i = toItems->begin(); i != toItems->cend(); ++i) { - auto iy = itemTop(i->first); + for (const auto &item : *toItems) { + auto iy = itemTop(item.first); if (iy < -1) { - toRemove.push_back(i->first); + toRemove.emplace_back(item.first); } else if (iy >= 0 && iy >= selfromy && iy < seltoy) { - toRemove.push_back(i->first); + toRemove.emplace_back(item.first); } } for (const auto item : toRemove) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 6bb22673b..75877a168 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -23,6 +23,7 @@ struct TextState; struct StateRequest; enum class CursorState : char; enum class PointState : char; +class EmptyPainter; } // namespace HistoryView namespace Window { @@ -54,6 +55,7 @@ public: void messagesReceivedDown(PeerData *peer, const QVector &messages); TextWithEntities getSelectedText() const; + void paintEmpty(Painter &p, int width, int height); void touchScrollUpdated(const QPoint &screenPos); @@ -292,8 +294,8 @@ private: not_null _controller; - not_null _peer; - not_null _history; + const not_null _peer; + const not_null _history; History *_migrated = nullptr; int _contentWidth = 0; int _historyPaddingTop = 0; @@ -303,6 +305,7 @@ private: int _historySkipHeight = 0; std::unique_ptr _botAbout; + std::unique_ptr _emptyPainter; HistoryWidget *_widget = nullptr; Ui::ScrollArea *_scroll = nullptr; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 1cf8482e2..79dd52479 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -298,7 +298,7 @@ protected: void setGroupId(MessageGroupId groupId); - Text _text = { int(st::msgMinWidth) }; + Text _text = { st::msgMinWidth }; int _textWidth = -1; int _textHeight = 0; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 3421355d1..25d3b2954 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6557,7 +6557,10 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { } if (_scroll->isHidden() && _history) { p.setClipRect(_scroll->geometry()); - HistoryView::paintEmpty(p, _history, width(), height() - _field->height() - 2 * st::historySendPadding); + _list->paintEmpty( + p, + width(), + height() - _field->height() - 2 * st::historySendPadding); } } else { const auto w = st::msgServiceFont->width(lang(lng_willbe_history)) diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index a1023a7ae..7b70cba2d 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -15,10 +15,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_abstract_structure.h" #include "data/data_chat.h" #include "data/data_channel.h" -#include "styles/style_history.h" +#include "ui/text_options.h" #include "mainwidget.h" #include "layout.h" #include "lang/lang_keys.h" +#include "styles/style_history.h" namespace HistoryView { namespace { @@ -175,81 +176,13 @@ void paintPreparedDate(Painter &p, const QString &dateText, int dateTextWidth, i p.drawText(left + st::msgServicePadding.left(), y + st::msgServiceMargin.top() + st::msgServicePadding.top() + st::msgServiceFont->ascent, dateText); } -void PaintAboutGroup(Painter &p, int width, int height) { - constexpr auto kPhrasesCount = 4; - const auto header = lang(lng_group_about_header); - const auto text = lang(lng_group_about_text); - const auto phrases = std::array{ - lang(lng_group_about1), - lang(lng_group_about2), - lang(lng_group_about3), - lang(lng_group_about4), - }; - - const auto &font = st::msgServiceFont; - const auto headerWidth = font->width(header); - const auto textWidth = font->width(text); - const auto phraseWidths = ranges::view::all( - phrases - ) | ranges::view::transform([&](const QString &text) { - return font->width(text); - }) | ranges::to_vector; - - const auto maxPhraseWidth = *ranges::max_element(phraseWidths); - - const auto margin = st::msgMargin.left(); - const auto maxBubbleWidth = width - 2 * st::historyGroupAboutMargin; - const auto padding = st::historyGroupAboutPadding; - const auto bubbleWidth = std::min( - maxBubbleWidth, - std::max({ - maxPhraseWidth + st::historyGroupAboutBulletSkip, - headerWidth, - textWidth }) + padding.left() + padding.right()); - const auto bubbleHeight = padding.top() - + font->height - + st::historyGroupAboutHeaderSkip - + font->height - + st::historyGroupAboutTextSkip - + font->height * kPhrasesCount - + st::historyGroupAboutSkip * (kPhrasesCount - 1) - + padding.bottom(); - const auto bubbleLeft = (width - bubbleWidth) / 2; - const auto bubbleTop = (height - bubbleHeight) / 3; - - ServiceMessagePainter::paintBubble( - p, - bubbleLeft, - bubbleTop, - bubbleWidth, - bubbleHeight); - - p.setFont(font); - p.setPen(st::msgServiceFg); - const auto left = bubbleLeft + padding.left(); - auto top = bubbleTop + padding.top(); - - p.drawTextLeft(bubbleLeft + (bubbleWidth - headerWidth) / 2, top, width, header); - top += font->height + st::historyGroupAboutHeaderSkip; - - p.drawTextLeft(left, top, width, text); - top += font->height + st::historyGroupAboutTextSkip; - - p.setBrush(st::msgServiceFg); - for (const auto &text : phrases) { - p.setPen(st::msgServiceFg); - p.drawTextLeft(left + st::historyGroupAboutBulletSkip, top, width, text); - { - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.drawEllipse( - left, - top + (font->height - st::mediaUnreadSize) / 2, - st::mediaUnreadSize, - st::mediaUnreadSize); - } - top += font->height + st::historyGroupAboutSkip; +bool NeedAboutGroup(not_null history) { + if (const auto chat = history->peer->asChat()) { + return chat->amCreator(); + } else if (const auto channel = history->peer->asMegagroup()) { + return channel->amCreator(); } + return false; } } // namepsace @@ -360,24 +293,6 @@ QVector ServiceMessagePainter::countLineWidths(const Text &text, const QRec return lineWidths; } -void paintEmpty( - Painter &p, - not_null history, - int width, - int height) { - const auto needAboutGroup = [&] { - if (const auto chat = history->peer->asChat()) { - return chat->amCreator(); - } else if (const auto channel = history->peer->asMegagroup()) { - return channel->amCreator(); - } - return false; - }(); - if (needAboutGroup) { - PaintAboutGroup(p, width, height); - } -} - void serviceColorsUpdated() { if (serviceMessageStyle) { for (auto &corner : serviceMessageStyle->corners) { @@ -625,4 +540,119 @@ TextSelection Service::adjustSelection( return message()->_text.adjustSelection(selection, type); } +EmptyPainter::EmptyPainter(not_null history) : _history(history) { + if (NeedAboutGroup(_history)) { + fillAboutGroup(); + } +} + +void EmptyPainter::fillAboutGroup() { + const auto phrases = { + lang(lng_group_about1), + lang(lng_group_about2), + lang(lng_group_about3), + lang(lng_group_about4), + }; + const auto setText = [](Text &text, const QString &content) { + text.setText( + st::serviceTextStyle, + content, + Ui::ItemTextServiceOptions()); + }; + setText(_header, lang(lng_group_about_header)); + setText(_text, lang(lng_group_about_header)); + for (const auto &text : phrases) { + _phrases.emplace_back(st::msgMinWidth); + setText(_phrases.back(), text); + } +} + +void EmptyPainter::paint(Painter &p, int width, int height) { + if (_phrases.empty()) { + return; + } + constexpr auto kMaxTextLines = 3; + const auto maxPhraseWidth = ranges::max_element( + _phrases, + ranges::less(), + &Text::maxWidth + )->maxWidth(); + + const auto &font = st::serviceTextStyle.font; + const auto margin = st::msgMargin.left(); + const auto maxBubbleWidth = width - 2 * st::historyGroupAboutMargin; + const auto padding = st::historyGroupAboutPadding; + const auto bubbleWidth = std::min( + maxBubbleWidth, + std::max({ + maxPhraseWidth + st::historyGroupAboutBulletSkip, + _header.maxWidth(), + _text.maxWidth() }) + padding.left() + padding.right()); + const auto innerWidth = bubbleWidth - padding.left() - padding.right(); + const auto textHeight = [&](const Text &text) { + return std::min( + text.countHeight(innerWidth), + kMaxTextLines * font->height); + }; + const auto bubbleHeight = padding.top() + + textHeight(_header) + + st::historyGroupAboutHeaderSkip + + textHeight(_text) + + st::historyGroupAboutTextSkip + + ranges::accumulate(_phrases, 0, ranges::plus(), textHeight) + + st::historyGroupAboutSkip * int(_phrases.size() - 1) + + padding.bottom(); + const auto bubbleLeft = (width - bubbleWidth) / 2; + const auto bubbleTop = (height - bubbleHeight) / 3; + + ServiceMessagePainter::paintBubble( + p, + bubbleLeft, + bubbleTop, + bubbleWidth, + bubbleHeight); + + p.setPen(st::msgServiceFg); + p.setBrush(st::msgServiceFg); + + const auto left = bubbleLeft + padding.left(); + auto top = bubbleTop + padding.top(); + + _header.drawElided( + p, + left, + top, + innerWidth, + kMaxTextLines, + style::al_top); + top += textHeight(_header) + st::historyGroupAboutHeaderSkip; + + _text.drawElided( + p, + left, + top, + innerWidth, + kMaxTextLines); + top += textHeight(_text) + st::historyGroupAboutTextSkip; + + for (const auto &text : _phrases) { + p.setPen(st::msgServiceFg); + text.drawElided( + p, + left + st::historyGroupAboutBulletSkip, + top, + innerWidth, + kMaxTextLines); + + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.drawEllipse( + left, + top + (font->height - st::mediaUnreadSize) / 2, + st::mediaUnreadSize, + st::mediaUnreadSize); + top += textHeight(text) + st::historyGroupAboutSkip; + } +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index 1854e2145..6562bf74c 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -74,11 +74,21 @@ private: }; -void paintEmpty( - Painter &p, - not_null history, - int width, - int height); +class EmptyPainter { +public: + explicit EmptyPainter(not_null history); + + void paint(Painter &p, int width, int height); + +private: + void fillAboutGroup(); + + not_null _history; + Text _header = { st::msgMinWidth }; + Text _text = { st::msgMinWidth }; + std::vector _phrases; + +}; void serviceColorsUpdated(); diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 78faa93bc..adb0dd04b 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -352,7 +352,7 @@ private: WebPageData *_page = nullptr; int _pixw = 0; int _pixh = 0; - Text _text = { int(st::msgMinWidth) }; + Text _text = { st::msgMinWidth }; struct LinkEntry { LinkEntry() : width(0) {