diff options
Diffstat (limited to 'src/render.c')
-rw-r--r-- | src/render.c | 146 |
1 files changed, 106 insertions, 40 deletions
diff --git a/src/render.c b/src/render.c index 9f2c1b1..908238e 100644 --- a/src/render.c +++ b/src/render.c @@ -33,27 +33,34 @@ GBytes* get_data_for_resource(const char *resource_path) return result; } +void set_password_prompt(saver_state_t *state, const char *prompt) +{ + strncpy(state->password_prompt, prompt, kMaxPromptLength - 1); +} + static void update_single_animation(saver_state_t *state, animation_t *anim) { // Cursor animation if (anim->type == ACursorAnimation) { CursorAnimation *ca = &anim->anim.cursor_anim; - if (ca->cursor_animating && !state->is_processing) { - const double cursor_fade_speed = 0.05; - if (ca->cursor_fade_direction > 0) { - state->cursor_opacity += cursor_fade_speed; - if (state->cursor_opacity > 1.0) { - ca->cursor_fade_direction *= -1; + if (ca->cursor_animating) { + if (!state->is_processing) { + const double cursor_fade_speed = 0.05; + if (ca->cursor_fade_direction > 0) { + state->cursor_opacity += cursor_fade_speed; + if (state->cursor_opacity > 1.0) { + ca->cursor_fade_direction *= -1; + } + } else { + state->cursor_opacity -= cursor_fade_speed; + if (state->cursor_opacity <= 0.0) { + ca->cursor_fade_direction *= -1; + } } } else { - state->cursor_opacity -= cursor_fade_speed; - if (state->cursor_opacity <= 0.0) { - ca->cursor_fade_direction *= -1; - } + state->cursor_opacity = 1.0; } - } else { - state->cursor_opacity = 1.0; } } @@ -113,6 +120,11 @@ static void update_single_animation(saver_state_t *state, animation_t *anim) anim->completed = completed; state->background_redshift = progress; } + + // Spinner animation + else if (anim->type == ASpinnerAnimation) { + anim->anim.spinner_anim.rotation += 0.07; + } } static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx) @@ -126,19 +138,38 @@ static unsigned next_anim_index(saver_state_t *state, unsigned cur_idx) return idx; } -void schedule_animation(saver_state_t *state, animation_t anim) +animation_key_t schedule_animation(saver_state_t *state, animation_t anim) { anim.start_time = anim_now(); // Find next empty element + animation_key_t key = 0; for (unsigned idx = 0; idx < kMaxAnimations; idx++) { animation_t check_anim = state->animations[idx]; if (check_anim.type == _EmptyAnimationType) { + key = idx; state->animations[idx] = anim; state->num_animations++; break; } } + + return key; +} + +void remove_animation(saver_state_t *state, animation_key_t key) +{ + state->animations[key].type = _EmptyAnimationType; +} + +animation_t* get_animation_for_key(saver_state_t *state, animation_key_t anim_key) +{ + animation_t *animation = NULL; + if (state->animations[anim_key].type != _EmptyAnimationType) { + animation = &state->animations[anim_key]; + } + + return animation; } void update_animations(saver_state_t *state) @@ -151,7 +182,7 @@ void update_animations(saver_state_t *state) update_single_animation(state, anim); if (anim->completed) { - state->animations[idx].type = _EmptyAnimationType; + remove_animation(state, idx); if (anim->completion_func != NULL) { anim->completion_func((struct animation_t *)anim, anim->completion_func_context); } @@ -167,6 +198,23 @@ void update_animations(saver_state_t *state) state->num_animations -= completed_animations; } +RsvgHandle* load_svg_for_resource_path(const char *resource_path) +{ + GError *error = NULL; + GBytes *bytes = get_data_for_resource(resource_path); + RsvgHandle *handle = NULL; + + gsize size = 0; + gconstpointer data = g_bytes_get_data(bytes, &size); + handle = rsvg_handle_new_from_data(data, size, &error); + g_bytes_unref(bytes); + if (error != NULL) { + fprintf(stderr, "Error loading SVG at resource path: %s\n", resource_path); + } + + return handle; +} + void draw_background(saver_state_t *state) { // Draw background @@ -178,20 +226,9 @@ void draw_background(saver_state_t *state) void draw_logo(saver_state_t *state) { if (state->logo_svg_handle == NULL) { - GError *error = NULL; - GBytes *bytes = get_data_for_resource("/resources/logo.svg"); - - gsize size = 0; - gconstpointer data = g_bytes_get_data(bytes, &size); - state->logo_svg_handle = rsvg_handle_new_from_data(data, size, &error); - g_bytes_unref(bytes); - if (error != NULL) { - fprintf(stderr, "Error loading logo SVG\n"); - return; - } + state->logo_svg_handle = load_svg_for_resource_path("/resources/logo.svg"); } - cairo_t *cr = state->ctx; cairo_save(cr); @@ -230,8 +267,8 @@ void draw_password_field(saver_state_t *state) // Common color for status and password field cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, state->password_opacity); - // Draw status text - const char *prompt = (state->password_prompt ?: "???"); + // Measure status text + const char *prompt = state->password_prompt; pango_layout_set_font_description(state->pango_layout, state->status_font); pango_layout_set_text(state->pango_layout, prompt, -1); @@ -239,22 +276,50 @@ void draw_password_field(saver_state_t *state) pango_layout_get_size(state->pango_layout, &t_width, &t_height); double line_height = t_height / PANGO_SCALE; - cairo_move_to(cr, field_x, field_y - line_height - field_padding); + // Measure processing indicator + double spinner_width = 0.0; + double spinner_scale_factor = 0.0; + RsvgDimensionData spinner_dimensions; + if (state->is_processing) { + if (state->spinner_svg_handle == NULL) { + state->spinner_svg_handle = load_svg_for_resource_path("/resources/spinner.svg"); + } + + rsvg_handle_get_dimensions(state->spinner_svg_handle, &spinner_dimensions); + spinner_scale_factor = ((line_height - 5.0) / spinner_dimensions.height); + spinner_width = spinner_dimensions.width * spinner_scale_factor; + + // padding + spinner_width += 10.0; + } + + // Draw status text + cairo_move_to(cr, spinner_width + field_x, field_y - line_height - field_padding); pango_cairo_show_layout(cr, state->pango_layout); + // Draw processing indicator + if (state->is_processing) { + SpinnerAnimation spinner_anim = get_animation_for_key(state, state->spinner_anim_key)->anim.spinner_anim; + + cairo_save(cr); + + cairo_translate(cr, field_x, field_y - line_height - 8.0); + + double tr_amount = (spinner_dimensions.width * spinner_scale_factor) / 2.0; + cairo_translate(cr, tr_amount, tr_amount); + cairo_rotate(cr, spinner_anim.rotation); + cairo_translate(cr, -tr_amount, -tr_amount); + + cairo_scale(cr, spinner_scale_factor, spinner_scale_factor); + + rsvg_handle_render_cairo(state->spinner_svg_handle, cr); + + cairo_restore(cr); + } + // Draw password asterisks if (state->asterisk_svg_handle == NULL) { - GError *error = NULL; - GBytes *bytes = get_data_for_resource("/resources/asterisk.svg"); - - gsize size = 0; - gconstpointer data = g_bytes_get_data(bytes, &size); - state->asterisk_svg_handle = rsvg_handle_new_from_data(data, size, &error); - g_bytes_unref(bytes); - if (error != NULL) { - fprintf(stderr, "Error loading asterisk SVG\n"); - return; - } + state->asterisk_svg_handle = load_svg_for_resource_path("/resources/asterisk.svg"); } const double cursor_padding_x = 10.0; @@ -284,6 +349,7 @@ void draw_password_field(saver_state_t *state) cairo_set_source(cr, asterisk_pattern); cairo_paint_with_alpha(cr, state->password_opacity); cairo_restore(cr); + cairo_pattern_destroy(asterisk_pattern); // Draw cursor cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, MIN(state->password_opacity, state->cursor_opacity)); |