| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include "ui/effects/radial_animation.h"
- #include "ui/arc_angles.h"
- #include "ui/painter.h"
- #include "styles/style_widgets.h"
- namespace Ui {
- namespace {
- constexpr auto kFullArcLength = arc::kFullLength;
- } // namespace
- const int RadialState::kFull = kFullArcLength;
- void RadialAnimation::start(float64 prg) {
- _firstStart = _lastStart = _lastTime = crl::now();
- const auto iprg = qRound(qMax(prg, 0.0001) * arc::kAlmostFullLength);
- const auto iprgstrict = qRound(prg * arc::kAlmostFullLength);
- _arcEnd = anim::value(iprgstrict, iprg);
- _animation.start();
- }
- bool RadialAnimation::update(float64 prg, bool finished, crl::time ms) {
- const auto iprg = qRound(qMax(prg, 0.0001) * arc::kAlmostFullLength);
- const auto result = (iprg != qRound(_arcEnd.to()))
- || (_finished != finished);
- if (_finished != finished) {
- _arcEnd.start(iprg);
- _finished = finished;
- _lastStart = _lastTime;
- } else if (result) {
- _arcEnd.start(iprg);
- _lastStart = _lastTime;
- }
- _lastTime = ms;
- const auto dt = float64(ms - _lastStart);
- const auto fulldt = float64(ms - _firstStart);
- const auto opacitydt = _finished
- ? (_lastStart - _firstStart)
- : fulldt;
- _opacity = qMin(opacitydt / st::radialDuration, 1.);
- if (anim::Disabled()) {
- _arcEnd.update(1., anim::linear);
- if (finished) {
- stop();
- }
- } else if (!finished) {
- _arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear);
- } else if (dt >= st::radialDuration) {
- _arcEnd.update(1., anim::linear);
- stop();
- } else {
- auto r = dt / st::radialDuration;
- _arcEnd.update(r, anim::linear);
- _opacity *= 1 - r;
- }
- auto fromstart = fulldt / st::radialPeriod;
- _arcStart.update(fromstart - std::floor(fromstart), anim::linear);
- return result;
- }
- void RadialAnimation::stop() {
- _firstStart = _lastStart = _lastTime = 0;
- _arcEnd = anim::value();
- _animation.stop();
- }
- void RadialAnimation::draw(
- QPainter &p,
- const QRectF &inner,
- float64 thickness,
- style::color color) const {
- const auto state = computeState();
- auto o = p.opacity();
- p.setOpacity(o * state.shown);
- auto pen = color->p;
- auto was = p.pen();
- pen.setWidthF(thickness);
- pen.setCapStyle(Qt::RoundCap);
- p.setPen(pen);
- {
- PainterHighQualityEnabler hq(p);
- p.drawArc(inner, state.arcFrom, state.arcLength);
- }
- p.setPen(was);
- p.setOpacity(o);
- }
- RadialState RadialAnimation::computeState() const {
- auto length = arc::kMinLength + qRound(_arcEnd.current());
- auto from = arc::kQuarterLength
- - length
- - (anim::Disabled() ? 0 : qRound(_arcStart.current()));
- if (style::RightToLeft()) {
- from = arc::kQuarterLength - (from - arc::kQuarterLength) - length;
- if (from < 0) from += arc::kFullLength;
- }
- return { _opacity, from, length };
- }
- void InfiniteRadialAnimation::init() {
- anim::Disables() | rpl::filter([=] {
- return animating();
- }) | rpl::start_with_next([=](bool disabled) {
- if (!disabled && !_animation.animating()) {
- _animation.start();
- } else if (disabled && _animation.animating()) {
- _animation.stop();
- }
- }, _lifetime);
- }
- void InfiniteRadialAnimation::start(crl::time skip) {
- if (!animating()) {
- const auto now = crl::now();
- _workStarted = std::max(now + _st.sineDuration - skip, crl::time(1));
- _workFinished = 0;
- }
- if (!anim::Disabled() && !_animation.animating()) {
- _animation.start();
- }
- }
- void InfiniteRadialAnimation::stop(anim::type animated) {
- const auto now = crl::now();
- if (anim::Disabled() || animated == anim::type::instant) {
- _workFinished = now;
- }
- if (!_workFinished) {
- const auto zero = _workStarted - _st.sineDuration;
- const auto index = (now - zero + _st.sinePeriod - _st.sineShift)
- / _st.sinePeriod;
- _workFinished = zero
- + _st.sineShift
- + (index * _st.sinePeriod)
- + _st.sineDuration;
- } else if (_workFinished <= now) {
- _animation.stop();
- }
- }
- void InfiniteRadialAnimation::draw(
- QPainter &p,
- QPoint position,
- int outerWidth) {
- Draw(
- p,
- computeState(),
- position,
- _st.size,
- outerWidth,
- _st.color,
- _st.thickness);
- }
- void InfiniteRadialAnimation::draw(
- QPainter &p,
- QPoint position,
- QSize size,
- int outerWidth) {
- Draw(
- p,
- computeState(),
- position,
- size,
- outerWidth,
- _st.color,
- _st.thickness);
- }
- void InfiniteRadialAnimation::Draw(
- QPainter &p,
- const RadialState &state,
- QPoint position,
- QSize size,
- int outerWidth,
- QPen pen,
- int thickness) {
- auto o = p.opacity();
- p.setOpacity(o * state.shown);
- const auto rect = style::rtlrect(
- position.x(),
- position.y(),
- size.width(),
- size.height(),
- outerWidth);
- const auto was = p.pen();
- const auto brush = p.brush();
- if (anim::Disabled()) {
- anim::DrawStaticLoading(p, rect, thickness, pen);
- } else {
- pen.setWidth(thickness);
- pen.setCapStyle(Qt::RoundCap);
- p.setPen(pen);
- {
- PainterHighQualityEnabler hq(p);
- p.drawArc(
- rect,
- state.arcFrom,
- state.arcLength);
- }
- }
- p.setPen(was);
- p.setBrush(brush);
- p.setOpacity(o);
- }
- RadialState InfiniteRadialAnimation::computeState() {
- const auto now = crl::now();
- const auto linear = kFullArcLength
- - int(((now * kFullArcLength) / _st.linearPeriod) % kFullArcLength);
- if (!animating()) {
- const auto shown = 0.;
- _animation.stop();
- return {
- shown,
- linear,
- kFullArcLength };
- }
- if (anim::Disabled()) {
- return { 1., 0, kFullArcLength };
- }
- const auto min = int(base::SafeRound(kFullArcLength * _st.arcMin));
- const auto max = int(base::SafeRound(kFullArcLength * _st.arcMax));
- if (now <= _workStarted) {
- // zero .. _workStarted
- const auto zero = _workStarted - _st.sineDuration;
- const auto shown = (now - zero) / float64(_st.sineDuration);
- const auto length = anim::interpolate(
- kFullArcLength,
- min,
- anim::sineInOut(1., std::clamp(shown, 0., 1.)));
- return {
- shown,
- linear,
- length };
- } else if (!_workFinished || now <= _workFinished - _st.sineDuration) {
- // _workStared .. _workFinished - _st.sineDuration
- const auto shown = 1.;
- const auto cycles = (now - _workStarted) / _st.sinePeriod;
- const auto relative = (now - _workStarted) % _st.sinePeriod;
- const auto smallDuration = _st.sineShift - _st.sineDuration;
- const auto basic = int((linear
- + min
- + (cycles * (kFullArcLength + min - max))) % kFullArcLength);
- if (relative <= smallDuration) {
- // localZero .. growStart
- return {
- shown,
- basic - min,
- min };
- } else if (relative <= smallDuration + _st.sineDuration) {
- // growStart .. growEnd
- const auto growLinear = (relative - smallDuration) /
- float64(_st.sineDuration);
- const auto growProgress = anim::sineInOut(1., growLinear);
- const auto length = anim::interpolate(min, max, growProgress);
- return {
- shown,
- basic - length,
- length };
- } else if (relative <= _st.sinePeriod - _st.sineDuration) {
- // growEnd .. shrinkStart
- return {
- shown,
- basic - max,
- max };
- } else {
- // shrinkStart .. shrinkEnd
- const auto shrinkLinear = (relative
- - (_st.sinePeriod - _st.sineDuration))
- / float64(_st.sineDuration);
- const auto shrinkProgress = anim::sineInOut(1., shrinkLinear);
- const auto shrink = anim::interpolate(
- 0,
- max - min,
- shrinkProgress);
- return {
- shown,
- basic - max,
- max - shrink }; // interpolate(max, min, shrinkProgress)
- }
- } else {
- // _workFinished - _st.sineDuration .. _workFinished
- const auto hidden = (now - (_workFinished - _st.sineDuration))
- / float64(_st.sineDuration);
- const auto cycles = (_workFinished - _workStarted) / _st.sinePeriod;
- const auto basic = int((linear
- + min
- + cycles * (kFullArcLength + min - max)) % kFullArcLength);
- const auto length = anim::interpolate(
- min,
- kFullArcLength,
- anim::sineInOut(1., std::clamp(hidden, 0., 1.)));
- return {
- 1. - hidden,
- basic - length,
- length };
- }
- //const auto frontPeriods = time / st.sinePeriod;
- //const auto frontCurrent = time % st.sinePeriod;
- //const auto frontProgress = anim::sineInOut(
- // st.arcMax - st.arcMin,
- // std::min(frontCurrent, crl::time(st.sineDuration))
- // / float64(st.sineDuration));
- //const auto backTime = std::max(time - st.sineShift, 0LL);
- //const auto backPeriods = backTime / st.sinePeriod;
- //const auto backCurrent = backTime % st.sinePeriod;
- //const auto backProgress = anim::sineInOut(
- // st.arcMax - st.arcMin,
- // std::min(backCurrent, crl::time(st.sineDuration))
- // / float64(st.sineDuration));
- //const auto front = linear + base::SafeRound((st.arcMin + frontProgress + frontPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
- //const auto from = linear + base::SafeRound((backProgress + backPeriods * (st.arcMax - st.arcMin)) * kFullArcLength);
- //const auto length = (front - from);
- //return {
- // _opacity,
- // from,
- // length
- //};
- }
- } // namespace Ui
|