Improve toasts: adaptive, with a title.

This commit is contained in:
John Preston 2023-08-01 19:05:07 +02:00
parent 91d43ea4b5
commit ad356135e4
5 changed files with 60 additions and 14 deletions

View file

@ -33,10 +33,12 @@ using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
inline constexpr auto kDefaultDuration = crl::time(1500);
struct Config {
QString title;
TextWithEntities text;
not_null<const style::Toast*> st = &st::defaultMultilineToast;
crl::time duration = kDefaultDuration;
int maxLines = 16;
bool adaptive = false;
bool multiline = true;
bool dark = false;
RectPart slideSide = RectPart::None;

View file

@ -7,6 +7,8 @@
#include "ui/toast/toast_widget.h"
#include "ui/image/image_prepare.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/tooltip.h"
#include "ui/painter.h"
#include "styles/palette.h"
#include "styles/style_widgets.h"
@ -16,6 +18,21 @@
namespace Ui {
namespace Toast {
namespace internal {
namespace {
[[nodiscard]] TextWithEntities ComputeText(const Config &config) {
auto result = config.text;
if (!config.title.isEmpty()) {
result = Text::Bold(
config.title
).append('\n').append(std::move(result));
}
return config.multiline
? result
: TextUtilities::SingleLine(std::move(result));
}
} // namespace
Widget::Widget(QWidget *parent, const Config &config)
: RpWidget(parent)
@ -24,6 +41,7 @@ Widget::Widget(QWidget *parent, const Config &config)
, _slideSide(config.slideSide)
, _multiline(config.multiline)
, _dark(config.dark)
, _adaptive(config.adaptive)
, _maxTextWidth(widthWithoutPadding(_st->maxWidth))
, _maxTextHeight(
config.st->style.font->height * (_multiline ? config.maxLines : 1))
@ -37,7 +55,7 @@ Widget::Widget(QWidget *parent, const Config &config)
};
_text.setMarkedText(
_st->style,
_multiline ? config.text : TextUtilities::SingleLine(config.text),
ComputeText(config),
toastOptions,
config.textContext ? config.textContext(this) : std::any());
if (_text.hasSpoilers()) {
@ -74,6 +92,12 @@ void Widget::updateGeometry() {
accumulate_min(
width,
parentWidget()->width() - _st->margin.left() - _st->margin.right());
if (_adaptive) {
const auto added = _st->padding.left() + _st->padding.right();
width = FindNiceTooltipWidth(0, width - added, [&](int width) {
return _text.countHeight(width);
}) + added;
}
_textWidth = widthWithoutPadding(width);
_textHeight = _multiline
? qMin(_text.countHeight(_textWidth), _maxTextHeight)

View file

@ -45,6 +45,7 @@ private:
bool _multiline = false;
bool _dark = false;
bool _processMouse = false;
bool _adaptive = false;
int _maxTextWidth = 0;
int _maxTextHeight = 0;

View file

@ -411,6 +411,25 @@ void ImportantTooltip::paintEvent(QPaintEvent *e) {
}
}
[[nodiscard]] int FindNiceTooltipWidth(
int minWidth,
int maxWidth,
Fn<int(int width)> heightForWidth) {
Expects(minWidth >= 0);
Expects(maxWidth > minWidth);
const auto desired = heightForWidth(maxWidth);
while (maxWidth - minWidth > 1) {
const auto middle = (minWidth + maxWidth) / 2;
if (heightForWidth(middle) > desired) {
minWidth = middle;
} else {
maxWidth = middle;
}
}
return maxWidth;
}
object_ptr<FlatLabel> MakeNiceTooltipLabel(
QWidget *parent,
rpl::producer<TextWithEntities> &&text,
@ -431,19 +450,14 @@ object_ptr<FlatLabel> MakeNiceTooltipLabel(
if (raw->naturalWidth() <= maxWidth) {
return;
}
const auto desired = raw->heightNoMargins();
auto from = st.minWidth;
auto till = maxWidth;
while (till - from > 1) {
const auto middle = (from + till) / 2;
raw->resizeToWidth(middle);
if (raw->heightNoMargins() > desired) {
from = middle;
} else {
till = middle;
}
}
raw->resizeToWidth(till);
const auto niceWidth = FindNiceTooltipWidth(
st.minWidth,
maxWidth,
[&](int width) {
raw->resizeToWidth(width);
return raw->heightNoMargins();
});
raw->resizeToWidth(niceWidth);
}, raw->lifetime());
return result;
}

View file

@ -122,6 +122,11 @@ private:
};
[[nodiscard]] int FindNiceTooltipWidth(
int minWidth,
int maxWidth,
Fn<int(int width)> heightForWidth);
[[nodiscard]] object_ptr<FlatLabel> MakeNiceTooltipLabel(
QWidget *parent,
rpl::producer<TextWithEntities> &&text,