#pragma once #include "callback-connector.h" #include "flipper.h" #include "flipper_v2.h" // simple app class with template variables template class AppTemplate { public: Widget* widget; osMessageQueueId_t event_queue; TState state; ValueMutex state_mutex; GuiApi* gui; AppTemplate(); ~AppTemplate(); void input_callback(InputEvent* input_event, void* ctx); void draw_callback(CanvasApi* canvas, void* ctx); virtual void render(CanvasApi* canvas) = 0; void acquire_state(void); void release_state(void); bool get_event(TEvent* event, uint32_t timeout); void app_ready(void); void exit(void); void update_gui(void); }; template AppTemplate::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); } // open gui gui = (GuiApi*)furi_open("gui"); if(gui == NULL) { printf("gui is not available\n"); furiac_exit(NULL); } // allocate widget widget = widget_alloc(); } template AppTemplate::~AppTemplate() { } // generic input callback template void AppTemplate::input_callback(InputEvent* input_event, void* ctx) { AppTemplate* app = static_cast(ctx); TEvent event; event.type = TEvent::EventTypeKey; event.value.input = *input_event; osMessageQueuePut(app->event_queue, &event, 0, 0); } // generic draw callback template void AppTemplate::draw_callback(CanvasApi* canvas, void* ctx) { AppTemplate* app = static_cast(ctx); app->acquire_state(); canvas->clear(canvas); app->render(canvas); app->release_state(); } template void AppTemplate::acquire_state(void) { acquire_mutex(&state_mutex, osWaitForever); } template void AppTemplate::release_state(void) { release_mutex(&state_mutex, &state); } template bool AppTemplate::get_event(TEvent* event, uint32_t timeout) { osStatus_t event_status = osMessageQueueGet(event_queue, event, NULL, timeout); return (event_status == osOK); } // signal that app is ready, and we can render something // also unblock dependent tasks template void AppTemplate::app_ready(void) { // 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); // add widget gui->add_widget(gui, widget, GuiLayerFullscreen); // signal that our app ready to work furiac_ready(); } template void AppTemplate::exit(void) { // TODO remove all widgets create by app widget_enabled_set(widget, false); furiac_exit(NULL); } template void AppTemplate::update_gui(void) { widget_update(widget); }