Implement nice dropdown collapse animation.
This commit is contained in:
parent
6a1630a84c
commit
cfc2a959cf
|
@ -116,6 +116,18 @@ int Button::scrollMax() const {
|
||||||
return _expandedInnerHeight - _expandedHeight;
|
return _expandedInnerHeight - _expandedHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float64 Button::expandAnimationOpacity(float64 expandRatio) const {
|
||||||
|
return (_collapseType == CollapseType::Fade)
|
||||||
|
? expandRatio
|
||||||
|
: 1.;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Button::expandAnimationScroll(float64 expandRatio) const {
|
||||||
|
return (_collapseType == CollapseType::Scroll && expandRatio < 1.)
|
||||||
|
? std::clamp(int(base::SafeRound(expandRatio * _scroll)), 0, _scroll)
|
||||||
|
: _scroll;
|
||||||
|
}
|
||||||
|
|
||||||
bool Button::expandUp() const {
|
bool Button::expandUp() const {
|
||||||
return (_expandDirection == ExpandDirection::Up);
|
return (_expandDirection == ExpandDirection::Up);
|
||||||
}
|
}
|
||||||
|
@ -247,6 +259,11 @@ void Button::applyState(State state, Fn<void(QRect)> update) {
|
||||||
if (state == State::Hidden) {
|
if (state == State::Hidden) {
|
||||||
_heightAnimation.stop();
|
_heightAnimation.stop();
|
||||||
} else {
|
} else {
|
||||||
|
if (!_heightAnimation.animating()) {
|
||||||
|
_collapseType = (_scroll < st::reactionCollapseFadeThreshold)
|
||||||
|
? CollapseType::Scroll
|
||||||
|
: CollapseType::Fade;
|
||||||
|
}
|
||||||
_heightAnimation.start(
|
_heightAnimation.start(
|
||||||
[=] { updateGeometry(_update); },
|
[=] { updateGeometry(_update); },
|
||||||
_finalHeight,
|
_finalHeight,
|
||||||
|
@ -736,7 +753,10 @@ void Manager::paintButton(
|
||||||
|
|
||||||
const auto current = (button == _button.get());
|
const auto current = (button == _button.get());
|
||||||
const auto expandRatio = expanded
|
const auto expandRatio = expanded
|
||||||
? (float64(expanded) / (button->expandedHeight() - _outer.height()))
|
? std::clamp(
|
||||||
|
float64(expanded) / (button->expandedHeight() - _outer.height()),
|
||||||
|
0.,
|
||||||
|
1.)
|
||||||
: 0.;
|
: 0.;
|
||||||
const auto expandedSkip = int(base::SafeRound(
|
const auto expandedSkip = int(base::SafeRound(
|
||||||
expandRatio * st::reactionExpandedSkip));
|
expandRatio * st::reactionExpandedSkip));
|
||||||
|
@ -745,17 +765,36 @@ void Manager::paintButton(
|
||||||
: button->expandUp()
|
: button->expandUp()
|
||||||
? QPoint(0, expanded - expandedSkip)
|
? QPoint(0, expanded - expandedSkip)
|
||||||
: QPoint(0, expandedSkip);
|
: QPoint(0, expandedSkip);
|
||||||
|
const auto source = validateEmoji(frameIndex, scale);
|
||||||
if (expanded || (current && !onlyMainEmojiVisible())) {
|
if (expanded || (current && !onlyMainEmojiVisible())) {
|
||||||
const auto origin = expanded ? QPoint() : position;
|
const auto origin = expanded ? QPoint() : position;
|
||||||
paintAllEmoji(*q, button, scale, origin, mainEmojiPosition);
|
const auto scroll = button->expandAnimationScroll(expandRatio);
|
||||||
|
const auto opacity = button->expandAnimationOpacity(expandRatio);
|
||||||
|
if (opacity != 1.) {
|
||||||
|
q->setOpacity(opacity);
|
||||||
|
}
|
||||||
|
paintAllEmoji(*q, button, scroll, scale, origin, mainEmojiPosition);
|
||||||
|
if (opacity != 1.) {
|
||||||
|
q->setOpacity(1.);
|
||||||
|
}
|
||||||
if (current && expanded) {
|
if (current && expanded) {
|
||||||
_showingAll = true;
|
_showingAll = true;
|
||||||
}
|
}
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
paintInnerGradients(*q, background, button, expandRatio);
|
paintInnerGradients(*q, background, button, scroll, expandRatio);
|
||||||
|
}
|
||||||
|
if (opacity != 1.) {
|
||||||
|
const auto appearShift = st::reactionMainAppearShift * opacity;
|
||||||
|
const auto appearPosition = !expanded
|
||||||
|
? position
|
||||||
|
: button->expandUp()
|
||||||
|
? QPoint(0, expanded - appearShift)
|
||||||
|
: QPoint(0, appearShift);
|
||||||
|
q->setOpacity(1. - opacity);
|
||||||
|
q->drawImage(appearPosition, _cacheParts, source);
|
||||||
|
q->setOpacity(1.);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto source = validateEmoji(frameIndex, scale);
|
|
||||||
p.drawImage(mainEmojiPosition, _cacheParts, source);
|
p.drawImage(mainEmojiPosition, _cacheParts, source);
|
||||||
}
|
}
|
||||||
if (current && !expanded) {
|
if (current && !expanded) {
|
||||||
|
@ -779,8 +818,8 @@ void Manager::paintInnerGradients(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
const QColor &background,
|
const QColor &background,
|
||||||
not_null<Button*> button,
|
not_null<Button*> button,
|
||||||
|
int scroll,
|
||||||
float64 expandRatio) {
|
float64 expandRatio) {
|
||||||
const auto scroll = button->scroll();
|
|
||||||
const auto endScroll = button->scrollMax() - scroll;
|
const auto endScroll = button->scrollMax() - scroll;
|
||||||
const auto size = st::reactionGradientSize;
|
const auto size = st::reactionGradientSize;
|
||||||
const auto ensureGradient = [&](QImage &gradient, bool top) {
|
const auto ensureGradient = [&](QImage &gradient, bool top) {
|
||||||
|
@ -970,6 +1009,7 @@ void Manager::paintLongImage(
|
||||||
void Manager::paintAllEmoji(
|
void Manager::paintAllEmoji(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<Button*> button,
|
not_null<Button*> button,
|
||||||
|
int scroll,
|
||||||
float64 scale,
|
float64 scale,
|
||||||
QPoint position,
|
QPoint position,
|
||||||
QPoint mainEmojiPosition) {
|
QPoint mainEmojiPosition) {
|
||||||
|
@ -1013,7 +1053,7 @@ void Manager::paintAllEmoji(
|
||||||
const auto expandUp = button->expandUp();
|
const auto expandUp = button->expandUp();
|
||||||
const auto shift = QPoint(0, oneHeight * (expandUp ? -1 : 1));
|
const auto shift = QPoint(0, oneHeight * (expandUp ? -1 : 1));
|
||||||
auto emojiPosition = mainEmojiPosition
|
auto emojiPosition = mainEmojiPosition
|
||||||
+ QPoint(0, button->scroll() * (expandUp ? 1 : -1));
|
+ QPoint(0, scroll * (expandUp ? 1 : -1));
|
||||||
const auto update = [=] {
|
const auto update = [=] {
|
||||||
updateCurrentButton();
|
updateCurrentButton();
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,12 +81,19 @@ public:
|
||||||
[[nodiscard]] int scrollMax() const;
|
[[nodiscard]] int scrollMax() const;
|
||||||
[[nodiscard]] float64 currentScale() const;
|
[[nodiscard]] float64 currentScale() const;
|
||||||
[[nodiscard]] float64 currentOpacity() const;
|
[[nodiscard]] float64 currentOpacity() const;
|
||||||
|
[[nodiscard]] float64 expandAnimationOpacity(float64 expandRatio) const;
|
||||||
|
[[nodiscard]] int expandAnimationScroll(float64 expandRatio) const;
|
||||||
[[nodiscard]] bool consumeWheelEvent(not_null<QWheelEvent*> e);
|
[[nodiscard]] bool consumeWheelEvent(not_null<QWheelEvent*> e);
|
||||||
|
|
||||||
[[nodiscard]] static float64 ScaleForState(State state);
|
[[nodiscard]] static float64 ScaleForState(State state);
|
||||||
[[nodiscard]] static float64 OpacityForScale(float64 scale);
|
[[nodiscard]] static float64 OpacityForScale(float64 scale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class CollapseType {
|
||||||
|
Scroll,
|
||||||
|
Fade,
|
||||||
|
};
|
||||||
|
|
||||||
void updateGeometry(Fn<void(QRect)> update);
|
void updateGeometry(Fn<void(QRect)> update);
|
||||||
void applyState(State satte, Fn<void(QRect)> update);
|
void applyState(State satte, Fn<void(QRect)> update);
|
||||||
void applyParameters(
|
void applyParameters(
|
||||||
|
@ -108,6 +115,7 @@ private:
|
||||||
int _finalHeight = 0;
|
int _finalHeight = 0;
|
||||||
int _scroll = 0;
|
int _scroll = 0;
|
||||||
ExpandDirection _expandDirection = ExpandDirection::Up;
|
ExpandDirection _expandDirection = ExpandDirection::Up;
|
||||||
|
CollapseType _collapseType = CollapseType::Scroll;
|
||||||
|
|
||||||
base::Timer _expandTimer;
|
base::Timer _expandTimer;
|
||||||
base::Timer _hideTimer;
|
base::Timer _hideTimer;
|
||||||
|
@ -174,6 +182,7 @@ private:
|
||||||
void paintAllEmoji(
|
void paintAllEmoji(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<Button*> button,
|
not_null<Button*> button,
|
||||||
|
int scroll,
|
||||||
float64 scale,
|
float64 scale,
|
||||||
QPoint position,
|
QPoint position,
|
||||||
QPoint mainEmojiPosition);
|
QPoint mainEmojiPosition);
|
||||||
|
@ -181,6 +190,7 @@ private:
|
||||||
Painter &p,
|
Painter &p,
|
||||||
const QColor &background,
|
const QColor &background,
|
||||||
not_null<Button*> button,
|
not_null<Button*> button,
|
||||||
|
int scroll,
|
||||||
float64 expandRatio);
|
float64 expandRatio);
|
||||||
void overlayExpandedBorder(
|
void overlayExpandedBorder(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
|
|
@ -987,3 +987,5 @@ reactionGradientStart: 8px;
|
||||||
reactionGradientSize: 24px;
|
reactionGradientSize: 24px;
|
||||||
reactionGradientFadeSize: 24px;
|
reactionGradientFadeSize: 24px;
|
||||||
reactionAppearStartSkip: 2px;
|
reactionAppearStartSkip: 2px;
|
||||||
|
reactionMainAppearShift: 20px;
|
||||||
|
reactionCollapseFadeThreshold: 40px;
|
||||||
|
|
Loading…
Reference in New Issue