Added initial implementation of label animation in mute button.
This commit is contained in:
parent
abb615a7c9
commit
a29e93ca55
3 changed files with 157 additions and 19 deletions
|
|
@ -47,6 +47,7 @@ constexpr auto kOverrideColorRippleAlpha = 50;
|
||||||
|
|
||||||
constexpr auto kShiftDuration = crl::time(300);
|
constexpr auto kShiftDuration = crl::time(300);
|
||||||
constexpr auto kSwitchStateDuration = crl::time(120);
|
constexpr auto kSwitchStateDuration = crl::time(120);
|
||||||
|
constexpr auto kSwitchLabelDuration = crl::time(180);
|
||||||
|
|
||||||
// Switch state from Connecting animation.
|
// Switch state from Connecting animation.
|
||||||
constexpr auto kSwitchRadialDuration = crl::time(350);
|
constexpr auto kSwitchRadialDuration = crl::time(350);
|
||||||
|
|
@ -148,6 +149,110 @@ void ComputeRadialFinish(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
class AnimatedLabel final : public RpWidget {
|
||||||
|
public:
|
||||||
|
AnimatedLabel(
|
||||||
|
QWidget *parent,
|
||||||
|
rpl::producer<QString> &&text,
|
||||||
|
crl::time duration,
|
||||||
|
int additionalHeight,
|
||||||
|
const style::FlatLabel &st = st::defaultFlatLabel);
|
||||||
|
|
||||||
|
int height() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int realHeight() const;
|
||||||
|
|
||||||
|
void setText(const QString &text);
|
||||||
|
|
||||||
|
const style::FlatLabel &_st;
|
||||||
|
const crl::time _duration;
|
||||||
|
const int _additionalHeight;
|
||||||
|
const TextParseOptions _options;
|
||||||
|
|
||||||
|
Text::String _text;
|
||||||
|
Text::String _previousText;
|
||||||
|
|
||||||
|
Animations::Simple _animation;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
AnimatedLabel::AnimatedLabel(
|
||||||
|
QWidget *parent,
|
||||||
|
rpl::producer<QString> &&text,
|
||||||
|
crl::time duration,
|
||||||
|
int additionalHeight,
|
||||||
|
const style::FlatLabel &st)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _st(st)
|
||||||
|
, _duration(duration)
|
||||||
|
, _additionalHeight(additionalHeight)
|
||||||
|
, _options({ 0, 0, 0, Qt::LayoutDirectionAuto }) {
|
||||||
|
std::move(
|
||||||
|
text
|
||||||
|
) | rpl::start_with_next([=](const QString &value) {
|
||||||
|
setText(value);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
paintRequest(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Painter p(this);
|
||||||
|
const auto progress = _animation.value(1.);
|
||||||
|
|
||||||
|
p.setFont(_st.style.font);
|
||||||
|
p.setPen(_st.textFg);
|
||||||
|
p.setTextPalette(_st.palette);
|
||||||
|
|
||||||
|
const auto textHeight = height();
|
||||||
|
const auto diffHeight = realHeight() - textHeight;
|
||||||
|
const auto center = (diffHeight) / 2;
|
||||||
|
|
||||||
|
p.setOpacity(1. - progress);
|
||||||
|
if (p.opacity()) {
|
||||||
|
_previousText.draw(
|
||||||
|
p,
|
||||||
|
0,
|
||||||
|
anim::interpolate(center, diffHeight, progress),
|
||||||
|
width(),
|
||||||
|
style::al_center);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setOpacity(progress);
|
||||||
|
if (p.opacity()) {
|
||||||
|
_text.draw(
|
||||||
|
p,
|
||||||
|
0,
|
||||||
|
anim::interpolate(0, center, progress),
|
||||||
|
width(),
|
||||||
|
style::al_center);
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
int AnimatedLabel::height() const {
|
||||||
|
return _st.style.font->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AnimatedLabel::realHeight() const {
|
||||||
|
return RpWidget::height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimatedLabel::setText(const QString &text) {
|
||||||
|
if (_text.toString() == text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_previousText = _text;
|
||||||
|
_text.setText(_st.style, text, _options);
|
||||||
|
|
||||||
|
const auto width = std::max(
|
||||||
|
_st.style.font->width(_text.toString()),
|
||||||
|
_st.style.font->width(_previousText.toString()));
|
||||||
|
resize(width + _additionalHeight, height() + _additionalHeight * 2);
|
||||||
|
|
||||||
|
_animation.stop();
|
||||||
|
_animation.start([=] { update(); }, 0., 1., _duration);
|
||||||
|
}
|
||||||
|
|
||||||
class BlobsWidget final : public RpWidget {
|
class BlobsWidget final : public RpWidget {
|
||||||
public:
|
public:
|
||||||
BlobsWidget(
|
BlobsWidget(
|
||||||
|
|
@ -379,19 +484,32 @@ CallMuteButton::CallMuteButton(
|
||||||
return isBadState || !(!animDisabled && !hide);
|
return isBadState || !(!animDisabled && !hide);
|
||||||
})))
|
})))
|
||||||
, _content(base::make_unique_q<AbstractButton>(parent))
|
, _content(base::make_unique_q<AbstractButton>(parent))
|
||||||
, _label(base::make_unique_q<FlatLabel>(
|
, _centerLabel(base::make_unique_q<AnimatedLabel>(
|
||||||
parent,
|
parent,
|
||||||
_state.value(
|
_state.value(
|
||||||
) | rpl::map([](const CallMuteButtonState &state) {
|
) | rpl::map([](const CallMuteButtonState &state) {
|
||||||
return state.text;
|
return state.subtext.isEmpty() ? state.text : QString();
|
||||||
}),
|
}),
|
||||||
|
kSwitchLabelDuration,
|
||||||
|
st::callMuteButtonLabelAdditional,
|
||||||
_st.label))
|
_st.label))
|
||||||
, _sublabel(base::make_unique_q<FlatLabel>(
|
, _label(base::make_unique_q<AnimatedLabel>(
|
||||||
|
parent,
|
||||||
|
_state.value(
|
||||||
|
) | rpl::map([](const CallMuteButtonState &state) {
|
||||||
|
return state.subtext.isEmpty() ? QString() : state.text;
|
||||||
|
}),
|
||||||
|
kSwitchLabelDuration,
|
||||||
|
st::callMuteButtonLabelAdditional,
|
||||||
|
_st.label))
|
||||||
|
, _sublabel(base::make_unique_q<AnimatedLabel>(
|
||||||
parent,
|
parent,
|
||||||
_state.value(
|
_state.value(
|
||||||
) | rpl::map([](const CallMuteButtonState &state) {
|
) | rpl::map([](const CallMuteButtonState &state) {
|
||||||
return state.subtext;
|
return state.subtext;
|
||||||
}),
|
}),
|
||||||
|
kSwitchLabelDuration,
|
||||||
|
st::callMuteButtonLabelAdditional,
|
||||||
st::callMuteButtonSublabel))
|
st::callMuteButtonSublabel))
|
||||||
, _radial(nullptr)
|
, _radial(nullptr)
|
||||||
, _colors(Colors())
|
, _colors(Colors())
|
||||||
|
|
@ -411,10 +529,9 @@ void CallMuteButton::init() {
|
||||||
_label->show();
|
_label->show();
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
_content->geometryValue(),
|
_content->geometryValue(),
|
||||||
_sublabel->widthValue(),
|
|
||||||
_label->sizeValue()
|
_label->sizeValue()
|
||||||
) | rpl::start_with_next([=](QRect my, int subWidth, QSize size) {
|
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||||
updateLabelGeometry(my, subWidth, size);
|
updateLabelGeometry(my, size);
|
||||||
}, _label->lifetime());
|
}, _label->lifetime());
|
||||||
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
|
@ -427,6 +544,15 @@ void CallMuteButton::init() {
|
||||||
}, _sublabel->lifetime());
|
}, _sublabel->lifetime());
|
||||||
_sublabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
_sublabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
_centerLabel->show();
|
||||||
|
rpl::combine(
|
||||||
|
_content->geometryValue(),
|
||||||
|
_centerLabel->sizeValue()
|
||||||
|
) | rpl::start_with_next([=](QRect my, QSize size) {
|
||||||
|
updateCenterLabelGeometry(my, size);
|
||||||
|
}, _centerLabel->lifetime());
|
||||||
|
_centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
_radialInfo.rawShowProgress.value(
|
_radialInfo.rawShowProgress.value(
|
||||||
) | rpl::start_with_next([=](float64 value) {
|
) | rpl::start_with_next([=](float64 value) {
|
||||||
auto &info = _radialInfo;
|
auto &info = _radialInfo;
|
||||||
|
|
@ -626,27 +752,34 @@ void CallMuteButton::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallMuteButton::updateLabelsGeometry() {
|
void CallMuteButton::updateLabelsGeometry() {
|
||||||
updateLabelGeometry(
|
updateLabelGeometry(_content->geometry(), _label->size());
|
||||||
_content->geometry(),
|
updateCenterLabelGeometry(_content->geometry(), _centerLabel->size());
|
||||||
_sublabel->width(),
|
|
||||||
_label->size());
|
|
||||||
updateSublabelGeometry(_content->geometry(), _sublabel->size());
|
updateSublabelGeometry(_content->geometry(), _sublabel->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallMuteButton::updateLabelGeometry(QRect my, int subWidth, QSize size) {
|
void CallMuteButton::updateLabelGeometry(QRect my, QSize size) {
|
||||||
const auto skip = subWidth
|
const auto skip = st::callMuteButtonSublabelSkip
|
||||||
? st::callMuteButtonSublabelSkip
|
+ st::callMuteButtonLabelsSkip;
|
||||||
: (st::callMuteButtonSublabelSkip / 2);
|
|
||||||
_label->moveToLeft(
|
_label->moveToLeft(
|
||||||
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||||
my.y() + my.height() - size.height() - skip,
|
my.y() + my.height() - _label->height() - skip,
|
||||||
|
my.width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallMuteButton::updateCenterLabelGeometry(QRect my, QSize size) {
|
||||||
|
const auto skip = (st::callMuteButtonSublabelSkip / 2)
|
||||||
|
+ st::callMuteButtonLabelsSkip;
|
||||||
|
_centerLabel->moveToLeft(
|
||||||
|
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||||
|
my.y() + my.height() - _centerLabel->height() - skip,
|
||||||
my.width());
|
my.width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) {
|
void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) {
|
||||||
|
const auto skip = st::callMuteButtonLabelsSkip;
|
||||||
_sublabel->moveToLeft(
|
_sublabel->moveToLeft(
|
||||||
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
my.x() + (my.width() - size.width()) / 2 + _labelShakeShift,
|
||||||
my.y() + my.height() - size.height(),
|
my.y() + my.height() - _sublabel->height() - skip,
|
||||||
my.width());
|
my.width());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class BlobsWidget;
|
||||||
class AbstractButton;
|
class AbstractButton;
|
||||||
class FlatLabel;
|
class FlatLabel;
|
||||||
class RpWidget;
|
class RpWidget;
|
||||||
|
class AnimatedLabel;
|
||||||
|
|
||||||
struct CallButtonColors;
|
struct CallButtonColors;
|
||||||
|
|
||||||
|
|
@ -87,7 +88,8 @@ private:
|
||||||
float64 progress);
|
float64 progress);
|
||||||
|
|
||||||
void setHandleMouseState(HandleMouseState state);
|
void setHandleMouseState(HandleMouseState state);
|
||||||
void updateLabelGeometry(QRect my, int subWidth, QSize size);
|
void updateCenterLabelGeometry(QRect my, QSize size);
|
||||||
|
void updateLabelGeometry(QRect my, QSize size);
|
||||||
void updateSublabelGeometry(QRect my, QSize size);
|
void updateSublabelGeometry(QRect my, QSize size);
|
||||||
void updateLabelsGeometry();
|
void updateLabelsGeometry();
|
||||||
|
|
||||||
|
|
@ -104,8 +106,9 @@ private:
|
||||||
|
|
||||||
const base::unique_qptr<BlobsWidget> _blobs;
|
const base::unique_qptr<BlobsWidget> _blobs;
|
||||||
const base::unique_qptr<AbstractButton> _content;
|
const base::unique_qptr<AbstractButton> _content;
|
||||||
const base::unique_qptr<FlatLabel> _label;
|
const base::unique_qptr<AnimatedLabel> _centerLabel;
|
||||||
const base::unique_qptr<FlatLabel> _sublabel;
|
const base::unique_qptr<AnimatedLabel> _label;
|
||||||
|
const base::unique_qptr<AnimatedLabel> _sublabel;
|
||||||
int _labelShakeShift = 0;
|
int _labelShakeShift = 0;
|
||||||
|
|
||||||
RadialInfo _radialInfo;
|
RadialInfo _radialInfo;
|
||||||
|
|
|
||||||
|
|
@ -1433,6 +1433,7 @@ callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||||
callMuteButtonSublabel: FlatLabel(defaultFlatLabel) {
|
callMuteButtonSublabel: FlatLabel(defaultFlatLabel) {
|
||||||
textFg: groupCallMemberNotJoinedStatus;
|
textFg: groupCallMemberNotJoinedStatus;
|
||||||
}
|
}
|
||||||
|
callMuteButtonLabelsSkip: 5px;
|
||||||
callMuteButtonSublabelSkip: 19px;
|
callMuteButtonSublabelSkip: 19px;
|
||||||
callMuteButtonActive: CallButton {
|
callMuteButtonActive: CallButton {
|
||||||
button: callMuteButtonActiveInner;
|
button: callMuteButtonActiveInner;
|
||||||
|
|
@ -1457,6 +1458,7 @@ callMuteButtonConnecting: CallButton(callMuteButtonMuted) {
|
||||||
bg: callIconBg;
|
bg: callIconBg;
|
||||||
label: callMuteButtonLabel;
|
label: callMuteButtonLabel;
|
||||||
}
|
}
|
||||||
|
callMuteButtonLabelAdditional: 5px;
|
||||||
|
|
||||||
callMuteCrossLine: CrossLineAnimation {
|
callMuteCrossLine: CrossLineAnimation {
|
||||||
fg: groupCallIconFg;
|
fg: groupCallIconFg;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue