[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 271 additions and 175 deletions

View File

@ -45,7 +45,6 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
void desktop_scene_locked_on_exit(void* context) { void desktop_scene_locked_on_exit(void* context) {
Desktop* desktop = (Desktop*)context; Desktop* desktop = (Desktop*)context;
DesktopLockedView* locked_view = desktop->locked_view;
desktop_locked_reset_counter(desktop->locked_view); desktop_locked_reset_counter(desktop->locked_view);
osTimerStop(locked_view->timer); osTimerStop(desktop->locked_view->timer);
} }

View File

@ -67,6 +67,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE); desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE);
consumed = true; consumed = true;
break; break;
case DesktopMainEventOpenFavorite: case DesktopMainEventOpenFavorite:
desktop_settings_load(&desktop->settings); desktop_settings_load(&desktop->settings);
desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]); desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]);

View File

@ -20,13 +20,12 @@ void locked_view_timer_callback(void* context) {
} }
// temporary locked screen animation managment // temporary locked screen animation managment
static void static void desktop_locked_set_scene(DesktopLockedView* locked_view, const Icon* icon_data) {
desktop_scene_handler_set_scene(DesktopLockedView* locked_view, const Icon* icon_data) {
with_view_model( with_view_model(
locked_view->view, (DesktopLockedViewModel * model) { locked_view->view, (DesktopLockedViewModel * model) {
if(model->animation) icon_animation_free(model->animation); if(model->animation) icon_animation_free(model->animation);
model->animation = icon_animation_alloc(icon_data); model->animation = icon_animation_alloc(icon_data);
icon_animation_start(model->animation); view_tie_icon_animation(locked_view->view, model->animation);
return true; return true;
}); });
} }
@ -148,6 +147,25 @@ bool desktop_locked_input(InputEvent* event, void* context) {
return true; return true;
} }
void desktop_locked_enter(void* context) {
DesktopLockedView* locked_view = context;
with_view_model(
locked_view->view, (DesktopLockedViewModel * model) {
if(model->animation) icon_animation_start(model->animation);
return false;
});
}
void desktop_locked_exit(void* context) {
DesktopLockedView* locked_view = context;
with_view_model(
locked_view->view, (DesktopLockedViewModel * model) {
if(model->animation) icon_animation_stop(model->animation);
return false;
});
}
DesktopLockedView* desktop_locked_alloc() { DesktopLockedView* desktop_locked_alloc() {
DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView)); DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView));
locked_view->view = view_alloc(); locked_view->view = view_alloc();
@ -158,8 +176,10 @@ DesktopLockedView* desktop_locked_alloc() {
view_set_context(locked_view->view, locked_view); view_set_context(locked_view->view, locked_view);
view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_render); view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_render);
view_set_input_callback(locked_view->view, desktop_locked_input); view_set_input_callback(locked_view->view, desktop_locked_input);
view_set_enter_callback(locked_view->view, desktop_locked_enter);
view_set_exit_callback(locked_view->view, desktop_locked_exit);
desktop_scene_handler_set_scene(locked_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); desktop_locked_set_scene(locked_view, idle_scenes[random() % COUNT_OF(idle_scenes)]);
return locked_view; return locked_view;
} }

View File

@ -17,17 +17,18 @@ void desktop_main_set_callback(
void desktop_main_reset_hint(DesktopMainView* main_view) { void desktop_main_reset_hint(DesktopMainView* main_view) {
with_view_model( with_view_model(
main_view->view, (DesktopMainViewModel * model) { main_view->view, (DesktopMainViewModel * model) {
model->hint_timeout = 0; model->hint_expire_at = 0;
return true; return true;
}); });
} }
// temporary main screen animation managment // temporary main screen animation managment
void desktop_scene_handler_set_scene(DesktopMainView* main_view, const Icon* icon_data) { static void desktop_main_set_scene(DesktopMainView* main_view, const Icon* icon_data) {
with_view_model( with_view_model(
main_view->view, (DesktopMainViewModel * model) { main_view->view, (DesktopMainViewModel * model) {
if(model->animation) icon_animation_free(model->animation); if(model->animation) icon_animation_free(model->animation);
model->animation = icon_animation_alloc(icon_data); model->animation = icon_animation_alloc(icon_data);
icon_animation_start(model->animation); view_tie_icon_animation(main_view->view, model->animation);
return true; return true;
}); });
} }
@ -38,7 +39,6 @@ void desktop_scene_handler_switch_scene(DesktopMainView* main_view) {
if(icon_animation_is_last_frame(model->animation)) { if(icon_animation_is_last_frame(model->animation)) {
if(model->animation) icon_animation_free(model->animation); if(model->animation) icon_animation_free(model->animation);
model->animation = icon_animation_alloc(idle_scenes[model->scene_num]); model->animation = icon_animation_alloc(idle_scenes[model->scene_num]);
icon_animation_start(model->animation);
model->scene_num = random() % COUNT_OF(idle_scenes); model->scene_num = random() % COUNT_OF(idle_scenes);
} }
return true; return true;
@ -53,8 +53,7 @@ void desktop_main_render(Canvas* canvas, void* model) {
canvas_draw_icon_animation(canvas, 0, -3, m->animation); canvas_draw_icon_animation(canvas, 0, -3, m->animation);
} }
if(m->unlocked && m->hint_timeout) { if(osKernelGetTickCount() < m->hint_expire_at) {
m->hint_timeout = CLAMP(m->hint_timeout - 1, 2, 0);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_framed(canvas, 42, 30, "Unlocked"); elements_multiline_text_framed(canvas, 42, 30, "Unlocked");
} }
@ -87,6 +86,25 @@ bool desktop_main_input(InputEvent* event, void* context) {
return true; return true;
} }
void desktop_main_enter(void* context) {
DesktopMainView* main_view = context;
with_view_model(
main_view->view, (DesktopMainViewModel * model) {
if(model->animation) icon_animation_start(model->animation);
return false;
});
}
void desktop_main_exit(void* context) {
DesktopMainView* main_view = context;
with_view_model(
main_view->view, (DesktopMainViewModel * model) {
if(model->animation) icon_animation_stop(model->animation);
return false;
});
}
DesktopMainView* desktop_main_alloc() { DesktopMainView* desktop_main_alloc() {
DesktopMainView* main_view = furi_alloc(sizeof(DesktopMainView)); DesktopMainView* main_view = furi_alloc(sizeof(DesktopMainView));
main_view->view = view_alloc(); main_view->view = view_alloc();
@ -94,8 +112,10 @@ DesktopMainView* desktop_main_alloc() {
view_set_context(main_view->view, main_view); view_set_context(main_view->view, main_view);
view_set_draw_callback(main_view->view, (ViewDrawCallback)desktop_main_render); view_set_draw_callback(main_view->view, (ViewDrawCallback)desktop_main_render);
view_set_input_callback(main_view->view, desktop_main_input); view_set_input_callback(main_view->view, desktop_main_input);
view_set_enter_callback(main_view->view, desktop_main_enter);
view_set_exit_callback(main_view->view, desktop_main_exit);
desktop_scene_handler_set_scene(main_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); desktop_main_set_scene(main_view, idle_scenes[random() % COUNT_OF(idle_scenes)]);
return main_view; return main_view;
} }
@ -109,8 +129,7 @@ void desktop_main_free(DesktopMainView* main_view) {
void desktop_main_unlocked(DesktopMainView* main_view) { void desktop_main_unlocked(DesktopMainView* main_view) {
with_view_model( with_view_model(
main_view->view, (DesktopMainViewModel * model) { main_view->view, (DesktopMainViewModel * model) {
model->unlocked = true; model->hint_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
model->hint_timeout = 2;
return true; return true;
}); });
} }

View File

@ -28,8 +28,7 @@ struct DesktopMainView {
typedef struct { typedef struct {
IconAnimation* animation; IconAnimation* animation;
uint8_t scene_num; uint8_t scene_num;
uint8_t hint_timeout; uint32_t hint_expire_at;
bool unlocked;
} DesktopMainViewModel; } DesktopMainViewModel;
void desktop_main_set_callback( void desktop_main_set_callback(
@ -40,4 +39,5 @@ void desktop_main_set_callback(
View* desktop_main_get_view(DesktopMainView* main_view); View* desktop_main_get_view(DesktopMainView* main_view);
DesktopMainView* desktop_main_alloc(); DesktopMainView* desktop_main_alloc();
void desktop_main_free(DesktopMainView* main_view); void desktop_main_free(DesktopMainView* main_view);

View File

@ -7,26 +7,26 @@ IconAnimation* icon_animation_alloc(const Icon* icon) {
furi_assert(icon); furi_assert(icon);
IconAnimation* instance = furi_alloc(sizeof(IconAnimation)); IconAnimation* instance = furi_alloc(sizeof(IconAnimation));
instance->icon = icon; instance->icon = icon;
instance->timer = osTimerNew(icon_animation_timer_callback, osTimerPeriodic, instance, NULL);
return instance; return instance;
} }
void icon_animation_free(IconAnimation* instance) { void icon_animation_free(IconAnimation* instance) {
furi_assert(instance); furi_assert(instance);
furi_check(osTimerDelete(instance->timer) == osOK);
free(instance); 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); furi_assert(instance);
if(instance->tick) { instance->callback = callback;
uint32_t now = osKernelGetTickCount(); instance->callback_context = context;
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);
}
} }
const uint8_t* icon_animation_get_data(IconAnimation* instance) {
return instance->icon->frames[instance->frame]; 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; 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) { uint8_t icon_animation_get_width(IconAnimation* instance) {
furi_assert(instance); furi_assert(instance);
return instance->icon->width; return instance->icon->width;
@ -45,30 +58,23 @@ uint8_t icon_animation_get_height(IconAnimation* instance) {
return instance->icon->height; 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) { void icon_animation_start(IconAnimation* instance) {
furi_assert(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) { void icon_animation_stop(IconAnimation* instance) {
furi_assert(instance); furi_assert(instance);
instance->tick = 0; if(instance->animating) {
instance->animating = false;
furi_check(osTimerStop(instance->timer) == osOK);
instance->frame = 0; instance->frame = 0;
} }
uint8_t icon_animation_get_current_frame(IconAnimation* instance) {
furi_assert(instance);
return instance->frame;
} }
bool icon_animation_is_last_frame(IconAnimation* instance) { bool icon_animation_is_last_frame(IconAnimation* instance) {

View File

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

View File

@ -2,20 +2,22 @@
#include "icon_animation.h" #include "icon_animation.h"
#include <stdint.h> #include <furi.h>
struct IconAnimation { struct IconAnimation {
const Icon* icon; const Icon* icon;
uint8_t frame; 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); const uint8_t* icon_animation_get_data(IconAnimation* instance);
/* /** Advance to next frame */
* Advance to next frame
*/
void icon_animation_next_frame(IconAnimation* instance); 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 { typedef struct {
MenuItemArray_t items; MenuItemArray_t items;
uint8_t position; size_t position;
} MenuModel; } MenuModel;
static void menu_process_up(Menu* menu); static void menu_process_up(Menu* menu);
@ -32,7 +32,7 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
canvas_clear(canvas); canvas_clear(canvas);
uint8_t position = model->position; size_t position = model->position;
size_t items_count = MenuItemArray_size(model->items); size_t items_count = MenuItemArray_size(model->items);
if(items_count) { if(items_count) {
MenuItem* item; MenuItem* item;
@ -43,7 +43,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position); item = MenuItemArray_get(model->items, shift_position);
if(item->icon) { if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 3, item->icon); canvas_draw_icon_animation(canvas, 4, 3, item->icon);
icon_animation_stop(item->icon);
} }
canvas_draw_str(canvas, 22, 14, item->label); canvas_draw_str(canvas, 22, 14, item->label);
// Second line main // Second line main
@ -52,7 +51,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position); item = MenuItemArray_get(model->items, shift_position);
if(item->icon) { if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 25, item->icon); canvas_draw_icon_animation(canvas, 4, 25, item->icon);
icon_animation_start(item->icon);
} }
canvas_draw_str(canvas, 22, 36, item->label); canvas_draw_str(canvas, 22, 36, item->label);
// Third line // Third line
@ -61,7 +59,6 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
item = MenuItemArray_get(model->items, shift_position); item = MenuItemArray_get(model->items, shift_position);
if(item->icon) { if(item->icon) {
canvas_draw_icon_animation(canvas, 4, 47, item->icon); canvas_draw_icon_animation(canvas, 4, 47, item->icon);
icon_animation_stop(item->icon);
} }
canvas_draw_str(canvas, 22, 58, item->label); canvas_draw_str(canvas, 22, 58, item->label);
// Frame and scrollbar // Frame and scrollbar
@ -93,6 +90,30 @@ static bool menu_input_callback(InputEvent* event, void* context) {
return consumed; 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_alloc() {
Menu* menu = furi_alloc(sizeof(Menu)); Menu* menu = furi_alloc(sizeof(Menu));
menu->view = view_alloc(menu->view); menu->view = view_alloc(menu->view);
@ -100,6 +121,8 @@ Menu* menu_alloc() {
view_allocate_model(menu->view, ViewModelTypeLocking, sizeof(MenuModel)); view_allocate_model(menu->view, ViewModelTypeLocking, sizeof(MenuModel));
view_set_draw_callback(menu->view, menu_draw_callback); view_set_draw_callback(menu->view, menu_draw_callback);
view_set_input_callback(menu->view, menu_input_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( with_view_model(
menu->view, (MenuModel * model) { menu->view, (MenuModel * model) {
@ -143,6 +166,7 @@ void menu_add_item(
item = MenuItemArray_push_new(model->items); item = MenuItemArray_push_new(model->items);
item->label = label; item->label = label;
item->icon = icon; item->icon = icon;
view_tie_icon_animation(menu->view, item->icon);
item->index = index; item->index = index;
item->callback = callback; item->callback = callback;
item->callback_context = context; 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) { static void menu_process_up(Menu* menu) {
with_view_model( with_view_model(
menu->view, (MenuModel * 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) { if(model->position > 0) {
model->position--; model->position--;
} else { } else {
model->position = MenuItemArray_size(model->items) - 1; 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; return true;
}); });
} }
@ -187,11 +221,21 @@ static void menu_process_up(Menu* menu) {
static void menu_process_down(Menu* menu) { static void menu_process_down(Menu* menu) {
with_view_model( with_view_model(
menu->view, (MenuModel * 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) { if(model->position < MenuItemArray_size(model->items) - 1) {
model->position++; model->position++;
} else { } else {
model->position = 0; model->position = 0;
} }
item = MenuItemArray_get(model->items, model->position);
if(item && item->icon) {
icon_animation_start(item->icon);
}
return true; return true;
}); });
} }

View File

@ -12,6 +12,11 @@ void view_free(View* view) {
free(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) { void view_set_draw_callback(View* view, ViewDrawCallback callback) {
furi_assert(view); furi_assert(view);
furi_assert(view->draw_callback == NULL); 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) { void view_unlock_model(View* view) {
furi_assert(view); furi_assert(view);
if(view->model_type == ViewModelTypeLocking) { if(view->model_type == ViewModelTypeLocking) {

View File

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

View File

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

View File

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

38
applications/power/power_service/power.c Executable file → Normal file
View File

@ -97,23 +97,27 @@ static void power_check_charging_state(Power* power) {
} }
} }
static void power_update_info(Power* power) { static bool power_update_info(Power* power) {
PowerInfo info;
info.charge = furi_hal_power_get_pct();
info.health = furi_hal_power_get_bat_health_pct();
info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
info.capacity_full = furi_hal_power_get_battery_full_capacity();
info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
info.voltage_vbus = furi_hal_power_get_usb_voltage();
info.temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger);
info.temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge);
osMutexAcquire(power->info_mtx, osWaitForever); osMutexAcquire(power->info_mtx, osWaitForever);
PowerInfo* info = &power->info; bool need_refresh = power->info.charge != info.charge;
power->info = info;
info->charge = furi_hal_power_get_pct();
info->health = furi_hal_power_get_bat_health_pct();
info->capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
info->capacity_full = furi_hal_power_get_battery_full_capacity();
info->current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
info->current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
info->voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
info->voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
info->voltage_vbus = furi_hal_power_get_usb_voltage();
info->temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger);
info->temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge);
osMutexRelease(power->info_mtx); osMutexRelease(power->info_mtx);
return need_refresh;
} }
static void power_check_low_battery(Power* power) { static void power_check_low_battery(Power* power) {
@ -156,7 +160,7 @@ int32_t power_srv(void* p) {
while(1) { while(1) {
// Update data from gauge and charger // Update data from gauge and charger
power_update_info(power); bool need_refresh = power_update_info(power);
// Check low battery level // Check low battery level
power_check_low_battery(power); power_check_low_battery(power);
@ -168,7 +172,7 @@ int32_t power_srv(void* p) {
power_check_battery_level_change(power); power_check_battery_level_change(power);
// Update battery view port // Update battery view port
view_port_update(power->battery_view_port); if(need_refresh) view_port_update(power->battery_view_port);
osDelay(1000); osDelay(1000);
} }

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 B

View File

@ -1 +1 @@
10 1