diff --git a/src/c/neat_bar.c b/src/c/neat_bar.c index 9b563ad..b869a3b 100644 --- a/src/c/neat_bar.c +++ b/src/c/neat_bar.c @@ -36,50 +36,87 @@ static const GRect s_base_grect_rect = GRect(PBL_DISPLAY_WIDTH - ACTION_BAR_WIDT static NeatBarLayer *s_current_neat_bar = NULL; -static Animation *s_animate_move(NeatBarLayer *neat_bar, uint8_t button_index, bool move_on_y_axis, int16_t distance) { - BitmapLayer *bitmap_layer = NULL; +static GRect s_get_home_frame(NeatBarLayer *neat_bar, uint8_t button_index) { + int16_t y_offset = neat_bar->main_grect.origin.y; + int8_t spread = neat_bar->spread; + uint16_t width = neat_bar->main_grect.size.w; + + switch (button_index) { + case BUTTON_ID_UP: + return GRect(ICON_X_OFFSET, UP_Y - spread - y_offset, width, 25); + case BUTTON_ID_SELECT: + return GRect(ICON_X_OFFSET, SELECT_Y - y_offset, width, 25); + case BUTTON_ID_DOWN: + return GRect(ICON_X_OFFSET, DOWN_Y + spread - y_offset, width, 25); + default: + return GRectZero; + } +} + +// Performs a press or release animation for a single button, anchored to its +// home position. Duplicate events (press when already pressed, release when +// already released) are ignored so overlapping animations cannot accumulate +// drift. +static void s_animate_icon(NeatBarLayer *neat_bar, uint8_t button_index, bool is_press) { + BitmapLayer *bitmap_layer; + bool *pressed; switch (button_index) { case BUTTON_ID_UP: bitmap_layer = neat_bar->up_layer; + pressed = &neat_bar->up_pressed; break; case BUTTON_ID_SELECT: bitmap_layer = neat_bar->select_layer; + pressed = &neat_bar->select_pressed; break; case BUTTON_ID_DOWN: bitmap_layer = neat_bar->down_layer; + pressed = &neat_bar->down_pressed; break; default: - return NULL; + return; } - if (!bitmap_layer) { - return NULL; + if (!bitmap_layer) + return; + if (is_press) { + if (*pressed) + return; + *pressed = true; + } else { + if (!*pressed) + return; + *pressed = false; } Layer *layer = bitmap_layer_get_layer(bitmap_layer); - GRect from_frame = layer_get_frame(layer); - GRect to_frame = from_frame; - if (move_on_y_axis) { - to_frame.origin.y += distance; + GRect home = s_get_home_frame(neat_bar, button_index); + + // off = home shifted by -distance (the "pressed" position) + GRect off = home; + int16_t distance = neat_bar->animations_move_distance; + if (neat_bar->animations_move_on_y_axis) { + off.origin.y -= distance; } else { - to_frame.origin.x += distance; + off.origin.x -= distance; } - PropertyAnimation *prop_anim = property_animation_create_layer_frame(layer, &from_frame, &to_frame); - return property_animation_get_animation(prop_anim); + GRect from = is_press ? home : off; + GRect to = is_press ? off : home; + + PropertyAnimation *prop_anim = property_animation_create_layer_frame(layer, &from, &to); + Animation *anim = property_animation_get_animation(prop_anim); + animation_set_duration(anim, neat_bar->animations_duration); + animation_schedule(anim); } static void s_icon_down_handler(NeatBarLayer *neat_bar, uint8_t button_index) { - Animation *anim = s_animate_move(neat_bar, button_index, neat_bar->animations_move_on_y_axis, -neat_bar->animations_move_distance); - animation_set_duration(anim, neat_bar->animations_duration); - animation_schedule(anim); + s_animate_icon(neat_bar, button_index, true); } static void s_icon_up_handler(NeatBarLayer *neat_bar, uint8_t button_index) { - Animation *anim = s_animate_move(neat_bar, button_index, neat_bar->animations_move_on_y_axis, neat_bar->animations_move_distance); - animation_set_duration(anim, neat_bar->animations_duration); - animation_schedule(anim); + s_animate_icon(neat_bar, button_index, false); } static void s_up_down_handler(ClickRecognizerRef recognizer, void *context) { @@ -332,6 +369,9 @@ NeatBarLayer *neat_bar_layer_create() { neat_bar->animations_move_on_y_axis = false; neat_bar->animations_move_distance = ANIM_DISTANCE; neat_bar->animations_duration = 144; + neat_bar->up_pressed = false; + neat_bar->select_pressed = false; + neat_bar->down_pressed = false; neat_bar->context = NULL; layer_set_update_proc(neat_bar->main_layer, s_main_layer_update_proc); s_current_neat_bar = neat_bar; diff --git a/src/c/neat_bar.h b/src/c/neat_bar.h index 870d650..8cf4330 100644 --- a/src/c/neat_bar.h +++ b/src/c/neat_bar.h @@ -21,6 +21,9 @@ typedef struct { int8_t animations_move_distance; uint8_t animations_duration; //bool use_legacy_animations + bool up_pressed; + bool select_pressed; + bool down_pressed; void *context; } NeatBarLayer;