1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#include <glib.h>
#include <stdbool.h>
#include <math.h>
#include "animate.h"
#include "state.h"
#include "log.h"
double clamp(double x, double min, double max)
{
const double t = x < min ? min : x;
return t > max ? max : t;
}
double smoothstep(double x, double edge0, double edge1)
{
x = clamp((x - edge0) / (edge1 - edge0), 0, 1);
return x * x * (3.0 - 2.0 * x);
}
double quadratic_bezier(double x, double a, double b, double c)
{
g_assert(x >= 0 && x <= 1);
g_assert(a >= 0 && a <= 1);
g_assert(b >= 0 && b <= 1);
g_assert(c >= 0 && c <= 1);
const double t = 1 - x;
return a * t * t + 2 * b * t * x + c * x * x;
}
double cubic_bezier(double x, double a, double b, double c, double d)
{
g_assert(x >= 0 && x <= 1);
g_assert(a >= 0 && a <= 1);
g_assert(b >= 0 && b <= 1);
g_assert(c >= 0 && c <= 1);
g_assert(d >= 0 && d <= 1);
const double t = 1 - x;
return a * (t * t * t) + 3 * b * (t * t * x) + 3 * c * (t * x * x) + d * (x * x * x);
}
typedef struct {
Animation anim;
int width;
cairo_pattern_t *gradient;
} AnimationShine;
// FIXME: Not working for button group
static bool shine_paint(AnimationShine *shine, cairo_t *cr, const Layout *layout)
{
gint64 end = shine->anim.start + shine->anim.duration;
gint64 now = g_get_monotonic_time();
if (now > end) return false;
double t = (double)(now - shine->anim.start) / (end - shine->anim.start);
double pos = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0);
double angle = atan((double)layout->height / layout->width);
// Make it double just to be sure
int h = 2 * (double)layout->height / cos(angle);
int x = layout->x + pos * layout->width - shine->width;
int y = layout->y;
cairo_matrix_t matrix;
cairo_matrix_init_translate(&matrix, -x, -y);
cairo_pattern_set_matrix(shine->gradient, &matrix);
int dx = layout->x + layout->width / 2;
int dy = layout->y + layout->height / 2;
cairo_translate(cr, dx, dy);
cairo_rotate(cr, -angle);
cairo_translate(cr, -dx, -dy);
cairo_set_operator(cr, CAIRO_OPERATOR_ATOP);
cairo_set_source(cr, shine->gradient);
cairo_rectangle(cr, x, y - (h - layout->height) / 2, shine->width, h);
cairo_fill(cr);
return true;
}
Animation *animation_shine_create(gint64 duration)
{
// Note the 0 initialization
AnimationShine *shine = g_malloc0(sizeof(AnimationShine));
shine->anim.type = ANIM_SHINE;
shine->anim.paint_func = (DrawFunc)shine_paint;
shine->anim.duration = duration;
// TODO: Change it depending on container size
shine->width = 20;
shine->gradient = cairo_pattern_create_linear(0, 0, shine->width, 0);
cairo_pattern_add_color_stop_rgba(shine->gradient, 0, 1, 1, 1, 0);
cairo_pattern_add_color_stop_rgba(shine->gradient, 0.5, 1, 1, 1, 0.333);
cairo_pattern_add_color_stop_rgba(shine->gradient, 1, 1, 1, 1, 0);
return (gpointer)shine;
}
Animation *animation_pulse_create(gint64 duration)
{
// TODO
return NULL;
}
void animation_destroy(Animation *anim)
{
if (anim == NULL) return;
if (anim->type == ANIM_SHINE)
cairo_pattern_destroy(CAST(anim, AnimationShine)->gradient);
g_free(anim);
}
// vim: ts=4 sw=4 et
|