diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/block.c | 2 | ||||
| -rw-r--r-- | src/block.h | 1 | ||||
| -rw-r--r-- | src/comet.c | 2 | ||||
| -rw-r--r-- | src/effect.c | 52 | ||||
| -rw-r--r-- | src/effect.h | 29 | ||||
| -rw-r--r-- | src/event.c | 5 | ||||
| -rw-r--r-- | src/layout.c | 25 | ||||
| -rw-r--r-- | src/util.c | 47 | ||||
| -rw-r--r-- | src/util.h | 10 |
9 files changed, 166 insertions, 7 deletions
diff --git a/src/block.c b/src/block.c index d0b66c9..29a8394 100644 --- a/src/block.c +++ b/src/block.c @@ -9,7 +9,7 @@ void block_update(block_t *block) if (block->update_cb != NULL) { struct timespec now, diff; timespec_get(&now, TIME_UTC); - diff = timespec_diff(block->update_last, now); + diff = timespec_diff(now, block->update_last); if (timespec_greater(diff, block->update_interval)) { log_value_trace("Updating block", diff --git a/src/block.h b/src/block.h index 4254355..6eeb0c0 100644 --- a/src/block.h +++ b/src/block.h @@ -52,6 +52,7 @@ struct block { block_update_t update_cb; block_event_t event_cb; block_finalize_t finalize_cb; + struct effect *effect; color_t color; color_t line_color; unsigned int line_width; diff --git a/src/comet.c b/src/comet.c index 6fccb3d..a539015 100644 --- a/src/comet.c +++ b/src/comet.c @@ -124,7 +124,7 @@ int main(int argc, char **argv) layout_free(&layout); timespec_get(&end, TIME_UTC); - diff = timespec_diff(timespec_diff(end, start), rate); + diff = timespec_diff(rate, timespec_diff(end, start)); nanosleep(&diff, NULL); } diff --git a/src/effect.c b/src/effect.c new file mode 100644 index 0000000..ae44c68 --- /dev/null +++ b/src/effect.c @@ -0,0 +1,52 @@ +#include <math.h> + +#include "effect.h" +#include "any_log.h" + +double cubic_bezier(double x, double a, double b, double c, double d) +{ + const double t = 1 - x; + return a * (t * t * t) + 3 * b * (t * t * x) + 3 * c * (t * x * x) + d * (x * x * x); +} + +static void effect_pulse_pre(effect_t *effect, layout_t *layout, cairo_t *cr) +{ + struct timespec now; + timespec_get(&now, TIME_UTC); + + // After half the duration we invert direction + struct timespec midpoint = timespec_div(effect->duration, 2); + struct timespec diff = timespec_diff(now, effect->start); + + double t = timespec_greater(midpoint, diff) + ? (double)timespec_to_ms(diff) / timespec_to_ms(midpoint) + : 1.0 - (double)timespec_to_ms(timespec_diff(diff, midpoint)) / timespec_to_ms(midpoint); + + // Make it customizable + double s = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0); + + // Make it a parameter + const double amplitude = 0.12; + + // FIXME: The intent was to scale the animation for long blocks, but it needs more love + // + int x_max = amplitude * (layout->height + (layout->width / (double)layout->height) - 1); + int y_max = amplitude * layout->height; + + layout->x_padding = layout->block->x_padding + x_max * s; + layout->y_padding = layout->block->y_padding + y_max * s; +} + +effect_t *effect_pulse(struct timespec duration) +{ + effect_t *effect = calloc(1, sizeof(effect_t)); + effect->type = EFFECT_PULSE; + effect->duration = duration; + effect->pre = effect_pulse_pre; + return effect; +} + +void effect_free(effect_t *effect) +{ + free(effect); +} diff --git a/src/effect.h b/src/effect.h new file mode 100644 index 0000000..b6c6282 --- /dev/null +++ b/src/effect.h @@ -0,0 +1,29 @@ +#ifndef COMET_EFFECT_H +#define COMET_EFFECT_H + +#include <cairo.h> + +#include "util.h" +#include "layout.h" + +typedef enum { + EFFECT_PULSE, +} effect_type_t; + +typedef struct effect effect_t; + +typedef void (*effect_render_t)(effect_t *effect, layout_t *layout, cairo_t *cr); + +struct effect { + effect_type_t type; + struct timespec start; + struct timespec duration; + effect_render_t pre; + effect_render_t post; +}; + +effect_t *effect_pulse(struct timespec duration); + +void effect_free(effect_t *effect); + +#endif diff --git a/src/event.c b/src/event.c index 0942fa1..a433fba 100644 --- a/src/event.c +++ b/src/event.c @@ -3,6 +3,7 @@ #include "util.h" #include "layout.h" #include "event.h" +#include "effect.h" #include "any_log.h" const char *even_type_to_string(event_type_t type) @@ -31,6 +32,10 @@ static bool event_click(layout_t *layout, event_t event) return true; } + if (layout->block->effect == NULL) { + layout->block->effect = effect_pulse(timespec_from_ms(200)); + } + block_event_t event_cb = layout->block->event_cb; log_value_debug("Block was clicked", "s:type", even_type_to_string(event.type), diff --git a/src/layout.c b/src/layout.c index 92e6469..3ebbcce 100644 --- a/src/layout.c +++ b/src/layout.c @@ -5,6 +5,7 @@ #include "any_log.h" #include "layout.h" +#include "effect.h" void layout_init(layout_t *layout, block_t *block, layout_info_t info) { @@ -73,6 +74,22 @@ void layout_init(layout_t *layout, block_t *block, layout_info_t info) void layout_render(layout_t *layout, cairo_t *cr) { + effect_t *effect = layout->block->effect; + if (effect != NULL) { + struct timespec now; + timespec_get(&now, TIME_UTC); + + if (timespec_zero(effect->start)) + effect->start = now; + else if (timespec_greater(now, timespec_add(effect->start, effect->duration))) + layout->block->effect = NULL; + } + + // Pre-processing effects + if (effect != NULL && effect->pre != NULL) { + effect->pre(effect, layout, cr); + } + double degree = M_PI / 180.0; int radius = layout->height / 2 - layout->y_padding; int line_radius = radius - layout->block->line_width / 2; @@ -117,6 +134,14 @@ void layout_render(layout_t *layout, cairo_t *cr) pango_cairo_update_layout(cr, layout->pl); pango_cairo_show_layout(cr, layout->pl); } + + // Post-processing effects + if (effect != NULL && effect->post != NULL) { + effect->post(effect, layout, cr); + } + + if (layout->block->effect == NULL && effect != NULL) + effect_free(effect); } void layout_free(layout_t *layout) @@ -28,14 +28,46 @@ void color_print(FILE *stream, color_t *color) fprintf(stream, "#%02x%02x%02x%02x", r, g, b, a); } +struct timespec timespec_from_ms(long ms) +{ + struct timespec ts = { + .tv_sec = ms / 1000, + .tv_nsec = (ms % 1000) * 1000000ul, + }; + return ts; +} + +long timespec_to_ms(struct timespec ts) +{ + return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000ul); +} + struct timespec timespec_diff(struct timespec a, struct timespec b) { - bool over = (b.tv_nsec - a.tv_nsec) < 0; - struct timespec diff = { - .tv_sec = b.tv_sec - a.tv_sec - over, - .tv_nsec = b.tv_nsec - a.tv_nsec + over * 1000000000ul, + bool over = (a.tv_nsec - b.tv_nsec) < 0; + struct timespec ts = { + .tv_sec = a.tv_sec - b.tv_sec - over, + .tv_nsec = a.tv_nsec - b.tv_nsec + over * 1000000000ul, }; - return diff; + return ts; +} + +struct timespec timespec_add(struct timespec a, struct timespec b) +{ + bool over = (a.tv_nsec + b.tv_nsec) > 1000000000ul; + struct timespec ts = { + .tv_sec = a.tv_sec + b.tv_sec + over, + .tv_nsec = a.tv_nsec + b.tv_nsec - over * 1000000000ul, + }; + return ts; +} + +struct timespec timespec_div(struct timespec ts, int n) +{ + ts.tv_nsec /= n; + ts.tv_nsec += ((ts.tv_sec % n) * 1000000000ul) / n; + ts.tv_sec /= n; + return ts; } bool timespec_greater(struct timespec a, struct timespec b) @@ -44,6 +76,11 @@ bool timespec_greater(struct timespec a, struct timespec b) || (a.tv_sec == b.tv_sec && a.tv_nsec > b.tv_nsec); } +bool timespec_zero(struct timespec ts) +{ + return ts.tv_sec == 0 && ts.tv_nsec == 0; +} + void timespec_print(FILE *stream, struct timespec *ts) { fprintf(stream, "%ld.%.9ld", ts->tv_sec, ts->tv_nsec); @@ -29,10 +29,20 @@ char *color_to_string(color_t *color); void color_print(FILE *stream, color_t *color); +struct timespec timespec_from_ms(long ms); + +long timespec_to_ms(struct timespec ts); + struct timespec timespec_diff(struct timespec a, struct timespec b); +struct timespec timespec_add(struct timespec a, struct timespec b); + +struct timespec timespec_div(struct timespec ts, int n); + bool timespec_greater(struct timespec a, struct timespec b); +bool timespec_zero(struct timespec ts); + void timespec_print(FILE *stream, struct timespec *ts); // Check if point (px, py) is inside a rectangle in (x, y), (x+w, y), (x, y+h) and (w+h, y+h) |
