Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_layout.c
Go to the documentation of this file.
1
7#include "app_config.h"
8
9#ifdef HAVE_SE_TOUCH
10/*********************
11 * INCLUDES
12 *********************/
13#include <string.h>
14#include <stdlib.h>
15#include "nbgl_debug.h"
16#include "nbgl_front.h"
18#include "nbgl_obj.h"
19#include "nbgl_draw.h"
20#include "nbgl_screen.h"
21#include "nbgl_touch.h"
22#include "glyphs.h"
23#include "os_pic.h"
24#include "os_helpers.h"
25#include "lcx_rng.h"
26
27/*********************
28 * DEFINES
29 *********************/
30// half internal margin, between items
31#define INTERNAL_SPACE 16
32// inner margin, between buttons
33#define INNER_MARGIN 12
34
35#define NB_MAX_LAYOUTS 3
36
37// used by container
38#define NB_MAX_CONTAINER_CHILDREN 20
39
40#define TAG_VALUE_ICON_WIDTH 32
41
42#ifdef TARGET_STAX
43#define RADIO_CHOICE_HEIGHT 96
44#define FOOTER_HEIGHT 80
45#define BAR_INTERVALE 12
46#define BACK_KEY_WIDTH 88
47#define FOOTER_BUTTON_HEIGHT 128
48#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
49#define ACTION_AND_FOOTER_FOOTER_HEIGHT 216
50#define INTER_ROWS_MARGIN 16
51#define LEFT_CONTENT_TEXT_PADDING 0
52#else // TARGET_STAX
53#define RADIO_CHOICE_HEIGHT 92
54#define FOOTER_HEIGHT 80
55#define BAR_INTERVALE 16
56#define BACK_KEY_WIDTH 104
57#define FOOTER_BUTTON_HEIGHT 136
58#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
59#define ACTION_AND_FOOTER_FOOTER_HEIGHT 232
60#define INTER_ROWS_MARGIN 26
61#define LEFT_CONTENT_TEXT_PADDING 4
62#endif // TARGET_STAX
63
64// refresh period of the spinner, in ms
65#define SPINNER_REFRESH_PERIOD 400
66
67#ifdef TARGET_STAX
68#define FIRST_BUTTON_INDEX 0
69#else // TARGET_STAX
70// for suggestion buttons, on Flex there are other objects than buttons
71enum {
73 LEFT_HALF_INDEX, // half disc displayed on the bottom left
74 RIGHT_HALF_INDEX, // half disc displayed on the bottom right
76};
77#endif // TARGET_STAX
78
79/**********************
80 * MACROS
81 **********************/
82
83/**********************
84 * TYPEDEFS
85 **********************/
86
92
93// used to build either a touchable bar or a switch
94typedef struct {
96 const nbgl_icon_details_t *iconLeft; // a buffer containing the 1BPP icon for icon on
97 // left (can be NULL)
98 const nbgl_icon_details_t *iconRight; // a buffer containing the 1BPP icon for icon 2 (can be
99 // NULL). Dimensions must be the same as iconLeft
100 const char *text; // text (can be NULL)
101 const char *subText; // sub text (can be NULL)
102 uint8_t token; // the token that will be used as argument of the callback
103 nbgl_state_t state; // state of the item
104 bool large; // set to true only for the main level of OS settings
105#ifdef HAVE_PIEZO_SOUND
106 tune_index_e tuneId; // if not @ref NBGL_NO_TUNE, a tune will be played
107#endif // HAVE_PIEZO_SOUND
108} listItem_t;
109
110/**********************
111 * VARIABLES
112 **********************/
113
118static nbgl_layoutInternal_t gLayout[NB_MAX_LAYOUTS] = {0};
119
120// numbers of touchable controls for the whole page
121static uint8_t nbTouchableControls = 0;
122
123/**********************
124 * STATIC PROTOTYPES
125 **********************/
126extern const char *get_ux_loc_string(uint32_t index);
127
128#ifdef HAVE_FAST_HOLD_TO_APPROVE
129// Unit step in % of touchable progress bar
130#define HOLD_TO_APPROVE_STEP_PERCENT (7)
131// Duration in ms the user must hold the progress bar
132// to make it progress HOLD_TO_APPROVE_STEP_PERCENT %.
133// This duration must be higher than the screen refresh duration.
134#define HOLD_TO_APPROVE_STEP_DURATION_MS (100)
135#else
136#define HOLD_TO_APPROVE_STEP_PERCENT (25)
137#define HOLD_TO_APPROVE_STEP_DURATION_MS (400)
138#endif // HAVE_FAST_HOLD_TO_APPROVE
139
140static inline uint8_t get_hold_to_approve_percent(uint32_t touch_duration)
141{
142#ifdef HAVE_FAST_HOLD_TO_APPROVE
143 uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS);
144#else
145 uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS) + 1;
146#endif
147 return (current_step_nb * HOLD_TO_APPROVE_STEP_PERCENT);
148}
149
150// function used to retrieve the concerned layout and layout obj matching the given touched obj
151static bool getLayoutAndLayoutObj(nbgl_obj_t *obj,
152 nbgl_layoutInternal_t **layout,
153 layoutObj_t **layoutObj)
154{
156
157 // parse all layouts (starting with modals) to find the object
158 *layout = NULL;
159 while (i > 0) {
160 i--;
161 if (gLayout[i].nbChildren > 0) {
162 uint8_t j;
163
164 // search index of obj in this layout
165 for (j = 0; j < gLayout[i].nbUsedCallbackObjs; j++) {
166 if (obj == gLayout[i].callbackObjPool[j].obj) {
168 "getLayoutAndLayoutObj(): obj found in layout[%d], index = %d, "
169 "nbUsedCallbackObjs = %d\n",
170 i,
171 j,
172 gLayout[i].nbUsedCallbackObjs);
173 *layout = &gLayout[i];
174 *layoutObj = &(gLayout[i].callbackObjPool[j]);
175 return true;
176 }
177 }
178 }
179 }
180 // not found
181 return false;
182}
183
184static void radioTouchCallback(nbgl_obj_t *obj,
185 nbgl_touchType_t eventType,
186 nbgl_layoutInternal_t *layout);
187static void longTouchCallback(nbgl_obj_t *obj,
188 nbgl_touchType_t eventType,
189 nbgl_layoutInternal_t *layout,
190 layoutObj_t *layoutObj);
191
192// callback for most touched object
193static void touchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
194{
195 nbgl_layoutInternal_t *layout;
196 layoutObj_t *layoutObj;
197 bool needRefresh = false;
198
199 if (obj == NULL) {
200 return;
201 }
202 LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): eventType = %d, obj = %p\n", eventType, obj);
203 if (getLayoutAndLayoutObj(obj, &layout, &layoutObj) == false) {
204 // try with parent, if existing
205 if (getLayoutAndLayoutObj(obj->parent, &layout, &layoutObj) == false) {
206 LOG_WARN(
208 "touchCallback(): eventType = %d, obj = %p, no active layout or obj not found\n",
209 eventType,
210 obj);
211 return;
212 }
213 }
214
215 // case of swipe
216 if (((eventType == SWIPED_UP) || (eventType == SWIPED_DOWN) || (eventType == SWIPED_LEFT)
217 || (eventType == SWIPED_RIGHT))
218 && (obj->type == CONTAINER)) {
219#ifdef NBGL_KEYBOARD
220 if (layout->swipeUsage == SWIPE_USAGE_SUGGESTIONS) {
221 keyboardSwipeCallback(obj, eventType);
222 return;
223 }
224#endif // NBGL_KEYBOARD
225 if (layout->swipeUsage == SWIPE_USAGE_CUSTOM) {
226 layoutObj->index = eventType;
227 }
228 else if ((layout->swipeUsage == SWIPE_USAGE_NAVIGATION)
229 && ((nbgl_obj_t *) layout->container == obj)) {
230 nbgl_container_t *navContainer;
231 if (layout->footerType == FOOTER_NAV) {
232 navContainer = (nbgl_container_t *) layout->footerContainer;
233 }
234 else if (layout->footerType == FOOTER_TEXT_AND_NAV) {
235 navContainer = (nbgl_container_t *) layout->footerContainer->children[1];
236 }
237 else {
238 return;
239 }
240
242 (nbgl_obj_t *) navContainer, eventType, layout->nbPages, &layout->activePage)
243 == false) {
244 // navigation was impossible
245 return;
246 }
247 layoutObj->index = layout->activePage;
248 }
249 }
250
251 // case of navigation bar
252 if (((obj->parent == (nbgl_obj_t *) layout->footerContainer)
253 && (layout->footerType == FOOTER_NAV))
254 || ((obj->parent->type == CONTAINER)
255 && (obj->parent->parent == (nbgl_obj_t *) layout->footerContainer)
256 && (layout->footerType == FOOTER_TEXT_AND_NAV))) {
257 if (layoutNavigationCallback(obj, eventType, layout->nbPages, &layout->activePage)
258 == false) {
259 // navigation was impossible
260 return;
261 }
262 layoutObj->index = layout->activePage;
263 }
264
265 // case of switch
266 if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren >= 2)
267 && (((nbgl_container_t *) obj)->children[1] != NULL)
268 && (((nbgl_container_t *) obj)->children[1]->type == SWITCH)) {
269 nbgl_switch_t *lSwitch = (nbgl_switch_t *) ((nbgl_container_t *) obj)->children[1];
270 lSwitch->state = (lSwitch->state == ON_STATE) ? OFF_STATE : ON_STATE;
271 nbgl_objDraw((nbgl_obj_t *) lSwitch);
272 // refresh will be done after tune playback
273 needRefresh = true;
274 // index is used for state
275 layoutObj->index = lSwitch->state;
276 }
277 // case of radio
278 else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 2)
279 && (((nbgl_container_t *) obj)->children[1] != NULL)
280 && (((nbgl_container_t *) obj)->children[1]->type == RADIO_BUTTON)) {
281 radioTouchCallback(obj, eventType, layout);
282 return;
283 }
284 // case of long press
285 else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 4)
286 && (((nbgl_container_t *) obj)->children[3] != NULL)
287 && (((nbgl_container_t *) obj)->children[3]->type == PROGRESS_BAR)) {
288 longTouchCallback(obj, eventType, layout, layoutObj);
289 return;
290 }
291 LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): layout->callback = %p\n", layout->callback);
292 if ((layout->callback != NULL) && (layoutObj->token != NBGL_INVALID_TOKEN)) {
293#ifdef HAVE_PIEZO_SOUND
294 if (layoutObj->tuneId < NBGL_NO_TUNE) {
295 io_seproxyhal_play_tune(layoutObj->tuneId);
296 }
297#endif // HAVE_PIEZO_SOUND
298 if (needRefresh) {
300 }
301 layout->callback(layoutObj->token, layoutObj->index);
302 }
303}
304
305// callback for long press button
306static void longTouchCallback(nbgl_obj_t *obj,
307 nbgl_touchType_t eventType,
308 nbgl_layoutInternal_t *layout,
309 layoutObj_t *layoutObj)
310{
311 nbgl_container_t *container = (nbgl_container_t *) obj;
312 // 4th child of container is the progress bar
313 nbgl_progress_bar_t *progressBar = (nbgl_progress_bar_t *) container->children[3];
314
316 "longTouchCallback(): eventType = %d, obj = %p, gLayout[1].nbChildren = %d\n",
317 eventType,
318 obj,
319 gLayout[1].nbChildren);
320
321 // case of pressing a long press button
322 if (eventType == TOUCHING) {
323 uint32_t touchDuration = nbgl_touchGetTouchDuration(obj);
324
325 // Compute the new progress bar state in %
326 uint8_t new_state = get_hold_to_approve_percent(touchDuration);
327
328 // Ensure the callback is triggered once,
329 // when the progress bar state reaches 100%
330 bool trigger_callback = (new_state >= 100) && (progressBar->state < 100);
331
332 // Cap progress bar state at 100%
333 if (new_state >= 100) {
334 new_state = 100;
335 }
336
337 // Update progress bar state
338 if (new_state != progressBar->state) {
339 progressBar->partialRedraw = true;
340 progressBar->state = new_state;
341
342 nbgl_objDraw((nbgl_obj_t *) progressBar);
343 // Ensure progress bar is fully drawn
344 // before calling the callback.
347 }
348
349 if (trigger_callback) {
350 // End of progress bar reached: trigger callback
351 if (layout->callback != NULL) {
352 layout->callback(layoutObj->token, layoutObj->index);
353 }
354 }
355 }
356 // case of releasing a long press button (or getting out of it)
357 else if ((eventType == TOUCH_RELEASED) || (eventType == OUT_OF_TOUCH)
358 || (eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT)) {
360 progressBar->partialRedraw = true;
361 progressBar->state = 0;
362 nbgl_objDraw((nbgl_obj_t *) progressBar);
364 }
365}
366
367// callback for radio button touch
368static void radioTouchCallback(nbgl_obj_t *obj,
369 nbgl_touchType_t eventType,
370 nbgl_layoutInternal_t *layout)
371{
372 uint8_t i = NB_MAX_LAYOUTS, radioIndex = 0, foundRadio = 0xFF, foundRadioIndex;
373
374 if (eventType != TOUCHED) {
375 return;
376 }
377
378 i = 0;
379 // parse all objs to find all containers of radio buttons
380 while (i < layout->nbUsedCallbackObjs) {
381 if ((obj == (nbgl_obj_t *) layout->callbackObjPool[i].obj)
382 && (layout->callbackObjPool[i].obj->type == CONTAINER)) {
383 nbgl_radio_t *radio
384 = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
385 ->children[1];
386 nbgl_text_area_t *textArea
388 ->children[0];
389 foundRadio = i;
390 foundRadioIndex = radioIndex;
391 // set text as active (black and bold)
392 textArea->textColor = BLACK;
393 textArea->fontId = SMALL_BOLD_FONT;
394 // ensure that radio button is ON
395 radio->state = ON_STATE;
396 // redraw container
397 nbgl_objDraw((nbgl_obj_t *) obj);
398 }
399 else if ((layout->callbackObjPool[i].obj->type == CONTAINER)
400 && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->nbChildren == 2)
401 && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->children[1]->type
402 == RADIO_BUTTON)) {
403 nbgl_radio_t *radio
404 = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
405 ->children[1];
406 nbgl_text_area_t *textArea
408 ->children[0];
409 radioIndex++;
410 // set to OFF the one that was in ON
411 if (radio->state == ON_STATE) {
412 radio->state = OFF_STATE;
413 // set text it as inactive (gray and normal)
414 textArea->textColor = DARK_GRAY;
415 textArea->fontId = SMALL_REGULAR_FONT;
416 // redraw container
418 }
419 }
420 i++;
421 }
422 // call callback after redraw to avoid asynchronicity
423 if (foundRadio != 0xFF) {
424 if (layout->callback != NULL) {
425#ifdef HAVE_PIEZO_SOUND
426 if (layout->callbackObjPool[foundRadio].tuneId < NBGL_NO_TUNE) {
427 io_seproxyhal_play_tune(layout->callbackObjPool[foundRadio].tuneId);
428 }
430#endif // HAVE_PIEZO_SOUND
431 layout->callback(layout->callbackObjPool[foundRadio].token, foundRadioIndex);
432 }
433 }
434}
435
436// callback for spinner ticker
437static void spinnerTickerCallback(void)
438{
439 nbgl_spinner_t *spinner;
440 uint8_t i = 0;
441 nbgl_layoutInternal_t *layout;
442
443 // gLayout[1] is on top of gLayout[0] so if gLayout[1] is active, it must catch the event
444 if (gLayout[1].nbChildren > 0) {
445 layout = &gLayout[1];
446 }
447 else {
448 layout = &gLayout[0];
449 }
450
451 // get index of obj
452 while (i < layout->container->nbChildren) {
453 if (layout->container->children[i]->type == CONTAINER) {
454 nbgl_container_t *container = (nbgl_container_t *) layout->container->children[i];
455 if (container->nbChildren && (container->children[0]->type == SPINNER)) {
456 spinner = (nbgl_spinner_t *) container->children[0];
457 spinner->position++;
458 // there are only NB_SPINNER_POSITIONS positions
459 if (spinner->position == NB_SPINNER_POSITIONS) {
460 spinner->position = 0;
461 }
462 nbgl_objDraw((nbgl_obj_t *) spinner);
464 return;
465 }
466 }
467 i++;
468 }
469}
470
471static nbgl_line_t *createHorizontalLine(uint8_t layer)
472{
473 nbgl_line_t *line;
474
475 line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
476 line->lineColor = LIGHT_GRAY;
477 line->obj.area.width = SCREEN_WIDTH;
478 line->obj.area.height = 4;
479 line->direction = HORIZONTAL;
480 line->thickness = 1;
481 return line;
482}
483
484static nbgl_line_t *createLeftVerticalLine(uint8_t layer)
485{
486 nbgl_line_t *line;
487
488 line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
489 line->lineColor = LIGHT_GRAY;
490 line->obj.area.width = 1;
491 line->obj.area.height = SCREEN_HEIGHT;
492 line->direction = VERTICAL;
493 line->thickness = 1;
494 line->obj.alignment = MID_LEFT;
495 return line;
496}
497
498// function adding a layout object in the callbackObjPool array for the given layout, and
499// configuring it
501 nbgl_obj_t *obj,
502 uint8_t token,
503 tune_index_e tuneId)
504{
505 layoutObj_t *layoutObj = NULL;
506
507 if (layout->nbUsedCallbackObjs < (LAYOUT_OBJ_POOL_LEN - 1)) {
508 layoutObj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
509 layout->nbUsedCallbackObjs++;
510 layoutObj->obj = obj;
511 layoutObj->token = token;
512 layoutObj->tuneId = tuneId;
513 }
514 else {
515 LOG_FATAL(LAYOUT_LOGGER, "layoutAddCallbackObj: no more callback obj\n");
516 }
517
518 return layoutObj;
519}
520
528{
529 if (layout->container->nbChildren == NB_MAX_CONTAINER_CHILDREN) {
530 LOG_FATAL(LAYOUT_LOGGER, "layoutAddObject(): No more object\n");
531 }
532 layout->container->children[layout->container->nbChildren] = obj;
533 layout->container->nbChildren++;
534}
535
545static int addSwipeInternal(nbgl_layoutInternal_t *layoutInt,
546 uint16_t swipesMask,
547 nbgl_swipe_usage_t usage,
548 uint8_t token,
549 tune_index_e tuneId)
550{
551 layoutObj_t *obj;
552
553 if ((swipesMask & SWIPE_MASK) == 0) {
554 return -1;
555 }
556
557 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, token, tuneId);
558 if (obj == NULL) {
559 return -1;
560 }
561 layoutInt->container->obj.touchMask = swipesMask;
562 layoutInt->swipeUsage = usage;
563
564 return 0;
565}
566
574static nbgl_container_t *addListItem(nbgl_layoutInternal_t *layoutInt, const listItem_t *itemDesc)
575{
576 layoutObj_t *obj;
577 nbgl_text_area_t *textArea;
578 nbgl_container_t *container;
579 color_t color = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == OFF_STATE))
580 ? LIGHT_GRAY
581 : BLACK;
582 int16_t usedHeight = 40;
583
584 LOG_DEBUG(LAYOUT_LOGGER, "addListItem():\n");
585
586 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
588 layoutInt, (nbgl_obj_t *) container, itemDesc->token, itemDesc->tuneId);
589 if (obj == NULL) {
590 return NULL;
591 }
592
593 // get container children (up to 4: text + left+right icons + sub text)
594 container->children = nbgl_containerPoolGet(4, layoutInt->layer);
595 container->nbChildren = 0;
596
597 container->obj.area.width = AVAILABLE_WIDTH;
598 container->obj.area.height = itemDesc->large ? TOUCHABLE_MAIN_BAR_HEIGHT : TOUCHABLE_BAR_HEIGHT;
599 container->layout = HORIZONTAL;
600 container->obj.alignmentMarginX = BORDER_MARGIN;
601 container->obj.alignment = NO_ALIGNMENT;
602 container->obj.alignTo = NULL;
603 // the bar can only be touched if not inactive AND if one of the icon is present
604 // otherwise it is seen as a title
605 if (((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == ON_STATE))
606 || (itemDesc->type == SWITCH_ITEM)) {
607 container->obj.touchMask = (1 << TOUCHED);
608 container->obj.touchId = CONTROLS_ID + nbTouchableControls;
609 nbTouchableControls++;
610 }
611
612 // allocate main text because always present
613 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
614 textArea->textColor = color;
615 textArea->text = PIC(itemDesc->text);
616 textArea->onDrawCallback = NULL;
617 textArea->fontId = SMALL_BOLD_FONT;
618 textArea->wrapping = true;
619 textArea->obj.area.width = container->obj.area.width;
620 if (itemDesc->iconLeft != NULL) {
621 // reduce text width accordingly
622 textArea->obj.area.width
623 -= ((nbgl_icon_details_t *) PIC(itemDesc->iconLeft))->width + BAR_INTERVALE;
624 }
625 if (itemDesc->iconRight != NULL) {
626 // reduce text width accordingly
627 textArea->obj.area.width
628 -= ((nbgl_icon_details_t *) PIC(itemDesc->iconRight))->width + BAR_INTERVALE;
629 }
630 else if (itemDesc->type == SWITCH_ITEM) {
631 textArea->obj.area.width -= 60 + BAR_INTERVALE;
632 }
633 textArea->obj.area.height = nbgl_getTextHeightInWidth(
634 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
635 usedHeight = MAX(usedHeight, textArea->obj.area.height);
636 textArea->style = NO_STYLE;
637 textArea->obj.alignment = MID_LEFT;
638 textArea->textAlignment = MID_LEFT;
639 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
640 container->nbChildren++;
641
642 // allocate left icon if present
643 if (itemDesc->iconLeft != NULL) {
644 nbgl_image_t *imageLeft = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
645 imageLeft->foregroundColor = color;
646 imageLeft->buffer = PIC(itemDesc->iconLeft);
647 // align at the left of text
648 imageLeft->obj.alignment = MID_LEFT;
649 imageLeft->obj.alignTo = (nbgl_obj_t *) textArea;
650 imageLeft->obj.alignmentMarginX = BAR_INTERVALE;
651 container->children[container->nbChildren] = (nbgl_obj_t *) imageLeft;
652 container->nbChildren++;
653
654 textArea->obj.alignmentMarginX = imageLeft->buffer->width + BAR_INTERVALE;
655
656 usedHeight = MAX(usedHeight, imageLeft->buffer->height);
657 }
658 // allocate right icon if present
659 if (itemDesc->iconRight != NULL) {
660 nbgl_image_t *imageRight = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
661 imageRight->foregroundColor = color;
662 imageRight->buffer = PIC(itemDesc->iconRight);
663 // align at the right of text
664 imageRight->obj.alignment = MID_RIGHT;
665 imageRight->obj.alignmentMarginX = BAR_INTERVALE;
666 imageRight->obj.alignTo = (nbgl_obj_t *) textArea;
667
668 container->children[container->nbChildren] = (nbgl_obj_t *) imageRight;
669 container->nbChildren++;
670
671 usedHeight = MAX(usedHeight, imageRight->buffer->height);
672 }
673 else if (itemDesc->type == SWITCH_ITEM) {
674 nbgl_switch_t *switchObj = (nbgl_switch_t *) nbgl_objPoolGet(SWITCH, layoutInt->layer);
675 switchObj->onColor = BLACK;
676 switchObj->offColor = LIGHT_GRAY;
677 switchObj->state = itemDesc->state;
678 switchObj->obj.alignment = MID_RIGHT;
679 switchObj->obj.alignmentMarginX = BAR_INTERVALE;
680 switchObj->obj.alignTo = (nbgl_obj_t *) textArea;
681
682 container->children[container->nbChildren] = (nbgl_obj_t *) switchObj;
683 container->nbChildren++;
684 }
685
686 if (itemDesc->subText != NULL) {
687 nbgl_text_area_t *subTextArea
689
690 subTextArea->textColor = color;
691 subTextArea->text = PIC(itemDesc->subText);
692 subTextArea->textAlignment = MID_LEFT;
693 subTextArea->fontId = SMALL_REGULAR_FONT;
694 subTextArea->style = NO_STYLE;
695 subTextArea->wrapping = true;
696 subTextArea->obj.alignment = MID_LEFT;
697 subTextArea->obj.area.width = container->obj.area.width;
698 subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
699 subTextArea->text,
700 subTextArea->obj.area.width,
701 subTextArea->wrapping);
702 container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
703 container->nbChildren++;
704 container->obj.area.height += subTextArea->obj.area.height + 12;
705
706 // modify alignments to have sub-text under (icon left - text - icon right)
707 textArea->obj.alignmentMarginY = -(subTextArea->obj.area.height + 12) / 2;
708 subTextArea->obj.alignmentMarginY = (usedHeight + 12) / 2;
709 }
710
711 // set this new container as child of main container
712 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
713
714 return container;
715}
716
725static nbgl_container_t *addContentCenter(nbgl_layoutInternal_t *layoutInt,
726 const nbgl_contentCenter_t *info)
727{
728 nbgl_container_t *container;
729 nbgl_text_area_t *textArea = NULL;
730 nbgl_image_t *image = NULL;
731 uint16_t fullHeight = 0;
732
733 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
734
735 // get container children
736 container->nbChildren = 0;
737 container->children = nbgl_containerPoolGet(5, layoutInt->layer);
738
739 // add icon if present
740 if (info->icon != NULL) {
741 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
742 image->foregroundColor = BLACK;
743 image->buffer = PIC(info->icon);
744 image->obj.alignment = TOP_MIDDLE;
745 image->obj.alignmentMarginY = info->iconHug;
746
747 fullHeight += image->buffer->height + info->iconHug;
748 container->children[container->nbChildren] = (nbgl_obj_t *) image;
749 container->nbChildren++;
750 }
751 // add title if present
752 if (info->title != NULL) {
753 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
754 textArea->textColor = BLACK;
755 textArea->text = PIC(info->title);
756 textArea->textAlignment = CENTER;
757 textArea->fontId = LARGE_MEDIUM_FONT;
758 textArea->wrapping = true;
759 textArea->obj.area.width = AVAILABLE_WIDTH;
760 textArea->obj.area.height = nbgl_getTextHeightInWidth(
761 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
762
763 // if not the first child, put on bottom of the previous, with a margin
764 if (container->nbChildren > 0) {
765 textArea->obj.alignment = BOTTOM_MIDDLE;
766 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
767 textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
768 }
769 else {
770 textArea->obj.alignment = TOP_MIDDLE;
771 }
772
773 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
774
775 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
776 container->nbChildren++;
777 }
778 // add small title if present
779 if (info->smallTitle != NULL) {
780 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
781 textArea->textColor = BLACK;
782 textArea->text = PIC(info->smallTitle);
783 textArea->textAlignment = CENTER;
784 textArea->fontId = SMALL_BOLD_FONT;
785 textArea->wrapping = true;
786 textArea->obj.area.width = AVAILABLE_WIDTH;
787 textArea->obj.area.height = nbgl_getTextHeightInWidth(
788 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
789
790 // if not the first child, put on bottom of the previous, with a margin
791 if (container->nbChildren > 0) {
792 textArea->obj.alignment = BOTTOM_MIDDLE;
793 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
794 textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN;
795 if (container->children[container->nbChildren - 1]->type == IMAGE) {
796 textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
797 }
798 else {
799 textArea->obj.alignmentMarginY = 16;
800 }
801 }
802 else {
803 textArea->obj.alignment = TOP_MIDDLE;
804 }
805
806 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
807
808 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
809 container->nbChildren++;
810 }
811 // add description if present
812 if (info->description != NULL) {
813 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
814 textArea->textColor = BLACK;
815 textArea->text = PIC(info->description);
816 textArea->textAlignment = CENTER;
817 textArea->fontId = SMALL_REGULAR_FONT;
818 textArea->wrapping = true;
819 textArea->obj.area.width = AVAILABLE_WIDTH;
820 textArea->obj.area.height = nbgl_getTextHeightInWidth(
821 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
822
823 // if not the first child, put on bottom of the previous, with a margin
824 if (container->nbChildren > 0) {
825 textArea->obj.alignment = BOTTOM_MIDDLE;
826 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
827 if (container->children[container->nbChildren - 1]->type == TEXT_AREA) {
828 // if previous element is text, only space of 16 px
829 textArea->obj.alignmentMarginY = 16;
830 }
831 else {
832 textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
833 }
834 }
835 else {
836 textArea->obj.alignment = TOP_MIDDLE;
837 }
838
839 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
840
841 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
842 container->nbChildren++;
843 }
844 // add sub-text if present
845 if (info->subText != NULL) {
846 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
847 textArea->textColor = DARK_GRAY;
848 textArea->text = PIC(info->subText);
849 textArea->textAlignment = CENTER;
850 textArea->fontId = SMALL_REGULAR_FONT;
851 textArea->wrapping = true;
852 textArea->obj.area.width = AVAILABLE_WIDTH;
853 textArea->obj.area.height = nbgl_getTextHeightInWidth(
854 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
855 // sub-text is included in a hug of 8px
856 textArea->obj.area.height += 2 * 8;
857 // if not the first child, put on bottom of the previous, with a margin
858 if (container->nbChildren > 0) {
859 textArea->obj.alignment = BOTTOM_MIDDLE;
860 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
861 textArea->obj.alignmentMarginY = 16;
862 if (container->children[container->nbChildren - 1]->type == IMAGE) {
863 textArea->obj.alignmentMarginY += info->iconHug;
864 }
865 }
866 else {
867 textArea->obj.alignment = TOP_MIDDLE;
868 }
869
870 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
871
872 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
873 container->nbChildren++;
874 }
875 container->layout = VERTICAL;
876 container->obj.alignment = CENTER;
877 container->obj.area.width = AVAILABLE_WIDTH;
878 container->obj.area.height = fullHeight;
879 if (info->padding) {
880 container->obj.area.height += 40;
881 }
882
883 // set this new container as child of main container
884 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
885
886 return container;
887}
888
889static int addText(nbgl_layout_t *layout,
890 const char *text,
891 const char *subText,
892 uint8_t token,
893 uint8_t index,
894 bool withAlias)
895{
896 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
897 nbgl_container_t *container;
898 nbgl_text_area_t *textArea;
899 nbgl_text_area_t *subTextArea;
900 uint16_t fullHeight = 0;
901
902 if (layout == NULL) {
903 return -1;
904 }
905 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
906
907 // get container children
908 container->children = nbgl_containerPoolGet(withAlias ? 3 : 2, layoutInt->layer);
909 container->obj.area.width = AVAILABLE_WIDTH;
910
911 if (text != NULL) {
912 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
913
914 textArea->textColor = BLACK;
915 textArea->text = PIC(text);
916 textArea->textAlignment = MID_LEFT;
917 textArea->fontId = SMALL_BOLD_FONT;
918 textArea->style = NO_STYLE;
919 textArea->wrapping = true;
920 textArea->obj.alignment = NO_ALIGNMENT;
921 textArea->obj.alignmentMarginY = PRE_TEXT_MARGIN;
922 textArea->obj.area.width = container->obj.area.width;
923 if (withAlias == true) {
924 textArea->obj.area.width -= 12 + MINI_PUSH_ICON.width;
925 }
926 textArea->obj.area.height = nbgl_getTextHeightInWidth(
927 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
928 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
929 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
930 container->nbChildren++;
931 if (withAlias == true) {
932 nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
933 // the whole container is touchable
934 layoutObj_t *obj
935 = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) container, token, TUNE_TAP_CASUAL);
936 obj->index = index;
937 image->foregroundColor = BLACK;
938 image->buffer = &PUSH_ICON;
939 image->obj.alignment = RIGHT_TOP;
940 image->obj.alignmentMarginX = 12;
941 image->obj.alignTo = (nbgl_obj_t *) textArea;
942 container->obj.touchMask = (1 << TOUCHED);
943 container->obj.touchId = VALUE_BUTTON_1_ID + index;
944
945 container->children[container->nbChildren] = (nbgl_obj_t *) image;
946 container->nbChildren++;
947 }
948 }
949 if (subText != NULL) {
950 subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
951 subTextArea->textColor = BLACK;
952 subTextArea->text = PIC(subText);
953 subTextArea->fontId = SMALL_REGULAR_FONT;
954 subTextArea->style = NO_STYLE;
955 subTextArea->wrapping = true;
956 subTextArea->obj.area.width = container->obj.area.width;
957 subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
958 subTextArea->text,
959 subTextArea->obj.area.width,
960 subTextArea->wrapping);
961 subTextArea->textAlignment = MID_LEFT;
962 subTextArea->obj.alignment = NO_ALIGNMENT;
963 if (text != NULL) {
964 subTextArea->obj.alignmentMarginY = TEXT_SUBTEXT_MARGIN;
965 fullHeight += POST_SUBTEXT_MARGIN; // under the subText
966 }
967 else {
968#ifdef TARGET_STAX
969 subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
970 fullHeight += BORDER_MARGIN;
971#else // TARGET_STAX
972 subTextArea->obj.alignmentMarginY = 26;
973 fullHeight += 26; // under the subText
974#endif // TARGET_STAX
975 }
976 container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
977 container->nbChildren++;
978 fullHeight += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
979 }
980 else {
981 fullHeight += PRE_TEXT_MARGIN;
982 }
983 container->obj.area.height = fullHeight;
984 container->layout = VERTICAL;
985 container->obj.alignmentMarginX = BORDER_MARGIN;
986 container->obj.alignment = NO_ALIGNMENT;
987 // set this new obj as child of main container
988 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
989
990 return container->obj.area.height;
991}
992
993/**********************
994 * GLOBAL FUNCTIONS
995 **********************/
996
1004{
1005 nbgl_layoutInternal_t *layout = NULL;
1006
1007 // find an empty layout in the proper "layer"
1008 if (description->modal) {
1009 if (gLayout[1].nbChildren == 0) {
1010 layout = &gLayout[1];
1011 }
1012 else if (gLayout[2].nbChildren == 0) {
1013 layout = &gLayout[2];
1014 }
1015 }
1016 else {
1017 // automatically "release" a potentially opened non-modal layout
1018 gLayout[0].nbChildren = 0;
1019 layout = &gLayout[0];
1020 }
1021 if (layout == NULL) {
1022 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutGet(): impossible to get a layout!\n");
1023 return NULL;
1024 }
1025
1026 // reset globals
1027 memset(layout, 0, sizeof(nbgl_layoutInternal_t));
1028
1029 nbTouchableControls = 0;
1030
1031 layout->callback = (nbgl_layoutTouchCallback_t) PIC(description->onActionCallback);
1032 layout->modal = description->modal;
1033 layout->withLeftBorder = description->withLeftBorder;
1034 if (description->modal) {
1035 layout->layer = nbgl_screenPush(&layout->children,
1037 &description->ticker,
1038 (nbgl_touchCallback_t) touchCallback);
1039 }
1040 else {
1041 nbgl_screenSet(&layout->children,
1043 &description->ticker,
1044 (nbgl_touchCallback_t) touchCallback);
1045 layout->layer = 0;
1046 }
1048 layout->container->obj.area.width = SCREEN_WIDTH;
1049 layout->container->obj.area.height = SCREEN_HEIGHT;
1050 layout->container->layout = VERTICAL;
1051 layout->container->children = nbgl_containerPoolGet(NB_MAX_CONTAINER_CHILDREN, layout->layer);
1052 // by default, if no header, main container is aligned on top-left
1053 layout->container->obj.alignment = TOP_LEFT;
1054 // main container is always the second object, leaving space for header
1055 layout->children[MAIN_CONTAINER_INDEX] = (nbgl_obj_t *) layout->container;
1057
1058 // if a tap text is defined, make the container tapable and display this text in gray
1059 if (description->tapActionText != NULL) {
1060 layoutObj_t *obj;
1061
1062 obj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
1063 layout->nbUsedCallbackObjs++;
1064 obj->obj = (nbgl_obj_t *) layout->container;
1065 obj->token = description->tapActionToken;
1066 obj->tuneId = description->tapTuneId;
1067 layout->container->obj.touchMask = (1 << TOUCHED);
1068 layout->container->obj.touchId = WHOLE_SCREEN_ID;
1069
1070 nbgl_layoutUpFooter_t footerDesc;
1071 footerDesc.type = UP_FOOTER_TEXT;
1072 footerDesc.text.text = PIC(description->tapActionText);
1073 footerDesc.text.token = description->tapActionToken;
1074 footerDesc.text.tuneId = description->tapTuneId;
1075 nbgl_layoutAddUpFooter((nbgl_layout_t *) layout, &footerDesc);
1076 }
1077
1078 return (nbgl_layout_t *) layout;
1079}
1080
1093 uint16_t swipesMask,
1094 const char *text,
1095 uint8_t token,
1096 tune_index_e tuneId)
1097{
1098 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1099
1100 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwipe():\n");
1101 if (layout == NULL) {
1102 return -1;
1103 }
1104
1105 if (text) {
1106 // create 'tap to continue' text area
1108 layoutInt->tapText->text = PIC(text);
1109 layoutInt->tapText->textColor = DARK_GRAY;
1110 layoutInt->tapText->fontId = SMALL_REGULAR_FONT;
1111 layoutInt->tapText->obj.area.width = AVAILABLE_WIDTH;
1112 layoutInt->tapText->obj.area.height = nbgl_getFontLineHeight(layoutInt->tapText->fontId);
1113 layoutInt->tapText->textAlignment = CENTER;
1114#ifdef TARGET_STAX
1115 layoutInt->tapText->obj.alignmentMarginY = BORDER_MARGIN;
1116#else // TARGET_STAX
1117 layoutInt->tapText->obj.alignmentMarginY = 30;
1118#endif // TARGET_STAX
1119 layoutInt->tapText->obj.alignment = BOTTOM_MIDDLE;
1120 }
1121 return addSwipeInternal(layoutInt, swipesMask, SWIPE_USAGE_CUSTOM, token, tuneId);
1122}
1123
1134 const nbgl_icon_details_t *icon,
1135 uint8_t token,
1136 tune_index_e tuneId)
1137{
1138 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1139 layoutObj_t *obj;
1140 nbgl_button_t *button;
1141
1142 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTopRightButton():\n");
1143 if (layout == NULL) {
1144 return -1;
1145 }
1146 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
1147 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
1148 if (obj == NULL) {
1149 return -1;
1150 }
1151
1152 button->obj.area.width = BUTTON_DIAMETER;
1153 button->obj.area.height = BUTTON_DIAMETER;
1154 button->radius = BUTTON_RADIUS;
1155 button->obj.alignmentMarginX = BORDER_MARGIN;
1156 button->obj.alignmentMarginY = BORDER_MARGIN;
1157 button->foregroundColor = BLACK;
1158 button->innerColor = WHITE;
1159 button->borderColor = LIGHT_GRAY;
1160 button->obj.touchMask = (1 << TOUCHED);
1161 button->obj.touchId = TOP_RIGHT_BUTTON_ID;
1162 button->icon = PIC(icon);
1163 button->obj.alignment = TOP_RIGHT;
1164
1165 // add to screen
1166 layoutInt->children[TOP_RIGHT_BUTTON_INDEX] = (nbgl_obj_t *) button;
1167
1168 return 0;
1169}
1170
1179{
1180 nbgl_layoutFooter_t footerDesc;
1181 footerDesc.type = FOOTER_NAV;
1182 footerDesc.separationLine = info->withSeparationLine;
1183 footerDesc.navigation.activePage = info->activePage;
1184 footerDesc.navigation.nbPages = info->nbPages;
1185 footerDesc.navigation.withExitKey = info->withExitKey;
1186 footerDesc.navigation.withBackKey = info->withBackKey;
1187 footerDesc.navigation.withPageIndicator = false;
1188 footerDesc.navigation.token = info->token;
1189 footerDesc.navigation.tuneId = info->tuneId;
1190 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1191}
1192
1205 const nbgl_icon_details_t *icon,
1206 uint8_t token,
1207 bool separationLine,
1208 tune_index_e tuneId)
1209{
1210 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddBottomButton():\n");
1211 nbgl_layoutFooter_t footerDesc;
1212 footerDesc.type = FOOTER_SIMPLE_BUTTON;
1213 footerDesc.separationLine = separationLine;
1214 footerDesc.button.fittingContent = false;
1215 footerDesc.button.icon = PIC(icon);
1216 footerDesc.button.text = NULL;
1217 footerDesc.button.token = token;
1218 footerDesc.button.tuneId = tuneId;
1219 footerDesc.button.style = WHITE_BACKGROUND;
1220 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1221}
1222
1231{
1232 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1233 nbgl_container_t *container;
1234 listItem_t itemDesc;
1235
1236 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar():\n");
1237 if (layout == NULL) {
1238 return -1;
1239 }
1240 // main text is mandatory
1241 if (barLayout->text == NULL) {
1242 LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar(): main text is mandatory\n");
1243 }
1244
1245 itemDesc.iconLeft = barLayout->iconLeft;
1246 itemDesc.iconRight = barLayout->iconRight;
1247 itemDesc.text = barLayout->text;
1248 itemDesc.subText = barLayout->subText;
1249 itemDesc.token = barLayout->token;
1250 itemDesc.tuneId = barLayout->tuneId;
1251 itemDesc.state = (barLayout->inactive) ? OFF_STATE : ON_STATE;
1252 itemDesc.large = barLayout->large;
1253 itemDesc.type = TOUCHABLE_BAR_ITEM;
1254 container = addListItem(layoutInt, &itemDesc);
1255
1256 if (container == NULL) {
1257 return -1;
1258 }
1259 return container->obj.area.height;
1260}
1261
1270{
1271 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1272 nbgl_container_t *container;
1273 listItem_t itemDesc;
1274
1275 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwitch():\n");
1276 if (layout == NULL) {
1277 return -1;
1278 }
1279 // main text is mandatory
1280 if (switchLayout->text == NULL) {
1281 LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddSwitch(): main text is mandatory\n");
1282 }
1283
1284 itemDesc.iconLeft = NULL;
1285 itemDesc.iconRight = NULL;
1286 itemDesc.text = switchLayout->text;
1287 itemDesc.subText = switchLayout->subText;
1288 itemDesc.token = switchLayout->token;
1289 itemDesc.tuneId = switchLayout->tuneId;
1290 itemDesc.state = switchLayout->initState;
1291 itemDesc.large = false;
1292 itemDesc.type = SWITCH_ITEM;
1293 container = addListItem(layoutInt, &itemDesc);
1294
1295 if (container == NULL) {
1296 return -1;
1297 }
1298 return container->obj.area.height;
1299}
1300
1309int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
1310{
1311 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddText():\n");
1312 return addText(layout, text, subText, 0, 0, false);
1313}
1314
1327 const char *text,
1328 const char *subText,
1329 uint8_t token,
1330 uint8_t index)
1331{
1332 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextWithAlias():\n");
1333 return addText(layout, text, subText, token, index, true);
1334}
1335
1343int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
1344{
1345 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1346 nbgl_text_area_t *textArea;
1347
1348 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSubHeaderText():\n");
1349 if (layout == NULL) {
1350 return -1;
1351 }
1352 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1353
1354 textArea->textColor = BLACK;
1355 textArea->text = PIC(text);
1356 textArea->textAlignment = MID_LEFT;
1357 textArea->fontId = SMALL_REGULAR_FONT;
1358 textArea->style = NO_STYLE;
1359 textArea->wrapping = true;
1360 textArea->obj.alignment = NO_ALIGNMENT;
1361 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1362 textArea->obj.area.width = AVAILABLE_WIDTH;
1363 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1364 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1365#ifdef TARGET_STAX
1366 textArea->obj.area.height += 2 * 24;
1367#else // TARGET_STAX
1368 textArea->obj.area.height += 2 * 28;
1369#endif // TARGET_STAX
1370
1371 // set this new obj as child of main container
1372 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1373
1374 return textArea->obj.area.height;
1375}
1376
1384int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text)
1385{
1386 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1387 nbgl_text_area_t *textArea;
1388
1389 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLargeCaseText():\n");
1390 if (layout == NULL) {
1391 return -1;
1392 }
1393 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1394
1395 textArea->textColor = BLACK;
1396 textArea->text = PIC(text);
1397 textArea->textAlignment = MID_LEFT;
1398 textArea->fontId = LARGE_MEDIUM_FONT;
1399 textArea->obj.area.width = AVAILABLE_WIDTH;
1400 textArea->wrapping = true;
1401 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1402 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1403 textArea->style = NO_STYLE;
1404 textArea->obj.alignment = NO_ALIGNMENT;
1405 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1406#ifdef TARGET_STAX
1407 // if first object of container, increase the margin from top
1408 if (layoutInt->container->nbChildren == 0) {
1409 textArea->obj.alignmentMarginY += BORDER_MARGIN;
1410 }
1411#endif // TARGET_STAX
1412
1413 // set this new obj as child of main container
1414 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1415
1416 return 0;
1417}
1418
1432 const char *title,
1433 const char *description,
1434 const char *info)
1435{
1436 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1437 nbgl_text_area_t *textArea;
1438
1439 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextContent():\n");
1440 if (layout == NULL) {
1441 return -1;
1442 }
1443
1444 // create title
1445 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1446 textArea->textColor = BLACK;
1447 textArea->text = PIC(title);
1448 textArea->textAlignment = MID_LEFT;
1449 textArea->fontId = LARGE_MEDIUM_FONT;
1450 textArea->style = NO_STYLE;
1451 textArea->wrapping = true;
1452 textArea->obj.alignment = NO_ALIGNMENT;
1453 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1454#ifdef TARGET_STAX
1455 textArea->obj.alignmentMarginY = 24;
1456#else // TARGET_STAX
1457 textArea->obj.alignmentMarginY = 16;
1458#endif // TARGET_STAX
1459 textArea->obj.area.width = AVAILABLE_WIDTH;
1460 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1461 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1462 // set this new obj as child of main container
1463 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1464
1465 // create description
1466 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1467 textArea->textColor = BLACK;
1468 textArea->text = PIC(description);
1469 textArea->fontId = SMALL_REGULAR_FONT;
1470 textArea->style = NO_STYLE;
1471 textArea->wrapping = true;
1472 textArea->obj.area.width = AVAILABLE_WIDTH;
1473 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1474 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1475 textArea->textAlignment = MID_LEFT;
1476 textArea->obj.alignment = NO_ALIGNMENT;
1477 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1478#ifdef TARGET_STAX
1479 textArea->obj.alignmentMarginY = 16;
1480#else // TARGET_STAX
1481 textArea->obj.alignmentMarginY = 24;
1482#endif // TARGET_STAX
1483 // set this new obj as child of main container
1484 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1485
1486 // create info on the bottom
1487 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1488 textArea->textColor = DARK_GRAY;
1489 textArea->text = PIC(info);
1490 textArea->fontId = SMALL_REGULAR_FONT;
1491 textArea->style = NO_STYLE;
1492 textArea->wrapping = true;
1493 textArea->obj.area.width = AVAILABLE_WIDTH;
1494 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1495 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1496 textArea->textAlignment = MID_LEFT;
1497 textArea->obj.alignment = BOTTOM_LEFT;
1498 textArea->obj.alignmentMarginX = BORDER_MARGIN;
1499 textArea->obj.alignmentMarginY = 40;
1500 // set this new obj as child of main container
1501 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1502
1503 return layoutInt->container->obj.area.height;
1504}
1505
1514{
1515 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1516 layoutObj_t *obj;
1517 uint8_t i;
1518
1519 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddRadioChoice():\n");
1520 if (layout == NULL) {
1521 return -1;
1522 }
1523 for (i = 0; i < choices->nbChoices; i++) {
1524 nbgl_container_t *container;
1525 nbgl_text_area_t *textArea;
1526 nbgl_radio_t *button;
1527 nbgl_line_t *line;
1528
1529 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1530 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1531 button = (nbgl_radio_t *) nbgl_objPoolGet(RADIO_BUTTON, layoutInt->layer);
1532
1534 layoutInt, (nbgl_obj_t *) container, choices->token, choices->tuneId);
1535 if (obj == NULL) {
1536 return -1;
1537 }
1538
1539 // get container children (max 2)
1540 container->nbChildren = 2;
1541 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
1542 container->obj.area.width = AVAILABLE_WIDTH;
1543 container->obj.area.height = RADIO_CHOICE_HEIGHT;
1544 container->obj.alignment = NO_ALIGNMENT;
1545 container->obj.alignmentMarginX = BORDER_MARGIN;
1546 container->obj.alignTo = (nbgl_obj_t *) NULL;
1547
1548 // init button for this choice
1549 button->activeColor = BLACK;
1550 button->borderColor = LIGHT_GRAY;
1551 button->obj.alignTo = (nbgl_obj_t *) container;
1552 button->obj.alignment = MID_RIGHT;
1553 button->state = OFF_STATE;
1554 container->children[1] = (nbgl_obj_t *) button;
1555
1556 // init text area for this choice
1557 if (choices->localized == true) {
1558#ifdef HAVE_LANGUAGE_PACK
1559 textArea->text = get_ux_loc_string(choices->nameIds[i]);
1560#endif // HAVE_LANGUAGE_PACK
1561 }
1562 else {
1563 textArea->text = PIC(choices->names[i]);
1564 }
1565 textArea->textAlignment = MID_LEFT;
1566 textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH;
1567 textArea->style = NO_STYLE;
1568 textArea->obj.alignment = MID_LEFT;
1569 textArea->obj.alignTo = (nbgl_obj_t *) container;
1570 container->children[0] = (nbgl_obj_t *) textArea;
1571
1572 // whole container should be touchable
1573 container->obj.touchMask = (1 << TOUCHED);
1574 container->obj.touchId = CONTROLS_ID + nbTouchableControls;
1575 nbTouchableControls++;
1576
1577 // highlight init choice
1578 if (i == choices->initChoice) {
1579 button->state = ON_STATE;
1580 textArea->textColor = BLACK;
1581 textArea->fontId = SMALL_BOLD_FONT;
1582 }
1583 else {
1584 button->state = OFF_STATE;
1585 textArea->textColor = DARK_GRAY;
1586 textArea->fontId = SMALL_REGULAR_FONT;
1587 }
1588 textArea->obj.area.height = nbgl_getFontHeight(textArea->fontId);
1589
1590 line = createHorizontalLine(layoutInt->layer);
1591 line->obj.alignmentMarginY = -4;
1592 line->offset = 3;
1593
1594 // set these new objs as child of main container
1595 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1596 layoutAddObject(layoutInt, (nbgl_obj_t *) line);
1597 }
1598
1599 return 0;
1600}
1601
1611{
1612 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1613 nbgl_container_t *container;
1614 nbgl_contentCenter_t centeredInfo = {.icon = info->icon,
1615 .title = NULL,
1616 .smallTitle = NULL,
1617 .description = NULL,
1618 .subText = NULL,
1619 .iconHug = 0,
1620 .padding = false};
1621
1622 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddCenteredInfo():\n");
1623 if (layout == NULL) {
1624 return -1;
1625 }
1626
1627 if (info->text1 != NULL) {
1628 if (info->style != NORMAL_INFO) {
1629 centeredInfo.title = info->text1;
1630 }
1631 else {
1632 centeredInfo.smallTitle = info->text1;
1633 }
1634 }
1635 if (info->text2 != NULL) {
1636 if (info->style != LARGE_CASE_BOLD_INFO) {
1637 centeredInfo.description = info->text2;
1638 }
1639 else {
1640 centeredInfo.smallTitle = info->text2;
1641 }
1642 }
1643 if (info->text3 != NULL) {
1644 if (info->style == LARGE_CASE_GRAY_INFO) {
1645 centeredInfo.subText = info->text3;
1646 }
1647 else {
1648 centeredInfo.description = info->text3;
1649 }
1650 }
1651 container = addContentCenter(layoutInt, &centeredInfo);
1652
1653 if (info->onTop) {
1654 container->obj.alignmentMarginX = BORDER_MARGIN;
1655 container->obj.alignmentMarginY = BORDER_MARGIN + info->offsetY;
1656 container->obj.alignment = NO_ALIGNMENT;
1657 }
1658 else {
1659 container->obj.alignmentMarginY = info->offsetY;
1660 }
1661
1662 return container->obj.area.height;
1663}
1664
1674{
1675 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1676 nbgl_container_t *container;
1677
1678 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddContentCenter():\n");
1679 if (layout == NULL) {
1680 return -1;
1681 }
1682
1683 container = addContentCenter(layoutInt, info);
1684
1685 return container->obj.area.height;
1686}
1687
1696{
1697 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1698 nbgl_container_t *container;
1699 nbgl_text_area_t *textArea;
1700 uint8_t row;
1701
1702 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLeftContent():\n");
1703 if (layout == NULL) {
1704 return -1;
1705 }
1706 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1707
1708 // get container children
1709 container->nbChildren = info->nbRows + 1;
1710 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
1711 container->layout = VERTICAL;
1712 container->obj.area.width = AVAILABLE_WIDTH;
1713 container->obj.alignmentMarginX = BORDER_MARGIN;
1714
1715 // create title
1716 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1717 textArea->textColor = BLACK;
1718 textArea->text = PIC(info->title);
1719 textArea->textAlignment = MID_LEFT;
1720 textArea->fontId = LARGE_MEDIUM_FONT;
1721 textArea->wrapping = true;
1722 textArea->obj.area.width = AVAILABLE_WIDTH;
1723 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1724 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1725
1726 container->obj.area.height += textArea->obj.area.height;
1727
1728 container->children[0] = (nbgl_obj_t *) textArea;
1729
1730 for (row = 0; row < info->nbRows; row++) {
1731 nbgl_container_t *rowContainer;
1732 nbgl_image_t *image;
1733
1734 // create a grid with 1 icon on the left column and 1 text on the right one
1735 rowContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, 0);
1736 rowContainer->nbChildren = 2; // 1 icon + 1 text
1737 rowContainer->children = nbgl_containerPoolGet(rowContainer->nbChildren, 0);
1738 rowContainer->obj.area.width = AVAILABLE_WIDTH;
1739
1740 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, 0);
1741 image->foregroundColor = BLACK;
1742 image->buffer = PIC(info->rowIcons[row]);
1743 rowContainer->children[0] = (nbgl_obj_t *) image;
1744
1745 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0);
1746 textArea->textColor = BLACK;
1747 textArea->text = PIC(info->rowTexts[row]);
1748 textArea->textAlignment = MID_LEFT;
1749 textArea->fontId = SMALL_REGULAR_FONT;
1750 textArea->wrapping = true;
1751 textArea->obj.area.width = AVAILABLE_WIDTH - image->buffer->width - 16;
1752 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1753 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1754 textArea->obj.alignment = MID_RIGHT;
1755 rowContainer->children[1] = (nbgl_obj_t *) textArea;
1756 rowContainer->obj.area.height
1757 = MAX(image->buffer->height, textArea->obj.area.height + LEFT_CONTENT_TEXT_PADDING);
1758
1759 if (row == 0) {
1760 rowContainer->obj.alignmentMarginY = 32;
1761 }
1762 else {
1763 rowContainer->obj.alignmentMarginY = INTER_ROWS_MARGIN;
1764 }
1765 container->children[1 + row] = (nbgl_obj_t *) rowContainer;
1766 container->obj.area.height
1767 += rowContainer->obj.area.height + rowContainer->obj.alignmentMarginY;
1768 }
1769 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1770
1771 return container->obj.area.height;
1772}
1773
1774#ifdef NBGL_QRCODE
1784{
1785 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1786 nbgl_container_t *container;
1787 nbgl_text_area_t *textArea = NULL;
1789 uint16_t fullHeight = 0;
1790
1791 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddQRCode():\n");
1792 if (layout == NULL) {
1793 return -1;
1794 }
1795
1796 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1797
1798 // get container children (max 2 (QRCode + text1 + text2))
1799 container->children = nbgl_containerPoolGet(3, layoutInt->layer);
1800 container->nbChildren = 0;
1801
1803 // version is forced to V10 if url is longer than 62 characters
1804 if (strlen(PIC(info->url)) > 62) {
1805 qrcode->version = QRCODE_V10;
1806 }
1807 else {
1808 qrcode->version = QRCODE_V4;
1809 }
1810 qrcode->foregroundColor = BLACK;
1811 // in QR V4, we use 8*8 screen pixels for one QR pixel
1812 // in QR V10, we use 4*4 screen pixels for one QR pixel
1813 qrcode->obj.area.width
1814 = (qrcode->version == QRCODE_V4) ? (QR_V4_NB_PIX_SIZE * 8) : (QR_V10_NB_PIX_SIZE * 4);
1815 qrcode->obj.area.height = qrcode->obj.area.width;
1816 qrcode->text = PIC(info->url);
1817 qrcode->obj.area.bpp = NBGL_BPP_1;
1818 qrcode->obj.alignment = TOP_MIDDLE;
1819
1820 fullHeight += qrcode->obj.area.height;
1821 container->children[container->nbChildren] = (nbgl_obj_t *) qrcode;
1822 container->nbChildren++;
1823
1824 if (info->text1 != NULL) {
1825 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1826 textArea->textColor = BLACK;
1827 textArea->text = PIC(info->text1);
1828 textArea->textAlignment = CENTER;
1829 textArea->fontId = (info->largeText1 == true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1830 textArea->wrapping = true;
1831 textArea->obj.area.width = AVAILABLE_WIDTH;
1832 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1833 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1834 textArea->obj.alignment = BOTTOM_MIDDLE;
1835 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1836 textArea->obj.alignmentMarginY = 24;
1837
1838 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1839
1840 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1841 container->nbChildren++;
1842 }
1843 if (info->text2 != NULL) {
1844 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1845 textArea->textColor = DARK_GRAY;
1846 textArea->text = PIC(info->text2);
1847 textArea->textAlignment = CENTER;
1848 textArea->fontId = SMALL_REGULAR_FONT;
1849 textArea->wrapping = true;
1850 textArea->obj.area.width = AVAILABLE_WIDTH;
1851 textArea->obj.area.height = nbgl_getTextHeightInWidth(
1852 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1853 textArea->obj.alignment = BOTTOM_MIDDLE;
1854 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1855 if (info->text1 != NULL) {
1856#ifdef TARGET_STAX
1857 textArea->obj.alignmentMarginY = 40;
1858#else // TARGET_STAX
1859 textArea->obj.alignmentMarginY = 28;
1860#endif // TARGET_STAX
1861 }
1862 else {
1863 textArea->obj.alignmentMarginY = 32;
1864 fullHeight += 8;
1865 }
1866
1867 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1868
1869 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1870 container->nbChildren++;
1871 }
1872 // ensure that fullHeight is fitting in main container height (with 16 px margin)
1873 if ((fullHeight >= (layoutInt->container->obj.area.height - 16))
1874 && (qrcode->version == QRCODE_V4)) {
1875 qrcode->version = QRCODE_V4_SMALL;
1876 // in QR V4 small, we use 4*4 screen pixels for one QR pixel
1877 qrcode->obj.area.width = QR_V4_NB_PIX_SIZE * 4;
1878 qrcode->obj.area.height = qrcode->obj.area.width;
1879 fullHeight -= QR_V4_NB_PIX_SIZE * 4;
1880 }
1881 container->obj.area.height = fullHeight;
1882 container->layout = VERTICAL;
1883 if (info->centered) {
1884 container->obj.alignment = CENTER;
1885 }
1886 else {
1887 container->obj.alignment = BOTTOM_MIDDLE;
1888 container->obj.alignTo
1889 = layoutInt->container->children[layoutInt->container->nbChildren - 1];
1890 }
1891 container->obj.alignmentMarginY = info->offsetY;
1892
1893 container->obj.area.width = AVAILABLE_WIDTH;
1894
1895 // set this new container as child of main container
1896 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1897
1898 return fullHeight;
1899}
1900#endif // NBGL_QRCODE
1901
1911{
1912 nbgl_layoutFooter_t footerDesc;
1913 footerDesc.type = FOOTER_CHOICE_BUTTONS;
1914 footerDesc.separationLine = false;
1915 footerDesc.choiceButtons.bottomText = info->bottomText;
1916 footerDesc.choiceButtons.token = info->token;
1917 footerDesc.choiceButtons.topText = info->topText;
1918 footerDesc.choiceButtons.topIcon = info->topIcon;
1919 footerDesc.choiceButtons.style = info->style;
1920 footerDesc.choiceButtons.tuneId = info->tuneId;
1921 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1922}
1923
1935{
1937 .horizontalButtons.leftIcon = info->leftIcon,
1938 .horizontalButtons.leftToken = info->leftToken,
1939 .horizontalButtons.rightText = info->rightText,
1940 .horizontalButtons.rightToken = info->rightToken,
1941 .horizontalButtons.tuneId = info->tuneId};
1942
1943 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHorizontalButtons():\n");
1944 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
1945}
1946
1955{
1956 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1957 nbgl_text_area_t *itemTextArea;
1958 nbgl_text_area_t *valueTextArea;
1959 nbgl_container_t *container;
1960 uint8_t i;
1961
1962 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTagValueList():\n");
1963 if (layout == NULL) {
1964 return -1;
1965 }
1966
1967 for (i = 0; i < list->nbPairs; i++) {
1968 const nbgl_layoutTagValue_t *pair;
1969 uint16_t fullHeight = 0;
1970 const nbgl_icon_details_t *valueIcon = NULL;
1971
1972 if (list->pairs != NULL) {
1973 pair = &list->pairs[i];
1974 }
1975 else {
1976 pair = list->callback(list->startIndex + i);
1977 }
1978
1979 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1980
1981 // get container children (max 3 if a valueIcon, otherwise 2)
1982 container->children
1983 = nbgl_containerPoolGet((pair->valueIcon != NULL) ? 3 : 2, layoutInt->layer);
1984
1985 itemTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1986 valueTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1987
1988 // init text area for this choice
1989 itemTextArea->textColor = DARK_GRAY;
1990 itemTextArea->text = PIC(pair->item);
1991 itemTextArea->textAlignment = MID_LEFT;
1992 itemTextArea->fontId = SMALL_REGULAR_FONT;
1993 itemTextArea->wrapping = true;
1994 itemTextArea->obj.area.width = AVAILABLE_WIDTH;
1995 itemTextArea->obj.area.height = nbgl_getTextHeightInWidth(
1996 itemTextArea->fontId, itemTextArea->text, AVAILABLE_WIDTH, itemTextArea->wrapping);
1997 itemTextArea->style = NO_STYLE;
1998 itemTextArea->obj.alignment = NO_ALIGNMENT;
1999 itemTextArea->obj.alignmentMarginX = 0;
2000 itemTextArea->obj.alignmentMarginY = 0;
2001 itemTextArea->obj.alignTo = NULL;
2002 container->children[container->nbChildren] = (nbgl_obj_t *) itemTextArea;
2003 container->nbChildren++;
2004
2005 fullHeight += itemTextArea->obj.area.height;
2006
2007 // init button for this choice
2008 valueTextArea->textColor = BLACK;
2009 valueTextArea->text = PIC(pair->value);
2010 valueTextArea->textAlignment = MID_LEFT;
2011 if (list->smallCaseForValue) {
2012 valueTextArea->fontId = SMALL_BOLD_FONT;
2013 }
2014 else {
2015 valueTextArea->fontId = LARGE_MEDIUM_FONT;
2016 }
2017 if ((pair->aliasValue == 0) && (pair->valueIcon == NULL)) {
2018 valueTextArea->obj.area.width = AVAILABLE_WIDTH;
2019 }
2020 else {
2021 if (pair->aliasValue) {
2022 // if the value is an alias, we automatically display a (>) icon
2023 valueIcon = &MINI_PUSH_ICON;
2024 }
2025 else {
2026 // otherwise use the provided icon
2027 valueIcon = PIC(pair->valueIcon);
2028 }
2029 // decrease the available width for value text
2030 valueTextArea->obj.area.width = AVAILABLE_WIDTH - valueIcon->width - 12;
2031 }
2032
2033 // handle the nbMaxLinesForValue parameter, used to automatically keep only
2034 // nbMaxLinesForValue lines
2035 uint16_t nbLines = nbgl_getTextNbLinesInWidth(valueTextArea->fontId,
2036 valueTextArea->text,
2037 valueTextArea->obj.area.width,
2038 list->wrapping);
2039 // use this nbMaxLinesForValue parameter only if >0
2040 if ((list->nbMaxLinesForValue > 0) && (nbLines > list->nbMaxLinesForValue)) {
2041 nbLines = list->nbMaxLinesForValue;
2042 valueTextArea->nbMaxLines = list->nbMaxLinesForValue;
2043 }
2044 const nbgl_font_t *font = nbgl_getFont(valueTextArea->fontId);
2045 valueTextArea->obj.area.height = nbLines * font->line_height;
2046 valueTextArea->style = NO_STYLE;
2047 valueTextArea->obj.alignment = BOTTOM_LEFT;
2048 valueTextArea->obj.alignmentMarginY = 4;
2049 valueTextArea->obj.alignTo = (nbgl_obj_t *) itemTextArea;
2050 valueTextArea->wrapping = list->wrapping;
2051 container->children[container->nbChildren] = (nbgl_obj_t *) valueTextArea;
2052 container->nbChildren++;
2053
2054 fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
2055 if (valueIcon != NULL) {
2056 nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
2058 layoutInt, (nbgl_obj_t *) image, list->token, TUNE_TAP_CASUAL);
2059 obj->index = i;
2060 image->foregroundColor = BLACK;
2061 image->buffer = valueIcon;
2062 image->obj.alignment = RIGHT_TOP;
2063 image->obj.alignmentMarginX = 12;
2064 image->obj.alignTo = (nbgl_obj_t *) valueTextArea;
2065 image->obj.touchMask = (1 << TOUCHED);
2066 image->obj.touchId = VALUE_BUTTON_1_ID + i;
2067
2068 container->children[container->nbChildren] = (nbgl_obj_t *) image;
2069 container->nbChildren++;
2070 }
2071
2072 container->obj.area.width = AVAILABLE_WIDTH;
2073 container->obj.area.height = fullHeight;
2074 container->layout = VERTICAL;
2075 container->obj.alignmentMarginX = BORDER_MARGIN;
2076#ifdef TARGET_STAX
2077 // On Stax, 12 px between each tag/value pair
2078 if (i > 0) {
2079 container->obj.alignmentMarginY = 12;
2080 }
2081 else {
2082 container->obj.alignmentMarginY = 24;
2083 }
2084#else // TARGET_STAX
2085 // On Flex, 24 px between each tag/value pair
2086 if (i > 0) {
2087 container->obj.alignmentMarginY = 24;
2088 }
2089#endif // TARGET_STAX
2090 container->obj.alignment = NO_ALIGNMENT;
2091
2092 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
2093 }
2094
2095 return 0;
2096}
2097
2107{
2108 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2109 nbgl_progress_bar_t *progress;
2110
2111 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressBar():\n");
2112 if (layout == NULL) {
2113 return -1;
2114 }
2115 if (barLayout->text != NULL) {
2116 nbgl_text_area_t *textArea;
2117
2119 ((nbgl_layoutInternal_t *) layout)->layer);
2120 textArea->textColor = BLACK;
2121 textArea->text = PIC(barLayout->text);
2122 textArea->textAlignment = MID_LEFT;
2123 textArea->fontId = SMALL_REGULAR_FONT;
2124 textArea->wrapping = true;
2125 textArea->obj.area.width = AVAILABLE_WIDTH;
2126 textArea->obj.area.height = nbgl_getTextHeightInWidth(
2127 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2128 textArea->style = NO_STYLE;
2129 textArea->obj.alignment = NO_ALIGNMENT;
2130 textArea->obj.alignmentMarginX = BORDER_MARGIN;
2131 textArea->obj.alignmentMarginY = BORDER_MARGIN;
2132 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
2133 }
2135 ((nbgl_layoutInternal_t *) layout)->layer);
2136 progress->foregroundColor = BLACK;
2137 progress->withBorder = true;
2138 progress->state = barLayout->percentage;
2139 progress->obj.area.width = 120;
2140 progress->obj.area.height = 12;
2141 progress->obj.alignment = NO_ALIGNMENT;
2142 progress->obj.alignmentMarginX = (AVAILABLE_WIDTH - progress->obj.area.width) / 2;
2143 progress->obj.alignmentMarginY = BORDER_MARGIN;
2144 layoutAddObject(layoutInt, (nbgl_obj_t *) progress);
2145
2146 if (barLayout->subText != NULL) {
2147 nbgl_text_area_t *subTextArea;
2148
2149 subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(
2150 TEXT_AREA, ((nbgl_layoutInternal_t *) layout)->layer);
2151 subTextArea->textColor = LIGHT_GRAY;
2152 subTextArea->text = PIC(barLayout->subText);
2153 subTextArea->textAlignment = MID_LEFT;
2154 subTextArea->fontId = SMALL_REGULAR_FONT;
2155 subTextArea->wrapping = true;
2156 subTextArea->obj.area.width = AVAILABLE_WIDTH;
2157 subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
2158 subTextArea->text,
2159 subTextArea->obj.area.width,
2160 subTextArea->wrapping);
2161 subTextArea->style = NO_STYLE;
2162 subTextArea->obj.alignment = NO_ALIGNMENT;
2163 subTextArea->obj.alignmentMarginX = BORDER_MARGIN;
2164 subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
2165 layoutAddObject(layoutInt, (nbgl_obj_t *) subTextArea);
2166 }
2167
2168 return 0;
2169}
2170
2178{
2179 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2180 nbgl_line_t *line;
2181
2182 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSeparationLine():\n");
2183 line = createHorizontalLine(layoutInt->layer);
2184 line->obj.alignmentMarginY = -4;
2185 line->offset = 3;
2186 layoutAddObject(layoutInt, (nbgl_obj_t *) line);
2187 return 0;
2188}
2189
2198{
2199 layoutObj_t *obj;
2200 nbgl_button_t *button;
2201 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2202
2203 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddButton():\n");
2204 if (layout == NULL) {
2205 return -1;
2206 }
2207
2208 // Add in footer if matching
2209 if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2210 if (layoutInt->footerContainer == NULL) {
2211 nbgl_layoutFooter_t footerDesc;
2212 footerDesc.type = FOOTER_SIMPLE_BUTTON;
2213 footerDesc.separationLine = false;
2214 footerDesc.button.text = buttonInfo->text;
2215 footerDesc.button.token = buttonInfo->token;
2216 footerDesc.button.tuneId = buttonInfo->tuneId;
2217 footerDesc.button.icon = buttonInfo->icon;
2218 footerDesc.button.style = buttonInfo->style;
2219 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2220 }
2221 else {
2222 nbgl_layoutUpFooter_t upFooterDesc;
2223 upFooterDesc.type = UP_FOOTER_BUTTON;
2224 upFooterDesc.button.text = buttonInfo->text;
2225 upFooterDesc.button.token = buttonInfo->token;
2226 upFooterDesc.button.tuneId = buttonInfo->tuneId;
2227 upFooterDesc.button.icon = buttonInfo->icon;
2228 upFooterDesc.button.style = buttonInfo->style;
2229 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2230 }
2231 }
2232
2233 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2235 layoutInt, (nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2236 if (obj == NULL) {
2237 return -1;
2238 }
2239
2240 button->obj.alignmentMarginX = BORDER_MARGIN;
2241 button->obj.alignmentMarginY = 12;
2242 button->obj.alignment = NO_ALIGNMENT;
2243 if (buttonInfo->style == BLACK_BACKGROUND) {
2244 button->innerColor = BLACK;
2245 button->foregroundColor = WHITE;
2246 }
2247 else {
2248 button->innerColor = WHITE;
2249 button->foregroundColor = BLACK;
2250 }
2251 if (buttonInfo->style == NO_BORDER) {
2252 button->borderColor = WHITE;
2253 }
2254 else {
2255 if (buttonInfo->style == BLACK_BACKGROUND) {
2256 button->borderColor = BLACK;
2257 }
2258 else {
2259 button->borderColor = LIGHT_GRAY;
2260 }
2261 }
2262 button->text = PIC(buttonInfo->text);
2263 button->fontId = SMALL_BOLD_FONT;
2264 button->icon = PIC(buttonInfo->icon);
2265 if (buttonInfo->fittingContent == true) {
2266 button->obj.area.width = nbgl_getTextWidth(button->fontId, button->text)
2268 + ((button->icon) ? (button->icon->width + 12) : 0);
2269 button->obj.area.height = SMALL_BUTTON_HEIGHT;
2270 button->radius = RADIUS_32_PIXELS;
2271 if (buttonInfo->onBottom != true) {
2272 button->obj.alignmentMarginX
2273 += (SCREEN_WIDTH - 2 * BORDER_MARGIN - button->obj.area.width) / 2;
2274 }
2275 }
2276 else {
2277 button->obj.area.width = AVAILABLE_WIDTH;
2278 button->obj.area.height = BUTTON_DIAMETER;
2279 button->radius = BUTTON_RADIUS;
2280 }
2281 button->obj.alignTo = NULL;
2282 button->obj.touchMask = (1 << TOUCHED);
2283 button->obj.touchId = (buttonInfo->fittingContent) ? EXTRA_BUTTON_ID : SINGLE_BUTTON_ID;
2284 // set this new button as child of the container
2285 layoutAddObject(layoutInt, (nbgl_obj_t *) button);
2286
2287 return 0;
2288}
2289
2300 const char *text,
2301 uint8_t token,
2302 tune_index_e tuneId)
2303{
2305 .longPress.text = text,
2306 .longPress.token = token,
2307 .longPress.tuneId = tuneId};
2308
2309 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLongPressButton():\n");
2310 if (layout == NULL) {
2311 return -1;
2312 }
2313
2314 return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2315}
2316
2328 const char *text,
2329 uint8_t token,
2330 tune_index_e tuneId)
2331{
2332 nbgl_layoutFooter_t footerDesc;
2333 footerDesc.type = FOOTER_SIMPLE_TEXT;
2334 footerDesc.separationLine = true;
2335 footerDesc.simpleText.text = text;
2336 footerDesc.simpleText.mutedOut = false;
2337 footerDesc.simpleText.token = token;
2338 footerDesc.simpleText.tuneId = tuneId;
2339 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2340}
2341
2355 const char *leftText,
2356 uint8_t leftToken,
2357 const char *rightText,
2358 uint8_t rightToken,
2359 tune_index_e tuneId)
2360{
2361 nbgl_layoutFooter_t footerDesc;
2362 footerDesc.type = FOOTER_DOUBLE_TEXT;
2363 footerDesc.separationLine = true;
2364 footerDesc.doubleText.leftText = leftText;
2365 footerDesc.doubleText.leftToken = leftToken;
2366 footerDesc.doubleText.rightText = rightText;
2367 footerDesc.doubleText.rightToken = rightToken;
2368 footerDesc.doubleText.tuneId = tuneId;
2369 return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2370}
2371
2381{
2382 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2383 layoutObj_t *obj;
2384 nbgl_text_area_t *textArea;
2385 nbgl_line_t *line, *separationLine = NULL;
2386 ;
2387 nbgl_button_t *button;
2388
2389 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHeader():\n");
2390 if (layout == NULL) {
2391 return -1;
2392 }
2393 if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2394 return -2;
2395 }
2396
2397 layoutInt->headerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2398 layoutInt->headerContainer->obj.area.width = SCREEN_WIDTH;
2399 layoutInt->headerContainer->layout = VERTICAL;
2400 layoutInt->headerContainer->children
2401 = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2402 layoutInt->headerContainer->obj.alignment = TOP_MIDDLE;
2403
2404 switch (headerDesc->type) {
2405 case HEADER_EMPTY: {
2406 layoutInt->headerContainer->obj.area.height = headerDesc->emptySpace.height;
2407 break;
2408 }
2410 case HEADER_EXTENDED_BACK: {
2411 const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2412 ? PIC(headerDesc->extendedBack.text)
2413 : PIC(headerDesc->backAndText.text);
2414 uint8_t backToken = (headerDesc->type == HEADER_EXTENDED_BACK)
2415 ? headerDesc->extendedBack.backToken
2416 : headerDesc->backAndText.token;
2417 // add back button
2418 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2419 // only make it active if valid token
2420 if (backToken != NBGL_INVALID_TOKEN) {
2421 obj = layoutAddCallbackObj(layoutInt,
2422 (nbgl_obj_t *) button,
2423 backToken,
2424 (headerDesc->type == HEADER_EXTENDED_BACK)
2425 ? headerDesc->extendedBack.tuneId
2426 : headerDesc->backAndText.tuneId);
2427 if (obj == NULL) {
2428 return -1;
2429 }
2430 }
2431
2432 button->obj.alignment = MID_LEFT;
2433 button->innerColor = WHITE;
2434 button->foregroundColor = (backToken != NBGL_INVALID_TOKEN) ? BLACK : WHITE;
2435 button->borderColor = WHITE;
2436 button->obj.area.width = BACK_KEY_WIDTH;
2437 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2438 button->text = NULL;
2439 button->icon = PIC(&LEFT_ARROW_ICON);
2440 button->obj.touchMask = (backToken != NBGL_INVALID_TOKEN) ? (1 << TOUCHED) : 0;
2441 button->obj.touchId = BACK_BUTTON_ID;
2442 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2443 = (nbgl_obj_t *) button;
2444 layoutInt->headerContainer->nbChildren++;
2445
2446 // add optional text if needed
2447 if (text != NULL) {
2448 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2449 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2450 && (headerDesc->extendedBack.textToken != NBGL_INVALID_TOKEN)) {
2451 obj = layoutAddCallbackObj(layoutInt,
2452 (nbgl_obj_t *) textArea,
2453 headerDesc->extendedBack.textToken,
2454 headerDesc->extendedBack.tuneId);
2455 if (obj == NULL) {
2456 return -1;
2457 }
2458 textArea->obj.touchMask = (1 << TOUCHED);
2459 }
2460 textArea->obj.alignment = CENTER;
2461 textArea->textColor = BLACK;
2462 textArea->obj.area.width
2463 = layoutInt->headerContainer->obj.area.width - 2 * BACK_KEY_WIDTH;
2464 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2465 textArea->text = text;
2466 textArea->fontId = SMALL_BOLD_FONT;
2467 textArea->textAlignment = CENTER;
2468 textArea->wrapping = true;
2469 // ensure that text fits on 2 lines maximum
2470 if (nbgl_getTextNbLinesInWidth(textArea->fontId,
2471 textArea->text,
2472 textArea->obj.area.width,
2473 textArea->wrapping)
2474 > 2) {
2476 "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2477 text);
2478 }
2479 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2480 = (nbgl_obj_t *) textArea;
2481 layoutInt->headerContainer->nbChildren++;
2482 }
2483 // add action key if the type is HEADER_EXTENDED_BACK
2484 if ((headerDesc->type == HEADER_EXTENDED_BACK)
2485 && (headerDesc->extendedBack.actionIcon)) {
2486 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2487 // if token is valid
2488 if (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) {
2489 obj = layoutAddCallbackObj(layoutInt,
2490 (nbgl_obj_t *) button,
2491 headerDesc->extendedBack.actionToken,
2492 headerDesc->extendedBack.tuneId);
2493 if (obj == NULL) {
2494 return -1;
2495 }
2496 button->obj.touchMask = (1 << TOUCHED);
2497 }
2498
2499 button->obj.alignment = MID_RIGHT;
2500 button->innerColor = WHITE;
2501 button->foregroundColor
2503 : LIGHT_GRAY;
2504 button->borderColor = WHITE;
2505 button->obj.area.width = BACK_KEY_WIDTH;
2506 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2507 button->text = NULL;
2508 button->icon = PIC(headerDesc->extendedBack.actionIcon);
2509 button->obj.touchId = EXTRA_BUTTON_ID;
2510 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2511 = (nbgl_obj_t *) button;
2512 layoutInt->headerContainer->nbChildren++;
2513 }
2514
2515 layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2516 break;
2517 }
2519#ifdef TARGET_STAX
2520 // add optional back button
2521 if (headerDesc->progressAndBack.withBack) {
2522 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2523 obj = layoutAddCallbackObj(layoutInt,
2524 (nbgl_obj_t *) button,
2525 headerDesc->progressAndBack.token,
2526 headerDesc->progressAndBack.tuneId);
2527 if (obj == NULL) {
2528 return -1;
2529 }
2530
2531 button->obj.alignment = MID_LEFT;
2532 button->innerColor = WHITE;
2533 button->foregroundColor = BLACK;
2534 button->borderColor = WHITE;
2535 button->obj.area.width = BACK_KEY_WIDTH;
2536 button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2537 button->text = NULL;
2538 button->icon = PIC(&LEFT_ARROW_ICON);
2539 button->obj.touchMask = (1 << TOUCHED);
2540 button->obj.touchId = BACK_BUTTON_ID;
2541 // add to container
2542 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2543 = (nbgl_obj_t *) button;
2544 layoutInt->headerContainer->nbChildren++;
2545 }
2546
2547 // add progress indicator
2548 if (headerDesc->progressAndBack.nbPages > 1
2550 nbgl_page_indicator_t *progress;
2551
2552 progress
2554 progress->activePage = headerDesc->progressAndBack.activePage;
2555 progress->nbPages = headerDesc->progressAndBack.nbPages;
2556 progress->obj.area.width = 224;
2557 progress->obj.alignment = CENTER;
2558 // add to container
2559 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2560 = (nbgl_obj_t *) progress;
2561 layoutInt->headerContainer->nbChildren++;
2562 }
2563 layoutInt->activePage = headerDesc->progressAndBack.activePage;
2564 layoutInt->nbPages = headerDesc->progressAndBack.nbPages;
2565 layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2566#endif // TARGET_STAX
2567 break;
2568 }
2569 case HEADER_TITLE: {
2570 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2571 textArea->textColor = BLACK;
2572 textArea->obj.area.width = AVAILABLE_WIDTH;
2573 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2574 textArea->text = PIC(headerDesc->title.text);
2575 textArea->fontId = SMALL_BOLD_FONT;
2576 textArea->textAlignment = CENTER;
2577 textArea->wrapping = true;
2578 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2579 = (nbgl_obj_t *) textArea;
2580 layoutInt->headerContainer->nbChildren++;
2581 layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2582 break;
2583 }
2584 case HEADER_RIGHT_TEXT: {
2585 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2586 obj = layoutAddCallbackObj(layoutInt,
2587 (nbgl_obj_t *) textArea,
2588 headerDesc->rightText.token,
2589 headerDesc->rightText.tuneId);
2590 if (obj == NULL) {
2591 return -1;
2592 }
2593 textArea->obj.alignment = MID_RIGHT;
2594 textArea->obj.alignmentMarginX = BORDER_MARGIN;
2595 textArea->textColor = BLACK;
2596 textArea->obj.area.width = AVAILABLE_WIDTH;
2597 textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2598 textArea->text = PIC(headerDesc->rightText.text);
2599 textArea->fontId = SMALL_BOLD_FONT;
2600 textArea->textAlignment = MID_RIGHT;
2601 textArea->obj.touchMask = (1 << TOUCHED);
2602 textArea->obj.touchId = TOP_RIGHT_BUTTON_ID;
2603 // add to bottom container
2604 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2605 = (nbgl_obj_t *) textArea;
2606 layoutInt->headerContainer->nbChildren++;
2607 layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2608 break;
2609 }
2610 default:
2611 return -2;
2612 }
2613
2614 if (headerDesc->separationLine) {
2615 line = createHorizontalLine(layoutInt->layer);
2616 line->obj.alignment = BOTTOM_MIDDLE;
2617 line->offset = 3;
2618 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2619 = (nbgl_obj_t *) line;
2620 layoutInt->headerContainer->nbChildren++;
2621 }
2622 if (separationLine != NULL) {
2623 layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2624 = (nbgl_obj_t *) separationLine;
2625 layoutInt->headerContainer->nbChildren++;
2626 }
2627 // header must be the first child
2628 layoutInt->children[HEADER_INDEX] = (nbgl_obj_t *) layoutInt->headerContainer;
2629
2630 // subtract header height from main container height
2631 layoutInt->container->obj.area.height -= layoutInt->headerContainer->obj.area.height;
2632 layoutInt->container->obj.alignTo = (nbgl_obj_t *) layoutInt->headerContainer;
2633 layoutInt->container->obj.alignment = BOTTOM_LEFT;
2634
2635 layoutInt->headerType = headerDesc->type;
2636
2637 return layoutInt->headerContainer->obj.area.height;
2638}
2639
2649{
2650 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2651 layoutObj_t *obj;
2652 nbgl_text_area_t *textArea;
2653 nbgl_line_t *line, *separationLine = NULL;
2654 nbgl_button_t *button;
2655
2656 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddExtendedFooter():\n");
2657 if (layout == NULL) {
2658 return -1;
2659 }
2660 if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2661 return -2;
2662 }
2663
2664 layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2665 layoutInt->footerContainer->obj.area.width = AVAILABLE_WIDTH;
2666 layoutInt->footerContainer->layout = VERTICAL;
2667 layoutInt->footerContainer->children
2668 = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2669 layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
2670
2671 switch (footerDesc->type) {
2672 case FOOTER_EMPTY: {
2673 layoutInt->footerContainer->obj.area.height = footerDesc->emptySpace.height;
2674 break;
2675 }
2676 case FOOTER_SIMPLE_TEXT: {
2677 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2678 obj = layoutAddCallbackObj(layoutInt,
2679 (nbgl_obj_t *) textArea,
2680 footerDesc->simpleText.token,
2681 footerDesc->simpleText.tuneId);
2682 if (obj == NULL) {
2683 return -1;
2684 }
2685
2686 textArea->obj.alignment = BOTTOM_MIDDLE;
2687 textArea->textColor = (footerDesc->simpleText.mutedOut) ? DARK_GRAY : BLACK;
2688 textArea->obj.area.width = AVAILABLE_WIDTH;
2689 textArea->obj.area.height
2691 textArea->text = PIC(footerDesc->simpleText.text);
2692 textArea->fontId
2693 = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
2694 textArea->textAlignment = CENTER;
2695 textArea->obj.touchMask = (1 << TOUCHED);
2696 textArea->obj.touchId = BOTTOM_BUTTON_ID;
2697 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2698 = (nbgl_obj_t *) textArea;
2699 layoutInt->footerContainer->nbChildren++;
2700 layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2701 break;
2702 }
2703 case FOOTER_DOUBLE_TEXT: {
2704 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2705 obj = layoutAddCallbackObj(layoutInt,
2706 (nbgl_obj_t *) textArea,
2707 footerDesc->doubleText.leftToken,
2708 footerDesc->doubleText.tuneId);
2709 if (obj == NULL) {
2710 return -1;
2711 }
2712 textArea->obj.alignment = BOTTOM_LEFT;
2713 textArea->textColor = BLACK;
2714 textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2715 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2716 textArea->text = PIC(footerDesc->doubleText.leftText);
2717 textArea->fontId = SMALL_BOLD_FONT;
2718 textArea->textAlignment = CENTER;
2719 textArea->obj.touchMask = (1 << TOUCHED);
2720 textArea->obj.touchId = BOTTOM_BUTTON_ID;
2721 // add to bottom container
2722 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2723 = (nbgl_obj_t *) textArea;
2724 layoutInt->footerContainer->nbChildren++;
2725
2726 // create right touchable text
2727 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2728 obj = layoutAddCallbackObj(layoutInt,
2729 (nbgl_obj_t *) textArea,
2730 footerDesc->doubleText.rightToken,
2731 footerDesc->doubleText.tuneId);
2732 if (obj == NULL) {
2733 return -1;
2734 }
2735
2736 textArea->obj.alignment = BOTTOM_RIGHT;
2737 textArea->textColor = BLACK;
2738 textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2739 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2740 textArea->text = PIC(footerDesc->doubleText.rightText);
2741 textArea->fontId = SMALL_BOLD_FONT;
2742 textArea->textAlignment = CENTER;
2743 textArea->obj.touchMask = (1 << TOUCHED);
2744 textArea->obj.touchId = RIGHT_BUTTON_ID;
2745 // add to bottom container
2746 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2747 = (nbgl_obj_t *) textArea;
2748 layoutInt->footerContainer->nbChildren++;
2749 layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2750
2751 // create vertical line separating texts
2752 separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2753 separationLine->lineColor = LIGHT_GRAY;
2754 separationLine->obj.area.width = 1;
2755 separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2756 separationLine->direction = VERTICAL;
2757 separationLine->thickness = 1;
2758 separationLine->obj.alignment = MID_LEFT;
2759 separationLine->obj.alignTo = (nbgl_obj_t *) textArea;
2760 separationLine->obj.alignmentMarginX = -1;
2761 break;
2762 }
2763 case FOOTER_TEXT_AND_NAV: {
2764 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2765 layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2766 // add touchable text on the left
2767 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2768 obj = layoutAddCallbackObj(layoutInt,
2769 (nbgl_obj_t *) textArea,
2770 footerDesc->textAndNav.token,
2771 footerDesc->textAndNav.tuneId);
2772 if (obj == NULL) {
2773 return -1;
2774 }
2775 textArea->obj.alignment = BOTTOM_LEFT;
2776 textArea->textColor = BLACK;
2777#ifdef TARGET_STAX
2778 textArea->obj.area.width = 160;
2779#else // TARGET_STAX
2780 textArea->obj.area.width = 192;
2781#endif // TARGET_STAX
2782 textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2783 textArea->text = PIC(footerDesc->textAndNav.text);
2784 textArea->fontId = SMALL_BOLD_FONT;
2785 textArea->textAlignment = CENTER;
2786 textArea->obj.touchMask = (1 << TOUCHED);
2787 textArea->obj.touchId = BOTTOM_BUTTON_ID;
2788 // add to bottom container
2789 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2790 = (nbgl_obj_t *) textArea;
2791 layoutInt->footerContainer->nbChildren++;
2792
2793 // add navigation on the right
2794 nbgl_container_t *navContainer
2796 navContainer->obj.area.width = AVAILABLE_WIDTH;
2797 navContainer->layout = VERTICAL;
2798 navContainer->nbChildren = 4;
2799 navContainer->children
2800 = (nbgl_obj_t **) nbgl_containerPoolGet(navContainer->nbChildren, layoutInt->layer);
2801 navContainer->obj.alignment = BOTTOM_RIGHT;
2802 navContainer->obj.area.width = SCREEN_WIDTH - textArea->obj.area.width;
2803 navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2804 layoutNavigationPopulate(navContainer, &footerDesc->navigation, layoutInt->layer);
2805 obj = layoutAddCallbackObj(layoutInt,
2806 (nbgl_obj_t *) navContainer,
2807 footerDesc->textAndNav.navigation.token,
2808 footerDesc->textAndNav.navigation.tuneId);
2809 if (obj == NULL) {
2810 return -1;
2811 }
2812
2813 // create vertical line separating text from nav
2814 separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2815 separationLine->lineColor = LIGHT_GRAY;
2816 separationLine->obj.area.width = 1;
2817 separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2818 separationLine->direction = VERTICAL;
2819 separationLine->thickness = 1;
2820 separationLine->obj.alignment = MID_LEFT;
2821 separationLine->obj.alignTo = (nbgl_obj_t *) navContainer;
2822 separationLine->obj.alignmentMarginX = -1;
2823
2824 layoutInt->activePage = footerDesc->textAndNav.navigation.activePage;
2825 layoutInt->nbPages = footerDesc->textAndNav.navigation.nbPages;
2826 // add to bottom container
2827 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2828 = (nbgl_obj_t *) navContainer;
2829 layoutInt->footerContainer->nbChildren++;
2830 break;
2831 }
2832 case FOOTER_NAV: {
2833 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2834 layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2836 layoutInt->footerContainer, &footerDesc->navigation, layoutInt->layer);
2837 layoutInt->footerContainer->nbChildren = 4;
2838 obj = layoutAddCallbackObj(layoutInt,
2839 (nbgl_obj_t *) layoutInt->footerContainer,
2840 footerDesc->navigation.token,
2841 footerDesc->navigation.tuneId);
2842 if (obj == NULL) {
2843 return -1;
2844 }
2845
2846 layoutInt->activePage = footerDesc->navigation.activePage;
2847 layoutInt->nbPages = footerDesc->navigation.nbPages;
2848 break;
2849 }
2850 case FOOTER_SIMPLE_BUTTON: {
2851 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2852 obj = layoutAddCallbackObj(layoutInt,
2853 (nbgl_obj_t *) button,
2854 footerDesc->button.token,
2855 footerDesc->button.tuneId);
2856 if (obj == NULL) {
2857 return -1;
2858 }
2859
2860 button->obj.alignment = CENTER;
2861 if (footerDesc->button.style == BLACK_BACKGROUND) {
2862 button->innerColor = BLACK;
2863 button->foregroundColor = WHITE;
2864 }
2865 else {
2866 button->innerColor = WHITE;
2867 button->foregroundColor = BLACK;
2868 }
2869
2870 if (footerDesc->button.style == NO_BORDER) {
2871 button->borderColor = WHITE;
2872 }
2873 else {
2874 if (footerDesc->button.style == BLACK_BACKGROUND) {
2875 button->borderColor = BLACK;
2876 }
2877 else {
2878 button->borderColor = LIGHT_GRAY;
2879 }
2880 }
2881 button->text = PIC(footerDesc->button.text);
2882 button->fontId = SMALL_BOLD_FONT;
2883 button->icon = PIC(footerDesc->button.icon);
2884 button->radius = BUTTON_RADIUS;
2885 button->obj.area.height = BUTTON_DIAMETER;
2886 layoutInt->footerContainer->obj.area.height = FOOTER_BUTTON_HEIGHT;
2887 if (footerDesc->button.text == NULL) {
2888 button->obj.area.width = BUTTON_DIAMETER;
2889 }
2890 else {
2891 button->obj.area.width = AVAILABLE_WIDTH;
2892 }
2893 button->obj.touchMask = (1 << TOUCHED);
2894 button->obj.touchId = button->text ? SINGLE_BUTTON_ID : BOTTOM_BUTTON_ID;
2895 // add to bottom container
2896 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2897 = (nbgl_obj_t *) button;
2898 layoutInt->footerContainer->nbChildren++;
2899 break;
2900 }
2901 case FOOTER_CHOICE_BUTTONS: {
2902 // texts cannot be NULL
2903 if ((footerDesc->choiceButtons.bottomText == NULL)
2904 || (footerDesc->choiceButtons.topText == NULL)) {
2905 return -1;
2906 }
2907
2908 // create bottom button (footer) at first
2909 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2910 obj = layoutAddCallbackObj(layoutInt,
2911 (nbgl_obj_t *) button,
2912 footerDesc->choiceButtons.token,
2913 footerDesc->choiceButtons.tuneId);
2914 if (obj == NULL) {
2915 return -1;
2916 }
2917 // associate with with index 1
2918 obj->index = 1;
2919 // put at the bottom of the container
2920 button->obj.alignment = BOTTOM_MIDDLE;
2921 button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
2922 button->borderColor = WHITE;
2923 button->innerColor = WHITE;
2924 button->foregroundColor = BLACK;
2925 button->obj.area.width = AVAILABLE_WIDTH;
2926 button->obj.area.height = BUTTON_DIAMETER;
2927 button->radius = BUTTON_RADIUS;
2928 button->text = PIC(footerDesc->choiceButtons.bottomText);
2929 button->fontId = SMALL_BOLD_FONT;
2930 button->obj.touchMask = (1 << TOUCHED);
2931 button->obj.touchId = CHOICE_2_ID;
2932 // add to bottom container
2933 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2934 = (nbgl_obj_t *) button;
2935 layoutInt->footerContainer->nbChildren++;
2936
2937 // add line if needed
2938 if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2939 line = createHorizontalLine(layoutInt->layer);
2940 line->obj.alignment = TOP_MIDDLE;
2941 line->obj.alignmentMarginY = 4;
2942 line->obj.alignTo = (nbgl_obj_t *) button;
2943 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2944 = (nbgl_obj_t *) line;
2945 layoutInt->footerContainer->nbChildren++;
2946 }
2947
2948 // then top button, on top of it
2949 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2950 obj = layoutAddCallbackObj(layoutInt,
2951 (nbgl_obj_t *) button,
2952 footerDesc->choiceButtons.token,
2953 footerDesc->choiceButtons.tuneId);
2954 if (obj == NULL) {
2955 return -1;
2956 }
2957 // associate with with index 0
2958 obj->index = 0;
2959 button->obj.alignment = TOP_MIDDLE;
2960 button->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN; // 24 pixels from top of container
2962 button->innerColor = WHITE;
2963 button->borderColor = LIGHT_GRAY;
2964 button->foregroundColor = BLACK;
2965 }
2966 else {
2967 button->innerColor = BLACK;
2968 button->borderColor = BLACK;
2969 button->foregroundColor = WHITE;
2970 }
2971 button->obj.area.width = AVAILABLE_WIDTH;
2972 button->obj.area.height = BUTTON_DIAMETER;
2973 button->radius = BUTTON_RADIUS;
2974 button->text = PIC(footerDesc->choiceButtons.topText);
2975 button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
2976 ? PIC(footerDesc->choiceButtons.topIcon)
2977 : NULL;
2978 button->fontId = SMALL_BOLD_FONT;
2979 button->obj.touchMask = (1 << TOUCHED);
2980 button->obj.touchId = CHOICE_1_ID;
2981 // add to bottom container
2982 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2983 = (nbgl_obj_t *) button;
2984 layoutInt->footerContainer->nbChildren++;
2985
2986 if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2987 layoutInt->footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
2988 }
2989 else {
2990 layoutInt->footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
2991 }
2992
2993 break;
2994 }
2995 default:
2996 return -2;
2997 }
2998
2999 // add swipable feature for navigation
3000 if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
3001 addSwipeInternal(layoutInt,
3002 ((1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT)),
3004 (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
3005 : footerDesc->textAndNav.navigation.token,
3006 (footerDesc->type == FOOTER_NAV)
3007 ? footerDesc->navigation.tuneId
3008 : footerDesc->textAndNav.navigation.tuneId);
3009 }
3010
3011 if (footerDesc->separationLine) {
3012 line = createHorizontalLine(layoutInt->layer);
3013 line->obj.alignment = TOP_MIDDLE;
3014 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
3015 = (nbgl_obj_t *) line;
3016 layoutInt->footerContainer->nbChildren++;
3017 }
3018 if (separationLine != NULL) {
3019 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
3020 = (nbgl_obj_t *) separationLine;
3021 layoutInt->footerContainer->nbChildren++;
3022 }
3023
3024 layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
3025
3026 // subtract footer height from main container height
3027 layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
3028
3029 layoutInt->footerType = footerDesc->type;
3030
3031 return layoutInt->footerContainer->obj.area.height;
3032}
3033
3043{
3044 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3045 layoutObj_t *obj;
3046 nbgl_text_area_t *textArea;
3047 nbgl_line_t *line;
3048 nbgl_button_t *button;
3049
3050 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddUpFooter():\n");
3051 if (layout == NULL) {
3052 return -1;
3053 }
3054 if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
3055 return -2;
3056 }
3057
3058 layoutInt->upFooterContainer
3060 layoutInt->upFooterContainer->obj.area.width = SCREEN_WIDTH;
3061 layoutInt->upFooterContainer->layout = VERTICAL;
3062 // maximum 4 children for long press button
3063 layoutInt->upFooterContainer->children
3064 = (nbgl_obj_t **) nbgl_containerPoolGet(4, layoutInt->layer);
3065 layoutInt->upFooterContainer->obj.alignTo = (nbgl_obj_t *) layoutInt->container;
3066 layoutInt->upFooterContainer->obj.alignment = BOTTOM_MIDDLE;
3067
3068 switch (upFooterDesc->type) {
3069 case UP_FOOTER_LONG_PRESS: {
3070 nbgl_progress_bar_t *progressBar;
3071
3072 obj = layoutAddCallbackObj(layoutInt,
3073 (nbgl_obj_t *) layoutInt->upFooterContainer,
3074 upFooterDesc->longPress.token,
3075 upFooterDesc->longPress.tuneId);
3076 if (obj == NULL) {
3077 return -1;
3078 }
3079 layoutInt->upFooterContainer->nbChildren = 4;
3080 layoutInt->upFooterContainer->obj.area.height = LONG_PRESS_BUTTON_HEIGHT;
3081 layoutInt->upFooterContainer->obj.touchId = LONG_PRESS_BUTTON_ID;
3082 layoutInt->upFooterContainer->obj.touchMask
3083 = ((1 << TOUCHING) | (1 << TOUCH_RELEASED) | (1 << OUT_OF_TOUCH)
3084 | (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT));
3085
3086 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3087 button->obj.alignmentMarginX = BORDER_MARGIN;
3088 button->obj.alignment = MID_RIGHT;
3089 button->innerColor = BLACK;
3090 button->foregroundColor = WHITE;
3091 button->borderColor = BLACK;
3092 button->obj.area.width = BUTTON_DIAMETER;
3093 button->obj.area.height = BUTTON_DIAMETER;
3094 button->radius = BUTTON_RADIUS;
3095 button->icon = PIC(&VALIDATE_ICON);
3096 layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3097
3098 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3099 textArea->textColor = BLACK;
3100 textArea->text = PIC(upFooterDesc->longPress.text);
3101 textArea->textAlignment = MID_LEFT;
3102 textArea->fontId = LARGE_MEDIUM_FONT;
3103 textArea->wrapping = true;
3104 textArea->obj.area.width = SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
3105 textArea->obj.area.height = nbgl_getTextHeightInWidth(
3106 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3107 textArea->style = NO_STYLE;
3108 textArea->obj.alignment = MID_LEFT;
3109 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3110 layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) textArea;
3111
3112 line = createHorizontalLine(layoutInt->layer);
3113 line->offset = 3;
3114 line->obj.alignment = TOP_MIDDLE;
3115 layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) line;
3116
3117 progressBar = (nbgl_progress_bar_t *) nbgl_objPoolGet(PROGRESS_BAR, layoutInt->layer);
3118 progressBar->withBorder = false;
3119 progressBar->obj.area.width = SCREEN_WIDTH;
3120 progressBar->obj.area.height = 8;
3121 progressBar->obj.alignment = TOP_MIDDLE;
3122 progressBar->obj.alignmentMarginY = 4;
3123 progressBar->obj.alignTo = NULL;
3124 layoutInt->upFooterContainer->children[3] = (nbgl_obj_t *) progressBar;
3125 break;
3126 }
3127 case UP_FOOTER_BUTTON: {
3128 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3129 obj = layoutAddCallbackObj(layoutInt,
3130 (nbgl_obj_t *) button,
3131 upFooterDesc->button.token,
3132 upFooterDesc->button.tuneId);
3133 if (obj == NULL) {
3134 return -1;
3135 }
3136
3137 layoutInt->upFooterContainer->nbChildren = 1;
3138 layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3139 button->obj.alignment = CENTER;
3140
3141 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3142 button->innerColor = BLACK;
3143 button->foregroundColor = WHITE;
3144 }
3145 else {
3146 button->innerColor = WHITE;
3147 button->foregroundColor = BLACK;
3148 }
3149 if (upFooterDesc->button.style == NO_BORDER) {
3150 button->borderColor = WHITE;
3151 }
3152 else {
3153 if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3154 button->borderColor = BLACK;
3155 }
3156 else {
3157 button->borderColor = LIGHT_GRAY;
3158 }
3159 }
3160 button->text = PIC(upFooterDesc->button.text);
3161 button->fontId = SMALL_BOLD_FONT;
3162 button->icon = PIC(upFooterDesc->button.icon);
3163 button->obj.area.width = AVAILABLE_WIDTH;
3164 button->obj.area.height = BUTTON_DIAMETER;
3165 button->radius = BUTTON_RADIUS;
3166
3167 button->obj.alignTo = NULL;
3168 button->obj.touchMask = (1 << TOUCHED);
3169 button->obj.touchId = SINGLE_BUTTON_ID;
3170 layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3171 break;
3172 }
3174 // icon & text cannot be NULL
3175 if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3176 || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3177 return -1;
3178 }
3179
3180 layoutInt->upFooterContainer->nbChildren = 2;
3181 layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3182
3183 // create left button (in white) at first
3184 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3185 obj = layoutAddCallbackObj(layoutInt,
3186 (nbgl_obj_t *) button,
3187 upFooterDesc->horizontalButtons.leftToken,
3188 upFooterDesc->horizontalButtons.tuneId);
3189 if (obj == NULL) {
3190 return -1;
3191 }
3192 // associate with with index 1
3193 obj->index = 1;
3194 button->obj.alignment = MID_LEFT;
3195 button->obj.alignmentMarginX = BORDER_MARGIN;
3196 button->borderColor = LIGHT_GRAY;
3197 button->innerColor = WHITE;
3198 button->foregroundColor = BLACK;
3199 button->obj.area.width = BUTTON_DIAMETER;
3200 button->obj.area.height = BUTTON_DIAMETER;
3201 button->radius = BUTTON_RADIUS;
3202 button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3203 button->fontId = SMALL_BOLD_FONT;
3204 button->obj.touchMask = (1 << TOUCHED);
3205 button->obj.touchId = CHOICE_2_ID;
3206 layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3207
3208 // then black button, on right
3209 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3210 obj = layoutAddCallbackObj(layoutInt,
3211 (nbgl_obj_t *) button,
3212 upFooterDesc->horizontalButtons.rightToken,
3213 upFooterDesc->horizontalButtons.tuneId);
3214 if (obj == NULL) {
3215 return -1;
3216 }
3217 // associate with with index 0
3218 obj->index = 0;
3219 button->obj.alignment = MID_RIGHT;
3220 button->obj.alignmentMarginX = BORDER_MARGIN;
3221 button->innerColor = BLACK;
3222 button->borderColor = BLACK;
3223 button->foregroundColor = WHITE;
3224 button->obj.area.width = AVAILABLE_WIDTH - BUTTON_DIAMETER - 16;
3225 button->obj.area.height = BUTTON_DIAMETER;
3226 button->radius = BUTTON_RADIUS;
3227 button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3228 button->fontId = SMALL_BOLD_FONT;
3229 button->obj.touchMask = (1 << TOUCHED);
3230 button->obj.touchId = CHOICE_1_ID;
3231 layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) button;
3232 break;
3233 }
3234 case UP_FOOTER_TIP_BOX: {
3235 // text cannot be NULL
3236 if (upFooterDesc->tipBox.text == NULL) {
3237 return -1;
3238 }
3239 obj = layoutAddCallbackObj(layoutInt,
3240 (nbgl_obj_t *) layoutInt->upFooterContainer,
3241 upFooterDesc->tipBox.token,
3242 upFooterDesc->tipBox.tuneId);
3243 if (obj == NULL) {
3244 return -1;
3245 }
3246 layoutInt->upFooterContainer->nbChildren = 3;
3247 layoutInt->upFooterContainer->obj.touchId = TIP_BOX_ID;
3248 layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3249
3250 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3251 textArea->textColor = BLACK;
3252 textArea->text = PIC(upFooterDesc->tipBox.text);
3253 textArea->textAlignment = MID_LEFT;
3254 textArea->fontId = SMALL_REGULAR_FONT;
3255 textArea->wrapping = true;
3256 textArea->obj.area.width = AVAILABLE_WIDTH;
3257 if (upFooterDesc->tipBox.icon != NULL) {
3258 textArea->obj.area.width
3259 -= ((nbgl_icon_details_t *) PIC(upFooterDesc->tipBox.icon))->width
3260 + BORDER_MARGIN;
3261 }
3262 textArea->obj.area.height = nbgl_getTextHeightInWidth(
3263 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3264 textArea->obj.alignment = MID_LEFT;
3265 textArea->obj.alignmentMarginX = BORDER_MARGIN;
3266 layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3267 layoutInt->upFooterContainer->obj.area.height = textArea->obj.area.height;
3268
3269 line = createHorizontalLine(layoutInt->layer);
3270 line->offset = 3;
3271 line->obj.alignment = TOP_MIDDLE;
3272 layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) line;
3273
3274 if (upFooterDesc->tipBox.icon != NULL) {
3275 nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
3276 image->obj.alignmentMarginX = BORDER_MARGIN;
3277 image->obj.alignment = MID_RIGHT;
3278 image->foregroundColor = BLACK;
3279 image->buffer = PIC(upFooterDesc->tipBox.icon);
3280 layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) image;
3281 if (layoutInt->upFooterContainer->obj.area.height < image->buffer->height) {
3282 layoutInt->upFooterContainer->obj.area.height = image->buffer->height;
3283 }
3284 }
3285 layoutInt->upFooterContainer->obj.area.height += 2 * BOTTOM_BORDER_MARGIN;
3286
3287 break;
3288 }
3289 case UP_FOOTER_TEXT: {
3290 obj = layoutAddCallbackObj(layoutInt,
3291 (nbgl_obj_t *) layoutInt->upFooterContainer,
3292 upFooterDesc->text.token,
3293 upFooterDesc->text.tuneId);
3294 if (obj == NULL) {
3295 return -1;
3296 }
3297 layoutInt->upFooterContainer->nbChildren = 1;
3298 layoutInt->upFooterContainer->obj.area.height = SMALL_FOOTER_HEIGHT;
3299 layoutInt->upFooterContainer->obj.touchId = WHOLE_SCREEN_ID;
3300 layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3301
3302 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3303 textArea->textColor = DARK_GRAY;
3304 textArea->text = PIC(upFooterDesc->text.text);
3305 textArea->textAlignment = CENTER;
3306 textArea->fontId = SMALL_REGULAR_FONT;
3307 textArea->wrapping = true;
3308 textArea->obj.area.width = AVAILABLE_WIDTH;
3309 textArea->obj.area.height = nbgl_getTextHeightInWidth(
3310 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3311 textArea->obj.alignment = CENTER;
3312 layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3313 break;
3314 }
3315 default:
3316 return -2;
3317 }
3318
3319 // subtract up footer height from main container height
3320 layoutInt->container->obj.area.height -= layoutInt->upFooterContainer->obj.area.height;
3321
3322 layoutInt->children[UP_FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->upFooterContainer;
3323
3324 layoutInt->upFooterType = upFooterDesc->type;
3325
3326 return layoutInt->upFooterContainer->obj.area.height;
3327}
3328
3343 uint8_t activePage,
3344 uint8_t nbPages,
3345 bool withBack,
3346 uint8_t backToken,
3347 tune_index_e tuneId)
3348{
3350 .separationLine = false,
3351 .progressAndBack.activePage = activePage,
3352 .progressAndBack.nbPages = nbPages,
3353 .progressAndBack.token = backToken,
3354 .progressAndBack.tuneId = tuneId,
3355 .progressAndBack.withBack = withBack,
3356 .progressAndBack.actionIcon = NULL,
3357 .progressAndBack.actionToken = NBGL_INVALID_TOKEN};
3358 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressIndicator():\n");
3359
3360 return nbgl_layoutAddHeader(layout, &headerDesc);
3361}
3362
3372int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, uint8_t initPosition)
3373{
3374 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3375 nbgl_container_t *container;
3376 nbgl_text_area_t *textArea;
3377 nbgl_spinner_t *spinner;
3378
3379 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSpinner():\n");
3380 if (layout == NULL) {
3381 return -1;
3382 }
3383
3384 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
3385 // spinner + text
3386 container->nbChildren = 2;
3387 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
3388
3389 container->obj.area.width = AVAILABLE_WIDTH;
3390 container->layout = VERTICAL;
3391 container->obj.alignment = CENTER;
3392
3393 // create spinner
3394 spinner = (nbgl_spinner_t *) nbgl_objPoolGet(SPINNER, layoutInt->layer);
3395 spinner->position = initPosition;
3396 spinner->obj.alignment = TOP_MIDDLE;
3397 // set this new spinner as child of the container
3398 container->children[0] = (nbgl_obj_t *) spinner;
3399
3400 // update container height
3401 container->obj.area.height += SPINNER_HEIGHT;
3402
3403 // create text area
3404 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3405 textArea->textColor = BLACK;
3406 textArea->text = PIC(text);
3407 textArea->textAlignment = CENTER;
3408 textArea->fontId = SMALL_REGULAR_FONT;
3409 textArea->wrapping = true;
3410#ifdef TARGET_STAX
3411 textArea->obj.alignmentMarginY = 20;
3412#else // TARGET_STAX
3413 textArea->obj.alignmentMarginY = 24;
3414#endif // TARGET_STAX
3415 textArea->obj.alignTo = (nbgl_obj_t *) spinner;
3416 textArea->obj.alignment = BOTTOM_MIDDLE;
3417 textArea->obj.area.width = AVAILABLE_WIDTH;
3418 textArea->obj.area.height = nbgl_getTextHeightInWidth(
3419 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3420 textArea->style = NO_STYLE;
3421
3422 // update container height
3423 container->obj.area.height += textArea->obj.alignmentMarginY + textArea->obj.area.height;
3424
3425 // set this text as child of the container
3426 container->children[1] = (nbgl_obj_t *) textArea;
3427
3428 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
3429
3430 if (initPosition != SPINNER_FIXED) {
3431 // update ticker to update the spinner periodically
3433
3434 tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD; // ms
3435 tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD; // ms
3436 tickerCfg.tickerCallback = &spinnerTickerCallback;
3437 nbgl_screenUpdateTicker(layoutInt->layer, &tickerCfg);
3438 }
3439
3440 return 0;
3441}
3442
3453int nbgl_layoutUpdateSpinner(nbgl_layout_t *layout, const char *text, uint8_t position)
3454{
3455 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3456 nbgl_container_t *container;
3457 nbgl_text_area_t *textArea;
3458 nbgl_spinner_t *spinner;
3459 int ret = 0;
3460
3461 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateSpinner():\n");
3462 if ((layout == NULL) || (layoutInt->container->nbChildren == 0)) {
3463 return -1;
3464 }
3465
3466 container = (nbgl_container_t *) layoutInt->container->children[0];
3467 if ((container->obj.type != CONTAINER) || (container->nbChildren < 2)) {
3468 return -1;
3469 }
3470
3471 spinner = (nbgl_spinner_t *) container->children[0];
3472 if (spinner->obj.type != SPINNER) {
3473 return -1;
3474 }
3475 // if position is different, redraw
3476 if (spinner->position != position) {
3477 spinner->position = position;
3478 nbgl_objDraw((nbgl_obj_t *) spinner);
3479 ret = 1;
3480 }
3481
3482 // update text area if necessary
3483 textArea = (nbgl_text_area_t *) container->children[1];
3484 if (textArea->obj.type != TEXT_AREA) {
3485 return -1;
3486 }
3487 const char *newText = PIC(text);
3488 size_t newTextLen = strlen(newText);
3489 // if text is different, redraw (don't use strcmp because it crashes with Rust SDK)
3490 if ((newTextLen != strlen(textArea->text)) || memcmp(textArea->text, newText, newTextLen)) {
3491 textArea->text = newText;
3492 nbgl_objDraw((nbgl_obj_t *) textArea);
3493 ret = 2;
3494 }
3495
3496 return ret;
3497}
3498
3506{
3507 nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3508
3509 if (layout == NULL) {
3510 return -1;
3511 }
3513 "nbgl_layoutDraw(): container.nbChildren =%d, layout->nbChildren = %d\n",
3514 layout->container->nbChildren,
3515 layout->nbChildren);
3516 if (layout->tapText) {
3517 // set this new container as child of main container
3518 layoutAddObject(layout, (nbgl_obj_t *) layout->tapText);
3519 }
3520 if (layout->withLeftBorder == true) {
3521 // draw now the line
3522 nbgl_line_t *line = createLeftVerticalLine(layout->layer);
3523 layout->children[LEFT_BORDER_INDEX] = (nbgl_obj_t *) line;
3524 }
3526
3527 return 0;
3528}
3529
3537{
3538 nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3539 LOG_DEBUG(PAGE_LOGGER, "nbgl_layoutRelease(): \n");
3540 if (layout == NULL) {
3541 return -1;
3542 }
3543 // if modal
3544 if (layout->modal) {
3545 nbgl_screenPop(layout->layer);
3546 }
3547 layout->nbChildren = 0;
3548 return 0;
3549}
3550
3551#endif // HAVE_SE_TOUCH
Random Number Generation.
@ LARGE_CASE_BOLD_INFO
@ NORMAL_INFO
@ LARGE_CASE_GRAY_INFO
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
#define LOG_FATAL(__logger,...)
Definition nbgl_debug.h:88
@ LAYOUT_LOGGER
Definition nbgl_debug.h:33
@ PAGE_LOGGER
Definition nbgl_debug.h:34
#define qrcode
Definition nbgl_draw.c:46
Middle Level API of the new BOLOS Graphical Library.
#define QR_V10_NB_PIX_SIZE
Definition nbgl_draw.h:24
#define QR_V4_NB_PIX_SIZE
Definition nbgl_draw.h:23
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
return the height in pixels of the font with the given font ID
Definition nbgl_fonts.c:398
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text (can be multiline)
Definition nbgl_fonts.c:360
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
Definition nbgl_fonts.c:731
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:136
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
return the height in pixels of the line of font with the given font ID
Definition nbgl_fonts.c:410
Font screen low-Level driver API, to draw elementary forms.
#define LEFT_CONTENT_TEXT_PADDING
Definition nbgl_layout.c:61
int nbgl_layoutUpdateSpinner(nbgl_layout_t *layout, const char *text, uint8_t position)
Update an existing spinner (must be the only object of the layout)
int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueList_t *list)
Creates a list of [tag,value] pairs.
int nbgl_layoutAddContentCenter(nbgl_layout_t *layout, const nbgl_contentCenter_t *info)
Creates an area on the center of the main panel, with a possible icon, and possible texts under it.
#define HOLD_TO_APPROVE_STEP_PERCENT
int nbgl_layoutAddUpFooter(nbgl_layout_t *layout, const nbgl_layoutUpFooter_t *upFooterDesc)
Creates a touchable area on top of the footer of the screen, containing various controls,...
int nbgl_layoutDraw(nbgl_layout_t *layoutParam)
Applies given layout. The screen will be redrawn.
#define NB_MAX_CONTAINER_CHILDREN
Definition nbgl_layout.c:38
int nbgl_layoutAddTextContent(nbgl_layout_t *layout, const char *title, const char *description, const char *info)
Creates in the main container three text areas:
int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, uint8_t initPosition)
Creates a centered (vertically & horizontally) spinner with a text under it.
int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
Creates an area with given text (in bold) and sub text (in regular)
int nbgl_layoutAddProgressIndicator(nbgl_layout_t *layout, uint8_t activePage, uint8_t nbPages, bool withBack, uint8_t backToken, tune_index_e tuneId)
Creates a kind of navigation bar with an optional <- arrow on the left. This widget is placed on top ...
int nbgl_layoutAddNavigationBar(nbgl_layout_t *layout, const nbgl_layoutNavigationBar_t *info)
Creates a navigation bar on bottom of main container.
#define ROUNDED_AND_FOOTER_FOOTER_HEIGHT
Definition nbgl_layout.c:58
int nbgl_layoutAddSeparationLine(nbgl_layout_t *layout)
adds a separation line on bottom of the last added item
int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info)
Creates an area on the center of the main panel, with a QRCode, a possible text in black (bold) under...
#define ACTION_AND_FOOTER_FOOTER_HEIGHT
Definition nbgl_layout.c:59
int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoice_t *choices)
Creates a list of radio buttons (on the right)
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_layoutAddSplitFooter(nbgl_layout_t *layout, const char *leftText, uint8_t leftToken, const char *rightText, uint8_t rightToken, tune_index_e tuneId)
Creates 2 touchable texts at the footer of the screen, separated with a thin line from the rest of th...
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_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
Creates an area with given text in small regular font, under the header.
int nbgl_layoutAddTextWithAlias(nbgl_layout_t *layout, const char *text, const char *subText, uint8_t token, uint8_t index)
Creates an area with given text (in bold) and sub text (in regular), with a ‍icon on right of text to...
int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout)
Creates a touchable bar in main panel.
#define SPINNER_REFRESH_PERIOD
Definition nbgl_layout.c:65
int nbgl_layoutAddTopRightButton(nbgl_layout_t *layout, const nbgl_icon_details_t *icon, uint8_t token, tune_index_e tuneId)
Creates a Top-right button in the top right corner of the top panel.
#define INTER_ROWS_MARGIN
Definition nbgl_layout.c:60
int nbgl_layoutAddSwipe(nbgl_layout_t *layout, uint16_t swipesMask, const char *text, uint8_t token, tune_index_e tuneId)
Creates a swipe interaction on the main container.
#define RADIO_CHOICE_HEIGHT
Definition nbgl_layout.c:53
int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
Creates a switch with the given text and its state.
int nbgl_layoutAddHorizontalButtons(nbgl_layout_t *layout, const nbgl_layoutHorizontalButtons_t *info)
Creates two buttons to make a choice. Both buttons are mandatory The left one contains only an icon a...
listItemType_t
Definition nbgl_layout.c:87
@ NB_ITEM_TYPES
Definition nbgl_layout.c:90
@ TOUCHABLE_BAR_ITEM
Definition nbgl_layout.c:88
@ SWITCH_ITEM
Definition nbgl_layout.c:89
int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *buttonInfo)
Creates a rounded button in the main container.
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
int nbgl_layoutAddExtendedFooter(nbgl_layout_t *layout, const nbgl_layoutFooter_t *footerDesc)
Creates a touchable area at the footer of the screen, containing various controls,...
int nbgl_layoutAddLeftContent(nbgl_layout_t *layout, const nbgl_layoutLeftContent_t *info)
Creates an area with a title, and rows of icon + text, left aligned.
const char * get_ux_loc_string(uint32_t index)
#define NB_MAX_LAYOUTS
Definition nbgl_layout.c:35
int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info)
Creates two buttons to make a choice. Both buttons are mandatory. Both buttons are full width,...
int nbgl_layoutRelease(nbgl_layout_t *layoutParam)
Release the layout obtained with nbgl_layoutGet()
#define BAR_INTERVALE
Definition nbgl_layout.c:55
int nbgl_layoutAddLongPressButton(nbgl_layout_t *layout, const char *text, uint8_t token, tune_index_e tuneId)
Creates a long press button in the main container.
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the main container
int nbgl_layoutAddHeader(nbgl_layout_t *layout, const nbgl_layoutHeader_t *headerDesc)
Creates a touchable (or not) area at the header of the screen, containing various controls,...
#define BACK_KEY_WIDTH
Definition nbgl_layout.c:56
int nbgl_layoutAddBottomButton(nbgl_layout_t *layout, const nbgl_icon_details_t *icon, uint8_t token, bool separationLine, tune_index_e tuneId)
Creates a centered button at bottom of main container.
int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text)
Creates an area with given text in 32px font (in Black)
#define HOLD_TO_APPROVE_STEP_DURATION_MS
#define FOOTER_BUTTON_HEIGHT
Definition nbgl_layout.c:57
int nbgl_layoutAddFooter(nbgl_layout_t *layout, const char *text, uint8_t token, tune_index_e tuneId)
Creates a touchable text at the footer of the screen, separated with a thin line from the rest of the...
@ LEFT_HALF_INDEX
Definition nbgl_layout.c:73
@ PAGE_INDICATOR_INDEX
Definition nbgl_layout.c:72
@ FIRST_BUTTON_INDEX
Definition nbgl_layout.c:75
@ RIGHT_HALF_INDEX
Definition nbgl_layout.c:74
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
#define SIMPLE_FOOTER_HEIGHT
Definition nbgl_layout.h:65
#define LONG_PRESS_BUTTON_HEIGHT
Definition nbgl_layout.h:69
#define PRE_TEXT_MARGIN
Definition nbgl_layout.h:85
#define TOUCHABLE_MAIN_BAR_HEIGHT
Definition nbgl_layout.h:62
#define TEXT_SUBTEXT_MARGIN
Definition nbgl_layout.h:86
#define TOUCHABLE_BAR_HEIGHT
Definition nbgl_layout.h:63
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
@ NO_BORDER
simple clickable text, in black
@ BLACK_BACKGROUND
rounded bordered button, with text/icon in white, on black background
#define AVAILABLE_WIDTH
Definition nbgl_layout.h:76
@ UP_FOOTER_TEXT
grayed-out text, for example "Tap to continue"
@ NB_UP_FOOTER_TYPES
@ UP_FOOTER_BUTTON
simple button
@ UP_FOOTER_LONG_PRESS
long-press button
@ UP_FOOTER_TIP_BOX
Tip-box.
@ UP_FOOTER_HORIZONTAL_BUTTONS
2 buttons, on the same line
void * nbgl_layout_t
type shared externally
@ HEADER_TITLE
simple centered text
@ HEADER_BACK_AND_PROGRESS
optional back key and progress indicator (only on Stax)
@ HEADER_EMPTY
empty space, to have a better vertical centering of centered info
@ NB_HEADER_TYPES
@ HEADER_EXTENDED_BACK
back key, centered text and touchable key on the right
@ HEADER_BACK_AND_TEXT
back key and optional text
@ HEADER_RIGHT_TEXT
touchable text on the right, with a vertical separation line
#define SMALL_FOOTER_HEIGHT
Definition nbgl_layout.h:64
#define NBGL_INVALID_TOKEN
Definition nbgl_layout.h:33
#define SPINNER_FIXED
position to use for a "fixed" spinner
Definition nbgl_layout.h:98
@ SOFT_ACTION_AND_FOOTER_STYLE
A white button on top of a footer, with a separation line.
@ ROUNDED_AND_FOOTER_STYLE
A black background button on top of a footer.
#define NBGL_NO_PROGRESS_INDICATOR
To be used when a control token shall not be used.
Definition nbgl_layout.h:30
#define POST_SUBTEXT_MARGIN
Definition nbgl_layout.h:87
#define NBGL_NO_TUNE
Definition nbgl_layout.h:29
@ FOOTER_SIMPLE_TEXT
simple touchable text in bold
@ FOOTER_NAV
navigation bar
@ FOOTER_SIMPLE_BUTTON
simple black or white button (see nbgl_layoutButtonStyle_t)
@ FOOTER_TEXT_AND_NAV
@ FOOTER_DOUBLE_TEXT
2 touchable texts in bold, separated by a vertical line (only on Stax)
@ NB_FOOTER_TYPES
@ FOOTER_EMPTY
empty space, to have a better vertical centering of centered info
@ FOOTER_CHOICE_BUTTONS
double buttons (see nbgl_layoutChoiceButtonsStyle_t)
#define UP_FOOTER_BUTTON_HEIGHT
Definition nbgl_layout.h:70
#define TOUCHABLE_HEADER_BAR_HEIGHT
Definition nbgl_layout.h:61
Internal functions/constants of NBGL layout layer.
nbgl_swipe_usage_t
@ SWIPE_USAGE_CUSTOM
@ SWIPE_USAGE_SUGGESTIONS
@ SWIPE_USAGE_NAVIGATION
bool keyboardSwipeCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
@ UP_FOOTER_INDEX
@ FOOTER_INDEX
@ HEADER_INDEX
@ TOP_RIGHT_BUTTON_INDEX
@ MAIN_CONTAINER_INDEX
@ LEFT_BORDER_INDEX
@ NB_MAX_SCREEN_CHILDREN
#define SMALL_BUTTON_HEIGHT
void layoutNavigationPopulate(nbgl_container_t *navContainer, const nbgl_layoutNavigationBar_t *navConfig, uint8_t layer)
This function creates a full navigation bar "object", with buttons and returns it as a container.
#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)
function to be called when any of the controls in navigation bar is touched
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)
#define PUSH_ICON
Definition nbgl_obj.h:143
#define NB_SPINNER_POSITIONS
Definition nbgl_obj.h:174
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
Definition nbgl_obj.h:234
struct PACKED__ nbgl_text_area_s nbgl_text_area_t
struct to represent a text area (TEXT_AREA type)
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
Definition nbgl_obj.c:1617
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)
Gets a new container from the pool, with the given number of obj pointers.
#define SWIPE_MASK
Definition nbgl_obj.h:180
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
Gets a new graphic object from the pool, with the given type. The type field of the object is set.
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
Definition nbgl_obj.c:1666
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
#define RADIO_WIDTH
Definition nbgl_obj.h:106
#define BUTTON_RADIUS
Definition nbgl_obj.h:87
#define BORDER_MARGIN
Definition nbgl_obj.h:71
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 VALIDATE_ICON
Definition nbgl_obj.h:140
#define MINI_PUSH_ICON
Definition nbgl_obj.h:152
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
Definition nbgl_obj.c:1682
@ CHOICE_1_ID
Definition nbgl_obj.h:566
@ TOP_RIGHT_BUTTON_ID
Definition nbgl_obj.h:562
@ LONG_PRESS_BUTTON_ID
Definition nbgl_obj.h:574
@ CONTROLS_ID
Definition nbgl_obj.h:576
@ RIGHT_BUTTON_ID
Definition nbgl_obj.h:560
@ WHOLE_SCREEN_ID
Definition nbgl_obj.h:561
@ BOTTOM_BUTTON_ID
Definition nbgl_obj.h:558
@ SINGLE_BUTTON_ID
Definition nbgl_obj.h:564
@ BACK_BUTTON_ID
Definition nbgl_obj.h:563
@ VALUE_BUTTON_1_ID
Definition nbgl_obj.h:571
@ TIP_BOX_ID
Definition nbgl_obj.h:575
@ EXTRA_BUTTON_ID
Definition nbgl_obj.h:565
@ CHOICE_2_ID
Definition nbgl_obj.h:567
#define BUTTON_DIAMETER
Definition nbgl_obj.h:88
#define BOTTOM_BORDER_MARGIN
Definition nbgl_obj.h:72
#define SPINNER_HEIGHT
Definition nbgl_obj.h:98
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)
#define LEFT_ARROW_ICON
Definition nbgl_obj.h:144
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
API to manage screens.
int nbgl_screenSet(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t touchCallback)
Configures the lowest layer screen. To be used by applications A nbgl_screenRedraw() can be called af...
int nbgl_screenPush(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t touchCallback)
Pushes a screen on top of the stack, with the given number of elements, if possible....
void nbgl_wait_pipeline(void)
int nbgl_screenUpdateTicker(uint8_t screenIndex, const nbgl_screenTickerConfiguration_t *ticker)
Updates the ticker configuration of the screen at the given screenIndex, always set at WHITE in.
int nbgl_screenPop(uint8_t screenIndex)
Release the screen at the given index in screen array (index returned by nbgl_screenPush())....
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screenRedraw(void)
This function redraws the whole screen on top of stack and its children.
Definition nbgl_screen.c:66
uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj)
Definition nbgl_touch.c:379
color_t
Definition nbgl_types.h:104
@ WHITE
Definition nbgl_types.h:108
@ DARK_GRAY
Definition nbgl_types.h:106
@ LIGHT_GRAY
Definition nbgl_types.h:107
@ BLACK
Definition nbgl_types.h:105
nbgl_state_t
to represent a boolean state.
Definition nbgl_types.h:163
@ ON_STATE
Definition nbgl_types.h:165
@ OFF_STATE
Definition nbgl_types.h:164
@ POST_REFRESH_FORCE_POWER_OFF
Force screen power off after refresh.
Definition nbgl_types.h:317
@ POST_REFRESH_FORCE_POWER_ON_WITH_PIPELINE
Force screen power on and enable pipeline.
Definition nbgl_types.h:319
#define SCREEN_WIDTH
Definition nbgl_types.h:32
@ RADIUS_32_PIXELS
32 pixels
Definition nbgl_types.h:329
nbgl_touchType_t
The different types of Touchscreen events.
Definition nbgl_types.h:223
@ SWIPED_LEFT
Definition nbgl_types.h:239
@ SWIPED_UP
Definition nbgl_types.h:236
@ SWIPED_DOWN
Definition nbgl_types.h:237
@ SWIPED_RIGHT
Definition nbgl_types.h:238
@ TOUCH_RELEASED
Definition nbgl_types.h:233
@ TOUCHED
Definition nbgl_types.h:224
@ TOUCHING
corresponding to an object that is currently touched
Definition nbgl_types.h:228
@ OUT_OF_TOUCH
Definition nbgl_types.h:229
@ QRCODE_V10
QRCode V10, can encode text len up to 1500 chars, display size = 228*228.
Definition nbgl_types.h:195
@ QRCODE_V4_SMALL
QRCode V4, can encode text len up to 1500 chars, display size = 132*132.
Definition nbgl_types.h:196
@ QRCODE_V4
QRCode V4, can encode text len up to 62 chars, display size = 264*264.
Definition nbgl_types.h:194
@ VERTICAL
from top to bottom
Definition nbgl_types.h:173
@ HORIZONTAL
from left to right
Definition nbgl_types.h:174
#define SCREEN_HEIGHT
Definition nbgl_types.h:45
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
@ TOP_MIDDLE
Definition nbgl_types.h:146
@ CENTER
Definition nbgl_types.h:149
@ BOTTOM_RIGHT
Definition nbgl_types.h:153
@ TOP_LEFT
Definition nbgl_types.h:145
@ NO_ALIGNMENT
used when parent container layout is used
Definition nbgl_types.h:144
@ BOTTOM_LEFT
Definition nbgl_types.h:151
@ MID_RIGHT
Definition nbgl_types.h:150
@ RIGHT_TOP
on outside right
Definition nbgl_types.h:156
@ TOP_RIGHT
Definition nbgl_types.h:147
@ MID_LEFT
Definition nbgl_types.h:148
@ BOTTOM_MIDDLE
Definition nbgl_types.h:152
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:121
@ SWITCH
Switch to turn on/off something.
Definition nbgl_types.h:125
@ RADIO_BUTTON
Indicator to inform whether something is on or off.
Definition nbgl_types.h:128
@ SPINNER
Spinner.
Definition nbgl_types.h:132
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition nbgl_types.h:124
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
Definition nbgl_types.h:127
@ QR_CODE
QR Code.
Definition nbgl_types.h:129
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition nbgl_types.h:126
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:122
@ CONTAINER
Empty container.
Definition nbgl_types.h:120
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:123
#define MAX(x, y)
Definition nbgl_types.h:85
@ NBGL_BPP_1
1 bit per pixel
Definition nbgl_types.h:248
@ NO_STYLE
no border
Definition nbgl_types.h:182
@ BLACK_AND_WHITE_REFRESH
to be used for pure B&W area, when contrast is important
Definition nbgl_types.h:294
@ BLACK_AND_WHITE_FAST_REFRESH
to be used for pure B&W area, when contrast is not priority
Definition nbgl_types.h:295
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition nbgl_types.h:292
tune_index_e tuneId
nbgl_state_t state
const char * text
const nbgl_icon_details_t * iconRight
Definition nbgl_layout.c:98
const char * subText
listItemType_t type
Definition nbgl_layout.c:95
uint8_t token
const nbgl_icon_details_t * iconLeft
Definition nbgl_layout.c:96
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
bool padding
if true, apply a padding of 40px at the bottom
const char * smallTitle
sub-title in black small bold case (can be null)
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
int16_t offsetY
vertical shift to apply to this info (if >0, shift to bottom)
const char * text3
third text (can be null)
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...
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
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
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_icon_details_t * valueIcon
const char * value
string giving the value name
const char * item
string giving the tag name
const char * text
text of the tip-box
const nbgl_icon_details_t * icon
icon of the tip-box
uint8_t token
token used when tip-box is tapped
structure defining an ASCII font
Definition nbgl_fonts.h:80
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:85
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)
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
This structure contains info to build a single button.
const char * text
button text
uint8_t token
the token that will be used as argument of the callback
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon for button
nbgl_layoutButtonStyle_t style
bool fittingContent
if set to true, fit the width of button to text, otherwise full width
This structure contains info to build a pair of buttons, one on top of the other.
nbgl_layoutChoiceButtonsStyle_t style
the style of the pair
const nbgl_icon_details_t * topIcon
icon of top button
uint8_t token
the token that will be used as argument of the callback
const char * topText
up-button text (index 0)
const char * bottomText
bottom-button text (index 1)
Structure containing all information when creating a layout. This structure must be passed as argumen...
nbgl_screenTickerConfiguration_t ticker
const char * tapActionText
Light gray text used when main container is "tapable".
nbgl_layoutTouchCallback_t onActionCallback
the callback to be called on any action on the layout
This structure contains info to build an extended footer.
nbgl_layoutChoiceButtons_t choiceButtons
if type is FOOTER_CHOICE_BUTTONS
struct nbgl_layoutFooter_t::@19::@24 textAndNav
if type is FOOTER_TEXT_AND_NAV
bool separationLine
if true, a separation line is added at the top of this control
const char * leftText
struct nbgl_layoutFooter_t::@19::@22 simpleText
if type is FOOTER_SIMPLE_TEXT
nbgl_layoutButton_t button
if type is FOOTER_SIMPLE_BUTTON
struct nbgl_layoutFooter_t::@19::@23 doubleText
if type is FOOTER_DOUBLE_TEXT
bool mutedOut
if true, text is displayed in gray
struct nbgl_layoutFooter_t::@19::@21 emptySpace
if type is FOOTER_EMPTY
nbgl_layoutFooterType_t type
type of footer
nbgl_layoutNavigationBar_t navigation
if type is FOOTER_NAV
const char * rightText
const char * text
tune_index_e tuneId
This structure contains info to build a header.
nbgl_layoutHeaderType_t type
type of header
uint8_t backToken
when back key is pressed
struct nbgl_layoutHeader_t::@11::@16 title
if type is HEADER_TITLE
struct nbgl_layoutHeader_t::@11::@18 rightText
if type is HEADER_RIGHT_TEXT
const nbgl_icon_details_t * actionIcon
right button icon
uint8_t actionToken
when optional right button is pressed
bool separationLine
if true, a separation line is added at the bottom of this control
tune_index_e tuneId
when back key is pressed
const char * text
can be NULL if no text
struct nbgl_layoutHeader_t::@11::@13 emptySpace
if type is HEADER_EMPTY
struct nbgl_layoutHeader_t::@11::@17 extendedBack
if type is HEADER_EXTENDED_BACK
uint8_t textToken
when text is touched
struct nbgl_layoutHeader_t::@11::@14 backAndText
if type is HEADER_BACK_AND_TEXT
uint8_t token
when back key is pressed
struct nbgl_layoutHeader_t::@11::@15 progressAndBack
if type is HEADER_BACK_AND_PROGRESS
This structure contains info to build a pair of buttons, the small one, with icon,...
const nbgl_icon_details_t * leftIcon
a buffer containing the 1BPP icon for left button
uint8_t leftToken
the token used when left button is pressed
uint8_t rightToken
the token used when right button is pressed
const char * rightText
right-button text
Structure containing all information about the current layout.
nbgl_container_t * footerContainer
container used to store footer (buttons, nav....)
uint8_t activePage
index of active page for navigation bar
nbgl_swipe_usage_t swipeUsage
nbgl_layoutTouchCallback_t callback
nbgl_container_t * container
nbgl_container_t * headerContainer
container used to store header (progress, back, empty space...)
nbgl_layoutFooterType_t footerType
type of footer
bool modal
if true, means the screen is a modal
uint8_t nbChildren
number of children in above array
nbgl_layoutHeaderType_t headerType
type of header
nbgl_container_t * upFooterContainer
uint8_t nbPages
number of pages for navigation bar
nbgl_layoutUpFooterType_t upFooterType
type of up-footer
layoutObj_t callbackObjPool[LAYOUT_OBJ_POOL_LEN]
nbgl_text_area_t * tapText
nbgl_obj_t ** children
children for main screen
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).
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 to build a progress bar with info. The progress bar itself is 120px widt...
uint8_t percentage
percentage of completion, from 0 to 100.
const char * text
text in black, on top of progress bar
const char * subText
text in gray, under progress bar
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)
const char * url
URL for QR code.
bool largeText1
if set to true, use 32px font for text1
int16_t offsetY
vertical shift to apply to this info (if > 0, shift to bottom)
bool centered
if set to true, center vertically
This structure contains info to build an up-footer (area on top of footer).
nbgl_layoutButton_t button
if type is UP_FOOTER_BUTTON
tune_index_e tuneId
tune played when button is long-pressed
nbgl_contentTipBox_t tipBox
if type is UP_FOOTER_TIP_BOX
const char * text
text in the long-press button
nbgl_layoutUpFooterType_t type
type of up-footer
struct nbgl_layoutUpFooter_t::@25::@27 longPress
if type is UP_FOOTER_LONG_PRESS
uint8_t token
token used when button is long-pressed
nbgl_layoutHorizontalButtons_t horizontalButtons
if type is UP_FOOTER_HORIZONTAL_BUTTONS
signed short int16_t
Definition usbd_conf.h:50
unsigned short uint16_t
Definition usbd_conf.h:54
unsigned char uint8_t
Definition usbd_conf.h:53