[FL-1908] New animation update scheme (#737)

* Assets: update desktop animation frame rate and cleanup.

* Power: update ViewPort only if changed.

* Gui: tie IconAnimation with View, new update event generation scheme. Desktop: update IconAnimation usage.

Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
あく
2021-10-02 20:00:56 +03:00
committed by GitHub
parent 6f346597d2
commit 61aaed8abb
18 changed files with 271 additions and 175 deletions

View File

@@ -7,26 +7,26 @@ IconAnimation* icon_animation_alloc(const Icon* icon) {
furi_assert(icon);
IconAnimation* instance = furi_alloc(sizeof(IconAnimation));
instance->icon = icon;
instance->timer = osTimerNew(icon_animation_timer_callback, osTimerPeriodic, instance, NULL);
return instance;
}
void icon_animation_free(IconAnimation* instance) {
furi_assert(instance);
furi_check(osTimerDelete(instance->timer) == osOK);
free(instance);
}
const uint8_t* icon_animation_get_data(IconAnimation* instance) {
void icon_animation_set_update_callback(
IconAnimation* instance,
IconAnimationCallback callback,
void* context) {
furi_assert(instance);
if(instance->tick) {
uint32_t now = osKernelGetTickCount();
if(now < instance->tick) {
instance->tick = now;
icon_animation_next_frame(instance);
} else if(now - instance->tick > osKernelGetTickFreq() / instance->icon->frame_rate) {
instance->tick = now;
icon_animation_next_frame(instance);
}
}
instance->callback = callback;
instance->callback_context = context;
}
const uint8_t* icon_animation_get_data(IconAnimation* instance) {
return instance->icon->frames[instance->frame];
}
@@ -35,6 +35,19 @@ void icon_animation_next_frame(IconAnimation* instance) {
instance->frame = (instance->frame + 1) % instance->icon->frame_count;
}
void icon_animation_timer_callback(void* context) {
furi_assert(context);
IconAnimation* instance = context;
if(!instance->animating) return;
icon_animation_next_frame(instance);
if(instance->callback) {
instance->callback(instance, instance->callback_context);
}
}
uint8_t icon_animation_get_width(IconAnimation* instance) {
furi_assert(instance);
return instance->icon->width;
@@ -45,33 +58,26 @@ uint8_t icon_animation_get_height(IconAnimation* instance) {
return instance->icon->height;
}
bool icon_animation_is_animated(IconAnimation* instance) {
furi_assert(instance);
return instance->icon->frame_count > 1;
}
bool icon_animation_is_animating(IconAnimation* instance) {
furi_assert(instance);
return instance->tick > 0;
}
void icon_animation_start(IconAnimation* instance) {
furi_assert(instance);
instance->tick = osKernelGetTickCount();
if(!instance->animating) {
instance->animating = true;
furi_check(
osTimerStart(instance->timer, (osKernelGetTickFreq() / instance->icon->frame_rate)) ==
osOK);
}
}
void icon_animation_stop(IconAnimation* instance) {
furi_assert(instance);
instance->tick = 0;
instance->frame = 0;
}
uint8_t icon_animation_get_current_frame(IconAnimation* instance) {
furi_assert(instance);
return instance->frame;
if(instance->animating) {
instance->animating = false;
furi_check(osTimerStop(instance->timer) == osOK);
instance->frame = 0;
}
}
bool icon_animation_is_last_frame(IconAnimation* instance) {
furi_assert(instance);
return instance->icon->frame_count - instance->frame <= 1;
}
}

View File

@@ -11,54 +11,41 @@ extern "C" {
typedef struct IconAnimation IconAnimation;
/*
* Allocate icon animation instance with const icon data.
typedef void (*IconAnimationCallback)(IconAnimation* instance, void* context);
/** Allocate icon animation instance with const icon data.
* always returns Icon or stops system if not enough memory
*/
IconAnimation* icon_animation_alloc(const Icon* icon);
/*
* Release icon animation instance
/** Release icon animation instance
*/
void icon_animation_free(IconAnimation* instance);
/*
* Get icon animation width
/** Get icon animation width
*/
void icon_animation_set_update_callback(
IconAnimation* instance,
IconAnimationCallback callback,
void* context);
/** Get icon animation width
*/
uint8_t icon_animation_get_width(IconAnimation* instance);
/*
* Get icon animation height
/** Get icon animation height
*/
uint8_t icon_animation_get_height(IconAnimation* instance);
/*
* Check if icon is animated
*/
bool icon_animation_is_animated(IconAnimation* instance);
/*
* Check if icon animation is active
*/
bool icon_animation_is_animating(IconAnimation* instance);
/*
* Start icon animation
/** Start icon animation
*/
void icon_animation_start(IconAnimation* instance);
/*
* Stop icon animation
/** Stop icon animation
*/
void icon_animation_stop(IconAnimation* instance);
/*
* Get current frame
*/
uint8_t icon_animation_get_current_frame(IconAnimation* instance);
/*
* Returns true if current frame is a last one
/** Returns true if current frame is a last one
*/
bool icon_animation_is_last_frame(IconAnimation* instance);

View File

@@ -2,20 +2,22 @@
#include "icon_animation.h"
#include <stdint.h>
#include <furi.h>
struct IconAnimation {
const Icon* icon;
uint8_t frame;
uint32_t tick;
bool animating;
osTimerId_t timer;
IconAnimationCallback callback;
void* callback_context;
};
/*
* Get pointer to current frame data
*/
/** Get pointer to current frame data */
const uint8_t* icon_animation_get_data(IconAnimation* instance);
/*
* Advance to next frame
*/
/** Advance to next frame */
void icon_animation_next_frame(IconAnimation* instance);
/** IconAnimation timer callback */
void icon_animation_timer_callback(void* context);

54
applications/gui/modules/menu.c Executable file → Normal file
View File

@@ -20,7 +20,7 @@ ARRAY_DEF(MenuItemArray, MenuItem, M_POD_OPLIST);
typedef struct {
MenuItemArray_t items;
uint8_t position;
size_t position;
} MenuModel;
static void menu_process_up(Menu* menu);
@@ -32,7 +32,7 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
canvas_clear(canvas);
uint8_t position = model->position;
size_t position = model->position;
size_t items_count = MenuItemArray_size(model->items);
if(items_count) {
MenuItem* item;
@@ -43,7 +43,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position);
if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 3, item->icon);
icon_animation_stop(item->icon);
}
canvas_draw_str(canvas, 22, 14, item->label);
// Second line main
@@ -52,7 +51,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position);
if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 25, item->icon);
icon_animation_start(item->icon);
}
canvas_draw_str(canvas, 22, 36, item->label);
// Third line
@@ -61,7 +59,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position);
if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 47, item->icon);
icon_animation_stop(item->icon);
}
canvas_draw_str(canvas, 22, 58, item->label);
// Frame and scrollbar
@@ -93,6 +90,30 @@ static bool menu_input_callback(InputEvent* event, void* context) {
return consumed;
}
static void menu_enter(void* context) {
Menu* menu = context;
with_view_model(
menu->view, (MenuModel * model) {
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_start(item->icon);
}
return false;
});
}
static void menu_exit(void* context) {
Menu* menu = context;
with_view_model(
menu->view, (MenuModel * model) {
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
}
return false;
});
}
Menu* menu_alloc() {
Menu* menu = furi_alloc(sizeof(Menu));
menu->view = view_alloc(menu->view);
@@ -100,6 +121,8 @@ Menu* menu_alloc() {
view_allocate_model(menu->view, ViewModelTypeLocking, sizeof(MenuModel));
view_set_draw_callback(menu->view, menu_draw_callback);
view_set_input_callback(menu->view, menu_input_callback);
view_set_enter_callback(menu->view, menu_enter);
view_set_exit_callback(menu->view, menu_exit);
with_view_model(
menu->view, (MenuModel * model) {
@@ -143,6 +166,7 @@ void menu_add_item(
item = MenuItemArray_push_new(model->items);
item->label = label;
item->icon = icon;
view_tie_icon_animation(menu->view, item->icon);
item->index = index;
item->callback = callback;
item->callback_context = context;
@@ -175,11 +199,21 @@ void menu_set_selected_item(Menu* menu, uint32_t index) {
static void menu_process_up(Menu* menu) {
with_view_model(
menu->view, (MenuModel * model) {
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
}
if(model->position > 0) {
model->position--;
} else {
model->position = MenuItemArray_size(model->items) - 1;
}
item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_start(item->icon);
}
return true;
});
}
@@ -187,11 +221,21 @@ static void menu_process_up(Menu* menu) {
static void menu_process_down(Menu* menu) {
with_view_model(
menu->view, (MenuModel * model) {
MenuItem* item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_stop(item->icon);
}
if(model->position < MenuItemArray_size(model->items) - 1) {
model->position++;
} else {
model->position = 0;
}
item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_start(item->icon);
}
return true;
});
}

View File

@@ -12,6 +12,11 @@ void view_free(View* view) {
free(view);
}
void view_tie_icon_animation(View* view, IconAnimation* icon_animation) {
furi_assert(view);
icon_animation_set_update_callback(icon_animation, view_icon_animation_callback, view);
}
void view_set_draw_callback(View* view, ViewDrawCallback callback) {
furi_assert(view);
furi_assert(view->draw_callback == NULL);
@@ -120,6 +125,14 @@ void view_commit_model(View* view, bool update) {
}
}
void view_icon_animation_callback(IconAnimation* instance, void* context) {
furi_assert(context);
View* view = context;
if(view->update_callback) {
view->update_callback(view, view->update_callback_context);
}
}
void view_unlock_model(View* view) {
furi_assert(view);
if(view->model_type == ViewModelTypeLocking) {

View File

@@ -1,6 +1,8 @@
#pragma once
#include <input/input.h>
#include "icon_animation.h"
#include "canvas.h"
#include <stddef.h>
@@ -10,9 +12,10 @@
extern "C" {
#endif
/* Hides drawing view_port */
/** Hides drawing view_port */
#define VIEW_NONE 0xFFFFFFFF
/* Ignore navigation event */
/** Ignore navigation event */
#define VIEW_IGNORE 0xFFFFFFFE
typedef enum {
@@ -20,17 +23,17 @@ typedef enum {
ViewOrientationVertical,
} ViewOrientation;
/* View, anonymous type */
/** View, anonymous type */
typedef struct View View;
/* View Draw callback
/** View Draw callback
* @param canvas, pointer to canvas
* @param view_model, pointer to context
* @warning called from GUI thread
*/
typedef void (*ViewDrawCallback)(Canvas* canvas, void* model);
/* View Input callback
/** View Input callback
* @param event, pointer to input event data
* @param context, pointer to context
* @return true if event handled, false if event ignored
@@ -38,27 +41,27 @@ typedef void (*ViewDrawCallback)(Canvas* canvas, void* model);
*/
typedef bool (*ViewInputCallback)(InputEvent* event, void* context);
/* View Custom callback
/** View Custom callback
* @param event, number of custom event
* @param context, pointer to context
* @return true if event handled, false if event ignored
*/
typedef bool (*ViewCustomCallback)(uint32_t event, void* context);
/* View navigation callback
/** View navigation callback
* @param context, pointer to context
* @return next view id
* @warning called from GUI thread
*/
typedef uint32_t (*ViewNavigationCallback)(void* context);
/* View callback
/** View callback
* @param context, pointer to context
* @warning called from GUI thread
*/
typedef void (*ViewCallback)(void* context);
/* View Update Callback
/** View Update Callback
* Called upon model change, need to be propagated to GUI throw ViewPort update
* @param view, pointer to view
* @param context, pointer to context
@@ -66,7 +69,7 @@ typedef void (*ViewCallback)(void* context);
*/
typedef void (*ViewUpdateCallback)(View* view, void* context);
/* View model types */
/** View model types */
typedef enum {
/* Model is not allocated */
ViewModelTypeNone,
@@ -80,97 +83,103 @@ typedef enum {
ViewModelTypeLocking,
} ViewModelType;
/* Allocate and init View
* @return pointer to View
/** Allocate and init View
* @return View instance
*/
View* view_alloc();
/* Free View
* @param pointer to View
/** Free View
* @param View instance
*/
void view_free(View* view);
/* Set View Draw callback
* @param view, pointer to View
/** Tie IconAnimation with View
* @param view, View instance
* @param icon_animation, IconAnimation instance
*/
void view_tie_icon_animation(View* view, IconAnimation* icon_animation);
/** Set View Draw callback
* @param view, View instance
* @param callback, draw callback
*/
void view_set_draw_callback(View* view, ViewDrawCallback callback);
/* Set View Input callback
* @param view, pointer to View
/** Set View Input callback
* @param view, View instance
* @param callback, input callback
*/
void view_set_input_callback(View* view, ViewInputCallback callback);
/* Set View Custom callback
* @param view, pointer to View
/** Set View Custom callback
* @param view, View instance
* @param callback, input callback
*/
void view_set_custom_callback(View* view, ViewCustomCallback callback);
/* Set Navigation Previous callback
* @param view, pointer to View
/** Set Navigation Previous callback
* @param view, View instance
* @param callback, input callback
*/
void view_set_previous_callback(View* view, ViewNavigationCallback callback);
/* Set Enter callback
* @param view, pointer to View
/** Set Enter callback
* @param view, View instance
* @param callback, callback
*/
void view_set_enter_callback(View* view, ViewCallback callback);
/* Set Exit callback
* @param view, pointer to View
/** Set Exit callback
* @param view, View instance
* @param callback, callback
*/
void view_set_exit_callback(View* view, ViewCallback callback);
/* Set Update callback
* @param view, pointer to View
/** Set Update callback
* @param view, View instance
* @param callback, callback
*/
void view_set_update_callback(View* view, ViewUpdateCallback callback);
/* Set View Draw callback
* @param view, pointer to View
/** Set View Draw callback
* @param view, View instance
* @param context, context for callbacks
*/
void view_set_update_callback_context(View* view, void* context);
/* Set View Draw callback
* @param view, pointer to View
/** Set View Draw callback
* @param view, View instance
* @param context, context for callbacks
*/
void view_set_context(View* view, void* context);
/* Set View Orientation
* @param view, pointer to View
/** Set View Orientation
* @param view, View instance
* @param orientation, either vertical or horizontal
*/
void view_set_orientation(View* view, ViewOrientation orientation);
/* Allocate view model.
* @param view, pointer to View
/** Allocate view model.
* @param view, View instance
* @param type, View Model Type
* @param size, size
*/
void view_allocate_model(View* view, ViewModelType type, size_t size);
/* Free view model data memory.
* @param view, pointer to View
/** Free view model data memory.
* @param view, View instance
*/
void view_free_model(View* view);
/* Get view model data
* @param view, pointer to View
/** Get view model data
* @param view, View instance
* @return pointer to model data
* @warning Don't forget to commit model changes
*/
void* view_get_model(View* view);
/* Commit view model
* @param view, pointer to View
/** Commit view model
* @param view, View instance
* @param update, true if you want to emit view update, false otherwise
*/
void view_commit_model(View* view, bool update);
@@ -187,7 +196,7 @@ void view_commit_model(View* view, bool update);
view_commit_model(view, update); \
}
#else
/*
/**
* With clause for view model
* @param view, View instance pointer
* @param function_body a (){} lambda declaration, executed within you parent function context

View File

@@ -26,6 +26,9 @@ struct View {
void* context;
};
/* IconAnimation tie callback */
void view_icon_animation_callback(IconAnimation* instance, void* context);
/* Unlock model */
void view_unlock_model(View* view);

View File

@@ -14,48 +14,41 @@ typedef enum {
ViewPortOrientationVertical,
} ViewPortOrientation;
/*
* ViewPort Draw callback
/** ViewPort Draw callback
* @warning called from GUI thread
*/
typedef void (*ViewPortDrawCallback)(Canvas* canvas, void* context);
/*
* ViewPort Input callback
/** ViewPort Input callback
* @warning called from GUI thread
*/
typedef void (*ViewPortInputCallback)(InputEvent* event, void* context);
/*
* ViewPort allocator
/** ViewPort allocator
* always returns view_port or stops system if not enough memory.
*/
ViewPort* view_port_alloc();
/*
* ViewPort deallocator
/** ViewPort deallocator
* Ensure that view_port was unregistered in GUI system before use.
*/
void view_port_free(ViewPort* view_port);
/*
* Set view_port width.
/** Set view_port width.
* Will be used to limit canvas drawing area and autolayout feature.
* @param width - wanted width, 0 - auto.
*/
void view_port_set_width(ViewPort* view_port, uint8_t width);
uint8_t view_port_get_width(ViewPort* view_port);
/*
* Set view_port height.
/** Set view_port height.
* Will be used to limit canvas drawing area and autolayout feature.
* @param height - wanted height, 0 - auto.
*/
void view_port_set_height(ViewPort* view_port, uint8_t height);
uint8_t view_port_get_height(ViewPort* view_port);
/*
* Enable or disable view_port rendering.
/** Enable or disable view_port rendering.
* @param view_port - ViewPort instance
* @param enabled
* @warning automatically dispatches update event
@@ -63,8 +56,7 @@ uint8_t view_port_get_height(ViewPort* view_port);
void view_port_enabled_set(ViewPort* view_port, bool enabled);
bool view_port_is_enabled(ViewPort* view_port);
/*
* ViewPort event callbacks
/** ViewPort event callbacks
* @param callback - appropriate callback function
* @param context - context to pass to callback
*/
@@ -74,14 +66,12 @@ void view_port_input_callback_set(
ViewPortInputCallback callback,
void* context);
/*
* Emit update signal to GUI system.
/** Emit update signal to GUI system.
* Rendering will happen later after GUI system process signal.
*/
void view_port_update(ViewPort* view_port);
/*
* Set ViewPort orientation.
/** Set ViewPort orientation.
* @param orientation, display orientation, horizontal or vertical.
*/
void view_port_set_orientation(ViewPort* view_port, ViewPortOrientation orientation);