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 app_archive(void* p); | ||||
| int32_t notification_app(void* p); | ||||
| int32_t scened_app(void* p); | ||||
| 
 | ||||
| // On system start hooks declaration
 | ||||
| void irda_cli_init(); | ||||
| @ -293,6 +294,10 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = { | ||||
|      .stack_size = 1024, | ||||
|      .icon = A_Plugins_14}, | ||||
| #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); | ||||
|  | ||||
| @ -46,7 +46,7 @@ void byte_input_free(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 input_callback input callback fn | ||||
|  | ||||
| @ -9,23 +9,31 @@ extern "C" { | ||||
| typedef struct TextInput TextInput; | ||||
| 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(); | ||||
| 
 | ||||
| /* Deinitialize and free text input
 | ||||
| /** 
 | ||||
|  * @brief Deinitialize and free text input | ||||
|  *  | ||||
|  * @param text_input - Text input instance | ||||
|  */ | ||||
| void text_input_free(TextInput* text_input); | ||||
| 
 | ||||
| /* Get text input view
 | ||||
| /**
 | ||||
|  * @brief Get text input view | ||||
|  *  | ||||
|  * @param text_input - Text input instance | ||||
|  * @return View instance that can be used for embedding | ||||
|  */ | ||||
| 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 callback - callback fn | ||||
|  * @param callback_context - callback context | ||||
| @ -39,7 +47,9 @@ void text_input_set_result_callback( | ||||
|     char* text, | ||||
|     uint8_t max_text_length); | ||||
| 
 | ||||
| /* Set text input header text
 | ||||
| /** 
 | ||||
|  * @brief Set text input header text | ||||
|  *  | ||||
|  * @param text input - Text input instance | ||||
|  * @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/valuemutex.h> | ||||
| #include <furi/log.h> | ||||
| #include <furi/common_defines.h> | ||||
| 
 | ||||
| #include <api-hal-gpio.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
 | ||||
| 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