23#include "os_io_seph_cmd.h"
24#include "os_io_seph_ux.h"
26#include "os_helpers.h"
31#if defined(TARGET_FLEX)
32#define USE_PARTIAL_BUTTONS 1
38#ifdef USE_PARTIAL_BUTTONS
44#ifndef USE_PARTIAL_BUTTONS
51#if defined(TARGET_STAX)
52#define TEXT_ENTRY_NORMAL_HEIGHT 64
53#define TEXT_ENTRY_COMPACT_HEIGHT 64
54#define BOTTOM_NORMAL_MARGIN 24
55#define BOTTOM_COMPACT_MARGIN 24
56#define TOP_NORMAL_MARGIN 20
57#define TOP_COMPACT_MARGIN 20
58#elif defined(TARGET_FLEX)
59#define TEXT_ENTRY_NORMAL_HEIGHT 72
60#define TEXT_ENTRY_COMPACT_HEIGHT 56
61#define BOTTOM_NORMAL_MARGIN 24
62#define BOTTOM_COMPACT_MARGIN 12
63#define TOP_NORMAL_MARGIN 20
64#define TOP_COMPACT_MARGIN 12
67#ifdef USE_PARTIAL_BUTTONS
68#if defined(TARGET_FLEX)
69#define LEFT_HALF_ICON C_left_half_64px
74#define LINE_REAL_HEIGHT 4
76#define NUMBER_WIDTH 56
79#define NUMBER_TEXT_SPACE 8
93static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS];
94static char numText[5];
95static uint8_t nbActiveButtons;
96#ifdef USE_PARTIAL_BUTTONS
108 uint8_t currentLeftButtonIndex)
110 bool needRefresh =
false;
115 && (currentLeftButtonIndex
116 < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
119 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
121 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex];
123 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
124 if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
126 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
132 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
136 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
139 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
140 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
142 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
144 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
162#ifndef USE_PARTIAL_BUTTONS
184 indicator->activePage = page;
186#ifdef USE_PARTIAL_BUTTONS
188 if (currentLeftButtonIndex > 0) {
189 container->children[LEFT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[0];
192 container->children[LEFT_HALF_INDEX] = NULL;
195 if (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
196 container->children[RIGHT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[1];
199 container->children[RIGHT_HALF_INDEX] = NULL;
214 if ((container->nbChildren < 2) || (container->children[1]->type !=
CONTAINER)) {
221 && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
223 while (i < (uint32_t) nbActiveButtons) {
231 if (i < (uint32_t) nbActiveButtons) {
232 if (updateSuggestionButtons(suggestionsContainer, eventType, i)) {
233 os_io_seph_cmd_piezo_play_tune(TUNE_TAP_CASUAL);
256 uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
260 container->nbChildren = 4;
263 container->obj.alignment =
CENTER;
268 textArea->textColor =
BLACK;
269 textArea->text = title;
270 textArea->textAlignment =
CENTER;
271 textArea->fontId = SMALL_REGULAR_FONT;
272 textArea->wrapping =
true;
276 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
277 container->children[0] = (
nbgl_obj_t *) textArea;
278 container->obj.area.height = textArea->obj.area.height + 4;
284 textArea->textColor =
BLACK;
285 snprintf(numText,
sizeof(numText),
"%d.", number);
286 textArea->text = numText;
287 textArea->textAlignment =
CENTER;
288 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
292 textArea->obj.alignTo = container->children[0];
301 container->children[1] = (
nbgl_obj_t *) textArea;
307 textArea->text = text;
309 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
312 textArea->obj.alignTo = container->children[0];
322 textArea->obj.area.width -= textArea->obj.alignmentMarginX;
325 textArea->autoHideLongLine =
true;
331 textArea->obj.touchMask = (1 <<
TOUCHED);
333 container->children[2] = (
nbgl_obj_t *) textArea;
334 container->obj.area.height += textEntryHeight;
353 uint8_t nbUsedButtons,
354 const char **buttonTexts,
355 int firstButtonToken,
362 nbActiveButtons = nbUsedButtons;
364 suggestionsContainer->layout =
VERTICAL;
365 suggestionsContainer->obj.area.width = SCREEN_WIDTH;
366#ifndef USE_PARTIAL_BUTTONS
368 suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT +
INTERNAL_MARGIN + 28;
371 suggestionsContainer->obj.area.height = SMALL_BUTTON_HEIGHT + 28;
374 suggestionsContainer->children
378 suggestionsContainer->obj.alignmentMarginY
379 = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
385 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
387 layoutInt, (
nbgl_obj_t *) choiceButtons[i], firstButtonToken + i, tuneId);
392 choiceButtons[i]->innerColor =
BLACK;
393 choiceButtons[i]->borderColor =
BLACK;
394 choiceButtons[i]->foregroundColor =
WHITE;
396 choiceButtons[i]->obj.area.height = SMALL_BUTTON_HEIGHT;
397 choiceButtons[i]->radius = SMALL_BUTTON_RADIUS_INDEX;
398 choiceButtons[i]->fontId = SMALL_BOLD_1BPP_FONT;
399 choiceButtons[i]->text = buttonTexts[i];
400 choiceButtons[i]->obj.touchMask = (1 <<
TOUCHED);
403 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
412 indicator->activePage = 0;
413 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
414 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
415 indicator->obj.area.width = 184;
419#ifdef USE_PARTIAL_BUTTONS
423 partialButtonImages[0]->buffer = &LEFT_HALF_ICON;
424 partialButtonImages[0]->obj.alignment =
TOP_LEFT;
425 partialButtonImages[0]->foregroundColor =
BLACK;
427 partialButtonImages[1]->buffer = &LEFT_HALF_ICON;
428 partialButtonImages[1]->obj.alignment =
TOP_RIGHT;
429 partialButtonImages[1]->foregroundColor =
BLACK;
431 updateSuggestionButtons(suggestionsContainer, 0, 0);
434 return suggestionsContainer;
454 button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
456 button->foregroundColor =
WHITE;
458 button->innerColor =
BLACK;
459 button->borderColor =
BLACK;
460 button->obj.touchMask = (1 <<
TOUCHED);
467 button->text = PIC(text);
468 button->fontId = SMALL_BOLD_1BPP_FONT;
470 button->obj.area.height = BUTTON_DIAMETER;
471 button->radius = BUTTON_RADIUS;
493 if (layout == NULL) {
503 keyboard->obj.area.width = SCREEN_WIDTH;
504 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
506 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
509 keyboard->obj.alignmentMarginY = 56;
513 keyboard->callback = PIC(kbdInfo->
callback);
515 keyboard->mode = kbdInfo->
mode;
516 keyboard->keyMask = kbdInfo->
keyMask;
517 keyboard->casing = kbdInfo->
casing;
527 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
566 if (layout == NULL) {
573 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
576 keyboard->keyMask = keyMask;
578 keyboard->casing = casing;
599 if (layout == NULL) {
606 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
609 if (keyboard->needsRefresh) {
610 keyboard->needsRefresh =
false;
630 uint8_t nbUsedButtons,
631 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS],
632 int firstButtonToken,
638 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
641 if (layout == NULL) {
645 container = addSuggestionButtons(
646 layoutInt, nbUsedButtons, buttonTexts, firstButtonToken, tuneId,
false);
649 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
651 ->obj.alignmentMarginY
652 -= (container->obj.area.height + container->obj.alignmentMarginY + 20) / 2;
654#ifdef USE_PARTIAL_BUTTONS
668 return (layoutInt->
container->nbChildren - 1);
684 uint8_t nbUsedButtons,
685 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
689 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
692 if (layout == NULL) {
698 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
701 nbActiveButtons = nbUsedButtons;
705 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
706 choiceButtons[i]->text = buttonTexts[i];
708 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbUsedButtons)) {
710 choiceButtons[i]->obj.alignmentMarginX = BORDER_MARGIN;
711#ifndef USE_PARTIAL_BUTTONS
719 choiceButtons[i]->obj.alignment =
TOP_LEFT;
725 choiceButtons[i]->obj.alignment =
MID_RIGHT;
726 choiceButtons[i]->obj.alignTo = (
nbgl_obj_t *) choiceButtons[i - 1];
734 container->forceClean =
true;
735#ifdef USE_PARTIAL_BUTTONS
739 indicator->nbPages = (nbUsedButtons + 1) / 2;
740 indicator->activePage = 0;
741 updateSuggestionButtons(container, 0, 0);
776 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
777 bool compactMode = ((layoutInt->
container->children[enteredTextIndex + 1] != NULL)
778 && (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON)
779 && (layoutInt->
container->nbChildren == 3));
782 if (layout == NULL) {
788 = addTextEntry(layoutInt, NULL, text, numbered, number, grayedOut, token, compactMode);
793 if (layoutInt->
container->children[enteredTextIndex + 1] != NULL) {
794 if (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON) {
797 container->obj.alignmentMarginY
798 -= (button->obj.area.height + button->obj.alignmentMarginY
799 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
805 container->obj.alignmentMarginY
806 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
807 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
813 if (layoutInt->
container->nbChildren == 3) {
814 container->obj.alignmentMarginY += layoutInt->
container->children[0]->area.height / 2;
844 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
847 if (layout == NULL) {
854 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
858 if ((textArea == NULL) || (textArea->obj.type !=
TEXT_AREA)) {
861 textArea->text = text;
870 snprintf(numText,
sizeof(numText),
"%d.", number);
871 textArea->text = numText;
900 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
901 bool compactMode = (layoutInt->
container->nbChildren == 3);
904 if (layout == NULL) {
908 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
911 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
913 ->obj.alignmentMarginY
914 -= (button->obj.area.height + button->obj.alignmentMarginY
915 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
940 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
945 if (layout == NULL) {
951 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
957 button->innerColor =
BLACK;
958 button->borderColor =
BLACK;
959 button->obj.touchMask = (1 <<
TOUCHED);
985 if (layout == NULL) {
989 container = addTextEntry(layoutInt,
1003 = addSuggestionButtons(layoutInt,
1019 container->obj.alignmentMarginY
1020 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1021 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1033 container->obj.alignmentMarginY
1034 -= (button->obj.area.height + button->obj.alignmentMarginY
1035 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1039 return layoutInt->
container->obj.area.height;
1059 if (layout == NULL) {
1069 snprintf(numText,
sizeof(numText),
"%d.", content->
number);
1076 textArea->text = content->
text;
1086 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1089 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
1097 suggestionsContainer->forceClean =
true;
1102 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1103 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1104 indicator->activePage = 0;
1105 updateSuggestionButtons(suggestionsContainer, 0, 0);
1112 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
1118 button->innerColor =
BLACK;
1119 button->borderColor =
BLACK;
1120 button->obj.touchMask = (1 <<
TOUCHED);
#define LOG_DEBUG(__logger,...)
Middle Level API of the new BOLOS Graphical Library.
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text until the first or \0 is encountered
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
Font screen low-Level driver API, to draw elementary forms.
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the main container
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
void * nbgl_layout_t
type shared externally
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
Internal functions/constants of NBGL layout layer.
@ SWIPE_USAGE_SUGGESTIONS
#define KEYBOARD_FOOTER_TYPE
int nbgl_layoutUpdateKeyboard(nbgl_layout_t *layout, uint8_t index, uint32_t keyMask, bool updateCasing, keyboardCase_t casing)
Updates an existing keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInfo)
Creates a keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutAddSuggestionButtons(nbgl_layout_t *layout, uint8_t nbUsedButtons, const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS], int firstButtonToken, tune_index_e tuneId)
Adds up to 4 black suggestion buttons under the previously added object.
bool keyboardSwipeCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
int nbgl_layoutUpdateSuggestionButtons(nbgl_layout_t *layout, uint8_t index, uint8_t nbUsedButtons, const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
Updates the number and/or the text suggestion buttons created with nbgl_layoutAddSuggestionButtons()
int nbgl_layoutAddKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
Adds an area containing a potential title, a text entry and either confirmation or suggestion buttons...
int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, bool numbered, uint8_t number, const char *text, bool grayedOut, int offsetY, int token)
Adds a "text entry" area under the previously entered object. This area can be preceded (beginning of...
int nbgl_layoutUpdateConfirmationButton(nbgl_layout_t *layout, uint8_t index, bool active, const char *text)
Updates an existing black full width confirmation button on top of the previously added keyboard.
int nbgl_layoutUpdateEnteredText(nbgl_layout_t *layout, uint8_t index, bool numbered, uint8_t number, const char *text, bool grayedOut)
Updates an existing "text entry" area, created with nbgl_layoutAddEnteredText()
int nbgl_layoutUpdateKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
Updates an area containing a potential title, a text entry and either confirmation or suggestion butt...
#define NUMBER_TEXT_SPACE
int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout, bool active, const char *text, int token, tune_index_e tuneId)
Adds a black full width confirmation button on top of the previously added keyboard.
bool nbgl_layoutKeyboardNeedsRefresh(nbgl_layout_t *layout, uint8_t index)
function called to know whether the keyboard has been redrawn and needs a refresh
API to draw all basic graphic objects.
struct PACKED__ nbgl_line_s nbgl_line_t
struct to represent a vertical or horizontal line
struct PACKED__ nbgl_navigation_bar_s nbgl_page_indicator_t
struct to represent a navigation bar (PAGE_INDICATOR type) There can be up to 5 page indicators,...
struct PACKED__ nbgl_text_area_s nbgl_text_area_t
struct to represent a text area (TEXT_AREA type)
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
Gets a new container from the pool, with the given number of obj pointers.
keyboardCase_t
Letters casing in which to open/set the keyboard.
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
Gets a new graphic object from the pool, with the given type. The type field of the object is set.
struct PACKED__ nbgl_keyboard_s nbgl_keyboard_t
struct to represent a keyboard (KEYBOARD type)
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
int nbgl_objPoolGetArray(nbgl_obj_type_t type, uint8_t nbObjs, uint8_t layer, nbgl_obj_t **objArray)
Gets nbObjects new graphic object from the pool, with the given type, for the given layer (screen)....
struct PACKED__ nbgl_button_s nbgl_button_t
struct to represent a button (BUTTON type) that can contain a text and/or an icon
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
@ CURRENT_INDICATOR
only current page dash is black
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
nbgl_touchType_t
The different types of Touchscreen events.
@ VERTICAL
from top to bottom
@ HORIZONTAL
from left to right
@ NO_ALIGNMENT
used when parent container layout is used
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
@ BUTTON
Rounded rectangle button with icon and/or text.
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
@ LINE
Vertical or Horizontal line.
@ CONTAINER
Empty container.
@ TEXT_AREA
Area to contain text line(s)
#define NO_TRANSFORMATION
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Structure containing all information about the current layout.
nbgl_container_t * footerContainer
container used to store footer (buttons, nav....)
uint8_t layer
layer in screen stack
nbgl_swipe_usage_t swipeUsage
nbgl_container_t * container
nbgl_layoutFooterType_t footerType
type of footer
nbgl_obj_t ** children
children for main screen
This structure contains info to build a keyboard with nbgl_layoutAddKeyboard()
bool lettersOnly
if true, only display letter keys and Backspace
keyboardCallback_t callback
function called when an active key is pressed
keyboardMode_t mode
keyboard mode to start with
keyboardCase_t casing
keyboard casing mode (lower, upper once or upper locked)
This structure contains info to build a keyboard content (controls that are linked to keyboard)
uint8_t number
if numbered is true, number used to build 'number.' text
const char * text
already entered text
nbgl_layoutKeyboardContentType_t type
type of content
nbgl_layoutSuggestionButtons_t suggestionButtons
nbgl_layoutConfirmationButton_t confirmationButton
used if type is KEYBOARD_WITH_SUGGESTIONS
const char * title
centered title explaining the screen
bool numbered
if set to true, the text is preceded on the left by 'number.'
bool grayedOut
if true, the text is grayed out (but not the potential number)