C++ apps: templated scene controller (#517)
* C++ apps: templated scene controller * templated app: fix type names * templated app: text store component * Applications: add "Templated Scene" application * templated app: refractoring * Gui module byte input: fix docs * templated app: new byte input scene * templated app: dialog ex view module * templated app: popup view module * templated app: dialog-ex view module, fix docs * templated app: text input view module * Gui module text input: fix docs * Furi: duplicated include * templated app: record holder (controller) class * templated app: view modules can now be accessed via cast * templated app: remove unused includes * templated app: fix return code
This commit is contained in:
		
							parent
							
								
									3a2121bbb8
								
							
						
					
					
						commit
						0b14db4fb3
					
				| @ -39,6 +39,7 @@ int32_t app_accessor(void* p); | |||||||
| int32_t internal_storage_task(void* p); | int32_t internal_storage_task(void* p); | ||||||
| int32_t app_archive(void* p); | int32_t app_archive(void* p); | ||||||
| int32_t notification_app(void* p); | int32_t notification_app(void* p); | ||||||
|  | int32_t scened_app(void* p); | ||||||
| 
 | 
 | ||||||
| // On system start hooks declaration
 | // On system start hooks declaration
 | ||||||
| void irda_cli_init(); | void irda_cli_init(); | ||||||
| @ -293,6 +294,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | |||||||
|      .stack_size = 1024, |      .stack_size = 1024, | ||||||
|      .icon = A_Plugins_14}, |      .icon = A_Plugins_14}, | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef APP_SCENED | ||||||
|  |     {.app = scened_app, .name = "Templated Scene", .stack_size = 1024, .icon = A_Plugins_14}, | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | const size_t FLIPPER_DEBUG_APPS_COUNT = sizeof(FLIPPER_DEBUG_APPS) / sizeof(FlipperApplication); | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ void byte_input_free(ByteInput* byte_input); | |||||||
| View* byte_input_get_view(ByteInput* byte_input); | View* byte_input_get_view(ByteInput* byte_input); | ||||||
| 
 | 
 | ||||||
| /** 
 | /** 
 | ||||||
|  * @brief Deinitialize and free byte input |  * @brief Set byte input result callback | ||||||
|  *  |  *  | ||||||
|  * @param byte_input byte input instance |  * @param byte_input byte input instance | ||||||
|  * @param input_callback input callback fn |  * @param input_callback input callback fn | ||||||
|  | |||||||
| @ -9,23 +9,31 @@ extern "C" { | |||||||
| typedef struct TextInput TextInput; | typedef struct TextInput TextInput; | ||||||
| typedef void (*TextInputCallback)(void* context, char* text); | typedef void (*TextInputCallback)(void* context, char* text); | ||||||
| 
 | 
 | ||||||
| /* Allocate and initialize text input
 | /** 
 | ||||||
|  * This text input is used to enter string |  * @brief Allocate and initialize text input | ||||||
|  |  *        This text input is used to enter string | ||||||
|  |  *  | ||||||
|  */ |  */ | ||||||
| TextInput* text_input_alloc(); | TextInput* text_input_alloc(); | ||||||
| 
 | 
 | ||||||
| /* Deinitialize and free text input
 | /** 
 | ||||||
|  |  * @brief Deinitialize and free text input | ||||||
|  |  *  | ||||||
|  * @param text_input - Text input instance |  * @param text_input - Text input instance | ||||||
|  */ |  */ | ||||||
| void text_input_free(TextInput* text_input); | void text_input_free(TextInput* text_input); | ||||||
| 
 | 
 | ||||||
| /* Get text input view
 | /**
 | ||||||
|  |  * @brief Get text input view | ||||||
|  |  *  | ||||||
|  * @param text_input - Text input instance |  * @param text_input - Text input instance | ||||||
|  * @return View instance that can be used for embedding |  * @return View instance that can be used for embedding | ||||||
|  */ |  */ | ||||||
| View* text_input_get_view(TextInput* text_input); | View* text_input_get_view(TextInput* text_input); | ||||||
| 
 | 
 | ||||||
| /* Deinitialize and free text input
 | /**
 | ||||||
|  |  * @brief Set text input result callback | ||||||
|  |  *  | ||||||
|  * @param text_input - Text input instance |  * @param text_input - Text input instance | ||||||
|  * @param callback - callback fn |  * @param callback - callback fn | ||||||
|  * @param callback_context - callback context |  * @param callback_context - callback context | ||||||
| @ -39,7 +47,9 @@ void text_input_set_result_callback( | |||||||
|     char* text, |     char* text, | ||||||
|     uint8_t max_text_length); |     uint8_t max_text_length); | ||||||
| 
 | 
 | ||||||
| /* Set text input header text
 | /** 
 | ||||||
|  |  * @brief Set text input header text | ||||||
|  |  *  | ||||||
|  * @param text input - Text input instance |  * @param text input - Text input instance | ||||||
|  * @param text - text to be shown |  * @param text - text to be shown | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -0,0 +1,35 @@ | |||||||
|  | #include "scened-app-scene-byte-input.h" | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneByteInput::on_enter(ScenedApp* app, bool need_restore) { | ||||||
|  |     ByteInputVM* byte_input = app->view_controller; | ||||||
|  |     auto callback = cbc::obtain_connector(this, &ScenedAppSceneByteInput::result_callback); | ||||||
|  | 
 | ||||||
|  |     byte_input->set_result_callback(callback, NULL, app, data, 4); | ||||||
|  |     byte_input->set_header_text("Enter the key"); | ||||||
|  | 
 | ||||||
|  |     app->view_controller.switch_to<ByteInputVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ScenedAppSceneByteInput::on_event(ScenedApp* app, ScenedApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == ScenedApp::EventType::ByteEditResult) { | ||||||
|  |         app->scene_controller.switch_to_previous_scene(); | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneByteInput::on_exit(ScenedApp* app) { | ||||||
|  |     app->view_controller.get<ByteInputVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneByteInput::result_callback(void* context, uint8_t* bytes, uint8_t bytes_count) { | ||||||
|  |     ScenedApp* app = static_cast<ScenedApp*>(context); | ||||||
|  |     ScenedApp::Event event; | ||||||
|  | 
 | ||||||
|  |     event.type = ScenedApp::EventType::ByteEditResult; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../scened-app.h" | ||||||
|  | 
 | ||||||
|  | class ScenedAppSceneByteInput : public GenericScene<ScenedApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(ScenedApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(ScenedApp* app, ScenedApp::Event* event) final; | ||||||
|  |     void on_exit(ScenedApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void result_callback(void* context, uint8_t* bytes, uint8_t bytes_count); | ||||||
|  | 
 | ||||||
|  |     uint8_t data[4] = { | ||||||
|  |         0x01, | ||||||
|  |         0xA2, | ||||||
|  |         0xF4, | ||||||
|  |         0xD3, | ||||||
|  |     }; | ||||||
|  | }; | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | #include "scened-app-scene-start.h" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     SubmenuByteInput, | ||||||
|  | } SubmenuIndex; | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneStart::on_enter(ScenedApp* app, bool need_restore) { | ||||||
|  |     auto submenu = app->view_controller.get<SubmenuVM>(); | ||||||
|  |     auto callback = cbc::obtain_connector(this, &ScenedAppSceneStart::submenu_callback); | ||||||
|  | 
 | ||||||
|  |     submenu->add_item("Byte Input", SubmenuByteInput, callback, app); | ||||||
|  | 
 | ||||||
|  |     if(need_restore) { | ||||||
|  |         submenu->set_selected_item(submenu_item_selected); | ||||||
|  |     } | ||||||
|  |     app->view_controller.switch_to<SubmenuVM>(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ScenedAppSceneStart::on_event(ScenedApp* app, ScenedApp::Event* event) { | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == ScenedApp::EventType::MenuSelected) { | ||||||
|  |         submenu_item_selected = event->payload.menu_index; | ||||||
|  |         switch(event->payload.menu_index) { | ||||||
|  |         case SubmenuByteInput: | ||||||
|  |             app->scene_controller.switch_to_next_scene(ScenedApp::SceneType::ByteInputScene); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneStart::on_exit(ScenedApp* app) { | ||||||
|  |     app->view_controller.get<SubmenuVM>()->clean(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScenedAppSceneStart::submenu_callback(void* context, uint32_t index) { | ||||||
|  |     ScenedApp* app = static_cast<ScenedApp*>(context); | ||||||
|  |     ScenedApp::Event event; | ||||||
|  | 
 | ||||||
|  |     event.type = ScenedApp::EventType::MenuSelected; | ||||||
|  |     event.payload.menu_index = index; | ||||||
|  | 
 | ||||||
|  |     app->view_controller.send_event(&event); | ||||||
|  | } | ||||||
| @ -0,0 +1,13 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "../scened-app.h" | ||||||
|  | 
 | ||||||
|  | class ScenedAppSceneStart : public GenericScene<ScenedApp> { | ||||||
|  | public: | ||||||
|  |     void on_enter(ScenedApp* app, bool need_restore) final; | ||||||
|  |     bool on_event(ScenedApp* app, ScenedApp::Event* event) final; | ||||||
|  |     void on_exit(ScenedApp* app) final; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void submenu_callback(void* context, uint32_t index); | ||||||
|  |     uint32_t submenu_item_selected = 0; | ||||||
|  | }; | ||||||
							
								
								
									
										10
									
								
								applications/scened-app-example/scened-app-launcher.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								applications/scened-app-example/scened-app-launcher.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #include "scened-app.h" | ||||||
|  | 
 | ||||||
|  | // app enter function
 | ||||||
|  | extern "C" int32_t scened_app(void* p) { | ||||||
|  |     ScenedApp* app = new ScenedApp(); | ||||||
|  |     app->run(); | ||||||
|  |     delete app; | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								applications/scened-app-example/scened-app.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								applications/scened-app-example/scened-app.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #include "scened-app.h" | ||||||
|  | #include "scene/scened-app-scene-start.h" | ||||||
|  | #include "scene/scened-app-scene-byte-input.h" | ||||||
|  | 
 | ||||||
|  | ScenedApp::ScenedApp() | ||||||
|  |     : scene_controller{this} | ||||||
|  |     , text_store{128} | ||||||
|  |     , notification{"notification"} { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ScenedApp::~ScenedApp() { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ScenedApp::run() { | ||||||
|  |     scene_controller.add_scene(SceneType::Start, new ScenedAppSceneStart()); | ||||||
|  |     scene_controller.add_scene(SceneType::ByteInputScene, new ScenedAppSceneByteInput()); | ||||||
|  | 
 | ||||||
|  |     notification_message(notification, &sequence_blink_green_10); | ||||||
|  |     scene_controller.process(100); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								applications/scened-app-example/scened-app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								applications/scened-app-example/scened-app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <furi.h> | ||||||
|  | #include <api-hal.h> | ||||||
|  | 
 | ||||||
|  | #include <generic-scene.hpp> | ||||||
|  | #include <scene-controller.hpp> | ||||||
|  | #include <view-controller.hpp> | ||||||
|  | #include <record-controller.hpp> | ||||||
|  | #include <text-store.h> | ||||||
|  | 
 | ||||||
|  | #include <view-modules/submenu-vm.h> | ||||||
|  | #include <view-modules/byte-input-vm.h> | ||||||
|  | 
 | ||||||
|  | #include <notification/notification-messages.h> | ||||||
|  | 
 | ||||||
|  | class ScenedApp { | ||||||
|  | public: | ||||||
|  |     enum class EventType : uint8_t { | ||||||
|  |         GENERIC_EVENT_ENUM_VALUES, | ||||||
|  |         MenuSelected, | ||||||
|  |         ByteEditResult, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     enum class SceneType : uint8_t { | ||||||
|  |         GENERIC_SCENE_ENUM_VALUES, | ||||||
|  |         ByteInputScene, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class Event { | ||||||
|  |     public: | ||||||
|  |         union { | ||||||
|  |             int32_t menu_index; | ||||||
|  |         } payload; | ||||||
|  | 
 | ||||||
|  |         EventType type; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     SceneController<GenericScene<ScenedApp>, ScenedApp> scene_controller; | ||||||
|  |     TextStore text_store; | ||||||
|  |     ViewController<ScenedApp, SubmenuVM, ByteInputVM> view_controller; | ||||||
|  |     RecordController<NotificationApp> notification; | ||||||
|  | 
 | ||||||
|  |     ~ScenedApp(); | ||||||
|  |     ScenedApp(); | ||||||
|  | 
 | ||||||
|  |     void run(); | ||||||
|  | }; | ||||||
| @ -11,7 +11,6 @@ | |||||||
| #include <furi/thread.h> | #include <furi/thread.h> | ||||||
| #include <furi/valuemutex.h> | #include <furi/valuemutex.h> | ||||||
| #include <furi/log.h> | #include <furi/log.h> | ||||||
| #include <furi/common_defines.h> |  | ||||||
| 
 | 
 | ||||||
| #include <api-hal-gpio.h> | #include <api-hal-gpio.h> | ||||||
| #include <api-hal/api-interrupt-mgr.h> | #include <api-hal/api-interrupt-mgr.h> | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								lib/app-scened-template/generic-scene.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/app-scened-template/generic-scene.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | template <typename TApp> class GenericScene { | ||||||
|  | public: | ||||||
|  |     virtual void on_enter(TApp* app, bool need_restore) = 0; | ||||||
|  |     virtual bool on_event(TApp* app, typename TApp::Event* event) = 0; | ||||||
|  |     virtual void on_exit(TApp* app) = 0; | ||||||
|  |     virtual ~GenericScene(){}; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | }; | ||||||
							
								
								
									
										46
									
								
								lib/app-scened-template/record-controller.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/app-scened-template/record-controller.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <furi/record.h> | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Class for opening, casting, holding and closing records | ||||||
|  |  *  | ||||||
|  |  * @tparam TRecordClass record class | ||||||
|  |  */ | ||||||
|  | template <typename TRecordClass> class RecordController { | ||||||
|  | public: | ||||||
|  |     /**
 | ||||||
|  |      * @brief Construct a new Record Controller object for record with record name | ||||||
|  |      *  | ||||||
|  |      * @param record_name record name | ||||||
|  |      */ | ||||||
|  |     RecordController(const char* record_name) { | ||||||
|  |         name = record_name; | ||||||
|  |         value = static_cast<TRecordClass*>(furi_record_open(name)); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     ~RecordController() { | ||||||
|  |         furi_record_close(name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Record getter | ||||||
|  |      *  | ||||||
|  |      * @return TRecordClass* record value | ||||||
|  |      */ | ||||||
|  |     TRecordClass* get() { | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Record getter (by cast) | ||||||
|  |      *  | ||||||
|  |      * @return TRecordClass* record value | ||||||
|  |      */ | ||||||
|  |     operator TRecordClass*() const { | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     const char* name; | ||||||
|  |     TRecordClass* value; | ||||||
|  | }; | ||||||
							
								
								
									
										178
									
								
								lib/app-scened-template/scene-controller.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								lib/app-scened-template/scene-controller.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,178 @@ | |||||||
|  | #include <map> | ||||||
|  | #include <forward_list> | ||||||
|  | #include <initializer_list> | ||||||
|  | 
 | ||||||
|  | #define GENERIC_SCENE_ENUM_VALUES Uninitalized, Exit, Start | ||||||
|  | #define GENERIC_EVENT_ENUM_VALUES Tick, Back | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Controller for scene navigation in application | ||||||
|  |  *  | ||||||
|  |  * @tparam TScene generic scene class | ||||||
|  |  * @tparam TApp application class | ||||||
|  |  */ | ||||||
|  | template <typename TScene, typename TApp> class SceneController { | ||||||
|  | public: | ||||||
|  |     /**
 | ||||||
|  |      * @brief Add scene to scene container | ||||||
|  |      *  | ||||||
|  |      * @param scene_index scene index | ||||||
|  |      * @param scene_pointer scene object pointer | ||||||
|  |      */ | ||||||
|  |     void add_scene(typename TApp::SceneType scene_index, TScene* scene_pointer) { | ||||||
|  |         furi_check(scenes.count(scene_index) == 0); | ||||||
|  |         scenes[scene_index] = scene_pointer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Switch to next scene and store current scene in previous scenes list | ||||||
|  |      *  | ||||||
|  |      * @param scene_index next scene index | ||||||
|  |      * @param need_restore true, if we want the scene to restore its parameters | ||||||
|  |      */ | ||||||
|  |     void switch_to_next_scene(typename TApp::SceneType scene_index, bool need_restore = false) { | ||||||
|  |         previous_scenes_list.push_front(current_scene_index); | ||||||
|  |         switch_to_scene(scene_index, need_restore); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Switch to next scene without ability to return to current scene | ||||||
|  |      *  | ||||||
|  |      * @param scene_index next scene index | ||||||
|  |      * @param need_restore true, if we want the scene to restore its parameters | ||||||
|  |      */ | ||||||
|  |     void switch_to_scene(typename TApp::SceneType scene_index, bool need_restore = false) { | ||||||
|  |         if(scene_index != TApp::SceneType::Exit) { | ||||||
|  |             scenes[current_scene_index]->on_exit(app); | ||||||
|  |             current_scene_index = scene_index; | ||||||
|  |             scenes[current_scene_index]->on_enter(app, need_restore); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Search the scene in the list of previous scenes and switch to it | ||||||
|  |      *  | ||||||
|  |      * @param scene_index_list list of scene indexes to which you want to switch | ||||||
|  |      */ | ||||||
|  |     void search_and_switch_to_previous_scene( | ||||||
|  |         const std::initializer_list<typename TApp::SceneType>& scene_index_list) { | ||||||
|  |         auto previous_scene_index = TApp::SceneType::Start; | ||||||
|  |         bool scene_found = false; | ||||||
|  | 
 | ||||||
|  |         while(!scene_found) { | ||||||
|  |             previous_scene_index = get_previous_scene_index(); | ||||||
|  |             for(const auto& element : scene_index_list) { | ||||||
|  |                 if(previous_scene_index == element) { | ||||||
|  |                     scene_found = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         switch_to_scene(previous_scene_index, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Start application main cycle | ||||||
|  |      *  | ||||||
|  |      * @param tick_length_ms tick event length in milliseconds | ||||||
|  |      */ | ||||||
|  |     void process(uint32_t tick_length_ms = 100) { | ||||||
|  |         typename TApp::Event event; | ||||||
|  |         bool consumed; | ||||||
|  |         bool exit = false; | ||||||
|  | 
 | ||||||
|  |         current_scene_index = TApp::SceneType::Start; | ||||||
|  |         scenes[current_scene_index]->on_enter(app, false); | ||||||
|  | 
 | ||||||
|  |         while(!exit) { | ||||||
|  |             app->view_controller.receive_event(&event); | ||||||
|  | 
 | ||||||
|  |             consumed = scenes[current_scene_index]->on_event(app, &event); | ||||||
|  | 
 | ||||||
|  |             if(!consumed) { | ||||||
|  |                 if(event.type == TApp::EventType::Back) { | ||||||
|  |                     exit = switch_to_previous_scene(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         scenes[current_scene_index]->on_exit(app); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Switch to previous scene | ||||||
|  |      *  | ||||||
|  |      * @param count how many steps back | ||||||
|  |      * @return true if app need to exit | ||||||
|  |      */ | ||||||
|  |     bool switch_to_previous_scene(uint8_t count = 1) { | ||||||
|  |         auto previous_scene_index = TApp::SceneType::Start; | ||||||
|  | 
 | ||||||
|  |         for(uint8_t i = 0; i < count; i++) previous_scene_index = get_previous_scene_index(); | ||||||
|  | 
 | ||||||
|  |         if(previous_scene_index == TApp::SceneType::Exit) return true; | ||||||
|  | 
 | ||||||
|  |         switch_to_scene(previous_scene_index, true); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Construct a new Scene Controller object | ||||||
|  |      *  | ||||||
|  |      * @param app_pointer pointer to application class | ||||||
|  |      */ | ||||||
|  |     SceneController(TApp* app_pointer) { | ||||||
|  |         app = app_pointer; | ||||||
|  |         current_scene_index = TApp::SceneType::Uninitalized; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Destroy the Scene Controller object | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     ~SceneController() { | ||||||
|  |         for(auto& it : scenes) delete it.second; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /**
 | ||||||
|  |      * @brief Scenes pointers container | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     std::map<typename TApp::SceneType, TScene*> scenes; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief List of indexes of previous scenes | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     std::forward_list<typename TApp::SceneType> previous_scenes_list; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Current scene index holder | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     typename TApp::SceneType current_scene_index; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Application pointer holder | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     TApp* app; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Get the previous scene index | ||||||
|  |      *  | ||||||
|  |      * @return previous scene index | ||||||
|  |      */ | ||||||
|  |     typename TApp::SceneType get_previous_scene_index() { | ||||||
|  |         auto scene_index = TApp::SceneType::Exit; | ||||||
|  | 
 | ||||||
|  |         if(!previous_scenes_list.empty()) { | ||||||
|  |             scene_index = previous_scenes_list.front(); | ||||||
|  |             previous_scenes_list.pop_front(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return scene_index; | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										18
									
								
								lib/app-scened-template/text-store.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/app-scened-template/text-store.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | #include "text-store.h" | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | TextStore::TextStore(uint8_t _text_size) | ||||||
|  |     : text_size(_text_size) { | ||||||
|  |     text = static_cast<char*>(malloc(text_size + 1)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TextStore::~TextStore() { | ||||||
|  |     free(text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextStore::set_text_store(const char* _text...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, _text); | ||||||
|  |     vsnprintf(text, text_size, _text, args); | ||||||
|  |     va_end(args); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								lib/app-scened-template/text-store.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								lib/app-scened-template/text-store.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | class TextStore { | ||||||
|  | public: | ||||||
|  |     TextStore(uint8_t text_size); | ||||||
|  |     ~TextStore(); | ||||||
|  | 
 | ||||||
|  |     void set_text_store(const char* text...); | ||||||
|  |     const uint8_t text_size; | ||||||
|  |     char* text; | ||||||
|  | }; | ||||||
							
								
								
									
										121
									
								
								lib/app-scened-template/typeindex_no_rtti.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								lib/app-scened-template/typeindex_no_rtti.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | /*
 | ||||||
|  |  * type_index without RTTI | ||||||
|  |  * | ||||||
|  |  * Copyright frickiericker 2016. | ||||||
|  |  * Distributed under the Boost Software License, Version 1.0. | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person or organization | ||||||
|  |  * obtaining a copy of the software and accompanying documentation covered by | ||||||
|  |  * this license (the "Software") to use, reproduce, display, distribute, | ||||||
|  |  * execute, and transmit the Software, and to prepare derivative works of the | ||||||
|  |  * Software, and to permit third-parties to whom the Software is furnished to | ||||||
|  |  * do so, all subject to the following: | ||||||
|  |  * | ||||||
|  |  * The copyright notices in the Software and this entire statement, including | ||||||
|  |  * the above license grant, this restriction and the following disclaimer, | ||||||
|  |  * must be included in all copies of the Software, in whole or in part, and | ||||||
|  |  * all derivative works of the Software, unless such copies or derivative | ||||||
|  |  * works are solely in the form of machine-executable object code generated by | ||||||
|  |  * a source language processor. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT | ||||||
|  |  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE | ||||||
|  |  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, | ||||||
|  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
|  |  * DEALINGS IN THE SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <functional> | ||||||
|  | 
 | ||||||
|  | namespace ext { | ||||||
|  | /**
 | ||||||
|  |  * Dummy type for tag-dispatching. | ||||||
|  |  */ | ||||||
|  | template <typename T> struct tag_type {}; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * A value of tag_type<T>. | ||||||
|  |  */ | ||||||
|  | template <typename T> constexpr tag_type<T> tag{}; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * A type_index implementation without RTTI. | ||||||
|  |  */ | ||||||
|  | struct type_index { | ||||||
|  |     /**
 | ||||||
|  |      * Creates a type_index object for the specified type. | ||||||
|  |      */ | ||||||
|  |     template <typename T> type_index(tag_type<T>) noexcept : hash_code_{index<T>} { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Returns the hash code. | ||||||
|  |      */ | ||||||
|  |     std::size_t hash_code() const noexcept { | ||||||
|  |         return hash_code_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /**
 | ||||||
|  |      * Unique integral index associated to template type argument. | ||||||
|  |      */ | ||||||
|  |     template <typename T> static std::size_t const index; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Global counter for generating index values. | ||||||
|  |      */ | ||||||
|  |     static std::size_t& counter() noexcept { | ||||||
|  |         static std::size_t counter_; | ||||||
|  |         return counter_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::size_t hash_code_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <typename> std::size_t const type_index::index = type_index::counter()++; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Creates a type_index object for the specified type. | ||||||
|  |  * | ||||||
|  |  * Equivalent to `ext::type_index{ext::tag<T>}`. | ||||||
|  |  */ | ||||||
|  | template <typename T> type_index make_type_index() noexcept { | ||||||
|  |     return tag<T>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator==(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return a.hash_code() == b.hash_code(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator!=(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return !(a == b); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator<(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return a.hash_code() < b.hash_code(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator<=(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return a.hash_code() <= b.hash_code(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator>(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return !(a <= b); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline bool operator>=(type_index const& a, type_index const& b) noexcept { | ||||||
|  |     return !(a < b); | ||||||
|  | } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <> struct std::hash<ext::type_index> { | ||||||
|  |     using argument_type = ext::type_index; | ||||||
|  |     using result_type = std::size_t; | ||||||
|  | 
 | ||||||
|  |     result_type operator()(argument_type const& t) const noexcept { | ||||||
|  |         return t.hash_code(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										163
									
								
								lib/app-scened-template/view-controller.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								lib/app-scened-template/view-controller.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "view-modules/generic-view-module.h" | ||||||
|  | #include <map> | ||||||
|  | #include <furi/check.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <callback-connector.h> | ||||||
|  | #include "typeindex_no_rtti.hpp" | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @brief Controller for switching application views and handling inputs and events | ||||||
|  |  *  | ||||||
|  |  * @tparam TApp application class | ||||||
|  |  * @tparam TViewModules variadic list of ViewModules | ||||||
|  |  */ | ||||||
|  | template <typename TApp, typename... TViewModules> class ViewController { | ||||||
|  | public: | ||||||
|  |     ViewController() { | ||||||
|  |         event_queue = osMessageQueueNew(10, sizeof(typename TApp::Event), NULL); | ||||||
|  | 
 | ||||||
|  |         view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |         previous_view_callback_pointer = cbc::obtain_connector( | ||||||
|  |             this, &ViewController<TApp, TViewModules...>::previous_view_callback); | ||||||
|  | 
 | ||||||
|  |         [](...) { | ||||||
|  |         }((this->add_view(ext::make_type_index<TViewModules>().hash_code(), new TViewModules()), | ||||||
|  |            0)...); | ||||||
|  | 
 | ||||||
|  |         gui = static_cast<Gui*>(furi_record_open("gui")); | ||||||
|  |         view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     ~ViewController() { | ||||||
|  |         for(auto& it : holder) { | ||||||
|  |             view_dispatcher_remove_view(view_dispatcher, static_cast<uint32_t>(it.first)); | ||||||
|  |             delete it.second; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         view_dispatcher_free(view_dispatcher); | ||||||
|  |         osMessageQueueDelete(event_queue); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Get ViewModule pointer | ||||||
|  |      *  | ||||||
|  |      * @tparam T Concrete ViewModule class | ||||||
|  |      * @return T* ViewModule pointer | ||||||
|  |      */ | ||||||
|  |     template <typename T> T* get() { | ||||||
|  |         uint32_t view_index = ext::make_type_index<T>().hash_code(); | ||||||
|  |         furi_check(holder.count(view_index) != 0); | ||||||
|  |         return static_cast<T*>(holder[view_index]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Get ViewModule pointer by cast | ||||||
|  |      *  | ||||||
|  |      * @tparam T Concrete ViewModule class | ||||||
|  |      * @return T* ViewModule pointer | ||||||
|  |      */ | ||||||
|  |     template <typename T> operator T*() { | ||||||
|  |         uint32_t view_index = ext::make_type_index<T>().hash_code(); | ||||||
|  |         furi_check(holder.count(view_index) != 0); | ||||||
|  |         return static_cast<T*>(holder[view_index]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Switch view to ViewModule | ||||||
|  |      *  | ||||||
|  |      * @tparam T Concrete ViewModule class | ||||||
|  |      * @return T* ViewModule pointer | ||||||
|  |      */ | ||||||
|  |     template <typename T> void switch_to() { | ||||||
|  |         uint32_t view_index = ext::make_type_index<T>().hash_code(); | ||||||
|  |         furi_check(holder.count(view_index) != 0); | ||||||
|  |         view_dispatcher_switch_to_view(view_dispatcher, view_index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Receive event from app event queue | ||||||
|  |      *  | ||||||
|  |      * @param event event pointer | ||||||
|  |      */ | ||||||
|  |     void receive_event(typename TApp::Event* event) { | ||||||
|  |         if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) { | ||||||
|  |             event->type = TApp::EventType::Tick; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Send event to app event queue | ||||||
|  |      *  | ||||||
|  |      * @param event event pointer | ||||||
|  |      */ | ||||||
|  |     void send_event(typename TApp::Event* event) { | ||||||
|  |         osStatus_t result = osMessageQueuePut(event_queue, event, 0, osWaitForever); | ||||||
|  |         furi_check(result == osOK); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     /**
 | ||||||
|  |      * @brief ViewModulesHolder | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     std::map<size_t, GenericViewModule*> holder; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief App event queue | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     osMessageQueueId_t event_queue; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Main ViewDispatcher pointer | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Gui record pointer | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     Gui* gui; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Previous view callback fn pointer | ||||||
|  |      *  | ||||||
|  |      */ | ||||||
|  |     ViewNavigationCallback previous_view_callback_pointer; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Previous view callback fn | ||||||
|  |      *  | ||||||
|  |      * @param context not used | ||||||
|  |      * @return uint32_t VIEW_IGNORE | ||||||
|  |      */ | ||||||
|  |     uint32_t previous_view_callback(void* context) { | ||||||
|  |         (void)context; | ||||||
|  | 
 | ||||||
|  |         typename TApp::Event event; | ||||||
|  |         event.type = TApp::EventType::Back; | ||||||
|  | 
 | ||||||
|  |         if(event_queue != NULL) { | ||||||
|  |             send_event(&event); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return VIEW_IGNORE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Add ViewModule to holder | ||||||
|  |      *  | ||||||
|  |      * @param view_index view index in holder | ||||||
|  |      * @param view_module view module pointer | ||||||
|  |      */ | ||||||
|  |     void add_view(size_t view_index, GenericViewModule* view_module) { | ||||||
|  |         furi_check(holder.count(view_index) == 0); | ||||||
|  |         holder[view_index] = view_module; | ||||||
|  | 
 | ||||||
|  |         View* view = view_module->get_view(); | ||||||
|  |         view_dispatcher_add_view(view_dispatcher, static_cast<uint32_t>(view_index), view); | ||||||
|  |         view_set_previous_callback(view, previous_view_callback_pointer); | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										32
									
								
								lib/app-scened-template/view-modules/byte-input-vm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/app-scened-template/view-modules/byte-input-vm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | #include "byte-input-vm.h" | ||||||
|  | 
 | ||||||
|  | ByteInputVM::ByteInputVM() { | ||||||
|  |     byte_input = byte_input_alloc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ByteInputVM::~ByteInputVM() { | ||||||
|  |     byte_input_free(byte_input); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* ByteInputVM::get_view() { | ||||||
|  |     return byte_input_get_view(byte_input); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ByteInputVM::clean() { | ||||||
|  |     byte_input_set_header_text(byte_input, ""); | ||||||
|  |     byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ByteInputVM::set_result_callback( | ||||||
|  |     ByteInputCallback input_callback, | ||||||
|  |     ByteChangedCallback changed_callback, | ||||||
|  |     void* callback_context, | ||||||
|  |     uint8_t* bytes, | ||||||
|  |     uint8_t bytes_count) { | ||||||
|  |     byte_input_set_result_callback( | ||||||
|  |         byte_input, input_callback, changed_callback, callback_context, bytes, bytes_count); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ByteInputVM::set_header_text(const char* text) { | ||||||
|  |     byte_input_set_header_text(byte_input, text); | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								lib/app-scened-template/view-modules/byte-input-vm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/app-scened-template/view-modules/byte-input-vm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "generic-view-module.h" | ||||||
|  | #include <gui/modules/byte_input.h> | ||||||
|  | 
 | ||||||
|  | class ByteInputVM : public GenericViewModule { | ||||||
|  | public: | ||||||
|  |     ByteInputVM(); | ||||||
|  |     ~ByteInputVM() final; | ||||||
|  |     View* get_view() final; | ||||||
|  |     void clean() final; | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * @brief Set byte input result callback | ||||||
|  |      *  | ||||||
|  |      * @param input_callback input callback fn | ||||||
|  |      * @param changed_callback changed callback fn | ||||||
|  |      * @param callback_context callback context | ||||||
|  |      * @param bytes buffer to use | ||||||
|  |      * @param bytes_count buffer length | ||||||
|  |      */ | ||||||
|  |     void set_result_callback( | ||||||
|  |         ByteInputCallback input_callback, | ||||||
|  |         ByteChangedCallback changed_callback, | ||||||
|  |         void* callback_context, | ||||||
|  |         uint8_t* bytes, | ||||||
|  |         uint8_t bytes_count); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Set byte input header text | ||||||
|  |      *  | ||||||
|  |      * @param text text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_header_text(const char* text); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     ByteInput* byte_input; | ||||||
|  | }; | ||||||
							
								
								
									
										61
									
								
								lib/app-scened-template/view-modules/dialog-ex-vm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								lib/app-scened-template/view-modules/dialog-ex-vm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | |||||||
|  | #include "dialog-ex-vm.h" | ||||||
|  | 
 | ||||||
|  | DialogExVM::DialogExVM() { | ||||||
|  |     dialog_ex = dialog_ex_alloc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DialogExVM::~DialogExVM() { | ||||||
|  |     dialog_ex_free(dialog_ex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* DialogExVM::get_view() { | ||||||
|  |     return dialog_ex_get_view(dialog_ex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::clean() { | ||||||
|  |     set_result_callback(NULL); | ||||||
|  |     set_context(NULL); | ||||||
|  |     set_header(NULL, 0, 0, AlignLeft, AlignBottom); | ||||||
|  |     set_text(NULL, 0, 0, AlignLeft, AlignBottom); | ||||||
|  |     set_icon(-1, -1, I_ButtonCenter_7x7); | ||||||
|  |     set_left_button_text(NULL); | ||||||
|  |     set_center_button_text(NULL); | ||||||
|  |     set_right_button_text(NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_result_callback(DialogExResultCallback callback) { | ||||||
|  |     dialog_ex_set_result_callback(dialog_ex, callback); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_context(void* context) { | ||||||
|  |     dialog_ex_set_context(dialog_ex, context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_header( | ||||||
|  |     const char* text, | ||||||
|  |     uint8_t x, | ||||||
|  |     uint8_t y, | ||||||
|  |     Align horizontal, | ||||||
|  |     Align vertical) { | ||||||
|  |     dialog_ex_set_header(dialog_ex, text, x, y, horizontal, vertical); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { | ||||||
|  |     dialog_ex_set_text(dialog_ex, text, x, y, horizontal, vertical); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_icon(int8_t x, int8_t y, IconName name) { | ||||||
|  |     dialog_ex_set_icon(dialog_ex, x, y, name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_left_button_text(const char* text) { | ||||||
|  |     dialog_ex_set_left_button_text(dialog_ex, text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_center_button_text(const char* text) { | ||||||
|  |     dialog_ex_set_center_button_text(dialog_ex, text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogExVM::set_right_button_text(const char* text) { | ||||||
|  |     dialog_ex_set_right_button_text(dialog_ex, text); | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								lib/app-scened-template/view-modules/dialog-ex-vm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								lib/app-scened-template/view-modules/dialog-ex-vm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "generic-view-module.h" | ||||||
|  | #include <gui/modules/dialog_ex.h> | ||||||
|  | 
 | ||||||
|  | class DialogExVM : public GenericViewModule { | ||||||
|  | public: | ||||||
|  |     DialogExVM(); | ||||||
|  |     ~DialogExVM() final; | ||||||
|  |     View* get_view() final; | ||||||
|  |     void clean() final; | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set dialog result callback | ||||||
|  |      * @param callback - result callback function | ||||||
|  |      */ | ||||||
|  |     void set_result_callback(DialogExResultCallback callback); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set dialog context | ||||||
|  |      * @param context - context pointer, will be passed to result callback | ||||||
|  |      */ | ||||||
|  |     void set_context(void* context); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set dialog header text | ||||||
|  |      * If text is null, dialog header will not be rendered | ||||||
|  |      * @param text - text to be shown, can be multiline | ||||||
|  |      * @param x, y - text position | ||||||
|  |      * @param horizontal, vertical - text aligment | ||||||
|  |      */ | ||||||
|  |     void set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set dialog text | ||||||
|  |      * If text is null, dialog text will not be rendered | ||||||
|  |      * @param text - text to be shown, can be multiline | ||||||
|  |      * @param x, y - text position | ||||||
|  |      * @param horizontal, vertical - text aligment | ||||||
|  |      */ | ||||||
|  |     void set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set dialog icon | ||||||
|  |      * If x or y is negative, dialog icon will not be rendered | ||||||
|  |      * @param x, y - icon position | ||||||
|  |      * @param name - icon to be shown | ||||||
|  |      */ | ||||||
|  |     void set_icon(int8_t x, int8_t y, IconName name); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Set left button text | ||||||
|  |      * If text is null, left button will not be rendered and processed | ||||||
|  |      * @param text - text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_left_button_text(const char* text); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set center button text | ||||||
|  |      * If text is null, center button will not be rendered and processed | ||||||
|  |      * @param text - text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_center_button_text(const char* text); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Set right button text | ||||||
|  |      * If text is null, right button will not be rendered and processed | ||||||
|  |      * @param text - text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_right_button_text(const char* text); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     DialogEx* dialog_ex; | ||||||
|  | }; | ||||||
							
								
								
									
										10
									
								
								lib/app-scened-template/view-modules/generic-view-module.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/app-scened-template/view-modules/generic-view-module.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #pragma once | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | class GenericViewModule { | ||||||
|  | public: | ||||||
|  |     GenericViewModule(){}; | ||||||
|  |     virtual ~GenericViewModule(){}; | ||||||
|  |     virtual View* get_view() = 0; | ||||||
|  |     virtual void clean() = 0; | ||||||
|  | }; | ||||||
							
								
								
									
										54
									
								
								lib/app-scened-template/view-modules/popup-vm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								lib/app-scened-template/view-modules/popup-vm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | #include "popup-vm.h" | ||||||
|  | PopupVM::PopupVM() { | ||||||
|  |     popup = popup_alloc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PopupVM::~PopupVM() { | ||||||
|  |     popup_free(popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* PopupVM::get_view() { | ||||||
|  |     return popup_get_view(popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::clean() { | ||||||
|  |     set_callback(NULL); | ||||||
|  |     set_context(NULL); | ||||||
|  |     set_header(NULL, 0, 0, AlignLeft, AlignBottom); | ||||||
|  |     set_text(NULL, 0, 0, AlignLeft, AlignBottom); | ||||||
|  |     set_icon(-1, -1, I_ButtonCenter_7x7); | ||||||
|  |     disable_timeout(); | ||||||
|  |     set_timeout(1000); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_callback(PopupCallback callback) { | ||||||
|  |     popup_set_callback(popup, callback); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_context(void* context) { | ||||||
|  |     popup_set_context(popup, context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { | ||||||
|  |     popup_set_header(popup, text, x, y, horizontal, vertical); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical) { | ||||||
|  |     popup_set_text(popup, text, x, y, horizontal, vertical); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_icon(int8_t x, int8_t y, IconName name) { | ||||||
|  |     popup_set_icon(popup, x, y, name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::set_timeout(uint32_t timeout_in_ms) { | ||||||
|  |     popup_set_timeout(popup, timeout_in_ms); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::enable_timeout() { | ||||||
|  |     popup_enable_timeout(popup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PopupVM::disable_timeout() { | ||||||
|  |     popup_enable_timeout(popup); | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								lib/app-scened-template/view-modules/popup-vm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/app-scened-template/view-modules/popup-vm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "generic-view-module.h" | ||||||
|  | #include <gui/modules/popup.h> | ||||||
|  | 
 | ||||||
|  | class PopupVM : public GenericViewModule { | ||||||
|  | public: | ||||||
|  |     PopupVM(); | ||||||
|  |     ~PopupVM() final; | ||||||
|  |     View* get_view() final; | ||||||
|  |     void clean() final; | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup header text | ||||||
|  |      * @param text - text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_callback(PopupCallback callback); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup context | ||||||
|  |      * @param context - context pointer, will be passed to result callback | ||||||
|  |      */ | ||||||
|  |     void set_context(void* context); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup header text | ||||||
|  |      * If text is null, popup header will not be rendered | ||||||
|  |      * @param text - text to be shown, can be multiline | ||||||
|  |      * @param x, y - text position | ||||||
|  |      * @param horizontal, vertical - text aligment | ||||||
|  |      */ | ||||||
|  |     void set_header(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup text | ||||||
|  |      * If text is null, popup text will not be rendered | ||||||
|  |      * @param text - text to be shown, can be multiline | ||||||
|  |      * @param x, y - text position | ||||||
|  |      * @param horizontal, vertical - text aligment | ||||||
|  |      */ | ||||||
|  |     void set_text(const char* text, uint8_t x, uint8_t y, Align horizontal, Align vertical); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup icon | ||||||
|  |      * If icon position is negative, popup icon will not be rendered | ||||||
|  |      * @param x, y - icon position | ||||||
|  |      * @param name - icon to be shown | ||||||
|  |      */ | ||||||
|  |     void set_icon(int8_t x, int8_t y, IconName name); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Set popup timeout | ||||||
|  |      * @param timeout_in_ms - popup timeout value in milliseconds | ||||||
|  |      */ | ||||||
|  |     void set_timeout(uint32_t timeout_in_ms); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Enable popup timeout | ||||||
|  |      */ | ||||||
|  |     void enable_timeout(); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * Disable popup timeout | ||||||
|  |      */ | ||||||
|  |     void disable_timeout(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Popup* popup; | ||||||
|  | }; | ||||||
							
								
								
									
										33
									
								
								lib/app-scened-template/view-modules/submenu-vm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/app-scened-template/view-modules/submenu-vm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | #include "submenu-vm.h" | ||||||
|  | 
 | ||||||
|  | SubmenuVM::SubmenuVM() { | ||||||
|  |     submenu = submenu_alloc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubmenuVM::~SubmenuVM() { | ||||||
|  |     submenu_free(submenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* SubmenuVM::get_view() { | ||||||
|  |     return submenu_get_view(submenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SubmenuVM::clean() { | ||||||
|  |     submenu_clean(submenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SubmenuItem* SubmenuVM::add_item( | ||||||
|  |     const char* label, | ||||||
|  |     uint32_t index, | ||||||
|  |     SubmenuItemCallback callback, | ||||||
|  |     void* callback_context) { | ||||||
|  |     return submenu_add_item(submenu, label, index, callback, callback_context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SubmenuVM::set_selected_item(uint32_t index) { | ||||||
|  |     submenu_set_selected_item(submenu, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void SubmenuVM::set_header(const char* header) { | ||||||
|  |     submenu_set_header(submenu, header); | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								lib/app-scened-template/view-modules/submenu-vm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								lib/app-scened-template/view-modules/submenu-vm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "generic-view-module.h" | ||||||
|  | #include <gui/modules/submenu.h> | ||||||
|  | 
 | ||||||
|  | class SubmenuVM : public GenericViewModule { | ||||||
|  | public: | ||||||
|  |     SubmenuVM(); | ||||||
|  |     ~SubmenuVM() final; | ||||||
|  |     View* get_view() final; | ||||||
|  |     void clean() final; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Add item to submenu | ||||||
|  |      *  | ||||||
|  |      * @param label - menu item label | ||||||
|  |      * @param index - menu item index, used for callback, may be the same with other items | ||||||
|  |      * @param callback - menu item callback | ||||||
|  |      * @param callback_context - menu item callback context | ||||||
|  |      * @return SubmenuItem instance that can be used to modify or delete that item | ||||||
|  |      */ | ||||||
|  |     SubmenuItem* add_item( | ||||||
|  |         const char* label, | ||||||
|  |         uint32_t index, | ||||||
|  |         SubmenuItemCallback callback, | ||||||
|  |         void* callback_context); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Set submenu item selector | ||||||
|  |      *  | ||||||
|  |      * @param index index of the item to be selected | ||||||
|  |      */ | ||||||
|  |     void set_selected_item(uint32_t index); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Set optional header for submenu | ||||||
|  |      *  | ||||||
|  |      * @param header header to set | ||||||
|  |      */ | ||||||
|  |     void set_header(const char* header); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Submenu* submenu; | ||||||
|  | }; | ||||||
							
								
								
									
										30
									
								
								lib/app-scened-template/view-modules/text-input-vm.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/app-scened-template/view-modules/text-input-vm.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #include "text-input-vm.h" | ||||||
|  | 
 | ||||||
|  | TextInputVM::TextInputVM() { | ||||||
|  |     text_input = text_input_alloc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | TextInputVM::~TextInputVM() { | ||||||
|  |     text_input_free(text_input); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* TextInputVM::get_view() { | ||||||
|  |     return text_input_get_view(text_input); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextInputVM::clean() { | ||||||
|  |     set_result_callback(NULL, NULL, NULL, 0); | ||||||
|  |     set_header_text(""); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextInputVM::set_result_callback( | ||||||
|  |     TextInputCallback callback, | ||||||
|  |     void* callback_context, | ||||||
|  |     char* text, | ||||||
|  |     uint8_t max_text_length) { | ||||||
|  |     text_input_set_result_callback(text_input, callback, callback_context, text, max_text_length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextInputVM::set_header_text(const char* text) { | ||||||
|  |     text_input_set_header_text(text_input, text); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								lib/app-scened-template/view-modules/text-input-vm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								lib/app-scened-template/view-modules/text-input-vm.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "generic-view-module.h" | ||||||
|  | #include <gui/modules/text_input.h> | ||||||
|  | 
 | ||||||
|  | class TextInputVM : public GenericViewModule { | ||||||
|  | public: | ||||||
|  |     TextInputVM(); | ||||||
|  |     ~TextInputVM() final; | ||||||
|  |     View* get_view() final; | ||||||
|  |     void clean() final; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * @brief Set text input result callback | ||||||
|  |      *  | ||||||
|  |      * @param callback - callback fn | ||||||
|  |      * @param callback_context - callback context | ||||||
|  |      * @param text - text buffer to use | ||||||
|  |      * @param max_text_length - text buffer length | ||||||
|  |      */ | ||||||
|  |     void set_result_callback( | ||||||
|  |         TextInputCallback callback, | ||||||
|  |         void* callback_context, | ||||||
|  |         char* text, | ||||||
|  |         uint8_t max_text_length); | ||||||
|  | 
 | ||||||
|  |     /** 
 | ||||||
|  |      * @brief Set text input header text | ||||||
|  |      *  | ||||||
|  |      * @param text - text to be shown | ||||||
|  |      */ | ||||||
|  |     void set_header_text(const char* text); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     TextInput* text_input; | ||||||
|  | }; | ||||||
| @ -94,4 +94,9 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/irda/*/*.c) | |||||||
| 
 | 
 | ||||||
| #args lib
 | #args lib
 | ||||||
| CFLAGS			+= -I$(LIB_DIR)/args | CFLAGS			+= -I$(LIB_DIR)/args | ||||||
| C_SOURCES		+= $(wildcard $(LIB_DIR)/args/*.c) | C_SOURCES		+= $(wildcard $(LIB_DIR)/args/*.c) | ||||||
|  | 
 | ||||||
|  | #scened app template lib
 | ||||||
|  | CFLAGS			+= -I$(LIB_DIR)/app-scened-template | ||||||
|  | CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*.cpp) | ||||||
|  | CPP_SOURCES		+= $(wildcard $(LIB_DIR)/app-scened-template/*/*.cpp) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 SG
						SG