cpp template application library (#232)

This commit is contained in:
DrZlo13
2020-11-12 14:13:29 +03:00
committed by GitHub
parent 608d458b9a
commit 38d895956a
4 changed files with 305 additions and 1 deletions

View File

@@ -0,0 +1,92 @@
#include "flipper.h"
#include "flipper_v2.h"
#include "app-template.h"
/*
To use this example you need to rename
AppExampleState - class to hold app state
AppExampleEvent - class to hold app event
AppExample - app class
app_cpp_example - function that launch app
*/
// event enumeration type
typedef uint8_t event_t;
// app state class
class AppExampleState {
public:
// state data
uint8_t example_data;
// state initializer
AppExampleState() {
example_data = 12;
}
};
// app events class
class AppExampleEvent {
public:
// events enum
static const event_t EventTypeTick = 0;
static const event_t EventTypeKey = 1;
// payload
union {
InputEvent input;
} value;
// event type
event_t type;
};
// our app derived from base AppTemplate class
// with template variables <state, events>
class AppExample : public AppTemplate<AppExampleState, AppExampleEvent> {
public:
void run();
void render(CanvasApi* canvas);
};
// start app
void AppExample::run() {
AppExampleEvent event;
while(1) {
if(get_event(&event, 1000)) {
if(event.type == AppExampleEvent::EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
printf("bye!\n");
exit();
}
if(event.value.input.state && event.value.input.input == InputUp) {
// to read or write state you need to execute
// acquire modify release state
acquire_state();
state.example_data = 24;
release_state();
}
}
}
// signal to force gui update
update_gui();
};
}
// render app
void AppExample::render(CanvasApi* canvas) {
// here you dont need to call acquire_state or release_state
// to read or write app state, that already handled by caller
canvas->set_color(canvas, ColorBlack);
canvas->set_font(canvas, FontPrimary);
canvas->draw_str(canvas, 2, state.example_data, "Example app");
}
// app enter function
extern "C" void app_cpp_example(void* p) {
AppExample* app = new AppExample();
app->run();
}

View File

@@ -0,0 +1,107 @@
#pragma once
#include "callback-connector.h"
#include "flipper.h"
#include "flipper_v2.h"
// simple app class with template variables <state, events>
template <class TState, class TEvent> class AppTemplate {
public:
AppTemplate();
~AppTemplate();
void input_callback(InputEvent* input_event, void* ctx);
void draw_callback(CanvasApi* canvas, void* ctx);
virtual void render(CanvasApi* canvas) = 0;
Widget* widget;
osMessageQueueId_t event_queue;
TState state;
ValueMutex state_mutex;
GuiApi* gui;
void acquire_state(void);
void release_state(void);
bool get_event(TEvent* event, uint32_t timeout);
void exit(void);
void update_gui(void);
};
template <class TState, class TEvent> AppTemplate<TState, TEvent>::AppTemplate() {
// allocate events queue
event_queue = osMessageQueueNew(10, sizeof(TEvent), NULL);
// allocate valuemutex
// TODO: use plain os mutex?
if(!init_mutex(&state_mutex, &state, sizeof(TState))) {
printf("cannot create mutex\n");
furiac_exit(NULL);
}
// allocate widget
widget = widget_alloc();
// connect widget with input callback
auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback);
widget_input_callback_set(widget, input_cb_ref, this);
// connect widget with draw callback
auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback);
widget_draw_callback_set(widget, draw_cb_ref, this);
// open gui and add widget
gui = (GuiApi*)furi_open("gui");
if(gui == NULL) {
printf("gui is not available\n");
furiac_exit(NULL);
}
gui->add_widget(gui, widget, GuiLayerFullscreen);
}
template <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() {
}
// generic input callback
template <class TState, class TEvent>
void AppTemplate<TState, TEvent>::input_callback(InputEvent* input_event, void* ctx) {
AppTemplate* app = static_cast<AppTemplate*>(ctx);
TEvent event;
event.type = TEvent::EventTypeKey;
event.value.input = *input_event;
osMessageQueuePut(app->event_queue, &event, 0, 0);
}
// generic draw callback
template <class TState, class TEvent>
void AppTemplate<TState, TEvent>::draw_callback(CanvasApi* canvas, void* ctx) {
AppTemplate* app = static_cast<AppTemplate*>(ctx);
app->acquire_state();
canvas->clear(canvas);
app->render(canvas);
app->release_state();
}
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::acquire_state(void) {
acquire_mutex(&state_mutex, osWaitForever);
}
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::release_state(void) {
release_mutex(&state_mutex, &state);
}
template <class TState, class TEvent>
bool AppTemplate<TState, TEvent>::get_event(TEvent* event, uint32_t timeout) {
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, timeout);
return (event_status == osOK);
}
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::exit(void) {
// TODO remove all widgets create by app
widget_enabled_set(widget, false);
furiac_exit(NULL);
}
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::update_gui(void) {
widget_update(widget);
}