23#include "os_helpers.h"
28#if defined(TARGET_FLEX)
29#define USE_PARTIAL_BUTTONS 1
35#ifdef USE_PARTIAL_BUTTONS
41#ifndef USE_PARTIAL_BUTTONS
48#if defined(TARGET_STAX)
49#define TEXT_ENTRY_NORMAL_HEIGHT 64
50#define TEXT_ENTRY_COMPACT_HEIGHT 64
51#define BOTTOM_NORMAL_MARGIN 24
52#define BOTTOM_COMPACT_MARGIN 24
53#define TOP_NORMAL_MARGIN 20
54#define TOP_COMPACT_MARGIN 20
55#elif defined(TARGET_FLEX)
56#define TEXT_ENTRY_NORMAL_HEIGHT 72
57#define TEXT_ENTRY_COMPACT_HEIGHT 56
58#define BOTTOM_NORMAL_MARGIN 24
59#define BOTTOM_COMPACT_MARGIN 12
60#define TOP_NORMAL_MARGIN 20
61#define TOP_COMPACT_MARGIN 12
64#ifdef USE_PARTIAL_BUTTONS
65#if defined(TARGET_FLEX)
66#define LEFT_HALF_ICON C_left_half_64px
71#define LINE_REAL_HEIGHT 4
73#define NUMBER_WIDTH 56
76#define NUMBER_TEXT_SPACE 8
90static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS];
91static char numText[5];
93#ifdef USE_PARTIAL_BUTTONS
105 uint8_t currentLeftButtonIndex)
107 bool needRefresh =
false;
112 && (currentLeftButtonIndex
113 < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
116 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
118 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex];
120 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
121 if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
123 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
129 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
133 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
136 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
137 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
139 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
141 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
159#ifndef USE_PARTIAL_BUTTONS
181 indicator->activePage = page;
183#ifdef USE_PARTIAL_BUTTONS
185 if (currentLeftButtonIndex > 0) {
186 container->children[LEFT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[0];
189 container->children[LEFT_HALF_INDEX] = NULL;
192 if (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
193 container->children[RIGHT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[1];
196 container->children[RIGHT_HALF_INDEX] = NULL;
211 if ((container->nbChildren < 2) || (container->children[1]->type !=
CONTAINER)) {
218 && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
220 while (i < (uint32_t) nbActiveButtons) {
228 if (i < (uint32_t) nbActiveButtons) {
229 if (updateSuggestionButtons(suggestionsContainer, eventType, i)) {
230 io_seproxyhal_play_tune(TUNE_TAP_CASUAL);
253 uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
257 container->nbChildren = 4;
260 container->obj.alignment =
CENTER;
265 textArea->textColor =
BLACK;
266 textArea->text = title;
267 textArea->textAlignment =
CENTER;
268 textArea->fontId = SMALL_REGULAR_FONT;
269 textArea->wrapping =
true;
273 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
274 container->children[0] = (
nbgl_obj_t *) textArea;
275 container->obj.area.height = textArea->obj.area.height + 4;
281 textArea->textColor =
BLACK;
282 snprintf(numText,
sizeof(numText),
"%d.", number);
283 textArea->text = numText;
284 textArea->textAlignment =
CENTER;
285 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
289 textArea->obj.alignTo = container->children[0];
298 container->children[1] = (
nbgl_obj_t *) textArea;
304 textArea->text = text;
306 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
309 textArea->obj.alignTo = container->children[0];
319 textArea->obj.area.width -= textArea->obj.alignmentMarginX;
322 textArea->autoHideLongLine =
true;
328 textArea->obj.touchMask = (1 <<
TOUCHED);
330 container->children[2] = (
nbgl_obj_t *) textArea;
331 container->obj.area.height += textEntryHeight;
351 const char **buttonTexts,
352 int firstButtonToken,
359 nbActiveButtons = nbUsedButtons;
361 suggestionsContainer->layout =
VERTICAL;
362 suggestionsContainer->obj.area.width = SCREEN_WIDTH;
363#ifndef USE_PARTIAL_BUTTONS
365 suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT +
INTERNAL_MARGIN + 28;
368 suggestionsContainer->obj.area.height = SMALL_BUTTON_HEIGHT + 28;
371 suggestionsContainer->children
375 suggestionsContainer->obj.alignmentMarginY
376 = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
382 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
384 layoutInt, (
nbgl_obj_t *) choiceButtons[i], firstButtonToken + i, tuneId);
389 choiceButtons[i]->innerColor =
BLACK;
390 choiceButtons[i]->borderColor =
BLACK;
391 choiceButtons[i]->foregroundColor =
WHITE;
393 choiceButtons[i]->obj.area.height = SMALL_BUTTON_HEIGHT;
394 choiceButtons[i]->radius = SMALL_BUTTON_RADIUS_INDEX;
395 choiceButtons[i]->fontId = SMALL_BOLD_1BPP_FONT;
396 choiceButtons[i]->text = buttonTexts[i];
397 choiceButtons[i]->obj.touchMask = (1 <<
TOUCHED);
400 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
409 indicator->activePage = 0;
410 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
411 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
412 indicator->obj.area.width = 184;
416#ifdef USE_PARTIAL_BUTTONS
420 partialButtonImages[0]->buffer = &LEFT_HALF_ICON;
421 partialButtonImages[0]->obj.alignment =
TOP_LEFT;
422 partialButtonImages[0]->foregroundColor =
BLACK;
424 partialButtonImages[1]->buffer = &LEFT_HALF_ICON;
425 partialButtonImages[1]->obj.alignment =
TOP_RIGHT;
426 partialButtonImages[1]->foregroundColor =
BLACK;
428 updateSuggestionButtons(suggestionsContainer, 0, 0);
431 return suggestionsContainer;
451 button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
453 button->foregroundColor =
WHITE;
455 button->innerColor =
BLACK;
456 button->borderColor =
BLACK;
457 button->obj.touchMask = (1 <<
TOUCHED);
464 button->text = PIC(text);
465 button->fontId = SMALL_BOLD_1BPP_FONT;
467 button->obj.area.height = BUTTON_DIAMETER;
468 button->radius = BUTTON_RADIUS;
490 if (layout == NULL) {
500 keyboard->obj.area.width = SCREEN_WIDTH;
501 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
503 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
506 keyboard->obj.alignmentMarginY = 56;
510 keyboard->callback = PIC(kbdInfo->
callback);
512 keyboard->mode = kbdInfo->
mode;
513 keyboard->keyMask = kbdInfo->
keyMask;
514 keyboard->casing = kbdInfo->
casing;
524 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
563 if (layout == NULL) {
570 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
573 keyboard->keyMask = keyMask;
575 keyboard->casing = casing;
596 if (layout == NULL) {
603 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
606 if (keyboard->needsRefresh) {
607 keyboard->needsRefresh =
false;
628 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS],
629 int firstButtonToken,
638 if (layout == NULL) {
642 container = addSuggestionButtons(
643 layoutInt, nbUsedButtons, buttonTexts, firstButtonToken, tuneId,
false);
646 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
648 ->obj.alignmentMarginY
649 -= (container->obj.area.height + container->obj.alignmentMarginY + 20) / 2;
651#ifdef USE_PARTIAL_BUTTONS
665 return (layoutInt->
container->nbChildren - 1);
682 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
689 if (layout == NULL) {
695 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
698 nbActiveButtons = nbUsedButtons;
702 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
703 choiceButtons[i]->text = buttonTexts[i];
705 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbUsedButtons)) {
707 choiceButtons[i]->obj.alignmentMarginX = BORDER_MARGIN;
708#ifndef USE_PARTIAL_BUTTONS
716 choiceButtons[i]->obj.alignment =
TOP_LEFT;
722 choiceButtons[i]->obj.alignment =
MID_RIGHT;
723 choiceButtons[i]->obj.alignTo = (
nbgl_obj_t *) choiceButtons[i - 1];
731 container->forceClean =
true;
732#ifdef USE_PARTIAL_BUTTONS
736 indicator->nbPages = (nbUsedButtons + 1) / 2;
737 indicator->activePage = 0;
738 updateSuggestionButtons(container, 0, 0);
774 bool compactMode = ((layoutInt->
container->children[enteredTextIndex + 1] != NULL)
775 && (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON)
776 && (layoutInt->
container->nbChildren == 3));
779 if (layout == NULL) {
785 = addTextEntry(layoutInt, NULL, text, numbered, number, grayedOut, token, compactMode);
790 if (layoutInt->
container->children[enteredTextIndex + 1] != NULL) {
791 if (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON) {
794 container->obj.alignmentMarginY
795 -= (button->obj.area.height + button->obj.alignmentMarginY
796 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
802 container->obj.alignmentMarginY
803 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
804 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
810 if (layoutInt->
container->nbChildren == 3) {
811 container->obj.alignmentMarginY += layoutInt->
container->children[0]->area.height / 2;
844 if (layout == NULL) {
851 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
855 if ((textArea == NULL) || (textArea->obj.type !=
TEXT_AREA)) {
858 textArea->text = text;
867 snprintf(numText,
sizeof(numText),
"%d.", number);
868 textArea->text = numText;
898 bool compactMode = (layoutInt->
container->nbChildren == 3);
901 if (layout == NULL) {
905 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
908 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
910 ->obj.alignmentMarginY
911 -= (button->obj.area.height + button->obj.alignmentMarginY
912 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
942 if (layout == NULL) {
948 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
954 button->innerColor =
BLACK;
955 button->borderColor =
BLACK;
956 button->obj.touchMask = (1 <<
TOUCHED);
982 if (layout == NULL) {
986 container = addTextEntry(layoutInt,
1000 = addSuggestionButtons(layoutInt,
1016 container->obj.alignmentMarginY
1017 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1018 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1030 container->obj.alignmentMarginY
1031 -= (button->obj.area.height + button->obj.alignmentMarginY
1032 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1036 return layoutInt->
container->obj.area.height;
1056 if (layout == NULL) {
1066 snprintf(numText,
sizeof(numText),
"%d.", content->
number);
1073 textArea->text = content->
text;
1083 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1086 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
1094 suggestionsContainer->forceClean =
true;
1099 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1100 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1101 indicator->activePage = 0;
1102 updateSuggestionButtons(suggestionsContainer, 0, 0);
1109 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
1115 button->innerColor =
BLACK;
1116 button->borderColor =
BLACK;
1117 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....)
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)