mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Expand reaction selection panel.
This commit is contained in:
parent
bd42c23999
commit
c9a98ae723
4 changed files with 161 additions and 22 deletions
|
@ -633,7 +633,11 @@ void Manager::paintButton(
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
q->fillRect(QRect(QPoint(), size), context.st->windowBg());
|
q->fillRect(QRect(QPoint(), size), context.st->windowBg());
|
||||||
} else {
|
} else {
|
||||||
const auto frame = _cachedRound.validateFrame(frameIndex, scale);
|
const auto radius = _inner.height() / 2.;
|
||||||
|
const auto frame = _cachedRound.validateFrame(
|
||||||
|
frameIndex,
|
||||||
|
scale,
|
||||||
|
radius);
|
||||||
p.drawImage(position, *frame.image, frame.rect);
|
p.drawImage(position, *frame.image, frame.rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ QMargins Selector::extentsForShadow() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Selector::extendTopForCategories() const {
|
int Selector::extendTopForCategories() const {
|
||||||
return st::emojiFooterHeight;
|
return _reactions.customAllowed ? st::emojiFooterHeight : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Selector::desiredHeight() const {
|
int Selector::desiredHeight() const {
|
||||||
|
@ -76,6 +76,10 @@ int Selector::desiredHeight() const {
|
||||||
: (_skipy + _recentRows * _size + _skipBottom);
|
: (_skipy + _recentRows * _size + _skipBottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Selector::setSpecialExpandTopSkip(int skip) {
|
||||||
|
_specialExpandTopSkip = skip;
|
||||||
|
}
|
||||||
|
|
||||||
void Selector::initGeometry(int innerTop) {
|
void Selector::initGeometry(int innerTop) {
|
||||||
const auto extents = extentsForShadow();
|
const auto extents = extentsForShadow();
|
||||||
const auto parent = parentWidget()->rect();
|
const auto parent = parentWidget()->rect();
|
||||||
|
@ -84,10 +88,14 @@ void Selector::initGeometry(int innerTop) {
|
||||||
const auto width = innerWidth + extents.left() + extents.right();
|
const auto width = innerWidth + extents.left() + extents.right();
|
||||||
const auto height = innerHeight + extents.top() + extents.bottom();
|
const auto height = innerHeight + extents.top() + extents.bottom();
|
||||||
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
|
const auto left = style::RightToLeft() ? 0 : (parent.width() - width);
|
||||||
const auto top = innerTop - extents.top();
|
_collapsedTopSkip = extendTopForCategories() + _specialExpandTopSkip;
|
||||||
|
const auto top = innerTop - extents.top() - _collapsedTopSkip;
|
||||||
const auto add = st::reactStripBubble.height() - extents.bottom();
|
const auto add = st::reactStripBubble.height() - extents.bottom();
|
||||||
_outer = QRect(0, 0, width, height);
|
_outer = QRect(0, _collapsedTopSkip, width, height);
|
||||||
setGeometry(_outer.marginsAdded({ 0, 0, 0, add }).translated(left, top));
|
_outerWithBubble = _outer.marginsAdded({ 0, 0, 0, add });
|
||||||
|
setGeometry(_outerWithBubble.marginsAdded(
|
||||||
|
{ 0, _collapsedTopSkip, 0, 0 }
|
||||||
|
).translated(left, top));
|
||||||
_inner = _outer.marginsRemoved(extents);
|
_inner = _outer.marginsRemoved(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +128,8 @@ void Selector::paintAppearing(QPainter &p) {
|
||||||
p.setOpacity(_appearOpacity);
|
p.setOpacity(_appearOpacity);
|
||||||
|
|
||||||
const auto factor = style::DevicePixelRatio();
|
const auto factor = style::DevicePixelRatio();
|
||||||
if (_paintBuffer.size() != size() * factor) {
|
if (_paintBuffer.size() != _outerWithBubble.size() * factor) {
|
||||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
_paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size());
|
||||||
}
|
}
|
||||||
_paintBuffer.fill(st::defaultPopupMenu.menu.itemBg->c);
|
_paintBuffer.fill(st::defaultPopupMenu.menu.itemBg->c);
|
||||||
auto q = QPainter(&_paintBuffer);
|
auto q = QPainter(&_paintBuffer);
|
||||||
|
@ -133,16 +141,18 @@ void Selector::paintAppearing(QPainter &p) {
|
||||||
const auto fullWidth = _inner.x() + appearedWidth + extents.right();
|
const auto fullWidth = _inner.x() + appearedWidth + extents.right();
|
||||||
const auto size = QSize(fullWidth, _outer.height());
|
const auto size = QSize(fullWidth, _outer.height());
|
||||||
|
|
||||||
|
q.translate(_inner.topLeft() - QPoint(0, _collapsedTopSkip));
|
||||||
_strip.paint(
|
_strip.paint(
|
||||||
q,
|
q,
|
||||||
{ _inner.x() + _skipx, _inner.y() + _skipy },
|
{ _skipx, _skipy },
|
||||||
{ _size, 0 },
|
{ _size, 0 },
|
||||||
{ _inner.x(), _inner.y(), appearedWidth, _inner.height() },
|
{ 0, 0, appearedWidth, _inner.height() },
|
||||||
1.,
|
1.,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
_cachedRound.setBackgroundColor(st::defaultPopupMenu.menu.itemBg->c);
|
_cachedRound.setBackgroundColor(st::defaultPopupMenu.menu.itemBg->c);
|
||||||
_cachedRound.setShadowColor(st::shadowFg->c);
|
_cachedRound.setShadowColor(st::shadowFg->c);
|
||||||
|
q.translate(QPoint(0, _collapsedTopSkip) - _inner.topLeft());
|
||||||
const auto radius = st::reactStripHeight / 2;
|
const auto radius = st::reactStripHeight / 2;
|
||||||
_cachedRound.overlayExpandedBorder(q, size, _appearProgress, radius, 1.);
|
_cachedRound.overlayExpandedBorder(q, size, _appearProgress, radius, 1.);
|
||||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
@ -154,38 +164,114 @@ void Selector::paintAppearing(QPainter &p) {
|
||||||
q.end();
|
q.end();
|
||||||
|
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QPoint(),
|
_outer.topLeft(),
|
||||||
_paintBuffer,
|
_paintBuffer,
|
||||||
QRect(QPoint(), QSize(fullWidth, height()) * factor));
|
QRect(QPoint(), QSize(fullWidth, height()) * factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selector::paintBackgroundToBuffer() {
|
void Selector::paintBackgroundToBuffer() {
|
||||||
if (_paintBuffer.size() != size() * style::DevicePixelRatio()) {
|
const auto factor = style::DevicePixelRatio();
|
||||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
if (_paintBuffer.size() != _outerWithBubble.size() * factor) {
|
||||||
|
_paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size());
|
||||||
}
|
}
|
||||||
_paintBuffer.fill(Qt::transparent);
|
_paintBuffer.fill(Qt::transparent);
|
||||||
|
|
||||||
auto p = QPainter(&_paintBuffer);
|
auto p = QPainter(&_paintBuffer);
|
||||||
_cachedRound.FillWithImage(p, _outer, _cachedRound.validateFrame(0, 1.));
|
const auto radius = _inner.height() / 2.;
|
||||||
|
const auto frame = _cachedRound.validateFrame(0, 1., radius);
|
||||||
|
const auto outer = _outer.translated(0, -_collapsedTopSkip);
|
||||||
|
_cachedRound.FillWithImage(p, outer, frame);
|
||||||
paintBubble(p, _inner.width());
|
paintBubble(p, _inner.width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selector::paintHorizontal(QPainter &p) {
|
void Selector::paintCollapsed(QPainter &p) {
|
||||||
if (_paintBuffer.isNull()) {
|
if (_paintBuffer.isNull()) {
|
||||||
paintBackgroundToBuffer();
|
paintBackgroundToBuffer();
|
||||||
}
|
}
|
||||||
p.drawImage(0, 0, _paintBuffer);
|
p.drawImage(_outer.topLeft(), _paintBuffer);
|
||||||
|
|
||||||
const auto extents = extentsForShadow();
|
|
||||||
_strip.paint(
|
_strip.paint(
|
||||||
p,
|
p,
|
||||||
{ _inner.x() + _skipx, _inner.y() + _skipy },
|
_inner.topLeft() + QPoint(_skipx, _skipy),
|
||||||
{ _size, 0 },
|
{ _size, 0 },
|
||||||
_inner,
|
_inner,
|
||||||
1.,
|
1.,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Selector::paintExpanding(QPainter &p, float64 progress) {
|
||||||
|
paintExpandingBg(p, progress);
|
||||||
|
paintStripWithoutExpand(p);
|
||||||
|
paintFadingExpandIcon(p, progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::paintExpandingBg(QPainter &p, float64 progress) {
|
||||||
|
constexpr auto kFramesCount = Ui::RoundAreaWithShadow::kFramesCount;
|
||||||
|
const auto frame = int(base::SafeRound(progress * (kFramesCount - 1)));
|
||||||
|
const auto radiusStart = st::reactStripHeight / 2.;
|
||||||
|
const auto radiusEnd = st::roundRadiusSmall;
|
||||||
|
const auto radius = radiusStart + progress * (radiusEnd - radiusStart);
|
||||||
|
const auto extents = extentsForShadow();
|
||||||
|
const auto expanding = anim::easeOutCirc(1., progress);
|
||||||
|
const auto expandUp = anim::interpolate(0, _collapsedTopSkip, expanding);
|
||||||
|
const auto expandDown = anim::interpolate(
|
||||||
|
0,
|
||||||
|
(height() - _outer.y() - _outer.height()),
|
||||||
|
expanding);
|
||||||
|
const auto outer = _outer.marginsAdded({ 0, expandUp, 0, expandDown });
|
||||||
|
const auto pattern = _cachedRound.validateFrame(frame, 1., radius);
|
||||||
|
const auto fill = _cachedRound.FillWithImage(p, outer, pattern);
|
||||||
|
if (!fill.isEmpty()) {
|
||||||
|
p.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::paintStripWithoutExpand(QPainter &p) {
|
||||||
|
_strip.paint(
|
||||||
|
p,
|
||||||
|
_inner.topLeft() + QPoint(_skipx, _skipy),
|
||||||
|
{ _size, 0 },
|
||||||
|
_inner.marginsRemoved({ 0, 0, _skipx + _size, 0 }),
|
||||||
|
1.,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::paintFadingExpandIcon(QPainter &p, float64 progress) {
|
||||||
|
if (progress >= 1.) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.setOpacity(1. - progress);
|
||||||
|
const auto sub = anim::interpolate(0, _size / 3, progress);
|
||||||
|
const auto expandIconPosition = _inner.topLeft()
|
||||||
|
+ QPoint(_inner.width() - _size - _skipx, _skipy);
|
||||||
|
const auto expandIconRect = QRect(
|
||||||
|
expandIconPosition,
|
||||||
|
QSize(_size, _size)
|
||||||
|
).marginsRemoved({ sub, sub, sub, sub });
|
||||||
|
p.drawImage(expandIconRect, _expandIconCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::paintExpanded(QPainter &p) {
|
||||||
|
paintExpandedBg(p);
|
||||||
|
paintStripWithoutExpand(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selector::paintExpandedBg(QPainter &p) {
|
||||||
|
if (!_expandedBgReady) {
|
||||||
|
_expandedBgReady = true;
|
||||||
|
auto q = QPainter(&_paintBuffer);
|
||||||
|
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
const auto pattern = _cachedRound.validateFrame(
|
||||||
|
kFramesCount - 1,
|
||||||
|
1.,
|
||||||
|
st::roundRadiusSmall);
|
||||||
|
const auto fill = _cachedRound.FillWithImage(q, rect(), pattern);
|
||||||
|
if (!fill.isEmpty()) {
|
||||||
|
q.fillRect(fill, st::defaultPopupMenu.menu.itemBg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.drawImage(0, 0, _paintBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
void Selector::paintBubble(QPainter &p, int innerWidth) {
|
void Selector::paintBubble(QPainter &p, int innerWidth) {
|
||||||
const auto &bubble = st::reactStripBubble;
|
const auto &bubble = st::reactStripBubble;
|
||||||
const auto bubbleRight = std::min(
|
const auto bubbleRight = std::min(
|
||||||
|
@ -194,7 +280,7 @@ void Selector::paintBubble(QPainter &p, int innerWidth) {
|
||||||
bubble.paint(
|
bubble.paint(
|
||||||
p,
|
p,
|
||||||
_inner.x() + innerWidth - bubbleRight - bubble.width(),
|
_inner.x() + innerWidth - bubbleRight - bubble.width(),
|
||||||
_inner.y() + _inner.height(),
|
_inner.y() + _inner.height() - _collapsedTopSkip,
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,8 +288,12 @@ void Selector::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
auto p = QPainter(this);
|
||||||
if (_appearing) {
|
if (_appearing) {
|
||||||
paintAppearing(p);
|
paintAppearing(p);
|
||||||
|
} else if (!_expanded) {
|
||||||
|
paintCollapsed(p);
|
||||||
|
} else if (const auto progress = _expanding.value(1.); progress < 1.) {
|
||||||
|
paintExpanding(p, progress);
|
||||||
} else {
|
} else {
|
||||||
paintHorizontal(p);
|
paintExpanded(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +342,7 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (selected == Strip::AddedButton::Premium) {
|
if (selected == Strip::AddedButton::Premium) {
|
||||||
_premiumPromoChosen.fire({});
|
_premiumPromoChosen.fire({});
|
||||||
} else if (selected == Strip::AddedButton::Expand) {
|
} else if (selected == Strip::AddedButton::Expand) {
|
||||||
|
expand();
|
||||||
} else {
|
} else {
|
||||||
const auto id = std::get_if<Data::ReactionId>(&selected);
|
const auto id = std::get_if<Data::ReactionId>(&selected);
|
||||||
if (id && !id->empty()) {
|
if (id && !id->empty()) {
|
||||||
|
@ -260,6 +351,33 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Selector::expand() {
|
||||||
|
const auto parent = parentWidget()->geometry();
|
||||||
|
const auto additionalBottom = parent.height() - y() - height();
|
||||||
|
const auto additional = _specialExpandTopSkip + additionalBottom;
|
||||||
|
if (additionalBottom < 0 || additional <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (additionalBottom > 0) {
|
||||||
|
resize(width(), height() + additionalBottom);
|
||||||
|
raise();
|
||||||
|
}
|
||||||
|
_expandIconCache = _cachedRound.PrepareImage({ _size, _size });
|
||||||
|
_expandIconCache.fill(Qt::transparent);
|
||||||
|
auto q = QPainter(&_expandIconCache);
|
||||||
|
const auto count = _strip.count();
|
||||||
|
_strip.paint(
|
||||||
|
q,
|
||||||
|
QPoint(-(count - 1) * _size, 0),
|
||||||
|
{ _size, 0 },
|
||||||
|
QRect(-(count - 1) * _size, 0, count * _size, _size),
|
||||||
|
1.,
|
||||||
|
false);
|
||||||
|
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||||
|
_expanded = true;
|
||||||
|
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
||||||
|
}
|
||||||
|
|
||||||
bool AdjustMenuGeometryForSelector(
|
bool AdjustMenuGeometryForSelector(
|
||||||
not_null<Ui::PopupMenu*> menu,
|
not_null<Ui::PopupMenu*> menu,
|
||||||
QPoint desiredPosition,
|
QPoint desiredPosition,
|
||||||
|
@ -317,6 +435,7 @@ bool AdjustMenuGeometryForSelector(
|
||||||
extents.right(),
|
extents.right(),
|
||||||
0
|
0
|
||||||
));
|
));
|
||||||
|
selector->setSpecialExpandTopSkip(additionalPaddingBottom);
|
||||||
return menu->prepareGeometryFor(desiredPosition);
|
return menu->prepareGeometryFor(desiredPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
[[nodiscard]] QMargins extentsForShadow() const;
|
[[nodiscard]] QMargins extentsForShadow() const;
|
||||||
[[nodiscard]] int extendTopForCategories() const;
|
[[nodiscard]] int extendTopForCategories() const;
|
||||||
[[nodiscard]] int desiredHeight() const;
|
[[nodiscard]] int desiredHeight() const;
|
||||||
|
void setSpecialExpandTopSkip(int skip);
|
||||||
void initGeometry(int innerTop);
|
void initGeometry(int innerTop);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<ChosenReaction> chosen() const {
|
[[nodiscard]] rpl::producer<ChosenReaction> chosen() const {
|
||||||
|
@ -68,13 +69,21 @@ private:
|
||||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
void paintAppearing(QPainter &p);
|
void paintAppearing(QPainter &p);
|
||||||
void paintHorizontal(QPainter &p);
|
void paintCollapsed(QPainter &p);
|
||||||
|
void paintExpanding(QPainter &p, float64 progress);
|
||||||
|
void paintExpandingBg(QPainter &p, float64 progress);
|
||||||
|
void paintStripWithoutExpand(QPainter &p);
|
||||||
|
void paintFadingExpandIcon(QPainter &p, float64 progress);
|
||||||
|
void paintExpanded(QPainter &p);
|
||||||
|
void paintExpandedBg(QPainter &p);
|
||||||
void paintBubble(QPainter &p, int innerWidth);
|
void paintBubble(QPainter &p, int innerWidth);
|
||||||
void paintBackgroundToBuffer();
|
void paintBackgroundToBuffer();
|
||||||
|
|
||||||
[[nodiscard]] int lookupSelectedIndex(QPoint position) const;
|
[[nodiscard]] int lookupSelectedIndex(QPoint position) const;
|
||||||
void setSelected(int index);
|
void setSelected(int index);
|
||||||
|
|
||||||
|
void expand();
|
||||||
|
|
||||||
const Data::PossibleItemReactions _reactions;
|
const Data::PossibleItemReactions _reactions;
|
||||||
Ui::RoundAreaWithShadow _cachedRound;
|
Ui::RoundAreaWithShadow _cachedRound;
|
||||||
Strip _strip;
|
Strip _strip;
|
||||||
|
@ -83,11 +92,16 @@ private:
|
||||||
rpl::event_stream<> _premiumPromoChosen;
|
rpl::event_stream<> _premiumPromoChosen;
|
||||||
|
|
||||||
QImage _paintBuffer;
|
QImage _paintBuffer;
|
||||||
|
Ui::Animations::Simple _expanding;
|
||||||
float64 _appearProgress = 0.;
|
float64 _appearProgress = 0.;
|
||||||
float64 _appearOpacity = 0.;
|
float64 _appearOpacity = 0.;
|
||||||
QRect _inner;
|
QRect _inner;
|
||||||
QRect _outer;
|
QRect _outer;
|
||||||
|
QRect _outerWithBubble;
|
||||||
|
QImage _expandIconCache;
|
||||||
QMargins _padding;
|
QMargins _padding;
|
||||||
|
int _specialExpandTopSkip = 0;
|
||||||
|
int _collapsedTopSkip = 0;
|
||||||
int _size = 0;
|
int _size = 0;
|
||||||
int _recentRows = 0;
|
int _recentRows = 0;
|
||||||
int _columns = 0;
|
int _columns = 0;
|
||||||
|
@ -97,6 +111,8 @@ private:
|
||||||
int _pressed = -1;
|
int _pressed = -1;
|
||||||
bool _appearing = false;
|
bool _appearing = false;
|
||||||
bool _toggling = false;
|
bool _toggling = false;
|
||||||
|
bool _expanded = false;
|
||||||
|
bool _expandedBgReady = false;
|
||||||
bool _small = false;
|
bool _small = false;
|
||||||
bool _over = false;
|
bool _over = false;
|
||||||
bool _low = false;
|
bool _low = false;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit eed9293c80eefd7b6d5398b4a65bf7822a1364fc
|
Subproject commit a1ec2c9ade2b050bd307ecf669a2ae5019d70df4
|
Loading…
Add table
Reference in a new issue