Graphic User Interface
This article includes details on how MuditaOS widgets are rendered and how the GUI handles key pressing.
Introduction
How widgets are rendered
- All widgets are children of
gui::Item - There are two major commands to trigger screen redraw:
gui::Item::buildDrawListin eachgui::Item- usesgui::Items tree to builds draw commandsapp::Application::refreshWindowinapp::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::Itemcallbacks, which are in [callbacks](@ref callbacks "Item callbacks"), orgui::Itemvirtual functions, [callback functions](@ref callbackCallers) When overriding please mind that you might want to use ancestor function inside too to i.e. not loose key presses etc.
- All
gui::Itemare able to handle keyPresses viagui::InputEvent - All
gui::Itemare able to traverse down on theirgui::Item::childrenand know which child hasgui::Item::focusItemat the time
How does it work on the application side
Please see app::Application, app::manager::ApplicationManager for detailed information on how messages are handled between both. This is just general documentation.
These actions are done on a chained bus request between: app::Application, app::manager::ApplicationManager and sapm::EventWorker
All of these are asynchronous and there is little state machine maintenance.
app::Applicationhas it's own state which is managed both in application and in manager (via setters and getters)sapm::ApplicationManagerhas it's own state which tells what exactly it's processing right now
Note: All app::Application:
- Register and initialize their windows on start of the application in
app::Application::createUserInterface - Need to pass
app::Application::DataReceivedHandlerfirst to parent function call to properly handle bus messages - Have windows based on
gui::AppWindow
Note: When it comes to gui::AppWindow:
gui::AppWindow::buildInterfacehas to call parent build interface first. Otherwise elements for child won't be created and it will crashgui::AppWindow::onInputhas to call parentonInput, otherwise handling key presses will fail- Applications react on key releases actions, in most scenarios key press event is useless
- all applications, if it hasn't been overriden in
gui::AppWindowwill try to return to previous window or application onback
gui::Item Key Press handling
What happens when you press a key?
bsphandles key press on I2C IRQ and sends Event to event worker on naked FreeRTOS pipe (on target RT1051, on Linuxgtkdoes that)EventWorkerworker ofEventService:- handles the press and sends it to current Application
- with focus (Note: when no application is in focus this will not work)
- application can either:
- process
gui::InputEventwithRawKeyorgui::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::InputModeand process key press however they want
- process
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 callsinputCallback; if handled here, other calls wont be calledgui::Item::inputCallback- handles any keygui::Item::activatedCallback- handles Enter key onlygui::Item::itemNavigation- handles up,down,left,right if next/previous elements are added for an item
Note: return True when any of callbacks ends processing the whole Items tree
There are 2 set of parameters for key press:
gui::InputEvent::State- state of key (pressed, released, long released). In general applications handle key releases not pressesgui::KeyCode- initially parsed key codegui::RawKey- raw key code, to be processed in widget based on event i.e. translate pressing key13 times into C ingui::TextmodeABC
How to add key mapping when basic key maps are not enough?
- Key maps are specific key translation mappings. i.e. press
13 times to get C, press14 times to get A, etc. - basic key maps are stored in:
InputMode, right now there are followingInputMode::Modes: [ABC,abc,digit,phone] - key maps in
gui::InputModeare changed in regards of language settings
How to add a new key map, i.e. phone
- Add new file for your key map:
cp image/assets/profiles/template.kprof image/assets/profiles/phone.kprof - Change your template accordingly
- Pin new key map = add it to language support, add:
"common_kbd_phone": "phone"to at leastimage/assets/lang/lang_en.jsonif it will differ per language, prepare onekproffile per language - Add new key map to
gui::InputMode- Add
InputMode::Modeenum i.e.InputMode::Mode::phone - Add new Mode to input mode mapping in
InputMode.cpp(same as with other enums) - Test new added mode in:
UITestWindow.cpp - Test new key map on phone
- Add
- Load key map to phone
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.