[](NOTE: This file is prepared for doxygen markdown, it should look just ok with normal markdown, but some links might not work) UI README ========= @tableofcontents schematics parts used: * `[name : part]` - name of module : part of code responsible * `=> / <=>` - direction of communication * `<>` event on diagrams, name placeholder of element in text # introduction ## How widgets are rendered Our UI is split into: ``` [bsp] <=> [renderer] <=> [application : widgets] ``` * All widgets are children of `gui::Item` * There are two major commands to trigger screen redraw: * `gui::Item::buildDrawList` in each `gui::Item` - uses `gui::Item`s tree to builds draw commands * `app::Application::refreshWindow` in `app::Application` - triggers update on display on message: `gui::AppRefreshMessage` (final draw on screen done with: `app::Application::render`) * All interface actions can be made with either: * `gui::Item` callbacks, which are in [callbacks](@ref callbacks "Item callbacks") * `gui::Item` virtual functions, [callback functions](@ref callbackCallers) When overriding please mind that you might want to use ancestor function inside too. I.e. to not loose key presses etc. * All `gui::Item` are able to handle keyPresses via `gui::InputEvent` * All `gui::Item` are able to traverse down on their `gui::Item::children` and know which child have `gui::Item::focusItem` at the time ## How does it work from application Please see `app::Application`, `sapm::ApplicationManager` for detailed information on how messages are handled between both. This is jus overall documentation. ``` [ApplicationManager] [Application] <=> START <=> <=> Set focus <=> <=> Set keyboard <=> <=> Put background <=> <=> kill <=> ``` These actions are done on chained bus request between: `app::Application`, `sapm::ApplicationManager` and `sapm::EventWorker` There all of these are asynchronous and there is little state machine maintenance. 1. `app::Application` has it's own state which is managed both in application and in manager (via setters and getters) 2. `sapm::ApplicationManager` has it's own state which tells what exactly it's processing right now *Important* all `app::Application` 1. register and initialize their windows on start of application in `app::Application::createUserInterface` 2. need to pass `app::Application::DataReceivedHandler` first to parent function call to properly handle bus messages 3. have windows based on `gui::AppWindow` *Important* `gui::AppWindow` 1. `gui::AppWindow::buildInterface` has to call parent build interface first. Otherwise elements for child won't be created and it will crash 2. `gui::AppWindow::onInput` has to call parent onInput, otherwise handling key presses might and most probably will fail 3. Applications react on key *releases* actions, in most scenarios key press event is useless. 4. All applications, if it wasn't overriden in `gui::AppWindow` will try to return to previous window or application on `back` # gui::Item key press handling ## What happens when you press the key? ``` [bsp] => [EventWorker : basic key translation] < key press event> => [Application with focus] ``` * bsp handles key press on I2C IRQ and sends Event to event worker on naked freertos pipe (on target rt1051, on linux gtk does that) * EventWorker worker of EventService * handles the press sends it to current Application * with focus **warning** when no application with focus this will stuck * application can either: * process `gui::InputEvent` with `RawKey` or `gui::KeyInputSimpleTranslation` * use callbacks see how to handle key press below * use widgets which override default key handling (see `gui::Item::onInput`) * have own `gui::KeyInputMappedTranslation` + `gui::InputMode` and process key however they want ## How to handle key press There are at least 3 ways to handle key press, listed in order of execution. * `gui::Item::onInput` - if not redefined calls inputCallback, if handled here, other calls wont be called * `gui::Item::inputCallback` - handles any key * `gui::Item::activatedCallback` - handles enter only * `gui::Item::itemNavigation` - handles up,down,left,right if next/previous elements are added for item **return true in any of callbacks ends processing for whole Items tree** There are 2 set of parameters for key press: * `gui::InputEvent::State` - tate of key, pressed, released, long released. In generall applications handle *releases* not presses! * `gui::KeyCode` - initially parsed key code * `gui::RawKey` - raw key code, to be processed in widget based on event. ( i.e. Translate 3 times 1 press to C in `gui::Text` mode `ABC`) ## How to add key mapping when basic key maps are not enough? * Key maps are specific key translation mappings. I.e. 3 times press 1 to get C, 4 times press 1 to get A etc. * basic key maps are stored in: `InputMode`, right now there are `InputMode::Mode`s: [ABC, abc, digit, phone] * key maps in `gui::InputMode` are changed in regards of lang settings ### To add new key map, i.e. phone 1. Add new file for your key map: `cp image/assets/profiles/template.kprof image/assets/profiles/phone.kprof` 2. change your template according to your desires 3. Pin new key map = add it to language support, add: `"common_kbd_phone": "phone"` to at least `image/assets/lang/lang_en.json` if it will differ per language, prepare one kprof per language 4. Add new key map to `gui::InputMode` 1. add `InputMode::Mode` enum i.e. `InputMode::Mode::phone` 2. add new Mode to input mode mapping in `InputMode.cpp` (same as with other enums) 3. test new added mode in: `UITestWindow.cpp` 4. test new key map on phone 5. load key map to phone, as you probably forgot Now you can use `InputMode::Mode::phone` translation in `gui::Text` widget. This means `gui::Text` will automatically change text on key press for you same as in modes `InputMode::Mode::phone` etc.