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:
あく
2020-10-29 10:11:16 +03:00
committed by GitHub
parent 8aeafd8179
commit 0af239ebc0
17 changed files with 357 additions and 33 deletions

View File

@@ -64,6 +64,12 @@ void canvas_api_free(CanvasApi* 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) {
furi_assert(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) {
furi_assert(api);
Canvas* canvas = (Canvas*)api;
x += canvas->offset_x;
y += canvas->offset_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) {
furi_assert(api);
Canvas* canvas = (Canvas*)api;
x += canvas->offset_x;
y += canvas->offset_y;
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) {
furi_assert(api);
Canvas* canvas = (Canvas*)api;
x += canvas->offset_x;
y += canvas->offset_y;
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) {
furi_assert(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);
}

View File

@@ -4,6 +4,8 @@ CanvasApi* canvas_api_init();
void canvas_api_free(CanvasApi* api);
void canvas_reset(CanvasApi* api);
void canvas_commit(CanvasApi* api);
void canvas_frame_set(

View File

@@ -41,7 +41,7 @@ void gui_update(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]);
if(widget) {
widget_draw(widget, gui->canvas_api);
@@ -51,18 +51,48 @@ bool gui_redraw_fs(Gui* gui) {
}
}
bool gui_redraw_status_bar(Gui* gui) {
canvas_frame_set(gui->canvas_api, 0, 0, 128, 64);
Widget* widget = gui_widget_find_enabled(gui->layers[GuiLayerStatusBar]);
if(widget) {
widget_draw(widget, gui->canvas_api);
return true;
void gui_redraw_status_bar(Gui* gui) {
WidgetArray_it_t it;
uint8_t x;
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);
}
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);
}
return false;
}
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]);
if(widget) {
widget_draw(widget, gui->canvas_api);
@@ -72,7 +102,7 @@ bool gui_redraw_normal(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]);
if(widget) {
widget_draw(widget, gui->canvas_api);
@@ -86,6 +116,8 @@ void gui_redraw(Gui* gui) {
furi_assert(gui);
gui_lock(gui);
canvas_reset(gui->canvas_api);
if(!gui_redraw_fs(gui)) {
if(!gui_redraw_normal(gui)) {
gui_redraw_none(gui);

View File

@@ -3,10 +3,24 @@
#include "widget.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 {
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 */
GuiLayerFullscreen, /* Fullscreen widget layer */

View File

@@ -6,9 +6,20 @@
struct GuiEvent {
PubSub* input_event_record;
osTimerId_t timer;
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) {
furi_assert(value);
furi_assert(ctx);
@@ -29,6 +40,10 @@ GuiEvent* gui_event_alloc() {
gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GuiMessage), NULL);
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
gui_event->input_event_record = furi_open("input_events");
furi_check(gui_event->input_event_record != NULL);

View File

@@ -10,15 +10,6 @@
// 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 = furi_alloc(sizeof(Widget));
widget->is_enabled = true;
@@ -31,6 +22,26 @@ void widget_free(Widget* 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) {
furi_assert(widget);
if(widget->is_enabled != enabled) {
@@ -80,7 +91,9 @@ void widget_draw(Widget* widget, CanvasApi* canvas_api) {
void widget_input(Widget* widget, InputEvent* event) {
furi_assert(widget);
furi_assert(event);
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);
}
}

View File

@@ -8,14 +8,51 @@ typedef struct Widget Widget;
typedef void (*WidgetDrawCallback)(CanvasApi* api, 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 deallocator
* Ensure that widget was unregistered in GUI system before use.
*/
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);
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_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);

View File

@@ -2,8 +2,31 @@
#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);
/*
* Process draw call. Calls draw callback.
* @param canvas_api - canvas to draw at.
*/
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);