17#include "localization.h"
27#include "os_io_seph_ux.h"
29#include "os_helpers.h"
36#define INTERNAL_SPACE 16
38#define INNER_MARGIN 12
40#define NB_MAX_LAYOUTS 3
43#define NB_MAX_CONTAINER_CHILDREN 20
45#define TAG_VALUE_ICON_WIDTH 32
47#if defined(TARGET_STAX)
48#define RADIO_CHOICE_HEIGHT 96
49#define BAR_INTERVALE 12
50#define FOOTER_BUTTON_HEIGHT 128
51#define FOOTER_IN_PAIR_HEIGHT 80
52#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
53#define FOOTER_TEXT_AND_NAV_WIDTH 160
54#define TAP_TO_CONTINUE_MARGIN 24
55#define SUB_HEADER_MARGIN 24
56#define PRE_FIRST_TEXT_MARGIN 24
57#define INTER_PARAGRAPHS_MARGIN 40
58#define PRE_TITLE_MARGIN 24
59#define PRE_DESCRIPTION_MARGIN 16
60#define INTER_DESCRIPTIONS_MARGIN 16
61#define PRE_FIRST_ROW_MARGIN 32
62#define INTER_ROWS_MARGIN 16
63#define QR_PRE_TEXT_MARGIN 24
64#define QR_INTER_TEXTS_MARGIN 40
65#define SPINNER_TEXT_MARGIN 20
66#define SPINNER_INTER_TEXTS_MARGIN 20
67#define BAR_TEXT_MARGIN 24
68#define BAR_INTER_TEXTS_MARGIN 16
69#define LEFT_CONTENT_TEXT_PADDING 0
70#define BUTTON_FROM_BOTTOM_MARGIN 4
71#define TOP_BUTTON_MARGIN VERTICAL_BORDER_MARGIN
72#define TOP_BUTTON_MARGIN_WITH_ACTION VERTICAL_BORDER_MARGIN
73#define SINGLE_BUTTON_MARGIN 24
74#define LONG_PRESS_PROGRESS_HEIGHT 8
75#define LONG_PRESS_PROGRESS_ALIGN 1
76#define LEFT_CONTENT_ICON_TEXT_X 16
77#define TIP_BOX_MARGIN_Y 24
78#define TIP_BOX_TEXT_ICON_MARGIN 24
79#elif defined(TARGET_FLEX)
80#define RADIO_CHOICE_HEIGHT 92
81#define BAR_INTERVALE 16
82#define FOOTER_BUTTON_HEIGHT 136
83#define FOOTER_IN_PAIR_HEIGHT 88
84#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
85#define FOOTER_TEXT_AND_NAV_WIDTH 192
86#define TAP_TO_CONTINUE_MARGIN 30
87#define SUB_HEADER_MARGIN 28
88#define PRE_FIRST_TEXT_MARGIN 0
89#define INTER_PARAGRAPHS_MARGIN 24
90#define PRE_TITLE_MARGIN 16
91#define PRE_DESCRIPTION_MARGIN 24
92#define INTER_DESCRIPTIONS_MARGIN 24
93#define PRE_FIRST_ROW_MARGIN 32
94#define INTER_ROWS_MARGIN 24
95#define QR_PRE_TEXT_MARGIN 24
96#define QR_INTER_TEXTS_MARGIN 28
97#define SPINNER_TEXT_MARGIN 24
98#define SPINNER_INTER_TEXTS_MARGIN 16
99#define BAR_TEXT_MARGIN 24
100#define BAR_INTER_TEXTS_MARGIN 16
101#define LEFT_CONTENT_TEXT_PADDING 4
102#define BUTTON_FROM_BOTTOM_MARGIN 4
103#define TOP_BUTTON_MARGIN VERTICAL_BORDER_MARGIN
104#define TOP_BUTTON_MARGIN_WITH_ACTION VERTICAL_BORDER_MARGIN
105#define SINGLE_BUTTON_MARGIN 24
106#define LONG_PRESS_PROGRESS_HEIGHT 8
107#define LONG_PRESS_PROGRESS_ALIGN 1
108#define LEFT_CONTENT_ICON_TEXT_X 16
109#define TIP_BOX_MARGIN_Y 24
110#define TIP_BOX_TEXT_ICON_MARGIN 32
111#elif defined(TARGET_APEX)
112#define RADIO_CHOICE_HEIGHT 68
113#define BAR_INTERVALE 8
114#define FOOTER_BUTTON_HEIGHT 88
115#define FOOTER_IN_PAIR_HEIGHT 60
116#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 128
117#define FOOTER_TEXT_AND_NAV_WIDTH 120
118#define TAP_TO_CONTINUE_MARGIN 30
119#define SUB_HEADER_MARGIN 16
120#define PRE_FIRST_TEXT_MARGIN 0
121#define INTER_PARAGRAPHS_MARGIN 16
122#define PRE_TITLE_MARGIN 16
123#define PRE_DESCRIPTION_MARGIN 12
124#define INTER_DESCRIPTIONS_MARGIN 12
125#define PRE_FIRST_ROW_MARGIN 24
126#define INTER_ROWS_MARGIN 12
127#define QR_PRE_TEXT_MARGIN 16
128#define QR_INTER_TEXTS_MARGIN 20
129#define SPINNER_TEXT_MARGIN 16
130#define SPINNER_INTER_TEXTS_MARGIN 16
131#define BAR_TEXT_MARGIN 16
132#define BAR_INTER_TEXTS_MARGIN 12
133#define LEFT_CONTENT_TEXT_PADDING 4
134#define BUTTON_FROM_BOTTOM_MARGIN 0
135#define TOP_BUTTON_MARGIN 12
136#define TOP_BUTTON_MARGIN_WITH_ACTION 0
137#define SINGLE_BUTTON_MARGIN 16
138#define LONG_PRESS_PROGRESS_HEIGHT 4
139#define LONG_PRESS_PROGRESS_ALIGN 0
140#define LEFT_CONTENT_ICON_TEXT_X 8
141#define TIP_BOX_MARGIN_Y 12
142#define TIP_BOX_TEXT_ICON_MARGIN 20
144#error Undefined target
148#define SPINNER_REFRESH_PERIOD 400
195static uint8_t nbTouchableControls = 0;
203#if defined(TARGET_FLEX)
205#define HOLD_TO_APPROVE_STEP_PERCENT (7)
207#define HOLD_TO_APPROVE_STEP_DURATION_MS (100)
209#define HOLD_TO_APPROVE_FIRST_STEP (0)
210#elif defined(TARGET_STAX)
211#define HOLD_TO_APPROVE_STEP_PERCENT (25)
212#define HOLD_TO_APPROVE_STEP_DURATION_MS (400)
213#define HOLD_TO_APPROVE_FIRST_STEP (1)
214#elif defined(TARGET_APEX)
215#define HOLD_TO_APPROVE_STEP_PERCENT (20)
216#define HOLD_TO_APPROVE_STEP_DURATION_MS (300)
217#define HOLD_TO_APPROVE_FIRST_STEP (1)
220static inline uint8_t get_hold_to_approve_percent(uint32_t touch_duration)
222 uint8_t current_step_nb
223 = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS) + HOLD_TO_APPROVE_FIRST_STEP;
224 return (current_step_nb * HOLD_TO_APPROVE_STEP_PERCENT);
228static bool getLayoutAndLayoutObj(
nbgl_obj_t *obj,
235 if ((topLayout) && (topLayout->
isUsed)) {
242 "getLayoutAndLayoutObj(): obj found in layout %p "
243 "nbUsedCallbackObjs = %d\n",
256static void radioTouchCallback(
nbgl_obj_t *obj,
269 bool needRefresh =
false;
275 if (getLayoutAndLayoutObj(obj, &layout, &layoutObj) ==
false) {
277 if (getLayoutAndLayoutObj(obj->parent, &layout, &layoutObj) ==
false) {
280 "touchCallback(): eventType = %d, obj = %p, no active layout or obj not found\n",
298 layoutObj->
index = eventType;
306 else if (layout->
footerType == FOOTER_TEXT_AND_NAV) {
328 && (layout->
footerType == FOOTER_TEXT_AND_NAV))) {
347 layoutObj->
index = lSwitch->state;
353 radioTouchCallback(obj, eventType, layout);
360 longTouchCallback(obj, eventType, layout, layoutObj);
365#ifdef HAVE_PIEZO_SOUND
367 os_io_seph_cmd_piezo_play_tune(layoutObj->
tuneId);
394 uint8_t new_state = get_hold_to_approve_percent(touchDuration);
398 bool trigger_callback = (new_state >= 100) && (progressBar->state < 100);
401 if (new_state >= 100) {
406 if (new_state != progressBar->state) {
407 progressBar->partialRedraw =
true;
408 progressBar->state = new_state;
417 if (trigger_callback) {
428 progressBar->partialRedraw =
true;
429 progressBar->state = 0;
439static void radioTouchCallback(
nbgl_obj_t *obj,
443 uint8_t i =
NB_MAX_LAYOUTS, radioIndex = 0, foundRadio = 0xFF, foundRadioIndex;
451 while (i < layout->nbUsedCallbackObjs) {
461 foundRadioIndex = radioIndex;
463 textArea->textColor =
BLACK;
464 textArea->fontId = SMALL_BOLD_FONT;
486 textArea->fontId = SMALL_REGULAR_FONT;
494 if (foundRadio != 0xFF) {
496#ifdef HAVE_PIEZO_SOUND
508static void spinnerTickerCallback(
void)
513 if (!topLayout || !topLayout->
isUsed) {
518 while (i < topLayout->container->nbChildren) {
521 if (container->nbChildren && (container->children[0]->type ==
SPINNER)) {
525 if (spinner->position == NB_SPINNER_POSITIONS) {
526 spinner->position = 0;
538static void animTickerCallback(
void)
549 while (i < layout->container->nbChildren) {
552 if (container->children[1]->type ==
IMAGE) {
591static nbgl_line_t *createHorizontalLine(uint8_t layer)
598 line->obj.area.height = 1;
605static nbgl_line_t *createLeftVerticalLine(uint8_t layer)
611 line->obj.area.width = 1;
632 layoutObj->
obj = obj;
633 layoutObj->
token = token;
634 layoutObj->
tuneId = tuneId;
653 if (layout == NULL) {
664 if (layoutObj->
obj == obj) {
665 layoutObj->
token = token;
679 if (layout->
container->nbChildren == NB_MAX_CONTAINER_CHILDREN) {
711 layoutInt->
container->obj.touchMask = swipesMask;
729 color_t color = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
OFF_STATE))
733 = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
OFF_STATE))
741 layoutInt, (
nbgl_obj_t *) container, itemDesc->token, itemDesc->tuneId);
745 obj->
index = itemDesc->index;
749 container->nbChildren = 0;
752 container->obj.area.height
753 = LIST_ITEM_MIN_TEXT_HEIGHT
754 + 2 * (itemDesc->large ? LIST_ITEM_PRE_HEADING_LARGE : LIST_ITEM_PRE_HEADING);
756 container->obj.alignmentMarginX = BORDER_MARGIN;
758 container->obj.alignTo = NULL;
761 if (((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state ==
ON_STATE))
762 || (itemDesc->type == SWITCH_ITEM)) {
763 container->obj.touchMask = (1 <<
TOUCHED);
764 container->obj.touchId =
CONTROLS_ID + nbTouchableControls;
765 nbTouchableControls++;
769 if (itemDesc->text != NULL) {
771 textArea->textColor = color;
772 textArea->text = PIC(itemDesc->text);
773 textArea->onDrawCallback = NULL;
774 textArea->fontId = fontId;
775 textArea->wrapping =
true;
776 textArea->obj.area.width = container->obj.area.width;
777 if (itemDesc->iconLeft != NULL) {
779 textArea->obj.area.width
782 if (itemDesc->iconRight != NULL) {
784 textArea->obj.area.width
787 else if (itemDesc->type == SWITCH_ITEM) {
788 textArea->obj.area.width -= SWITCH_ICON.width + BAR_INTERVALE;
790 textArea->obj.area.height =
MAX(
791 LIST_ITEM_MIN_TEXT_HEIGHT,
793 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping));
796 textArea->obj.alignmentMarginY
797 = itemDesc->large ? LIST_ITEM_PRE_HEADING_LARGE : LIST_ITEM_PRE_HEADING;
798 if (textArea->obj.area.height > LIST_ITEM_MIN_TEXT_HEIGHT) {
799 textArea->obj.alignmentMarginY
800 -= (textArea->obj.area.height - LIST_ITEM_MIN_TEXT_HEIGHT) / 2;
803 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
804 container->nbChildren++;
808 if (itemDesc->iconLeft != NULL) {
810 imageLeft->foregroundColor = color;
811 imageLeft->buffer = PIC(itemDesc->iconLeft);
813 imageLeft->obj.alignment =
MID_LEFT;
814 imageLeft->obj.alignTo = (
nbgl_obj_t *) textArea;
815 imageLeft->obj.alignmentMarginX = BAR_INTERVALE;
816 container->children[container->nbChildren] = (
nbgl_obj_t *) imageLeft;
817 container->nbChildren++;
819 if (textArea != NULL) {
820 textArea->obj.alignmentMarginX = imageLeft->buffer->width + BAR_INTERVALE;
824 if (itemDesc->iconRight != NULL) {
826 imageRight->foregroundColor = color;
827 imageRight->buffer = PIC(itemDesc->iconRight);
830 imageRight->obj.alignmentMarginX = BAR_INTERVALE;
831 imageRight->obj.alignTo = (
nbgl_obj_t *) textArea;
833 container->children[container->nbChildren] = (
nbgl_obj_t *) imageRight;
834 container->nbChildren++;
836 else if (itemDesc->type == SWITCH_ITEM) {
838 switchObj->onColor =
BLACK;
840 switchObj->state = itemDesc->state;
842 switchObj->obj.alignmentMarginX = BAR_INTERVALE;
843 switchObj->obj.alignTo = (
nbgl_obj_t *) textArea;
845 container->children[container->nbChildren] = (
nbgl_obj_t *) switchObj;
846 container->nbChildren++;
849 if (itemDesc->subText != NULL) {
853 subTextArea->textColor = color;
854 subTextArea->text = PIC(itemDesc->subText);
855 subTextArea->textAlignment =
MID_LEFT;
856 subTextArea->fontId = SMALL_REGULAR_FONT;
858 subTextArea->wrapping =
true;
859 if (itemDesc->text != NULL) {
861 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
862 subTextArea->obj.alignmentMarginY = LIST_ITEM_HEADING_SUB_TEXT;
865 subTextArea->obj.alignment =
TOP_LEFT;
866 subTextArea->obj.alignmentMarginY = SUB_HEADER_MARGIN;
867 container->obj.area.height = SUB_HEADER_MARGIN;
869 if (itemDesc->iconLeft != NULL) {
870 subTextArea->obj.alignmentMarginX
873 subTextArea->obj.area.width = container->obj.area.width;
876 subTextArea->obj.area.width,
877 subTextArea->wrapping);
878 container->children[container->nbChildren] = (
nbgl_obj_t *) subTextArea;
879 container->nbChildren++;
880 container->obj.area.height
881 += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
903 uint16_t fullHeight = 0;
908 container->nbChildren = 0;
913 if (info->
icon != NULL) {
916 image->buffer = PIC(info->
icon);
918 image->obj.alignmentMarginY = info->
iconHug;
920 fullHeight += image->buffer->height + info->
iconHug;
921 container->children[container->nbChildren] = (
nbgl_obj_t *) image;
922 container->nbChildren++;
933 container->children[container->nbChildren] = (
nbgl_obj_t *) anim;
934 container->nbChildren++;
945 tickerCfg.tickerCallback = &animTickerCallback;
950 if (info->
title != NULL) {
953 textArea->text = PIC(info->
title);
954 textArea->textAlignment =
CENTER;
955 textArea->fontId = LARGE_MEDIUM_FONT;
956 textArea->wrapping =
true;
959 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
962 if (container->nbChildren > 0) {
965 textArea->obj.alignmentMarginY = ICON_TITLE_MARGIN + info->
iconHug;
971 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
973 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
974 container->nbChildren++;
981 textArea->textAlignment =
CENTER;
982 textArea->fontId = SMALL_BOLD_FONT;
983 textArea->wrapping =
true;
986 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
989 if (container->nbChildren > 0) {
991 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
992 textArea->obj.alignmentMarginY = VERTICAL_BORDER_MARGIN;
993 if (container->children[container->nbChildren - 1]->type ==
IMAGE) {
994 textArea->obj.alignmentMarginY = VERTICAL_BORDER_MARGIN + info->
iconHug;
997 textArea->obj.alignmentMarginY = TITLE_DESC_MARGIN;
1004 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1006 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1007 container->nbChildren++;
1014 textArea->textAlignment =
CENTER;
1015 textArea->fontId = SMALL_REGULAR_FONT;
1016 textArea->wrapping =
true;
1019 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1022 if (container->nbChildren > 0) {
1024 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1025 if (container->children[container->nbChildren - 1]->type ==
TEXT_AREA) {
1027 textArea->obj.alignmentMarginY = TITLE_DESC_MARGIN;
1030 textArea->obj.alignmentMarginY = ICON_TITLE_MARGIN + info->
iconHug;
1037 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1039 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1040 container->nbChildren++;
1046 textArea->text = PIC(info->
subText);
1047 textArea->textAlignment =
CENTER;
1048 textArea->fontId = SMALL_REGULAR_FONT;
1049 textArea->wrapping =
true;
1052 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1054 textArea->obj.area.height += 2 * 8;
1056 if (container->nbChildren > 0) {
1058 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1059 textArea->obj.alignmentMarginY = 16;
1060 if (container->children[container->nbChildren - 1]->type ==
IMAGE) {
1061 textArea->obj.alignmentMarginY += info->
iconHug;
1068 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1070 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1071 container->nbChildren++;
1074 container->obj.alignment =
CENTER;
1076 container->obj.area.height = fullHeight;
1078 container->obj.area.height += 40;
1101 if (description->
modal) {
1105 if (!gLayout[i].isUsed) {
1106 layout = &gLayout[i];
1112 layout = &gLayout[0];
1113 if (topLayout == NULL) {
1117 if (layout == NULL) {
1126 if (description->
modal) {
1127 if (topLayout != NULL) {
1129 topLayout->
top = layout;
1130 layout->
bottom = topLayout;
1134 layout->
bottom = &gLayout[0];
1135 gLayout[0].
top = layout;
1141 gLayout[0].
top = backgroundTop;
1144 nbTouchableControls = 0;
1149 if (description->
modal) {
1174 if (description->tapActionText != NULL) {
1176 const char *tapActionText = PIC(description->tapActionText);
1181 obj->
token = description->tapActionToken;
1182 obj->
tuneId = description->tapTuneId;
1186 if (strlen(tapActionText) > 0) {
1187 nbgl_layoutUpFooter_t footerDesc;
1188 footerDesc.type = UP_FOOTER_TEXT;
1189 footerDesc.text.text = tapActionText;
1190 footerDesc.text.token = description->tapActionToken;
1191 footerDesc.text.tuneId = description->tapTuneId;
1192 nbgl_layoutAddUpFooter((
nbgl_layout_t *) layout, &footerDesc);
1210 uint16_t swipesMask,
1213 tune_index_e tuneId)
1218 if (layout == NULL) {
1225 layoutInt->
tapText->text = PIC(text);
1227 layoutInt->
tapText->fontId = SMALL_REGULAR_FONT;
1231 layoutInt->
tapText->obj.alignmentMarginY = TAP_TO_CONTINUE_MARGIN;
1249 if (layout == NULL) {
1279 tune_index_e tuneId)
1286 if (layout == NULL) {
1295 button->obj.area.width = BUTTON_WIDTH;
1296 button->obj.area.height = BUTTON_DIAMETER;
1297 button->radius = BUTTON_RADIUS;
1298 button->obj.alignmentMarginX = BORDER_MARGIN;
1299 button->obj.alignmentMarginY = BORDER_MARGIN;
1300 button->foregroundColor =
BLACK;
1301 button->innerColor =
WHITE;
1303 button->obj.touchMask = (1 <<
TOUCHED);
1305 button->icon = PIC(icon);
1323 nbgl_layoutFooter_t footerDesc;
1324 footerDesc.type = FOOTER_NAV;
1326 footerDesc.navigation.activePage = info->
activePage;
1327 footerDesc.navigation.nbPages = info->
nbPages;
1328 footerDesc.navigation.withExitKey = info->
withExitKey;
1329 footerDesc.navigation.withBackKey = info->
withBackKey;
1330 footerDesc.navigation.withPageIndicator =
false;
1331 footerDesc.navigation.token = info->
token;
1332 footerDesc.navigation.tuneId = info->
tuneId;
1333 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1350 bool separationLine,
1351 tune_index_e tuneId)
1354 nbgl_layoutFooter_t footerDesc;
1355 footerDesc.type = FOOTER_SIMPLE_BUTTON;
1356 footerDesc.separationLine = separationLine;
1357 footerDesc.button.fittingContent =
false;
1358 footerDesc.button.icon = PIC(icon);
1359 footerDesc.button.text = NULL;
1360 footerDesc.button.token = token;
1361 footerDesc.button.tuneId = tuneId;
1363 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1377 listItem_t itemDesc = {0};
1380 if (layout == NULL) {
1384 if (barLayout->
text == NULL) {
1388 itemDesc.iconLeft = barLayout->
iconLeft;
1389 itemDesc.iconRight = barLayout->
iconRight;
1390 itemDesc.text = barLayout->
text;
1391 itemDesc.subText = barLayout->
subText;
1392 itemDesc.token = barLayout->
token;
1393 itemDesc.tuneId = barLayout->
tuneId;
1395 itemDesc.large = barLayout->
large;
1396 itemDesc.type = TOUCHABLE_BAR_ITEM;
1397 container = addListItem(layoutInt, &itemDesc);
1399 if (container == NULL) {
1402 return container->obj.area.height;
1416 listItem_t itemDesc = {0};
1419 if (layout == NULL) {
1423 if (switchLayout->
text == NULL) {
1427 itemDesc.text = switchLayout->
text;
1428 itemDesc.subText = switchLayout->
subText;
1429 itemDesc.token = switchLayout->
token;
1430 itemDesc.tuneId = switchLayout->
tuneId;
1431 itemDesc.state = switchLayout->
initState;
1432 itemDesc.large =
false;
1433 itemDesc.type = SWITCH_ITEM;
1434 container = addListItem(layoutInt, &itemDesc);
1436 if (container == NULL) {
1439 return container->obj.area.height;
1454 listItem_t itemDesc = {0};
1457 if (layout == NULL) {
1461 itemDesc.text = text;
1462 itemDesc.subText = subText;
1465 itemDesc.type = TEXT_ITEM;
1466 container = addListItem(layoutInt, &itemDesc);
1468 if (container == NULL) {
1471 return container->obj.area.height;
1487 const char *subText,
1493 listItem_t itemDesc = {0};
1495 if (layout == NULL) {
1499 itemDesc.text = text;
1500 itemDesc.subText = subText;
1501 itemDesc.iconRight = &MINI_PUSH_ICON;
1502 itemDesc.token = token;
1504 itemDesc.type = TOUCHABLE_BAR_ITEM;
1505 itemDesc.index = index;
1507 container = addListItem(layoutInt, &itemDesc);
1509 if (container == NULL) {
1512 return container->obj.area.height;
1523int nbgl_layoutAddLargeCaseText(
nbgl_layout_t *layout,
const char *text,
bool grayedOut)
1529 if (layout == NULL) {
1535 textArea->text = PIC(text);
1536 textArea->textAlignment =
MID_LEFT;
1537 textArea->fontId = LARGE_MEDIUM_FONT;
1539 textArea->wrapping =
true;
1541 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1544 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1545 if (layoutInt->
container->nbChildren == 0) {
1547 textArea->obj.alignmentMarginY += PRE_FIRST_TEXT_MARGIN;
1550 textArea->obj.alignmentMarginY = INTER_PARAGRAPHS_MARGIN;
1576 if (layout == NULL) {
1581 if (content->
title != NULL) {
1583 textArea->textColor =
BLACK;
1584 textArea->text = PIC(content->
title);
1585 textArea->textAlignment =
MID_LEFT;
1586 textArea->fontId = LARGE_MEDIUM_FONT;
1588 textArea->wrapping =
true;
1590 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1591 textArea->obj.alignmentMarginY = PRE_TITLE_MARGIN;
1594 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1602 textArea->textColor =
BLACK;
1604 textArea->fontId = SMALL_REGULAR_FONT;
1606 textArea->wrapping =
true;
1609 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1610 textArea->textAlignment =
MID_LEFT;
1612 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1613 textArea->obj.alignmentMarginY
1614 = (i == 0) ? PRE_DESCRIPTION_MARGIN : INTER_DESCRIPTIONS_MARGIN;
1620 if (content->
info != NULL) {
1623 textArea->text = PIC(content->
info);
1624 textArea->fontId = SMALL_REGULAR_FONT;
1626 textArea->wrapping =
true;
1629 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1630 textArea->textAlignment =
MID_LEFT;
1632 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1633 textArea->obj.alignmentMarginY = 40;
1638 return layoutInt->
container->obj.area.height;
1655 if (layout == NULL) {
1658 for (i = 0; i < choices->
nbChoices; i++) {
1675 container->nbChildren = 2;
1678 container->obj.area.height = RADIO_CHOICE_HEIGHT;
1680 container->obj.alignmentMarginX = BORDER_MARGIN;
1681 container->obj.alignTo = (
nbgl_obj_t *) NULL;
1684 button->activeColor =
BLACK;
1686 button->obj.alignTo = (
nbgl_obj_t *) container;
1689 container->children[1] = (
nbgl_obj_t *) button;
1693#ifdef HAVE_LANGUAGE_PACK
1694 textArea->text = get_ux_loc_string(choices->nameIds[i]);
1698 textArea->text = PIC(choices->
names[i]);
1700 textArea->textAlignment =
MID_LEFT;
1701 textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH;
1703 textArea->obj.alignment =
MID_LEFT;
1704 textArea->obj.alignTo = (
nbgl_obj_t *) container;
1705 container->children[0] = (
nbgl_obj_t *) textArea;
1708 container->obj.touchMask = (1 <<
TOUCHED);
1709 container->obj.touchId =
CONTROLS_ID + nbTouchableControls;
1710 nbTouchableControls++;
1715 textArea->textColor =
BLACK;
1716 textArea->fontId = SMALL_BOLD_FONT;
1721 textArea->fontId = SMALL_REGULAR_FONT;
1725 line = createHorizontalLine(layoutInt->
layer);
1726 line->obj.alignmentMarginY = -1;
1751 if (layout == NULL) {
1758 if (info->
text1 != NULL) {
1759 if (info->
style != NORMAL_INFO) {
1766 if (info->
text2 != NULL) {
1767 if (info->
style != LARGE_CASE_BOLD_INFO) {
1774 if (info->text3 != NULL) {
1775 if (info->
style == LARGE_CASE_GRAY_INFO) {
1776 centeredInfo.
subText = info->text3;
1782 container = addContentCenter(layoutInt, ¢eredInfo);
1785 container->obj.alignmentMarginX = BORDER_MARGIN;
1786 container->obj.alignmentMarginY = BORDER_MARGIN + info->offsetY;
1790 container->obj.alignmentMarginY = info->offsetY;
1793 return container->obj.area.height;
1810 if (layout == NULL) {
1814 container = addContentCenter(layoutInt, info);
1816 return container->obj.area.height;
1834 if (layout == NULL) {
1840 container->nbChildren = info->
nbRows + 1;
1844 container->obj.alignmentMarginX = BORDER_MARGIN;
1848 textArea->textColor =
BLACK;
1849 textArea->text = PIC(info->
title);
1850 textArea->textAlignment =
MID_LEFT;
1851 textArea->fontId = LARGE_MEDIUM_FONT;
1852 textArea->wrapping =
true;
1854 textArea->obj.alignmentMarginY = 24;
1858 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1860 container->obj.area.height += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1862 container->children[0] = (
nbgl_obj_t *) textArea;
1864 for (row = 0; row < info->
nbRows; row++) {
1870 rowContainer->nbChildren = 2;
1875 image->foregroundColor =
BLACK;
1876 image->buffer = PIC(info->
rowIcons[row]);
1877 rowContainer->children[0] = (
nbgl_obj_t *) image;
1880 textArea->textColor =
BLACK;
1881 textArea->text = PIC(info->
rowTexts[row]);
1882 textArea->textAlignment =
MID_LEFT;
1883 textArea->fontId = SMALL_REGULAR_FONT;
1884 textArea->wrapping =
true;
1885 textArea->obj.area.width
1888 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1890 rowContainer->children[1] = (
nbgl_obj_t *) textArea;
1891 rowContainer->obj.area.height
1892 =
MAX(image->buffer->height, textArea->obj.area.height + LEFT_CONTENT_TEXT_PADDING);
1895 rowContainer->obj.alignmentMarginY = PRE_FIRST_ROW_MARGIN;
1898 rowContainer->obj.alignmentMarginY = INTER_ROWS_MARGIN;
1900 container->children[1 + row] = (
nbgl_obj_t *) rowContainer;
1901 container->obj.area.height
1902 += rowContainer->obj.area.height + rowContainer->obj.alignmentMarginY;
1906 return container->obj.area.height;
1918int nbgl_layoutAddQRCode(
nbgl_layout_t *layout,
const nbgl_layoutQRCode_t *info)
1924 uint16_t fullHeight = 0;
1927 if (layout == NULL) {
1935 container->nbChildren = 0;
1939 if (strlen(PIC(info->url)) > 62) {
1945 qrcode->foregroundColor =
BLACK;
1951 qrcode->obj.area.width
1954 qrcode->obj.area.width
1957 qrcode->obj.area.height = qrcode->obj.area.width;
1958 qrcode->text = PIC(info->url);
1962 fullHeight += qrcode->obj.area.height;
1963 container->children[container->nbChildren] = (
nbgl_obj_t *) qrcode;
1964 container->nbChildren++;
1966 if (info->text1 != NULL) {
1968 textArea->textColor =
BLACK;
1969 textArea->text = PIC(info->text1);
1970 textArea->textAlignment =
CENTER;
1971 textArea->fontId = (info->largeText1 ==
true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1972 textArea->wrapping =
true;
1975 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1977 textArea->obj.alignTo = (
nbgl_obj_t *) container->children[container->nbChildren - 1];
1978 textArea->obj.alignmentMarginY = QR_PRE_TEXT_MARGIN;
1980 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1982 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
1983 container->nbChildren++;
1985 if (info->text2 != NULL) {
1988 textArea->text = PIC(info->text2);
1989 textArea->textAlignment =
CENTER;
1990 textArea->fontId = 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 if (info->text1 != NULL) {
1998 textArea->obj.alignmentMarginY = QR_INTER_TEXTS_MARGIN;
2001 textArea->obj.alignmentMarginY = QR_PRE_TEXT_MARGIN + 8;
2004 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY + 8;
2006 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
2007 container->nbChildren++;
2010 if ((fullHeight >= (layoutInt->
container->obj.area.height - 16))
2015 qrcode->obj.area.height = qrcode->obj.area.width;
2018 container->obj.area.height = fullHeight;
2020 if (info->centered) {
2021 container->obj.alignment =
CENTER;
2025 container->obj.alignTo
2028 container->obj.alignmentMarginY = info->offsetY;
2047int nbgl_layoutAddChoiceButtons(
nbgl_layout_t *layout,
const nbgl_layoutChoiceButtons_t *info)
2049 nbgl_layoutFooter_t footerDesc;
2050 footerDesc.type = FOOTER_CHOICE_BUTTONS;
2051 footerDesc.separationLine =
false;
2052 footerDesc.choiceButtons.bottomText = info->bottomText;
2053 footerDesc.choiceButtons.token = info->token;
2054 footerDesc.choiceButtons.topText = info->topText;
2055 footerDesc.choiceButtons.topIcon = info->topIcon;
2056 footerDesc.choiceButtons.style = info->style;
2057 footerDesc.choiceButtons.tuneId = info->tuneId;
2058 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2071 const nbgl_layoutHorizontalButtons_t *info)
2073 nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_HORIZONTAL_BUTTONS,
2074 .horizontalButtons.leftIcon = info->leftIcon,
2075 .horizontalButtons.leftToken = info->leftToken,
2076 .horizontalButtons.rightText = info->rightText,
2077 .horizontalButtons.rightToken = info->rightToken,
2078 .horizontalButtons.tuneId = info->tuneId};
2081 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2098 if (layout == NULL) {
2102 for (i = 0; i < list->
nbPairs; i++) {
2104 uint16_t fullHeight = 0;
2108 uint8_t nbChildren = 2;
2111 if (list->
pairs != NULL) {
2112 pair = &list->
pairs[i];
2136 itemTextArea->text = PIC(pair->
item);
2137 itemTextArea->textAlignment =
MID_LEFT;
2138 itemTextArea->fontId = SMALL_REGULAR_FONT;
2139 itemTextArea->wrapping =
true;
2142 itemTextArea->fontId, itemTextArea->text,
AVAILABLE_WIDTH, itemTextArea->wrapping);
2143 container->children[container->nbChildren] = (
nbgl_obj_t *) itemTextArea;
2144 container->nbChildren++;
2146 fullHeight += itemTextArea->obj.area.height;
2149 valueTextArea->textColor =
BLACK;
2150 valueTextArea->text = PIC(pair->
value);
2151 valueTextArea->textAlignment =
MID_LEFT;
2153 valueTextArea->fontId = SMALL_BOLD_FONT;
2156 valueTextArea->fontId = LARGE_MEDIUM_FONT;
2164 valueIcon = &MINI_PUSH_ICON;
2171 valueTextArea->obj.area.width
2178 valueTextArea->text,
2179 valueTextArea->obj.area.width,
2190 valueTextArea->nbMaxLines = 2;
2191 valueTextArea->hideEndOfLastLine =
true;
2194 valueTextArea->obj.area.height = nbLines * font->
line_height;
2196 valueTextArea->obj.alignmentMarginY = TAG_VALUE_INTERVALE;
2197 valueTextArea->obj.alignTo = (
nbgl_obj_t *) itemTextArea;
2198 valueTextArea->wrapping = list->
wrapping;
2199 container->children[container->nbChildren] = (
nbgl_obj_t *) valueTextArea;
2200 container->nbChildren++;
2202 fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
2203 if (valueIcon != NULL) {
2209 image->foregroundColor =
BLACK;
2210 image->buffer = valueIcon;
2212 image->obj.alignmentMarginX = VALUE_ICON_INTERVALE;
2213 image->obj.alignTo = (
nbgl_obj_t *) valueTextArea;
2215 container->obj.touchMask = (1 <<
TOUCHED);
2218 container->children[container->nbChildren] = (
nbgl_obj_t *) image;
2219 container->nbChildren++;
2225 textArea->textColor =
BLACK;
2227 textArea->textAlignment =
MID_LEFT;
2228 textArea->nbMaxLines = 1;
2229 textArea->fontId = SMALL_REGULAR_FONT;
2231 textArea->obj.area.width = valueTextArea->obj.area.width;
2233 textArea->obj.alignmentMarginY = TAG_VALUE_INTERVALE;
2234 textArea->obj.alignTo = (
nbgl_obj_t *) valueTextArea;
2235 textArea->wrapping = list->
wrapping;
2236 textArea->hideEndOfLastLine
2238 > textArea->obj.area.width);
2239 container->children[container->nbChildren] = (
nbgl_obj_t *) textArea;
2240 container->nbChildren++;
2241 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
2246 container->obj.area.height = fullHeight;
2248 container->obj.alignmentMarginX = BORDER_MARGIN;
2250 container->obj.alignmentMarginY = INTER_TAG_VALUE_MARGIN;
2258 container->obj.alignmentMarginY = INTER_TAG_VALUE_MARGIN;
2261 container->obj.alignmentMarginY = PRE_TAG_VALUE_MARGIN;
2286 const char *subText,
2295 if (layout == NULL) {
2302 container->nbChildren = (subText != NULL) ? 3 : 2;
2307 container->obj.alignment =
CENTER;
2311 progress->foregroundColor =
BLACK;
2312 progress->withBorder =
true;
2313 progress->state = percentage;
2314 progress->obj.area.width = PROGRESSBAR_WIDTH;
2315 progress->obj.area.height = PROGRESSBAR_HEIGHT;
2319 container->children[0] = (
nbgl_obj_t *) progress;
2322 container->obj.area.height = progress->obj.alignmentMarginY + progress->obj.area.height;
2326 textArea->textColor =
BLACK;
2327 textArea->text = PIC(text);
2328 textArea->textAlignment =
CENTER;
2329 textArea->fontId = LARGE_MEDIUM_FONT;
2330 textArea->wrapping =
true;
2331 textArea->obj.alignmentMarginY = BAR_TEXT_MARGIN;
2332 textArea->obj.alignTo = (
nbgl_obj_t *) progress;
2336 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2340 container->obj.area.height += textArea->obj.alignmentMarginY + textArea->obj.area.height;
2343 container->children[1] = (
nbgl_obj_t *) textArea;
2345 if (subText != NULL) {
2349 subTextArea->textColor =
BLACK;
2350 subTextArea->text = PIC(subText);
2351 subTextArea->textAlignment =
CENTER;
2352 subTextArea->fontId = SMALL_REGULAR_FONT;
2353 subTextArea->wrapping =
true;
2354 subTextArea->obj.alignmentMarginY = BAR_INTER_TEXTS_MARGIN;
2355 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
2360 subTextArea->obj.area.width,
2361 subTextArea->wrapping);
2365 container->obj.area.height
2366 += subTextArea->obj.alignmentMarginY + subTextArea->obj.area.height;
2369 container->children[2] = (
nbgl_obj_t *) subTextArea;
2372 container->obj.area.height = (container->obj.area.height + 7) & 0xFFF8;
2391 line = createHorizontalLine(layoutInt->
layer);
2392 line->obj.alignmentMarginY = -1;
2411 if (layout == NULL) {
2416 if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2418 nbgl_layoutFooter_t footerDesc;
2419 footerDesc.type = FOOTER_SIMPLE_BUTTON;
2420 footerDesc.separationLine =
false;
2421 footerDesc.button.text = buttonInfo->
text;
2422 footerDesc.button.token = buttonInfo->token;
2423 footerDesc.button.tuneId = buttonInfo->tuneId;
2424 footerDesc.button.
icon = buttonInfo->
icon;
2425 footerDesc.button.style = buttonInfo->
style;
2426 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2429 nbgl_layoutUpFooter_t upFooterDesc;
2430 upFooterDesc.type = UP_FOOTER_BUTTON;
2431 upFooterDesc.button.text = buttonInfo->
text;
2432 upFooterDesc.button.token = buttonInfo->token;
2433 upFooterDesc.button.tuneId = buttonInfo->tuneId;
2434 upFooterDesc.button.
icon = buttonInfo->
icon;
2435 upFooterDesc.button.style = buttonInfo->
style;
2436 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2442 layoutInt, (
nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2447 button->obj.alignmentMarginX = BORDER_MARGIN;
2448 button->obj.alignmentMarginY = 12;
2450 if (buttonInfo->
style == BLACK_BACKGROUND) {
2451 button->innerColor =
BLACK;
2452 button->foregroundColor =
WHITE;
2455 button->innerColor =
WHITE;
2456 button->foregroundColor =
BLACK;
2458 if (buttonInfo->
style == NO_BORDER) {
2459 button->borderColor =
WHITE;
2462 if (buttonInfo->
style == BLACK_BACKGROUND) {
2463 button->borderColor =
BLACK;
2469 button->text = PIC(buttonInfo->
text);
2470 button->fontId = SMALL_BOLD_FONT;
2471 button->icon = PIC(buttonInfo->
icon);
2472 if (buttonInfo->fittingContent ==
true) {
2474 + SMALL_BUTTON_HEIGHT
2475 + ((button->icon) ? (button->icon->width + 12) : 0);
2476 button->obj.area.height = SMALL_BUTTON_HEIGHT;
2477 button->radius = SMALL_BUTTON_RADIUS_INDEX;
2478 if (buttonInfo->onBottom !=
true) {
2479 button->obj.alignmentMarginX += (
AVAILABLE_WIDTH - button->obj.area.width) / 2;
2484 button->obj.area.height = BUTTON_DIAMETER;
2485 button->radius = BUTTON_RADIUS;
2487 button->obj.alignTo = NULL;
2488 button->obj.touchMask = (1 <<
TOUCHED);
2508 tune_index_e tuneId)
2510 nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_LONG_PRESS,
2511 .longPress.text = text,
2512 .longPress.token = token,
2513 .longPress.tuneId = tuneId};
2516 if (layout == NULL) {
2520 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2536 tune_index_e tuneId)
2538 nbgl_layoutFooter_t footerDesc;
2539 footerDesc.type = FOOTER_SIMPLE_TEXT;
2540 footerDesc.separationLine =
true;
2541 footerDesc.simpleText.text = text;
2542 footerDesc.simpleText.mutedOut =
false;
2543 footerDesc.simpleText.token = token;
2544 footerDesc.simpleText.tuneId = tuneId;
2545 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2561 const char *leftText,
2563 const char *rightText,
2565 tune_index_e tuneId)
2567 nbgl_layoutFooter_t footerDesc;
2568 footerDesc.type = FOOTER_DOUBLE_TEXT;
2569 footerDesc.separationLine =
true;
2570 footerDesc.doubleText.leftText = leftText;
2571 footerDesc.doubleText.leftToken = leftToken;
2572 footerDesc.doubleText.rightText = rightText;
2573 footerDesc.doubleText.rightToken = rightToken;
2574 footerDesc.doubleText.tuneId = tuneId;
2575 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2586int nbgl_layoutAddHeader(
nbgl_layout_t *layout,
const nbgl_layoutHeader_t *headerDesc)
2596 if (layout == NULL) {
2599 if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2610 switch (headerDesc->type) {
2611 case HEADER_EMPTY: {
2612 layoutInt->
headerContainer->obj.area.height = headerDesc->emptySpace.height;
2615 case HEADER_BACK_AND_TEXT:
2616 case HEADER_BACK_ICON_AND_TEXT:
2617 case HEADER_EXTENDED_BACK: {
2618 const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2619 ? PIC(headerDesc->extendedBack.text)
2620 : PIC(headerDesc->backAndText.text);
2621 uint8_t backToken = (headerDesc->type == HEADER_EXTENDED_BACK)
2622 ? headerDesc->extendedBack.backToken
2623 : headerDesc->backAndText.token;
2632 (headerDesc->type == HEADER_EXTENDED_BACK)
2633 ? headerDesc->extendedBack.tuneId
2634 : headerDesc->backAndText.tuneId);
2641 button->innerColor =
WHITE;
2643 button->borderColor =
WHITE;
2644 button->obj.area.width = BACK_KEY_WIDTH;
2645 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2646 button->text = NULL;
2647 button->icon = PIC(&LEFT_ARROW_ICON);
2657 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2659 image->buffer = PIC(headerDesc->backAndText.icon);
2660 image->foregroundColor =
BLACK;
2661 image->obj.alignment =
CENTER;
2667 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2671 headerDesc->extendedBack.textToken,
2672 headerDesc->extendedBack.tuneId);
2676 textArea->obj.touchMask = (1 <<
TOUCHED);
2678 textArea->obj.alignment =
CENTER;
2679 textArea->textColor =
BLACK;
2680 textArea->obj.area.width
2683 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2684 textArea->obj.area.width -= 16 + image->buffer->width;
2686 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2687 textArea->text = text;
2688 textArea->fontId = SMALL_BOLD_FONT;
2689 textArea->textAlignment =
CENTER;
2690 textArea->wrapping =
true;
2691 uint8_t nbMaxLines = (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) ? 1 : 2;
2695 textArea->obj.area.width,
2698 textArea->obj.area.height
2700#ifndef BUILD_SCREENSHOTS
2702 "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2706 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2713 if (headerDesc->type == HEADER_BACK_ICON_AND_TEXT) {
2714 textArea->obj.alignmentMarginX = 8 + image->buffer->width / 2;
2715 image->obj.alignmentMarginX = -8 - textArea->obj.area.width / 2;
2719 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2720 && (headerDesc->extendedBack.actionIcon)) {
2726 headerDesc->extendedBack.actionToken,
2727 headerDesc->extendedBack.tuneId);
2731 actionButton->obj.touchMask = (1 <<
TOUCHED);
2734 actionButton->obj.alignment =
MID_RIGHT;
2735 actionButton->innerColor =
WHITE;
2736 button->foregroundColor
2739 actionButton->borderColor =
WHITE;
2740 actionButton->obj.area.width = BACK_KEY_WIDTH;
2741 actionButton->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2742 actionButton->text = NULL;
2743 actionButton->icon = PIC(headerDesc->extendedBack.actionIcon);
2750 layoutInt->
headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2752 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2753 && (headerDesc->extendedBack.subText != NULL)) {
2756 line = createHorizontalLine(layoutInt->
layer);
2758 line->obj.alignmentMarginY = TOUCHABLE_HEADER_BAR_HEIGHT;
2764 subTextArea->textColor =
BLACK;
2765 subTextArea->text = PIC(headerDesc->extendedBack.subText);
2766 subTextArea->textAlignment =
MID_LEFT;
2767 subTextArea->fontId = SMALL_REGULAR_FONT;
2768 subTextArea->wrapping =
true;
2770 subTextArea->obj.alignmentMarginY = SUB_HEADER_MARGIN;
2772 subTextArea->obj.area.height
2775 subTextArea->obj.area.width,
2776 subTextArea->wrapping);
2781 += subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN;
2783 if (button != NULL) {
2784 button->obj.alignmentMarginY
2785 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2787 if (textArea != NULL) {
2788 textArea->obj.alignmentMarginY
2789 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2791 if (actionButton != NULL) {
2792 actionButton->obj.alignmentMarginY
2793 -= (subTextArea->obj.area.height + 2 * SUB_HEADER_MARGIN) / 2;
2798 case HEADER_BACK_AND_PROGRESS: {
2801 if (headerDesc->progressAndBack.withBack) {
2805 headerDesc->progressAndBack.token,
2806 headerDesc->progressAndBack.tuneId);
2812 button->innerColor =
WHITE;
2813 button->foregroundColor =
BLACK;
2814 button->borderColor =
WHITE;
2815 button->obj.area.width = BACK_KEY_WIDTH;
2816 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2817 button->text = NULL;
2818 button->icon = PIC(&LEFT_ARROW_ICON);
2819 button->obj.touchMask = (1 <<
TOUCHED);
2828 if (headerDesc->progressAndBack.nbPages > 1
2834 progress->activePage = headerDesc->progressAndBack.activePage;
2835 progress->nbPages = headerDesc->progressAndBack.nbPages;
2836 progress->obj.area.width = 224;
2837 progress->obj.alignment =
CENTER;
2843 layoutInt->
activePage = headerDesc->progressAndBack.activePage;
2844 layoutInt->
nbPages = headerDesc->progressAndBack.nbPages;
2845 layoutInt->
headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2849 case HEADER_TITLE: {
2851 textArea->textColor =
BLACK;
2853 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2854 textArea->text = PIC(headerDesc->title.text);
2855 textArea->fontId = SMALL_BOLD_FONT;
2856 textArea->textAlignment =
CENTER;
2857 textArea->wrapping =
true;
2861 layoutInt->
headerContainer->obj.area.height = textArea->obj.area.height;
2864 case HEADER_RIGHT_TEXT: {
2868 headerDesc->rightText.token,
2869 headerDesc->rightText.tuneId);
2874 textArea->obj.alignmentMarginX = BORDER_MARGIN;
2875 textArea->textColor =
BLACK;
2877 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2878 textArea->text = PIC(headerDesc->rightText.text);
2879 textArea->fontId = SMALL_BOLD_FONT;
2881 textArea->obj.touchMask = (1 <<
TOUCHED);
2887 layoutInt->
headerContainer->obj.area.height = textArea->obj.area.height;
2894 if (headerDesc->separationLine) {
2895 line = createHorizontalLine(layoutInt->
layer);
2922int nbgl_layoutAddExtendedFooter(
nbgl_layout_t *layout,
const nbgl_layoutFooter_t *footerDesc)
2931 if (layout == NULL) {
2934 if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2945 switch (footerDesc->type) {
2946 case FOOTER_EMPTY: {
2947 layoutInt->
footerContainer->obj.area.height = footerDesc->emptySpace.height;
2950 case FOOTER_SIMPLE_TEXT: {
2954 footerDesc->simpleText.token,
2955 footerDesc->simpleText.tuneId);
2963 textArea->obj.area.height
2964 = (footerDesc->simpleText.mutedOut) ? SMALL_FOOTER_HEIGHT : SIMPLE_FOOTER_HEIGHT;
2965 textArea->text = PIC(footerDesc->simpleText.text);
2967 = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
2968 textArea->textAlignment =
CENTER;
2969 textArea->obj.touchMask = (1 <<
TOUCHED);
2974 layoutInt->
footerContainer->obj.area.height = textArea->obj.area.height;
2977 case FOOTER_DOUBLE_TEXT: {
2981 footerDesc->doubleText.leftToken,
2982 footerDesc->doubleText.tuneId);
2987 textArea->textColor =
BLACK;
2989 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2990 textArea->text = PIC(footerDesc->doubleText.leftText);
2991 textArea->fontId = SMALL_BOLD_FONT;
2992 textArea->textAlignment =
CENTER;
2993 textArea->obj.touchMask = (1 <<
TOUCHED);
3004 footerDesc->doubleText.rightToken,
3005 footerDesc->doubleText.tuneId);
3011 textArea->textColor =
BLACK;
3013 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3014 textArea->text = PIC(footerDesc->doubleText.rightText);
3015 textArea->fontId = SMALL_BOLD_FONT;
3016 textArea->textAlignment =
CENTER;
3017 textArea->obj.touchMask = (1 <<
TOUCHED);
3023 layoutInt->
footerContainer->obj.area.height = textArea->obj.area.height;
3028 separationLine->obj.area.width = 1;
3029 separationLine->obj.area.height = layoutInt->
footerContainer->obj.area.height;
3030 separationLine->direction =
VERTICAL;
3031 separationLine->thickness = 1;
3032 separationLine->obj.alignment =
MID_LEFT;
3033 separationLine->obj.alignTo = (
nbgl_obj_t *) textArea;
3034 separationLine->obj.alignmentMarginX = -1;
3037 case FOOTER_TEXT_AND_NAV: {
3043 footerDesc->textAndNav.token,
3044 footerDesc->textAndNav.tuneId);
3049 textArea->textColor =
BLACK;
3050 textArea->obj.area.width = FOOTER_TEXT_AND_NAV_WIDTH;
3051 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3052 textArea->text = PIC(footerDesc->textAndNav.text);
3053 textArea->fontId = SMALL_BOLD_FONT;
3054 textArea->textAlignment =
CENTER;
3055 textArea->obj.touchMask = (1 <<
TOUCHED);
3067 navContainer->nbChildren = 4;
3068 navContainer->children
3071 navContainer->obj.area.width =
SCREEN_WIDTH - textArea->obj.area.width;
3072 navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
3076 footerDesc->textAndNav.navigation.token,
3077 footerDesc->textAndNav.navigation.tuneId);
3085 separationLine->obj.area.width = 1;
3086 separationLine->obj.area.height = layoutInt->
footerContainer->obj.area.height;
3087 separationLine->direction =
VERTICAL;
3088 separationLine->thickness = 1;
3089 separationLine->obj.alignment =
MID_LEFT;
3090 separationLine->obj.alignTo = (
nbgl_obj_t *) navContainer;
3091 separationLine->obj.alignmentMarginX = -1;
3093 layoutInt->
activePage = footerDesc->textAndNav.navigation.activePage;
3094 layoutInt->
nbPages = footerDesc->textAndNav.navigation.nbPages;
3108 footerDesc->navigation.token,
3109 footerDesc->navigation.tuneId);
3114 layoutInt->
activePage = footerDesc->navigation.activePage;
3115 layoutInt->
nbPages = footerDesc->navigation.nbPages;
3118 case FOOTER_SIMPLE_BUTTON: {
3122 footerDesc->button.token,
3123 footerDesc->button.tuneId);
3129 button->obj.alignmentMarginY = SINGLE_BUTTON_MARGIN;
3130 if (footerDesc->button.style == BLACK_BACKGROUND) {
3131 button->innerColor =
BLACK;
3132 button->foregroundColor =
WHITE;
3135 button->innerColor =
WHITE;
3136 button->foregroundColor =
BLACK;
3139 if (footerDesc->button.style == NO_BORDER) {
3140 button->borderColor =
WHITE;
3143 if (footerDesc->button.style == BLACK_BACKGROUND) {
3144 button->borderColor =
BLACK;
3150 button->text = PIC(footerDesc->button.text);
3151 button->fontId = SMALL_BOLD_FONT;
3152 button->icon = PIC(footerDesc->button.icon);
3153 button->radius = BUTTON_RADIUS;
3154 button->obj.area.height = BUTTON_DIAMETER;
3156 if (footerDesc->button.text == NULL) {
3157 button->obj.area.width = BUTTON_DIAMETER;
3162 button->obj.touchMask = (1 <<
TOUCHED);
3170 case FOOTER_CHOICE_BUTTONS: {
3172 if ((footerDesc->choiceButtons.bottomText == NULL)
3173 || (footerDesc->choiceButtons.topText == NULL)) {
3181 footerDesc->choiceButtons.token,
3182 footerDesc->choiceButtons.tuneId);
3190 button->innerColor =
WHITE;
3191 if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3192 button->obj.alignmentMarginY
3193 = SINGLE_BUTTON_MARGIN;
3195 button->obj.area.height = BUTTON_DIAMETER;
3198 button->obj.alignmentMarginY
3199 = BUTTON_FROM_BOTTOM_MARGIN;
3200 button->borderColor =
WHITE;
3201 button->obj.area.height = FOOTER_IN_PAIR_HEIGHT;
3203 button->foregroundColor =
BLACK;
3205 button->radius = BUTTON_RADIUS;
3206 button->text = PIC(footerDesc->choiceButtons.bottomText);
3207 button->fontId = SMALL_BOLD_FONT;
3208 button->obj.touchMask = (1 <<
TOUCHED);
3216 if ((footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
3217 && (footerDesc->choiceButtons.style != BOTH_ROUNDED_STYLE)) {
3218 line = createHorizontalLine(layoutInt->
layer);
3230 footerDesc->choiceButtons.token,
3231 footerDesc->choiceButtons.tuneId);
3238 if (footerDesc->choiceButtons.style == ROUNDED_AND_FOOTER_STYLE) {
3239 button->obj.alignmentMarginY = TOP_BUTTON_MARGIN;
3241 else if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3242 button->obj.alignmentMarginY
3243 = SINGLE_BUTTON_MARGIN;
3246 button->obj.alignmentMarginY
3247 = TOP_BUTTON_MARGIN_WITH_ACTION;
3249 if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
3250 button->innerColor =
WHITE;
3252 button->foregroundColor =
BLACK;
3255 button->innerColor =
BLACK;
3256 button->borderColor =
BLACK;
3257 button->foregroundColor =
WHITE;
3260 button->obj.area.height = BUTTON_DIAMETER;
3261 button->radius = BUTTON_RADIUS;
3262 button->text = PIC(footerDesc->choiceButtons.topText);
3263 button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
3264 ? PIC(footerDesc->choiceButtons.topIcon)
3266 button->fontId = SMALL_BOLD_FONT;
3267 button->obj.touchMask = (1 <<
TOUCHED);
3274 if (footerDesc->choiceButtons.style == ROUNDED_AND_FOOTER_STYLE) {
3275 layoutInt->
footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
3277 else if (footerDesc->choiceButtons.style == BOTH_ROUNDED_STYLE) {
3278 layoutInt->
footerContainer->obj.area.height = BOTH_ROUNDED_FOOTER_HEIGHT;
3281 layoutInt->
footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
3291 if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
3292 addSwipeInternal(layoutInt,
3295 (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
3296 : footerDesc->textAndNav.navigation.token,
3297 (footerDesc->type == FOOTER_NAV)
3298 ? footerDesc->navigation.tuneId
3299 : footerDesc->textAndNav.navigation.tuneId);
3302 if (footerDesc->separationLine) {
3303 line = createHorizontalLine(layoutInt->
layer);
3309 if (separationLine != NULL) {
3333int nbgl_layoutAddUpFooter(
nbgl_layout_t *layout,
const nbgl_layoutUpFooter_t *upFooterDesc)
3342 if (layout == NULL) {
3345 if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
3359 switch (upFooterDesc->type) {
3360 case UP_FOOTER_LONG_PRESS: {
3365 upFooterDesc->longPress.token,
3366 upFooterDesc->longPress.tuneId);
3378 button->obj.alignmentMarginX = BORDER_MARGIN;
3380 button->innerColor =
BLACK;
3381 button->foregroundColor =
WHITE;
3382 button->borderColor =
BLACK;
3383 button->obj.area.width = BUTTON_DIAMETER;
3384 button->obj.area.height = BUTTON_DIAMETER;
3385 button->radius = BUTTON_RADIUS;
3386 button->icon = PIC(&VALIDATE_ICON);
3390 textArea->textColor =
BLACK;
3391 textArea->text = PIC(upFooterDesc->longPress.text);
3392 textArea->textAlignment =
MID_LEFT;
3393 textArea->fontId = LARGE_MEDIUM_FONT;
3394 textArea->wrapping =
true;
3395 textArea->obj.area.width =
SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
3397 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3399 textArea->obj.alignment =
MID_LEFT;
3400 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3403 line = createHorizontalLine(layoutInt->
layer);
3409 progressBar->obj.area.height = LONG_PRESS_PROGRESS_HEIGHT;
3411 progressBar->obj.alignmentMarginY = LONG_PRESS_PROGRESS_ALIGN;
3412 progressBar->resetIfOverriden =
true;
3413 progressBar->partialRedraw =
true;
3417 case UP_FOOTER_BUTTON: {
3421 upFooterDesc->button.token,
3422 upFooterDesc->button.tuneId);
3429 button->obj.alignment =
CENTER;
3431 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3432 button->innerColor =
BLACK;
3433 button->foregroundColor =
WHITE;
3436 button->innerColor =
WHITE;
3437 button->foregroundColor =
BLACK;
3439 if (upFooterDesc->button.style == NO_BORDER) {
3440 button->borderColor =
WHITE;
3443 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3444 button->borderColor =
BLACK;
3450 button->text = PIC(upFooterDesc->button.text);
3451 button->fontId = SMALL_BOLD_FONT;
3452 button->icon = PIC(upFooterDesc->button.icon);
3454 button->obj.area.height = BUTTON_DIAMETER;
3455 button->radius = BUTTON_RADIUS;
3457 button->obj.alignTo = NULL;
3458 button->obj.touchMask = (1 <<
TOUCHED);
3463 case UP_FOOTER_HORIZONTAL_BUTTONS: {
3465 if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3466 || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3477 upFooterDesc->horizontalButtons.leftToken,
3478 upFooterDesc->horizontalButtons.tuneId);
3485 button->obj.alignmentMarginX = BORDER_MARGIN;
3487 button->innerColor =
WHITE;
3488 button->foregroundColor =
BLACK;
3489 button->obj.area.width = BUTTON_WIDTH;
3490 button->obj.area.height = BUTTON_DIAMETER;
3491 button->radius = BUTTON_RADIUS;
3492 button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3493 button->fontId = SMALL_BOLD_FONT;
3494 button->obj.touchMask = (1 <<
TOUCHED);
3502 upFooterDesc->horizontalButtons.rightToken,
3503 upFooterDesc->horizontalButtons.tuneId);
3510 button->obj.alignmentMarginX = BORDER_MARGIN;
3511 button->innerColor =
BLACK;
3512 button->borderColor =
BLACK;
3513 button->foregroundColor =
WHITE;
3514 button->obj.area.width =
AVAILABLE_WIDTH - BUTTON_WIDTH - LEFT_CONTENT_ICON_TEXT_X;
3515 button->obj.area.height = BUTTON_DIAMETER;
3516 button->radius = BUTTON_RADIUS;
3517 button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3518 button->fontId = SMALL_BOLD_FONT;
3519 button->obj.touchMask = (1 <<
TOUCHED);
3524 case UP_FOOTER_TIP_BOX: {
3526 if (upFooterDesc->tipBox.text == NULL) {
3531 upFooterDesc->tipBox.token,
3532 upFooterDesc->tipBox.tuneId);
3541 textArea->textColor =
BLACK;
3542 textArea->text = PIC(upFooterDesc->tipBox.text);
3543 textArea->textAlignment =
MID_LEFT;
3544 textArea->fontId = SMALL_REGULAR_FONT;
3545 textArea->wrapping =
true;
3547 if (upFooterDesc->tipBox.icon != NULL) {
3548 textArea->obj.area.width
3550 + TIP_BOX_TEXT_ICON_MARGIN;
3553 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3554 textArea->obj.alignment =
MID_LEFT;
3555 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3559 line = createHorizontalLine(layoutInt->
layer);
3563 if (upFooterDesc->tipBox.icon != NULL) {
3565 image->obj.alignmentMarginX = BORDER_MARGIN;
3567 image->foregroundColor =
BLACK;
3568 image->buffer = PIC(upFooterDesc->tipBox.icon);
3578 case UP_FOOTER_TEXT: {
3581 upFooterDesc->text.token,
3582 upFooterDesc->text.tuneId);
3592 if (strlen(PIC(upFooterDesc->text.text))) {
3595 textArea->text = PIC(upFooterDesc->text.text);
3596 textArea->textAlignment =
CENTER;
3597 textArea->fontId = SMALL_REGULAR_FONT;
3598 textArea->wrapping =
true;
3601 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3602 textArea->obj.alignment =
CENTER;
3639 tune_index_e tuneId)
3641 nbgl_layoutHeader_t headerDesc = {.type = HEADER_BACK_AND_PROGRESS,
3642 .separationLine =
false,
3643 .progressAndBack.activePage = activePage,
3644 .progressAndBack.nbPages = nbPages,
3645 .progressAndBack.token = backToken,
3646 .progressAndBack.tuneId = tuneId,
3647 .progressAndBack.withBack = withBack,
3648 .progressAndBack.actionIcon = NULL,
3652 return nbgl_layoutAddHeader(layout, &headerDesc);
3667 const char *subText,
3668 uint8_t initPosition)
3676 if (layout == NULL) {
3682 container->nbChildren = 3;
3687 container->obj.alignment =
CENTER;
3691 spinner->position = initPosition;
3694 container->children[0] = (
nbgl_obj_t *) spinner;
3697 container->obj.area.height += SPINNER_HEIGHT;
3701 textArea->textColor =
BLACK;
3702 textArea->text = PIC(text);
3703 textArea->textAlignment =
CENTER;
3704 textArea->fontId = (subText != NULL) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
3705 textArea->wrapping =
true;
3706 textArea->obj.alignmentMarginY = SPINNER_TEXT_MARGIN;
3707 textArea->obj.alignTo = (
nbgl_obj_t *) spinner;
3711 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3715 container->obj.area.height += textArea->obj.alignmentMarginY + textArea->obj.area.height;
3718 container->children[1] = (
nbgl_obj_t *) textArea;
3720 if (subText != NULL) {
3724 subTextArea->textColor =
BLACK;
3725 subTextArea->text = PIC(subText);
3726 subTextArea->textAlignment =
CENTER;
3727 subTextArea->fontId = SMALL_REGULAR_FONT;
3728 subTextArea->wrapping =
true;
3729 subTextArea->obj.alignmentMarginY = SPINNER_INTER_TEXTS_MARGIN;
3730 subTextArea->obj.alignTo = (
nbgl_obj_t *) textArea;
3735 subTextArea->obj.area.width,
3736 subTextArea->wrapping);
3740 container->obj.area.height
3741 += subTextArea->obj.alignmentMarginY + subTextArea->obj.area.height;
3744 container->children[2] = (
nbgl_obj_t *) subTextArea;
3752 tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD;
3753 tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD;
3754 tickerCfg.tickerCallback = &spinnerTickerCallback;
3774 const char *subText,
3784 if ((layout == NULL) || (layoutInt->
container->nbChildren == 0)) {
3789 if ((container->obj.type !=
CONTAINER) || (container->nbChildren < 2)) {
3794 if (spinner->obj.type !=
SPINNER) {
3798 if (spinner->position != position) {
3799 spinner->position = position;
3809 const char *newText = PIC(text);
3810 size_t newTextLen = strlen(newText);
3812 if ((newTextLen != strlen(textArea->text)) || memcmp(textArea->text, newText, newTextLen)) {
3813 textArea->text = newText;
3818 if (subText != NULL) {
3821 if (container->nbChildren != 3) {
3825 if (subTextArea->obj.type !=
TEXT_AREA) {
3828 const char *newSubText = PIC(subText);
3829 size_t newSubTextLen = strlen(newSubText);
3831 if ((newSubTextLen != strlen(subTextArea->text))
3832 || memcmp(subTextArea->text, newSubText, newSubTextLen)) {
3833 subTextArea->text = newSubText;
3852 if (layout == NULL) {
3882 if ((layout == NULL) || (!layout->
isUsed)) {
3886 if (layout->
modal) {
3889 if (layout == topLayout) {
3890 topLayout = layout->
bottom;
3891 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
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)
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)
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)