mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-25 14:22:27 +03:00
GUI: status bar rendering. Power: battery indicator. (#207)
* Menu: animation. Irukagotchi: idle image. * Power: battery, usb activity widget * Power: tune battery max voltage and clamp overshoot * get initial charge state Co-authored-by: Aleksandr Kutuzov <aku@plooks.com> Co-authored-by: aanper <mail@s3f.ru>
This commit is contained in:
parent
8aeafd8179
commit
0af239ebc0
@ -2,6 +2,7 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
#include "applications.h"
|
#include "applications.h"
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriApp* handler;
|
FuriApp* handler;
|
||||||
@ -87,7 +88,9 @@ void app_loader(void* p) {
|
|||||||
ctx->app = &FLIPPER_APPS[i];
|
ctx->app = &FLIPPER_APPS[i];
|
||||||
|
|
||||||
menu_item_add(
|
menu_item_add(
|
||||||
menu, menu_item_alloc_function(FLIPPER_APPS[i].name, NULL, handle_menu, ctx));
|
menu,
|
||||||
|
menu_item_alloc_function(
|
||||||
|
FLIPPER_APPS[i].name, assets_icons_get(A_Infrared_14), handle_menu, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -31,6 +31,7 @@ void cc1101_workaround(void* p);
|
|||||||
void lf_rfid_workaround(void* p);
|
void lf_rfid_workaround(void* p);
|
||||||
void nfc_task(void* p);
|
void nfc_task(void* p);
|
||||||
void irukagotchi_task(void* p);
|
void irukagotchi_task(void* p);
|
||||||
|
void power_task(void* p);
|
||||||
|
|
||||||
const FlipperStartupApp FLIPPER_STARTUP[] = {
|
const FlipperStartupApp FLIPPER_STARTUP[] = {
|
||||||
#ifdef APP_DISPLAY
|
#ifdef APP_DISPLAY
|
||||||
@ -59,6 +60,10 @@ const FlipperStartupApp FLIPPER_STARTUP[] = {
|
|||||||
{.app = irukagotchi_task, .name = "irukagotchi_task", .libs = {1, FURI_LIB{"menu_task"}}},
|
{.app = irukagotchi_task, .name = "irukagotchi_task", .libs = {1, FURI_LIB{"menu_task"}}},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef APP_POWER
|
||||||
|
{.app = power_task, .name = "power_task", .libs = {1, FURI_LIB{"gui_task"}}},
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef APP_CC1101
|
#ifdef APP_CC1101
|
||||||
{.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
|
{.app = cc1101_workaround, .name = "cc1101 workaround", .libs = {1, FURI_LIB{"gui_task"}}},
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,6 +10,7 @@ APP_RELEASE ?= 0
|
|||||||
ifeq ($(APP_RELEASE), 1)
|
ifeq ($(APP_RELEASE), 1)
|
||||||
APP_MENU = 1
|
APP_MENU = 1
|
||||||
APP_NFC = 1
|
APP_NFC = 1
|
||||||
|
APP_POWER = 1
|
||||||
BUILD_IRDA = 1
|
BUILD_IRDA = 1
|
||||||
APP_IRUKAGOTCHI = 1
|
APP_IRUKAGOTCHI = 1
|
||||||
BUILD_EXAMPLE_BLINK = 1
|
BUILD_EXAMPLE_BLINK = 1
|
||||||
@ -34,6 +35,13 @@ CFLAGS += -DAPP_IRUKAGOTCHI
|
|||||||
C_SOURCES += $(wildcard $(APP_DIR)/irukagotchi/*.c)
|
C_SOURCES += $(wildcard $(APP_DIR)/irukagotchi/*.c)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
APP_POWER ?= 0
|
||||||
|
ifeq ($(APP_POWER), 1)
|
||||||
|
APP_GUI = 1
|
||||||
|
CFLAGS += -DAPP_POWER
|
||||||
|
C_SOURCES += $(wildcard $(APP_DIR)/power/*.c)
|
||||||
|
endif
|
||||||
|
|
||||||
APP_MENU ?= 0
|
APP_MENU ?= 0
|
||||||
ifeq ($(APP_MENU), 1)
|
ifeq ($(APP_MENU), 1)
|
||||||
CFLAGS += -DAPP_MENU
|
CFLAGS += -DAPP_MENU
|
||||||
|
@ -64,6 +64,12 @@ void canvas_api_free(CanvasApi* api) {
|
|||||||
free(api);
|
free(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void canvas_reset(CanvasApi* api) {
|
||||||
|
assert(api);
|
||||||
|
canvas_color_set(api, ColorBlack);
|
||||||
|
canvas_font_set(api, FontSecondary);
|
||||||
|
}
|
||||||
|
|
||||||
void canvas_commit(CanvasApi* api) {
|
void canvas_commit(CanvasApi* api) {
|
||||||
furi_assert(api);
|
furi_assert(api);
|
||||||
Canvas* canvas = (Canvas*)api;
|
Canvas* canvas = (Canvas*)api;
|
||||||
@ -144,23 +150,33 @@ void canvas_icon_draw(CanvasApi* api, uint8_t x, uint8_t y, Icon* icon) {
|
|||||||
void canvas_dot_draw(CanvasApi* api, uint8_t x, uint8_t y) {
|
void canvas_dot_draw(CanvasApi* api, uint8_t x, uint8_t y) {
|
||||||
furi_assert(api);
|
furi_assert(api);
|
||||||
Canvas* canvas = (Canvas*)api;
|
Canvas* canvas = (Canvas*)api;
|
||||||
|
x += canvas->offset_x;
|
||||||
|
y += canvas->offset_y;
|
||||||
u8g2_DrawPixel(&canvas->fb, x, y);
|
u8g2_DrawPixel(&canvas->fb, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void canvas_box_draw(CanvasApi* api, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
void canvas_box_draw(CanvasApi* api, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
||||||
furi_assert(api);
|
furi_assert(api);
|
||||||
Canvas* canvas = (Canvas*)api;
|
Canvas* canvas = (Canvas*)api;
|
||||||
|
x += canvas->offset_x;
|
||||||
|
y += canvas->offset_y;
|
||||||
u8g2_DrawBox(&canvas->fb, x, y, width, height);
|
u8g2_DrawBox(&canvas->fb, x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void canvas_draw_frame(CanvasApi* api, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
void canvas_draw_frame(CanvasApi* api, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
||||||
furi_assert(api);
|
furi_assert(api);
|
||||||
Canvas* canvas = (Canvas*)api;
|
Canvas* canvas = (Canvas*)api;
|
||||||
|
x += canvas->offset_x;
|
||||||
|
y += canvas->offset_y;
|
||||||
u8g2_DrawFrame(&canvas->fb, x, y, width, height);
|
u8g2_DrawFrame(&canvas->fb, x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void canvas_draw_line(CanvasApi* api, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
|
void canvas_draw_line(CanvasApi* api, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
|
||||||
furi_assert(api);
|
furi_assert(api);
|
||||||
Canvas* canvas = (Canvas*)api;
|
Canvas* canvas = (Canvas*)api;
|
||||||
|
x1 += canvas->offset_x;
|
||||||
|
y1 += canvas->offset_y;
|
||||||
|
x2 += canvas->offset_x;
|
||||||
|
y2 += canvas->offset_y;
|
||||||
u8g2_DrawLine(&canvas->fb, x1, y1, x2, y2);
|
u8g2_DrawLine(&canvas->fb, x1, y1, x2, y2);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ CanvasApi* canvas_api_init();
|
|||||||
|
|
||||||
void canvas_api_free(CanvasApi* api);
|
void canvas_api_free(CanvasApi* api);
|
||||||
|
|
||||||
|
void canvas_reset(CanvasApi* api);
|
||||||
|
|
||||||
void canvas_commit(CanvasApi* api);
|
void canvas_commit(CanvasApi* api);
|
||||||
|
|
||||||
void canvas_frame_set(
|
void canvas_frame_set(
|
||||||
|
@ -41,7 +41,7 @@ void gui_update(Gui* gui) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool gui_redraw_fs(Gui* gui) {
|
bool gui_redraw_fs(Gui* gui) {
|
||||||
canvas_frame_set(gui->canvas_api, 0, 0, 128, 64);
|
canvas_frame_set(gui->canvas_api, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
|
||||||
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerFullscreen]);
|
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerFullscreen]);
|
||||||
if(widget) {
|
if(widget) {
|
||||||
widget_draw(widget, gui->canvas_api);
|
widget_draw(widget, gui->canvas_api);
|
||||||
@ -51,18 +51,48 @@ bool gui_redraw_fs(Gui* gui) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gui_redraw_status_bar(Gui* gui) {
|
void gui_redraw_status_bar(Gui* gui) {
|
||||||
canvas_frame_set(gui->canvas_api, 0, 0, 128, 64);
|
WidgetArray_it_t it;
|
||||||
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerStatusBar]);
|
uint8_t x;
|
||||||
if(widget) {
|
uint8_t x_used = 0;
|
||||||
|
uint8_t width;
|
||||||
|
Widget* widget;
|
||||||
|
// Right side
|
||||||
|
x = 128;
|
||||||
|
WidgetArray_it(it, gui->layers[GuiLayerStatusBarRight]);
|
||||||
|
while(!WidgetArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) {
|
||||||
|
// Render widget;
|
||||||
|
widget = *WidgetArray_ref(it);
|
||||||
|
if(widget_is_enabled(widget)) {
|
||||||
|
width = widget_get_width(widget);
|
||||||
|
if(!width) width = 8;
|
||||||
|
x_used += width;
|
||||||
|
x -= width;
|
||||||
|
canvas_frame_set(gui->canvas_api, x, GUI_STATUS_BAR_Y, width, GUI_STATUS_BAR_HEIGHT);
|
||||||
widget_draw(widget, gui->canvas_api);
|
widget_draw(widget, gui->canvas_api);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
WidgetArray_next(it);
|
||||||
|
}
|
||||||
|
// Left side
|
||||||
|
x = 0;
|
||||||
|
WidgetArray_it(it, gui->layers[GuiLayerStatusBarLeft]);
|
||||||
|
while(!WidgetArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) {
|
||||||
|
// Render widget;
|
||||||
|
widget = *WidgetArray_ref(it);
|
||||||
|
if(widget_is_enabled(widget)) {
|
||||||
|
width = widget_get_width(widget);
|
||||||
|
if(!width) width = 8;
|
||||||
|
x_used += width;
|
||||||
|
canvas_frame_set(gui->canvas_api, x, GUI_STATUS_BAR_Y, width, GUI_STATUS_BAR_HEIGHT);
|
||||||
|
widget_draw(widget, gui->canvas_api);
|
||||||
|
x += width;
|
||||||
|
}
|
||||||
|
WidgetArray_next(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gui_redraw_normal(Gui* gui) {
|
bool gui_redraw_normal(Gui* gui) {
|
||||||
canvas_frame_set(gui->canvas_api, 0, 9, 128, 55);
|
canvas_frame_set(gui->canvas_api, GUI_MAIN_X, GUI_MAIN_Y, GUI_MAIN_WIDTH, GUI_MAIN_HEIGHT);
|
||||||
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerMain]);
|
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerMain]);
|
||||||
if(widget) {
|
if(widget) {
|
||||||
widget_draw(widget, gui->canvas_api);
|
widget_draw(widget, gui->canvas_api);
|
||||||
@ -72,7 +102,7 @@ bool gui_redraw_normal(Gui* gui) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool gui_redraw_none(Gui* gui) {
|
bool gui_redraw_none(Gui* gui) {
|
||||||
canvas_frame_set(gui->canvas_api, 0, 9, 118, 44);
|
canvas_frame_set(gui->canvas_api, GUI_MAIN_X, GUI_MAIN_Y, GUI_MAIN_WIDTH, GUI_MAIN_HEIGHT);
|
||||||
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerNone]);
|
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerNone]);
|
||||||
if(widget) {
|
if(widget) {
|
||||||
widget_draw(widget, gui->canvas_api);
|
widget_draw(widget, gui->canvas_api);
|
||||||
@ -86,6 +116,8 @@ void gui_redraw(Gui* gui) {
|
|||||||
furi_assert(gui);
|
furi_assert(gui);
|
||||||
gui_lock(gui);
|
gui_lock(gui);
|
||||||
|
|
||||||
|
canvas_reset(gui->canvas_api);
|
||||||
|
|
||||||
if(!gui_redraw_fs(gui)) {
|
if(!gui_redraw_fs(gui)) {
|
||||||
if(!gui_redraw_normal(gui)) {
|
if(!gui_redraw_normal(gui)) {
|
||||||
gui_redraw_none(gui);
|
gui_redraw_none(gui);
|
||||||
|
@ -3,10 +3,24 @@
|
|||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
|
|
||||||
|
#define GUI_DISPLAY_WIDTH 128
|
||||||
|
#define GUI_DISPLAY_HEIGHT 64
|
||||||
|
|
||||||
|
#define GUI_STATUS_BAR_X 0
|
||||||
|
#define GUI_STATUS_BAR_Y 0
|
||||||
|
#define GUI_STATUS_BAR_WIDTH GUI_DISPLAY_WIDTH
|
||||||
|
#define GUI_STATUS_BAR_HEIGHT 8
|
||||||
|
|
||||||
|
#define GUI_MAIN_X 0
|
||||||
|
#define GUI_MAIN_Y 9
|
||||||
|
#define GUI_MAIN_WIDTH GUI_DISPLAY_WIDTH
|
||||||
|
#define GUI_MAIN_HEIGHT (GUI_DISPLAY_HEIGHT - GUI_MAIN_Y)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GuiLayerNone, /* Special layer for internal use only */
|
GuiLayerNone, /* Special layer for internal use only */
|
||||||
|
|
||||||
GuiLayerStatusBar, /* Status bar widget layer */
|
GuiLayerStatusBarLeft, /* Status bar left-side widget layer, auto-layout */
|
||||||
|
GuiLayerStatusBarRight, /* Status bar right-side widget layer, auto-layout */
|
||||||
GuiLayerMain, /* Main widget layer, status bar is shown */
|
GuiLayerMain, /* Main widget layer, status bar is shown */
|
||||||
GuiLayerFullscreen, /* Fullscreen widget layer */
|
GuiLayerFullscreen, /* Fullscreen widget layer */
|
||||||
|
|
||||||
|
@ -6,9 +6,20 @@
|
|||||||
|
|
||||||
struct GuiEvent {
|
struct GuiEvent {
|
||||||
PubSub* input_event_record;
|
PubSub* input_event_record;
|
||||||
|
osTimerId_t timer;
|
||||||
osMessageQueueId_t mqueue;
|
osMessageQueueId_t mqueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void gui_event_timer_callback(void* arg) {
|
||||||
|
assert(arg);
|
||||||
|
GuiEvent* gui_event = arg;
|
||||||
|
|
||||||
|
GuiMessage message;
|
||||||
|
message.type = GuiMessageTypeRedraw;
|
||||||
|
|
||||||
|
osMessageQueuePut(gui_event->mqueue, &message, 0, osWaitForever);
|
||||||
|
}
|
||||||
|
|
||||||
void gui_event_input_events_callback(const void* value, void* ctx) {
|
void gui_event_input_events_callback(const void* value, void* ctx) {
|
||||||
furi_assert(value);
|
furi_assert(value);
|
||||||
furi_assert(ctx);
|
furi_assert(ctx);
|
||||||
@ -29,6 +40,10 @@ GuiEvent* gui_event_alloc() {
|
|||||||
gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GuiMessage), NULL);
|
gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GuiMessage), NULL);
|
||||||
furi_check(gui_event->mqueue);
|
furi_check(gui_event->mqueue);
|
||||||
|
|
||||||
|
gui_event->timer = osTimerNew(gui_event_timer_callback, osTimerPeriodic, gui_event, NULL);
|
||||||
|
assert(gui_event->timer);
|
||||||
|
osTimerStart(gui_event->timer, 1000 / 10);
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
gui_event->input_event_record = furi_open("input_events");
|
gui_event->input_event_record = furi_open("input_events");
|
||||||
furi_check(gui_event->input_event_record != NULL);
|
furi_check(gui_event->input_event_record != NULL);
|
||||||
|
@ -10,15 +10,6 @@
|
|||||||
|
|
||||||
// TODO add mutex to widget ops
|
// TODO add mutex to widget ops
|
||||||
|
|
||||||
struct Widget {
|
|
||||||
Gui* gui;
|
|
||||||
bool is_enabled;
|
|
||||||
WidgetDrawCallback draw_callback;
|
|
||||||
void* draw_callback_context;
|
|
||||||
WidgetInputCallback input_callback;
|
|
||||||
void* input_callback_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
Widget* widget_alloc(WidgetDrawCallback callback, void* callback_context) {
|
Widget* widget_alloc(WidgetDrawCallback callback, void* callback_context) {
|
||||||
Widget* widget = furi_alloc(sizeof(Widget));
|
Widget* widget = furi_alloc(sizeof(Widget));
|
||||||
widget->is_enabled = true;
|
widget->is_enabled = true;
|
||||||
@ -31,6 +22,26 @@ void widget_free(Widget* widget) {
|
|||||||
free(widget);
|
free(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void widget_set_width(Widget* widget, uint8_t width) {
|
||||||
|
assert(widget);
|
||||||
|
widget->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t widget_get_width(Widget* widget) {
|
||||||
|
assert(widget);
|
||||||
|
return widget->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void widget_set_height(Widget* widget, uint8_t height) {
|
||||||
|
assert(widget);
|
||||||
|
widget->height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t widget_get_height(Widget* widget) {
|
||||||
|
assert(widget);
|
||||||
|
return widget->height;
|
||||||
|
}
|
||||||
|
|
||||||
void widget_enabled_set(Widget* widget, bool enabled) {
|
void widget_enabled_set(Widget* widget, bool enabled) {
|
||||||
furi_assert(widget);
|
furi_assert(widget);
|
||||||
if(widget->is_enabled != enabled) {
|
if(widget->is_enabled != enabled) {
|
||||||
@ -80,7 +91,9 @@ void widget_draw(Widget* widget, CanvasApi* canvas_api) {
|
|||||||
void widget_input(Widget* widget, InputEvent* event) {
|
void widget_input(Widget* widget, InputEvent* event) {
|
||||||
furi_assert(widget);
|
furi_assert(widget);
|
||||||
furi_assert(event);
|
furi_assert(event);
|
||||||
|
|
||||||
furi_check(widget->gui);
|
furi_check(widget->gui);
|
||||||
if(widget->input_callback) widget->input_callback(event, widget->input_callback_context);
|
|
||||||
|
if(widget->input_callback) {
|
||||||
|
widget->input_callback(event, widget->input_callback_context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,51 @@ typedef struct Widget Widget;
|
|||||||
typedef void (*WidgetDrawCallback)(CanvasApi* api, void* context);
|
typedef void (*WidgetDrawCallback)(CanvasApi* api, void* context);
|
||||||
typedef void (*WidgetInputCallback)(InputEvent* event, void* context);
|
typedef void (*WidgetInputCallback)(InputEvent* event, void* context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widget allocator
|
||||||
|
* always returns widget or stops system if not enough memory.
|
||||||
|
*/
|
||||||
Widget* widget_alloc();
|
Widget* widget_alloc();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widget deallocator
|
||||||
|
* Ensure that widget was unregistered in GUI system before use.
|
||||||
|
*/
|
||||||
void widget_free(Widget* widget);
|
void widget_free(Widget* widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set widget width.
|
||||||
|
* Will be used to limit canvas drawing area and autolayout feature.
|
||||||
|
* @param width - wanted width, 0 - auto.
|
||||||
|
*/
|
||||||
|
void widget_set_width(Widget* widget, uint8_t width);
|
||||||
|
uint8_t widget_get_width(Widget* widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set widget height.
|
||||||
|
* Will be used to limit canvas drawing area and autolayout feature.
|
||||||
|
* @param height - wanted height, 0 - auto.
|
||||||
|
*/
|
||||||
|
void widget_set_height(Widget* widget, uint8_t height);
|
||||||
|
uint8_t widget_get_height(Widget* widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable or disable widget rendering.
|
||||||
|
* @param enabled.
|
||||||
|
*/
|
||||||
void widget_enabled_set(Widget* widget, bool enabled);
|
void widget_enabled_set(Widget* widget, bool enabled);
|
||||||
bool widget_is_enabled(Widget* widget);
|
bool widget_is_enabled(Widget* widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widget event callbacks
|
||||||
|
* @param callback - appropriate callback function
|
||||||
|
* @param context - context to pass to callback
|
||||||
|
*/
|
||||||
void widget_draw_callback_set(Widget* widget, WidgetDrawCallback callback, void* context);
|
void widget_draw_callback_set(Widget* widget, WidgetDrawCallback callback, void* context);
|
||||||
void widget_input_callback_set(Widget* widget, WidgetInputCallback callback, void* context);
|
void widget_input_callback_set(Widget* widget, WidgetInputCallback callback, void* context);
|
||||||
|
|
||||||
// emit update signal
|
/*
|
||||||
|
* Emit update signal to GUI system.
|
||||||
|
* Rendering will happen later after GUI system process signal.
|
||||||
|
*/
|
||||||
void widget_update(Widget* widget);
|
void widget_update(Widget* widget);
|
||||||
|
@ -2,8 +2,31 @@
|
|||||||
|
|
||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
|
|
||||||
|
struct Widget {
|
||||||
|
Gui* gui;
|
||||||
|
bool is_enabled;
|
||||||
|
uint8_t width;
|
||||||
|
uint8_t height;
|
||||||
|
WidgetDrawCallback draw_callback;
|
||||||
|
void* draw_callback_context;
|
||||||
|
WidgetInputCallback input_callback;
|
||||||
|
void* input_callback_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set GUI referenec.
|
||||||
|
* @param gui - gui instance pointer.
|
||||||
|
*/
|
||||||
void widget_gui_set(Widget* widget, Gui* gui);
|
void widget_gui_set(Widget* widget, Gui* gui);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process draw call. Calls draw callback.
|
||||||
|
* @param canvas_api - canvas to draw at.
|
||||||
|
*/
|
||||||
void widget_draw(Widget* widget, CanvasApi* canvas_api);
|
void widget_draw(Widget* widget, CanvasApi* canvas_api);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process input. Calls input callback.
|
||||||
|
* @param event - pointer to input event.
|
||||||
|
*/
|
||||||
void widget_input(Widget* widget, InputEvent* event);
|
void widget_input(Widget* widget, InputEvent* event);
|
||||||
|
@ -21,8 +21,9 @@ void irukagotchi_draw_callback(CanvasApi* canvas, void* context) {
|
|||||||
canvas->clear(canvas);
|
canvas->clear(canvas);
|
||||||
canvas->set_color(canvas, ColorBlack);
|
canvas->set_color(canvas, ColorBlack);
|
||||||
canvas->set_font(canvas, FontPrimary);
|
canvas->set_font(canvas, FontPrimary);
|
||||||
canvas->draw_icon(canvas, 10, 20, irukagotchi->icon);
|
canvas->draw_icon(canvas, 0, 0, irukagotchi->icon);
|
||||||
canvas->draw_str(canvas, 30, 32, "Irukagotchi");
|
canvas->draw_str(canvas, 80, 30, "111001");
|
||||||
|
canvas->draw_str(canvas, 80, 42, "011010");
|
||||||
}
|
}
|
||||||
|
|
||||||
void irukagotchi_input_callback(InputEvent* event, void* context) {
|
void irukagotchi_input_callback(InputEvent* event, void* context) {
|
||||||
@ -37,7 +38,7 @@ void irukagotchi_input_callback(InputEvent* event, void* context) {
|
|||||||
Irukagotchi* irukagotchi_alloc() {
|
Irukagotchi* irukagotchi_alloc() {
|
||||||
Irukagotchi* irukagotchi = furi_alloc(sizeof(Irukagotchi));
|
Irukagotchi* irukagotchi = furi_alloc(sizeof(Irukagotchi));
|
||||||
|
|
||||||
irukagotchi->icon = assets_icons_get(A_Tamagotchi_14);
|
irukagotchi->icon = assets_icons_get(I_Flipper_young_80x60);
|
||||||
icon_start_animation(irukagotchi->icon);
|
icon_start_animation(irukagotchi->icon);
|
||||||
|
|
||||||
irukagotchi->widget = widget_alloc();
|
irukagotchi->widget = widget_alloc();
|
||||||
|
@ -9,12 +9,14 @@
|
|||||||
|
|
||||||
#include "menu_event.h"
|
#include "menu_event.h"
|
||||||
#include "menu_item.h"
|
#include "menu_item.h"
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
struct Menu {
|
struct Menu {
|
||||||
MenuEvent* event;
|
MenuEvent* event;
|
||||||
|
|
||||||
// GUI
|
// GUI
|
||||||
Widget* widget;
|
Widget* widget;
|
||||||
|
Icon* icon;
|
||||||
|
|
||||||
// State
|
// State
|
||||||
MenuItem* root;
|
MenuItem* root;
|
||||||
@ -56,7 +58,8 @@ void menu_build_main(Menu* menu) {
|
|||||||
// Root point
|
// Root point
|
||||||
menu->root = menu_item_alloc_menu(NULL, NULL);
|
menu->root = menu_item_alloc_menu(NULL, NULL);
|
||||||
|
|
||||||
menu->settings = menu_item_alloc_menu("Setting", NULL);
|
Icon* icon = assets_icons_get(A_Bluetooth_14);
|
||||||
|
menu->settings = menu_item_alloc_menu("Setting", icon);
|
||||||
|
|
||||||
menu_item_add(menu, menu->settings);
|
menu_item_add(menu, menu->settings);
|
||||||
}
|
}
|
||||||
@ -103,16 +106,18 @@ void menu_widget_callback(CanvasApi* canvas, void* context) {
|
|||||||
canvas->set_font(canvas, FontPrimary);
|
canvas->set_font(canvas, FontPrimary);
|
||||||
shift_position = (1 + position + items_count - 1) % (MenuItemArray_size(*items));
|
shift_position = (1 + position + items_count - 1) % (MenuItemArray_size(*items));
|
||||||
item = *MenuItemArray_get(*items, shift_position);
|
item = *MenuItemArray_get(*items, shift_position);
|
||||||
canvas->draw_icon(canvas, 4, 24, menu_item_get_icon(item));
|
canvas->draw_icon(canvas, 4, 25, menu_item_get_icon(item));
|
||||||
canvas->draw_str(canvas, 22, 35, menu_item_get_label(item));
|
canvas->draw_str(canvas, 22, 36, menu_item_get_label(item));
|
||||||
// Third line
|
// Third line
|
||||||
canvas->set_font(canvas, FontSecondary);
|
canvas->set_font(canvas, FontSecondary);
|
||||||
shift_position = (2 + position + items_count - 1) % (MenuItemArray_size(*items));
|
shift_position = (2 + position + items_count - 1) % (MenuItemArray_size(*items));
|
||||||
item = *MenuItemArray_get(*items, shift_position);
|
item = *MenuItemArray_get(*items, shift_position);
|
||||||
canvas->draw_icon(canvas, 4, 46, menu_item_get_icon(item));
|
canvas->draw_icon(canvas, 4, 47, menu_item_get_icon(item));
|
||||||
canvas->draw_str(canvas, 22, 57, menu_item_get_label(item));
|
canvas->draw_str(canvas, 22, 58, menu_item_get_label(item));
|
||||||
// Frame and scrollbar
|
// Frame and scrollbar
|
||||||
elements_frame(canvas, 0, 20, 128 - 5, 22);
|
// elements_frame(canvas, 0, 0, 128 - 5, 21);
|
||||||
|
elements_frame(canvas, 0, 21, 128 - 5, 21);
|
||||||
|
// elements_frame(canvas, 0, 42, 128 - 5, 21);
|
||||||
elements_scrollbar(canvas, position, items_count);
|
elements_scrollbar(canvas, position, items_count);
|
||||||
} else {
|
} else {
|
||||||
canvas->draw_str(canvas, 2, 32, "Empty");
|
canvas->draw_str(canvas, 2, 32, "Empty");
|
||||||
@ -122,9 +127,33 @@ void menu_widget_callback(CanvasApi* canvas, void* context) {
|
|||||||
release_mutex((ValueMutex*)context, menu);
|
release_mutex((ValueMutex*)context, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void menu_set_icon(Menu* menu, Icon* icon) {
|
||||||
|
assert(menu);
|
||||||
|
|
||||||
|
if(menu->icon) {
|
||||||
|
icon_stop_animation(menu->icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->icon = icon;
|
||||||
|
|
||||||
|
if(menu->icon) {
|
||||||
|
icon_start_animation(menu->icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void menu_update(Menu* menu) {
|
void menu_update(Menu* menu) {
|
||||||
furi_assert(menu);
|
furi_assert(menu);
|
||||||
|
|
||||||
|
if(menu->current) {
|
||||||
|
size_t position = menu_item_get_position(menu->current);
|
||||||
|
MenuItemArray_t* items = menu_item_get_subitems(menu->current);
|
||||||
|
size_t items_count = MenuItemArray_size(*items);
|
||||||
|
if(items_count) {
|
||||||
|
MenuItem* item = *MenuItemArray_get(*items, position);
|
||||||
|
menu_set_icon(menu, menu_item_get_icon(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
menu_event_activity_notify(menu->event);
|
menu_event_activity_notify(menu->event);
|
||||||
widget_update(menu->widget);
|
widget_update(menu->widget);
|
||||||
}
|
}
|
||||||
|
117
applications/power/power.c
Normal file
117
applications/power/power.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include "power.h"
|
||||||
|
|
||||||
|
#include <flipper_v2.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/widget.h>
|
||||||
|
#include <assets_icons.h>
|
||||||
|
|
||||||
|
#define BATTERY_MIN_VOLTAGE 3.2f
|
||||||
|
#define BATTERY_MAX_VOLTAGE 4.0f
|
||||||
|
#define BATTERY_INIT 0xFFAACCEE
|
||||||
|
|
||||||
|
extern ADC_HandleTypeDef hadc1;
|
||||||
|
|
||||||
|
struct Power {
|
||||||
|
Icon* usb_icon;
|
||||||
|
Widget* usb_widget;
|
||||||
|
|
||||||
|
Icon* battery_icon;
|
||||||
|
Widget* battery_widget;
|
||||||
|
|
||||||
|
uint32_t charge;
|
||||||
|
};
|
||||||
|
|
||||||
|
void power_draw_usb_callback(CanvasApi* canvas, void* context) {
|
||||||
|
assert(context);
|
||||||
|
Power* power = context;
|
||||||
|
canvas->draw_icon(canvas, 0, 0, power->usb_icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_draw_battery_callback(CanvasApi* canvas, void* context) {
|
||||||
|
assert(context);
|
||||||
|
Power* power = context;
|
||||||
|
|
||||||
|
canvas->draw_icon(canvas, 0, 0, power->battery_icon);
|
||||||
|
|
||||||
|
if(power->charge != BATTERY_INIT) {
|
||||||
|
float charge = ((float)power->charge / 1000 * 2 - BATTERY_MIN_VOLTAGE) /
|
||||||
|
(BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE);
|
||||||
|
if(charge > 1) {
|
||||||
|
charge = 1;
|
||||||
|
}
|
||||||
|
canvas->draw_box(canvas, 2, 2, charge * 14, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_input_events_callback(const void* value, void* ctx) {
|
||||||
|
assert(ctx);
|
||||||
|
Power* power = ctx;
|
||||||
|
InputEvent* event = value;
|
||||||
|
|
||||||
|
if(event->input != InputCharging) return;
|
||||||
|
|
||||||
|
widget_enabled_set(power->usb_widget, event->state);
|
||||||
|
widget_update(power->usb_widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
Power* power_alloc() {
|
||||||
|
Power* power = furi_alloc(sizeof(Power));
|
||||||
|
|
||||||
|
power->usb_icon = assets_icons_get(I_USBConnected_15x8);
|
||||||
|
power->usb_widget = widget_alloc();
|
||||||
|
widget_set_width(power->usb_widget, icon_get_width(power->usb_icon));
|
||||||
|
|
||||||
|
ValueManager* input_state_manager = furi_open("input_state");
|
||||||
|
InputState input_state;
|
||||||
|
read_mutex_block(input_state_manager, &input_state, sizeof(input_state));
|
||||||
|
widget_enabled_set(power->usb_widget, input_state.charging);
|
||||||
|
|
||||||
|
widget_draw_callback_set(power->usb_widget, power_draw_usb_callback, power);
|
||||||
|
|
||||||
|
power->battery_icon = assets_icons_get(I_Battery_19x8);
|
||||||
|
power->battery_widget = widget_alloc();
|
||||||
|
widget_set_width(power->battery_widget, icon_get_width(power->battery_icon));
|
||||||
|
widget_draw_callback_set(power->battery_widget, power_draw_battery_callback, power);
|
||||||
|
|
||||||
|
PubSub* input_event_record = furi_open("input_events");
|
||||||
|
assert(input_event_record);
|
||||||
|
subscribe_pubsub(input_event_record, power_input_events_callback, power);
|
||||||
|
|
||||||
|
power->charge = BATTERY_INIT;
|
||||||
|
|
||||||
|
return power;
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_free(Power* power) {
|
||||||
|
assert(power);
|
||||||
|
free(power);
|
||||||
|
}
|
||||||
|
|
||||||
|
void power_task(void* p) {
|
||||||
|
(void)p;
|
||||||
|
Power* power = power_alloc();
|
||||||
|
|
||||||
|
FuriRecordSubscriber* gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL);
|
||||||
|
assert(gui_record);
|
||||||
|
GuiApi* gui = furi_take(gui_record);
|
||||||
|
assert(gui);
|
||||||
|
gui->add_widget(gui, power->usb_widget, GuiLayerStatusBarLeft);
|
||||||
|
gui->add_widget(gui, power->battery_widget, GuiLayerStatusBarRight);
|
||||||
|
furi_commit(gui_record);
|
||||||
|
|
||||||
|
if(!furi_create("power", power)) {
|
||||||
|
printf("[power_task] unable to create power record\n");
|
||||||
|
furiac_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
furiac_ready();
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
HAL_ADC_Start(&hadc1);
|
||||||
|
if(HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_TIMEOUT) {
|
||||||
|
power->charge = HAL_ADC_GetValue(&hadc1);
|
||||||
|
widget_update(power->battery_widget);
|
||||||
|
}
|
||||||
|
osDelay(1000);
|
||||||
|
}
|
||||||
|
}
|
3
applications/power/power.h
Normal file
3
applications/power/power.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct Power Power;
|
3
assets/icons/IrukaGotchi/Flipper_idle_76x52.png
Normal file
3
assets/icons/IrukaGotchi/Flipper_idle_76x52.png
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:526c2637560aab102f259c029eeee93cc13e5cd8bdb935acb624f1318502f286
|
||||||
|
size 652
|
3
assets/icons/IrukaGotchi/Flipper_young_80x60.png
Normal file
3
assets/icons/IrukaGotchi/Flipper_young_80x60.png
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c7d2c5da9b957635189c2ee475d7065ae714fd6fb5d6f0c83ca5fa0bcd1497f8
|
||||||
|
size 2653
|
Loading…
Reference in New Issue
Block a user