Improve ImportantTooltip.
This commit is contained in:
parent
8fbeb7f503
commit
f475fe28e4
2 changed files with 104 additions and 91 deletions
|
|
@ -185,51 +185,54 @@ void Tooltip::Hide() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportantTooltip::ImportantTooltip(QWidget *parent, object_ptr<TWidget> content, const style::ImportantTooltip &st) : TWidget(parent)
|
ImportantTooltip::ImportantTooltip(
|
||||||
|
QWidget *parent,
|
||||||
|
object_ptr<RpWidget> content,
|
||||||
|
const style::ImportantTooltip &st)
|
||||||
|
: RpWidget(parent)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
, _content(std::move(content)) {
|
, _content(std::move(content)) {
|
||||||
_content->setParent(this);
|
_content->setParent(this);
|
||||||
_hideTimer.setCallback([this] { toggleAnimated(false); });
|
_hideTimer.setCallback([this] { toggleAnimated(false); });
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
|
_content->widthValue(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
resizeToContent();
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::pointAt(QRect area, RectParts side) {
|
void ImportantTooltip::pointAt(
|
||||||
if (_area == area && _side == side) {
|
QRect area,
|
||||||
|
RectParts side,
|
||||||
|
Fn<QPoint(QSize)> countPosition) {
|
||||||
|
if (_area == area
|
||||||
|
&& _side == side
|
||||||
|
&& !_countPosition
|
||||||
|
&& !countPosition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setArea(area);
|
_countPosition = std::move(countPosition);
|
||||||
|
_area = area;
|
||||||
countApproachSide(side);
|
countApproachSide(side);
|
||||||
updateGeometry();
|
resizeToContent();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::setArea(QRect area) {
|
void ImportantTooltip::resizeToContent() {
|
||||||
Expects(parentWidget() != nullptr);
|
|
||||||
_area = area;
|
|
||||||
auto point = parentWidget()->mapToGlobal(_area.center());
|
|
||||||
_useTransparency = Platform::TranslucentWindowsSupported(point);
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
|
|
||||||
|
|
||||||
auto contentWidth = parentWidget()->rect().marginsRemoved(_st.padding).width();
|
|
||||||
accumulate_min(contentWidth, _content->naturalWidth());
|
|
||||||
_content->resizeToWidth(contentWidth);
|
|
||||||
|
|
||||||
auto size = _content->rect().marginsAdded(_st.padding).size();
|
auto size = _content->rect().marginsAdded(_st.padding).size();
|
||||||
if (_useTransparency) {
|
size.setHeight(size.height() + _st.arrow);
|
||||||
size.setHeight(size.height() + _st.arrow);
|
|
||||||
}
|
|
||||||
if (size.width() < 2 * (_st.arrowSkipMin + _st.arrow)) {
|
if (size.width() < 2 * (_st.arrowSkipMin + _st.arrow)) {
|
||||||
size.setWidth(2 * (_st.arrowSkipMin + _st.arrow));
|
size.setWidth(2 * (_st.arrowSkipMin + _st.arrow));
|
||||||
}
|
}
|
||||||
resize(size);
|
resize(size);
|
||||||
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::countApproachSide(RectParts preferSide) {
|
void ImportantTooltip::countApproachSide(RectParts preferSide) {
|
||||||
Expects(parentWidget() != nullptr);
|
Expects(parentWidget() != nullptr);
|
||||||
auto requiredSpace = countInner().height() + _st.shift;
|
|
||||||
if (_useTransparency) {
|
auto requiredSpace = countInner().height() + _st.shift + _st.arrow;
|
||||||
requiredSpace += _st.arrow;
|
|
||||||
}
|
|
||||||
auto available = parentWidget()->rect();
|
auto available = parentWidget()->rect();
|
||||||
auto availableAbove = _area.y() - available.y();
|
auto availableAbove = _area.y() - available.y();
|
||||||
auto availableBelow = (available.y() + available.height()) - (_area.y() + _area.height());
|
auto availableBelow = (available.y() + available.height()) - (_area.y() + _area.height());
|
||||||
|
|
@ -241,28 +244,26 @@ void ImportantTooltip::countApproachSide(RectParts preferSide) {
|
||||||
_side = (allowedAbove ? RectPart::Top : RectPart::Bottom)
|
_side = (allowedAbove ? RectPart::Top : RectPart::Bottom)
|
||||||
| (preferSide & (RectPart::Left | RectPart::Center | RectPart::Right));
|
| (preferSide & (RectPart::Left | RectPart::Center | RectPart::Right));
|
||||||
}
|
}
|
||||||
if (_useTransparency) {
|
auto arrow = QImage(
|
||||||
auto arrow = QImage(
|
QSize(_st.arrow * 2, _st.arrow) * style::DevicePixelRatio(),
|
||||||
QSize(_st.arrow * 2, _st.arrow) * style::DevicePixelRatio(),
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
arrow.fill(Qt::transparent);
|
||||||
arrow.fill(Qt::transparent);
|
arrow.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
arrow.setDevicePixelRatio(style::DevicePixelRatio());
|
{
|
||||||
{
|
Painter p(&arrow);
|
||||||
Painter p(&arrow);
|
PainterHighQualityEnabler hq(p);
|
||||||
PainterHighQualityEnabler hq(p);
|
|
||||||
|
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
path.moveTo(0, 0);
|
path.moveTo(0, 0);
|
||||||
path.lineTo(2 * _st.arrow, 0);
|
path.lineTo(2 * _st.arrow, 0);
|
||||||
path.lineTo(_st.arrow, _st.arrow);
|
path.lineTo(_st.arrow, _st.arrow);
|
||||||
path.lineTo(0, 0);
|
path.lineTo(0, 0);
|
||||||
p.fillPath(path, _st.bg);
|
p.fillPath(path, _st.bg);
|
||||||
}
|
|
||||||
if (_side & RectPart::Bottom) {
|
|
||||||
arrow = std::move(arrow).transformed(QTransform(1, 0, 0, -1, 0, 0));
|
|
||||||
}
|
|
||||||
_arrow = PixmapFromImage(std::move(arrow));
|
|
||||||
}
|
}
|
||||||
|
if (_side & RectPart::Bottom) {
|
||||||
|
arrow = std::move(arrow).transformed(QTransform(1, 0, 0, -1, 0, 0));
|
||||||
|
}
|
||||||
|
_arrow = PixmapFromImage(std::move(arrow));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::toggleAnimated(bool visible) {
|
void ImportantTooltip::toggleAnimated(bool visible) {
|
||||||
|
|
@ -294,14 +295,15 @@ void ImportantTooltip::animationCallback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::refreshAnimationCache() {
|
void ImportantTooltip::refreshAnimationCache() {
|
||||||
if (_cache.isNull() && _useTransparency) {
|
if (!_cache.isNull()) {
|
||||||
auto animation = base::take(_visibleAnimation);
|
return;
|
||||||
auto visible = std::exchange(_visible, true);
|
|
||||||
showChildren();
|
|
||||||
_cache = GrabWidget(this);
|
|
||||||
_visible = base::take(visible);
|
|
||||||
_visibleAnimation = base::take(animation);
|
|
||||||
}
|
}
|
||||||
|
auto animation = base::take(_visibleAnimation);
|
||||||
|
auto visible = std::exchange(_visible, true);
|
||||||
|
showChildren();
|
||||||
|
_cache = GrabWidget(this);
|
||||||
|
_visible = base::take(visible);
|
||||||
|
_visibleAnimation = base::take(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::toggleFast(bool visible) {
|
void ImportantTooltip::toggleFast(bool visible) {
|
||||||
|
|
@ -328,8 +330,9 @@ void ImportantTooltip::checkAnimationFinish() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::updateGeometry() {
|
QPoint ImportantTooltip::countPosition() const {
|
||||||
Expects(parentWidget() != nullptr);
|
Expects(parentWidget() != nullptr);
|
||||||
|
|
||||||
auto parent = parentWidget();
|
auto parent = parentWidget();
|
||||||
auto areaMiddle = _area.x() + (_area.width() / 2);
|
auto areaMiddle = _area.x() + (_area.width() / 2);
|
||||||
auto left = areaMiddle - (width() / 2);
|
auto left = areaMiddle - (width() / 2);
|
||||||
|
|
@ -343,19 +346,26 @@ void ImportantTooltip::updateGeometry() {
|
||||||
accumulate_max(left, areaMiddle + _st.arrow + _st.arrowSkipMin - width());
|
accumulate_max(left, areaMiddle + _st.arrow + _st.arrowSkipMin - width());
|
||||||
accumulate_min(left, areaMiddle - _st.arrow - _st.arrowSkipMin);
|
accumulate_min(left, areaMiddle - _st.arrow - _st.arrowSkipMin);
|
||||||
|
|
||||||
auto countTop = [this] {
|
const auto top = (_side & RectPart::Top)
|
||||||
auto shift = anim::interpolate(_st.shift, 0, _visibleAnimation.value(_visible ? 1. : 0.));
|
? (_area.y() - height())
|
||||||
if (_side & RectPart::Top) {
|
: (_area.y() + _area.height());
|
||||||
return _area.y() - height() - shift;
|
return { left, top };
|
||||||
}
|
}
|
||||||
return _area.y() + _area.height() + shift;
|
|
||||||
};
|
void ImportantTooltip::updateGeometry() {
|
||||||
move(left, countTop());
|
const auto position = _countPosition
|
||||||
|
? _countPosition(size())
|
||||||
|
: countPosition();
|
||||||
|
const auto shift = anim::interpolate(
|
||||||
|
(_side & RectPart::Top) ? -_st.shift : _st.shift,
|
||||||
|
0,
|
||||||
|
_visibleAnimation.value(_visible ? 1. : 0.));
|
||||||
|
move(position.x(), position.y() + shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportantTooltip::resizeEvent(QResizeEvent *e) {
|
void ImportantTooltip::resizeEvent(QResizeEvent *e) {
|
||||||
auto contentTop = _st.padding.top();
|
auto contentTop = _st.padding.top();
|
||||||
if (_useTransparency && (_side & RectPart::Bottom)) {
|
if (_side & RectPart::Bottom) {
|
||||||
contentTop += _st.arrow;
|
contentTop += _st.arrow;
|
||||||
}
|
}
|
||||||
_content->moveToLeft(_st.padding.left(), contentTop);
|
_content->moveToLeft(_st.padding.left(), contentTop);
|
||||||
|
|
@ -369,31 +379,27 @@ void ImportantTooltip::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
auto inner = countInner();
|
auto inner = countInner();
|
||||||
if (_useTransparency) {
|
if (!_cache.isNull()) {
|
||||||
if (!_cache.isNull()) {
|
auto opacity = _visibleAnimation.value(_visible ? 1. : 0.);
|
||||||
auto opacity = _visibleAnimation.value(_visible ? 1. : 0.);
|
p.setOpacity(opacity);
|
||||||
p.setOpacity(opacity);
|
p.drawPixmap(0, 0, _cache);
|
||||||
p.drawPixmap(0, 0, _cache);
|
|
||||||
} else {
|
|
||||||
if (!_visible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p.setBrush(_st.bg);
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
{
|
|
||||||
PainterHighQualityEnabler hq(p);
|
|
||||||
p.drawRoundedRect(inner, _st.radius, _st.radius);
|
|
||||||
}
|
|
||||||
auto areaMiddle = _area.x() + (_area.width() / 2) - x();
|
|
||||||
auto arrowLeft = areaMiddle - _st.arrow;
|
|
||||||
if (_side & RectPart::Top) {
|
|
||||||
p.drawPixmapLeft(arrowLeft, inner.y() + inner.height(), width(), _arrow);
|
|
||||||
} else {
|
|
||||||
p.drawPixmapLeft(arrowLeft, inner.y() - _st.arrow, width(), _arrow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
p.fillRect(inner, QColor(_st.bg->c.red(), _st.bg->c.green(), _st.bg->c.blue()));
|
if (!_visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.setBrush(_st.bg);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
{
|
||||||
|
PainterHighQualityEnabler hq(p);
|
||||||
|
p.drawRoundedRect(inner, _st.radius, _st.radius);
|
||||||
|
}
|
||||||
|
auto areaMiddle = _area.x() + (_area.width() / 2) - x();
|
||||||
|
auto arrowLeft = areaMiddle - _st.arrow;
|
||||||
|
if (_side & RectPart::Top) {
|
||||||
|
p.drawPixmapLeft(arrowLeft, inner.y() + inner.height(), width(), _arrow);
|
||||||
|
} else {
|
||||||
|
p.drawPixmapLeft(arrowLeft, inner.y() - _st.arrow, width(), _arrow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,17 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImportantTooltip : public TWidget {
|
class ImportantTooltip : public RpWidget {
|
||||||
public:
|
public:
|
||||||
ImportantTooltip(QWidget *parent, object_ptr<TWidget> content, const style::ImportantTooltip &st);
|
ImportantTooltip(
|
||||||
|
QWidget *parent,
|
||||||
|
object_ptr<RpWidget> content,
|
||||||
|
const style::ImportantTooltip &st);
|
||||||
|
|
||||||
void pointAt(QRect area, RectParts preferSide = RectPart::Top | RectPart::Left);
|
void pointAt(
|
||||||
|
QRect area,
|
||||||
|
RectParts preferSide = RectPart::Top | RectPart::Left,
|
||||||
|
Fn<QPoint(QSize)> countPosition = nullptr);
|
||||||
|
|
||||||
void toggleAnimated(bool visible);
|
void toggleAnimated(bool visible);
|
||||||
void toggleFast(bool visible);
|
void toggleFast(bool visible);
|
||||||
|
|
@ -84,24 +90,25 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void animationCallback();
|
void animationCallback();
|
||||||
QRect countInner() const;
|
[[nodiscard]] QRect countInner() const;
|
||||||
void setArea(QRect area);
|
|
||||||
void countApproachSide(RectParts preferSide);
|
void countApproachSide(RectParts preferSide);
|
||||||
|
void resizeToContent();
|
||||||
void updateGeometry();
|
void updateGeometry();
|
||||||
void checkAnimationFinish();
|
void checkAnimationFinish();
|
||||||
void refreshAnimationCache();
|
void refreshAnimationCache();
|
||||||
|
[[nodiscard]] QPoint countPosition() const;
|
||||||
|
|
||||||
base::Timer _hideTimer;
|
base::Timer _hideTimer;
|
||||||
const style::ImportantTooltip &_st;
|
const style::ImportantTooltip &_st;
|
||||||
object_ptr<TWidget> _content;
|
object_ptr<RpWidget> _content;
|
||||||
QRect _area;
|
QRect _area;
|
||||||
RectParts _side = RectPart::Top | RectPart::Left;
|
RectParts _side = RectPart::Top | RectPart::Left;
|
||||||
QPixmap _arrow;
|
QPixmap _arrow;
|
||||||
|
|
||||||
Ui::Animations::Simple _visibleAnimation;
|
Ui::Animations::Simple _visibleAnimation;
|
||||||
|
Fn<QPoint(QSize)> _countPosition;
|
||||||
bool _visible = false;
|
bool _visible = false;
|
||||||
Fn<void()> _hiddenCallback;
|
Fn<void()> _hiddenCallback;
|
||||||
bool _useTransparency = true;
|
|
||||||
QPixmap _cache;
|
QPixmap _cache;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue