Added animation support to arc painter.
This commit is contained in:
parent
5bcd894429
commit
ddda92c777
3 changed files with 150 additions and 13 deletions
|
|
@ -6,13 +6,30 @@
|
||||||
//
|
//
|
||||||
#include "ui/paint/arcs.h"
|
#include "ui/paint/arcs.h"
|
||||||
|
|
||||||
|
#include "ui/effects/animation_value.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
|
||||||
namespace Ui::Paint {
|
namespace Ui::Paint {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline float64 InterpolateF(float a, float b, float64 b_ratio) {
|
||||||
|
return a + float64(b - a) * b_ratio;
|
||||||
|
};
|
||||||
|
|
||||||
|
QRectF InterpolatedRect(const QRectF &r1, const QRectF &r2, float64 ratio) {
|
||||||
|
return QRectF(
|
||||||
|
InterpolateF(r1.x(), r2.x(), ratio),
|
||||||
|
InterpolateF(r1.y(), r2.y(), ratio),
|
||||||
|
InterpolateF(r1.width(), r2.width(), ratio),
|
||||||
|
InterpolateF(r1.height(), r2.height(), ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ArcsAnimation::ArcsAnimation(
|
ArcsAnimation::ArcsAnimation(
|
||||||
const style::ArcsAnimation &st,
|
const style::ArcsAnimation &st,
|
||||||
int count,
|
std::vector<float> thresholds,
|
||||||
|
float64 startValue,
|
||||||
VerticalDirection direction,
|
VerticalDirection direction,
|
||||||
int centerX,
|
int centerX,
|
||||||
int startY)
|
int startY)
|
||||||
|
|
@ -23,13 +40,16 @@ ArcsAnimation::ArcsAnimation(
|
||||||
, _verticalDirection(direction)
|
, _verticalDirection(direction)
|
||||||
, _startAngle((st.deltaAngle
|
, _startAngle((st.deltaAngle
|
||||||
+ ((direction == VerticalDirection::Up) ? 90 : 270)) * 16)
|
+ ((direction == VerticalDirection::Up) ? 90 : 270)) * 16)
|
||||||
, _spanAngle(-st.deltaAngle * 2 * 16) {
|
, _spanAngle(-st.deltaAngle * 2 * 16)
|
||||||
initArcs(count);
|
, _emptyRect(computeArcRect(0))
|
||||||
|
, _currentValue(startValue) {
|
||||||
|
initArcs(std::move(thresholds));
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcsAnimation::ArcsAnimation(
|
ArcsAnimation::ArcsAnimation(
|
||||||
const style::ArcsAnimation &st,
|
const style::ArcsAnimation &st,
|
||||||
int count,
|
std::vector<float> thresholds,
|
||||||
|
float64 startValue,
|
||||||
HorizontalDirection direction,
|
HorizontalDirection direction,
|
||||||
int startX,
|
int startX,
|
||||||
int centerY)
|
int centerY)
|
||||||
|
|
@ -40,15 +60,24 @@ ArcsAnimation::ArcsAnimation(
|
||||||
, _verticalDirection(VerticalDirection::None)
|
, _verticalDirection(VerticalDirection::None)
|
||||||
, _startAngle((st.deltaAngle
|
, _startAngle((st.deltaAngle
|
||||||
+ ((direction == HorizontalDirection::Left) ? 180 : 0)) * 16)
|
+ ((direction == HorizontalDirection::Left) ? 180 : 0)) * 16)
|
||||||
, _spanAngle(-st.deltaAngle * 2 * 16) {
|
, _spanAngle(-st.deltaAngle * 2 * 16)
|
||||||
initArcs(count);
|
, _emptyRect(computeArcRect(0))
|
||||||
|
, _currentValue(startValue) {
|
||||||
|
initArcs(std::move(thresholds));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArcsAnimation::initArcs(int count) {
|
void ArcsAnimation::initArcs(std::vector<float> thresholds) {
|
||||||
|
const auto count = thresholds.size();
|
||||||
_arcs.reserve(count);
|
_arcs.reserve(count);
|
||||||
|
|
||||||
for (auto i = 0; i < count; i++) {
|
for (auto i = 0; i < count; i++) {
|
||||||
auto arc = Arc{ .rect = computeArcRect(i) };
|
const auto threshold = thresholds[i];
|
||||||
|
const auto progress = (threshold > _currentValue) ? 1. : 0.;
|
||||||
|
auto arc = Arc{
|
||||||
|
.rect = computeArcRect(i + 1),
|
||||||
|
.threshold = threshold,
|
||||||
|
.progress = progress,
|
||||||
|
};
|
||||||
_arcs.push_back(std::move(arc));
|
_arcs.push_back(std::move(arc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +105,77 @@ QRectF ArcsAnimation::computeArcRect(int index) const {
|
||||||
return QRectF();
|
return QRectF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ArcsAnimation::update(crl::time now) {
|
||||||
|
for (auto &arc : _arcs) {
|
||||||
|
if (!isArcFinished(arc)) {
|
||||||
|
const auto progress = std::clamp(
|
||||||
|
(now - arc.startTime) / float64(_st.duration),
|
||||||
|
0.,
|
||||||
|
1.);
|
||||||
|
arc.progress = (arc.threshold > _currentValue)
|
||||||
|
? progress
|
||||||
|
: (1. - progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isFinished()) {
|
||||||
|
_stopUpdateRequests.fire({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ArcsAnimation::setValue(float64 value) {
|
||||||
|
if (_currentValue == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto previousValue = _currentValue;
|
||||||
|
_currentValue = value;
|
||||||
|
if (!isFinished()) {
|
||||||
|
const auto now = crl::now();
|
||||||
|
_startUpdateRequests.fire({});
|
||||||
|
for (auto &arc : _arcs) {
|
||||||
|
updateArcStartTime(arc, previousValue, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArcsAnimation::updateArcStartTime(
|
||||||
|
Arc &arc,
|
||||||
|
float64 previousValue,
|
||||||
|
crl::time now) {
|
||||||
|
if ((arc.progress == 0.) || (arc.progress == 1.)) {
|
||||||
|
arc.startTime = isArcFinished(arc) ? 0 : now;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto isPreviousToHide = (arc.threshold <= previousValue); // 0 -> 1
|
||||||
|
const auto isCurrentToHide = (arc.threshold <= _currentValue);
|
||||||
|
if (isPreviousToHide != isCurrentToHide) {
|
||||||
|
const auto passedTime = _st.duration * arc.progress;
|
||||||
|
const auto newDelta = isCurrentToHide
|
||||||
|
? (_st.duration - passedTime)
|
||||||
|
: passedTime;
|
||||||
|
arc.startTime = now - newDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> ArcsAnimation::startUpdateRequests() {
|
||||||
|
return _startUpdateRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> ArcsAnimation::stopUpdateRequests() {
|
||||||
|
return _stopUpdateRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArcsAnimation::isFinished() const {
|
||||||
|
return ranges::all_of(
|
||||||
|
_arcs,
|
||||||
|
[=](const Arc &arc) { return isArcFinished(arc); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArcsAnimation::isArcFinished(const Arc &arc) const {
|
||||||
|
return ((arc.threshold > _currentValue) && (arc.progress == 1.))
|
||||||
|
|| ((arc.threshold <= _currentValue) && (arc.progress == 0.));
|
||||||
|
}
|
||||||
|
|
||||||
void ArcsAnimation::paint(Painter &p, std::optional<QColor> colorOverride) {
|
void ArcsAnimation::paint(Painter &p, std::optional<QColor> colorOverride) {
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
QPen pen;
|
QPen pen;
|
||||||
|
|
@ -83,8 +183,18 @@ void ArcsAnimation::paint(Painter &p, std::optional<QColor> colorOverride) {
|
||||||
pen.setCapStyle(Qt::RoundCap);
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
pen.setColor(colorOverride ? (*colorOverride) : _st.fg->c);
|
pen.setColor(colorOverride ? (*colorOverride) : _st.fg->c);
|
||||||
p.setPen(pen);
|
p.setPen(pen);
|
||||||
for (const auto &arc : _arcs) {
|
for (auto i = 0; i < _arcs.size(); i++) {
|
||||||
p.drawArc(arc.rect, _startAngle, _spanAngle);
|
const auto &arc = _arcs[i];
|
||||||
|
const auto previousRect = (!i) ? _emptyRect : _arcs[i - 1].rect;
|
||||||
|
const auto progress = arc.progress;
|
||||||
|
const auto opactity = (1. - progress);
|
||||||
|
p.setOpacity(opactity * opactity);
|
||||||
|
const auto rect = (progress == 0.)
|
||||||
|
? arc.rect
|
||||||
|
: (progress == 1.)
|
||||||
|
? previousRect
|
||||||
|
: InterpolatedRect(arc.rect, previousRect, progress);
|
||||||
|
p.drawArc(rect, _startAngle, _spanAngle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,16 @@ public:
|
||||||
|
|
||||||
ArcsAnimation(
|
ArcsAnimation(
|
||||||
const style::ArcsAnimation &st,
|
const style::ArcsAnimation &st,
|
||||||
int count,
|
std::vector<float> thresholds,
|
||||||
|
float64 startValue,
|
||||||
VerticalDirection direction,
|
VerticalDirection direction,
|
||||||
int centerX,
|
int centerX,
|
||||||
int startY);
|
int startY);
|
||||||
|
|
||||||
ArcsAnimation(
|
ArcsAnimation(
|
||||||
const style::ArcsAnimation &st,
|
const style::ArcsAnimation &st,
|
||||||
int count,
|
std::vector<float> thresholds,
|
||||||
|
float64 startValue,
|
||||||
HorizontalDirection direction,
|
HorizontalDirection direction,
|
||||||
int startX,
|
int startX,
|
||||||
int centerY);
|
int centerY);
|
||||||
|
|
@ -45,14 +47,32 @@ public:
|
||||||
Painter &p,
|
Painter &p,
|
||||||
std::optional<QColor> colorOverride = std::nullopt);
|
std::optional<QColor> colorOverride = std::nullopt);
|
||||||
|
|
||||||
|
void setValue(float64 value);
|
||||||
|
|
||||||
|
rpl::producer<> startUpdateRequests();
|
||||||
|
rpl::producer<> stopUpdateRequests();
|
||||||
|
|
||||||
|
void update(crl::time now);
|
||||||
|
|
||||||
|
bool isFinished() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Arc {
|
struct Arc {
|
||||||
QRectF rect;
|
QRectF rect;
|
||||||
|
float threshold;
|
||||||
|
crl::time startTime = 0;
|
||||||
|
float64 progress = 0.;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initArcs(int count);
|
void initArcs(std::vector<float> thresholds);
|
||||||
QRectF computeArcRect(int index) const;
|
QRectF computeArcRect(int index) const;
|
||||||
|
|
||||||
|
bool isArcFinished(const Arc &arc) const;
|
||||||
|
void updateArcStartTime(
|
||||||
|
Arc &arc,
|
||||||
|
float64 previousValue,
|
||||||
|
crl::time now);
|
||||||
|
|
||||||
const style::ArcsAnimation &_st;
|
const style::ArcsAnimation &_st;
|
||||||
const int _center;
|
const int _center;
|
||||||
const int _start;
|
const int _start;
|
||||||
|
|
@ -60,6 +80,12 @@ private:
|
||||||
const VerticalDirection _verticalDirection;
|
const VerticalDirection _verticalDirection;
|
||||||
const int _startAngle;
|
const int _startAngle;
|
||||||
const int _spanAngle;
|
const int _spanAngle;
|
||||||
|
const QRectF _emptyRect;
|
||||||
|
|
||||||
|
float64 _currentValue = 0.;
|
||||||
|
|
||||||
|
rpl::event_stream<> _startUpdateRequests;
|
||||||
|
rpl::event_stream<> _stopUpdateRequests;
|
||||||
|
|
||||||
std::vector<Arc> _arcs;
|
std::vector<Arc> _arcs;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -414,6 +414,7 @@ ArcsAnimation {
|
||||||
fg: color;
|
fg: color;
|
||||||
stroke: pixels;
|
stroke: pixels;
|
||||||
space: pixels;
|
space: pixels;
|
||||||
|
duration: int;
|
||||||
deltaAngle: int;
|
deltaAngle: int;
|
||||||
deltaHeight: pixels;
|
deltaHeight: pixels;
|
||||||
deltaWidth: pixels;
|
deltaWidth: pixels;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue