Embedded SDK
Embedded SDK
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"
17 #include "nbgl_layout_internal.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 UP_FOOTER_BUTTON_HEIGHT 120
49 #define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
50 #define ACTION_AND_FOOTER_FOOTER_HEIGHT 216
51 #else // TARGET_STAX
52 #define RADIO_CHOICE_HEIGHT 92
53 #define FOOTER_HEIGHT 80
54 #define BAR_INTERVALE 16
55 #define BACK_KEY_WIDTH 104
56 #define FOOTER_BUTTON_HEIGHT 136
57 #define UP_FOOTER_BUTTON_HEIGHT 136
58 #define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
59 #define ACTION_AND_FOOTER_FOOTER_HEIGHT 232
60 #endif // TARGET_STAX
61 
62 // refresh period of the spinner, in ms
63 #define SPINNER_REFRESH_PERIOD 400
64 
65 #ifdef TARGET_STAX
66 #define FIRST_BUTTON_INDEX 0
67 #else // TARGET_STAX
68 // for suggestion buttons, on Flex there are other objects than buttons
69 enum {
71  LEFT_HALF_INDEX, // half disc displayed on the bottom left
72  RIGHT_HALF_INDEX, // half disc displayed on the bottom right
74 };
75 #endif // TARGET_STAX
76 
77 /**********************
78  * MACROS
79  **********************/
80 
81 /**********************
82  * TYPEDEFS
83  **********************/
84 
85 typedef enum {
90 
91 // used to build either a touchable bar or a switch
92 typedef struct {
94  const nbgl_icon_details_t *iconLeft; // a buffer containing the 1BPP icon for icon on
95  // left (can be NULL)
96  const nbgl_icon_details_t *iconRight; // a buffer containing the 1BPP icon for icon 2 (can be
97  // NULL). Dimensions must be the same as iconLeft
98  const char *text; // text (can be NULL)
99  const char *subText; // sub text (can be NULL)
100  uint8_t token; // the token that will be used as argument of the callback
101  nbgl_state_t state; // state of the item
102  bool large; // set to true only for the main level of OS settings
103 #ifdef HAVE_PIEZO_SOUND
104  tune_index_e tuneId; // if not @ref NBGL_NO_TUNE, a tune will be played
105 #endif // HAVE_PIEZO_SOUND
106 } listItem_t;
107 
108 /**********************
109  * VARIABLES
110  **********************/
111 
116 static nbgl_layoutInternal_t gLayout[NB_MAX_LAYOUTS] = {0};
117 
118 // numbers of touchable controls for the whole page
119 static uint8_t nbTouchableControls = 0;
120 
121 /**********************
122  * STATIC PROTOTYPES
123  **********************/
124 extern const char *get_ux_loc_string(uint32_t index);
125 
126 #ifdef HAVE_FAST_HOLD_TO_APPROVE
127 // Unit step in % of touchable progress bar
128 #define HOLD_TO_APPROVE_STEP_PERCENT (7)
129 // Duration in ms the user must hold the progress bar
130 // to make it progress HOLD_TO_APPROVE_STEP_PERCENT %.
131 // This duration must be higher than the screen refresh duration.
132 #define HOLD_TO_APPROVE_STEP_DURATION_MS (100)
133 #else
134 #define HOLD_TO_APPROVE_STEP_PERCENT (25)
135 #define HOLD_TO_APPROVE_STEP_DURATION_MS (400)
136 #endif // HAVE_FAST_HOLD_TO_APPROVE
137 
138 static inline uint8_t get_hold_to_approve_percent(uint32_t touch_duration)
139 {
140 #ifdef HAVE_FAST_HOLD_TO_APPROVE
141  uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS);
142 #else
143  uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS) + 1;
144 #endif
145  return (current_step_nb * HOLD_TO_APPROVE_STEP_PERCENT);
146 }
147 
148 // function used to retrieve the concerned layout and layout obj matching the given touched obj
149 static bool getLayoutAndLayoutObj(nbgl_obj_t *obj,
150  nbgl_layoutInternal_t **layout,
151  layoutObj_t **layoutObj)
152 {
154 
155  // parse all layouts (starting with modals) to find the object
156  *layout = NULL;
157  while (i > 0) {
158  i--;
159  if (gLayout[i].nbChildren > 0) {
160  uint8_t j;
161 
162  // search index of obj in this layout
163  for (j = 0; j < gLayout[i].nbUsedCallbackObjs; j++) {
164  if (obj == gLayout[i].callbackObjPool[j].obj) {
166  "getLayoutAndLayoutObj(): obj found in layout[%d], index = %d, "
167  "nbUsedCallbackObjs = %d\n",
168  i,
169  j,
170  gLayout[i].nbUsedCallbackObjs);
171  *layout = &gLayout[i];
172  *layoutObj = &(gLayout[i].callbackObjPool[j]);
173  return true;
174  }
175  }
176  }
177  }
178  // not found
179  return false;
180 }
181 
182 static void radioTouchCallback(nbgl_obj_t *obj,
183  nbgl_touchType_t eventType,
184  nbgl_layoutInternal_t *layout);
185 static void longTouchCallback(nbgl_obj_t *obj,
186  nbgl_touchType_t eventType,
187  nbgl_layoutInternal_t *layout,
188  layoutObj_t *layoutObj);
189 
190 // callback for most touched object
191 static void touchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
192 {
193  nbgl_layoutInternal_t *layout;
194  layoutObj_t *layoutObj;
195  bool needRefresh = false;
196 
197  if (obj == NULL) {
198  return;
199  }
200  LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): eventType = %d, obj = %p\n", eventType, obj);
201  if (getLayoutAndLayoutObj(obj, &layout, &layoutObj) == false) {
202  // try with parent, if existing
203  if (getLayoutAndLayoutObj(obj->parent, &layout, &layoutObj) == false) {
204  LOG_WARN(
206  "touchCallback(): eventType = %d, obj = %p, no active layout or obj not found\n",
207  eventType,
208  obj);
209  return;
210  }
211  }
212 
213  // case of swipe
214  if (((eventType == SWIPED_UP) || (eventType == SWIPED_DOWN) || (eventType == SWIPED_LEFT)
215  || (eventType == SWIPED_RIGHT))
216  && (obj->type == CONTAINER)) {
217 #ifdef NBGL_KEYBOARD
218  if (layout->swipeUsage == SWIPE_USAGE_SUGGESTIONS) {
219  keyboardSwipeCallback(obj, eventType);
220  return;
221  }
222 #endif // NBGL_KEYBOARD
223  if (layout->swipeUsage == SWIPE_USAGE_CUSTOM) {
224  layoutObj->index = eventType;
225  }
226  else if ((layout->swipeUsage == SWIPE_USAGE_NAVIGATION)
227  && ((nbgl_obj_t *) layout->container == obj)) {
228  nbgl_container_t *navContainer;
229  if (layout->footerType == FOOTER_NAV) {
230  navContainer = (nbgl_container_t *) layout->footerContainer;
231  }
232  else if (layout->footerType == FOOTER_TEXT_AND_NAV) {
233  navContainer = (nbgl_container_t *) layout->footerContainer->children[1];
234  }
235  else {
236  return;
237  }
238 
240  (nbgl_obj_t *) navContainer, eventType, layout->nbPages, &layout->activePage)
241  == false) {
242  // navigation was impossible
243  return;
244  }
245  layoutObj->index = layout->activePage;
246  }
247  }
248 
249  // case of navigation bar
250  if (((obj->parent == (nbgl_obj_t *) layout->footerContainer)
251  && (layout->footerType == FOOTER_NAV))
252  || ((obj->parent->type == CONTAINER)
253  && (obj->parent->parent == (nbgl_obj_t *) layout->footerContainer)
254  && (layout->footerType == FOOTER_TEXT_AND_NAV))) {
255  if (layoutNavigationCallback(obj, eventType, layout->nbPages, &layout->activePage)
256  == false) {
257  // navigation was impossible
258  return;
259  }
260  layoutObj->index = layout->activePage;
261  }
262 
263  // case of switch
264  if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren >= 2)
265  && (((nbgl_container_t *) obj)->children[1] != NULL)
266  && (((nbgl_container_t *) obj)->children[1]->type == SWITCH)) {
267  nbgl_switch_t *lSwitch = (nbgl_switch_t *) ((nbgl_container_t *) obj)->children[1];
268  lSwitch->state = (lSwitch->state == ON_STATE) ? OFF_STATE : ON_STATE;
269  nbgl_objDraw((nbgl_obj_t *) lSwitch);
270  // refresh will be done after tune playback
271  needRefresh = true;
272  // index is used for state
273  layoutObj->index = lSwitch->state;
274  }
275  // case of radio
276  else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 2)
277  && (((nbgl_container_t *) obj)->children[1] != NULL)
278  && (((nbgl_container_t *) obj)->children[1]->type == RADIO_BUTTON)) {
279  radioTouchCallback(obj, eventType, layout);
280  return;
281  }
282  // case of long press
283  else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 4)
284  && (((nbgl_container_t *) obj)->children[3] != NULL)
285  && (((nbgl_container_t *) obj)->children[3]->type == PROGRESS_BAR)) {
286  longTouchCallback(obj, eventType, layout, layoutObj);
287  return;
288  }
289  LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): layout->callback = %p\n", layout->callback);
290  if (layout->callback != NULL) {
291 #ifdef HAVE_PIEZO_SOUND
292  if (layoutObj->tuneId < NBGL_NO_TUNE) {
293  io_seproxyhal_play_tune(layoutObj->tuneId);
294  }
295 #endif // HAVE_PIEZO_SOUND
296  if (needRefresh) {
298  }
299  layout->callback(layoutObj->token, layoutObj->index);
300  }
301 }
302 
303 // callback for long press button
304 static void longTouchCallback(nbgl_obj_t *obj,
305  nbgl_touchType_t eventType,
306  nbgl_layoutInternal_t *layout,
307  layoutObj_t *layoutObj)
308 {
309  nbgl_container_t *container = (nbgl_container_t *) obj;
310  // 4th child of container is the progress bar
311  nbgl_progress_bar_t *progressBar = (nbgl_progress_bar_t *) container->children[3];
312 
314  "longTouchCallback(): eventType = %d, obj = %p, gLayout[1].nbChildren = %d\n",
315  eventType,
316  obj,
317  gLayout[1].nbChildren);
318 
319  // case of pressing a long press button
320  if (eventType == TOUCHING) {
321  uint32_t touchDuration = nbgl_touchGetTouchDuration(obj);
322 
323  // Compute the new progress bar state in %
324  uint8_t new_state = get_hold_to_approve_percent(touchDuration);
325 
326  // Ensure the callback is triggered once,
327  // when the progress bar state reaches 100%
328  bool trigger_callback = (new_state >= 100) && (progressBar->state < 100);
329 
330  // Cap progress bar state at 100%
331  if (new_state >= 100) {
332  new_state = 100;
333  }
334 
335  // Update progress bar state
336  if (new_state != progressBar->state) {
337  progressBar->partialRedraw = true;
338  progressBar->state = new_state;
339 
340  nbgl_objDraw((nbgl_obj_t *) progressBar);
341  // Ensure progress bar is fully drawn
342  // before calling the callback.
345  }
346 
347  if (trigger_callback) {
348  // End of progress bar reached: trigger callback
349  if (layout->callback != NULL) {
350  layout->callback(layoutObj->token, layoutObj->index);
351  }
352  }
353  }
354  // case of releasing a long press button (or getting out of it)
355  else if ((eventType == TOUCH_RELEASED) || (eventType == OUT_OF_TOUCH)
356  || (eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT)) {
358  progressBar->partialRedraw = true;
359  progressBar->state = 0;
360  nbgl_objDraw((nbgl_obj_t *) progressBar);
362  }
363 }
364 
365 // callback for radio button touch
366 static void radioTouchCallback(nbgl_obj_t *obj,
367  nbgl_touchType_t eventType,
368  nbgl_layoutInternal_t *layout)
369 {
370  uint8_t i = NB_MAX_LAYOUTS, radioIndex = 0, foundRadio = 0xFF, foundRadioIndex;
371 
372  if (eventType != TOUCHED) {
373  return;
374  }
375 
376  i = 0;
377  // parse all objs to find all containers of radio buttons
378  while (i < layout->nbUsedCallbackObjs) {
379  if ((obj == (nbgl_obj_t *) layout->callbackObjPool[i].obj)
380  && (layout->callbackObjPool[i].obj->type == CONTAINER)) {
381  nbgl_radio_t *radio
382  = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
383  ->children[1];
384  nbgl_text_area_t *textArea
386  ->children[0];
387  foundRadio = i;
388  foundRadioIndex = radioIndex;
389  // set text as active (black and bold)
390  textArea->textColor = BLACK;
391  textArea->fontId = SMALL_BOLD_FONT;
392  // ensure that radio button is ON
393  radio->state = ON_STATE;
394  // redraw container
395  nbgl_objDraw((nbgl_obj_t *) obj);
396  }
397  else if ((layout->callbackObjPool[i].obj->type == CONTAINER)
398  && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->nbChildren == 2)
399  && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->children[1]->type
400  == RADIO_BUTTON)) {
401  nbgl_radio_t *radio
402  = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
403  ->children[1];
404  nbgl_text_area_t *textArea
406  ->children[0];
407  radioIndex++;
408  // set to OFF the one that was in ON
409  if (radio->state == ON_STATE) {
410  radio->state = OFF_STATE;
411  // set text it as inactive (gray and normal)
412  textArea->textColor = DARK_GRAY;
413  textArea->fontId = SMALL_REGULAR_FONT;
414  // redraw container
415  nbgl_objDraw((nbgl_obj_t *) layout->callbackObjPool[i].obj);
416  }
417  }
418  i++;
419  }
420  // call callback after redraw to avoid asynchronicity
421  if (foundRadio != 0xFF) {
422  if (layout->callback != NULL) {
423 #ifdef HAVE_PIEZO_SOUND
424  if (layout->callbackObjPool[foundRadio].tuneId < NBGL_NO_TUNE) {
425  io_seproxyhal_play_tune(layout->callbackObjPool[foundRadio].tuneId);
426  }
428 #endif // HAVE_PIEZO_SOUND
429  layout->callback(layout->callbackObjPool[foundRadio].token, foundRadioIndex);
430  }
431  }
432 }
433 
434 // callback for spinner ticker
435 static void spinnerTickerCallback(void)
436 {
437  nbgl_spinner_t *spinner;
438  uint8_t i = 0;
439  nbgl_layoutInternal_t *layout;
440 
441  // gLayout[1] is on top of gLayout[0] so if gLayout[1] is active, it must catch the event
442  if (gLayout[1].nbChildren > 0) {
443  layout = &gLayout[1];
444  }
445  else {
446  layout = &gLayout[0];
447  }
448 
449  // get index of obj
450  while (i < layout->container->nbChildren) {
451  if (layout->container->children[i]->type == SPINNER) {
452  spinner = (nbgl_spinner_t *) layout->container->children[i];
453  spinner->position++;
454  spinner->position &= 3; // modulo 4
455  nbgl_objDraw((nbgl_obj_t *) spinner);
457  return;
458  }
459  i++;
460  }
461 }
462 
463 static nbgl_line_t *createHorizontalLine(uint8_t layer)
464 {
465  nbgl_line_t *line;
466 
467  line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
468  line->lineColor = LIGHT_GRAY;
469  line->obj.area.width = SCREEN_WIDTH;
470  line->obj.area.height = 4;
471  line->direction = HORIZONTAL;
472  line->thickness = 1;
473  return line;
474 }
475 
476 static nbgl_line_t *createLeftVerticalLine(uint8_t layer)
477 {
478  nbgl_line_t *line;
479 
480  line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
481  line->lineColor = LIGHT_GRAY;
482  line->obj.area.width = 1;
483  line->obj.area.height = SCREEN_HEIGHT;
484  line->direction = VERTICAL;
485  line->thickness = 1;
486  line->obj.alignment = MID_LEFT;
487  return line;
488 }
489 
490 // function adding a layout object in the callbackObjPool array for the given layout, and
491 // configuring it
493  nbgl_obj_t *obj,
494  uint8_t token,
495  tune_index_e tuneId)
496 {
497  layoutObj_t *layoutObj = NULL;
498 
499  if (layout->nbUsedCallbackObjs < (LAYOUT_OBJ_POOL_LEN - 1)) {
500  layoutObj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
501  layout->nbUsedCallbackObjs++;
502  layoutObj->obj = obj;
503  layoutObj->token = token;
504  layoutObj->tuneId = tuneId;
505  }
506  else {
507  LOG_FATAL(LAYOUT_LOGGER, "layoutAddCallbackObj: no more callback obj\n");
508  }
509 
510  return layoutObj;
511 }
512 
520 {
521  if (layout->container->nbChildren == NB_MAX_CONTAINER_CHILDREN) {
522  LOG_FATAL(LAYOUT_LOGGER, "layoutAddObject(): No more object\n");
523  }
524  layout->container->children[layout->container->nbChildren] = obj;
525  layout->container->nbChildren++;
526 }
527 
537 static int addSwipeInternal(nbgl_layoutInternal_t *layoutInt,
538  uint16_t swipesMask,
539  nbgl_swipe_usage_t usage,
540  uint8_t token,
541  tune_index_e tuneId)
542 {
543  layoutObj_t *obj;
544 
545  if ((swipesMask & SWIPE_MASK) == 0) {
546  return -1;
547  }
548 
549  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, token, tuneId);
550  if (obj == NULL) {
551  return -1;
552  }
553  layoutInt->container->obj.touchMask = swipesMask;
554  layoutInt->swipeUsage = usage;
555 
556  return 0;
557 }
558 
566 static nbgl_container_t *addListItem(nbgl_layoutInternal_t *layoutInt, const listItem_t *itemDesc)
567 {
568  layoutObj_t *obj;
569  nbgl_text_area_t *textArea;
570  nbgl_container_t *container;
571  color_t color = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == OFF_STATE))
572  ? LIGHT_GRAY
573  : BLACK;
574  int16_t usedHeight = 40;
575 
576  LOG_DEBUG(LAYOUT_LOGGER, "addListItem():\n");
577 
578  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
579  obj = layoutAddCallbackObj(
580  layoutInt, (nbgl_obj_t *) container, itemDesc->token, itemDesc->tuneId);
581  if (obj == NULL) {
582  return NULL;
583  }
584 
585  // get container children (up to 4: text + left+right icons + sub text)
586  container->children = nbgl_containerPoolGet(4, layoutInt->layer);
587  container->nbChildren = 0;
588 
589  container->obj.area.width = AVAILABLE_WIDTH;
590  container->obj.area.height = itemDesc->large ? TOUCHABLE_MAIN_BAR_HEIGHT : TOUCHABLE_BAR_HEIGHT;
591  container->layout = HORIZONTAL;
592  container->obj.alignmentMarginX = BORDER_MARGIN;
593  container->obj.alignment = NO_ALIGNMENT;
594  container->obj.alignTo = NULL;
595  // the bar can only be touched if not inactive AND if one of the icon is present
596  // otherwise it is seen as a title
597  if (((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == ON_STATE))
598  || (itemDesc->type == SWITCH_ITEM)) {
599  container->obj.touchMask = (1 << TOUCHED);
600  container->obj.touchId = CONTROLS_ID + nbTouchableControls;
601  nbTouchableControls++;
602  }
603 
604  // allocate main text because always present
605  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
606  textArea->textColor = color;
607  textArea->text = PIC(itemDesc->text);
608  textArea->onDrawCallback = NULL;
609  textArea->fontId = SMALL_BOLD_FONT;
610  textArea->wrapping = true;
611  textArea->obj.area.width = container->obj.area.width;
612  if (itemDesc->iconLeft != NULL) {
613  // reduce text width accordingly
614  textArea->obj.area.width
615  -= ((nbgl_icon_details_t *) PIC(itemDesc->iconLeft))->width + BAR_INTERVALE;
616  }
617  if (itemDesc->iconRight != NULL) {
618  // reduce text width accordingly
619  textArea->obj.area.width
620  -= ((nbgl_icon_details_t *) PIC(itemDesc->iconRight))->width + BAR_INTERVALE;
621  }
622  else if (itemDesc->type == SWITCH_ITEM) {
623  textArea->obj.area.width -= 60 + BAR_INTERVALE;
624  }
625  textArea->obj.area.height = nbgl_getTextHeightInWidth(
626  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
627  usedHeight = MAX(usedHeight, textArea->obj.area.height);
628  textArea->style = NO_STYLE;
629  textArea->obj.alignment = MID_LEFT;
630  textArea->textAlignment = MID_LEFT;
631  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
632  container->nbChildren++;
633 
634  // allocate left icon if present
635  if (itemDesc->iconLeft != NULL) {
636  nbgl_image_t *imageLeft = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
637  imageLeft->foregroundColor = color;
638  imageLeft->buffer = PIC(itemDesc->iconLeft);
639  // align at the left of text
640  imageLeft->obj.alignment = MID_LEFT;
641  imageLeft->obj.alignTo = (nbgl_obj_t *) textArea;
642  imageLeft->obj.alignmentMarginX = BAR_INTERVALE;
643  container->children[container->nbChildren] = (nbgl_obj_t *) imageLeft;
644  container->nbChildren++;
645 
646  textArea->obj.alignmentMarginX = imageLeft->buffer->width + BAR_INTERVALE;
647 
648  usedHeight = MAX(usedHeight, imageLeft->buffer->height);
649  }
650  // allocate right icon if present
651  if (itemDesc->iconRight != NULL) {
652  nbgl_image_t *imageRight = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
653  imageRight->foregroundColor = color;
654  imageRight->buffer = PIC(itemDesc->iconRight);
655  // align at the right of text
656  imageRight->obj.alignment = MID_RIGHT;
657  imageRight->obj.alignmentMarginX = BAR_INTERVALE;
658  imageRight->obj.alignTo = (nbgl_obj_t *) textArea;
659 
660  container->children[container->nbChildren] = (nbgl_obj_t *) imageRight;
661  container->nbChildren++;
662 
663  usedHeight = MAX(usedHeight, imageRight->buffer->height);
664  }
665  else if (itemDesc->type == SWITCH_ITEM) {
666  nbgl_switch_t *switchObj = (nbgl_switch_t *) nbgl_objPoolGet(SWITCH, layoutInt->layer);
667  switchObj->onColor = BLACK;
668  switchObj->offColor = LIGHT_GRAY;
669  switchObj->state = itemDesc->state;
670  switchObj->obj.alignment = MID_RIGHT;
671  switchObj->obj.alignmentMarginX = BAR_INTERVALE;
672  switchObj->obj.alignTo = (nbgl_obj_t *) textArea;
673 
674  container->children[container->nbChildren] = (nbgl_obj_t *) switchObj;
675  container->nbChildren++;
676  }
677 
678  if (itemDesc->subText != NULL) {
679  nbgl_text_area_t *subTextArea
680  = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
681 
682  subTextArea->textColor = color;
683  subTextArea->text = PIC(itemDesc->subText);
684  subTextArea->textAlignment = MID_LEFT;
685  subTextArea->fontId = SMALL_REGULAR_FONT;
686  subTextArea->style = NO_STYLE;
687  subTextArea->wrapping = true;
688  subTextArea->obj.alignment = MID_LEFT;
689  subTextArea->obj.area.width = container->obj.area.width;
690  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
691  subTextArea->text,
692  subTextArea->obj.area.width,
693  subTextArea->wrapping);
694  container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
695  container->nbChildren++;
696  container->obj.area.height += subTextArea->obj.area.height + 12;
697 
698  // modify alignments to have sub-text under (icon left - text - icon right)
699  textArea->obj.alignmentMarginY = -(subTextArea->obj.area.height + 12) / 2;
700  subTextArea->obj.alignmentMarginY = (usedHeight + 12) / 2;
701  }
702 
703  // set this new container as child of main container
704  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
705 
706  return container;
707 }
708 
717 static nbgl_container_t *addContentCenter(nbgl_layoutInternal_t *layoutInt,
718  const nbgl_contentCenter_t *info)
719 {
720  nbgl_container_t *container;
721  nbgl_text_area_t *textArea = NULL;
722  nbgl_image_t *image = NULL;
723  uint16_t fullHeight = 0;
724 
725  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
726 
727  // get container children
728  container->nbChildren = 0;
729  container->children = nbgl_containerPoolGet(5, layoutInt->layer);
730 
731  // add icon if present
732  if (info->icon != NULL) {
733  image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
734  image->foregroundColor = BLACK;
735  image->buffer = PIC(info->icon);
736  image->obj.alignment = TOP_MIDDLE;
737  image->obj.alignmentMarginY = info->iconHug;
738 
739  fullHeight += image->buffer->height + info->iconHug;
740  container->children[container->nbChildren] = (nbgl_obj_t *) image;
741  container->nbChildren++;
742  }
743  // add title if present
744  if (info->title != NULL) {
745  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
746  textArea->textColor = BLACK;
747  textArea->text = PIC(info->title);
748  textArea->textAlignment = CENTER;
749  textArea->fontId = LARGE_MEDIUM_FONT;
750  textArea->wrapping = true;
751  textArea->obj.area.width = AVAILABLE_WIDTH;
752  textArea->obj.area.height = nbgl_getTextHeightInWidth(
753  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
754 
755  // if not the first child, put on bottom of the previous, with a margin
756  if (container->nbChildren > 0) {
757  textArea->obj.alignment = BOTTOM_MIDDLE;
758  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
759  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
760  }
761  else {
762  textArea->obj.alignment = TOP_MIDDLE;
763  }
764 
765  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
766 
767  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
768  container->nbChildren++;
769  }
770  // add small title if present
771  if (info->smallTitle != NULL) {
772  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
773  textArea->textColor = BLACK;
774  textArea->text = PIC(info->smallTitle);
775  textArea->textAlignment = CENTER;
776  textArea->fontId = SMALL_BOLD_FONT;
777  textArea->wrapping = true;
778  textArea->obj.area.width = AVAILABLE_WIDTH;
779  textArea->obj.area.height = nbgl_getTextHeightInWidth(
780  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
781 
782  // if not the first child, put on bottom of the previous, with a margin
783  if (container->nbChildren > 0) {
784  textArea->obj.alignment = BOTTOM_MIDDLE;
785  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
786  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN;
787  if (container->children[container->nbChildren - 1]->type == IMAGE) {
788  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
789  }
790  else {
791  textArea->obj.alignmentMarginY = 16;
792  }
793  }
794  else {
795  textArea->obj.alignment = TOP_MIDDLE;
796  }
797 
798  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
799 
800  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
801  container->nbChildren++;
802  }
803  // add description if present
804  if (info->description != NULL) {
805  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
806  textArea->textColor = BLACK;
807  textArea->text = PIC(info->description);
808  textArea->textAlignment = CENTER;
809  textArea->fontId = SMALL_REGULAR_FONT;
810  textArea->wrapping = true;
811  textArea->obj.area.width = AVAILABLE_WIDTH;
812  textArea->obj.area.height = nbgl_getTextHeightInWidth(
813  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
814 
815  // if not the first child, put on bottom of the previous, with a margin
816  if (container->nbChildren > 0) {
817  textArea->obj.alignment = BOTTOM_MIDDLE;
818  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
819  if (container->children[container->nbChildren - 1]->type == TEXT_AREA) {
820  // if previous element is text, only space of 16 px
821  textArea->obj.alignmentMarginY = 16;
822  }
823  else {
824  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
825  }
826  }
827  else {
828  textArea->obj.alignment = TOP_MIDDLE;
829  }
830 
831  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
832 
833  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
834  container->nbChildren++;
835  }
836  // add sub-text if present
837  if (info->subText != NULL) {
838  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
839  textArea->textColor = DARK_GRAY;
840  textArea->text = PIC(info->subText);
841  textArea->textAlignment = CENTER;
842  textArea->fontId = SMALL_REGULAR_FONT;
843  textArea->wrapping = true;
844  textArea->obj.area.width = AVAILABLE_WIDTH;
845  textArea->obj.area.height = nbgl_getTextHeightInWidth(
846  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
847  // sub-text is included in a hug of 8px
848  textArea->obj.area.height += 2 * 8;
849  // if not the first child, put on bottom of the previous, with a margin
850  if (container->nbChildren > 0) {
851  textArea->obj.alignment = BOTTOM_MIDDLE;
852  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
853  textArea->obj.alignmentMarginY = 16;
854  if (container->children[container->nbChildren - 1]->type == IMAGE) {
855  textArea->obj.alignmentMarginY += info->iconHug;
856  }
857  }
858  else {
859  textArea->obj.alignment = TOP_MIDDLE;
860  }
861 
862  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
863 
864  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
865  container->nbChildren++;
866  }
867  container->layout = VERTICAL;
868  container->obj.alignment = CENTER;
869  container->obj.area.width = AVAILABLE_WIDTH;
870  container->obj.area.height = fullHeight;
871  if (info->padding) {
872  container->obj.area.height += 40;
873  }
874 
875  // set this new container as child of main container
876  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
877 
878  return container;
879 }
880 
881 static int addText(nbgl_layout_t *layout,
882  const char *text,
883  const char *subText,
884  uint8_t token,
885  uint8_t index,
886  bool withAlias)
887 {
888  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
889  nbgl_container_t *container;
890  nbgl_text_area_t *textArea;
891  nbgl_text_area_t *subTextArea;
892  uint16_t fullHeight = 0;
893 
894  if (layout == NULL) {
895  return -1;
896  }
897  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
898 
899  // get container children
900  container->children = nbgl_containerPoolGet(withAlias ? 3 : 2, layoutInt->layer);
901  container->obj.area.width = AVAILABLE_WIDTH;
902 
903  if (text != NULL) {
904  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
905 
906  textArea->textColor = BLACK;
907  textArea->text = PIC(text);
908  textArea->textAlignment = MID_LEFT;
909  textArea->fontId = SMALL_BOLD_FONT;
910  textArea->style = NO_STYLE;
911  textArea->wrapping = true;
912  textArea->obj.alignment = NO_ALIGNMENT;
913  textArea->obj.alignmentMarginY = PRE_TEXT_MARGIN;
914  textArea->obj.area.width = container->obj.area.width;
915  if (withAlias == true) {
916  textArea->obj.area.width -= 12 + MINI_PUSH_ICON.width;
917  }
918  textArea->obj.area.height = nbgl_getTextHeightInWidth(
919  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
920  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
921  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
922  container->nbChildren++;
923  if (withAlias == true) {
924  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
925  // the whole container is touchable
926  layoutObj_t *obj
927  = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) container, token, TUNE_TAP_CASUAL);
928  obj->index = index;
929  image->foregroundColor = BLACK;
930  image->buffer = &PUSH_ICON;
931  image->obj.alignment = RIGHT_TOP;
932  image->obj.alignmentMarginX = 12;
933  image->obj.alignTo = (nbgl_obj_t *) textArea;
934  container->obj.touchMask = (1 << TOUCHED);
935  container->obj.touchId = VALUE_BUTTON_1_ID + index;
936 
937  container->children[container->nbChildren] = (nbgl_obj_t *) image;
938  container->nbChildren++;
939  }
940  }
941  if (subText != NULL) {
942  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
943  subTextArea->textColor = BLACK;
944  subTextArea->text = PIC(subText);
945  subTextArea->fontId = SMALL_REGULAR_FONT;
946  subTextArea->style = NO_STYLE;
947  subTextArea->wrapping = true;
948  subTextArea->obj.area.width = container->obj.area.width;
949  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
950  subTextArea->text,
951  subTextArea->obj.area.width,
952  subTextArea->wrapping);
953  subTextArea->textAlignment = MID_LEFT;
954  subTextArea->obj.alignment = NO_ALIGNMENT;
955  if (text != NULL) {
956  subTextArea->obj.alignmentMarginY = TEXT_SUBTEXT_MARGIN;
957  fullHeight += POST_SUBTEXT_MARGIN; // under the subText
958  }
959  else {
960 #ifdef TARGET_STAX
961  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
962  fullHeight += BORDER_MARGIN;
963 #else // TARGET_STAX
964  subTextArea->obj.alignmentMarginY = 26;
965  fullHeight += 26; // under the subText
966 #endif // TARGET_STAX
967  }
968  container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
969  container->nbChildren++;
970  fullHeight += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
971  }
972  else {
973  fullHeight += PRE_TEXT_MARGIN;
974  }
975  container->obj.area.height = fullHeight;
976  container->layout = VERTICAL;
977  container->obj.alignmentMarginX = BORDER_MARGIN;
978  container->obj.alignment = NO_ALIGNMENT;
979  // set this new obj as child of main container
980  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
981 
982  return container->obj.area.height;
983 }
984 
985 /**********************
986  * GLOBAL FUNCTIONS
987  **********************/
988 
996 {
997  nbgl_layoutInternal_t *layout = NULL;
998 
999  // find an empty layout in the proper "layer"
1000  if (description->modal) {
1001  if (gLayout[1].nbChildren == 0) {
1002  layout = &gLayout[1];
1003  }
1004  else if (gLayout[2].nbChildren == 0) {
1005  layout = &gLayout[2];
1006  }
1007  }
1008  else {
1009  // automatically "release" a potentially opened non-modal layout
1010  gLayout[0].nbChildren = 0;
1011  layout = &gLayout[0];
1012  }
1013  if (layout == NULL) {
1014  LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutGet(): impossible to get a layout!\n");
1015  return NULL;
1016  }
1017 
1018  // reset globals
1019  memset(layout, 0, sizeof(nbgl_layoutInternal_t));
1020 
1021  nbTouchableControls = 0;
1022 
1023  layout->callback = (nbgl_layoutTouchCallback_t) PIC(description->onActionCallback);
1024  layout->modal = description->modal;
1025  layout->withLeftBorder = description->withLeftBorder;
1026  if (description->modal) {
1027  layout->layer = nbgl_screenPush(&layout->children,
1029  &description->ticker,
1030  (nbgl_touchCallback_t) touchCallback);
1031  }
1032  else {
1033  nbgl_screenSet(&layout->children,
1035  &description->ticker,
1036  (nbgl_touchCallback_t) touchCallback);
1037  layout->layer = 0;
1038  }
1039  layout->container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layout->layer);
1040  layout->container->obj.area.width = SCREEN_WIDTH;
1041  layout->container->obj.area.height = SCREEN_HEIGHT;
1042  layout->container->layout = VERTICAL;
1043  layout->container->children = nbgl_containerPoolGet(NB_MAX_CONTAINER_CHILDREN, layout->layer);
1044  // by default, if no header, main container is aligned on top-left
1045  layout->container->obj.alignment = TOP_LEFT;
1046  // main container is always the second object, leaving space for header
1047  layout->children[MAIN_CONTAINER_INDEX] = (nbgl_obj_t *) layout->container;
1049 
1050  // if a tap text is defined, make the container tapable and display this text in gray
1051  if (description->tapActionText != NULL) {
1052  layoutObj_t *obj;
1053 
1054  obj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
1055  layout->nbUsedCallbackObjs++;
1056  obj->obj = (nbgl_obj_t *) layout->container;
1057  obj->token = description->tapActionToken;
1058  obj->tuneId = description->tapTuneId;
1059  layout->container->obj.touchMask = (1 << TOUCHED);
1060  layout->container->obj.touchId = WHOLE_SCREEN_ID;
1061 
1062  nbgl_layoutUpFooter_t footerDesc;
1063  footerDesc.type = UP_FOOTER_TEXT;
1064  footerDesc.text.text = PIC(description->tapActionText);
1065  footerDesc.text.token = description->tapActionToken;
1066  footerDesc.text.tuneId = description->tapTuneId;
1067  nbgl_layoutAddUpFooter((nbgl_layout_t *) layout, &footerDesc);
1068  }
1069 
1070  return (nbgl_layout_t *) layout;
1071 }
1072 
1085  uint16_t swipesMask,
1086  const char *text,
1087  uint8_t token,
1088  tune_index_e tuneId)
1089 {
1090  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1091 
1092  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwipe():\n");
1093  if (layout == NULL) {
1094  return -1;
1095  }
1096 
1097  if (text) {
1098  // create 'tap to continue' text area
1099  layoutInt->tapText = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0);
1100  layoutInt->tapText->text = PIC(text);
1101  layoutInt->tapText->textColor = DARK_GRAY;
1102  layoutInt->tapText->fontId = SMALL_REGULAR_FONT;
1103  layoutInt->tapText->obj.area.width = AVAILABLE_WIDTH;
1104  layoutInt->tapText->obj.area.height = nbgl_getFontLineHeight(layoutInt->tapText->fontId);
1105  layoutInt->tapText->textAlignment = CENTER;
1106 #ifdef TARGET_STAX
1107  layoutInt->tapText->obj.alignmentMarginY = BORDER_MARGIN;
1108 #else // TARGET_STAX
1109  layoutInt->tapText->obj.alignmentMarginY = 30;
1110 #endif // TARGET_STAX
1111  layoutInt->tapText->obj.alignment = BOTTOM_MIDDLE;
1112  }
1113  return addSwipeInternal(layoutInt, swipesMask, SWIPE_USAGE_CUSTOM, token, tuneId);
1114 }
1115 
1126  const nbgl_icon_details_t *icon,
1127  uint8_t token,
1128  tune_index_e tuneId)
1129 {
1130  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1131  layoutObj_t *obj;
1132  nbgl_button_t *button;
1133 
1134  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTopRightButton():\n");
1135  if (layout == NULL) {
1136  return -1;
1137  }
1138  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
1139  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
1140  if (obj == NULL) {
1141  return -1;
1142  }
1143 
1144  button->obj.area.width = BUTTON_DIAMETER;
1145  button->obj.area.height = BUTTON_DIAMETER;
1146  button->radius = BUTTON_RADIUS;
1147  button->obj.alignmentMarginX = BORDER_MARGIN;
1148  button->obj.alignmentMarginY = BORDER_MARGIN;
1149  button->foregroundColor = BLACK;
1150  button->innerColor = WHITE;
1151  button->borderColor = LIGHT_GRAY;
1152  button->obj.touchMask = (1 << TOUCHED);
1153  button->obj.touchId = TOP_RIGHT_BUTTON_ID;
1154  button->icon = PIC(icon);
1155  button->obj.alignment = TOP_RIGHT;
1156 
1157  // add to screen
1158  layoutInt->children[TOP_RIGHT_BUTTON_INDEX] = (nbgl_obj_t *) button;
1159 
1160  return 0;
1161 }
1162 
1171 {
1172  nbgl_layoutFooter_t footerDesc;
1173  footerDesc.type = FOOTER_NAV;
1174  footerDesc.separationLine = info->withSeparationLine;
1175  footerDesc.navigation.activePage = info->activePage;
1176  footerDesc.navigation.nbPages = info->nbPages;
1177  footerDesc.navigation.withExitKey = info->withExitKey;
1178  footerDesc.navigation.withBackKey = info->withBackKey;
1179  footerDesc.navigation.withPageIndicator = false;
1180  footerDesc.navigation.token = info->token;
1181  footerDesc.navigation.tuneId = info->tuneId;
1182  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1183 }
1184 
1197  const nbgl_icon_details_t *icon,
1198  uint8_t token,
1199  bool separationLine,
1200  tune_index_e tuneId)
1201 {
1202  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddBottomButton():\n");
1203  nbgl_layoutFooter_t footerDesc;
1204  footerDesc.type = FOOTER_SIMPLE_BUTTON;
1205  footerDesc.separationLine = separationLine;
1206  footerDesc.button.fittingContent = false;
1207  footerDesc.button.icon = PIC(icon);
1208  footerDesc.button.text = NULL;
1209  footerDesc.button.token = token;
1210  footerDesc.button.tuneId = tuneId;
1211  footerDesc.button.style = WHITE_BACKGROUND;
1212  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1213 }
1214 
1223 {
1224  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1225  nbgl_container_t *container;
1226  listItem_t itemDesc;
1227 
1228  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar():\n");
1229  if (layout == NULL) {
1230  return -1;
1231  }
1232  // main text is mandatory
1233  if (barLayout->text == NULL) {
1234  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar(): main text is mandatory\n");
1235  }
1236 
1237  itemDesc.iconLeft = barLayout->iconLeft;
1238  itemDesc.iconRight = barLayout->iconRight;
1239  itemDesc.text = barLayout->text;
1240  itemDesc.subText = barLayout->subText;
1241  itemDesc.token = barLayout->token;
1242  itemDesc.tuneId = barLayout->tuneId;
1243  itemDesc.state = (barLayout->inactive) ? OFF_STATE : ON_STATE;
1244  itemDesc.large = barLayout->large;
1245  itemDesc.type = TOUCHABLE_BAR_ITEM;
1246  container = addListItem(layoutInt, &itemDesc);
1247 
1248  if (container == NULL) {
1249  return -1;
1250  }
1251  return container->obj.area.height;
1252 }
1253 
1261 int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
1262 {
1263  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1264  nbgl_container_t *container;
1265  listItem_t itemDesc;
1266 
1267  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwitch():\n");
1268  if (layout == NULL) {
1269  return -1;
1270  }
1271  // main text is mandatory
1272  if (switchLayout->text == NULL) {
1273  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddSwitch(): main text is mandatory\n");
1274  }
1275 
1276  itemDesc.iconLeft = NULL;
1277  itemDesc.iconRight = NULL;
1278  itemDesc.text = switchLayout->text;
1279  itemDesc.subText = switchLayout->subText;
1280  itemDesc.token = switchLayout->token;
1281  itemDesc.tuneId = switchLayout->tuneId;
1282  itemDesc.state = switchLayout->initState;
1283  itemDesc.large = false;
1284  itemDesc.type = SWITCH_ITEM;
1285  container = addListItem(layoutInt, &itemDesc);
1286 
1287  if (container == NULL) {
1288  return -1;
1289  }
1290  return container->obj.area.height;
1291 }
1292 
1301 int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
1302 {
1303  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddText():\n");
1304  return addText(layout, text, subText, 0, 0, false);
1305 }
1306 
1319  const char *text,
1320  const char *subText,
1321  uint8_t token,
1322  uint8_t index)
1323 {
1324  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextWithAlias():\n");
1325  return addText(layout, text, subText, token, index, true);
1326 }
1327 
1335 int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
1336 {
1337  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1338  nbgl_text_area_t *textArea;
1339 
1340  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSubHeaderText():\n");
1341  if (layout == NULL) {
1342  return -1;
1343  }
1344  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1345 
1346  textArea->textColor = BLACK;
1347  textArea->text = PIC(text);
1348  textArea->textAlignment = MID_LEFT;
1349  textArea->fontId = SMALL_REGULAR_FONT;
1350  textArea->style = NO_STYLE;
1351  textArea->wrapping = true;
1352  textArea->obj.alignment = NO_ALIGNMENT;
1353  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1354  textArea->obj.area.width = AVAILABLE_WIDTH;
1355  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1356  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1357 #ifdef TARGET_STAX
1358  textArea->obj.area.height += 2 * 24;
1359 #else // TARGET_STAX
1360  textArea->obj.area.height += 2 * 28;
1361 #endif // TARGET_STAX
1362 
1363  // set this new obj as child of main container
1364  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1365 
1366  return textArea->obj.area.height;
1367 }
1368 
1377 int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text, bool grayedOut)
1378 {
1379  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1380  nbgl_text_area_t *textArea;
1381 
1382  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLargeCaseText():\n");
1383  if (layout == NULL) {
1384  return -1;
1385  }
1386  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1387 
1388  textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK;
1389  textArea->text = PIC(text);
1390  textArea->textAlignment = MID_LEFT;
1391  textArea->fontId = LARGE_MEDIUM_FONT;
1392  textArea->obj.area.width = AVAILABLE_WIDTH;
1393  textArea->wrapping = true;
1394  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1395  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1396  textArea->style = NO_STYLE;
1397  textArea->obj.alignment = NO_ALIGNMENT;
1398  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1399  if (layoutInt->container->nbChildren == 0) {
1400 #ifdef TARGET_STAX
1401  // if first object of container, increase the margin from top
1402  textArea->obj.alignmentMarginY += BORDER_MARGIN;
1403 #endif // TARGET_STAX
1404  }
1405  else {
1406 #ifdef TARGET_STAX
1407  textArea->obj.alignmentMarginY = 40; // 40px between paragraphs
1408 #else // TARGET_STAX
1409  textArea->obj.alignmentMarginY = 24; // 24px between paragraphs
1410 #endif // TARGET_STAX
1411  }
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 
1533  obj = layoutAddCallbackObj(
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 = 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 = info->rowTexts[row];
1748  textArea->textAlignment = MID_LEFT;
1749  textArea->fontId = SMALL_REGULAR_FONT;
1750  textArea->wrapping = true;
1751  textArea->obj.alignmentMarginX = 16;
1752  textArea->obj.area.width
1753  = AVAILABLE_WIDTH - image->buffer->width - textArea->obj.alignmentMarginX;
1754  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1755  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1756  textArea->obj.alignment = RIGHT_TOP;
1757  textArea->obj.alignTo = (nbgl_obj_t *) image;
1758  rowContainer->children[1] = (nbgl_obj_t *) textArea;
1759  rowContainer->obj.area.height = MAX(image->buffer->height, textArea->obj.area.height);
1760 
1761  if (row == 0) {
1762  rowContainer->obj.alignmentMarginY = 32;
1763  }
1764  else {
1765 #ifdef TARGET_STAX
1766  rowContainer->obj.alignmentMarginY = 16;
1767 #else // TARGET_STAX
1768  rowContainer->obj.alignmentMarginY = 26;
1769 #endif // TARGET_STAX
1770  }
1771  container->children[1 + row] = (nbgl_obj_t *) rowContainer;
1772  container->obj.area.height
1773  += rowContainer->obj.area.height + rowContainer->obj.alignmentMarginY;
1774  }
1775  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1776 
1777  return container->obj.area.height;
1778 }
1779 
1780 #ifdef NBGL_QRCODE
1790 {
1791  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1792  nbgl_container_t *container;
1793  nbgl_text_area_t *textArea = NULL;
1795  uint16_t fullHeight = 0;
1796 
1797  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddQRCode():\n");
1798  if (layout == NULL) {
1799  return -1;
1800  }
1801 
1802  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1803 
1804  // get container children (max 2 (QRCode + text1 + text2))
1805  container->children = nbgl_containerPoolGet(3, layoutInt->layer);
1806  container->nbChildren = 0;
1807 
1808  qrcode = (nbgl_qrcode_t *) nbgl_objPoolGet(QR_CODE, layoutInt->layer);
1809  // version is forced to V10 if url is longer than 62 characters
1810  if (strlen(PIC(info->url)) > 62) {
1811  qrcode->version = QRCODE_V10;
1812  }
1813  else {
1814  qrcode->version = QRCODE_V4;
1815  }
1816  qrcode->foregroundColor = BLACK;
1817  // in QR V4, we use 8*8 screen pixels for one QR pixel
1818  // in QR V10, we use 4*4 screen pixels for one QR pixel
1819  qrcode->obj.area.width
1820  = (qrcode->version == QRCODE_V4) ? (QR_V4_NB_PIX_SIZE * 8) : (QR_V10_NB_PIX_SIZE * 4);
1821  qrcode->obj.area.height = qrcode->obj.area.width;
1822  qrcode->text = PIC(info->url);
1823  qrcode->obj.area.bpp = NBGL_BPP_1;
1824  qrcode->obj.alignment = TOP_MIDDLE;
1825 
1826  fullHeight += qrcode->obj.area.height;
1827  container->children[container->nbChildren] = (nbgl_obj_t *) qrcode;
1828  container->nbChildren++;
1829 
1830  if (info->text1 != NULL) {
1831  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1832  textArea->textColor = BLACK;
1833  textArea->text = PIC(info->text1);
1834  textArea->textAlignment = CENTER;
1835  textArea->fontId = (info->largeText1 == true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1836  textArea->wrapping = true;
1837  textArea->obj.area.width = AVAILABLE_WIDTH;
1838  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1839  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1840  textArea->obj.alignment = BOTTOM_MIDDLE;
1841  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1842  textArea->obj.alignmentMarginY = 24;
1843 
1844  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1845 
1846  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1847  container->nbChildren++;
1848  }
1849  if (info->text2 != NULL) {
1850  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1851  textArea->textColor = DARK_GRAY;
1852  textArea->text = PIC(info->text2);
1853  textArea->textAlignment = CENTER;
1854  textArea->fontId = SMALL_REGULAR_FONT;
1855  textArea->wrapping = true;
1856  textArea->obj.area.width = AVAILABLE_WIDTH;
1857  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1858  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1859  textArea->obj.alignment = BOTTOM_MIDDLE;
1860  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1861  if (info->text1 != NULL) {
1862 #ifdef TARGET_STAX
1863  textArea->obj.alignmentMarginY = 40;
1864 #else // TARGET_STAX
1865  textArea->obj.alignmentMarginY = 28;
1866 #endif // TARGET_STAX
1867  }
1868  else {
1869  textArea->obj.alignmentMarginY = 32;
1870  fullHeight += 8;
1871  }
1872 
1873  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1874 
1875  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1876  container->nbChildren++;
1877  }
1878  // ensure that fullHeight is fitting in main container height (with 16 px margin)
1879  if ((fullHeight >= (layoutInt->container->obj.area.height - 16))
1880  && (qrcode->version == QRCODE_V4)) {
1881  qrcode->version = QRCODE_V4_SMALL;
1882  // in QR V4 small, we use 4*4 screen pixels for one QR pixel
1883  qrcode->obj.area.width = QR_V4_NB_PIX_SIZE * 4;
1884  qrcode->obj.area.height = qrcode->obj.area.width;
1885  fullHeight -= QR_V4_NB_PIX_SIZE * 4;
1886  }
1887  container->obj.area.height = fullHeight;
1888  container->layout = VERTICAL;
1889  if (info->centered) {
1890  container->obj.alignment = CENTER;
1891  }
1892  else {
1893  container->obj.alignment = BOTTOM_MIDDLE;
1894  container->obj.alignTo
1895  = layoutInt->container->children[layoutInt->container->nbChildren - 1];
1896  }
1897  container->obj.alignmentMarginY = info->offsetY;
1898 
1899  container->obj.area.width = AVAILABLE_WIDTH;
1900 
1901  // set this new container as child of main container
1902  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1903 
1904  return fullHeight;
1905 }
1906 #endif // NBGL_QRCODE
1907 
1917 {
1918  nbgl_layoutFooter_t footerDesc;
1919  footerDesc.type = FOOTER_CHOICE_BUTTONS;
1920  footerDesc.separationLine = false;
1921  footerDesc.choiceButtons.bottomText = info->bottomText;
1922  footerDesc.choiceButtons.token = info->token;
1923  footerDesc.choiceButtons.topText = info->topText;
1924  footerDesc.choiceButtons.topIcon = info->topIcon;
1925  footerDesc.choiceButtons.style = info->style;
1926  footerDesc.choiceButtons.tuneId = info->tuneId;
1927  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1928 }
1929 
1940  const nbgl_layoutHorizontalButtons_t *info)
1941 {
1943  .horizontalButtons.leftIcon = info->leftIcon,
1944  .horizontalButtons.leftToken = info->leftToken,
1945  .horizontalButtons.rightText = info->rightText,
1946  .horizontalButtons.rightToken = info->rightToken,
1947  .horizontalButtons.tuneId = info->tuneId};
1948 
1949  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHorizontalButtons():\n");
1950  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
1951 }
1952 
1961 {
1962  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1963  nbgl_text_area_t *itemTextArea;
1964  nbgl_text_area_t *valueTextArea;
1965  nbgl_container_t *container;
1966  uint8_t i;
1967 
1968  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTagValueList():\n");
1969  if (layout == NULL) {
1970  return -1;
1971  }
1972 
1973  for (i = 0; i < list->nbPairs; i++) {
1974  const nbgl_layoutTagValue_t *pair;
1975  uint16_t fullHeight = 0;
1976  const nbgl_icon_details_t *valueIcon = NULL;
1977 
1978  if (list->pairs != NULL) {
1979  pair = &list->pairs[i];
1980  }
1981  else {
1982  pair = list->callback(list->startIndex + i);
1983  }
1984 
1985  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1986 
1987  // get container children (max 3 if a valueIcon, otherwise 2)
1988  container->children
1989  = nbgl_containerPoolGet((pair->valueIcon != NULL) ? 3 : 2, layoutInt->layer);
1990 
1991  itemTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1992  valueTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1993 
1994  // init text area for this choice
1995  itemTextArea->textColor = DARK_GRAY;
1996  itemTextArea->text = PIC(pair->item);
1997  itemTextArea->textAlignment = MID_LEFT;
1998  itemTextArea->fontId = SMALL_REGULAR_FONT;
1999  itemTextArea->wrapping = true;
2000  itemTextArea->obj.area.width = AVAILABLE_WIDTH;
2001  itemTextArea->obj.area.height = nbgl_getTextHeightInWidth(
2002  itemTextArea->fontId, itemTextArea->text, AVAILABLE_WIDTH, itemTextArea->wrapping);
2003  itemTextArea->style = NO_STYLE;
2004  itemTextArea->obj.alignment = NO_ALIGNMENT;
2005  itemTextArea->obj.alignmentMarginX = 0;
2006  itemTextArea->obj.alignmentMarginY = 0;
2007  itemTextArea->obj.alignTo = NULL;
2008  container->children[container->nbChildren] = (nbgl_obj_t *) itemTextArea;
2009  container->nbChildren++;
2010 
2011  fullHeight += itemTextArea->obj.area.height;
2012 
2013  // init button for this choice
2014  valueTextArea->textColor = BLACK;
2015  valueTextArea->text = PIC(pair->value);
2016  valueTextArea->textAlignment = MID_LEFT;
2017  if (list->smallCaseForValue) {
2018  valueTextArea->fontId = SMALL_BOLD_FONT;
2019  }
2020  else {
2021  valueTextArea->fontId = LARGE_MEDIUM_FONT;
2022  }
2023  if ((pair->aliasValue == 0) && (pair->valueIcon == NULL)) {
2024  valueTextArea->obj.area.width = AVAILABLE_WIDTH;
2025  }
2026  else {
2027  if (pair->aliasValue) {
2028  // if the value is an alias, we automatically display a (>) icon
2029  valueIcon = &MINI_PUSH_ICON;
2030  }
2031  else {
2032  // otherwise use the provided icon
2033  valueIcon = PIC(pair->valueIcon);
2034  }
2035  // decrease the available width for value text
2036  valueTextArea->obj.area.width = AVAILABLE_WIDTH - valueIcon->width - 12;
2037  }
2038 
2039  // handle the nbMaxLinesForValue parameter, used to automatically keep only
2040  // nbMaxLinesForValue lines
2041  uint16_t nbLines = nbgl_getTextNbLinesInWidth(valueTextArea->fontId,
2042  valueTextArea->text,
2043  valueTextArea->obj.area.width,
2044  list->wrapping);
2045  // use this nbMaxLinesForValue parameter only if >0
2046  if ((list->nbMaxLinesForValue > 0) && (nbLines > list->nbMaxLinesForValue)) {
2047  nbLines = list->nbMaxLinesForValue;
2048  valueTextArea->nbMaxLines = list->nbMaxLinesForValue;
2049  }
2050  const nbgl_font_t *font = nbgl_getFont(valueTextArea->fontId);
2051  valueTextArea->obj.area.height = nbLines * font->line_height;
2052  valueTextArea->style = NO_STYLE;
2053  valueTextArea->obj.alignment = BOTTOM_LEFT;
2054  valueTextArea->obj.alignmentMarginY = 4;
2055  valueTextArea->obj.alignTo = (nbgl_obj_t *) itemTextArea;
2056  valueTextArea->wrapping = list->wrapping;
2057  container->children[container->nbChildren] = (nbgl_obj_t *) valueTextArea;
2058  container->nbChildren++;
2059 
2060  fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
2061  if (valueIcon != NULL) {
2062  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
2064  layoutInt, (nbgl_obj_t *) image, list->token, TUNE_TAP_CASUAL);
2065  obj->index = i;
2066  image->foregroundColor = BLACK;
2067  image->buffer = valueIcon;
2068  image->obj.alignment = RIGHT_TOP;
2069  image->obj.alignmentMarginX = 12;
2070  image->obj.alignTo = (nbgl_obj_t *) valueTextArea;
2071  image->obj.touchMask = (1 << TOUCHED);
2072  image->obj.touchId = VALUE_BUTTON_1_ID + i;
2073 
2074  container->children[container->nbChildren] = (nbgl_obj_t *) image;
2075  container->nbChildren++;
2076  }
2077 
2078  container->obj.area.width = AVAILABLE_WIDTH;
2079  container->obj.area.height = fullHeight;
2080  container->layout = VERTICAL;
2081  container->obj.alignmentMarginX = BORDER_MARGIN;
2082 #ifdef TARGET_STAX
2083  // On Stax, 12 px between each tag/value pair
2084  if (i > 0) {
2085  container->obj.alignmentMarginY = 12;
2086  }
2087  else {
2088  container->obj.alignmentMarginY = 24;
2089  }
2090 #else // TARGET_STAX
2091  // On Flex, 24 px between each tag/value pair
2092  if (i > 0) {
2093  container->obj.alignmentMarginY = 24;
2094  }
2095 #endif // TARGET_STAX
2096  container->obj.alignment = NO_ALIGNMENT;
2097 
2098  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
2099  }
2100 
2101  return 0;
2102 }
2103 
2113 {
2114  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2115  nbgl_progress_bar_t *progress;
2116 
2117  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressBar():\n");
2118  if (layout == NULL) {
2119  return -1;
2120  }
2121  if (barLayout->text != NULL) {
2122  nbgl_text_area_t *textArea;
2123 
2125  ((nbgl_layoutInternal_t *) layout)->layer);
2126  textArea->textColor = BLACK;
2127  textArea->text = PIC(barLayout->text);
2128  textArea->textAlignment = MID_LEFT;
2129  textArea->fontId = SMALL_REGULAR_FONT;
2130  textArea->wrapping = true;
2131  textArea->obj.area.width = AVAILABLE_WIDTH;
2132  textArea->obj.area.height = nbgl_getTextHeightInWidth(
2133  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2134  textArea->style = NO_STYLE;
2135  textArea->obj.alignment = NO_ALIGNMENT;
2136  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2137  textArea->obj.alignmentMarginY = BORDER_MARGIN;
2138  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
2139  }
2141  ((nbgl_layoutInternal_t *) layout)->layer);
2142  progress->foregroundColor = BLACK;
2143  progress->withBorder = true;
2144  progress->state = barLayout->percentage;
2145  progress->obj.area.width = 120;
2146  progress->obj.area.height = 12;
2147  progress->obj.alignment = NO_ALIGNMENT;
2148  progress->obj.alignmentMarginX = (AVAILABLE_WIDTH - progress->obj.area.width) / 2;
2149  progress->obj.alignmentMarginY = BORDER_MARGIN;
2150  layoutAddObject(layoutInt, (nbgl_obj_t *) progress);
2151 
2152  if (barLayout->subText != NULL) {
2153  nbgl_text_area_t *subTextArea;
2154 
2155  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(
2156  TEXT_AREA, ((nbgl_layoutInternal_t *) layout)->layer);
2157  subTextArea->textColor = LIGHT_GRAY;
2158  subTextArea->text = PIC(barLayout->subText);
2159  subTextArea->textAlignment = MID_LEFT;
2160  subTextArea->fontId = SMALL_REGULAR_FONT;
2161  subTextArea->wrapping = true;
2162  subTextArea->obj.area.width = AVAILABLE_WIDTH;
2163  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
2164  subTextArea->text,
2165  subTextArea->obj.area.width,
2166  subTextArea->wrapping);
2167  subTextArea->style = NO_STYLE;
2168  subTextArea->obj.alignment = NO_ALIGNMENT;
2169  subTextArea->obj.alignmentMarginX = BORDER_MARGIN;
2170  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
2171  layoutAddObject(layoutInt, (nbgl_obj_t *) subTextArea);
2172  }
2173 
2174  return 0;
2175 }
2176 
2184 {
2185  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2186  nbgl_line_t *line;
2187 
2188  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSeparationLine():\n");
2189  line = createHorizontalLine(layoutInt->layer);
2190  line->obj.alignmentMarginY = -4;
2191  line->offset = 3;
2192  layoutAddObject(layoutInt, (nbgl_obj_t *) line);
2193  return 0;
2194 }
2195 
2204 {
2205  layoutObj_t *obj;
2206  nbgl_button_t *button;
2207  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2208 
2209  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddButton():\n");
2210  if (layout == NULL) {
2211  return -1;
2212  }
2213 
2214  // Add in footer if matching
2215  if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2216  if (layoutInt->footerContainer == NULL) {
2217  nbgl_layoutFooter_t footerDesc;
2218  footerDesc.type = FOOTER_SIMPLE_BUTTON;
2219  footerDesc.separationLine = false;
2220  footerDesc.button.text = buttonInfo->text;
2221  footerDesc.button.token = buttonInfo->token;
2222  footerDesc.button.tuneId = buttonInfo->tuneId;
2223  footerDesc.button.icon = buttonInfo->icon;
2224  footerDesc.button.style = buttonInfo->style;
2225  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2226  }
2227  else {
2228  nbgl_layoutUpFooter_t upFooterDesc;
2229  upFooterDesc.type = UP_FOOTER_BUTTON;
2230  upFooterDesc.button.text = buttonInfo->text;
2231  upFooterDesc.button.token = buttonInfo->token;
2232  upFooterDesc.button.tuneId = buttonInfo->tuneId;
2233  upFooterDesc.button.icon = buttonInfo->icon;
2234  upFooterDesc.button.style = buttonInfo->style;
2235  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2236  }
2237  }
2238 
2239  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2240  obj = layoutAddCallbackObj(
2241  layoutInt, (nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2242  if (obj == NULL) {
2243  return -1;
2244  }
2245 
2246  button->obj.alignmentMarginX = BORDER_MARGIN;
2247  button->obj.alignmentMarginY = 12;
2248  button->obj.alignment = NO_ALIGNMENT;
2249  if (buttonInfo->style == BLACK_BACKGROUND) {
2250  button->innerColor = BLACK;
2251  button->foregroundColor = WHITE;
2252  }
2253  else {
2254  button->innerColor = WHITE;
2255  button->foregroundColor = BLACK;
2256  }
2257  if (buttonInfo->style == NO_BORDER) {
2258  button->borderColor = WHITE;
2259  }
2260  else {
2261  if (buttonInfo->style == BLACK_BACKGROUND) {
2262  button->borderColor = BLACK;
2263  }
2264  else {
2265  button->borderColor = LIGHT_GRAY;
2266  }
2267  }
2268  button->text = PIC(buttonInfo->text);
2269  button->fontId = SMALL_BOLD_FONT;
2270  button->icon = PIC(buttonInfo->icon);
2271  if (buttonInfo->fittingContent == true) {
2272  button->obj.area.width = nbgl_getTextWidth(button->fontId, button->text)
2274  + ((button->icon) ? (button->icon->width + 12) : 0);
2275  button->obj.area.height = SMALL_BUTTON_HEIGHT;
2276  button->radius = RADIUS_32_PIXELS;
2277  if (buttonInfo->onBottom != true) {
2278  button->obj.alignmentMarginX
2279  += (SCREEN_WIDTH - 2 * BORDER_MARGIN - button->obj.area.width) / 2;
2280  }
2281  }
2282  else {
2283  button->obj.area.width = AVAILABLE_WIDTH;
2284  button->obj.area.height = BUTTON_DIAMETER;
2285  button->radius = BUTTON_RADIUS;
2286  }
2287  button->obj.alignTo = NULL;
2288  button->obj.touchMask = (1 << TOUCHED);
2289  button->obj.touchId = (buttonInfo->fittingContent) ? EXTRA_BUTTON_ID : SINGLE_BUTTON_ID;
2290  // set this new button as child of the container
2291  layoutAddObject(layoutInt, (nbgl_obj_t *) button);
2292 
2293  return 0;
2294 }
2295 
2306  const char *text,
2307  uint8_t token,
2308  tune_index_e tuneId)
2309 {
2310  nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_LONG_PRESS,
2311  .longPress.text = text,
2312  .longPress.token = token,
2313  .longPress.tuneId = tuneId};
2314 
2315  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLongPressButton():\n");
2316  if (layout == NULL) {
2317  return -1;
2318  }
2319 
2320  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2321 }
2322 
2334  const char *text,
2335  uint8_t token,
2336  tune_index_e tuneId)
2337 {
2338  nbgl_layoutFooter_t footerDesc;
2339  footerDesc.type = FOOTER_SIMPLE_TEXT;
2340  footerDesc.separationLine = true;
2341  footerDesc.simpleText.text = text;
2342  footerDesc.simpleText.mutedOut = false;
2343  footerDesc.simpleText.token = token;
2344  footerDesc.simpleText.tuneId = tuneId;
2345  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2346 }
2347 
2361  const char *leftText,
2362  uint8_t leftToken,
2363  const char *rightText,
2364  uint8_t rightToken,
2365  tune_index_e tuneId)
2366 {
2367  nbgl_layoutFooter_t footerDesc;
2368  footerDesc.type = FOOTER_DOUBLE_TEXT;
2369  footerDesc.separationLine = true;
2370  footerDesc.doubleText.leftText = leftText;
2371  footerDesc.doubleText.leftToken = leftToken;
2372  footerDesc.doubleText.rightText = rightText;
2373  footerDesc.doubleText.rightToken = rightToken;
2374  footerDesc.doubleText.tuneId = tuneId;
2375  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2376 }
2377 
2387 {
2388  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2389  layoutObj_t *obj;
2390  nbgl_text_area_t *textArea;
2391  nbgl_line_t *line, *separationLine = NULL;
2392  ;
2393  nbgl_button_t *button;
2394 
2395  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHeader():\n");
2396  if (layout == NULL) {
2397  return -1;
2398  }
2399  if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2400  return -2;
2401  }
2402 
2403  layoutInt->headerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2404  layoutInt->headerContainer->obj.area.width = SCREEN_WIDTH;
2405  layoutInt->headerContainer->layout = VERTICAL;
2406  layoutInt->headerContainer->children
2407  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2408  layoutInt->headerContainer->obj.alignment = TOP_MIDDLE;
2409 
2410  switch (headerDesc->type) {
2411  case HEADER_EMPTY: {
2412  layoutInt->headerContainer->obj.area.height = headerDesc->emptySpace.height;
2413  break;
2414  }
2415  case HEADER_BACK_AND_TEXT:
2416  case HEADER_EXTENDED_BACK: {
2417  const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2418  ? PIC(headerDesc->extendedBack.text)
2419  : PIC(headerDesc->backAndText.text);
2420  // add back button
2421  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2422  obj = layoutAddCallbackObj(
2423  layoutInt,
2424  (nbgl_obj_t *) button,
2425  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.backToken
2426  : headerDesc->backAndText.token,
2427  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.tuneId
2428  : headerDesc->backAndText.tuneId);
2429  if (obj == NULL) {
2430  return -1;
2431  }
2432 
2433  button->obj.alignment = MID_LEFT;
2434  button->innerColor = WHITE;
2435  button->foregroundColor = BLACK;
2436  button->borderColor = WHITE;
2437  button->obj.area.width = BACK_KEY_WIDTH;
2438  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2439  button->text = NULL;
2440  button->icon = PIC(&LEFT_ARROW_ICON);
2441  button->obj.touchMask = (1 << TOUCHED);
2442  button->obj.touchId = BACK_BUTTON_ID;
2443  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2444  = (nbgl_obj_t *) button;
2445  layoutInt->headerContainer->nbChildren++;
2446 
2447  // add optional text if needed
2448  if (text != NULL) {
2449  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2450  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2451  && (headerDesc->extendedBack.textToken != NBGL_INVALID_TOKEN)) {
2452  obj = layoutAddCallbackObj(layoutInt,
2453  (nbgl_obj_t *) textArea,
2454  headerDesc->extendedBack.textToken,
2455  headerDesc->extendedBack.tuneId);
2456  if (obj == NULL) {
2457  return -1;
2458  }
2459  textArea->obj.touchMask = (1 << TOUCHED);
2460  }
2461  textArea->obj.alignment = CENTER;
2462  textArea->textColor = BLACK;
2463  textArea->obj.area.width
2464  = layoutInt->headerContainer->obj.area.width - 2 * BACK_KEY_WIDTH;
2465  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2466  textArea->text = text;
2467  textArea->fontId = SMALL_BOLD_FONT;
2468  textArea->textAlignment = CENTER;
2469  textArea->wrapping = true;
2470  // ensure that text fits on 2 lines maximum
2471  if (nbgl_getTextNbLinesInWidth(textArea->fontId,
2472  textArea->text,
2473  textArea->obj.area.width,
2474  textArea->wrapping)
2475  > 2) {
2477  "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2478  text);
2479  }
2480  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2481  = (nbgl_obj_t *) textArea;
2482  layoutInt->headerContainer->nbChildren++;
2483  }
2484  // add action key if the type is HEADER_EXTENDED_BACK
2485  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2486  && (headerDesc->extendedBack.actionIcon)) {
2487  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2488  // if token is valid
2489  if (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) {
2490  obj = layoutAddCallbackObj(layoutInt,
2491  (nbgl_obj_t *) button,
2492  headerDesc->extendedBack.actionToken,
2493  headerDesc->extendedBack.tuneId);
2494  if (obj == NULL) {
2495  return -1;
2496  }
2497  button->obj.touchMask = (1 << TOUCHED);
2498  }
2499 
2500  button->obj.alignment = MID_RIGHT;
2501  button->innerColor = WHITE;
2502  button->foregroundColor
2503  = (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) ? BLACK
2504  : LIGHT_GRAY;
2505  button->borderColor = WHITE;
2506  button->obj.area.width = BACK_KEY_WIDTH;
2507  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2508  button->text = NULL;
2509  button->icon = PIC(headerDesc->extendedBack.actionIcon);
2510  button->obj.touchId = EXTRA_BUTTON_ID;
2511  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2512  = (nbgl_obj_t *) button;
2513  layoutInt->headerContainer->nbChildren++;
2514  }
2515 
2516  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2517  break;
2518  }
2519  case HEADER_BACK_AND_PROGRESS: {
2520 #ifdef TARGET_STAX
2521  // add optional back button
2522  if (headerDesc->progressAndBack.withBack) {
2523  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2524  obj = layoutAddCallbackObj(layoutInt,
2525  (nbgl_obj_t *) button,
2526  headerDesc->progressAndBack.token,
2527  headerDesc->progressAndBack.tuneId);
2528  if (obj == NULL) {
2529  return -1;
2530  }
2531 
2532  button->obj.alignment = MID_LEFT;
2533  button->innerColor = WHITE;
2534  button->foregroundColor = BLACK;
2535  button->borderColor = WHITE;
2536  button->obj.area.width = BACK_KEY_WIDTH;
2537  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2538  button->text = NULL;
2539  button->icon = PIC(&LEFT_ARROW_ICON);
2540  button->obj.touchMask = (1 << TOUCHED);
2541  button->obj.touchId = BACK_BUTTON_ID;
2542  // add to container
2543  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2544  = (nbgl_obj_t *) button;
2545  layoutInt->headerContainer->nbChildren++;
2546  }
2547 
2548  // add progress indicator
2549  if (headerDesc->progressAndBack.nbPages > 1
2550  && headerDesc->progressAndBack.nbPages != NBGL_NO_PROGRESS_INDICATOR) {
2551  nbgl_page_indicator_t *progress;
2552 
2553  progress
2555  progress->activePage = headerDesc->progressAndBack.activePage;
2556  progress->nbPages = headerDesc->progressAndBack.nbPages;
2557  progress->obj.area.width = 224;
2558  progress->obj.alignment = CENTER;
2559  // add to container
2560  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2561  = (nbgl_obj_t *) progress;
2562  layoutInt->headerContainer->nbChildren++;
2563  }
2564  layoutInt->activePage = headerDesc->progressAndBack.activePage;
2565  layoutInt->nbPages = headerDesc->progressAndBack.nbPages;
2566  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2567 #endif // TARGET_STAX
2568  break;
2569  }
2570  case HEADER_TITLE: {
2571  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2572  textArea->textColor = BLACK;
2573  textArea->obj.area.width = AVAILABLE_WIDTH;
2574  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2575  textArea->text = PIC(headerDesc->title.text);
2576  textArea->fontId = SMALL_BOLD_FONT;
2577  textArea->textAlignment = CENTER;
2578  textArea->wrapping = true;
2579  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2580  = (nbgl_obj_t *) textArea;
2581  layoutInt->headerContainer->nbChildren++;
2582  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2583  break;
2584  }
2585  case HEADER_RIGHT_TEXT: {
2586  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2587  obj = layoutAddCallbackObj(layoutInt,
2588  (nbgl_obj_t *) textArea,
2589  headerDesc->rightText.token,
2590  headerDesc->rightText.tuneId);
2591  if (obj == NULL) {
2592  return -1;
2593  }
2594  textArea->obj.alignment = MID_RIGHT;
2595  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2596  textArea->textColor = BLACK;
2597  textArea->obj.area.width = AVAILABLE_WIDTH;
2598  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2599  textArea->text = PIC(headerDesc->rightText.text);
2600  textArea->fontId = SMALL_BOLD_FONT;
2601  textArea->textAlignment = MID_RIGHT;
2602  textArea->obj.touchMask = (1 << TOUCHED);
2603  textArea->obj.touchId = TOP_RIGHT_BUTTON_ID;
2604  // add to bottom container
2605  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2606  = (nbgl_obj_t *) textArea;
2607  layoutInt->headerContainer->nbChildren++;
2608  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2609  break;
2610  }
2611  default:
2612  return -2;
2613  }
2614 
2615  if (headerDesc->separationLine) {
2616  line = createHorizontalLine(layoutInt->layer);
2617  line->obj.alignment = BOTTOM_MIDDLE;
2618  line->offset = 3;
2619  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2620  = (nbgl_obj_t *) line;
2621  layoutInt->headerContainer->nbChildren++;
2622  }
2623  if (separationLine != NULL) {
2624  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2625  = (nbgl_obj_t *) separationLine;
2626  layoutInt->headerContainer->nbChildren++;
2627  }
2628  // header must be the first child
2629  layoutInt->children[HEADER_INDEX] = (nbgl_obj_t *) layoutInt->headerContainer;
2630 
2631  // subtract header height from main container height
2632  layoutInt->container->obj.area.height -= layoutInt->headerContainer->obj.area.height;
2633  layoutInt->container->obj.alignTo = (nbgl_obj_t *) layoutInt->headerContainer;
2634  layoutInt->container->obj.alignment = BOTTOM_LEFT;
2635 
2636  layoutInt->headerType = headerDesc->type;
2637 
2638  return layoutInt->headerContainer->obj.area.height;
2639 }
2640 
2650 {
2651  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2652  layoutObj_t *obj;
2653  nbgl_text_area_t *textArea;
2654  nbgl_line_t *line, *separationLine = NULL;
2655  nbgl_button_t *button;
2656 
2657  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddExtendedFooter():\n");
2658  if (layout == NULL) {
2659  return -1;
2660  }
2661  if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2662  return -2;
2663  }
2664 
2665  layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2666  layoutInt->footerContainer->obj.area.width = AVAILABLE_WIDTH;
2667  layoutInt->footerContainer->layout = VERTICAL;
2668  layoutInt->footerContainer->children
2669  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2670  layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
2671 
2672  switch (footerDesc->type) {
2673  case FOOTER_EMPTY: {
2674  layoutInt->footerContainer->obj.area.height = footerDesc->emptySpace.height;
2675  break;
2676  }
2677  case FOOTER_SIMPLE_TEXT: {
2678  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2679  obj = layoutAddCallbackObj(layoutInt,
2680  (nbgl_obj_t *) textArea,
2681  footerDesc->simpleText.token,
2682  footerDesc->simpleText.tuneId);
2683  if (obj == NULL) {
2684  return -1;
2685  }
2686 
2687  textArea->obj.alignment = BOTTOM_MIDDLE;
2688  textArea->textColor = (footerDesc->simpleText.mutedOut) ? DARK_GRAY : BLACK;
2689  textArea->obj.area.width = AVAILABLE_WIDTH;
2690  textArea->obj.area.height
2691  = (footerDesc->simpleText.mutedOut) ? SMALL_FOOTER_HEIGHT : SIMPLE_FOOTER_HEIGHT;
2692  textArea->text = PIC(footerDesc->simpleText.text);
2693  textArea->fontId
2694  = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
2695  textArea->textAlignment = CENTER;
2696  textArea->obj.touchMask = (1 << TOUCHED);
2697  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2698  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2699  = (nbgl_obj_t *) textArea;
2700  layoutInt->footerContainer->nbChildren++;
2701  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2702  break;
2703  }
2704  case FOOTER_DOUBLE_TEXT: {
2705  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2706  obj = layoutAddCallbackObj(layoutInt,
2707  (nbgl_obj_t *) textArea,
2708  footerDesc->doubleText.leftToken,
2709  footerDesc->doubleText.tuneId);
2710  if (obj == NULL) {
2711  return -1;
2712  }
2713  textArea->obj.alignment = BOTTOM_LEFT;
2714  textArea->textColor = BLACK;
2715  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2716  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2717  textArea->text = PIC(footerDesc->doubleText.leftText);
2718  textArea->fontId = SMALL_BOLD_FONT;
2719  textArea->textAlignment = CENTER;
2720  textArea->obj.touchMask = (1 << TOUCHED);
2721  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2722  // add to bottom container
2723  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2724  = (nbgl_obj_t *) textArea;
2725  layoutInt->footerContainer->nbChildren++;
2726 
2727  // create right touchable text
2728  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2729  obj = layoutAddCallbackObj(layoutInt,
2730  (nbgl_obj_t *) textArea,
2731  footerDesc->doubleText.rightToken,
2732  footerDesc->doubleText.tuneId);
2733  if (obj == NULL) {
2734  return -1;
2735  }
2736 
2737  textArea->obj.alignment = BOTTOM_RIGHT;
2738  textArea->textColor = BLACK;
2739  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2740  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2741  textArea->text = PIC(footerDesc->doubleText.rightText);
2742  textArea->fontId = SMALL_BOLD_FONT;
2743  textArea->textAlignment = CENTER;
2744  textArea->obj.touchMask = (1 << TOUCHED);
2745  textArea->obj.touchId = RIGHT_BUTTON_ID;
2746  // add to bottom container
2747  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2748  = (nbgl_obj_t *) textArea;
2749  layoutInt->footerContainer->nbChildren++;
2750  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2751 
2752  // create vertical line separating texts
2753  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2754  separationLine->lineColor = LIGHT_GRAY;
2755  separationLine->obj.area.width = 1;
2756  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2757  separationLine->direction = VERTICAL;
2758  separationLine->thickness = 1;
2759  separationLine->obj.alignment = MID_LEFT;
2760  separationLine->obj.alignTo = (nbgl_obj_t *) textArea;
2761  separationLine->obj.alignmentMarginX = -1;
2762  break;
2763  }
2764  case FOOTER_TEXT_AND_NAV: {
2765  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2766  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2767  // add touchable text on the left
2768  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2769  obj = layoutAddCallbackObj(layoutInt,
2770  (nbgl_obj_t *) textArea,
2771  footerDesc->textAndNav.token,
2772  footerDesc->textAndNav.tuneId);
2773  if (obj == NULL) {
2774  return -1;
2775  }
2776  textArea->obj.alignment = BOTTOM_LEFT;
2777  textArea->textColor = BLACK;
2778 #ifdef TARGET_STAX
2779  textArea->obj.area.width = 160;
2780 #else // TARGET_STAX
2781  textArea->obj.area.width = 192;
2782 #endif // TARGET_STAX
2783  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2784  textArea->text = PIC(footerDesc->textAndNav.text);
2785  textArea->fontId = SMALL_BOLD_FONT;
2786  textArea->textAlignment = CENTER;
2787  textArea->obj.touchMask = (1 << TOUCHED);
2788  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2789  // add to bottom container
2790  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2791  = (nbgl_obj_t *) textArea;
2792  layoutInt->footerContainer->nbChildren++;
2793 
2794  // add navigation on the right
2795  nbgl_container_t *navContainer
2796  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2797  navContainer->obj.area.width = AVAILABLE_WIDTH;
2798  navContainer->layout = VERTICAL;
2799  navContainer->nbChildren = 4;
2800  navContainer->children
2801  = (nbgl_obj_t **) nbgl_containerPoolGet(navContainer->nbChildren, layoutInt->layer);
2802  navContainer->obj.alignment = BOTTOM_RIGHT;
2803  navContainer->obj.area.width = SCREEN_WIDTH - textArea->obj.area.width;
2804  navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2805  layoutNavigationPopulate(navContainer, &footerDesc->navigation, layoutInt->layer);
2806  obj = layoutAddCallbackObj(layoutInt,
2807  (nbgl_obj_t *) navContainer,
2808  footerDesc->textAndNav.navigation.token,
2809  footerDesc->textAndNav.navigation.tuneId);
2810  if (obj == NULL) {
2811  return -1;
2812  }
2813 
2814  // create vertical line separating text from nav
2815  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2816  separationLine->lineColor = LIGHT_GRAY;
2817  separationLine->obj.area.width = 1;
2818  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2819  separationLine->direction = VERTICAL;
2820  separationLine->thickness = 1;
2821  separationLine->obj.alignment = MID_LEFT;
2822  separationLine->obj.alignTo = (nbgl_obj_t *) navContainer;
2823  separationLine->obj.alignmentMarginX = -1;
2824 
2825  layoutInt->activePage = footerDesc->textAndNav.navigation.activePage;
2826  layoutInt->nbPages = footerDesc->textAndNav.navigation.nbPages;
2827  // add to bottom container
2828  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2829  = (nbgl_obj_t *) navContainer;
2830  layoutInt->footerContainer->nbChildren++;
2831  break;
2832  }
2833  case FOOTER_NAV: {
2834  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2835  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2837  layoutInt->footerContainer, &footerDesc->navigation, layoutInt->layer);
2838  layoutInt->footerContainer->nbChildren = 4;
2839  obj = layoutAddCallbackObj(layoutInt,
2840  (nbgl_obj_t *) layoutInt->footerContainer,
2841  footerDesc->navigation.token,
2842  footerDesc->navigation.tuneId);
2843  if (obj == NULL) {
2844  return -1;
2845  }
2846 
2847  layoutInt->activePage = footerDesc->navigation.activePage;
2848  layoutInt->nbPages = footerDesc->navigation.nbPages;
2849  break;
2850  }
2851  case FOOTER_SIMPLE_BUTTON: {
2852  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2853  obj = layoutAddCallbackObj(layoutInt,
2854  (nbgl_obj_t *) button,
2855  footerDesc->button.token,
2856  footerDesc->button.tuneId);
2857  if (obj == NULL) {
2858  return -1;
2859  }
2860 
2861  button->obj.alignment = CENTER;
2862  if (footerDesc->button.style == BLACK_BACKGROUND) {
2863  button->innerColor = BLACK;
2864  button->foregroundColor = WHITE;
2865  }
2866  else {
2867  button->innerColor = WHITE;
2868  button->foregroundColor = BLACK;
2869  }
2870 
2871  if (footerDesc->button.style == NO_BORDER) {
2872  button->borderColor = WHITE;
2873  }
2874  else {
2875  if (footerDesc->button.style == BLACK_BACKGROUND) {
2876  button->borderColor = BLACK;
2877  }
2878  else {
2879  button->borderColor = LIGHT_GRAY;
2880  }
2881  }
2882  button->text = PIC(footerDesc->button.text);
2883  button->fontId = SMALL_BOLD_FONT;
2884  button->icon = PIC(footerDesc->button.icon);
2885  button->radius = BUTTON_RADIUS;
2886  button->obj.area.height = BUTTON_DIAMETER;
2887  layoutInt->footerContainer->obj.area.height = FOOTER_BUTTON_HEIGHT;
2888  if (footerDesc->button.text == NULL) {
2889  button->obj.area.width = BUTTON_DIAMETER;
2890  }
2891  else {
2892  button->obj.area.width = AVAILABLE_WIDTH;
2893  }
2894  button->obj.touchMask = (1 << TOUCHED);
2895  button->obj.touchId = button->text ? SINGLE_BUTTON_ID : BOTTOM_BUTTON_ID;
2896  // add to bottom container
2897  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2898  = (nbgl_obj_t *) button;
2899  layoutInt->footerContainer->nbChildren++;
2900  break;
2901  }
2902  case FOOTER_CHOICE_BUTTONS: {
2903  // texts cannot be NULL
2904  if ((footerDesc->choiceButtons.bottomText == NULL)
2905  || (footerDesc->choiceButtons.topText == NULL)) {
2906  return -1;
2907  }
2908 
2909  // create bottom button (footer) at first
2910  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2911  obj = layoutAddCallbackObj(layoutInt,
2912  (nbgl_obj_t *) button,
2913  footerDesc->choiceButtons.token,
2914  footerDesc->choiceButtons.tuneId);
2915  if (obj == NULL) {
2916  return -1;
2917  }
2918  // associate with with index 1
2919  obj->index = 1;
2920  // put at the bottom of the container
2921  button->obj.alignment = BOTTOM_MIDDLE;
2922  button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
2923  button->borderColor = WHITE;
2924  button->innerColor = WHITE;
2925  button->foregroundColor = BLACK;
2926  button->obj.area.width = AVAILABLE_WIDTH;
2927  button->obj.area.height = BUTTON_DIAMETER;
2928  button->radius = BUTTON_RADIUS;
2929  button->text = PIC(footerDesc->choiceButtons.bottomText);
2930  button->fontId = SMALL_BOLD_FONT;
2931  button->obj.touchMask = (1 << TOUCHED);
2932  button->obj.touchId = CHOICE_2_ID;
2933  // add to bottom container
2934  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2935  = (nbgl_obj_t *) button;
2936  layoutInt->footerContainer->nbChildren++;
2937 
2938  // add line if needed
2939  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2940  line = createHorizontalLine(layoutInt->layer);
2941  line->obj.alignment = TOP_MIDDLE;
2942  line->obj.alignmentMarginY = 4;
2943  line->obj.alignTo = (nbgl_obj_t *) button;
2944  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2945  = (nbgl_obj_t *) line;
2946  layoutInt->footerContainer->nbChildren++;
2947  }
2948 
2949  // then top button, on top of it
2950  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2951  obj = layoutAddCallbackObj(layoutInt,
2952  (nbgl_obj_t *) button,
2953  footerDesc->choiceButtons.token,
2954  footerDesc->choiceButtons.tuneId);
2955  if (obj == NULL) {
2956  return -1;
2957  }
2958  // associate with with index 0
2959  obj->index = 0;
2960  button->obj.alignment = TOP_MIDDLE;
2961  button->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN; // 24 pixels from top of container
2962  if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
2963  button->innerColor = WHITE;
2964  button->borderColor = LIGHT_GRAY;
2965  button->foregroundColor = BLACK;
2966  }
2967  else {
2968  button->innerColor = BLACK;
2969  button->borderColor = BLACK;
2970  button->foregroundColor = WHITE;
2971  }
2972  button->obj.area.width = AVAILABLE_WIDTH;
2973  button->obj.area.height = BUTTON_DIAMETER;
2974  button->radius = BUTTON_RADIUS;
2975  button->text = PIC(footerDesc->choiceButtons.topText);
2976  button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
2977  ? PIC(footerDesc->choiceButtons.topIcon)
2978  : NULL;
2979  button->fontId = SMALL_BOLD_FONT;
2980  button->obj.touchMask = (1 << TOUCHED);
2981  button->obj.touchId = CHOICE_1_ID;
2982  // add to bottom container
2983  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2984  = (nbgl_obj_t *) button;
2985  layoutInt->footerContainer->nbChildren++;
2986 
2987  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2988  layoutInt->footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
2989  }
2990  else {
2991  layoutInt->footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
2992  }
2993 
2994  break;
2995  }
2996  default:
2997  return -2;
2998  }
2999 
3000  // add swipable feature for navigation
3001  if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
3002  addSwipeInternal(layoutInt,
3003  ((1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT)),
3005  (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
3006  : footerDesc->textAndNav.navigation.token,
3007  (footerDesc->type == FOOTER_NAV)
3008  ? footerDesc->navigation.tuneId
3009  : footerDesc->textAndNav.navigation.tuneId);
3010  }
3011 
3012  if (footerDesc->separationLine) {
3013  line = createHorizontalLine(layoutInt->layer);
3014  line->obj.alignment = TOP_MIDDLE;
3015  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
3016  = (nbgl_obj_t *) line;
3017  layoutInt->footerContainer->nbChildren++;
3018  }
3019  if (separationLine != NULL) {
3020  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
3021  = (nbgl_obj_t *) separationLine;
3022  layoutInt->footerContainer->nbChildren++;
3023  }
3024 
3025  layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
3026 
3027  // subtract footer height from main container height
3028  layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
3029 
3030  layoutInt->footerType = footerDesc->type;
3031 
3032  return layoutInt->footerContainer->obj.area.height;
3033 }
3034 
3044 {
3045  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3046  layoutObj_t *obj;
3047  nbgl_text_area_t *textArea;
3048  nbgl_line_t *line;
3049  nbgl_button_t *button;
3050 
3051  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddUpFooter():\n");
3052  if (layout == NULL) {
3053  return -1;
3054  }
3055  if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
3056  return -2;
3057  }
3058 
3059  layoutInt->upFooterContainer
3060  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
3061  layoutInt->upFooterContainer->obj.area.width = SCREEN_WIDTH;
3062  layoutInt->upFooterContainer->layout = VERTICAL;
3063  // maximum 4 children for long press button
3064  layoutInt->upFooterContainer->children
3065  = (nbgl_obj_t **) nbgl_containerPoolGet(4, layoutInt->layer);
3066  layoutInt->upFooterContainer->obj.alignTo = (nbgl_obj_t *) layoutInt->container;
3067  layoutInt->upFooterContainer->obj.alignment = BOTTOM_MIDDLE;
3068 
3069  switch (upFooterDesc->type) {
3070  case UP_FOOTER_LONG_PRESS: {
3071  nbgl_progress_bar_t *progressBar;
3072 
3073  obj = layoutAddCallbackObj(layoutInt,
3074  (nbgl_obj_t *) layoutInt->upFooterContainer,
3075  upFooterDesc->longPress.token,
3076  upFooterDesc->longPress.tuneId);
3077  if (obj == NULL) {
3078  return -1;
3079  }
3080  layoutInt->upFooterContainer->nbChildren = 4;
3081  layoutInt->upFooterContainer->obj.area.height = LONG_PRESS_BUTTON_HEIGHT;
3082  layoutInt->upFooterContainer->obj.touchId = LONG_PRESS_BUTTON_ID;
3083  layoutInt->upFooterContainer->obj.touchMask
3084  = ((1 << TOUCHING) | (1 << TOUCH_RELEASED) | (1 << OUT_OF_TOUCH)
3085  | (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT));
3086 
3087  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3088  button->obj.alignmentMarginX = BORDER_MARGIN;
3089  button->obj.alignment = MID_RIGHT;
3090  button->innerColor = BLACK;
3091  button->foregroundColor = WHITE;
3092  button->borderColor = BLACK;
3093  button->obj.area.width = BUTTON_DIAMETER;
3094  button->obj.area.height = BUTTON_DIAMETER;
3095  button->radius = BUTTON_RADIUS;
3096  button->icon = PIC(&VALIDATE_ICON);
3097  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3098 
3099  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3100  textArea->textColor = BLACK;
3101  textArea->text = PIC(upFooterDesc->longPress.text);
3102  textArea->textAlignment = MID_LEFT;
3103  textArea->fontId = LARGE_MEDIUM_FONT;
3104  textArea->wrapping = true;
3105  textArea->obj.area.width = SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
3106  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3107  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3108  textArea->style = NO_STYLE;
3109  textArea->obj.alignment = MID_LEFT;
3110  textArea->obj.alignmentMarginX = BORDER_MARGIN;
3111  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) textArea;
3112 
3113  line = createHorizontalLine(layoutInt->layer);
3114  line->offset = 3;
3115  line->obj.alignment = TOP_MIDDLE;
3116  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) line;
3117 
3118  progressBar = (nbgl_progress_bar_t *) nbgl_objPoolGet(PROGRESS_BAR, layoutInt->layer);
3119  progressBar->withBorder = false;
3120  progressBar->obj.area.width = SCREEN_WIDTH;
3121  progressBar->obj.area.height = 8;
3122  progressBar->obj.alignment = TOP_MIDDLE;
3123  progressBar->obj.alignmentMarginY = 4;
3124  progressBar->obj.alignTo = NULL;
3125  layoutInt->upFooterContainer->children[3] = (nbgl_obj_t *) progressBar;
3126  break;
3127  }
3128  case UP_FOOTER_BUTTON: {
3129  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3130  obj = layoutAddCallbackObj(layoutInt,
3131  (nbgl_obj_t *) button,
3132  upFooterDesc->button.token,
3133  upFooterDesc->button.tuneId);
3134  if (obj == NULL) {
3135  return -1;
3136  }
3137 
3138  layoutInt->upFooterContainer->nbChildren = 1;
3139  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3140  button->obj.alignment = CENTER;
3141 
3142  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3143  button->innerColor = BLACK;
3144  button->foregroundColor = WHITE;
3145  }
3146  else {
3147  button->innerColor = WHITE;
3148  button->foregroundColor = BLACK;
3149  }
3150  if (upFooterDesc->button.style == NO_BORDER) {
3151  button->borderColor = WHITE;
3152  }
3153  else {
3154  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3155  button->borderColor = BLACK;
3156  }
3157  else {
3158  button->borderColor = LIGHT_GRAY;
3159  }
3160  }
3161  button->text = PIC(upFooterDesc->button.text);
3162  button->fontId = SMALL_BOLD_FONT;
3163  button->icon = PIC(upFooterDesc->button.icon);
3164  button->obj.area.width = AVAILABLE_WIDTH;
3165  button->obj.area.height = BUTTON_DIAMETER;
3166  button->radius = BUTTON_RADIUS;
3167 
3168  button->obj.alignTo = NULL;
3169  button->obj.touchMask = (1 << TOUCHED);
3170  button->obj.touchId = SINGLE_BUTTON_ID;
3171  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3172  break;
3173  }
3175  // icon & text cannot be NULL
3176  if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3177  || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3178  return -1;
3179  }
3180 
3181  layoutInt->upFooterContainer->nbChildren = 2;
3182  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3183 
3184  // create left button (in white) at first
3185  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3186  obj = layoutAddCallbackObj(layoutInt,
3187  (nbgl_obj_t *) button,
3188  upFooterDesc->horizontalButtons.leftToken,
3189  upFooterDesc->horizontalButtons.tuneId);
3190  if (obj == NULL) {
3191  return -1;
3192  }
3193  // associate with with index 1
3194  obj->index = 1;
3195  button->obj.alignment = MID_LEFT;
3196  button->obj.alignmentMarginX = BORDER_MARGIN;
3197  button->borderColor = LIGHT_GRAY;
3198  button->innerColor = WHITE;
3199  button->foregroundColor = BLACK;
3200  button->obj.area.width = BUTTON_DIAMETER;
3201  button->obj.area.height = BUTTON_DIAMETER;
3202  button->radius = BUTTON_RADIUS;
3203  button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3204  button->fontId = SMALL_BOLD_FONT;
3205  button->obj.touchMask = (1 << TOUCHED);
3206  button->obj.touchId = CHOICE_2_ID;
3207  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3208 
3209  // then black button, on right
3210  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3211  obj = layoutAddCallbackObj(layoutInt,
3212  (nbgl_obj_t *) button,
3213  upFooterDesc->horizontalButtons.rightToken,
3214  upFooterDesc->horizontalButtons.tuneId);
3215  if (obj == NULL) {
3216  return -1;
3217  }
3218  // associate with with index 0
3219  obj->index = 0;
3220  button->obj.alignment = MID_RIGHT;
3221  button->obj.alignmentMarginX = BORDER_MARGIN;
3222  button->innerColor = BLACK;
3223  button->borderColor = BLACK;
3224  button->foregroundColor = WHITE;
3225  button->obj.area.width = AVAILABLE_WIDTH - BUTTON_DIAMETER - 16;
3226  button->obj.area.height = BUTTON_DIAMETER;
3227  button->radius = BUTTON_RADIUS;
3228  button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3229  button->fontId = SMALL_BOLD_FONT;
3230  button->obj.touchMask = (1 << TOUCHED);
3231  button->obj.touchId = CHOICE_1_ID;
3232  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) button;
3233  break;
3234  }
3235  case UP_FOOTER_TIP_BOX: {
3236  // text cannot be NULL
3237  if (upFooterDesc->tipBox.text == NULL) {
3238  return -1;
3239  }
3240  obj = layoutAddCallbackObj(layoutInt,
3241  (nbgl_obj_t *) layoutInt->upFooterContainer,
3242  upFooterDesc->tipBox.token,
3243  upFooterDesc->tipBox.tuneId);
3244  if (obj == NULL) {
3245  return -1;
3246  }
3247  layoutInt->upFooterContainer->nbChildren = 3;
3248  layoutInt->upFooterContainer->obj.touchId = TIP_BOX_ID;
3249  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3250 
3251  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3252  textArea->textColor = BLACK;
3253  textArea->text = PIC(upFooterDesc->tipBox.text);
3254  textArea->textAlignment = MID_LEFT;
3255  textArea->fontId = SMALL_REGULAR_FONT;
3256  textArea->wrapping = true;
3257  textArea->obj.area.width = AVAILABLE_WIDTH;
3258  if (upFooterDesc->tipBox.icon != NULL) {
3259  textArea->obj.area.width
3260  -= ((nbgl_icon_details_t *) PIC(upFooterDesc->tipBox.icon))->width
3261  + BORDER_MARGIN;
3262  }
3263  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3264  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3265  textArea->obj.alignment = MID_LEFT;
3266  textArea->obj.alignmentMarginX = BORDER_MARGIN;
3267  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3268  layoutInt->upFooterContainer->obj.area.height = textArea->obj.area.height;
3269 
3270  line = createHorizontalLine(layoutInt->layer);
3271  line->offset = 3;
3272  line->obj.alignment = TOP_MIDDLE;
3273  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) line;
3274 
3275  if (upFooterDesc->tipBox.icon != NULL) {
3276  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
3277  image->obj.alignmentMarginX = BORDER_MARGIN;
3278  image->obj.alignment = MID_RIGHT;
3279  image->foregroundColor = BLACK;
3280  image->buffer = PIC(upFooterDesc->tipBox.icon);
3281  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) image;
3282  if (layoutInt->upFooterContainer->obj.area.height < image->buffer->height) {
3283  layoutInt->upFooterContainer->obj.area.height = image->buffer->height;
3284  }
3285  }
3286  layoutInt->upFooterContainer->obj.area.height += 2 * BOTTOM_BORDER_MARGIN;
3287 
3288  break;
3289  }
3290  case UP_FOOTER_TEXT: {
3291  obj = layoutAddCallbackObj(layoutInt,
3292  (nbgl_obj_t *) layoutInt->upFooterContainer,
3293  upFooterDesc->text.token,
3294  upFooterDesc->text.tuneId);
3295  if (obj == NULL) {
3296  return -1;
3297  }
3298  layoutInt->upFooterContainer->nbChildren = 1;
3299  layoutInt->upFooterContainer->obj.area.height = SMALL_FOOTER_HEIGHT;
3300  layoutInt->upFooterContainer->obj.touchId = WHOLE_SCREEN_ID;
3301  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3302 
3303  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3304  textArea->textColor = DARK_GRAY;
3305  textArea->text = PIC(upFooterDesc->text.text);
3306  textArea->textAlignment = CENTER;
3307  textArea->fontId = SMALL_REGULAR_FONT;
3308  textArea->wrapping = true;
3309  textArea->obj.area.width = AVAILABLE_WIDTH;
3310  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3311  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3312  textArea->obj.alignment = CENTER;
3313  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3314  break;
3315  }
3316  default:
3317  return -2;
3318  }
3319 
3320  // subtract up footer height from main container height
3321  layoutInt->container->obj.area.height -= layoutInt->upFooterContainer->obj.area.height;
3322 
3323  layoutInt->children[UP_FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->upFooterContainer;
3324 
3325  layoutInt->upFooterType = upFooterDesc->type;
3326 
3327  return layoutInt->upFooterContainer->obj.area.height;
3328 }
3329 
3344  uint8_t activePage,
3345  uint8_t nbPages,
3346  bool withBack,
3347  uint8_t backToken,
3348  tune_index_e tuneId)
3349 {
3351  .separationLine = false,
3352  .progressAndBack.activePage = activePage,
3353  .progressAndBack.nbPages = nbPages,
3354  .progressAndBack.token = backToken,
3355  .progressAndBack.tuneId = tuneId,
3356  .progressAndBack.withBack = withBack,
3357  .progressAndBack.actionIcon = NULL,
3358  .progressAndBack.actionToken = NBGL_INVALID_TOKEN};
3359  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressIndicator():\n");
3360 
3361  return nbgl_layoutAddHeader(layout, &headerDesc);
3362 }
3363 
3372 int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, bool fixed)
3373 {
3374  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3375  nbgl_text_area_t *textArea;
3376  nbgl_spinner_t *spinner;
3377 
3378  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSpinner():\n");
3379  if (layout == NULL) {
3380  return -1;
3381  }
3382 
3383  // create spinner
3384  spinner = (nbgl_spinner_t *) nbgl_objPoolGet(SPINNER, layoutInt->layer);
3385  spinner->position = fixed ? 0xFF : 0;
3386  spinner->obj.alignmentMarginY = -20;
3387  spinner->obj.alignTo = NULL;
3388  spinner->obj.alignment = CENTER;
3389  // set this new spinner as child of the container
3390  layoutAddObject(layoutInt, (nbgl_obj_t *) spinner);
3391 
3392  // create text area
3393  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3394  textArea->textColor = BLACK;
3395  textArea->text = PIC(text);
3396  textArea->textAlignment = CENTER;
3397  textArea->fontId = SMALL_REGULAR_FONT;
3398  textArea->wrapping = true;
3399 #ifdef TARGET_STAX
3400  textArea->obj.alignmentMarginY = 20;
3401 #else // TARGET_STAX
3402  textArea->obj.alignmentMarginY = 24;
3403 #endif // TARGET_STAX
3404  textArea->obj.alignTo = (nbgl_obj_t *) spinner;
3405  textArea->obj.alignment = BOTTOM_MIDDLE;
3406  textArea->obj.area.width = AVAILABLE_WIDTH;
3407  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3408  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3409  textArea->style = NO_STYLE;
3410 
3411  // center spinner + text vertically
3412  spinner->obj.alignmentMarginY
3413  = -(textArea->obj.alignmentMarginY + textArea->obj.area.height) / 2;
3414 
3415  // set this new spinner as child of the container
3416  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
3417 
3418  if (!fixed) {
3419  // update ticker to update the spinner periodically
3421 
3422  tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD; // ms
3423  tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD; // ms
3424  tickerCfg.tickerCallback = &spinnerTickerCallback;
3425  nbgl_screenUpdateTicker(layoutInt->layer, &tickerCfg);
3426  }
3427 
3428  return 0;
3429 }
3430 
3438 {
3439  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3440 
3441  if (layout == NULL) {
3442  return -1;
3443  }
3445  "nbgl_layoutDraw(): container.nbChildren =%d, layout->nbChildren = %d\n",
3446  layout->container->nbChildren,
3447  layout->nbChildren);
3448  if (layout->tapText) {
3449  // set this new container as child of main container
3450  layoutAddObject(layout, (nbgl_obj_t *) layout->tapText);
3451  }
3452  if (layout->withLeftBorder == true) {
3453  // draw now the line
3454  nbgl_line_t *line = createLeftVerticalLine(layout->layer);
3455  layout->children[LEFT_BORDER_INDEX] = (nbgl_obj_t *) line;
3456  }
3458 
3459  return 0;
3460 }
3461 
3469 {
3470  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3471  LOG_DEBUG(PAGE_LOGGER, "nbgl_layoutRelease(): \n");
3472  if (layout == NULL) {
3473  return -1;
3474  }
3475  // if modal
3476  if (layout->modal) {
3477  nbgl_screenPop(layout->layer);
3478  }
3479  layout->nbChildren = 0;
3480  return 0;
3481 }
3482 
3483 #endif // HAVE_SE_TOUCH
Random Number Generation.
@ LARGE_CASE_BOLD_INFO
Definition: nbgl_content.h:37
@ NORMAL_INFO
Definition: nbgl_content.h:41
@ LARGE_CASE_GRAY_INFO
Definition: nbgl_content.h:39
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:390
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:352
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.
Definition: nbgl_fonts.c:1040
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:723
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
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:402
Font screen low-Level driver API, to draw elementary forms.
int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueList_t *list)
Creates a list of [tag,value] pairs.
Definition: nbgl_layout.c:1960
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.
Definition: nbgl_layout.c:1673
#define HOLD_TO_APPROVE_STEP_PERCENT
Definition: nbgl_layout.c:134
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,...
Definition: nbgl_layout.c:3043
int nbgl_layoutDraw(nbgl_layout_t *layoutParam)
Applies given layout. The screen will be redrawn.
Definition: nbgl_layout.c:3437
#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:
Definition: nbgl_layout.c:1431
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)
Definition: nbgl_layout.c:1301
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 ...
Definition: nbgl_layout.c:3343
int nbgl_layoutAddNavigationBar(nbgl_layout_t *layout, const nbgl_layoutNavigationBar_t *info)
Creates a navigation bar on bottom of main container.
Definition: nbgl_layout.c:1170
#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
Definition: nbgl_layout.c:2183
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...
Definition: nbgl_layout.c:1789
#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)
Definition: nbgl_layout.c:1513
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...
Definition: nbgl_layout.c:1610
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...
Definition: nbgl_layout.c:2360
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...
Definition: nbgl_layout.c:2112
int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
Creates an area with given text in small regular font, under the header.
Definition: nbgl_layout.c:1335
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 ...
Definition: nbgl_layout.c:1318
int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout)
Creates a touchable bar in main panel.
Definition: nbgl_layout.c:1222
#define SPINNER_REFRESH_PERIOD
Definition: nbgl_layout.c:63
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.
Definition: nbgl_layout.c:1125
const char * get_ux_loc_string(uint32_t index)
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.
Definition: nbgl_layout.c:1084
#define RADIO_CHOICE_HEIGHT
Definition: nbgl_layout.c:52
int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
Creates a switch with the given text and its state.
Definition: nbgl_layout.c:1261
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...
Definition: nbgl_layout.c:1939
listItemType_t
Definition: nbgl_layout.c:85
@ NB_ITEM_TYPES
Definition: nbgl_layout.c:88
@ TOUCHABLE_BAR_ITEM
Definition: nbgl_layout.c:86
@ SWITCH_ITEM
Definition: nbgl_layout.c:87
int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *buttonInfo)
Creates a rounded button in the main container.
Definition: nbgl_layout.c:2203
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,...
Definition: nbgl_layout.c:2649
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.
Definition: nbgl_layout.c:1695
#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,...
Definition: nbgl_layout.c:1916
int nbgl_layoutRelease(nbgl_layout_t *layoutParam)
Release the layout obtained with nbgl_layoutGet()
Definition: nbgl_layout.c:3468
#define BAR_INTERVALE
Definition: nbgl_layout.c:54
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.
Definition: nbgl_layout.c:2305
@ LEFT_HALF_INDEX
Definition: nbgl_layout.c:71
@ PAGE_INDICATOR_INDEX
Definition: nbgl_layout.c:70
@ FIRST_BUTTON_INDEX
Definition: nbgl_layout.c:73
@ RIGHT_HALF_INDEX
Definition: nbgl_layout.c:72
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the main container
Definition: nbgl_layout.c:519
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
Definition: nbgl_layout.c:492
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,...
Definition: nbgl_layout.c:2386
#define BACK_KEY_WIDTH
Definition: nbgl_layout.c:55
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.
Definition: nbgl_layout.c:1196
#define HOLD_TO_APPROVE_STEP_DURATION_MS
Definition: nbgl_layout.c:135
#define FOOTER_BUTTON_HEIGHT
Definition: nbgl_layout.c:56
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...
Definition: nbgl_layout.c:2333
int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text, bool grayedOut)
Creates an area with given text in 32px font (in Black or Light Gray)
Definition: nbgl_layout.c:1377
int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, bool fixed)
Creates a centered (vertically & horizontally) spinner with a text under it.
Definition: nbgl_layout.c:3372
#define UP_FOOTER_BUTTON_HEIGHT
Definition: nbgl_layout.c:57
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
Definition: nbgl_layout.c:995
void(* nbgl_layoutTouchCallback_t)(int token, uint8_t index)
prototype of function to be called when an object is touched
Definition: nbgl_layout.h:104
#define SIMPLE_FOOTER_HEIGHT
Definition: nbgl_layout.h:60
#define LONG_PRESS_BUTTON_HEIGHT
Definition: nbgl_layout.h:63
#define PRE_TEXT_MARGIN
Definition: nbgl_layout.h:75
#define TOUCHABLE_MAIN_BAR_HEIGHT
Definition: nbgl_layout.h:57
#define TEXT_SUBTEXT_MARGIN
Definition: nbgl_layout.h:76
#define TOUCHABLE_BAR_HEIGHT
Definition: nbgl_layout.h:58
@ WHITE_BACKGROUND
rounded bordered button, with text/icon in black, on white background
Definition: nbgl_layout.h:338
@ NO_BORDER
simple clickable text, in black
Definition: nbgl_layout.h:339
@ BLACK_BACKGROUND
rounded bordered button, with text/icon in white, on black background
Definition: nbgl_layout.h:336
#define AVAILABLE_WIDTH
Definition: nbgl_layout.h:66
@ UP_FOOTER_TEXT
grayed-out text, for example "Tap to continue"
Definition: nbgl_layout.h:531
@ NB_UP_FOOTER_TYPES
Definition: nbgl_layout.h:532
@ UP_FOOTER_BUTTON
simple button
Definition: nbgl_layout.h:528
@ UP_FOOTER_LONG_PRESS
long-press button
Definition: nbgl_layout.h:527
@ UP_FOOTER_TIP_BOX
Tip-box.
Definition: nbgl_layout.h:530
@ UP_FOOTER_HORIZONTAL_BUTTONS
2 buttons, on the same line
Definition: nbgl_layout.h:529
void * nbgl_layout_t
type shared externally
Definition: nbgl_layout.h:96
@ HEADER_TITLE
simple centered text
Definition: nbgl_layout.h:420
@ HEADER_BACK_AND_PROGRESS
optional back key and progress indicator (only on Stax)
Definition: nbgl_layout.h:419
@ HEADER_EMPTY
empty space, to have a better vertical centering of centered info
Definition: nbgl_layout.h:417
@ NB_HEADER_TYPES
Definition: nbgl_layout.h:423
@ HEADER_EXTENDED_BACK
back key, centered text and touchable key on the right
Definition: nbgl_layout.h:421
@ HEADER_BACK_AND_TEXT
back key and optional text
Definition: nbgl_layout.h:418
@ HEADER_RIGHT_TEXT
touchable text on the right, with a vertical separation line
Definition: nbgl_layout.h:422
#define SMALL_FOOTER_HEIGHT
Definition: nbgl_layout.h:59
#define NBGL_INVALID_TOKEN
Definition: nbgl_layout.h:33
@ SOFT_ACTION_AND_FOOTER_STYLE
A white button on top of a footer, with a separation line.
Definition: nbgl_layout.h:293
@ ROUNDED_AND_FOOTER_STYLE
A black background button on top of a footer.
Definition: nbgl_layout.h:291
#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:77
#define NBGL_NO_TUNE
Definition: nbgl_layout.h:29
@ FOOTER_SIMPLE_TEXT
simple touchable text in bold
Definition: nbgl_layout.h:476
@ FOOTER_NAV
navigation bar
Definition: nbgl_layout.h:480
@ FOOTER_SIMPLE_BUTTON
simple black or white button (see nbgl_layoutButtonStyle_t)
Definition: nbgl_layout.h:481
@ FOOTER_TEXT_AND_NAV
Definition: nbgl_layout.h:478
@ FOOTER_DOUBLE_TEXT
2 touchable texts in bold, separated by a vertical line (only on Stax)
Definition: nbgl_layout.h:477
@ NB_FOOTER_TYPES
Definition: nbgl_layout.h:483
@ FOOTER_EMPTY
empty space, to have a better vertical centering of centered info
Definition: nbgl_layout.h:475
@ FOOTER_CHOICE_BUTTONS
double buttons (see nbgl_layoutChoiceButtonsStyle_t)
Definition: nbgl_layout.h:482
#define TOUCHABLE_HEADER_BAR_HEIGHT
Definition: nbgl_layout.h:56
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:138
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:221
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:1522
struct PACKED__ nbgl_progress_bar_s nbgl_progress_bar_t
struct to represent a progress bar (PROGRESS_BAR type)
#define SWIPE_MASK
Definition: nbgl_obj.h:167
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.
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:1571
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:135
#define MINI_PUSH_ICON
Definition: nbgl_obj.h:147
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
Definition: nbgl_obj.c:1587
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.
#define BUTTON_DIAMETER
Definition: nbgl_obj.h:88
#define BOTTOM_BORDER_MARGIN
Definition: nbgl_obj.h:72
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
@ CHOICE_1_ID
Definition: nbgl_obj.h:553
@ TOP_RIGHT_BUTTON_ID
Definition: nbgl_obj.h:549
@ LONG_PRESS_BUTTON_ID
Definition: nbgl_obj.h:561
@ CONTROLS_ID
Definition: nbgl_obj.h:563
@ RIGHT_BUTTON_ID
Definition: nbgl_obj.h:547
@ WHOLE_SCREEN_ID
Definition: nbgl_obj.h:548
@ BOTTOM_BUTTON_ID
Definition: nbgl_obj.h:545
@ SINGLE_BUTTON_ID
Definition: nbgl_obj.h:551
@ BACK_BUTTON_ID
Definition: nbgl_obj.h:550
@ VALUE_BUTTON_1_ID
Definition: nbgl_obj.h:558
@ TIP_BOX_ID
Definition: nbgl_obj.h:562
@ EXTRA_BUTTON_ID
Definition: nbgl_obj.h:552
@ CHOICE_2_ID
Definition: nbgl_obj.h:554
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:139
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...
Definition: nbgl_screen.c:225
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....
Definition: nbgl_screen.c:330
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.
Definition: nbgl_screen.c:289
int nbgl_screenPop(uint8_t screenIndex)
Release the screen at the given index in screen array (index returned by nbgl_screenPush())....
Definition: nbgl_screen.c:403
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:402
color_t
Definition: nbgl_types.h:101
@ WHITE
Definition: nbgl_types.h:105
@ DARK_GRAY
Definition: nbgl_types.h:103
@ LIGHT_GRAY
Definition: nbgl_types.h:104
@ BLACK
Definition: nbgl_types.h:102
nbgl_state_t
to represent a boolean state.
Definition: nbgl_types.h:160
@ ON_STATE
Definition: nbgl_types.h:162
@ OFF_STATE
Definition: nbgl_types.h:161
@ POST_REFRESH_FORCE_POWER_OFF
Force screen power off after refresh.
Definition: nbgl_types.h:316
@ POST_REFRESH_FORCE_POWER_ON_WITH_PIPELINE
Force screen power on and enable pipeline.
Definition: nbgl_types.h:318
#define SCREEN_WIDTH
Definition: nbgl_types.h:32
@ RADIUS_32_PIXELS
32 pixels
Definition: nbgl_types.h:328
nbgl_touchType_t
The different types of Touchscreen events.
Definition: nbgl_types.h:220
@ SWIPED_LEFT
Definition: nbgl_types.h:236
@ SWIPED_UP
Definition: nbgl_types.h:233
@ SWIPED_DOWN
Definition: nbgl_types.h:234
@ SWIPED_RIGHT
Definition: nbgl_types.h:235
@ TOUCH_RELEASED
Definition: nbgl_types.h:230
@ TOUCHED
Definition: nbgl_types.h:221
@ TOUCHING
corresponding to an object that is currently touched
Definition: nbgl_types.h:225
@ OUT_OF_TOUCH
Definition: nbgl_types.h:226
@ QRCODE_V10
QRCode V10, can encode text len up to 1500 chars, display size = 228*228.
Definition: nbgl_types.h:192
@ QRCODE_V4_SMALL
QRCode V4, can encode text len up to 1500 chars, display size = 132*132.
Definition: nbgl_types.h:193
@ QRCODE_V4
QRCode V4, can encode text len up to 62 chars, display size = 264*264.
Definition: nbgl_types.h:191
@ VERTICAL
from top to bottom
Definition: nbgl_types.h:170
@ HORIZONTAL
from left to right
Definition: nbgl_types.h:171
#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:143
@ CENTER
Definition: nbgl_types.h:146
@ BOTTOM_RIGHT
Definition: nbgl_types.h:150
@ TOP_LEFT
Definition: nbgl_types.h:142
@ NO_ALIGNMENT
used when parent container layout is used
Definition: nbgl_types.h:141
@ BOTTOM_LEFT
Definition: nbgl_types.h:148
@ MID_RIGHT
Definition: nbgl_types.h:147
@ RIGHT_TOP
on outside right
Definition: nbgl_types.h:153
@ TOP_RIGHT
Definition: nbgl_types.h:144
@ MID_LEFT
Definition: nbgl_types.h:145
@ BOTTOM_MIDDLE
Definition: nbgl_types.h:149
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition: nbgl_types.h:118
@ SWITCH
Switch to turn on/off something.
Definition: nbgl_types.h:122
@ RADIO_BUTTON
Indicator to inform whether something is on or off.
Definition: nbgl_types.h:125
@ SPINNER
Spinner.
Definition: nbgl_types.h:129
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition: nbgl_types.h:121
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
Definition: nbgl_types.h:124
@ QR_CODE
QR Code.
Definition: nbgl_types.h:126
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition: nbgl_types.h:123
@ LINE
Vertical or Horizontal line.
Definition: nbgl_types.h:119
@ CONTAINER
Empty container.
Definition: nbgl_types.h:117
@ TEXT_AREA
Area to contain text line(s)
Definition: nbgl_types.h:120
#define MAX(x, y)
Definition: nbgl_types.h:82
@ NBGL_BPP_1
1 bit per pixel
Definition: nbgl_types.h:245
@ NO_STYLE
no border
Definition: nbgl_types.h:179
@ BLACK_AND_WHITE_REFRESH
to be used for pure B&W area, when contrast is important
Definition: nbgl_types.h:291
@ BLACK_AND_WHITE_FAST_REFRESH
to be used for pure B&W area, when contrast is not priority
Definition: nbgl_types.h:292
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition: nbgl_types.h:289
nbgl_obj_t * obj
tune_index_e tuneId
nbgl_state_t state
Definition: nbgl_layout.c:101
const char * text
Definition: nbgl_layout.c:98
const nbgl_icon_details_t * iconRight
Definition: nbgl_layout.c:96
const char * subText
Definition: nbgl_layout.c:99
listItemType_t type
Definition: nbgl_layout.c:93
uint8_t token
Definition: nbgl_layout.c:100
const nbgl_icon_details_t * iconLeft
Definition: nbgl_layout.c:94
This structure contains info to build a centered (vertically and horizontally) area,...
Definition: nbgl_content.h:81
uint16_t iconHug
vertical margin to apply on top and bottom of the icon
Definition: nbgl_content.h:87
const nbgl_icon_details_t * icon
the icon (can be null)
Definition: nbgl_content.h:82
const char * title
title in black large (can be null)
Definition: nbgl_content.h:83
const char * description
description in black small regular case (can be null)
Definition: nbgl_content.h:85
const char * subText
sub-text in dark gray regular small case
Definition: nbgl_content.h:86
bool padding
if true, apply a padding of 40px at the bottom
Definition: nbgl_content.h:88
const char * smallTitle
sub-title in black small bold case (can be null)
Definition: nbgl_content.h:84
This structure contains info to build a centered (vertically and horizontally) area,...
Definition: nbgl_content.h:57
const char * text2
second text (can be null)
Definition: nbgl_content.h:59
const char * text1
first text (can be null)
Definition: nbgl_content.h:58
bool onTop
if set to true, align only horizontally
Definition: nbgl_content.h:64
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
Definition: nbgl_content.h:65
int16_t offsetY
vertical shift to apply to this info (if >0, shift to bottom)
Definition: nbgl_content.h:67
const char * text3
third text (can be null)
Definition: nbgl_content.h:61
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
Definition: nbgl_content.h:63
This structure contains a list of names to build a list of radio buttons (on the right part of screen...
Definition: nbgl_content.h:286
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:296
bool localized
if set to true, use nameIds and not names
Definition: nbgl_content.h:293
uint8_t initChoice
index of the current choice
Definition: nbgl_content.h:295
const char *const * names
array of strings giving the choices (nbChoices)
Definition: nbgl_content.h:288
uint8_t nbChoices
number of choices
Definition: nbgl_content.h:294
This structure contains info to build a switch (on the right) with a description (on the left),...
Definition: nbgl_content.h:246
const char * text
main text for the switch
Definition: nbgl_content.h:247
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:251
nbgl_state_t initState
initial state of the switch
Definition: nbgl_content.h:250
const char * subText
description under main text (NULL terminated, single line, may be null)
Definition: nbgl_content.h:249
This structure contains a list of [tag,value] pairs.
Definition: nbgl_content.h:185
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
Definition: nbgl_content.h:187
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
Definition: nbgl_content.h:198
uint8_t startIndex
index of the first pair to get with callback
Definition: nbgl_content.h:191
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
Definition: nbgl_content.h:188
This structure contains a [tag,value] pair.
Definition: nbgl_content.h:148
const nbgl_icon_details_t * valueIcon
Definition: nbgl_content.h:153
const char * value
string giving the value name
Definition: nbgl_content.h:150
const char * item
string giving the tag name
Definition: nbgl_content.h:149
const char * text
text of the tip-box
Definition: nbgl_content.h:320
const nbgl_icon_details_t * icon
icon of the tip-box
Definition: nbgl_content.h:321
uint8_t token
token used when tip-box is tapped
Definition: nbgl_content.h:322
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.
Definition: nbgl_layout.h:197
bool inactive
if set to true, the bar is grayed-out and cannot be touched
Definition: nbgl_layout.h:206
const char * text
text (can be NULL)
Definition: nbgl_layout.h:200
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:205
bool large
set to true only for the main level of OS settings
Definition: nbgl_layout.h:204
const char * subText
sub text (can be NULL)
Definition: nbgl_layout.h:203
const nbgl_icon_details_t * iconLeft
a buffer containing the 1BPP icon for icon on left (can be NULL)
Definition: nbgl_layout.h:199
const nbgl_icon_details_t * iconRight
Definition: nbgl_layout.h:201
This structure contains info to build a single button.
Definition: nbgl_layout.h:346
const char * text
button text
Definition: nbgl_layout.h:347
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:349
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon for button
Definition: nbgl_layout.h:348
nbgl_layoutButtonStyle_t style
Definition: nbgl_layout.h:350
bool fittingContent
if set to true, fit the width of button to text, otherwise full width
Definition: nbgl_layout.h:351
This structure contains info to build a pair of buttons, one on top of the other.
Definition: nbgl_layout.h:304
nbgl_layoutChoiceButtonsStyle_t style
the style of the pair
Definition: nbgl_layout.h:309
const nbgl_icon_details_t * topIcon
icon of top button
Definition: nbgl_layout.h:307
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:308
const char * topText
up-button text (index 0)
Definition: nbgl_layout.h:305
const char * bottomText
bottom-button text (index 1)
Definition: nbgl_layout.h:306
Structure containing all information when creating a layout. This structure must be passed as argumen...
Definition: nbgl_layout.h:171
nbgl_screenTickerConfiguration_t ticker
Definition: nbgl_layout.h:190
const char * tapActionText
Light gray text used when main container is "tapable".
Definition: nbgl_layout.h:177
nbgl_layoutTouchCallback_t onActionCallback
the callback to be called on any action on the layout
Definition: nbgl_layout.h:185
This structure contains info to build an extended footer.
Definition: nbgl_layout.h:490
nbgl_layoutChoiceButtons_t choiceButtons
if type is FOOTER_CHOICE_BUTTONS
Definition: nbgl_layout.h:518
struct nbgl_layoutFooter_t::@15::@17 emptySpace
if type is FOOTER_EMPTY
bool separationLine
if true, a separation line is added at the top of this control
Definition: nbgl_layout.h:492
struct nbgl_layoutFooter_t::@15::@18 simpleText
if type is FOOTER_SIMPLE_TEXT
nbgl_layoutButton_t button
if type is FOOTER_SIMPLE_BUTTON
Definition: nbgl_layout.h:517
nbgl_layoutFooterType_t type
type of footer
Definition: nbgl_layout.h:491
nbgl_layoutNavigationBar_t navigation
if type is FOOTER_NAV
Definition: nbgl_layout.h:511
struct nbgl_layoutFooter_t::@15::@20 textAndNav
if type is FOOTER_TEXT_AND_NAV
struct nbgl_layoutFooter_t::@15::@19 doubleText
if type is FOOTER_DOUBLE_TEXT
This structure contains info to build a header.
Definition: nbgl_layout.h:430
nbgl_layoutHeaderType_t type
type of header
Definition: nbgl_layout.h:431
struct nbgl_layoutHeader_t::@7::@12 title
if type is HEADER_TITLE
struct nbgl_layoutHeader_t::@7::@10 backAndText
if type is HEADER_BACK_AND_TEXT
bool separationLine
if true, a separation line is added at the bottom of this control
Definition: nbgl_layout.h:432
struct nbgl_layoutHeader_t::@7::@13 extendedBack
if type is HEADER_EXTENDED_BACK
struct nbgl_layoutHeader_t::@7::@11 progressAndBack
if type is HEADER_BACK_AND_PROGRESS
struct nbgl_layoutHeader_t::@7::@9 emptySpace
if type is HEADER_EMPTY
struct nbgl_layoutHeader_t::@7::@14 rightText
if type is HEADER_RIGHT_TEXT
This structure contains info to build a pair of buttons, the small one, with icon,...
Definition: nbgl_layout.h:321
const nbgl_icon_details_t * leftIcon
a buffer containing the 1BPP icon for left button
Definition: nbgl_layout.h:322
uint8_t leftToken
the token used when left button is pressed
Definition: nbgl_layout.h:324
uint8_t rightToken
the token used when right button is pressed
Definition: nbgl_layout.h:325
const char * rightText
right-button text
Definition: nbgl_layout.h:323
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.
Definition: nbgl_layout.h:262
uint8_t nbRows
number of rows in the area
Definition: nbgl_layout.h:263
const char * title
title of area in bold
Definition: nbgl_layout.h:264
const nbgl_icon_details_t ** rowIcons
array of nbRows icon
Definition: nbgl_layout.h:266
const char ** rowTexts
array of nbRows texts (displayed in regular)
Definition: nbgl_layout.h:265
This structure contains info to build a navigation bar at the bottom of the screen.
Definition: nbgl_layout.h:118
uint8_t activePage
index of active page (from 0 to nbPages-1).
Definition: nbgl_layout.h:121
bool withBackKey
if set to true, the "back" key is drawn
Definition: nbgl_layout.h:123
bool withExitKey
if set to true, an exit button is drawn (X on the left)
Definition: nbgl_layout.h:122
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:119
uint8_t nbPages
number of pages. (if 0, no navigation)
Definition: nbgl_layout.h:120
This structure contains info to build a progress bar with info. The progress bar itself is 120px widt...
Definition: nbgl_layout.h:565
uint8_t percentage
percentage of completion, from 0 to 100.
Definition: nbgl_layout.h:566
const char * text
text in black, on top of progress bar
Definition: nbgl_layout.h:567
const char * subText
text in gray, under progress bar
Definition: nbgl_layout.h:568
This structure contains info to build a centered (vertically and horizontally) area,...
Definition: nbgl_layout.h:277
const char * text2
second text (can be null)
Definition: nbgl_layout.h:280
const char * text1
first text (can be null)
Definition: nbgl_layout.h:279
const char * url
URL for QR code.
Definition: nbgl_layout.h:278
bool largeText1
if set to true, use 32px font for text1
Definition: nbgl_layout.h:283
int16_t offsetY
vertical shift to apply to this info (if > 0, shift to bottom)
Definition: nbgl_layout.h:281
bool centered
if set to true, center vertically
Definition: nbgl_layout.h:282
This structure contains info to build an up-footer (area on top of footer).
Definition: nbgl_layout.h:539
nbgl_layoutButton_t button
if type is UP_FOOTER_BUTTON
Definition: nbgl_layout.h:547
nbgl_contentTipBox_t tipBox
if type is UP_FOOTER_TIP_BOX
Definition: nbgl_layout.h:550
const char * text
text in the long-press button
Definition: nbgl_layout.h:543
nbgl_layoutUpFooterType_t type
type of up-footer
Definition: nbgl_layout.h:540
nbgl_layoutHorizontalButtons_t horizontalButtons
if type is UP_FOOTER_HORIZONTAL_BUTTONS
Definition: nbgl_layout.h:549
struct nbgl_layoutUpFooter_t::@21::@23 longPress
if type is UP_FOOTER_LONG_PRESS
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