[FL-1549] Gui Widget module (#598)
* gui_widget: rework with mlib container * widget: rename gui_widget-> widget; gui_element->widget_element * gui: move widget from nfc to gui/modules * nfc: rework widget usage * nfc: return to ReadEmvAppSuccess scene after ReadEmvDataSuccess exit Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
152
applications/gui/modules/widget.c
Executable file
152
applications/gui/modules/widget.c
Executable file
@@ -0,0 +1,152 @@
|
||||
#include <furi.h>
|
||||
#include "widget.h"
|
||||
#include <m-array.h>
|
||||
|
||||
ARRAY_DEF(ElementArray, WidgetElement*, M_PTR_OPLIST);
|
||||
|
||||
struct Widget {
|
||||
View* view;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ElementArray_t element;
|
||||
} GuiWidgetModel;
|
||||
|
||||
static void gui_widget_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
GuiWidgetModel* model = _model;
|
||||
canvas_clear(canvas);
|
||||
|
||||
// Draw all elements
|
||||
ElementArray_it_t it;
|
||||
ElementArray_it(it, model->element);
|
||||
while(!ElementArray_end_p(it)) {
|
||||
WidgetElement* element = *ElementArray_ref(it);
|
||||
if(element->draw != NULL) {
|
||||
element->draw(canvas, element);
|
||||
}
|
||||
ElementArray_next(it);
|
||||
}
|
||||
}
|
||||
|
||||
static bool gui_widget_view_input_callback(InputEvent* event, void* context) {
|
||||
Widget* widget = context;
|
||||
bool consumed = false;
|
||||
|
||||
// Call all Widget Elements input handlers
|
||||
with_view_model(
|
||||
widget->view, (GuiWidgetModel * model) {
|
||||
ElementArray_it_t it;
|
||||
ElementArray_it(it, model->element);
|
||||
while(!ElementArray_end_p(it)) {
|
||||
WidgetElement* element = *ElementArray_ref(it);
|
||||
if(element->input != NULL) {
|
||||
consumed |= element->input(event, element);
|
||||
}
|
||||
ElementArray_next(it);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
Widget* widget_alloc() {
|
||||
Widget* widget = furi_alloc(sizeof(Widget));
|
||||
widget->view = view_alloc();
|
||||
view_set_context(widget->view, widget);
|
||||
view_allocate_model(widget->view, ViewModelTypeLocking, sizeof(GuiWidgetModel));
|
||||
view_set_draw_callback(widget->view, gui_widget_view_draw_callback);
|
||||
view_set_input_callback(widget->view, gui_widget_view_input_callback);
|
||||
|
||||
with_view_model(
|
||||
widget->view, (GuiWidgetModel * model) {
|
||||
ElementArray_init(model->element);
|
||||
return true;
|
||||
});
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
void widget_clear(Widget* widget) {
|
||||
furi_assert(widget);
|
||||
|
||||
with_view_model(
|
||||
widget->view, (GuiWidgetModel * model) {
|
||||
ElementArray_it_t it;
|
||||
ElementArray_it(it, model->element);
|
||||
while(!ElementArray_end_p(it)) {
|
||||
WidgetElement* element = *ElementArray_ref(it);
|
||||
furi_assert(element->free);
|
||||
element->free(element);
|
||||
ElementArray_next(it);
|
||||
}
|
||||
ElementArray_clean(model->element);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void widget_free(Widget* widget) {
|
||||
furi_assert(widget);
|
||||
// Free all elements
|
||||
widget_clear(widget);
|
||||
// Free elements container
|
||||
with_view_model(
|
||||
widget->view, (GuiWidgetModel * model) {
|
||||
ElementArray_clear(model->element);
|
||||
return true;
|
||||
});
|
||||
|
||||
view_free(widget->view);
|
||||
free(widget);
|
||||
}
|
||||
|
||||
View* widget_get_view(Widget* widget) {
|
||||
furi_assert(widget);
|
||||
return widget->view;
|
||||
}
|
||||
|
||||
static void widget_add_element(Widget* widget, WidgetElement* element) {
|
||||
furi_assert(widget);
|
||||
furi_assert(element);
|
||||
|
||||
with_view_model(
|
||||
widget->view, (GuiWidgetModel * model) {
|
||||
element->parent = widget;
|
||||
ElementArray_push_back(model->element, element);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void widget_add_string_element(
|
||||
Widget* widget,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
Font font,
|
||||
const char* text) {
|
||||
furi_assert(widget);
|
||||
WidgetElement* string_element =
|
||||
widget_element_string_create(x, y, horizontal, vertical, font, text);
|
||||
widget_add_element(widget, string_element);
|
||||
}
|
||||
|
||||
void widget_add_button_element(
|
||||
Widget* widget,
|
||||
GuiButtonType button_type,
|
||||
const char* text,
|
||||
ButtonCallback callback,
|
||||
void* context) {
|
||||
furi_assert(widget);
|
||||
WidgetElement* button_element =
|
||||
widget_element_button_create(button_type, text, callback, context);
|
||||
widget_add_element(widget, button_element);
|
||||
}
|
||||
|
||||
void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon) {
|
||||
furi_assert(widget);
|
||||
furi_assert(icon);
|
||||
WidgetElement* icon_element = widget_element_icon_create(x, y, icon);
|
||||
widget_add_element(widget, icon_element);
|
||||
}
|
66
applications/gui/modules/widget.h
Executable file
66
applications/gui/modules/widget.h
Executable file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include "widget_elements/widget_element_i.h"
|
||||
|
||||
typedef struct Widget Widget;
|
||||
typedef struct WidgetElement WidgetElement;
|
||||
|
||||
/** Allocate Widget that holds Widget Elements
|
||||
* @return Widget instance
|
||||
*/
|
||||
Widget* widget_alloc();
|
||||
|
||||
/** Free Widget
|
||||
* @note this function free allocated Widget Elements
|
||||
* @param widget Widget instance
|
||||
*/
|
||||
void widget_free(Widget* widget);
|
||||
|
||||
/** Clear Widget
|
||||
* @param widget Widget instance
|
||||
*/
|
||||
void widget_clear(Widget* widget);
|
||||
|
||||
/** Get Widget view
|
||||
* @param widget Widget instance
|
||||
* @return View instance
|
||||
*/
|
||||
View* widget_get_view(Widget* widget);
|
||||
|
||||
/** Add String Element
|
||||
* @param widget Widget instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param horizontal - Align instance
|
||||
* @param vertical - Align instance
|
||||
* @param font Font instance
|
||||
*/
|
||||
void widget_add_string_element(
|
||||
Widget* widget,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
Font font,
|
||||
const char* text);
|
||||
|
||||
/** Add Button Element
|
||||
* @param widget Widget instance
|
||||
* @param button_type GuiButtonType instance
|
||||
* @param text text on allocated button
|
||||
* @param callback ButtonCallback instance
|
||||
* @param context pointer to context
|
||||
*/
|
||||
void widget_add_button_element(
|
||||
Widget* widget,
|
||||
GuiButtonType button_type,
|
||||
const char* text,
|
||||
ButtonCallback callback,
|
||||
void* context);
|
||||
|
||||
/** Add Icon Element
|
||||
* @param widget Widget instance
|
||||
* @param x - x coordinate
|
||||
* @param y - y coordinate
|
||||
* @param icon Icon instance
|
||||
*/
|
||||
void widget_add_icon_element(Widget* widget, uint8_t x, uint8_t y, const Icon* icon);
|
@@ -0,0 +1,79 @@
|
||||
#include "widget_element_i.h"
|
||||
#include <gui/elements.h>
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
GuiButtonType button_type;
|
||||
string_t text;
|
||||
ButtonCallback callback;
|
||||
void* context;
|
||||
} GuiButtonModel;
|
||||
|
||||
static void gui_button_draw(Canvas* canvas, WidgetElement* element) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(element);
|
||||
GuiButtonModel* model = element->model;
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
if(model->button_type == GuiButtonTypeLeft) {
|
||||
elements_button_left(canvas, string_get_cstr(model->text));
|
||||
} else if(model->button_type == GuiButtonTypeRight) {
|
||||
elements_button_right(canvas, string_get_cstr(model->text));
|
||||
} else if(model->button_type == GuiButtonTypeCenter) {
|
||||
elements_button_center(canvas, string_get_cstr(model->text));
|
||||
}
|
||||
}
|
||||
|
||||
static bool gui_button_input(InputEvent* event, WidgetElement* element) {
|
||||
GuiButtonModel* model = element->model;
|
||||
bool consumed = false;
|
||||
|
||||
if((event->type == InputTypeShort) && model->callback) {
|
||||
if((model->button_type == GuiButtonTypeLeft) && (event->key == InputKeyLeft)) {
|
||||
model->callback(model->button_type, model->context);
|
||||
consumed = true;
|
||||
} else if((model->button_type == GuiButtonTypeRight) && (event->key == InputKeyRight)) {
|
||||
model->callback(model->button_type, model->context);
|
||||
consumed = true;
|
||||
} else if((model->button_type == GuiButtonTypeCenter) && (event->key == InputKeyOk)) {
|
||||
model->callback(model->button_type, model->context);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static void gui_button_free(WidgetElement* gui_button) {
|
||||
furi_assert(gui_button);
|
||||
|
||||
GuiButtonModel* model = gui_button->model;
|
||||
string_clear(model->text);
|
||||
free(gui_button->model);
|
||||
free(gui_button);
|
||||
}
|
||||
|
||||
WidgetElement* widget_element_button_create(
|
||||
GuiButtonType button_type,
|
||||
const char* text,
|
||||
ButtonCallback callback,
|
||||
void* context) {
|
||||
// Allocate and init model
|
||||
GuiButtonModel* model = furi_alloc(sizeof(GuiButtonModel));
|
||||
model->button_type = button_type;
|
||||
model->callback = callback;
|
||||
model->context = context;
|
||||
string_init_set_str(model->text, text);
|
||||
|
||||
// Allocate and init Element
|
||||
WidgetElement* gui_button = furi_alloc(sizeof(WidgetElement));
|
||||
gui_button->parent = NULL;
|
||||
gui_button->input = gui_button_input;
|
||||
gui_button->draw = gui_button_draw;
|
||||
gui_button->free = gui_button_free;
|
||||
gui_button->model = model;
|
||||
|
||||
return gui_button;
|
||||
}
|
48
applications/gui/modules/widget_elements/widget_element_i.h
Executable file
48
applications/gui/modules/widget_elements/widget_element_i.h
Executable file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef enum {
|
||||
GuiButtonTypeLeft,
|
||||
GuiButtonTypeCenter,
|
||||
GuiButtonTypeRight,
|
||||
} GuiButtonType;
|
||||
|
||||
typedef void (*ButtonCallback)(GuiButtonType result, void* context);
|
||||
|
||||
typedef struct WidgetElement WidgetElement;
|
||||
typedef struct Widget Widget;
|
||||
|
||||
struct WidgetElement {
|
||||
// generic draw and input callbacks
|
||||
void (*draw)(Canvas* canvas, WidgetElement* element);
|
||||
bool (*input)(InputEvent* event, WidgetElement* element);
|
||||
|
||||
// free callback
|
||||
void (*free)(WidgetElement* element);
|
||||
|
||||
// generic model holder
|
||||
void* model;
|
||||
|
||||
// pointer to widget that hold our element
|
||||
Widget* parent;
|
||||
};
|
||||
|
||||
/* Create string element */
|
||||
WidgetElement* widget_element_string_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
Font font,
|
||||
const char* text);
|
||||
|
||||
/* Create button element */
|
||||
WidgetElement* widget_element_button_create(
|
||||
GuiButtonType button_type,
|
||||
const char* text,
|
||||
ButtonCallback callback,
|
||||
void* context);
|
||||
|
||||
/* Create icon element element */
|
||||
WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon);
|
@@ -0,0 +1,45 @@
|
||||
#include "widget_element_i.h"
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
const Icon* icon;
|
||||
} GuiIconModel;
|
||||
|
||||
static void gui_icon_draw(Canvas* canvas, WidgetElement* element) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(element);
|
||||
GuiIconModel* model = element->model;
|
||||
|
||||
if(model->icon) {
|
||||
canvas_draw_icon(canvas, model->x, model->y, model->icon);
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_icon_free(WidgetElement* gui_icon) {
|
||||
furi_assert(gui_icon);
|
||||
|
||||
free(gui_icon->model);
|
||||
free(gui_icon);
|
||||
}
|
||||
|
||||
WidgetElement* widget_element_icon_create(uint8_t x, uint8_t y, const Icon* icon) {
|
||||
furi_assert(icon);
|
||||
|
||||
// Allocate and init model
|
||||
GuiIconModel* model = furi_alloc(sizeof(GuiIconModel));
|
||||
model->x = x;
|
||||
model->y = y;
|
||||
model->icon = icon;
|
||||
|
||||
// Allocate and init Element
|
||||
WidgetElement* gui_icon = furi_alloc(sizeof(WidgetElement));
|
||||
gui_icon->parent = NULL;
|
||||
gui_icon->input = NULL;
|
||||
gui_icon->draw = gui_icon_draw;
|
||||
gui_icon->free = gui_icon_free;
|
||||
gui_icon->model = model;
|
||||
|
||||
return gui_icon;
|
||||
}
|
66
applications/gui/modules/widget_elements/widget_element_string.c
Executable file
66
applications/gui/modules/widget_elements/widget_element_string.c
Executable file
@@ -0,0 +1,66 @@
|
||||
#include "widget_element_i.h"
|
||||
#include <m-string.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
Align horizontal;
|
||||
Align vertical;
|
||||
Font font;
|
||||
string_t text;
|
||||
} GuiStringModel;
|
||||
|
||||
static void gui_string_draw(Canvas* canvas, WidgetElement* element) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(element);
|
||||
GuiStringModel* model = element->model;
|
||||
|
||||
if(string_size(model->text)) {
|
||||
canvas_set_font(canvas, model->font);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
model->x,
|
||||
model->y,
|
||||
model->horizontal,
|
||||
model->vertical,
|
||||
string_get_cstr(model->text));
|
||||
}
|
||||
}
|
||||
|
||||
static void gui_string_free(WidgetElement* gui_string) {
|
||||
furi_assert(gui_string);
|
||||
|
||||
GuiStringModel* model = gui_string->model;
|
||||
string_clear(model->text);
|
||||
free(gui_string->model);
|
||||
free(gui_string);
|
||||
}
|
||||
|
||||
WidgetElement* widget_element_string_create(
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical,
|
||||
Font font,
|
||||
const char* text) {
|
||||
furi_assert(text);
|
||||
|
||||
// Allocate and init model
|
||||
GuiStringModel* model = furi_alloc(sizeof(GuiStringModel));
|
||||
model->x = x;
|
||||
model->y = y;
|
||||
model->horizontal = horizontal;
|
||||
model->vertical = vertical;
|
||||
model->font = font;
|
||||
string_init_set_str(model->text, text);
|
||||
|
||||
// Allocate and init Element
|
||||
WidgetElement* gui_string = furi_alloc(sizeof(WidgetElement));
|
||||
gui_string->parent = NULL;
|
||||
gui_string->input = NULL;
|
||||
gui_string->draw = gui_string_draw;
|
||||
gui_string->free = gui_string_free;
|
||||
gui_string->model = model;
|
||||
|
||||
return gui_string;
|
||||
}
|
Reference in New Issue
Block a user