#include #include #include #include #include "scheme.h" #include "../any_log.h" typedef struct { effect_t effect; double amplitude; } effect_pulse_t; 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->info->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); const double amplitude = ((effect_pulse_t *)effect)->amplitude; // 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; } static effect_t *effect_pulse_allocate(const effect_info_t *info) { effect_pulse_t *effect = malloc(sizeof(effect_pulse_t)); effect_init((effect_t *)effect, info); effect->amplitude = *(unsigned int *)info->state / 100.0; return (effect_t *)effect; } static void effect_pulse_finalize(effect_t *effect) { free(effect); } static bool effect_pulse_validate(effect_info_t *info, const effect_scheme_t *scheme) { unsigned int amplitude = *(unsigned int *)info->state; if (amplitude > 100) { log_error("Effect '%s' pulse amplitude must not exceed 100", info->label); return false; } return true; } static const config_entry_t effect_pulse_entries[] = { { "amplitude", CONFIG_UINT, NULL, 0 }, { 0 }, }; const effect_scheme_t effect_pulse_scheme = { .name = "pulse", .info = { .duration = { .tv_sec = 0, .tv_nsec = 200000000, }, .allocate = effect_pulse_allocate, .finalize = effect_pulse_finalize, .pre = effect_pulse_pre, }, .size = sizeof(unsigned int), .entries = effect_pulse_entries, .validate = effect_pulse_validate, };