18#include "localization.h"
28#include "os_io_seph_ux.h"
30#include "os_helpers.h"
37#define INTERNAL_SPACE 16
39#define INNER_MARGIN 12
41#define NB_MAX_LAYOUTS 3
44#define NB_MAX_CONTAINER_CHILDREN 20
46#define TAG_VALUE_ICON_WIDTH 32
48#if defined(TARGET_STAX)
49#define RADIO_CHOICE_HEIGHT 96
50#define BAR_INTERVALE 12
51#define FOOTER_BUTTON_HEIGHT 128
52#define FOOTER_IN_PAIR_HEIGHT 80
53#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
54#define FOOTER_TEXT_AND_NAV_WIDTH 160
55#define TAP_TO_CONTINUE_MARGIN 24
56#define SUB_HEADER_MARGIN 24
57#define PRE_FIRST_TEXT_MARGIN 24
58#define INTER_PARAGRAPHS_MARGIN 40
59#define PRE_TITLE_MARGIN 24
60#define PRE_DESCRIPTION_MARGIN 16
61#define INTER_DESCRIPTIONS_MARGIN 16
62#define PRE_FIRST_ROW_MARGIN 32
63#define INTER_ROWS_MARGIN 16
64#define QR_PRE_TEXT_MARGIN 24
65#define QR_INTER_TEXTS_MARGIN 40
66#define SPINNER_TEXT_MARGIN 20
67#define SPINNER_INTER_TEXTS_MARGIN 20
68#define BAR_TEXT_MARGIN 24
69#define BAR_INTER_TEXTS_MARGIN 16
70#define LEFT_CONTENT_TEXT_PADDING 0
71#define BUTTON_FROM_BOTTOM_MARGIN 4
72#define TOP_BUTTON_MARGIN VERTICAL_BORDER_MARGIN
73#define TOP_BUTTON_MARGIN_WITH_ACTION VERTICAL_BORDER_MARGIN
74#define SINGLE_BUTTON_MARGIN 24
75#define LONG_PRESS_PROGRESS_HEIGHT 8
76#define LONG_PRESS_PROGRESS_ALIGN 1
77#define LEFT_CONTENT_ICON_TEXT_X 16
78#define TIP_BOX_MARGIN_Y 24
79#define TIP_BOX_TEXT_ICON_MARGIN 24
80#elif defined(TARGET_FLEX)
81#define RADIO_CHOICE_HEIGHT 92
82#define BAR_INTERVALE 16
83#define FOOTER_BUTTON_HEIGHT 136
84#define FOOTER_IN_PAIR_HEIGHT 88
85#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
86#define FOOTER_TEXT_AND_NAV_WIDTH 192
87#define TAP_TO_CONTINUE_MARGIN 30
88#define SUB_HEADER_MARGIN 28
89#define PRE_FIRST_TEXT_MARGIN 0
90#define INTER_PARAGRAPHS_MARGIN 24
91#define PRE_TITLE_MARGIN 16
92#define PRE_DESCRIPTION_MARGIN 24
93#define INTER_DESCRIPTIONS_MARGIN 24
94#define PRE_FIRST_ROW_MARGIN 32
95#define INTER_ROWS_MARGIN 24
96#define QR_PRE_TEXT_MARGIN 24
97#define QR_INTER_TEXTS_MARGIN 28
98#define SPINNER_TEXT_MARGIN 24
99#define SPINNER_INTER_TEXTS_MARGIN 16
100#define BAR_TEXT_MARGIN 24
101#define BAR_INTER_TEXTS_MARGIN 16
102#define LEFT_CONTENT_TEXT_PADDING 4
103#define BUTTON_FROM_BOTTOM_MARGIN 4
104#define TOP_BUTTON_MARGIN VERTICAL_BORDER_MARGIN
105#define TOP_BUTTON_MARGIN_WITH_ACTION VERTICAL_BORDER_MARGIN
106#define SINGLE_BUTTON_MARGIN 24
107#define LONG_PRESS_PROGRESS_HEIGHT 8
108#define LONG_PRESS_PROGRESS_ALIGN 1
109#define LEFT_CONTENT_ICON_TEXT_X 16
110#define TIP_BOX_MARGIN_Y 24
111#define TIP_BOX_TEXT_ICON_MARGIN 32
112#elif defined(TARGET_APEX)
113#define RADIO_CHOICE_HEIGHT 68
114#define BAR_INTERVALE 8
115#define FOOTER_BUTTON_HEIGHT 88
116#define FOOTER_IN_PAIR_HEIGHT 60
117#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 128
118#define FOOTER_TEXT_AND_NAV_WIDTH 120
119#define TAP_TO_CONTINUE_MARGIN 30
120#define SUB_HEADER_MARGIN 16
121#define PRE_FIRST_TEXT_MARGIN 0
122#define INTER_PARAGRAPHS_MARGIN 16
123#define PRE_TITLE_MARGIN 16
124#define PRE_DESCRIPTION_MARGIN 12
125#define INTER_DESCRIPTIONS_MARGIN 12
126#define PRE_FIRST_ROW_MARGIN 24
127#define INTER_ROWS_MARGIN 12
128#define QR_PRE_TEXT_MARGIN 16
129#define QR_INTER_TEXTS_MARGIN 20
130#define SPINNER_TEXT_MARGIN 16
131#define SPINNER_INTER_TEXTS_MARGIN 16
132#define BAR_TEXT_MARGIN 16
133#define BAR_INTER_TEXTS_MARGIN 12
134#define LEFT_CONTENT_TEXT_PADDING 4
135#define BUTTON_FROM_BOTTOM_MARGIN 0
136#define TOP_BUTTON_MARGIN 12
137#define TOP_BUTTON_MARGIN_WITH_ACTION 0
138#define SINGLE_BUTTON_MARGIN 16
139#define LONG_PRESS_PROGRESS_HEIGHT 4
140#define LONG_PRESS_PROGRESS_ALIGN 0
141#define LEFT_CONTENT_ICON_TEXT_X 8
142#define TIP_BOX_MARGIN_Y 12
143#define TIP_BOX_TEXT_ICON_MARGIN 20
145#error Undefined target
149#define SPINNER_REFRESH_PERIOD 400
196static uint8_t nbTouchableControls = 0;
204#if defined(TARGET_FLEX)
206#define HOLD_TO_APPROVE_STEP_PERCENT (7)
208#define HOLD_TO_APPROVE_STEP_DURATION_MS (100)
210#define HOLD_TO_APPROVE_FIRST_STEP (0)
211#elif defined(TARGET_STAX)
212#define HOLD_TO_APPROVE_STEP_PERCENT (25)
213#define HOLD_TO_APPROVE_STEP_DURATION_MS (400)
214#define HOLD_TO_APPROVE_FIRST_STEP (1)
215#elif defined(TARGET_APEX)
216#define HOLD_TO_APPROVE_STEP_PERCENT (20)
217#define HOLD_TO_APPROVE_STEP_DURATION_MS (300)
218#define HOLD_TO_APPROVE_FIRST_STEP (1)
221static inline uint8_t get_hold_to_approve_percent(uint32_t touch_duration)
223 uint8_t current_step_nb
224 = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS) + HOLD_TO_APPROVE_FIRST_STEP;
225 return (current_step_nb * HOLD_TO_APPROVE_STEP_PERCENT);
229static bool getLayoutAndLayoutObj(
nbgl_obj_t *obj,
236 if ((topLayout) && (topLayout->
isUsed)) {
243 "getLayoutAndLayoutObj(): obj found in layout %p "
244 "nbUsedCallbackObjs = %d\n",
257static void radioTouchCallback(
nbgl_obj_t *obj,
270 bool needRefresh =
false;
277 if (getLayoutAndLayoutObj(obj, &layout, &layoutObj) ==
false) {
279 if (getLayoutAndLayoutObj(obj->parent, &layout, &layoutObj) ==
false) {
282 "touchCallback(): eventType = %d, obj = %p, no active layout or obj not found\n",
300 layoutObj->
index = eventType;
308 else if (layout->
footerType == FOOTER_TEXT_AND_NAV) {
330 && (layout->
footerType == FOOTER_TEXT_AND_NAV))) {
349 layoutObj->
index = lSwitch->state;
355 radioTouchCallback(obj, eventType, layout);
362 longTouchCallback(obj, eventType, layout, layoutObj);
367#ifdef HAVE_PIEZO_SOUND
369 os_io_seph_cmd_piezo_play_tune(layoutObj->
tuneId);
396 uint8_t new_state = get_hold_to_approve_percent(touchDuration);
400 bool trigger_callback = (new_state >= 100) && (progressBar->state < 100);
403 if (new_state >= 100) {
408 if (new_state != progressBar->state) {
409 progressBar->partialRedraw =
true;
410 progressBar->state = new_state;
419 if (trigger_callback) {
430 progressBar->partialRedraw =
true;
431 progressBar->state = 0;
441static void radioTouchCallback(
nbgl_obj_t *obj,
445 uint8_t i =
NB_MAX_LAYOUTS, radioIndex = 0, foundRadio = 0xFF, foundRadioIndex;
453 while (i < layout->nbUsedCallbackObjs) {
463 foundRadioIndex = radioIndex;
465 textArea->textColor =
BLACK;
466 textArea->fontId = SMALL_BOLD_FONT;
488 textArea->fontId = SMALL_REGULAR_FONT;
496 if (foundRadio != 0xFF) {
498#ifdef HAVE_PIEZO_SOUND
510static void spinnerTickerCallback(
void)
515 if (!topLayout || !topLayout->
isUsed) {
520 while (i < topLayout->container->nbChildren) {
523 if (container->nbChildren && (container->children[0]->type ==
SPINNER)) {
527 if (spinner->position == NB_SPINNER_POSITIONS) {
528 spinner->position = 0;
540static void animTickerCallback(
void)
551 while (i < layout->container->nbChildren) {
554 if (container->children[1]->type ==
IMAGE) {
593static nbgl_line_t *createHorizontalLine(uint8_t layer)
600 line->obj.area.height = 1;
607static nbgl_line_t *createLeftVerticalLine(uint8_t layer)
613 line->obj.area.width = 1;
634 layoutObj->
obj = obj;
635 layoutObj->
token = token;
636 layoutObj->
tuneId = tuneId;
655 if (layout == NULL) {
668 if (layoutObj->
obj == obj) {
669 layoutObj->
token = token;
683 if (layout->
container->nbChildren == NB_MAX_CONTAINER_CHILDREN) {
718 layoutInt->
container->obj.touchMask = swipesMask;
739 if ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
OFF_STATE)) {
744 common_color =
BLACK;
745 right_icon_color =
BLACK;
749 = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
OFF_STATE))
757 layoutInt, (
nbgl_obj_t *) container, itemDesc->token, itemDesc->tuneId);
762 obj->
index = itemDesc->index;
766 container->nbChildren = 0;
769 container->obj.area.height
770 = LIST_ITEM_MIN_TEXT_HEIGHT
771 + 2 * (itemDesc->large ? LIST_ITEM_PRE_HEADING_LARGE : LIST_ITEM_PRE_HEADING);
773 container->obj.alignmentMarginX = BORDER_MARGIN;
775 container->obj.alignTo = NULL;
778 if (((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
ON_STATE))
779 || (itemDesc->type == SWITCH_ITEM)) {
780 container->obj.touchMask = (1 <<
TOUCHED);
781 container->obj.touchId =
CONTROLS_ID + nbTouchableControls;
782 nbTouchableControls++;
786 if (itemDesc->text != NULL) {
788 textArea->textColor = common_color;
789 textArea->text = PIC(itemDesc->text);
790 textArea->onDrawCallback = NULL;
791 textArea->fontId = fontId;
792 textArea->wrapping =
true;
793 textArea->obj.area.width = container->obj.area.width;
794 if (itemDesc->iconLeft != NULL) {
796 textArea->obj.area.width
799 if (itemDesc->iconRight != NULL) {
801 textArea->obj.area.width
804 else if (itemDesc->type == SWITCH_ITEM) {
805 textArea->obj.area.width -= SWITCH_ICON.width + BAR_INTERVALE;
807 textArea->obj.area.height =
MAX(
808 LIST_ITEM_MIN_TEXT_HEIGHT,
810 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping));
813 textArea->obj.alignmentMarginY
814 = itemDesc->large ? LIST_ITEM_PRE_HEADING_LARGE : LIST_ITEM_PRE_HEADING;
815 if (textArea->obj.area.height > LIST_ITEM_MIN_TEXT_HEIGHT) {
816 textArea->obj.alignmentMarginY
817 -= (textArea->obj.area.height - LIST_ITEM_MIN_TEXT_HEIGHT) / 2;
820 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
821 container->nbChildren++;
825 if (itemDesc->iconLeft != NULL) {
827 imageLeft->foregroundColor = common_color;
828 imageLeft->buffer = PIC(itemDesc->iconLeft);
830 imageLeft->obj.alignment =
MID_LEFT;
831 imageLeft->obj.alignTo = (
nbgl_obj_t *) textArea;
832 imageLeft->obj.alignmentMarginX = BAR_INTERVALE;
833 container->children[container->nbChildren] = (
nbgl_obj_t *) imageLeft;
834 container->nbChildren++;
836 if (textArea != NULL) {
837 textArea->obj.alignmentMarginX = imageLeft->buffer->width + BAR_INTERVALE;
841 if (itemDesc->iconRight != NULL) {
843 imageRight->foregroundColor = right_icon_color;
844 imageRight->buffer = PIC(itemDesc->iconRight);
847 imageRight->obj.alignmentMarginX = BAR_INTERVALE;
848 imageRight->obj.alignTo = (
nbgl_obj_t *) textArea;
850 container->children[container->nbChildren] = (
nbgl_obj_t *) imageRight;
851 container->nbChildren++;
853 else if (itemDesc->type == SWITCH_ITEM) {
855 switchObj->onColor =
BLACK;
857 switchObj->state = itemDesc->state;
859 switchObj->obj.alignmentMarginX = BAR_INTERVALE;
860 switchObj->obj.alignTo = (
nbgl_obj_t *) textArea;
862 container->children[container->nbChildren] = (
nbgl_obj_t *) switchObj;
863 container->nbChildren++;
866 if (itemDesc->subText != NULL) {
870 subTextArea->textColor = common_color;
871 subTextArea->text = PIC(itemDesc->subText);
872 subTextArea->textAlignment =
MID_LEFT;
873 subTextArea->fontId = SMALL_REGULAR_FONT;
875 subTextArea->wrapping =
true;
876 if (itemDesc->text != NULL) {
878 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
879 subTextArea->obj.alignmentMarginY = LIST_ITEM_HEADING_SUB_TEXT;
882 subTextArea->obj.alignment =
TOP_LEFT;
883 subTextArea->obj.alignmentMarginY = SUB_HEADER_MARGIN;
884 container->obj.area.height = SUB_HEADER_MARGIN;
886 if (itemDesc->iconLeft != NULL) {
887 subTextArea->obj.alignmentMarginX
890 subTextArea->obj.area.width = container->obj.area.width;
893 subTextArea->obj.area.width,
894 subTextArea->wrapping);
895 container->children[container->nbChildren] = (
nbgl_obj_t *) subTextArea;
896 container->nbChildren++;
897 container->obj.area.height
898 += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
920 uint16_t fullHeight = 0;
925 container->nbChildren = 0;
930 if (info->
icon != NULL) {
933 image->buffer = PIC(info->
icon);
935 image->obj.alignmentMarginY = info->
iconHug;
937 fullHeight += image->buffer->height + info->
iconHug;
938 container->children[container->nbChildren] = (
nbgl_obj_t *) image;
939 container->nbChildren++;
950 container->children[container->nbChildren] = (
nbgl_obj_t *) anim;
951 container->nbChildren++;
962 tickerCfg.tickerCallback = &animTickerCallback;
967 if (info->
title != NULL) {
970 textArea->text = PIC(info->
title);
971 textArea->textAlignment =
CENTER;
972 textArea->fontId = LARGE_MEDIUM_FONT;
973 textArea->wrapping =
true;
976 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
979 if (container->nbChildren > 0) {
982 textArea->obj.alignmentMarginY = ICON_TITLE_MARGIN + info->
iconHug;
988 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
990 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
991 container->nbChildren++;
998 textArea->textAlignment =
CENTER;
999 textArea->fontId = SMALL_BOLD_FONT;
1000 textArea->wrapping =
true;
1003 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1006 if (container->nbChildren > 0) {
1008 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1009 textArea->obj.alignmentMarginY = VERTICAL_BORDER_MARGIN;
1010 if (container->children[container->nbChildren - 1]->type ==
IMAGE) {
1011 textArea->obj.alignmentMarginY = VERTICAL_BORDER_MARGIN + info->
iconHug;
1014 textArea->obj.alignmentMarginY = TITLE_DESC_MARGIN;
1021 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1023 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1024 container->nbChildren++;
1031 textArea->textAlignment =
CENTER;
1032 textArea->fontId = SMALL_REGULAR_FONT;
1033 textArea->wrapping =
true;
1036 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1039 if (container->nbChildren > 0) {
1041 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1042 if (container->children[container->nbChildren - 1]->type ==
TEXT_AREA) {
1044 textArea->obj.alignmentMarginY = TITLE_DESC_MARGIN;
1047 textArea->obj.alignmentMarginY = ICON_TITLE_MARGIN + info->
iconHug;
1054 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1056 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1057 container->nbChildren++;
1063 textArea->text = PIC(info->
subText);
1064 textArea->textAlignment =
CENTER;
1065 textArea->fontId = SMALL_REGULAR_FONT;
1066 textArea->wrapping =
true;
1069 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1071 textArea->obj.area.height += 2 * 8;
1073 if (container->nbChildren > 0) {
1075 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1076 textArea->obj.alignmentMarginY = 16;
1077 if (container->children[container->nbChildren - 1]->type ==
IMAGE) {
1078 textArea->obj.alignmentMarginY += info->
iconHug;
1085 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1087 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1088 container->nbChildren++;
1091 container->obj.alignment =
CENTER;
1093 container->obj.area.height = fullHeight;
1095 container->obj.area.height += 40;
1118 if (description->
modal) {
1130 if (topLayout == NULL) {
1134 if (layout == NULL) {
1143 if (description->
modal) {
1144 if (topLayout != NULL) {
1146 topLayout->
top = layout;
1147 layout->
bottom = topLayout;
1161 nbTouchableControls = 0;
1166 if (description->
modal) {
1191 if (description->tapActionText != NULL) {
1193 const char *tapActionText = PIC(description->tapActionText);
1198 obj->
token = description->tapActionToken;
1199 obj->
tuneId = description->tapTuneId;
1203 if (strlen(tapActionText) > 0) {
1204 nbgl_layoutUpFooter_t footerDesc = {0};
1205 footerDesc.type = UP_FOOTER_TEXT;
1206 footerDesc.text.text = tapActionText;
1207 footerDesc.text.token = description->tapActionToken;
1208 footerDesc.text.tuneId = description->tapTuneId;
1209 nbgl_layoutAddUpFooter((
nbgl_layout_t *) layout, &footerDesc);
1227 uint16_t swipesMask,
1230 tune_index_e tuneId)
1235 if (layout == NULL) {
1242 layoutInt->
tapText->text = PIC(text);
1244 layoutInt->
tapText->fontId = SMALL_REGULAR_FONT;
1248 layoutInt->
tapText->obj.alignmentMarginY = TAP_TO_CONTINUE_MARGIN;
1266 if (layout == NULL) {
1296 tune_index_e tuneId)
1303 if (layout == NULL) {
1313 button->obj.area.width = BUTTON_WIDTH;
1314 button->obj.area.height = BUTTON_DIAMETER;
1315 button->radius = BUTTON_RADIUS;
1316 button->obj.alignmentMarginX = BORDER_MARGIN;
1317 button->obj.alignmentMarginY = BORDER_MARGIN;
1318 button->foregroundColor =
BLACK;
1319 button->innerColor =
WHITE;
1321 button->obj.touchMask = (1 <<
TOUCHED);
1323 button->icon = PIC(icon);
1341 nbgl_layoutFooter_t footerDesc = {0};
1342 footerDesc.type = FOOTER_NAV;
1344 footerDesc.navigation.activePage = info->
activePage;
1345 footerDesc.navigation.nbPages = info->
nbPages;
1346 footerDesc.navigation.withExitKey = info->
withExitKey;
1347 footerDesc.navigation.withBackKey = info->
withBackKey;
1348 footerDesc.navigation.token = info->
token;
1349 footerDesc.navigation.tuneId = info->
tuneId;
1350 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1367 bool separationLine,
1368 tune_index_e tuneId)
1371 nbgl_layoutFooter_t footerDesc = {0};
1372 footerDesc.type = FOOTER_SIMPLE_BUTTON;
1373 footerDesc.separationLine = separationLine;
1374 footerDesc.button.icon = PIC(icon);
1375 footerDesc.button.token = token;
1376 footerDesc.button.tuneId = tuneId;
1378 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1392 listItem_t itemDesc = {0};
1395 if (layout == NULL) {
1399 if (barLayout->
text == NULL) {
1403 itemDesc.iconLeft = barLayout->
iconLeft;
1404 itemDesc.iconRight = barLayout->
iconRight;
1405 itemDesc.text = barLayout->
text;
1406 itemDesc.subText = barLayout->
subText;
1407 itemDesc.token = barLayout->
token;
1408 itemDesc.tuneId = barLayout->
tuneId;
1410 itemDesc.large = barLayout->
large;
1411 itemDesc.type = TOUCHABLE_BAR_ITEM;
1412 container = addListItem(layoutInt, &itemDesc);
1414 if (container == NULL) {
1418 return container->obj.area.height;
1432 listItem_t itemDesc = {0};
1435 if (layout == NULL) {
1439 if (switchLayout->
text == NULL) {
1443 itemDesc.text = switchLayout->
text;
1444 itemDesc.subText = switchLayout->
subText;
1445 itemDesc.token = switchLayout->
token;
1446 itemDesc.tuneId = switchLayout->
tuneId;
1447 itemDesc.state = switchLayout->
initState;
1448 itemDesc.type = SWITCH_ITEM;
1449 container = addListItem(layoutInt, &itemDesc);
1451 if (container == NULL) {
1455 return container->obj.area.height;
1470 listItem_t itemDesc = {0};
1473 if (layout == NULL) {
1477 itemDesc.text = text;
1478 itemDesc.subText = subText;
1481 itemDesc.type = TEXT_ITEM;
1482 container = addListItem(layoutInt, &itemDesc);
1484 if (container == NULL) {
1488 return container->obj.area.height;
1504 const char *subText,
1510 listItem_t itemDesc = {0};
1512 if (layout == NULL) {
1516 itemDesc.text = text;
1517 itemDesc.subText = subText;
1518 itemDesc.iconRight = &MINI_PUSH_ICON;
1519 itemDesc.token = token;
1521 itemDesc.type = TOUCHABLE_BAR_ITEM;
1522 itemDesc.index = index;
1524 container = addListItem(layoutInt, &itemDesc);
1526 if (container == NULL) {
1530 return container->obj.area.height;
1541int nbgl_layoutAddLargeCaseText(
nbgl_layout_t *layout,
const char *text,
bool grayedOut)
1547 if (layout == NULL) {
1553 textArea->text = PIC(text);
1554 textArea->textAlignment =
MID_LEFT;
1555 textArea->fontId = LARGE_MEDIUM_FONT;
1557 textArea->wrapping =
true;
1559 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1562 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1563 if (layoutInt->
container->nbChildren == 0) {
1565 textArea->obj.alignmentMarginY += PRE_FIRST_TEXT_MARGIN;
1568 textArea->obj.alignmentMarginY = INTER_PARAGRAPHS_MARGIN;
1594 if (layout == NULL) {
1599 if (content->
title != NULL) {
1601 textArea->textColor =
BLACK;
1602 textArea->text = PIC(content->
title);
1603 textArea->textAlignment =
MID_LEFT;
1604 textArea->fontId = LARGE_MEDIUM_FONT;
1606 textArea->wrapping =
true;
1608 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1609 textArea->obj.alignmentMarginY = PRE_TITLE_MARGIN;
1612 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1620 textArea->textColor =
BLACK;
1622 textArea->fontId = SMALL_REGULAR_FONT;
1624 textArea->wrapping =
true;
1627 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1628 textArea->textAlignment =
MID_LEFT;
1630 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1631 textArea->obj.alignmentMarginY
1632 = (i == 0) ? PRE_DESCRIPTION_MARGIN : INTER_DESCRIPTIONS_MARGIN;
1638 if (content->
info != NULL) {
1641 textArea->text = PIC(content->
info);
1642 textArea->fontId = SMALL_REGULAR_FONT;
1644 textArea->wrapping =
true;
1647 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1648 textArea->textAlignment =
MID_LEFT;
1650 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1651 textArea->obj.alignmentMarginY = 40;
1656 return layoutInt->
container->obj.area.height;
1673 if (layout == NULL) {
1676 for (i = 0; i < choices->
nbChoices; i++) {
1694 container->nbChildren = 2;
1697 container->obj.area.height = RADIO_CHOICE_HEIGHT;
1699 container->obj.alignmentMarginX = BORDER_MARGIN;
1700 container->obj.alignTo = (
nbgl_obj_t *) NULL;
1703 button->activeColor =
BLACK;
1705 button->obj.alignTo = (
nbgl_obj_t *) container;
1708 container->children[1] = (
nbgl_obj_t *) button;
1712#ifdef HAVE_LANGUAGE_PACK
1713 textArea->text = get_ux_loc_string(choices->nameIds[i]);
1717 textArea->text = PIC(choices->
names[i]);
1719 textArea->textAlignment =
MID_LEFT;
1720 textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH;
1722 textArea->obj.alignment =
MID_LEFT;
1723 textArea->obj.alignTo = (
nbgl_obj_t *) container;
1724 container->children[0] = (
nbgl_obj_t *) textArea;
1727 container->obj.touchMask = (1 <<
TOUCHED);
1728 container->obj.touchId =
CONTROLS_ID + nbTouchableControls;
1729 nbTouchableControls++;
1734 textArea->textColor =
BLACK;
1735 textArea->fontId = SMALL_BOLD_FONT;
1740 textArea->fontId = SMALL_REGULAR_FONT;
1744 line = createHorizontalLine(layoutInt->
layer);
1745 line->obj.alignmentMarginY = -1;
1770 if (layout == NULL) {
1777 if (info->
text1 != NULL) {
1778 if (info->
style != NORMAL_INFO) {
1785 if (info->
text2 != NULL) {
1786 if (info->
style != LARGE_CASE_BOLD_INFO) {
1793 if (info->text3 != NULL) {
1794 if (info->
style == LARGE_CASE_GRAY_INFO) {
1795 centeredInfo.
subText = info->text3;
1801 container = addContentCenter(layoutInt, ¢eredInfo);
1804 container->obj.alignmentMarginX = BORDER_MARGIN;
1805 container->obj.alignmentMarginY = BORDER_MARGIN + info->offsetY;
1809 container->obj.alignmentMarginY = info->offsetY;
1812 return container->obj.area.height;
1829 if (layout == NULL) {
1833 container = addContentCenter(layoutInt, info);
1835 return container->obj.area.height;
1853 if (layout == NULL) {
1859 container->nbChildren = info->
nbRows + 1;
1863 container->obj.alignmentMarginX = BORDER_MARGIN;
1867 textArea->textColor =
BLACK;
1868 textArea->text = PIC(info->
title);
1869 textArea->textAlignment =
MID_LEFT;
1870 textArea->fontId = LARGE_MEDIUM_FONT;
1871 textArea->wrapping =
true;
1873 textArea->obj.alignmentMarginY = 24;
1877 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1879 container->obj.area.height += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1881 container->children[0] = (
nbgl_obj_t *) textArea;
1883 for (row = 0; row < info->
nbRows; row++) {
1889 rowContainer->nbChildren = 2;
1894 image->foregroundColor =
BLACK;
1895 image->buffer = PIC(info->
rowIcons[row]);
1896 rowContainer->children[0] = (
nbgl_obj_t *) image;
1899 textArea->textColor =
BLACK;
1900 textArea->text = PIC(info->
rowTexts[row]);
1901 textArea->textAlignment =
MID_LEFT;
1902 textArea->fontId = SMALL_REGULAR_FONT;
1903 textArea->wrapping =
true;
1904 textArea->obj.area.width
1907 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1909 rowContainer->children[1] = (
nbgl_obj_t *) textArea;
1910 rowContainer->obj.area.height
1911 =
MAX(image->buffer->height, textArea->obj.area.height + LEFT_CONTENT_TEXT_PADDING);
1914 rowContainer->obj.alignmentMarginY = PRE_FIRST_ROW_MARGIN;
1917 rowContainer->obj.alignmentMarginY = INTER_ROWS_MARGIN;
1919 container->children[1 + row] = (
nbgl_obj_t *) rowContainer;
1920 container->obj.area.height
1921 += rowContainer->obj.area.height + rowContainer->obj.alignmentMarginY;
1925 return container->obj.area.height;
1937int nbgl_layoutAddQRCode(
nbgl_layout_t *layout,
const nbgl_layoutQRCode_t *info)
1943 uint16_t fullHeight = 0;
1946 if (layout == NULL) {
1954 container->nbChildren = 0;
1958 if (strlen(PIC(info->url)) > 62) {
1964 qrcode->foregroundColor =
BLACK;
1970 qrcode->obj.area.width
1973 qrcode->obj.area.width
1976 qrcode->obj.area.height = qrcode->obj.area.width;
1977 qrcode->text = PIC(info->url);
1981 fullHeight += qrcode->obj.area.height;
1982 container->children[container->nbChildren] = (
nbgl_obj_t *) qrcode;
1983 container->nbChildren++;
1985 if (info->text1 != NULL) {
1987 textArea->textColor =
BLACK;
1988 textArea->text = PIC(info->text1);
1989 textArea->textAlignment =
CENTER;
1990 textArea->fontId = (info->largeText1 ==
true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1991 textArea->wrapping =
true;
1994 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1996 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1997 textArea->obj.alignmentMarginY = QR_PRE_TEXT_MARGIN;
1999 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
2001 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
2002 container->nbChildren++;
2004 if (info->text2 != NULL) {
2007 textArea->text = PIC(info->text2);
2008 textArea->textAlignment =
CENTER;
2009 textArea->fontId = SMALL_REGULAR_FONT;
2010 textArea->wrapping =
true;
2013 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2015 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
2016 if (info->text1 != NULL) {
2017 textArea->obj.alignmentMarginY = QR_INTER_TEXTS_MARGIN;
2020 textArea->obj.alignmentMarginY = QR_PRE_TEXT_MARGIN + 8;
2023 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY + 8;
2025 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
2026 container->nbChildren++;
2029 if ((fullHeight >= (layoutInt->
container->obj.area.height - 16))
2034 qrcode->obj.area.height = qrcode->obj.area.width;
2037 container->obj.area.height = fullHeight;
2039 if (info->centered) {
2040 container->obj.alignment =
CENTER;
2044 container->obj.alignTo
2047 container->obj.alignmentMarginY = info->offsetY;
2066int nbgl_layoutAddChoiceButtons(
nbgl_layout_t *layout,
const nbgl_layoutChoiceButtons_t *info)
2068 nbgl_layoutFooter_t footerDesc = {0};
2069 footerDesc.type = FOOTER_CHOICE_BUTTONS;
2070 footerDesc.choiceButtons.bottomText = info->bottomText;
2071 footerDesc.choiceButtons.token = info->token;
2072 footerDesc.choiceButtons.topText = info->topText;
2073 footerDesc.choiceButtons.topIcon = info->topIcon;
2074 footerDesc.choiceButtons.style = info->style;
2075 footerDesc.choiceButtons.tuneId = info->tuneId;
2076 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2089 const nbgl_layoutHorizontalButtons_t *info)
2091 nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_HORIZONTAL_BUTTONS,
2092 .horizontalButtons.leftIcon = info->leftIcon,
2093 .horizontalButtons.leftToken = info->leftToken,
2094 .horizontalButtons.rightText = info->rightText,
2095 .horizontalButtons.rightToken = info->rightToken,
2096 .horizontalButtons.tuneId = info->tuneId};
2099 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2116 if (layout == NULL) {
2124 for (i = 0; i < list->
nbPairs; i++) {
2126 uint16_t fullHeight = 0;
2130 uint8_t nbChildren = 2;
2133 if (list->
pairs != NULL) {
2134 pair = &list->
pairs[i];
2140 "nbgl_layoutAddTagValueList(): callback returned NULL for index %d\n",
2166 itemTextArea->text = PIC(pair->
item);
2167 itemTextArea->textAlignment =
MID_LEFT;
2168 itemTextArea->fontId = SMALL_REGULAR_FONT;
2169 itemTextArea->wrapping =
true;
2172 itemTextArea->fontId, itemTextArea->text,
AVAILABLE_WIDTH, itemTextArea->wrapping);
2173 container->children[container->nbChildren] = (
nbgl_obj_t *) itemTextArea;
2174 container->nbChildren++;
2176 fullHeight += itemTextArea->obj.area.height;
2179 valueTextArea->textColor =
BLACK;
2180 valueTextArea->text = PIC(pair->
value);
2181 valueTextArea->textAlignment =
MID_LEFT;
2183 valueTextArea->fontId = SMALL_BOLD_FONT;
2186 valueTextArea->fontId = LARGE_MEDIUM_FONT;
2194 valueIcon = &MINI_PUSH_ICON;
2201 valueTextArea->obj.area.width
2208 valueTextArea->text,
2209 valueTextArea->obj.area.width,
2220 valueTextArea->nbMaxLines = 2;
2221 valueTextArea->hideEndOfLastLine =
true;
2224 valueTextArea->obj.area.height = nbLines * font->
line_height;
2226 valueTextArea->obj.alignmentMarginY = TAG_VALUE_INTERVALE;
2227 valueTextArea->obj.alignTo = (
nbgl_obj_t *) itemTextArea;
2228 valueTextArea->wrapping = list->
wrapping;
2229 container->children[container->nbChildren] = (
nbgl_obj_t *) valueTextArea;
2230 container->nbChildren++;
2232 fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
2233 if (valueIcon != NULL) {
2239 image->foregroundColor =
BLACK;
2240 image->buffer = valueIcon;
2242 image->obj.alignmentMarginX = VALUE_ICON_INTERVALE;
2243 image->obj.alignTo = (
nbgl_obj_t *) valueTextArea;
2245 container->obj.touchMask = (1 <<
TOUCHED);
2248 container->children[container->nbChildren] = (
nbgl_obj_t *) image;
2249 container->nbChildren++;
2256 textArea->textColor =
BLACK;
2258 textArea->textAlignment =
MID_LEFT;
2259 textArea->nbMaxLines = 1;
2260 textArea->fontId = SMALL_REGULAR_FONT;
2262 textArea->obj.area.width = valueTextArea->obj.area.width;
2264 textArea->obj.alignmentMarginY = TAG_VALUE_INTERVALE;
2265 textArea->obj.alignTo = (
nbgl_obj_t *) valueTextArea;
2266 textArea->wrapping = list->
wrapping;
2267 textArea->hideEndOfLastLine
2269 > textArea->obj.area.width);
2270 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
2271 container->nbChildren++;
2272 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
2277 container->obj.area.height = fullHeight;
2279 container->obj.alignmentMarginX = BORDER_MARGIN;
2281 container->obj.alignmentMarginY = INTER_TAG_VALUE_MARGIN;
2289 container->obj.alignmentMarginY = INTER_TAG_VALUE_MARGIN;
2292 container->obj.alignmentMarginY = PRE_TAG_VALUE_MARGIN;
2317 const char *subText,
2326 if (layout == NULL) {
2333 container->nbChildren = (subText != NULL) ? 3 : 2;
2338 container->obj.alignment =
CENTER;
2342 progress->foregroundColor =
BLACK;
2343 progress->withBorder =
true;
2344 progress->state = percentage;
2345 progress->obj.area.width = PROGRESSBAR_WIDTH;
2346 progress->obj.area.height = PROGRESSBAR_HEIGHT;
2350 container->children[0] = (
nbgl_obj_t *) progress;
2353 container->obj.area.height = progress->obj.alignmentMarginY + progress->obj.area.height;
2357 textArea->textColor =
BLACK;
2358 textArea->text = PIC(text);
2359 textArea->textAlignment =
CENTER;
2360 textArea->fontId = LARGE_MEDIUM_FONT;
2361 textArea->wrapping =
true;
2362 textArea->obj.alignmentMarginY = BAR_TEXT_MARGIN;
2363 textArea->obj.alignTo = (
nbgl_obj_t *) progress;
2367 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2371 container->obj.area.height += textArea->obj.alignmentMarginY + textArea->obj.area.height;
2374 container->children[1] = (
nbgl_obj_t *) textArea;
2376 if (subText != NULL) {
2380 subTextArea->textColor =
BLACK;
2381 subTextArea->text = PIC(subText);
2382 subTextArea->textAlignment =
CENTER;
2383 subTextArea->fontId = SMALL_REGULAR_FONT;
2384 subTextArea->wrapping =
true;
2385 subTextArea->obj.alignmentMarginY = BAR_INTER_TEXTS_MARGIN;
2386 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
2391 subTextArea->obj.area.width,
2392 subTextArea->wrapping);
2396 container->obj.area.height
2397 += subTextArea->obj.alignmentMarginY + subTextArea->obj.area.height;
2400 container->children[2] = (
nbgl_obj_t *) subTextArea;
2403 container->obj.area.height = (container->obj.area.height + 7) & 0xFFF8;
2422 line = createHorizontalLine(layoutInt->
layer);
2423 line->obj.alignmentMarginY = -1;
2442 if (layout == NULL) {
2447 if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2449 nbgl_layoutFooter_t footerDesc = {0};
2450 footerDesc.type = FOOTER_SIMPLE_BUTTON;
2451 footerDesc.button.text = buttonInfo->
text;
2452 footerDesc.button.token = buttonInfo->token;
2453 footerDesc.button.tuneId = buttonInfo->tuneId;
2454 footerDesc.button.
icon = buttonInfo->
icon;
2455 footerDesc.button.style = buttonInfo->
style;
2456 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2459 nbgl_layoutUpFooter_t upFooterDesc = {0};
2460 upFooterDesc.type = UP_FOOTER_BUTTON;
2461 upFooterDesc.button.text = buttonInfo->
text;
2462 upFooterDesc.button.token = buttonInfo->token;
2463 upFooterDesc.button.tuneId = buttonInfo->tuneId;
2464 upFooterDesc.button.
icon = buttonInfo->
icon;
2465 upFooterDesc.button.style = buttonInfo->
style;
2466 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2472 layoutInt, (
nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2478 button->obj.alignmentMarginX = BORDER_MARGIN;
2479 button->obj.alignmentMarginY = 12;
2481 if (buttonInfo->
style == BLACK_BACKGROUND) {
2482 button->innerColor =
BLACK;
2483 button->foregroundColor =
WHITE;
2486 button->innerColor =
WHITE;
2487 button->foregroundColor =
BLACK;
2489 if (buttonInfo->
style == NO_BORDER) {
2490 button->borderColor =
WHITE;
2493 if (buttonInfo->
style == BLACK_BACKGROUND) {
2494 button->borderColor =
BLACK;
2500 button->text = PIC(buttonInfo->
text);
2501 button->fontId = SMALL_BOLD_FONT;
2502 button->icon = PIC(buttonInfo->
icon);
2503 if (buttonInfo->fittingContent ==
true) {
2505 + SMALL_BUTTON_HEIGHT
2506 + ((button->icon) ? (button->icon->width + 12) : 0);
2507 button->obj.area.height = SMALL_BUTTON_HEIGHT;
2508 button->radius = SMALL_BUTTON_RADIUS_INDEX;
2509 if (buttonInfo->onBottom !=
true) {
2510 button->obj.alignmentMarginX += (
AVAILABLE_WIDTH - button->obj.area.width) / 2;
2515 button->obj.area.height = BUTTON_DIAMETER;
2516 button->radius = BUTTON_RADIUS;
2518 button->obj.alignTo = NULL;
2519 button->obj.touchMask = (1 <<
TOUCHED);
2539 tune_index_e tuneId)
2541 nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_LONG_PRESS,
2542 .longPress.text = text,
2543 .longPress.token = token,
2544 .longPress.tuneId = tuneId};
2547 if (layout == NULL) {
2551 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2567 tune_index_e tuneId)
2569 nbgl_layoutFooter_t footerDesc = {0};
2570 footerDesc.type = FOOTER_SIMPLE_TEXT;
2571 footerDesc.separationLine =
true;
2572 footerDesc.simpleText.text = text;
2573 footerDesc.simpleText.token = token;
2574 footerDesc.simpleText.tuneId = tuneId;
2575 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2591 const char *leftText,
2593 const char *rightText,
2595 tune_index_e tuneId)
2597 nbgl_layoutFooter_t footerDesc = {0};
2598 footerDesc.type = FOOTER_DOUBLE_TEXT;
2599 footerDesc.separationLine =
true;
2600 footerDesc.doubleText.leftText = leftText;
2601 footerDesc.doubleText.leftToken = leftToken;
2602 footerDesc.doubleText.rightText = rightText;
2603 footerDesc.doubleText.rightToken = rightToken;
2604 footerDesc.doubleText.tuneId = tuneId;
2605 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2616int nbgl_layoutAddHeader(
nbgl_layout_t *layout,
const nbgl_layoutHeader_t *headerDesc)
2626 if (layout == NULL) {
2629 if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2640 switch (headerDesc->type) {
2641 case HEADER_EMPTY: {
2642 layoutInt->
headerContainer->obj.area.height = headerDesc->emptySpace.height;
2645 case HEADER_BACK_AND_TEXT:
2646 case HEADER_BACK_ICON_AND_TEXT:
2647 case HEADER_EXTENDED_BACK: {
2648 const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2649 ? PIC(headerDesc->extendedBack.text)
2650 : PIC(headerDesc->backAndText.text);
2651 uint8_t backToken = (headerDesc->type == HEADER_EXTENDED_BACK)
2652 ? headerDesc->extendedBack.backToken
2653 : headerDesc->backAndText.token;
2661 (headerDesc->type == HEADER_EXTENDED_BACK)
2662 ? headerDesc->extendedBack.tuneId
2663 : headerDesc->backAndText.tuneId);
2666 "nbgl_layoutAddHeader(): no more callback obj for type %d\n",
2671 button->innerColor =
WHITE;
2672 button->foregroundColor =
BLACK;
2673 button->borderColor =
WHITE;
2674 button->obj.area.width = BACK_KEY_WIDTH;
2675 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2676 button->text = NULL;
2677 button->icon = PIC(&LEFT_ARROW_ICON);
2678 button->obj.touchMask = (1 <<
TOUCHED);
2688 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2690 image->buffer = PIC(headerDesc->backAndText.icon);
2691 image->foregroundColor =
BLACK;
2692 image->obj.alignment =
CENTER;
2698 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2702 headerDesc->extendedBack.textToken,
2703 headerDesc->extendedBack.tuneId);
2706 "nbgl_layoutAddHeader(): no more callback obj for type %d\n",
2710 textArea->obj.touchMask = (1 <<
TOUCHED);
2712 textArea->obj.alignment =
CENTER;
2713 textArea->textColor =
BLACK;
2714 textArea->obj.area.width
2717 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2718 textArea->obj.area.width -= 16 + image->buffer->width;
2720 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2721 textArea->text = text;
2722 textArea->fontId = SMALL_BOLD_FONT;
2723 textArea->textAlignment =
CENTER;
2724 textArea->wrapping =
true;
2725 uint8_t nbMaxLines = (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) ? 1 : 2;
2729 textArea->obj.area.width,
2732 textArea->obj.area.height
2734#ifndef BUILD_SCREENSHOTS
2736 "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2740 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2747 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2748 textArea->obj.alignmentMarginX = 8 + image->buffer->width / 2;
2749 image->obj.alignmentMarginX = -8 - textArea->obj.area.width / 2;
2753 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2754 && (headerDesc->extendedBack.actionIcon)) {
2760 headerDesc->extendedBack.actionToken,
2761 headerDesc->extendedBack.tuneId);
2764 "nbgl_layoutAddHeader(): no more callback obj for type %d\n",
2768 actionButton->obj.touchMask = (1 <<
TOUCHED);
2771 actionButton->obj.alignment =
MID_RIGHT;
2772 actionButton->innerColor =
WHITE;
2773 actionButton->foregroundColor
2776 actionButton->borderColor =
WHITE;
2777 actionButton->obj.area.width = BACK_KEY_WIDTH;
2778 actionButton->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2779 actionButton->text = NULL;
2780 actionButton->icon = PIC(headerDesc->extendedBack.actionIcon);
2787 layoutInt->
headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2789 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2790 && (headerDesc->extendedBack.subText != NULL)) {
2793 line = createHorizontalLine(layoutInt->
layer);
2795 line->obj.alignmentMarginY = TOUCHABLE_HEADER_BAR_HEIGHT;
2801 subTextArea->textColor =
BLACK;
2802 subTextArea->text = PIC(headerDesc->extendedBack.subText);
2803 subTextArea->textAlignment =
MID_LEFT;
2804 subTextArea->fontId = SMALL_REGULAR_FONT;
2805 subTextArea->wrapping =
true;
2807 subTextArea->obj.alignmentMarginY = SUB_HEADER_MARGIN;
2809 subTextArea->obj.area.height
2812 subTextArea->obj.area.width,
2813 subTextArea->wrapping);
2818 += subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN;
2820 if (button != NULL) {
2821 button->obj.alignmentMarginY
2822 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2824 if (textArea != NULL) {
2825 textArea->obj.alignmentMarginY
2826 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2828 if (actionButton != NULL) {
2829 actionButton->obj.alignmentMarginY
2830 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2835 case HEADER_BACK_AND_PROGRESS: {
2838 if (headerDesc->progressAndBack.withBack) {
2842 headerDesc->progressAndBack.token,
2843 headerDesc->progressAndBack.tuneId);
2846 "nbgl_layoutAddHeader(): no more callback obj for type %d\n",
2852 button->innerColor =
WHITE;
2853 button->foregroundColor =
BLACK;
2854 button->borderColor =
WHITE;
2855 button->obj.area.width = BACK_KEY_WIDTH;
2856 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2857 button->text = NULL;
2858 button->icon = PIC(&LEFT_ARROW_ICON);
2859 button->obj.touchMask = (1 <<
TOUCHED);
2868 if (headerDesc->progressAndBack.nbPages > 1
2874 progress->activePage = headerDesc->progressAndBack.activePage;
2875 progress->nbPages = headerDesc->progressAndBack.nbPages;
2876 progress->obj.area.width = 224;
2877 progress->obj.alignment =
CENTER;
2883 layoutInt->
activePage = headerDesc->progressAndBack.activePage;
2884 layoutInt->
nbPages = headerDesc->progressAndBack.nbPages;
2885 layoutInt->
headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2889 case HEADER_TITLE: {
2891 textArea->textColor =
BLACK;
2893 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2894 textArea->text = PIC(headerDesc->title.text);
2895 textArea->fontId = SMALL_BOLD_FONT;
2896 textArea->textAlignment =
CENTER;
2897 textArea->wrapping =
true;
2901 layoutInt->
headerContainer->obj.area.height = textArea->obj.area.height;
2904 case HEADER_RIGHT_TEXT: {
2908 headerDesc->rightText.token,
2909 headerDesc->rightText.tuneId);
2912 "nbgl_layoutAddHeader(): no more callback obj for type %d\n",
2917 textArea->obj.alignmentMarginX = BORDER_MARGIN;
2918 textArea->textColor =
BLACK;
2920 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2921 textArea->text = PIC(headerDesc->rightText.text);
2922 textArea->fontId = SMALL_BOLD_FONT;
2924 textArea->obj.touchMask = (1 <<
TOUCHED);
2930 layoutInt->
headerContainer->obj.area.height = textArea->obj.area.height;
2937 if (headerDesc->separationLine) {
2938 line = createHorizontalLine(layoutInt->
layer);
2965int nbgl_layoutAddExtendedFooter(
nbgl_layout_t *layout,
const nbgl_layoutFooter_t *footerDesc)
2974 if (layout == NULL) {
2977 if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2988 switch (footerDesc->type) {
2989 case FOOTER_EMPTY: {
2990 layoutInt->
footerContainer->obj.area.height = footerDesc->emptySpace.height;
2993 case FOOTER_SIMPLE_TEXT: {
2997 footerDesc->simpleText.token,
2998 footerDesc->simpleText.tuneId);
3007 textArea->obj.area.height
3008 = (footerDesc->simpleText.mutedOut) ? SMALL_FOOTER_HEIGHT : SIMPLE_FOOTER_HEIGHT;
3009 textArea->text = PIC(footerDesc->simpleText.text);
3011 = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
3012 textArea->textAlignment =
CENTER;
3013 textArea->obj.touchMask = (1 <<
TOUCHED);
3018 layoutInt->
footerContainer->obj.area.height = textArea->obj.area.height;
3021 case FOOTER_DOUBLE_TEXT: {
3025 footerDesc->doubleText.leftToken,
3026 footerDesc->doubleText.tuneId);
3032 textArea->textColor =
BLACK;
3034 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3035 textArea->text = PIC(footerDesc->doubleText.leftText);
3036 textArea->fontId = SMALL_BOLD_FONT;
3037 textArea->textAlignment =
CENTER;
3038 textArea->obj.touchMask = (1 <<
TOUCHED);
3049 footerDesc->doubleText.rightToken,
3050 footerDesc->doubleText.tuneId);
3057 textArea->textColor =
BLACK;
3059 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3060 textArea->text = PIC(footerDesc->doubleText.rightText);
3061 textArea->fontId = SMALL_BOLD_FONT;
3062 textArea->textAlignment =
CENTER;
3063 textArea->obj.touchMask = (1 <<
TOUCHED);
3069 layoutInt->
footerContainer->obj.area.height = textArea->obj.area.height;
3074 separationLine->obj.area.width = 1;
3075 separationLine->obj.area.height = layoutInt->
footerContainer->obj.area.height;
3076 separationLine->direction =
VERTICAL;
3077 separationLine->thickness = 1;
3078 separationLine->obj.alignment =
MID_LEFT;
3079 separationLine->obj.alignTo = (
nbgl_obj_t *) textArea;
3080 separationLine->obj.alignmentMarginX = -1;
3083 case FOOTER_TEXT_AND_NAV: {
3089 footerDesc->textAndNav.token,
3090 footerDesc->textAndNav.tuneId);
3096 textArea->textColor =
BLACK;
3097 textArea->obj.area.width = FOOTER_TEXT_AND_NAV_WIDTH;
3098 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3099 textArea->text = PIC(footerDesc->textAndNav.text);
3100 textArea->fontId = SMALL_BOLD_FONT;
3101 textArea->textAlignment =
CENTER;
3102 textArea->obj.touchMask = (1 <<
TOUCHED);
3114 navContainer->nbChildren = 4;
3115 navContainer->children
3118 navContainer->obj.area.width =
SCREEN_WIDTH - textArea->obj.area.width;
3119 navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3123 footerDesc->textAndNav.navigation.token,
3124 footerDesc->textAndNav.navigation.tuneId);
3133 separationLine->obj.area.width = 1;
3134 separationLine->obj.area.height = layoutInt->
footerContainer->obj.area.height;
3135 separationLine->direction =
VERTICAL;
3136 separationLine->thickness = 1;
3137 separationLine->obj.alignment =
MID_LEFT;
3138 separationLine->obj.alignTo = (
nbgl_obj_t *) navContainer;
3139 separationLine->obj.alignmentMarginX = -1;
3141 layoutInt->
activePage = footerDesc->textAndNav.navigation.activePage;
3142 layoutInt->
nbPages = footerDesc->textAndNav.navigation.nbPages;
3156 footerDesc->navigation.token,
3157 footerDesc->navigation.tuneId);
3163 layoutInt->
activePage = footerDesc->navigation.activePage;
3164 layoutInt->
nbPages = footerDesc->navigation.nbPages;
3167 case FOOTER_SIMPLE_BUTTON: {
3171 footerDesc->button.token,
3172 footerDesc->button.tuneId);
3179 button->obj.alignmentMarginY = SINGLE_BUTTON_MARGIN;
3180 if (footerDesc->button.style == BLACK_BACKGROUND) {
3181 button->innerColor =
BLACK;
3182 button->foregroundColor =
WHITE;
3185 button->innerColor =
WHITE;
3186 button->foregroundColor =
BLACK;
3189 if (footerDesc->button.style == NO_BORDER) {
3190 button->borderColor =
WHITE;
3193 if (footerDesc->button.style == BLACK_BACKGROUND) {
3194 button->borderColor =
BLACK;
3200 button->text = PIC(footerDesc->button.text);
3201 button->fontId = SMALL_BOLD_FONT;
3202 button->icon = PIC(footerDesc->button.icon);
3203 button->radius = BUTTON_RADIUS;
3204 button->obj.area.height = BUTTON_DIAMETER;
3206 if (footerDesc->button.text == NULL) {
3207 button->obj.area.width = BUTTON_DIAMETER;
3212 button->obj.touchMask = (1 <<
TOUCHED);
3220 case FOOTER_CHOICE_BUTTONS: {
3222 if ((footerDesc->choiceButtons.bottomText == NULL)
3223 || (footerDesc->choiceButtons.topText == NULL)) {
3225 "nbgl_layoutAddFooter(): FOOTER_CHOICE_BUTTONS texts cannot be NULL\n");
3233 footerDesc->choiceButtons.token,
3234 footerDesc->choiceButtons.tuneId);
3243 button->innerColor =
WHITE;
3244 if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3245 button->obj.alignmentMarginY
3246 = SINGLE_BUTTON_MARGIN;
3248 button->obj.area.height = BUTTON_DIAMETER;
3251 button->obj.alignmentMarginY
3252 = BUTTON_FROM_BOTTOM_MARGIN;
3253 button->borderColor =
WHITE;
3254 button->obj.area.height = FOOTER_IN_PAIR_HEIGHT;
3256 button->foregroundColor =
BLACK;
3258 button->radius = BUTTON_RADIUS;
3259 button->text = PIC(footerDesc->choiceButtons.bottomText);
3260 button->fontId = SMALL_BOLD_FONT;
3261 button->obj.touchMask = (1 <<
TOUCHED);
3269 if ((footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
3270 && (footerDesc->choiceButtons.style != BOTH_ROUNDED_STYLE)) {
3271 line = createHorizontalLine(layoutInt->
layer);
3283 footerDesc->choiceButtons.token,
3284 footerDesc->choiceButtons.tuneId);
3292 if (footerDesc->choiceButtons.style == ROUNDED_AND_FOOTER_STYLE) {
3293 button->obj.alignmentMarginY = TOP_BUTTON_MARGIN;
3295 else if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3296 button->obj.alignmentMarginY
3297 = SINGLE_BUTTON_MARGIN;
3300 button->obj.alignmentMarginY
3301 = TOP_BUTTON_MARGIN_WITH_ACTION;
3303 if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
3304 button->innerColor =
WHITE;
3306 button->foregroundColor =
BLACK;
3309 button->innerColor =
BLACK;
3310 button->borderColor =
BLACK;
3311 button->foregroundColor =
WHITE;
3314 button->obj.area.height = BUTTON_DIAMETER;
3315 button->radius = BUTTON_RADIUS;
3316 button->text = PIC(footerDesc->choiceButtons.topText);
3317 button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
3318 ? PIC(footerDesc->choiceButtons.topIcon)
3320 button->fontId = SMALL_BOLD_FONT;
3321 button->obj.touchMask = (1 <<
TOUCHED);
3328 if (footerDesc->choiceButtons.style == ROUNDED_AND_FOOTER_STYLE) {
3329 layoutInt->
footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
3331 else if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3332 layoutInt->
footerContainer->obj.area.height = BOTH_ROUNDED_FOOTER_HEIGHT;
3335 layoutInt->
footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
3345 if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
3346 addSwipeInternal(layoutInt,
3349 (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
3350 : footerDesc->textAndNav.navigation.token,
3351 (footerDesc->type == FOOTER_NAV)
3352 ? footerDesc->navigation.tuneId
3353 : footerDesc->textAndNav.navigation.tuneId);
3356 if (footerDesc->separationLine) {
3357 line = createHorizontalLine(layoutInt->
layer);
3363 if (separationLine != NULL) {
3387int nbgl_layoutAddUpFooter(
nbgl_layout_t *layout,
const nbgl_layoutUpFooter_t *upFooterDesc)
3396 if (layout == NULL) {
3399 if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
3413 switch (upFooterDesc->type) {
3414 case UP_FOOTER_LONG_PRESS: {
3419 upFooterDesc->longPress.token,
3420 upFooterDesc->longPress.tuneId);
3433 button->obj.alignmentMarginX = BORDER_MARGIN;
3435 button->innerColor =
BLACK;
3436 button->foregroundColor =
WHITE;
3437 button->borderColor =
BLACK;
3438 button->obj.area.width = BUTTON_DIAMETER;
3439 button->obj.area.height = BUTTON_DIAMETER;
3440 button->radius = BUTTON_RADIUS;
3445 textArea->textColor =
BLACK;
3446 textArea->text = PIC(upFooterDesc->longPress.text);
3447 textArea->textAlignment =
MID_LEFT;
3448 textArea->fontId = LARGE_MEDIUM_FONT;
3449 textArea->wrapping =
true;
3450 textArea->obj.area.width =
SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
3452 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3454 textArea->obj.alignment =
MID_LEFT;
3455 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3458 line = createHorizontalLine(layoutInt->
layer);
3464 progressBar->obj.area.height = LONG_PRESS_PROGRESS_HEIGHT;
3466 progressBar->obj.alignmentMarginY = LONG_PRESS_PROGRESS_ALIGN;
3467 progressBar->resetIfOverriden =
true;
3468 progressBar->partialRedraw =
true;
3472 case UP_FOOTER_BUTTON: {
3476 upFooterDesc->button.token,
3477 upFooterDesc->button.tuneId);
3485 button->obj.alignment =
CENTER;
3487 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3488 button->innerColor =
BLACK;
3489 button->foregroundColor =
WHITE;
3492 button->innerColor =
WHITE;
3493 button->foregroundColor =
BLACK;
3495 if (upFooterDesc->button.style == NO_BORDER) {
3496 button->borderColor =
WHITE;
3499 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3500 button->borderColor =
BLACK;
3506 button->text = PIC(upFooterDesc->button.text);
3507 button->fontId = SMALL_BOLD_FONT;
3508 button->icon = PIC(upFooterDesc->button.icon);
3510 button->obj.area.height = BUTTON_DIAMETER;
3511 button->radius = BUTTON_RADIUS;
3513 button->obj.alignTo = NULL;
3514 button->obj.touchMask = (1 <<
TOUCHED);
3519 case UP_FOOTER_HORIZONTAL_BUTTONS: {
3521 if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3522 || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3524 "nbgl_layoutAddUpFooter(): UP_FOOTER_HORIZONTAL_BUTTONS fields cannot be "
3536 upFooterDesc->horizontalButtons.leftToken,
3537 upFooterDesc->horizontalButtons.tuneId);
3545 button->obj.alignmentMarginX = BORDER_MARGIN;
3547 button->innerColor =
WHITE;
3548 button->foregroundColor =
BLACK;
3549 button->obj.area.width = BUTTON_WIDTH;
3550 button->obj.area.height = BUTTON_DIAMETER;
3551 button->radius = BUTTON_RADIUS;
3552 button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3553 button->fontId = SMALL_BOLD_FONT;
3554 button->obj.touchMask = (1 <<
TOUCHED);
3562 upFooterDesc->horizontalButtons.rightToken,
3563 upFooterDesc->horizontalButtons.tuneId);
3571 button->obj.alignmentMarginX = BORDER_MARGIN;
3572 button->innerColor =
BLACK;
3573 button->borderColor =
BLACK;
3574 button->foregroundColor =
WHITE;
3575 button->obj.area.width =
AVAILABLE_WIDTH - BUTTON_WIDTH - LEFT_CONTENT_ICON_TEXT_X;
3576 button->obj.area.height = BUTTON_DIAMETER;
3577 button->radius = BUTTON_RADIUS;
3578 button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3579 button->fontId = SMALL_BOLD_FONT;
3580 button->obj.touchMask = (1 <<
TOUCHED);
3585 case UP_FOOTER_TIP_BOX: {
3587 if (upFooterDesc->tipBox.text == NULL) {
3589 "nbgl_layoutAddUpFooter(): UP_FOOTER_TIP_BOX text cannot be NULL\n");
3594 upFooterDesc->tipBox.token,
3595 upFooterDesc->tipBox.tuneId);
3605 textArea->textColor =
BLACK;
3606 textArea->text = PIC(upFooterDesc->tipBox.text);
3607 textArea->textAlignment =
MID_LEFT;
3608 textArea->fontId = SMALL_REGULAR_FONT;
3609 textArea->wrapping =
true;
3611 if (upFooterDesc->tipBox.icon != NULL) {
3612 textArea->obj.area.width
3614 + TIP_BOX_TEXT_ICON_MARGIN;
3617 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3618 textArea->obj.alignment =
MID_LEFT;
3619 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3623 line = createHorizontalLine(layoutInt->
layer);
3627 if (upFooterDesc->tipBox.icon != NULL) {
3629 image->obj.alignmentMarginX = BORDER_MARGIN;
3631 image->foregroundColor =
BLACK;
3632 image->buffer = PIC(upFooterDesc->tipBox.icon);
3642 case UP_FOOTER_TEXT: {
3645 upFooterDesc->text.token,
3646 upFooterDesc->text.tuneId);
3657 if (strlen(PIC(upFooterDesc->text.text))) {
3660 textArea->text = PIC(upFooterDesc->text.text);
3661 textArea->textAlignment =
CENTER;
3662 textArea->fontId = SMALL_REGULAR_FONT;
3663 textArea->wrapping =
true;
3666 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3667 textArea->obj.alignment =
CENTER;
3704 tune_index_e tuneId)
3706 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_PROGRESS,
3707 .separationLine =
false,
3708 .progressAndBack.activePage = activePage,
3709 .progressAndBack.nbPages = nbPages,
3710 .progressAndBack.token = backToken,
3711 .progressAndBack.tuneId = tuneId,
3712 .progressAndBack.withBack = withBack,
3713 .progressAndBack.actionIcon = NULL,
3717 return nbgl_layoutAddHeader(layout, &headerDesc);
3732 const char *subText,
3733 uint8_t initPosition)
3741 if (layout == NULL) {
3747 container->nbChildren = 3;
3752 container->obj.alignment =
CENTER;
3756 spinner->position = initPosition;
3759 container->children[0] = (
nbgl_obj_t *) spinner;
3762 container->obj.area.height += SPINNER_HEIGHT;
3766 textArea->textColor =
BLACK;
3767 textArea->text = PIC(text);
3768 textArea->textAlignment =
CENTER;
3769 textArea->fontId = (subText != NULL) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
3770 textArea->wrapping =
true;
3771 textArea->obj.alignmentMarginY = SPINNER_TEXT_MARGIN;
3772 textArea->obj.alignTo = (
nbgl_obj_t *) spinner;
3776 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3780 container->obj.area.height += textArea->obj.alignmentMarginY + textArea->obj.area.height;
3783 container->children[1] = (
nbgl_obj_t *) textArea;
3785 if (subText != NULL) {
3789 subTextArea->textColor =
BLACK;
3790 subTextArea->text = PIC(subText);
3791 subTextArea->textAlignment =
CENTER;
3792 subTextArea->fontId = SMALL_REGULAR_FONT;
3793 subTextArea->wrapping =
true;
3794 subTextArea->obj.alignmentMarginY = SPINNER_INTER_TEXTS_MARGIN;
3795 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
3800 subTextArea->obj.area.width,
3801 subTextArea->wrapping);
3805 container->obj.area.height
3806 += subTextArea->obj.alignmentMarginY + subTextArea->obj.area.height;
3809 container->children[2] = (
nbgl_obj_t *) subTextArea;
3817 tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD;
3818 tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD;
3819 tickerCfg.tickerCallback = &spinnerTickerCallback;
3839 const char *subText,
3849 if ((layout == NULL) || (layoutInt->
container->nbChildren == 0)) {
3854 if ((container->obj.type !=
CONTAINER) || (container->nbChildren < 2)) {
3860 if (spinner->obj.type !=
SPINNER) {
3862 "nbgl_layoutUpdateSpinner(): expected SPINNER, got type %d\n",
3867 if (spinner->position != position) {
3868 spinner->position = position;
3877 "nbgl_layoutUpdateSpinner(): expected TEXT_AREA, got type %d\n",
3878 textArea->obj.type);
3881 const char *newText = PIC(text);
3882 size_t newTextLen = strlen(newText);
3884 if ((newTextLen != strlen(textArea->text)) || memcmp(textArea->text, newText, newTextLen)) {
3885 textArea->text = newText;
3890 if (subText != NULL) {
3893 if (container->nbChildren != 3) {
3895 "nbgl_layoutUpdateSpinner(): expected 3 children for subText, got %d\n",
3896 container->nbChildren);
3900 if (subTextArea->obj.type !=
TEXT_AREA) {
3902 "nbgl_layoutUpdateSpinner(): expected TEXT_AREA for subText, got type %d\n",
3903 subTextArea->obj.type);
3906 const char *newSubText = PIC(subText);
3907 size_t newSubTextLen = strlen(newSubText);
3909 if ((newSubTextLen != strlen(subTextArea->text))
3910 || memcmp(subTextArea->text, newSubText, newSubTextLen)) {
3911 subTextArea->text = newSubText;
3930 if (layout == NULL) {
3961 if ((layout == NULL) || (!layout->
isUsed)) {
3965 if (layout->
modal) {
3968 if (layout == topLayout) {
3969 topLayout = layout->
bottom;
3970 topLayout->
top = NULL;
Random Number Generation.
@ ANIM_ILLUSTRATION
animation
@ ICON_ILLUSTRATION
simple icon
#define LOG_WARN(__logger,...)
#define LOG_DEBUG(__logger,...)
#define LOG_FATAL(__logger,...)
Middle Level API of the new BOLOS Graphical Library.
#define QR_V10_NB_PIX_SIZE
#define QR_V4_NB_PIX_SIZE
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
Font screen low-Level driver API, to draw elementary forms.
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
int nbgl_layoutAddContentCenter(nbgl_layout_t *layout, const nbgl_contentCenter_t *info)
int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredInfo_t *info)
Creates an area on the center of the main panel, with a possible icon/image, a possible text in black...
int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText, nbgl_contentCenteredInfoStyle_t style)
Creates an area with given text and sub text, using the given style.
int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const nbgl_layoutProgressBar_t *barLayout)
Creates an area in main panel to display a progress bar, with a title text and a description under th...
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
void * nbgl_layout_t
type shared externally
int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
Creates an area in main panel to display a switch.
#define NBGL_INVALID_TOKEN
int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *buttonInfo)
Creates an area in main panel to display a button, with the given style.
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
int nbgl_layoutAddLeftContent(nbgl_layout_t *layout, const nbgl_layoutLeftContent_t *info)
#define SPINNER_FIXED
position to use for a "fixed" spinner
#define NBGL_NO_PROGRESS_INDICATOR
To be used when a control token shall not be used.
int nbgl_layoutRelease(nbgl_layout_t *layout)
Release the layout obtained with nbgl_layoutGet()
Internal functions/constants of NBGL layout layer.
@ SWIPE_USAGE_SUGGESTIONS
void layoutNavigationPopulate(nbgl_container_t *navContainer, const nbgl_layoutNavigationBar_t *navConfig, uint8_t layer)
bool keyboardSwipeCallback(nbgl_layoutInternal_t *layoutInt, nbgl_obj_t *obj, nbgl_touchType_t eventType)
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the layout
void layoutUpdateCallbackObjToken(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token)
#define LAYOUT_OBJ_POOL_LEN
Max number of complex objects with callback retrievable from pool.
bool layoutNavigationCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType, uint8_t nbPages, uint8_t *activePage)
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
#define NB_MAX_SCREEN_CHILDREN
static nbgl_layoutInternal_t gLayout[NB_MAX_LAYOUTS]
array of layouts, if used by modal
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_radio_s nbgl_radio_t
struct to represent a radio button (RADIO_BUTTON type)
void(* nbgl_touchCallback_t)(void *obj, nbgl_touchType_t eventType)
prototype of function to be called when a touch event is received by an object
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)
struct PACKED__ nbgl_progress_bar_s nbgl_progress_bar_t
struct to represent a progress bar (PROGRESS_BAR type)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
#define INACTIVE_ARROW_COLOR
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
#define INACTIVE_SMALL_FONT
struct PACKED__ nbgl_button_s nbgl_button_t
struct to represent a button (BUTTON type) that can contain a text and/or an icon
#define INACTIVE_TEXT_COLOR
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
struct PACKED__ nbgl_switch_s nbgl_switch_t
struct to represent a switch (size is fixed) (SWITCH type)
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
struct PACKED__ nbgl_spinner_s nbgl_spinner_t
struct to represent a "spinner", represented by the Ledger corners, in gray, with one of the corners ...
struct PACKED__ nbgl_qrcode_s nbgl_qrcode_t
struct to represent a QR code (QR_CODE type), whose size is fixed
int nbgl_screenPush(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_buttonCallback_t buttonCallback)
int nbgl_screenSet(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_buttonCallback_t buttonCallback)
void nbgl_wait_pipeline(void)
int nbgl_screenUpdateTicker(uint8_t screenIndex, const nbgl_screenTickerConfiguration_t *ticker)
int nbgl_screenPop(uint8_t screenIndex)
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
int nbgl_screenUpdateBackgroundColor(uint8_t screenIndex, color_t color)
void nbgl_screenRedraw(void)
uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj)
common types for Graphical Library
nbgl_state_t
to represent a boolean state.
@ POST_REFRESH_FORCE_POWER_OFF
Force screen power off after refresh.
@ POST_REFRESH_FORCE_POWER_ON
Force screen power on after refresh.
@ POST_REFRESH_FORCE_POWER_ON_WITH_PIPELINE
Force screen power on and enable pipeline.
nbgl_touchType_t
The different types of Touchscreen events.
@ TOUCHING
corresponding to an object that is currently touched
@ QRCODE_V10
QRCode V10, can encode text len up to 1500 chars, display size = 228*228.
@ QRCODE_V4_SMALL
QRCode V4, can encode text len up to 1500 chars, display size = 132*132.
@ QRCODE_V4
QRCode V4, can encode text len up to 62 chars, display size = 264*264.
@ VERTICAL
from top to bottom
@ HORIZONTAL
from left to right
@ LOOP_PARSING
0, 1, 2, 0, 1, 2, ...
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
@ NO_ALIGNMENT
used when parent container layout is used
@ RIGHT_TOP
on outside right
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
@ SWITCH
Switch to turn on/off something.
@ RADIO_BUTTON
Indicator to inform whether something is on or off.
@ BUTTON
Rounded rectangle button with icon and/or text.
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
@ 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)
@ NBGL_BPP_1
1 bit per pixel
@ BLACK_AND_WHITE_REFRESH
to be used for pure B&W area, when contrast is important
@ BLACK_AND_WHITE_FAST_REFRESH
to be used for pure B&W area, when contrast is not priority
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
uint16_t delayMs
delay between 2 drawings
uint8_t nbIcons
number of icons in icons array
const nbgl_icon_details_t ** icons
array of nbIcons pointers on icons
nbgl_parsingType_t parsing
This structure contains info to build a centered (vertically and horizontally) area,...
uint16_t iconHug
vertical margin to apply on top and bottom of the icon
const nbgl_icon_details_t * icon
the icon (can be null)
const char * title
title in black large (can be null)
const char * description
description in black small regular case (can be null)
const char * subText
sub-text in dark gray regular small case
uint16_t animOffsetY
vertical offset of animation in icon if integrated (but usually 0)
bool padding
if true, apply a padding of 40px at the bottom
const nbgl_animation_t * animation
the animation (can be null), used if illustrType is ANIM_ILLUSTRATION
const char * smallTitle
sub-title in black small bold case (can be null)
uint16_t animOffsetX
horizontal offset of animation in icon if integrated (but usually 0)
nbgl_contentIllustrationType_t illustrType
This structure contains info to build a centered (vertically and horizontally) area,...
const char * text2
second text (can be null)
const char * text1
first text (can be null)
bool onTop
if set to true, align only horizontally
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
This structure contains a list of names to build a list of radio buttons (on the right part of screen...
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when selecting a radio button)
uint8_t token
the token that will be used as argument of the callback
bool localized
if set to true, use nameIds and not names
uint8_t initChoice
index of the current choice
const char *const * names
array of strings giving the choices (nbChoices)
uint8_t nbChoices
number of choices
This structure contains info to build a switch (on the right) with a description (on the left),...
const char * text
main text for the switch
uint8_t token
the token that will be used as argument of the callback (unused on Nano)
nbgl_state_t initState
initial state of the switch
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played
const char * subText
description under main text (NULL terminated, single line, may be null)
This structure contains a list of [tag,value] pairs.
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
uint8_t nbMaxLinesForValue
if > 0, set the max number of lines for value field.
bool hideEndOfLastLine
if set to true, replace 3 last chars of last line by "..."
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
uint8_t startIndex
index of the first pair to get with callback
This structure contains a [tag,value] pair and possible extensions.
const nbgl_contentValueExt_t * extension
if not NULL, gives additional info on value field
const nbgl_icon_details_t * valueIcon
const char * value
string giving the value name
const char * item
string giving the tag name
const char * aliasSubName
string displayed under alias and in details view
structure defining an ASCII font
uint8_t line_height
height of a line for all characters in pixels
This structure contains info to build a clickable "bar" with a text and an icon.
bool inactive
if set to true, the bar is grayed-out and cannot be touched
const char * text
text (can be NULL)
uint8_t token
the token that will be used as argument of the callback
bool large
set to true only for the main level of OS settings
const char * subText
sub text (can be NULL)
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played
const nbgl_icon_details_t * iconLeft
a buffer containing the 1BPP icon for icon on left (can be NULL)
const nbgl_icon_details_t * iconRight
Structure containing all information when creating a layout. This structure must be passed as argumen...
nbgl_screenTickerConfiguration_t ticker
nbgl_layoutButtonCallback_t onActionCallback
the callback to be called on any action on the layout
Structure containing all information about the current layout.
uint8_t nbUsedCallbackObjs
nbgl_container_t * footerContainer
container used to store footer (buttons, nav....)
uint8_t activePage
index of active page for navigation bar
uint8_t layer
layer in screen stack
struct nbgl_layoutInternal_s * top
layout above this one, in stack
nbgl_swipe_usage_t swipeUsage
nbgl_layoutTouchCallback_t callback
user callback for all controls
struct nbgl_layoutInternal_s * bottom
layout under this one, in stack
uint8_t invertedColors
if true, means that background is black
nbgl_container_t * container
uint8_t iconIdxInAnim
current icon index in animation
nbgl_container_t * headerContainer
container used to store header (progress, back, empty space...)
uint8_t isUsed
if true, means this layout is in use
nbgl_layoutFooterType_t footerType
type of footer
nbgl_layoutHeaderType_t headerType
type of header
nbgl_container_t * upFooterContainer
uint8_t incrementAnim
if true, means that animation index is currently incrementing
uint8_t nbPages
number of pages for navigation bar
nbgl_layoutUpFooterType_t upFooterType
type of up-footer
uint8_t modal
if true, means the screen is a modal
layoutObj_t callbackObjPool[LAYOUT_OBJ_POOL_LEN]
nbgl_text_area_t * tapText
nbgl_obj_t ** children
children for main screen
const nbgl_animation_t * animation
current animation (if not NULL)
This structure contains info to build a left content area.
uint8_t nbRows
number of rows in the area
const char * title
title of area in bold
const nbgl_icon_details_t ** rowIcons
array of nbRows icon
const char ** rowTexts
array of nbRows texts (displayed in regular)
This structure contains info to build a navigation bar at the bottom of the screen.
uint8_t activePage
index of active page (from 0 to nbPages-1).
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played when pressing keys)
bool withBackKey
if set to true, the "back" key is drawn
bool withExitKey
if set to true, an exit button is drawn (X on the left)
uint8_t token
the token that will be used as argument of the callback
uint8_t nbPages
number of pages. (if 0, no navigation)
This structure contains info for Text content, to be set with nbgl_layoutAddTextContent().
const char * descriptions[NB_MAX_DESCRIPTIONS]
uint8_t nbDescriptions
number of used descriptions in above array
const char * info
description at bottom (in small gray)
const char * title
main text (in large bold font)