Support rich text in toasts.

This commit is contained in:
John Preston 2020-04-07 13:58:24 +04:00
parent 14c5da49f9
commit 8d8d561127
7 changed files with 75 additions and 5 deletions

View file

@ -271,6 +271,10 @@ inlineResultsMinWidth: 48px;
inlineDurationMargin: 3px; inlineDurationMargin: 3px;
toastTextStyle: defaultTextStyle; toastTextStyle: defaultTextStyle;
toastTextPalette: TextPalette(defaultTextPalette) {
linkFg: mediaviewTextLinkFg;
monoFg: mediaviewCaptionFg;
}
toastMaxWidth: 480px; toastMaxWidth: 480px;
toastMinMargin: 13px; toastMinMargin: 13px;
toastPadding: margins(19px, 13px, 19px, 12px); toastPadding: margins(19px, 13px, 19px, 12px);

View file

@ -1321,6 +1321,12 @@ QString SingleLine(const QString &text) {
return result; return result;
} }
TextWithEntities SingleLine(const TextWithEntities &text) {
auto copy = text;
Trim(copy);
return { SingleLine(copy.text), std::move(copy.entities) };
}
QString RemoveAccents(const QString &text) { QString RemoveAccents(const QString &text) {
auto result = text; auto result = text;
auto copying = false; auto copying = false;

View file

@ -285,6 +285,7 @@ QString MarkdownPreBadAfter();
QString Clean(const QString &text); QString Clean(const QString &text);
QString EscapeForRichParsing(const QString &text); QString EscapeForRichParsing(const QString &text);
QString SingleLine(const QString &text); QString SingleLine(const QString &text);
TextWithEntities SingleLine(const TextWithEntities &text);
QString RemoveAccents(const QString &text); QString RemoveAccents(const QString &text);
QString RemoveEmoji(const QString &text); QString RemoveEmoji(const QString &text);
QStringList PrepareSearchWords(const QString &query, const QRegularExpression *SplitterOverride = nullptr); QStringList PrepareSearchWords(const QString &query, const QRegularExpression *SplitterOverride = nullptr);

View file

@ -50,13 +50,13 @@ void Show(const Config &config) {
void Show(not_null<QWidget*> parent, const QString &text) { void Show(not_null<QWidget*> parent, const QString &text) {
auto config = Config(); auto config = Config();
config.text = text; config.text = { text };
Show(parent, config); Show(parent, config);
} }
void Show(const QString &text) { void Show(const QString &text) {
auto config = Config(); auto config = Config();
config.text = text; config.text = { text };
Show(config); Show(config);
} }

View file

@ -7,6 +7,7 @@
#pragma once #pragma once
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/text/text_entity.h"
namespace Ui { namespace Ui {
namespace Toast { namespace Toast {
@ -18,7 +19,7 @@ class Widget;
inline constexpr auto kDefaultDuration = crl::time(1500); inline constexpr auto kDefaultDuration = crl::time(1500);
struct Config { struct Config {
QString text; TextWithEntities text;
QMargins padding; QMargins padding;
crl::time durationMs = kDefaultDuration; crl::time durationMs = kDefaultDuration;
int minWidth = 0; int minWidth = 0;

View file

@ -9,6 +9,8 @@
#include "ui/image/image_prepare.h" #include "ui/image/image_prepare.h"
#include "styles/palette.h" #include "styles/palette.h"
#include <QtGui/QtEvents>
namespace Ui { namespace Ui {
namespace Toast { namespace Toast {
namespace internal { namespace internal {
@ -29,12 +31,16 @@ Widget::Widget(QWidget *parent, const Config &config)
_maxTextHeight, _maxTextHeight,
Qt::LayoutDirectionAuto Qt::LayoutDirectionAuto
}; };
_text.setText( _text.setMarkedText(
st::toastTextStyle, st::toastTextStyle,
_multiline ? config.text : TextUtilities::SingleLine(config.text), _multiline ? config.text : TextUtilities::SingleLine(config.text),
toastOptions); toastOptions);
if (_text.hasLinks()) {
setMouseTracking(true);
} else {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
}
onParentResized(); onParentResized();
show(); show();
@ -63,11 +69,58 @@ void Widget::paintEvent(QPaintEvent *e) {
p.setOpacity(_shownLevel); p.setOpacity(_shownLevel);
_roundRect.paint(p, rect()); _roundRect.paint(p, rect());
p.setTextPalette(st::toastTextPalette);
const auto lines = _maxTextHeight / st::toastTextStyle.font->height; const auto lines = _maxTextHeight / st::toastTextStyle.font->height;
p.setPen(st::toastFg); p.setPen(st::toastFg);
_text.drawElided(p, _padding.left(), _padding.top(), _textWidth + 1, lines); _text.drawElided(p, _padding.left(), _padding.top(), _textWidth + 1, lines);
} }
void Widget::leaveEventHook(QEvent *e) {
if (!_text.hasLinks()) {
return;
}
if (ClickHandler::getActive()) {
ClickHandler::setActive(nullptr);
setCursor(style::cur_default);
update();
}
}
void Widget::mouseMoveEvent(QMouseEvent *e) {
if (!_text.hasLinks()) {
return;
}
const auto point = e->pos() - QPoint(_padding.left(), _padding.top());
const auto lines = _maxTextHeight / st::toastTextStyle.font->height;
const auto state = _text.getStateElided(point, _textWidth + 1);
const auto was = ClickHandler::getActive();
if (was != state.link) {
ClickHandler::setActive(state.link);
if ((was != nullptr) != (state.link != nullptr)) {
setCursor(was ? style::cur_default : style::cur_pointer);
}
update();
}
}
void Widget::mousePressEvent(QMouseEvent *e) {
if (!_text.hasLinks() || e->button() != Qt::LeftButton) {
return;
}
ClickHandler::pressed();
}
void Widget::mouseReleaseEvent(QMouseEvent *e) {
if (!_text.hasLinks() || e->button() != Qt::LeftButton) {
return;
}
if (const auto handler = ClickHandler::unpressed()) {
handler->onClick({ e->button() });
}
}
} // namespace internal } // namespace internal
} // namespace Toast } // namespace Toast
} // namespace Ui } // namespace Ui

View file

@ -27,6 +27,11 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private: private:
int widthWithoutPadding(int w) { int widthWithoutPadding(int w) {
return w - _padding.left() - _padding.right(); return w - _padding.left() - _padding.right();