22#include "os_io_seph_cmd.h"
23#include "os_io_seph_ux.h"
25#include "os_helpers.h"
30#if defined(TARGET_FLEX)
31#define USE_PARTIAL_BUTTONS 1
37#ifdef USE_PARTIAL_BUTTONS
43#ifndef USE_PARTIAL_BUTTONS
50#if defined(TARGET_STAX)
51#define TEXT_ENTRY_NORMAL_HEIGHT 64
52#define TEXT_ENTRY_COMPACT_HEIGHT 64
53#define BOTTOM_NORMAL_MARGIN 24
54#define BOTTOM_COMPACT_MARGIN 24
55#define TOP_NORMAL_MARGIN 20
56#define TOP_COMPACT_MARGIN 20
57#elif defined(TARGET_FLEX)
58#define TEXT_ENTRY_NORMAL_HEIGHT 72
59#define TEXT_ENTRY_COMPACT_HEIGHT 56
60#define BOTTOM_NORMAL_MARGIN 24
61#define BOTTOM_COMPACT_MARGIN 12
62#define TOP_NORMAL_MARGIN 20
63#define TOP_COMPACT_MARGIN 12
66#ifdef USE_PARTIAL_BUTTONS
67#if defined(TARGET_FLEX)
68#define LEFT_HALF_ICON C_left_half_64px
73#define LINE_REAL_HEIGHT 4
75#define NUMBER_WIDTH 56
78#define NUMBER_TEXT_SPACE 8
92static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS];
93static char numText[5];
94static uint8_t nbActiveButtons;
95#ifdef USE_PARTIAL_BUTTONS
107 uint8_t currentLeftButtonIndex)
109 bool needRefresh =
false;
114 && (currentLeftButtonIndex
115 < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
118 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
120 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex];
122 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
123 if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
125 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
131 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
135 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
138 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
139 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
141 = (
nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
143 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
161#ifndef USE_PARTIAL_BUTTONS
183 indicator->activePage = page;
185#ifdef USE_PARTIAL_BUTTONS
187 if (currentLeftButtonIndex > 0) {
188 container->children[LEFT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[0];
191 container->children[LEFT_HALF_INDEX] = NULL;
194 if (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
195 container->children[RIGHT_HALF_INDEX] = (
nbgl_obj_t *) partialButtonImages[1];
198 container->children[RIGHT_HALF_INDEX] = NULL;
213 if ((container->nbChildren < 2) || (container->children[1]->type !=
CONTAINER)) {
220 && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
222 while (i < (uint32_t) nbActiveButtons) {
230 if (i < (uint32_t) nbActiveButtons) {
231 if (updateSuggestionButtons(suggestionsContainer, eventType, i)) {
232 os_io_seph_cmd_piezo_play_tune(TUNE_TAP_CASUAL);
255 uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
259 container->nbChildren = 4;
262 container->obj.alignment =
CENTER;
267 textArea->textColor =
BLACK;
268 textArea->text = title;
269 textArea->textAlignment =
CENTER;
270 textArea->fontId = SMALL_REGULAR_FONT;
271 textArea->wrapping =
true;
275 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
276 container->children[0] = (
nbgl_obj_t *) textArea;
277 container->obj.area.height = textArea->obj.area.height + 4;
283 textArea->textColor =
BLACK;
284 snprintf(numText,
sizeof(numText),
"%d.", number);
285 textArea->text = numText;
286 textArea->textAlignment =
CENTER;
287 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
291 textArea->obj.alignTo = container->children[0];
300 container->children[1] = (
nbgl_obj_t *) textArea;
306 textArea->text = text;
308 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
311 textArea->obj.alignTo = container->children[0];
321 textArea->obj.area.width -= textArea->obj.alignmentMarginX;
324 textArea->autoHideLongLine =
true;
330 textArea->obj.touchMask = (1 <<
TOUCHED);
332 container->children[2] = (
nbgl_obj_t *) textArea;
333 container->obj.area.height += textEntryHeight;
352 uint8_t nbUsedButtons,
353 const char **buttonTexts,
354 int firstButtonToken,
361 nbActiveButtons = nbUsedButtons;
363 suggestionsContainer->layout =
VERTICAL;
364 suggestionsContainer->obj.area.width = SCREEN_WIDTH;
365#ifndef USE_PARTIAL_BUTTONS
367 suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT +
INTERNAL_MARGIN + 28;
370 suggestionsContainer->obj.area.height = SMALL_BUTTON_HEIGHT + 28;
373 suggestionsContainer->children
377 suggestionsContainer->obj.alignmentMarginY
378 = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
384 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
386 layoutInt, (
nbgl_obj_t *) choiceButtons[i], firstButtonToken + i, tuneId);
391 choiceButtons[i]->innerColor =
BLACK;
392 choiceButtons[i]->borderColor =
BLACK;
393 choiceButtons[i]->foregroundColor =
WHITE;
395 choiceButtons[i]->obj.area.height = SMALL_BUTTON_HEIGHT;
396 choiceButtons[i]->radius = SMALL_BUTTON_RADIUS_INDEX;
397 choiceButtons[i]->fontId = SMALL_BOLD_1BPP_FONT;
398 choiceButtons[i]->text = buttonTexts[i];
399 choiceButtons[i]->obj.touchMask = (1 <<
TOUCHED);
402 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
411 indicator->activePage = 0;
412 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
413 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
414 indicator->obj.area.width = 184;
418#ifdef USE_PARTIAL_BUTTONS
422 partialButtonImages[0]->buffer = &LEFT_HALF_ICON;
423 partialButtonImages[0]->obj.alignment =
TOP_LEFT;
424 partialButtonImages[0]->foregroundColor =
BLACK;
426 partialButtonImages[1]->buffer = &LEFT_HALF_ICON;
427 partialButtonImages[1]->obj.alignment =
TOP_RIGHT;
428 partialButtonImages[1]->foregroundColor =
BLACK;
430 updateSuggestionButtons(suggestionsContainer, 0, 0);
433 return suggestionsContainer;
453 button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
455 button->foregroundColor =
WHITE;
457 button->innerColor =
BLACK;
458 button->borderColor =
BLACK;
459 button->obj.touchMask = (1 <<
TOUCHED);
466 button->text = PIC(text);
467 button->fontId = SMALL_BOLD_1BPP_FONT;
469 button->obj.area.height = BUTTON_DIAMETER;
470 button->radius = BUTTON_RADIUS;
492 if (layout == NULL) {
502 keyboard->obj.area.width = SCREEN_WIDTH;
503 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
505 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
508 keyboard->obj.alignmentMarginY = 56;
512 keyboard->callback = PIC(kbdInfo->
callback);
514 keyboard->mode = kbdInfo->
mode;
515 keyboard->keyMask = kbdInfo->
keyMask;
516 keyboard->casing = kbdInfo->
casing;
526 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
565 if (layout == NULL) {
572 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
575 keyboard->keyMask = keyMask;
577 keyboard->casing = casing;
598 if (layout == NULL) {
605 if ((keyboard == NULL) || (keyboard->obj.type !=
KEYBOARD)) {
608 if (keyboard->needsRefresh) {
609 keyboard->needsRefresh =
false;
629 uint8_t nbUsedButtons,
630 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS],
631 int firstButtonToken,
637 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
640 if (layout == NULL) {
644 container = addSuggestionButtons(
645 layoutInt, nbUsedButtons, buttonTexts, firstButtonToken, tuneId,
false);
648 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
650 ->obj.alignmentMarginY
651 -= (container->obj.area.height + container->obj.alignmentMarginY + 20) / 2;
653#ifdef USE_PARTIAL_BUTTONS
667 return (layoutInt->
container->nbChildren - 1);
683 uint8_t nbUsedButtons,
684 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
688 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
691 if (layout == NULL) {
697 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
700 nbActiveButtons = nbUsedButtons;
704 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
705 choiceButtons[i]->text = buttonTexts[i];
707 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbUsedButtons)) {
709 choiceButtons[i]->obj.alignmentMarginX = BORDER_MARGIN;
710#ifndef USE_PARTIAL_BUTTONS
718 choiceButtons[i]->obj.alignment =
TOP_LEFT;
724 choiceButtons[i]->obj.alignment =
MID_RIGHT;
725 choiceButtons[i]->obj.alignTo = (
nbgl_obj_t *) choiceButtons[i - 1];
733 container->forceClean =
true;
734#ifdef USE_PARTIAL_BUTTONS
738 indicator->nbPages = (nbUsedButtons + 1) / 2;
739 indicator->activePage = 0;
740 updateSuggestionButtons(container, 0, 0);
775 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
776 bool compactMode = ((layoutInt->
container->children[enteredTextIndex + 1] != NULL)
777 && (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON)
778 && (layoutInt->
container->nbChildren == 3));
781 if (layout == NULL) {
787 = addTextEntry(layoutInt, NULL, text, numbered, number, grayedOut, token, compactMode);
792 if (layoutInt->
container->children[enteredTextIndex + 1] != NULL) {
793 if (layoutInt->
container->children[enteredTextIndex + 1]->type ==
BUTTON) {
796 container->obj.alignmentMarginY
797 -= (button->obj.area.height + button->obj.alignmentMarginY
798 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
804 container->obj.alignmentMarginY
805 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
806 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
812 if (layoutInt->
container->nbChildren == 3) {
813 container->obj.alignmentMarginY += layoutInt->
container->children[0]->area.height / 2;
843 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
846 if (layout == NULL) {
853 if ((container == NULL) || (container->obj.type !=
CONTAINER)) {
857 if ((textArea == NULL) || (textArea->obj.type !=
TEXT_AREA)) {
860 textArea->text = text;
869 snprintf(numText,
sizeof(numText),
"%d.", number);
870 textArea->text = numText;
899 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
900 bool compactMode = (layoutInt->
container->nbChildren == 3);
903 if (layout == NULL) {
907 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
910 if (layoutInt->
container->children[enteredTextIndex] != NULL) {
912 ->obj.alignmentMarginY
913 -= (button->obj.area.height + button->obj.alignmentMarginY
914 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
939 uint8_t enteredTextIndex = (layoutInt->
container->nbChildren == 2) ? 0 : 1;
944 if (layout == NULL) {
950 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
956 button->innerColor =
BLACK;
957 button->borderColor =
BLACK;
958 button->obj.touchMask = (1 <<
TOUCHED);
984 if (layout == NULL) {
988 container = addTextEntry(layoutInt,
1002 = addSuggestionButtons(layoutInt,
1018 container->obj.alignmentMarginY
1019 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1020 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1032 container->obj.alignmentMarginY
1033 -= (button->obj.area.height + button->obj.alignmentMarginY
1034 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1038 return layoutInt->
container->obj.area.height;
1058 if (layout == NULL) {
1068 snprintf(numText,
sizeof(numText),
"%d.", content->
number);
1075 textArea->text = content->
text;
1085 for (
int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1088 if (i <
MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
1096 suggestionsContainer->forceClean =
true;
1101 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1102 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1103 indicator->activePage = 0;
1104 updateSuggestionButtons(suggestionsContainer, 0, 0);
1111 if ((button == NULL) || (button->obj.type !=
BUTTON)) {
1117 button->innerColor =
BLACK;
1118 button->borderColor =
BLACK;
1119 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)