Add Ui::PathShiftGradient effect.

This commit is contained in:
John Preston 2021-07-02 17:57:13 +03:00
parent 3b3413e618
commit baf4d80867
3 changed files with 241 additions and 0 deletions

View file

@ -51,6 +51,8 @@ PRIVATE
ui/effects/numbers_animation.h
ui/effects/panel_animation.cpp
ui/effects/panel_animation.h
ui/effects/path_shift_gradient.cpp
ui/effects/path_shift_gradient.h
ui/effects/radial_animation.cpp
ui/effects/radial_animation.h
ui/effects/ripple_animation.cpp

View file

@ -0,0 +1,175 @@
// 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/path_shift_gradient.h"
#include "base/call_delayed.h"
#include "ui/effects/animations.h"
namespace Ui {
namespace {
constexpr auto kSlideDuration = crl::time(1000);
constexpr auto kWaitDuration = crl::time(1000);
constexpr auto kFullDuration = kSlideDuration + kWaitDuration;
} // namespace
struct PathShiftGradient::AnimationData {
Ui::Animations::Simple animation;
base::flat_set<not_null<PathShiftGradient*>> active;
bool scheduled = false;
};
std::weak_ptr<PathShiftGradient::AnimationData> PathShiftGradient::Animation;
PathShiftGradient::PathShiftGradient(
const style::color &bg,
const style::color &fg,
Fn<void()> animationCallback)
: _bg(bg)
, _fg(fg)
, _animationCallback(std::move(animationCallback)) {
refreshColors();
style::PaletteChanged(
) | rpl::start_with_next([=] {
refreshColors();
}, _lifetime);
}
PathShiftGradient::~PathShiftGradient() {
if (const auto strong = _animation.get()) {
strong->active.erase(this);
}
}
void PathShiftGradient::overrideColors(
const style::color &bg,
const style::color &fg) {
_colorsOverriden = true;
refreshColors(bg, fg);
}
void PathShiftGradient::clearOverridenColors() {
if (!_colorsOverriden) {
return;
}
_colorsOverriden = false;
refreshColors();
}
void PathShiftGradient::startFrame(
int viewportLeft,
int viewportWidth,
int gradientWidth) {
_viewportLeft = viewportLeft;
_viewportWidth = viewportWidth;
_gradientWidth = gradientWidth;
_geometryUpdated = false;
}
void PathShiftGradient::updateGeometry() {
if (_geometryUpdated) {
return;
}
_geometryUpdated = true;
const auto now = crl::now();
const auto period = now % kFullDuration;
if (period >= kSlideDuration) {
_gradientEnabled = false;
return;
}
const auto progress = period / float64(kSlideDuration);
_gradientStart = anim::interpolate(
_viewportLeft - _gradientWidth,
_viewportLeft + _viewportWidth,
progress);
_gradientFinalStop = _gradientStart + _gradientWidth;
_gradientEnabled = true;
}
bool PathShiftGradient::paint(Fn<bool(const Background&)> painter) {
updateGeometry();
if (_gradientEnabled) {
_gradient.setStart(_gradientStart, 0);
_gradient.setFinalStop(_gradientFinalStop, 0);
}
const auto background = _gradientEnabled
? Background(&_gradient)
: _bgOverride
? *_bgOverride
: _bg;
if (!painter(background)) {
return false;
}
activateAnimation();
return true;
}
void PathShiftGradient::activateAnimation() {
if (_animationActive) {
return;
}
_animationActive = true;
if (!_animation) {
_animation = Animation.lock();
if (!_animation) {
_animation = std::make_shared<AnimationData>();
Animation = _animation;
}
}
const auto raw = _animation.get();
if (_animationCallback) {
raw->active.emplace(this);
}
const auto globalCallback = [] {
const auto strong = Animation.lock();
if (!strong) {
return;
}
strong->scheduled = false;
while (!strong->active.empty()) {
const auto entry = strong->active.back();
strong->active.erase(strong->active.end() - 1);
entry->_animationActive = false;
entry->_animationCallback();
}
};
const auto now = crl::now();
const auto period = now % kFullDuration;
if (period >= kSlideDuration) {
const auto tillWaitFinish = kFullDuration - period;
if (!raw->scheduled) {
raw->scheduled = true;
raw->animation.stop();
base::call_delayed(tillWaitFinish, globalCallback);
}
} else {
const auto tillSlideFinish = kSlideDuration - period;
if (!raw->animation.animating()) {
raw->animation.start(globalCallback, 0., 1., tillSlideFinish);
}
}
}
void PathShiftGradient::refreshColors() {
refreshColors(_bg, _fg);
}
void PathShiftGradient::refreshColors(
const style::color &bg,
const style::color &fg) {
_gradient.setStops({
{ 0., bg->c },
{ 0.5, fg->c },
{ 1., bg->c },
});
_bgOverride = _colorsOverriden ? &bg : nullptr;
}
} // namespace Ui

View file

@ -0,0 +1,64 @@
// 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
//
#pragma once
#include "ui/style/style_core_types.h"
#include <QtGui/QLinearGradient>
namespace Ui {
class PathShiftGradient final {
public:
PathShiftGradient(
const style::color &bg,
const style::color &fg,
Fn<void()> animationCallback);
~PathShiftGradient();
void startFrame(
int viewportLeft,
int viewportWidth,
int gradientWidth);
void overrideColors(const style::color &bg, const style::color &fg);
void clearOverridenColors();
using Background = std::variant<QLinearGradient*, style::color>;
bool paint(Fn<bool(const Background&)> painter);
private:
struct AnimationData;
void refreshColors();
void refreshColors(const style::color &bg, const style::color &fg);
void updateGeometry();
void activateAnimation();
static std::weak_ptr<AnimationData> Animation;
const style::color &_bg;
const style::color &_fg;
const style::color *_bgOverride = nullptr;
QLinearGradient _gradient;
std::shared_ptr<AnimationData> _animation;
const Fn<void()> _animationCallback;
int _viewportLeft = 0;
int _viewportWidth = 0;
int _gradientWidth = 0;
int _gradientStart = 0;
int _gradientFinalStop = 0;
bool _gradientEnabled = false;
bool _geometryUpdated = false;
bool _animationActive = false;
bool _colorsOverriden = false;
rpl::lifetime _lifetime;
};
} // namespace Ui