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 /**********************
882  * GLOBAL FUNCTIONS
883  **********************/
884 
892 {
893  nbgl_layoutInternal_t *layout = NULL;
894 
895  // find an empty layout in the proper "layer"
896  if (description->modal) {
897  if (gLayout[1].nbChildren == 0) {
898  layout = &gLayout[1];
899  }
900  else if (gLayout[2].nbChildren == 0) {
901  layout = &gLayout[2];
902  }
903  }
904  else {
905  // automatically "release" a potentially opened non-modal layout
906  gLayout[0].nbChildren = 0;
907  layout = &gLayout[0];
908  }
909  if (layout == NULL) {
910  LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutGet(): impossible to get a layout!\n");
911  return NULL;
912  }
913 
914  // reset globals
915  memset(layout, 0, sizeof(nbgl_layoutInternal_t));
916 
917  nbTouchableControls = 0;
918 
919  layout->callback = (nbgl_layoutTouchCallback_t) PIC(description->onActionCallback);
920  layout->modal = description->modal;
921  layout->withLeftBorder = description->withLeftBorder;
922  if (description->modal) {
923  layout->layer = nbgl_screenPush(&layout->children,
925  &description->ticker,
926  (nbgl_touchCallback_t) touchCallback);
927  }
928  else {
929  nbgl_screenSet(&layout->children,
931  &description->ticker,
932  (nbgl_touchCallback_t) touchCallback);
933  layout->layer = 0;
934  }
935  layout->container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layout->layer);
936  layout->container->obj.area.width = SCREEN_WIDTH;
937  layout->container->obj.area.height = SCREEN_HEIGHT;
938  layout->container->layout = VERTICAL;
939  layout->container->children = nbgl_containerPoolGet(NB_MAX_CONTAINER_CHILDREN, layout->layer);
940  // by default, if no header, main container is aligned on top-left
941  layout->container->obj.alignment = TOP_LEFT;
942  // main container is always the second object, leaving space for header
943  layout->children[MAIN_CONTAINER_INDEX] = (nbgl_obj_t *) layout->container;
945 
946  // if a tap text is defined, make the container tapable and display this text in gray
947  if (description->tapActionText != NULL) {
948  layoutObj_t *obj;
949 
950  obj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
951  layout->nbUsedCallbackObjs++;
952  obj->obj = (nbgl_obj_t *) layout->container;
953  obj->token = description->tapActionToken;
954  obj->tuneId = description->tapTuneId;
955  layout->container->obj.touchMask = (1 << TOUCHED);
956  layout->container->obj.touchId = WHOLE_SCREEN_ID;
957 
958  nbgl_layoutUpFooter_t footerDesc;
959  footerDesc.type = UP_FOOTER_TEXT;
960  footerDesc.text.text = PIC(description->tapActionText);
961  footerDesc.text.token = description->tapActionToken;
962  footerDesc.text.tuneId = description->tapTuneId;
963  nbgl_layoutAddUpFooter((nbgl_layout_t *) layout, &footerDesc);
964  }
965 
966  return (nbgl_layout_t *) layout;
967 }
968 
981  uint16_t swipesMask,
982  const char *text,
983  uint8_t token,
984  tune_index_e tuneId)
985 {
986  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
987 
988  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwipe():\n");
989  if (layout == NULL) {
990  return -1;
991  }
992 
993  if (text) {
994  // create 'tap to continue' text area
995  layoutInt->tapText = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0);
996  layoutInt->tapText->text = PIC(text);
997  layoutInt->tapText->textColor = DARK_GRAY;
998  layoutInt->tapText->fontId = SMALL_REGULAR_FONT;
999  layoutInt->tapText->obj.area.width = AVAILABLE_WIDTH;
1000  layoutInt->tapText->obj.area.height = nbgl_getFontLineHeight(layoutInt->tapText->fontId);
1001  layoutInt->tapText->textAlignment = CENTER;
1002 #ifdef TARGET_STAX
1003  layoutInt->tapText->obj.alignmentMarginY = BORDER_MARGIN;
1004 #else // TARGET_STAX
1005  layoutInt->tapText->obj.alignmentMarginY = 30;
1006 #endif // TARGET_STAX
1007  layoutInt->tapText->obj.alignment = BOTTOM_MIDDLE;
1008  }
1009  return addSwipeInternal(layoutInt, swipesMask, SWIPE_USAGE_CUSTOM, token, tuneId);
1010 }
1011 
1022  const nbgl_icon_details_t *icon,
1023  uint8_t token,
1024  tune_index_e tuneId)
1025 {
1026  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1027  layoutObj_t *obj;
1028  nbgl_button_t *button;
1029 
1030  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTopRightButton():\n");
1031  if (layout == NULL) {
1032  return -1;
1033  }
1034  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
1035  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
1036  if (obj == NULL) {
1037  return -1;
1038  }
1039 
1040  button->obj.area.width = BUTTON_DIAMETER;
1041  button->obj.area.height = BUTTON_DIAMETER;
1042  button->radius = BUTTON_RADIUS;
1043  button->obj.alignmentMarginX = BORDER_MARGIN;
1044  button->obj.alignmentMarginY = BORDER_MARGIN;
1045  button->foregroundColor = BLACK;
1046  button->innerColor = WHITE;
1047  button->borderColor = LIGHT_GRAY;
1048  button->obj.touchMask = (1 << TOUCHED);
1049  button->obj.touchId = TOP_RIGHT_BUTTON_ID;
1050  button->icon = PIC(icon);
1051  button->obj.alignment = TOP_RIGHT;
1052 
1053  // add to screen
1054  layoutInt->children[TOP_RIGHT_BUTTON_INDEX] = (nbgl_obj_t *) button;
1055 
1056  return 0;
1057 }
1058 
1067 {
1068  nbgl_layoutFooter_t footerDesc;
1069  footerDesc.type = FOOTER_NAV;
1070  footerDesc.separationLine = info->withSeparationLine;
1071  footerDesc.navigation.activePage = info->activePage;
1072  footerDesc.navigation.nbPages = info->nbPages;
1073  footerDesc.navigation.withExitKey = info->withExitKey;
1074  footerDesc.navigation.withBackKey = info->withBackKey;
1075  footerDesc.navigation.withPageIndicator = false;
1076  footerDesc.navigation.token = info->token;
1077  footerDesc.navigation.tuneId = info->tuneId;
1078  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1079 }
1080 
1093  const nbgl_icon_details_t *icon,
1094  uint8_t token,
1095  bool separationLine,
1096  tune_index_e tuneId)
1097 {
1098  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddBottomButton():\n");
1099  nbgl_layoutFooter_t footerDesc;
1100  footerDesc.type = FOOTER_SIMPLE_BUTTON;
1101  footerDesc.separationLine = separationLine;
1102  footerDesc.button.fittingContent = false;
1103  footerDesc.button.icon = PIC(icon);
1104  footerDesc.button.text = NULL;
1105  footerDesc.button.token = token;
1106  footerDesc.button.tuneId = tuneId;
1107  footerDesc.button.style = WHITE_BACKGROUND;
1108  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1109 }
1110 
1119 {
1120  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1121  nbgl_container_t *container;
1122  listItem_t itemDesc;
1123 
1124  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar():\n");
1125  if (layout == NULL) {
1126  return -1;
1127  }
1128  // main text is mandatory
1129  if (barLayout->text == NULL) {
1130  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar(): main text is mandatory\n");
1131  }
1132 
1133  itemDesc.iconLeft = barLayout->iconLeft;
1134  itemDesc.iconRight = barLayout->iconRight;
1135  itemDesc.text = barLayout->text;
1136  itemDesc.subText = barLayout->subText;
1137  itemDesc.token = barLayout->token;
1138  itemDesc.tuneId = barLayout->tuneId;
1139  itemDesc.state = (barLayout->inactive) ? OFF_STATE : ON_STATE;
1140  itemDesc.large = barLayout->large;
1141  itemDesc.type = TOUCHABLE_BAR_ITEM;
1142  container = addListItem(layoutInt, &itemDesc);
1143 
1144  if (container == NULL) {
1145  return -1;
1146  }
1147  return container->obj.area.height;
1148 }
1149 
1157 int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
1158 {
1159  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1160  nbgl_container_t *container;
1161  listItem_t itemDesc;
1162 
1163  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwitch():\n");
1164  if (layout == NULL) {
1165  return -1;
1166  }
1167  // main text is mandatory
1168  if (switchLayout->text == NULL) {
1169  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddSwitch(): main text is mandatory\n");
1170  }
1171 
1172  itemDesc.iconLeft = NULL;
1173  itemDesc.iconRight = NULL;
1174  itemDesc.text = switchLayout->text;
1175  itemDesc.subText = switchLayout->subText;
1176  itemDesc.token = switchLayout->token;
1177  itemDesc.tuneId = switchLayout->tuneId;
1178  itemDesc.state = switchLayout->initState;
1179  itemDesc.large = false;
1180  itemDesc.type = SWITCH_ITEM;
1181  container = addListItem(layoutInt, &itemDesc);
1182 
1183  if (container == NULL) {
1184  return -1;
1185  }
1186  return container->obj.area.height;
1187 }
1188 
1197 int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
1198 {
1199  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1200  nbgl_container_t *container;
1201  nbgl_text_area_t *textArea;
1202  nbgl_text_area_t *subTextArea;
1203  uint16_t fullHeight = 0;
1204 
1205  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddText():\n");
1206  if (layout == NULL) {
1207  return -1;
1208  }
1209  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1210 
1211  // get container children
1212  container->children = nbgl_containerPoolGet(2, layoutInt->layer);
1213  container->obj.area.width = AVAILABLE_WIDTH;
1214 
1215  if (text != NULL) {
1216  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1217 
1218  textArea->textColor = BLACK;
1219  textArea->text = PIC(text);
1220  textArea->textAlignment = MID_LEFT;
1221  textArea->fontId = SMALL_BOLD_FONT;
1222  textArea->style = NO_STYLE;
1223  textArea->wrapping = true;
1224  textArea->obj.alignment = NO_ALIGNMENT;
1225  textArea->obj.alignmentMarginY = PRE_TEXT_MARGIN;
1226  textArea->obj.area.width = container->obj.area.width;
1227  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1228  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1229  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1230  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1231  container->nbChildren++;
1232  }
1233  if (subText != NULL) {
1234  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1235  subTextArea->textColor = BLACK;
1236  subTextArea->text = PIC(subText);
1237  subTextArea->fontId = SMALL_REGULAR_FONT;
1238  subTextArea->style = NO_STYLE;
1239  subTextArea->wrapping = true;
1240  subTextArea->obj.area.width = container->obj.area.width;
1241  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
1242  subTextArea->text,
1243  subTextArea->obj.area.width,
1244  subTextArea->wrapping);
1245  subTextArea->textAlignment = MID_LEFT;
1246  subTextArea->obj.alignment = NO_ALIGNMENT;
1247  if (text != NULL) {
1248  subTextArea->obj.alignmentMarginY = TEXT_SUBTEXT_MARGIN;
1249  fullHeight += POST_SUBTEXT_MARGIN; // under the subText
1250  }
1251  else {
1252 #ifdef TARGET_STAX
1253  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
1254  fullHeight += BORDER_MARGIN;
1255 #else // TARGET_STAX
1256  subTextArea->obj.alignmentMarginY = 26;
1257  fullHeight += 26; // under the subText
1258 #endif // TARGET_STAX
1259  }
1260  container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
1261  container->nbChildren++;
1262  fullHeight += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
1263  }
1264  else {
1265  fullHeight += PRE_TEXT_MARGIN;
1266  }
1267  container->obj.area.height = fullHeight;
1268  container->layout = VERTICAL;
1269  container->obj.alignmentMarginX = BORDER_MARGIN;
1270  container->obj.alignment = NO_ALIGNMENT;
1271  // set this new obj as child of main container
1272  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1273 
1274  return container->obj.area.height;
1275 }
1276 
1284 int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
1285 {
1286  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1287  nbgl_text_area_t *textArea;
1288 
1289  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSubHeaderText():\n");
1290  if (layout == NULL) {
1291  return -1;
1292  }
1293  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1294 
1295  textArea->textColor = BLACK;
1296  textArea->text = PIC(text);
1297  textArea->textAlignment = MID_LEFT;
1298  textArea->fontId = SMALL_REGULAR_FONT;
1299  textArea->style = NO_STYLE;
1300  textArea->wrapping = true;
1301  textArea->obj.alignment = NO_ALIGNMENT;
1302  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1303  textArea->obj.area.width = AVAILABLE_WIDTH;
1304  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1305  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1306 #ifdef TARGET_STAX
1307  textArea->obj.area.height += 2 * 24;
1308 #else // TARGET_STAX
1309  textArea->obj.area.height += 2 * 28;
1310 #endif // TARGET_STAX
1311 
1312  // set this new obj as child of main container
1313  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1314 
1315  return textArea->obj.area.height;
1316 }
1317 
1325 int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text)
1326 {
1327  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1328  nbgl_text_area_t *textArea;
1329 
1330  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLargeCaseText():\n");
1331  if (layout == NULL) {
1332  return -1;
1333  }
1334  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1335 
1336  textArea->textColor = BLACK;
1337  textArea->text = PIC(text);
1338  textArea->textAlignment = MID_LEFT;
1339  textArea->fontId = LARGE_MEDIUM_FONT;
1340  textArea->obj.area.width = AVAILABLE_WIDTH;
1341  textArea->wrapping = true;
1342  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1343  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1344  textArea->style = NO_STYLE;
1345  textArea->obj.alignment = NO_ALIGNMENT;
1346  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1347 #ifdef TARGET_STAX
1348  // if first object of container, increase the margin from top
1349  if (layoutInt->container->nbChildren == 0) {
1350  textArea->obj.alignmentMarginY += BORDER_MARGIN;
1351  }
1352 #endif // TARGET_STAX
1353 
1354  // set this new obj as child of main container
1355  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1356 
1357  return 0;
1358 }
1359 
1373  const char *title,
1374  const char *description,
1375  const char *info)
1376 {
1377  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1378  nbgl_text_area_t *textArea;
1379 
1380  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextContent():\n");
1381  if (layout == NULL) {
1382  return -1;
1383  }
1384 
1385  // create title
1386  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1387  textArea->textColor = BLACK;
1388  textArea->text = PIC(title);
1389  textArea->textAlignment = MID_LEFT;
1390  textArea->fontId = LARGE_MEDIUM_FONT;
1391  textArea->style = NO_STYLE;
1392  textArea->wrapping = true;
1393  textArea->obj.alignment = NO_ALIGNMENT;
1394  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1395 #ifdef TARGET_STAX
1396  textArea->obj.alignmentMarginY = 24;
1397 #else // TARGET_STAX
1398  textArea->obj.alignmentMarginY = 16;
1399 #endif // TARGET_STAX
1400  textArea->obj.area.width = AVAILABLE_WIDTH;
1401  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1402  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1403  // set this new obj as child of main container
1404  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1405 
1406  // create description
1407  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1408  textArea->textColor = BLACK;
1409  textArea->text = PIC(description);
1410  textArea->fontId = SMALL_REGULAR_FONT;
1411  textArea->style = NO_STYLE;
1412  textArea->wrapping = true;
1413  textArea->obj.area.width = AVAILABLE_WIDTH;
1414  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1415  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1416  textArea->textAlignment = MID_LEFT;
1417  textArea->obj.alignment = NO_ALIGNMENT;
1418  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1419 #ifdef TARGET_STAX
1420  textArea->obj.alignmentMarginY = 16;
1421 #else // TARGET_STAX
1422  textArea->obj.alignmentMarginY = 24;
1423 #endif // TARGET_STAX
1424  // set this new obj as child of main container
1425  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1426 
1427  // create info on the bottom
1428  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1429  textArea->textColor = DARK_GRAY;
1430  textArea->text = PIC(info);
1431  textArea->fontId = SMALL_REGULAR_FONT;
1432  textArea->style = NO_STYLE;
1433  textArea->wrapping = true;
1434  textArea->obj.area.width = AVAILABLE_WIDTH;
1435  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1436  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1437  textArea->textAlignment = MID_LEFT;
1438  textArea->obj.alignment = BOTTOM_LEFT;
1439  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1440  textArea->obj.alignmentMarginY = 40;
1441  // set this new obj as child of main container
1442  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1443 
1444  return layoutInt->container->obj.area.height;
1445 }
1446 
1455 {
1456  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1457  layoutObj_t *obj;
1458  uint8_t i;
1459 
1460  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddRadioChoice():\n");
1461  if (layout == NULL) {
1462  return -1;
1463  }
1464  for (i = 0; i < choices->nbChoices; i++) {
1465  nbgl_container_t *container;
1466  nbgl_text_area_t *textArea;
1467  nbgl_radio_t *button;
1468  nbgl_line_t *line;
1469 
1470  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1471  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1472  button = (nbgl_radio_t *) nbgl_objPoolGet(RADIO_BUTTON, layoutInt->layer);
1473 
1474  obj = layoutAddCallbackObj(
1475  layoutInt, (nbgl_obj_t *) container, choices->token, choices->tuneId);
1476  if (obj == NULL) {
1477  return -1;
1478  }
1479 
1480  // get container children (max 2)
1481  container->nbChildren = 2;
1482  container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
1483  container->obj.area.width = AVAILABLE_WIDTH;
1484  container->obj.area.height = RADIO_CHOICE_HEIGHT;
1485  container->obj.alignment = NO_ALIGNMENT;
1486  container->obj.alignmentMarginX = BORDER_MARGIN;
1487  container->obj.alignTo = (nbgl_obj_t *) NULL;
1488 
1489  // init button for this choice
1490  button->activeColor = BLACK;
1491  button->borderColor = LIGHT_GRAY;
1492  button->obj.alignTo = (nbgl_obj_t *) container;
1493  button->obj.alignment = MID_RIGHT;
1494  button->state = OFF_STATE;
1495  container->children[1] = (nbgl_obj_t *) button;
1496 
1497  // init text area for this choice
1498  if (choices->localized == true) {
1499 #ifdef HAVE_LANGUAGE_PACK
1500  textArea->text = get_ux_loc_string(choices->nameIds[i]);
1501 #endif // HAVE_LANGUAGE_PACK
1502  }
1503  else {
1504  textArea->text = PIC(choices->names[i]);
1505  }
1506  textArea->textAlignment = MID_LEFT;
1507  textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH;
1508  textArea->style = NO_STYLE;
1509  textArea->obj.alignment = MID_LEFT;
1510  textArea->obj.alignTo = (nbgl_obj_t *) container;
1511  container->children[0] = (nbgl_obj_t *) textArea;
1512 
1513  // whole container should be touchable
1514  container->obj.touchMask = (1 << TOUCHED);
1515  container->obj.touchId = CONTROLS_ID + nbTouchableControls;
1516  nbTouchableControls++;
1517 
1518  // highlight init choice
1519  if (i == choices->initChoice) {
1520  button->state = ON_STATE;
1521  textArea->textColor = BLACK;
1522  textArea->fontId = SMALL_BOLD_FONT;
1523  }
1524  else {
1525  button->state = OFF_STATE;
1526  textArea->textColor = DARK_GRAY;
1527  textArea->fontId = SMALL_REGULAR_FONT;
1528  }
1529  textArea->obj.area.height = nbgl_getFontHeight(textArea->fontId);
1530 
1531  line = createHorizontalLine(layoutInt->layer);
1532  line->obj.alignmentMarginY = -4;
1533  line->offset = 3;
1534 
1535  // set these new objs as child of main container
1536  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1537  layoutAddObject(layoutInt, (nbgl_obj_t *) line);
1538  }
1539 
1540  return 0;
1541 }
1542 
1552 {
1553  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1554  nbgl_container_t *container;
1555  nbgl_contentCenter_t centeredInfo = {.icon = info->icon,
1556  .title = NULL,
1557  .smallTitle = NULL,
1558  .description = NULL,
1559  .subText = NULL,
1560  .iconHug = 0,
1561  .padding = false};
1562 
1563  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddCenteredInfo():\n");
1564  if (layout == NULL) {
1565  return -1;
1566  }
1567 
1568  if (info->text1 != NULL) {
1569  if (info->style != NORMAL_INFO) {
1570  centeredInfo.title = info->text1;
1571  }
1572  else {
1573  centeredInfo.smallTitle = info->text1;
1574  }
1575  }
1576  if (info->text2 != NULL) {
1577  if (info->style != LARGE_CASE_BOLD_INFO) {
1578  centeredInfo.description = info->text2;
1579  }
1580  else {
1581  centeredInfo.smallTitle = info->text2;
1582  }
1583  }
1584  if (info->text3 != NULL) {
1585  if (info->style == LARGE_CASE_GRAY_INFO) {
1586  centeredInfo.subText = info->text3;
1587  }
1588  else {
1589  centeredInfo.description = info->text3;
1590  }
1591  }
1592  container = addContentCenter(layoutInt, &centeredInfo);
1593 
1594  if (info->onTop) {
1595  container->obj.alignmentMarginX = BORDER_MARGIN;
1596  container->obj.alignmentMarginY = BORDER_MARGIN + info->offsetY;
1597  container->obj.alignment = NO_ALIGNMENT;
1598  }
1599  else {
1600  container->obj.alignmentMarginY = info->offsetY;
1601  }
1602 
1603  return container->obj.area.height;
1604 }
1605 
1615 {
1616  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1617  nbgl_container_t *container;
1618 
1619  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddContentCenter():\n");
1620  if (layout == NULL) {
1621  return -1;
1622  }
1623 
1624  container = addContentCenter(layoutInt, info);
1625 
1626  return container->obj.area.height;
1627 }
1628 
1629 #ifdef NBGL_QRCODE
1639 {
1640  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1641  nbgl_container_t *container;
1642  nbgl_text_area_t *textArea = NULL;
1644  uint16_t fullHeight = 0;
1645 
1646  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddQRCode():\n");
1647  if (layout == NULL) {
1648  return -1;
1649  }
1650 
1651  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1652 
1653  // get container children (max 2 (QRCode + text1 + text2))
1654  container->children = nbgl_containerPoolGet(3, layoutInt->layer);
1655  container->nbChildren = 0;
1656 
1657  qrcode = (nbgl_qrcode_t *) nbgl_objPoolGet(QR_CODE, layoutInt->layer);
1658  // version is forced to V10 if url is longer than 62 characters
1659  if (strlen(PIC(info->url)) > 62) {
1660  qrcode->version = QRCODE_V10;
1661  }
1662  else {
1663  qrcode->version = QRCODE_V4;
1664  }
1665  qrcode->foregroundColor = BLACK;
1666  // in QR V4, we use 8*8 screen pixels for one QR pixel
1667  // in QR V10, we use 4*4 screen pixels for one QR pixel
1668  qrcode->obj.area.width
1669  = (qrcode->version == QRCODE_V4) ? (QR_V4_NB_PIX_SIZE * 8) : (QR_V10_NB_PIX_SIZE * 4);
1670  qrcode->obj.area.height = qrcode->obj.area.width;
1671  qrcode->text = PIC(info->url);
1672  qrcode->obj.area.bpp = NBGL_BPP_1;
1673  qrcode->obj.alignment = TOP_MIDDLE;
1674 
1675  fullHeight += qrcode->obj.area.height;
1676  container->children[container->nbChildren] = (nbgl_obj_t *) qrcode;
1677  container->nbChildren++;
1678 
1679  if (info->text1 != NULL) {
1680  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1681  textArea->textColor = BLACK;
1682  textArea->text = PIC(info->text1);
1683  textArea->textAlignment = CENTER;
1684  textArea->fontId = (info->largeText1 == true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1685  textArea->wrapping = true;
1686  textArea->obj.area.width = AVAILABLE_WIDTH;
1687  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1688  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1689  textArea->obj.alignment = BOTTOM_MIDDLE;
1690  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1691  textArea->obj.alignmentMarginY = 24;
1692 
1693  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1694 
1695  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1696  container->nbChildren++;
1697  }
1698  if (info->text2 != NULL) {
1699  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1700  textArea->textColor = DARK_GRAY;
1701  textArea->text = PIC(info->text2);
1702  textArea->textAlignment = CENTER;
1703  textArea->fontId = SMALL_REGULAR_FONT;
1704  textArea->wrapping = true;
1705  textArea->obj.area.width = AVAILABLE_WIDTH;
1706  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1707  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1708  textArea->obj.alignment = BOTTOM_MIDDLE;
1709  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1710  if (info->text1 != NULL) {
1711 #ifdef TARGET_STAX
1712  textArea->obj.alignmentMarginY = 40;
1713 #else // TARGET_STAX
1714  textArea->obj.alignmentMarginY = 28;
1715 #endif // TARGET_STAX
1716  }
1717  else {
1718  textArea->obj.alignmentMarginY = 32;
1719  fullHeight += 8;
1720  }
1721 
1722  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1723 
1724  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1725  container->nbChildren++;
1726  }
1727  // ensure that fullHeight is fitting in main container height (with 16 px margin)
1728  if ((fullHeight >= (layoutInt->container->obj.area.height - 16))
1729  && (qrcode->version == QRCODE_V4)) {
1730  qrcode->version = QRCODE_V4_SMALL;
1731  // in QR V4 small, we use 4*4 screen pixels for one QR pixel
1732  qrcode->obj.area.width = QR_V4_NB_PIX_SIZE * 4;
1733  qrcode->obj.area.height = qrcode->obj.area.width;
1734  fullHeight -= QR_V4_NB_PIX_SIZE * 4;
1735  }
1736  container->obj.area.height = fullHeight;
1737  container->layout = VERTICAL;
1738  if (info->centered) {
1739  container->obj.alignment = CENTER;
1740  }
1741  else {
1742  container->obj.alignment = BOTTOM_MIDDLE;
1743  container->obj.alignTo
1744  = layoutInt->container->children[layoutInt->container->nbChildren - 1];
1745  }
1746  container->obj.alignmentMarginY = info->offsetY;
1747 
1748  container->obj.area.width = AVAILABLE_WIDTH;
1749 
1750  // set this new container as child of main container
1751  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1752 
1753  return fullHeight;
1754 }
1755 #endif // NBGL_QRCODE
1756 
1766 {
1767  nbgl_layoutFooter_t footerDesc;
1768  footerDesc.type = FOOTER_CHOICE_BUTTONS;
1769  footerDesc.separationLine = false;
1770  footerDesc.choiceButtons.bottomText = info->bottomText;
1771  footerDesc.choiceButtons.token = info->token;
1772  footerDesc.choiceButtons.topText = info->topText;
1773  footerDesc.choiceButtons.topIcon = info->topIcon;
1774  footerDesc.choiceButtons.style = info->style;
1775  footerDesc.choiceButtons.tuneId = info->tuneId;
1776  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1777 }
1778 
1789  const nbgl_layoutHorizontalButtons_t *info)
1790 {
1792  .horizontalButtons.leftIcon = info->leftIcon,
1793  .horizontalButtons.leftToken = info->leftToken,
1794  .horizontalButtons.rightText = info->rightText,
1795  .horizontalButtons.rightToken = info->rightToken,
1796  .horizontalButtons.tuneId = info->tuneId};
1797 
1798  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHorizontalButtons():\n");
1799  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
1800 }
1801 
1810 {
1811  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1812  nbgl_text_area_t *itemTextArea;
1813  nbgl_text_area_t *valueTextArea;
1814  nbgl_container_t *container;
1815  uint8_t i;
1816 
1817  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTagValueList():\n");
1818  if (layout == NULL) {
1819  return -1;
1820  }
1821 
1822  for (i = 0; i < list->nbPairs; i++) {
1823  const nbgl_layoutTagValue_t *pair;
1824  uint16_t fullHeight = 0;
1825  const nbgl_icon_details_t *valueIcon = NULL;
1826 
1827  if (list->pairs != NULL) {
1828  pair = &list->pairs[i];
1829  }
1830  else {
1831  pair = list->callback(list->startIndex + i);
1832  }
1833 
1834  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1835 
1836  // get container children (max 3 if a valueIcon, otherwise 2)
1837  container->children
1838  = nbgl_containerPoolGet((pair->valueIcon != NULL) ? 3 : 2, layoutInt->layer);
1839 
1840  itemTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1841  valueTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1842 
1843  // init text area for this choice
1844  itemTextArea->textColor = DARK_GRAY;
1845  itemTextArea->text = PIC(pair->item);
1846  itemTextArea->textAlignment = MID_LEFT;
1847  itemTextArea->fontId = SMALL_REGULAR_FONT;
1848  itemTextArea->wrapping = true;
1849  itemTextArea->obj.area.width = AVAILABLE_WIDTH;
1850  itemTextArea->obj.area.height = nbgl_getTextHeightInWidth(
1851  itemTextArea->fontId, itemTextArea->text, AVAILABLE_WIDTH, itemTextArea->wrapping);
1852  itemTextArea->style = NO_STYLE;
1853  itemTextArea->obj.alignment = NO_ALIGNMENT;
1854  itemTextArea->obj.alignmentMarginX = 0;
1855  itemTextArea->obj.alignmentMarginY = 0;
1856  itemTextArea->obj.alignTo = NULL;
1857  container->children[container->nbChildren] = (nbgl_obj_t *) itemTextArea;
1858  container->nbChildren++;
1859 
1860  fullHeight += itemTextArea->obj.area.height;
1861 
1862  // init button for this choice
1863  valueTextArea->textColor = BLACK;
1864  valueTextArea->text = PIC(pair->value);
1865  valueTextArea->textAlignment = MID_LEFT;
1866  if (list->smallCaseForValue) {
1867  valueTextArea->fontId = SMALL_BOLD_FONT;
1868  }
1869  else {
1870  valueTextArea->fontId = LARGE_MEDIUM_FONT;
1871  }
1872  if ((pair->aliasValue == 0) && (pair->valueIcon == NULL)) {
1873  valueTextArea->obj.area.width = AVAILABLE_WIDTH;
1874  }
1875  else {
1876  if (pair->aliasValue) {
1877  // if the value is an alias, we automatically display a (>) icon
1878  valueIcon = &MINI_PUSH_ICON;
1879  }
1880  else {
1881  // otherwise use the provided icon
1882  valueIcon = PIC(pair->valueIcon);
1883  }
1884  // decrease the available width for value text
1885  valueTextArea->obj.area.width = AVAILABLE_WIDTH - valueIcon->width - 12;
1886  }
1887 
1888  // handle the nbMaxLinesForValue parameter, used to automatically keep only
1889  // nbMaxLinesForValue lines
1890  uint16_t nbLines = nbgl_getTextNbLinesInWidth(valueTextArea->fontId,
1891  valueTextArea->text,
1892  valueTextArea->obj.area.width,
1893  list->wrapping);
1894  // use this nbMaxLinesForValue parameter only if >0
1895  if ((list->nbMaxLinesForValue > 0) && (nbLines > list->nbMaxLinesForValue)) {
1896  nbLines = list->nbMaxLinesForValue;
1897  valueTextArea->nbMaxLines = list->nbMaxLinesForValue;
1898  }
1899  const nbgl_font_t *font = nbgl_getFont(valueTextArea->fontId);
1900  valueTextArea->obj.area.height = nbLines * font->line_height;
1901  valueTextArea->style = NO_STYLE;
1902  valueTextArea->obj.alignment = BOTTOM_LEFT;
1903  valueTextArea->obj.alignmentMarginY = 4;
1904  valueTextArea->obj.alignTo = (nbgl_obj_t *) itemTextArea;
1905  valueTextArea->wrapping = list->wrapping;
1906  container->children[container->nbChildren] = (nbgl_obj_t *) valueTextArea;
1907  container->nbChildren++;
1908 
1909  fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
1910  if (valueIcon != NULL) {
1911  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
1913  layoutInt, (nbgl_obj_t *) image, list->token, TUNE_TAP_CASUAL);
1914  obj->index = i;
1915  image->foregroundColor = BLACK;
1916  image->buffer = valueIcon;
1917  image->obj.alignment = RIGHT_TOP;
1918  image->obj.alignmentMarginX = 12;
1919  image->obj.alignTo = (nbgl_obj_t *) valueTextArea;
1920  image->obj.touchMask = (1 << TOUCHED);
1921  image->obj.touchId = VALUE_BUTTON_1_ID + i;
1922 
1923  container->children[container->nbChildren] = (nbgl_obj_t *) image;
1924  container->nbChildren++;
1925  }
1926 
1927  container->obj.area.width = AVAILABLE_WIDTH;
1928  container->obj.area.height = fullHeight;
1929  container->layout = VERTICAL;
1930  container->obj.alignmentMarginX = BORDER_MARGIN;
1931 #ifdef TARGET_STAX
1932  // On Stax, 12 px between each tag/value pair
1933  if (i > 0) {
1934  container->obj.alignmentMarginY = 12;
1935  }
1936  else {
1937  container->obj.alignmentMarginY = 24;
1938  }
1939 #else // TARGET_STAX
1940  // On Flex, 24 px between each tag/value pair
1941  if (i > 0) {
1942  container->obj.alignmentMarginY = 24;
1943  }
1944 #endif // TARGET_STAX
1945  container->obj.alignment = NO_ALIGNMENT;
1946 
1947  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1948  }
1949 
1950  return 0;
1951 }
1952 
1962 {
1963  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1964  nbgl_progress_bar_t *progress;
1965 
1966  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressBar():\n");
1967  if (layout == NULL) {
1968  return -1;
1969  }
1970  if (barLayout->text != NULL) {
1971  nbgl_text_area_t *textArea;
1972 
1974  ((nbgl_layoutInternal_t *) layout)->layer);
1975  textArea->textColor = BLACK;
1976  textArea->text = PIC(barLayout->text);
1977  textArea->textAlignment = MID_LEFT;
1978  textArea->fontId = SMALL_REGULAR_FONT;
1979  textArea->wrapping = true;
1980  textArea->obj.area.width = AVAILABLE_WIDTH;
1981  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1982  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1983  textArea->style = NO_STYLE;
1984  textArea->obj.alignment = NO_ALIGNMENT;
1985  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1986  textArea->obj.alignmentMarginY = BORDER_MARGIN;
1987  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1988  }
1990  ((nbgl_layoutInternal_t *) layout)->layer);
1991  progress->foregroundColor = BLACK;
1992  progress->withBorder = true;
1993  progress->state = barLayout->percentage;
1994  progress->obj.area.width = 120;
1995  progress->obj.area.height = 12;
1996  progress->obj.alignment = NO_ALIGNMENT;
1997  progress->obj.alignmentMarginX = (AVAILABLE_WIDTH - progress->obj.area.width) / 2;
1998  progress->obj.alignmentMarginY = BORDER_MARGIN;
1999  layoutAddObject(layoutInt, (nbgl_obj_t *) progress);
2000 
2001  if (barLayout->subText != NULL) {
2002  nbgl_text_area_t *subTextArea;
2003 
2004  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(
2005  TEXT_AREA, ((nbgl_layoutInternal_t *) layout)->layer);
2006  subTextArea->textColor = LIGHT_GRAY;
2007  subTextArea->text = PIC(barLayout->subText);
2008  subTextArea->textAlignment = MID_LEFT;
2009  subTextArea->fontId = SMALL_REGULAR_FONT;
2010  subTextArea->wrapping = true;
2011  subTextArea->obj.area.width = AVAILABLE_WIDTH;
2012  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
2013  subTextArea->text,
2014  subTextArea->obj.area.width,
2015  subTextArea->wrapping);
2016  subTextArea->style = NO_STYLE;
2017  subTextArea->obj.alignment = NO_ALIGNMENT;
2018  subTextArea->obj.alignmentMarginX = BORDER_MARGIN;
2019  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
2020  layoutAddObject(layoutInt, (nbgl_obj_t *) subTextArea);
2021  }
2022 
2023  return 0;
2024 }
2025 
2033 {
2034  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2035  nbgl_line_t *line;
2036 
2037  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSeparationLine():\n");
2038  line = createHorizontalLine(layoutInt->layer);
2039  line->obj.alignmentMarginY = -4;
2040  line->offset = 3;
2041  layoutAddObject(layoutInt, (nbgl_obj_t *) line);
2042  return 0;
2043 }
2044 
2053 {
2054  layoutObj_t *obj;
2055  nbgl_button_t *button;
2056  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2057 
2058  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddButton():\n");
2059  if (layout == NULL) {
2060  return -1;
2061  }
2062 
2063  // Add in footer if matching
2064  if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2065  if (layoutInt->footerContainer == NULL) {
2066  nbgl_layoutFooter_t footerDesc;
2067  footerDesc.type = FOOTER_SIMPLE_BUTTON;
2068  footerDesc.separationLine = false;
2069  footerDesc.button.text = buttonInfo->text;
2070  footerDesc.button.token = buttonInfo->token;
2071  footerDesc.button.tuneId = buttonInfo->tuneId;
2072  footerDesc.button.icon = buttonInfo->icon;
2073  footerDesc.button.style = buttonInfo->style;
2074  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2075  }
2076  else {
2077  nbgl_layoutUpFooter_t upFooterDesc;
2078  upFooterDesc.type = UP_FOOTER_BUTTON;
2079  upFooterDesc.button.text = buttonInfo->text;
2080  upFooterDesc.button.token = buttonInfo->token;
2081  upFooterDesc.button.tuneId = buttonInfo->tuneId;
2082  upFooterDesc.button.icon = buttonInfo->icon;
2083  upFooterDesc.button.style = buttonInfo->style;
2084  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2085  }
2086  }
2087 
2088  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2089  obj = layoutAddCallbackObj(
2090  layoutInt, (nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2091  if (obj == NULL) {
2092  return -1;
2093  }
2094 
2095  button->obj.alignmentMarginX = BORDER_MARGIN;
2096  button->obj.alignmentMarginY = 12;
2097  button->obj.alignment = NO_ALIGNMENT;
2098  if (buttonInfo->style == BLACK_BACKGROUND) {
2099  button->innerColor = BLACK;
2100  button->foregroundColor = WHITE;
2101  }
2102  else {
2103  button->innerColor = WHITE;
2104  button->foregroundColor = BLACK;
2105  }
2106  if (buttonInfo->style == NO_BORDER) {
2107  button->borderColor = WHITE;
2108  }
2109  else {
2110  if (buttonInfo->style == BLACK_BACKGROUND) {
2111  button->borderColor = BLACK;
2112  }
2113  else {
2114  button->borderColor = LIGHT_GRAY;
2115  }
2116  }
2117  button->text = PIC(buttonInfo->text);
2118  button->fontId = SMALL_BOLD_FONT;
2119  button->icon = PIC(buttonInfo->icon);
2120  if (buttonInfo->fittingContent == true) {
2121  button->obj.area.width = nbgl_getTextWidth(button->fontId, button->text)
2123  + ((button->icon) ? (button->icon->width + 12) : 0);
2124  button->obj.area.height = SMALL_BUTTON_HEIGHT;
2125  button->radius = RADIUS_32_PIXELS;
2126  if (buttonInfo->onBottom != true) {
2127  button->obj.alignmentMarginX
2128  += (SCREEN_WIDTH - 2 * BORDER_MARGIN - button->obj.area.width) / 2;
2129  }
2130  }
2131  else {
2132  button->obj.area.width = AVAILABLE_WIDTH;
2133  button->obj.area.height = BUTTON_DIAMETER;
2134  button->radius = BUTTON_RADIUS;
2135  }
2136  button->obj.alignTo = NULL;
2137  button->obj.touchMask = (1 << TOUCHED);
2138  button->obj.touchId = (buttonInfo->fittingContent) ? EXTRA_BUTTON_ID : SINGLE_BUTTON_ID;
2139  // set this new button as child of the container
2140  layoutAddObject(layoutInt, (nbgl_obj_t *) button);
2141 
2142  return 0;
2143 }
2144 
2155  const char *text,
2156  uint8_t token,
2157  tune_index_e tuneId)
2158 {
2159  nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_LONG_PRESS,
2160  .longPress.text = text,
2161  .longPress.token = token,
2162  .longPress.tuneId = tuneId};
2163 
2164  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLongPressButton():\n");
2165  if (layout == NULL) {
2166  return -1;
2167  }
2168 
2169  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2170 }
2171 
2183  const char *text,
2184  uint8_t token,
2185  tune_index_e tuneId)
2186 {
2187  nbgl_layoutFooter_t footerDesc;
2188  footerDesc.type = FOOTER_SIMPLE_TEXT;
2189  footerDesc.separationLine = true;
2190  footerDesc.simpleText.text = text;
2191  footerDesc.simpleText.mutedOut = false;
2192  footerDesc.simpleText.token = token;
2193  footerDesc.simpleText.tuneId = tuneId;
2194  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2195 }
2196 
2210  const char *leftText,
2211  uint8_t leftToken,
2212  const char *rightText,
2213  uint8_t rightToken,
2214  tune_index_e tuneId)
2215 {
2216  nbgl_layoutFooter_t footerDesc;
2217  footerDesc.type = FOOTER_DOUBLE_TEXT;
2218  footerDesc.separationLine = true;
2219  footerDesc.doubleText.leftText = leftText;
2220  footerDesc.doubleText.leftToken = leftToken;
2221  footerDesc.doubleText.rightText = rightText;
2222  footerDesc.doubleText.rightToken = rightToken;
2223  footerDesc.doubleText.tuneId = tuneId;
2224  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2225 }
2226 
2236 {
2237  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2238  layoutObj_t *obj;
2239  nbgl_text_area_t *textArea;
2240  nbgl_line_t *line, *separationLine = NULL;
2241  ;
2242  nbgl_button_t *button;
2243 
2244  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHeader():\n");
2245  if (layout == NULL) {
2246  return -1;
2247  }
2248  if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2249  return -2;
2250  }
2251 
2252  layoutInt->headerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2253  layoutInt->headerContainer->obj.area.width = SCREEN_WIDTH;
2254  layoutInt->headerContainer->layout = VERTICAL;
2255  layoutInt->headerContainer->children
2256  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2257  layoutInt->headerContainer->obj.alignment = TOP_MIDDLE;
2258 
2259  switch (headerDesc->type) {
2260  case HEADER_EMPTY: {
2261  layoutInt->headerContainer->obj.area.height = headerDesc->emptySpace.height;
2262  break;
2263  }
2264  case HEADER_BACK_AND_TEXT:
2265  case HEADER_EXTENDED_BACK: {
2266  const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2267  ? PIC(headerDesc->extendedBack.text)
2268  : PIC(headerDesc->backAndText.text);
2269  // add back button
2270  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2271  obj = layoutAddCallbackObj(
2272  layoutInt,
2273  (nbgl_obj_t *) button,
2274  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.backToken
2275  : headerDesc->backAndText.token,
2276  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.tuneId
2277  : headerDesc->backAndText.tuneId);
2278  if (obj == NULL) {
2279  return -1;
2280  }
2281 
2282  button->obj.alignment = MID_LEFT;
2283  button->innerColor = WHITE;
2284  button->foregroundColor = BLACK;
2285  button->borderColor = WHITE;
2286  button->obj.area.width = BACK_KEY_WIDTH;
2287  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2288  button->text = NULL;
2289  button->icon = PIC(&LEFT_ARROW_ICON);
2290  button->obj.touchMask = (1 << TOUCHED);
2291  button->obj.touchId = BACK_BUTTON_ID;
2292  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2293  = (nbgl_obj_t *) button;
2294  layoutInt->headerContainer->nbChildren++;
2295 
2296  // add optional text if needed
2297  if (text != NULL) {
2298  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2299  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2300  && (headerDesc->extendedBack.textToken != NBGL_INVALID_TOKEN)) {
2301  obj = layoutAddCallbackObj(layoutInt,
2302  (nbgl_obj_t *) textArea,
2303  headerDesc->extendedBack.textToken,
2304  headerDesc->extendedBack.tuneId);
2305  if (obj == NULL) {
2306  return -1;
2307  }
2308  textArea->obj.touchMask = (1 << TOUCHED);
2309  }
2310  textArea->obj.alignment = CENTER;
2311  textArea->textColor = BLACK;
2312  textArea->obj.area.width
2313  = layoutInt->headerContainer->obj.area.width - 2 * BACK_KEY_WIDTH;
2314  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2315  textArea->text = text;
2316  textArea->fontId = SMALL_BOLD_FONT;
2317  textArea->textAlignment = CENTER;
2318  textArea->wrapping = true;
2319  // ensure that text fits on 2 lines maximum
2320  if (nbgl_getTextNbLinesInWidth(textArea->fontId,
2321  textArea->text,
2322  textArea->obj.area.width,
2323  textArea->wrapping)
2324  > 2) {
2326  "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2327  text);
2328  }
2329  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2330  = (nbgl_obj_t *) textArea;
2331  layoutInt->headerContainer->nbChildren++;
2332  }
2333  // add action key if the type is HEADER_EXTENDED_BACK
2334  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2335  && (headerDesc->extendedBack.actionIcon)) {
2336  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2337  // if token is valid
2338  if (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) {
2339  obj = layoutAddCallbackObj(layoutInt,
2340  (nbgl_obj_t *) button,
2341  headerDesc->extendedBack.actionToken,
2342  headerDesc->extendedBack.tuneId);
2343  if (obj == NULL) {
2344  return -1;
2345  }
2346  button->obj.touchMask = (1 << TOUCHED);
2347  }
2348 
2349  button->obj.alignment = MID_RIGHT;
2350  button->innerColor = WHITE;
2351  button->foregroundColor
2352  = (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) ? BLACK
2353  : LIGHT_GRAY;
2354  button->borderColor = WHITE;
2355  button->obj.area.width = BACK_KEY_WIDTH;
2356  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2357  button->text = NULL;
2358  button->icon = PIC(headerDesc->extendedBack.actionIcon);
2359  button->obj.touchId = EXTRA_BUTTON_ID;
2360  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2361  = (nbgl_obj_t *) button;
2362  layoutInt->headerContainer->nbChildren++;
2363  }
2364 
2365  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2366  break;
2367  }
2368  case HEADER_BACK_AND_PROGRESS: {
2369 #ifdef TARGET_STAX
2370  // add optional back button
2371  if (headerDesc->progressAndBack.withBack) {
2372  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2373  obj = layoutAddCallbackObj(layoutInt,
2374  (nbgl_obj_t *) button,
2375  headerDesc->progressAndBack.token,
2376  headerDesc->progressAndBack.tuneId);
2377  if (obj == NULL) {
2378  return -1;
2379  }
2380 
2381  button->obj.alignment = MID_LEFT;
2382  button->innerColor = WHITE;
2383  button->foregroundColor = BLACK;
2384  button->borderColor = WHITE;
2385  button->obj.area.width = BACK_KEY_WIDTH;
2386  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2387  button->text = NULL;
2388  button->icon = PIC(&LEFT_ARROW_ICON);
2389  button->obj.touchMask = (1 << TOUCHED);
2390  button->obj.touchId = BACK_BUTTON_ID;
2391  // add to container
2392  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2393  = (nbgl_obj_t *) button;
2394  layoutInt->headerContainer->nbChildren++;
2395  }
2396 
2397  // add progress indicator
2398  if (headerDesc->progressAndBack.nbPages > 1
2399  && headerDesc->progressAndBack.nbPages != NBGL_NO_PROGRESS_INDICATOR) {
2400  nbgl_page_indicator_t *progress;
2401 
2402  progress
2404  progress->activePage = headerDesc->progressAndBack.activePage;
2405  progress->nbPages = headerDesc->progressAndBack.nbPages;
2406  progress->obj.area.width = 224;
2407  progress->obj.alignment = CENTER;
2408  // add to container
2409  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2410  = (nbgl_obj_t *) progress;
2411  layoutInt->headerContainer->nbChildren++;
2412  }
2413  layoutInt->activePage = headerDesc->progressAndBack.activePage;
2414  layoutInt->nbPages = headerDesc->progressAndBack.nbPages;
2415  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2416 #endif // TARGET_STAX
2417  break;
2418  }
2419  case HEADER_TITLE: {
2420  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2421  textArea->textColor = BLACK;
2422  textArea->obj.area.width = AVAILABLE_WIDTH;
2423  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2424  textArea->text = PIC(headerDesc->title.text);
2425  textArea->fontId = SMALL_BOLD_FONT;
2426  textArea->textAlignment = CENTER;
2427  textArea->wrapping = true;
2428  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2429  = (nbgl_obj_t *) textArea;
2430  layoutInt->headerContainer->nbChildren++;
2431  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2432  break;
2433  }
2434  case HEADER_RIGHT_TEXT: {
2435  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2436  obj = layoutAddCallbackObj(layoutInt,
2437  (nbgl_obj_t *) textArea,
2438  headerDesc->rightText.token,
2439  headerDesc->rightText.tuneId);
2440  if (obj == NULL) {
2441  return -1;
2442  }
2443  textArea->obj.alignment = MID_RIGHT;
2444  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2445  textArea->textColor = BLACK;
2446  textArea->obj.area.width = AVAILABLE_WIDTH;
2447  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2448  textArea->text = PIC(headerDesc->rightText.text);
2449  textArea->fontId = SMALL_BOLD_FONT;
2450  textArea->textAlignment = MID_RIGHT;
2451  textArea->obj.touchMask = (1 << TOUCHED);
2452  textArea->obj.touchId = TOP_RIGHT_BUTTON_ID;
2453  // add to bottom container
2454  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2455  = (nbgl_obj_t *) textArea;
2456  layoutInt->headerContainer->nbChildren++;
2457  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2458  break;
2459  }
2460  default:
2461  return -2;
2462  }
2463 
2464  if (headerDesc->separationLine) {
2465  line = createHorizontalLine(layoutInt->layer);
2466  line->obj.alignment = BOTTOM_MIDDLE;
2467  line->offset = 3;
2468  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2469  = (nbgl_obj_t *) line;
2470  layoutInt->headerContainer->nbChildren++;
2471  }
2472  if (separationLine != NULL) {
2473  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2474  = (nbgl_obj_t *) separationLine;
2475  layoutInt->headerContainer->nbChildren++;
2476  }
2477  // header must be the first child
2478  layoutInt->children[HEADER_INDEX] = (nbgl_obj_t *) layoutInt->headerContainer;
2479 
2480  // subtract header height from main container height
2481  layoutInt->container->obj.area.height -= layoutInt->headerContainer->obj.area.height;
2482  layoutInt->container->obj.alignTo = (nbgl_obj_t *) layoutInt->headerContainer;
2483  layoutInt->container->obj.alignment = BOTTOM_LEFT;
2484 
2485  layoutInt->headerType = headerDesc->type;
2486 
2487  return layoutInt->headerContainer->obj.area.height;
2488 }
2489 
2499 {
2500  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2501  layoutObj_t *obj;
2502  nbgl_text_area_t *textArea;
2503  nbgl_line_t *line, *separationLine = NULL;
2504  nbgl_button_t *button;
2505 
2506  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddExtendedFooter():\n");
2507  if (layout == NULL) {
2508  return -1;
2509  }
2510  if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2511  return -2;
2512  }
2513 
2514  layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2515  layoutInt->footerContainer->obj.area.width = AVAILABLE_WIDTH;
2516  layoutInt->footerContainer->layout = VERTICAL;
2517  layoutInt->footerContainer->children
2518  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2519  layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
2520 
2521  switch (footerDesc->type) {
2522  case FOOTER_EMPTY: {
2523  layoutInt->footerContainer->obj.area.height = footerDesc->emptySpace.height;
2524  break;
2525  }
2526  case FOOTER_SIMPLE_TEXT: {
2527  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2528  obj = layoutAddCallbackObj(layoutInt,
2529  (nbgl_obj_t *) textArea,
2530  footerDesc->simpleText.token,
2531  footerDesc->simpleText.tuneId);
2532  if (obj == NULL) {
2533  return -1;
2534  }
2535 
2536  textArea->obj.alignment = BOTTOM_MIDDLE;
2537  textArea->textColor = (footerDesc->simpleText.mutedOut) ? DARK_GRAY : BLACK;
2538  textArea->obj.area.width = AVAILABLE_WIDTH;
2539  textArea->obj.area.height
2540  = (footerDesc->simpleText.mutedOut) ? SMALL_FOOTER_HEIGHT : SIMPLE_FOOTER_HEIGHT;
2541  textArea->text = PIC(footerDesc->simpleText.text);
2542  textArea->fontId
2543  = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
2544  textArea->textAlignment = CENTER;
2545  textArea->obj.touchMask = (1 << TOUCHED);
2546  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2547  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2548  = (nbgl_obj_t *) textArea;
2549  layoutInt->footerContainer->nbChildren++;
2550  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2551  break;
2552  }
2553  case FOOTER_DOUBLE_TEXT: {
2554  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2555  obj = layoutAddCallbackObj(layoutInt,
2556  (nbgl_obj_t *) textArea,
2557  footerDesc->doubleText.leftToken,
2558  footerDesc->doubleText.tuneId);
2559  if (obj == NULL) {
2560  return -1;
2561  }
2562  textArea->obj.alignment = BOTTOM_LEFT;
2563  textArea->textColor = BLACK;
2564  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2565  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2566  textArea->text = PIC(footerDesc->doubleText.leftText);
2567  textArea->fontId = SMALL_BOLD_FONT;
2568  textArea->textAlignment = CENTER;
2569  textArea->obj.touchMask = (1 << TOUCHED);
2570  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2571  // add to bottom container
2572  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2573  = (nbgl_obj_t *) textArea;
2574  layoutInt->footerContainer->nbChildren++;
2575 
2576  // create right touchable text
2577  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2578  obj = layoutAddCallbackObj(layoutInt,
2579  (nbgl_obj_t *) textArea,
2580  footerDesc->doubleText.rightToken,
2581  footerDesc->doubleText.tuneId);
2582  if (obj == NULL) {
2583  return -1;
2584  }
2585 
2586  textArea->obj.alignment = BOTTOM_RIGHT;
2587  textArea->textColor = BLACK;
2588  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2589  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2590  textArea->text = PIC(footerDesc->doubleText.rightText);
2591  textArea->fontId = SMALL_BOLD_FONT;
2592  textArea->textAlignment = CENTER;
2593  textArea->obj.touchMask = (1 << TOUCHED);
2594  textArea->obj.touchId = RIGHT_BUTTON_ID;
2595  // add to bottom container
2596  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2597  = (nbgl_obj_t *) textArea;
2598  layoutInt->footerContainer->nbChildren++;
2599  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2600 
2601  // create vertical line separating texts
2602  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2603  separationLine->lineColor = LIGHT_GRAY;
2604  separationLine->obj.area.width = 1;
2605  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2606  separationLine->direction = VERTICAL;
2607  separationLine->thickness = 1;
2608  separationLine->obj.alignment = MID_LEFT;
2609  separationLine->obj.alignTo = (nbgl_obj_t *) textArea;
2610  separationLine->obj.alignmentMarginX = -1;
2611  break;
2612  }
2613  case FOOTER_TEXT_AND_NAV: {
2614  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2615  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2616  // add touchable text on the left
2617  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2618  obj = layoutAddCallbackObj(layoutInt,
2619  (nbgl_obj_t *) textArea,
2620  footerDesc->textAndNav.token,
2621  footerDesc->textAndNav.tuneId);
2622  if (obj == NULL) {
2623  return -1;
2624  }
2625  textArea->obj.alignment = BOTTOM_LEFT;
2626  textArea->textColor = BLACK;
2627 #ifdef TARGET_STAX
2628  textArea->obj.area.width = 160;
2629 #else // TARGET_STAX
2630  textArea->obj.area.width = 192;
2631 #endif // TARGET_STAX
2632  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2633  textArea->text = PIC(footerDesc->textAndNav.text);
2634  textArea->fontId = SMALL_BOLD_FONT;
2635  textArea->textAlignment = CENTER;
2636  textArea->obj.touchMask = (1 << TOUCHED);
2637  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2638  // add to bottom container
2639  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2640  = (nbgl_obj_t *) textArea;
2641  layoutInt->footerContainer->nbChildren++;
2642 
2643  // add navigation on the right
2644  nbgl_container_t *navContainer
2645  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2646  navContainer->obj.area.width = AVAILABLE_WIDTH;
2647  navContainer->layout = VERTICAL;
2648  navContainer->nbChildren = 4;
2649  navContainer->children
2650  = (nbgl_obj_t **) nbgl_containerPoolGet(navContainer->nbChildren, layoutInt->layer);
2651  navContainer->obj.alignment = BOTTOM_RIGHT;
2652  navContainer->obj.area.width = SCREEN_WIDTH - textArea->obj.area.width;
2653  navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2654  layoutNavigationPopulate(navContainer, &footerDesc->navigation, layoutInt->layer);
2655  obj = layoutAddCallbackObj(layoutInt,
2656  (nbgl_obj_t *) navContainer,
2657  footerDesc->textAndNav.navigation.token,
2658  footerDesc->textAndNav.navigation.tuneId);
2659  if (obj == NULL) {
2660  return -1;
2661  }
2662 
2663  // create vertical line separating text from nav
2664  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2665  separationLine->lineColor = LIGHT_GRAY;
2666  separationLine->obj.area.width = 1;
2667  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2668  separationLine->direction = VERTICAL;
2669  separationLine->thickness = 1;
2670  separationLine->obj.alignment = MID_LEFT;
2671  separationLine->obj.alignTo = (nbgl_obj_t *) navContainer;
2672  separationLine->obj.alignmentMarginX = -1;
2673 
2674  layoutInt->activePage = footerDesc->textAndNav.navigation.activePage;
2675  layoutInt->nbPages = footerDesc->textAndNav.navigation.nbPages;
2676  // add to bottom container
2677  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2678  = (nbgl_obj_t *) navContainer;
2679  layoutInt->footerContainer->nbChildren++;
2680  break;
2681  }
2682  case FOOTER_NAV: {
2683  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2684  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2686  layoutInt->footerContainer, &footerDesc->navigation, layoutInt->layer);
2687  layoutInt->footerContainer->nbChildren = 4;
2688  obj = layoutAddCallbackObj(layoutInt,
2689  (nbgl_obj_t *) layoutInt->footerContainer,
2690  footerDesc->navigation.token,
2691  footerDesc->navigation.tuneId);
2692  if (obj == NULL) {
2693  return -1;
2694  }
2695 
2696  layoutInt->activePage = footerDesc->navigation.activePage;
2697  layoutInt->nbPages = footerDesc->navigation.nbPages;
2698  break;
2699  }
2700  case FOOTER_SIMPLE_BUTTON: {
2701  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2702  obj = layoutAddCallbackObj(layoutInt,
2703  (nbgl_obj_t *) button,
2704  footerDesc->button.token,
2705  footerDesc->button.tuneId);
2706  if (obj == NULL) {
2707  return -1;
2708  }
2709 
2710  button->obj.alignment = CENTER;
2711  if (footerDesc->button.style == BLACK_BACKGROUND) {
2712  button->innerColor = BLACK;
2713  button->foregroundColor = WHITE;
2714  }
2715  else {
2716  button->innerColor = WHITE;
2717  button->foregroundColor = BLACK;
2718  }
2719 
2720  if (footerDesc->button.style == NO_BORDER) {
2721  button->borderColor = WHITE;
2722  }
2723  else {
2724  if (footerDesc->button.style == BLACK_BACKGROUND) {
2725  button->borderColor = BLACK;
2726  }
2727  else {
2728  button->borderColor = LIGHT_GRAY;
2729  }
2730  }
2731  button->text = PIC(footerDesc->button.text);
2732  button->fontId = SMALL_BOLD_FONT;
2733  button->icon = PIC(footerDesc->button.icon);
2734  button->radius = BUTTON_RADIUS;
2735  button->obj.area.height = BUTTON_DIAMETER;
2736  layoutInt->footerContainer->obj.area.height = FOOTER_BUTTON_HEIGHT;
2737  if (footerDesc->button.text == NULL) {
2738  button->obj.area.width = BUTTON_DIAMETER;
2739  }
2740  else {
2741  button->obj.area.width = AVAILABLE_WIDTH;
2742  }
2743  button->obj.touchMask = (1 << TOUCHED);
2744  button->obj.touchId = button->text ? SINGLE_BUTTON_ID : BOTTOM_BUTTON_ID;
2745  // add to bottom container
2746  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2747  = (nbgl_obj_t *) button;
2748  layoutInt->footerContainer->nbChildren++;
2749  break;
2750  }
2751  case FOOTER_CHOICE_BUTTONS: {
2752  // texts cannot be NULL
2753  if ((footerDesc->choiceButtons.bottomText == NULL)
2754  || (footerDesc->choiceButtons.topText == NULL)) {
2755  return -1;
2756  }
2757 
2758  // create bottom button (footer) at first
2759  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2760  obj = layoutAddCallbackObj(layoutInt,
2761  (nbgl_obj_t *) button,
2762  footerDesc->choiceButtons.token,
2763  footerDesc->choiceButtons.tuneId);
2764  if (obj == NULL) {
2765  return -1;
2766  }
2767  // associate with with index 1
2768  obj->index = 1;
2769  // put at the bottom of the container
2770  button->obj.alignment = BOTTOM_MIDDLE;
2771  button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
2772  button->borderColor = WHITE;
2773  button->innerColor = WHITE;
2774  button->foregroundColor = BLACK;
2775  button->obj.area.width = AVAILABLE_WIDTH;
2776  button->obj.area.height = BUTTON_DIAMETER;
2777  button->radius = BUTTON_RADIUS;
2778  button->text = PIC(footerDesc->choiceButtons.bottomText);
2779  button->fontId = SMALL_BOLD_FONT;
2780  button->obj.touchMask = (1 << TOUCHED);
2781  button->obj.touchId = CHOICE_2_ID;
2782  // add to bottom container
2783  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2784  = (nbgl_obj_t *) button;
2785  layoutInt->footerContainer->nbChildren++;
2786 
2787  // add line if needed
2788  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2789  line = createHorizontalLine(layoutInt->layer);
2790  line->obj.alignment = TOP_MIDDLE;
2791  line->obj.alignmentMarginY = 4;
2792  line->obj.alignTo = (nbgl_obj_t *) button;
2793  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2794  = (nbgl_obj_t *) line;
2795  layoutInt->footerContainer->nbChildren++;
2796  }
2797 
2798  // then top button, on top of it
2799  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2800  obj = layoutAddCallbackObj(layoutInt,
2801  (nbgl_obj_t *) button,
2802  footerDesc->choiceButtons.token,
2803  footerDesc->choiceButtons.tuneId);
2804  if (obj == NULL) {
2805  return -1;
2806  }
2807  // associate with with index 0
2808  obj->index = 0;
2809  button->obj.alignment = TOP_MIDDLE;
2810  button->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN; // 24 pixels from top of container
2811  if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
2812  button->innerColor = WHITE;
2813  button->borderColor = LIGHT_GRAY;
2814  button->foregroundColor = BLACK;
2815  }
2816  else {
2817  button->innerColor = BLACK;
2818  button->borderColor = BLACK;
2819  button->foregroundColor = WHITE;
2820  }
2821  button->obj.area.width = AVAILABLE_WIDTH;
2822  button->obj.area.height = BUTTON_DIAMETER;
2823  button->radius = BUTTON_RADIUS;
2824  button->text = PIC(footerDesc->choiceButtons.topText);
2825  button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
2826  ? PIC(footerDesc->choiceButtons.topIcon)
2827  : NULL;
2828  button->fontId = SMALL_BOLD_FONT;
2829  button->obj.touchMask = (1 << TOUCHED);
2830  button->obj.touchId = CHOICE_1_ID;
2831  // add to bottom container
2832  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2833  = (nbgl_obj_t *) button;
2834  layoutInt->footerContainer->nbChildren++;
2835 
2836  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2837  layoutInt->footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
2838  }
2839  else {
2840  layoutInt->footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
2841  }
2842 
2843  break;
2844  }
2845  default:
2846  return -2;
2847  }
2848 
2849  // add swipable feature for navigation
2850  if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
2851  addSwipeInternal(layoutInt,
2852  ((1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT)),
2854  (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
2855  : footerDesc->textAndNav.navigation.token,
2856  (footerDesc->type == FOOTER_NAV)
2857  ? footerDesc->navigation.tuneId
2858  : footerDesc->textAndNav.navigation.tuneId);
2859  }
2860 
2861  if (footerDesc->separationLine) {
2862  line = createHorizontalLine(layoutInt->layer);
2863  line->obj.alignment = TOP_MIDDLE;
2864  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2865  = (nbgl_obj_t *) line;
2866  layoutInt->footerContainer->nbChildren++;
2867  }
2868  if (separationLine != NULL) {
2869  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2870  = (nbgl_obj_t *) separationLine;
2871  layoutInt->footerContainer->nbChildren++;
2872  }
2873 
2874  layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
2875 
2876  // subtract footer height from main container height
2877  layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
2878 
2879  layoutInt->footerType = footerDesc->type;
2880 
2881  return layoutInt->footerContainer->obj.area.height;
2882 }
2883 
2893 {
2894  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2895  layoutObj_t *obj;
2896  nbgl_text_area_t *textArea;
2897  nbgl_line_t *line;
2898  nbgl_button_t *button;
2899 
2900  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddUpFooter():\n");
2901  if (layout == NULL) {
2902  return -1;
2903  }
2904  if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
2905  return -2;
2906  }
2907 
2908  layoutInt->upFooterContainer
2909  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2910  layoutInt->upFooterContainer->obj.area.width = SCREEN_WIDTH;
2911  layoutInt->upFooterContainer->layout = VERTICAL;
2912  // maximum 4 children for long press button
2913  layoutInt->upFooterContainer->children
2914  = (nbgl_obj_t **) nbgl_containerPoolGet(4, layoutInt->layer);
2915  layoutInt->upFooterContainer->obj.alignTo = (nbgl_obj_t *) layoutInt->container;
2916  layoutInt->upFooterContainer->obj.alignment = BOTTOM_MIDDLE;
2917 
2918  switch (upFooterDesc->type) {
2919  case UP_FOOTER_LONG_PRESS: {
2920  nbgl_progress_bar_t *progressBar;
2921 
2922  obj = layoutAddCallbackObj(layoutInt,
2923  (nbgl_obj_t *) layoutInt->upFooterContainer,
2924  upFooterDesc->longPress.token,
2925  upFooterDesc->longPress.tuneId);
2926  if (obj == NULL) {
2927  return -1;
2928  }
2929  layoutInt->upFooterContainer->nbChildren = 4;
2930  layoutInt->upFooterContainer->obj.area.height = LONG_PRESS_BUTTON_HEIGHT;
2931  layoutInt->upFooterContainer->obj.touchId = LONG_PRESS_BUTTON_ID;
2932  layoutInt->upFooterContainer->obj.touchMask
2933  = ((1 << TOUCHING) | (1 << TOUCH_RELEASED) | (1 << OUT_OF_TOUCH)
2934  | (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT));
2935 
2936  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2937  button->obj.alignmentMarginX = BORDER_MARGIN;
2938  button->obj.alignment = MID_RIGHT;
2939  button->innerColor = BLACK;
2940  button->foregroundColor = WHITE;
2941  button->borderColor = BLACK;
2942  button->obj.area.width = BUTTON_DIAMETER;
2943  button->obj.area.height = BUTTON_DIAMETER;
2944  button->radius = BUTTON_RADIUS;
2945  button->icon = PIC(&VALIDATE_ICON);
2946  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
2947 
2948  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2949  textArea->textColor = BLACK;
2950  textArea->text = PIC(upFooterDesc->longPress.text);
2951  textArea->textAlignment = MID_LEFT;
2952  textArea->fontId = LARGE_MEDIUM_FONT;
2953  textArea->wrapping = true;
2954  textArea->obj.area.width = SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
2955  textArea->obj.area.height = nbgl_getTextHeightInWidth(
2956  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2957  textArea->style = NO_STYLE;
2958  textArea->obj.alignment = MID_LEFT;
2959  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2960  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) textArea;
2961 
2962  line = createHorizontalLine(layoutInt->layer);
2963  line->offset = 3;
2964  line->obj.alignment = TOP_MIDDLE;
2965  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) line;
2966 
2967  progressBar = (nbgl_progress_bar_t *) nbgl_objPoolGet(PROGRESS_BAR, layoutInt->layer);
2968  progressBar->withBorder = false;
2969  progressBar->obj.area.width = SCREEN_WIDTH;
2970  progressBar->obj.area.height = 8;
2971  progressBar->obj.alignment = TOP_MIDDLE;
2972  progressBar->obj.alignmentMarginY = 4;
2973  progressBar->obj.alignTo = NULL;
2974  layoutInt->upFooterContainer->children[3] = (nbgl_obj_t *) progressBar;
2975  break;
2976  }
2977  case UP_FOOTER_BUTTON: {
2978  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2979  obj = layoutAddCallbackObj(layoutInt,
2980  (nbgl_obj_t *) button,
2981  upFooterDesc->button.token,
2982  upFooterDesc->button.tuneId);
2983  if (obj == NULL) {
2984  return -1;
2985  }
2986 
2987  layoutInt->upFooterContainer->nbChildren = 1;
2988  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
2989  button->obj.alignment = CENTER;
2990 
2991  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
2992  button->innerColor = BLACK;
2993  button->foregroundColor = WHITE;
2994  }
2995  else {
2996  button->innerColor = WHITE;
2997  button->foregroundColor = BLACK;
2998  }
2999  if (upFooterDesc->button.style == NO_BORDER) {
3000  button->borderColor = WHITE;
3001  }
3002  else {
3003  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3004  button->borderColor = BLACK;
3005  }
3006  else {
3007  button->borderColor = LIGHT_GRAY;
3008  }
3009  }
3010  button->text = PIC(upFooterDesc->button.text);
3011  button->fontId = SMALL_BOLD_FONT;
3012  button->icon = PIC(upFooterDesc->button.icon);
3013  button->obj.area.width = AVAILABLE_WIDTH;
3014  button->obj.area.height = BUTTON_DIAMETER;
3015  button->radius = BUTTON_RADIUS;
3016 
3017  button->obj.alignTo = NULL;
3018  button->obj.touchMask = (1 << TOUCHED);
3019  button->obj.touchId = SINGLE_BUTTON_ID;
3020  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3021  break;
3022  }
3024  // icon & text cannot be NULL
3025  if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3026  || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3027  return -1;
3028  }
3029 
3030  layoutInt->upFooterContainer->nbChildren = 2;
3031  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3032 
3033  // create left button (in white) at first
3034  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3035  obj = layoutAddCallbackObj(layoutInt,
3036  (nbgl_obj_t *) button,
3037  upFooterDesc->horizontalButtons.leftToken,
3038  upFooterDesc->horizontalButtons.tuneId);
3039  if (obj == NULL) {
3040  return -1;
3041  }
3042  // associate with with index 1
3043  obj->index = 1;
3044  button->obj.alignment = MID_LEFT;
3045  button->obj.alignmentMarginX = BORDER_MARGIN;
3046  button->borderColor = LIGHT_GRAY;
3047  button->innerColor = WHITE;
3048  button->foregroundColor = BLACK;
3049  button->obj.area.width = BUTTON_DIAMETER;
3050  button->obj.area.height = BUTTON_DIAMETER;
3051  button->radius = BUTTON_RADIUS;
3052  button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3053  button->fontId = SMALL_BOLD_FONT;
3054  button->obj.touchMask = (1 << TOUCHED);
3055  button->obj.touchId = CHOICE_2_ID;
3056  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3057 
3058  // then black button, on right
3059  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3060  obj = layoutAddCallbackObj(layoutInt,
3061  (nbgl_obj_t *) button,
3062  upFooterDesc->horizontalButtons.rightToken,
3063  upFooterDesc->horizontalButtons.tuneId);
3064  if (obj == NULL) {
3065  return -1;
3066  }
3067  // associate with with index 0
3068  obj->index = 0;
3069  button->obj.alignment = MID_RIGHT;
3070  button->obj.alignmentMarginX = BORDER_MARGIN;
3071  button->innerColor = BLACK;
3072  button->borderColor = BLACK;
3073  button->foregroundColor = WHITE;
3074  button->obj.area.width = AVAILABLE_WIDTH - BUTTON_DIAMETER - 16;
3075  button->obj.area.height = BUTTON_DIAMETER;
3076  button->radius = BUTTON_RADIUS;
3077  button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3078  button->fontId = SMALL_BOLD_FONT;
3079  button->obj.touchMask = (1 << TOUCHED);
3080  button->obj.touchId = CHOICE_1_ID;
3081  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) button;
3082  break;
3083  }
3084  case UP_FOOTER_TIP_BOX: {
3085  // text cannot be NULL
3086  if (upFooterDesc->tipBox.text == NULL) {
3087  return -1;
3088  }
3089  obj = layoutAddCallbackObj(layoutInt,
3090  (nbgl_obj_t *) layoutInt->upFooterContainer,
3091  upFooterDesc->tipBox.token,
3092  upFooterDesc->tipBox.tuneId);
3093  if (obj == NULL) {
3094  return -1;
3095  }
3096  layoutInt->upFooterContainer->nbChildren = 3;
3097  layoutInt->upFooterContainer->obj.touchId = TIP_BOX_ID;
3098  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3099 
3100  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3101  textArea->textColor = BLACK;
3102  textArea->text = PIC(upFooterDesc->tipBox.text);
3103  textArea->textAlignment = MID_LEFT;
3104  textArea->fontId = SMALL_REGULAR_FONT;
3105  textArea->wrapping = true;
3106  textArea->obj.area.width = AVAILABLE_WIDTH;
3107  if (upFooterDesc->tipBox.icon != NULL) {
3108  textArea->obj.area.width
3109  -= ((nbgl_icon_details_t *) PIC(upFooterDesc->tipBox.icon))->width
3110  + BORDER_MARGIN;
3111  }
3112  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3113  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3114  textArea->obj.alignment = MID_LEFT;
3115  textArea->obj.alignmentMarginX = BORDER_MARGIN;
3116  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3117  layoutInt->upFooterContainer->obj.area.height = textArea->obj.area.height;
3118 
3119  line = createHorizontalLine(layoutInt->layer);
3120  line->offset = 3;
3121  line->obj.alignment = TOP_MIDDLE;
3122  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) line;
3123 
3124  if (upFooterDesc->tipBox.icon != NULL) {
3125  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
3126  image->obj.alignmentMarginX = BORDER_MARGIN;
3127  image->obj.alignment = MID_RIGHT;
3128  image->foregroundColor = BLACK;
3129  image->buffer = PIC(upFooterDesc->tipBox.icon);
3130  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) image;
3131  if (layoutInt->upFooterContainer->obj.area.height < image->buffer->height) {
3132  layoutInt->upFooterContainer->obj.area.height = image->buffer->height;
3133  }
3134  }
3135  layoutInt->upFooterContainer->obj.area.height += 2 * BOTTOM_BORDER_MARGIN;
3136 
3137  break;
3138  }
3139  case UP_FOOTER_TEXT: {
3140  obj = layoutAddCallbackObj(layoutInt,
3141  (nbgl_obj_t *) layoutInt->upFooterContainer,
3142  upFooterDesc->text.token,
3143  upFooterDesc->text.tuneId);
3144  if (obj == NULL) {
3145  return -1;
3146  }
3147  layoutInt->upFooterContainer->nbChildren = 1;
3148  layoutInt->upFooterContainer->obj.area.height = SMALL_FOOTER_HEIGHT;
3149  layoutInt->upFooterContainer->obj.touchId = WHOLE_SCREEN_ID;
3150  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3151 
3152  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3153  textArea->textColor = DARK_GRAY;
3154  textArea->text = PIC(upFooterDesc->text.text);
3155  textArea->textAlignment = CENTER;
3156  textArea->fontId = SMALL_REGULAR_FONT;
3157  textArea->wrapping = true;
3158  textArea->obj.area.width = AVAILABLE_WIDTH;
3159  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3160  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3161  textArea->obj.alignment = CENTER;
3162  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3163  break;
3164  }
3165  default:
3166  return -2;
3167  }
3168 
3169  // subtract up footer height from main container height
3170  layoutInt->container->obj.area.height -= layoutInt->upFooterContainer->obj.area.height;
3171 
3172  layoutInt->children[UP_FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->upFooterContainer;
3173 
3174  layoutInt->upFooterType = upFooterDesc->type;
3175 
3176  return layoutInt->upFooterContainer->obj.area.height;
3177 }
3178 
3193  uint8_t activePage,
3194  uint8_t nbPages,
3195  bool withBack,
3196  uint8_t backToken,
3197  tune_index_e tuneId)
3198 {
3200  .separationLine = false,
3201  .progressAndBack.activePage = activePage,
3202  .progressAndBack.nbPages = nbPages,
3203  .progressAndBack.token = backToken,
3204  .progressAndBack.tuneId = tuneId,
3205  .progressAndBack.withBack = withBack,
3206  .progressAndBack.actionIcon = NULL,
3207  .progressAndBack.actionToken = NBGL_INVALID_TOKEN};
3208  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressIndicator():\n");
3209 
3210  return nbgl_layoutAddHeader(layout, &headerDesc);
3211 }
3212 
3221 int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, bool fixed)
3222 {
3223  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3224  nbgl_text_area_t *textArea;
3225  nbgl_spinner_t *spinner;
3226 
3227  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSpinner():\n");
3228  if (layout == NULL) {
3229  return -1;
3230  }
3231 
3232  // create spinner
3233  spinner = (nbgl_spinner_t *) nbgl_objPoolGet(SPINNER, layoutInt->layer);
3234  spinner->position = fixed ? 0xFF : 0;
3235  spinner->obj.alignmentMarginY = -20;
3236  spinner->obj.alignTo = NULL;
3237  spinner->obj.alignment = CENTER;
3238  // set this new spinner as child of the container
3239  layoutAddObject(layoutInt, (nbgl_obj_t *) spinner);
3240 
3241  // create text area
3242  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3243  textArea->textColor = BLACK;
3244  textArea->text = PIC(text);
3245  textArea->textAlignment = CENTER;
3246  textArea->fontId = SMALL_REGULAR_FONT;
3247  textArea->wrapping = true;
3248 #ifdef TARGET_STAX
3249  textArea->obj.alignmentMarginY = 20;
3250 #else // TARGET_STAX
3251  textArea->obj.alignmentMarginY = 24;
3252 #endif // TARGET_STAX
3253  textArea->obj.alignTo = (nbgl_obj_t *) spinner;
3254  textArea->obj.alignment = BOTTOM_MIDDLE;
3255  textArea->obj.area.width = AVAILABLE_WIDTH;
3256  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3257  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3258  textArea->style = NO_STYLE;
3259 
3260  // center spinner + text vertically
3261  spinner->obj.alignmentMarginY
3262  = -(textArea->obj.alignmentMarginY + textArea->obj.area.height) / 2;
3263 
3264  // set this new spinner as child of the container
3265  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
3266 
3267  if (!fixed) {
3268  // update ticker to update the spinner periodically
3270 
3271  tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD; // ms
3272  tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD; // ms
3273  tickerCfg.tickerCallback = &spinnerTickerCallback;
3274  nbgl_screenUpdateTicker(layoutInt->layer, &tickerCfg);
3275  }
3276 
3277  return 0;
3278 }
3279 
3287 {
3288  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3289 
3290  if (layout == NULL) {
3291  return -1;
3292  }
3294  "nbgl_layoutDraw(): container.nbChildren =%d, layout->nbChildren = %d\n",
3295  layout->container->nbChildren,
3296  layout->nbChildren);
3297  if (layout->tapText) {
3298  // set this new container as child of main container
3299  layoutAddObject(layout, (nbgl_obj_t *) layout->tapText);
3300  }
3301  if (layout->withLeftBorder == true) {
3302  // draw now the line
3303  nbgl_line_t *line = createLeftVerticalLine(layout->layer);
3304  layout->children[LEFT_BORDER_INDEX] = (nbgl_obj_t *) line;
3305  }
3307 
3308  return 0;
3309 }
3310 
3318 {
3319  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3320  LOG_DEBUG(PAGE_LOGGER, "nbgl_layoutRelease(): \n");
3321  if (layout == NULL) {
3322  return -1;
3323  }
3324  // if modal
3325  if (layout->modal) {
3326  nbgl_screenPop(layout->layer);
3327  }
3328  layout->nbChildren = 0;
3329  return 0;
3330 }
3331 
3332 #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:398
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text (can be multiline)
Definition: nbgl_fonts.c:360
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
Definition: nbgl_fonts.c:1048
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
Definition: nbgl_fonts.c:731
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
return the non-unicode font corresponding to the given font ID
Definition: nbgl_fonts.c:136
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
return the height in pixels of the line of font with the given font ID
Definition: nbgl_fonts.c:410
Font screen low-Level driver API, to draw elementary forms.
int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueList_t *list)
Creates a list of [tag,value] pairs.
Definition: nbgl_layout.c:1809
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:1614
#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:2892
int nbgl_layoutDraw(nbgl_layout_t *layoutParam)
Applies given layout. The screen will be redrawn.
Definition: nbgl_layout.c:3286
#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:1372
int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
Creates an area with given text and sub text (in gray)
Definition: nbgl_layout.c:1197
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:3192
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:1066
#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:2032
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:1638
#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:1454
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:1551
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:2209
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:1961
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:1284
int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout)
Creates a touchable bar in main panel.
Definition: nbgl_layout.c:1118
#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:1021
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:980
#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:1157
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:1788
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:2052
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:2498
#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:1765
int nbgl_layoutRelease(nbgl_layout_t *layoutParam)
Release the layout obtained with nbgl_layoutGet()
Definition: nbgl_layout.c:3317
#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:2154
@ 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:2235
#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:1092
int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text)
Creates an area with given text in 32px font (in Black)
Definition: nbgl_layout.c:1325
#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:2182
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:3221
#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:891
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:327
@ NO_BORDER
simple clickable text, in black
Definition: nbgl_layout.h:328
@ BLACK_BACKGROUND
rounded bordered button, with text/icon in white, on black background
Definition: nbgl_layout.h:325
#define AVAILABLE_WIDTH
Definition: nbgl_layout.h:66
@ UP_FOOTER_TEXT
grayed-out text, for example "Tap to continue"
Definition: nbgl_layout.h:520
@ NB_UP_FOOTER_TYPES
Definition: nbgl_layout.h:521
@ UP_FOOTER_BUTTON
simple button
Definition: nbgl_layout.h:517
@ UP_FOOTER_LONG_PRESS
long-press button
Definition: nbgl_layout.h:516
@ UP_FOOTER_TIP_BOX
Tip-box.
Definition: nbgl_layout.h:519
@ UP_FOOTER_HORIZONTAL_BUTTONS
2 buttons, on the same line
Definition: nbgl_layout.h:518
void * nbgl_layout_t
type shared externally
Definition: nbgl_layout.h:96
@ HEADER_TITLE
simple centered text
Definition: nbgl_layout.h:409
@ HEADER_BACK_AND_PROGRESS
optional back key and progress indicator (only on Stax)
Definition: nbgl_layout.h:408
@ HEADER_EMPTY
empty space, to have a better vertical centering of centered info
Definition: nbgl_layout.h:406
@ NB_HEADER_TYPES
Definition: nbgl_layout.h:412
@ HEADER_EXTENDED_BACK
back key, centered text and touchable key on the right
Definition: nbgl_layout.h:410
@ HEADER_BACK_AND_TEXT
back key and optional text
Definition: nbgl_layout.h:407
@ HEADER_RIGHT_TEXT
touchable text on the right, with a vertical separation line
Definition: nbgl_layout.h:411
#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:282
@ ROUNDED_AND_FOOTER_STYLE
A black background button on top of a footer.
Definition: nbgl_layout.h:280
#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:465
@ FOOTER_NAV
navigation bar
Definition: nbgl_layout.h:469
@ FOOTER_SIMPLE_BUTTON
simple black or white button (see nbgl_layoutButtonStyle_t)
Definition: nbgl_layout.h:470
@ FOOTER_TEXT_AND_NAV
Definition: nbgl_layout.h:467
@ FOOTER_DOUBLE_TEXT
2 touchable texts in bold, separated by a vertical line (only on Stax)
Definition: nbgl_layout.h:466
@ NB_FOOTER_TYPES
Definition: nbgl_layout.h:472
@ FOOTER_EMPTY
empty space, to have a better vertical centering of centered info
Definition: nbgl_layout.h:464
@ FOOTER_CHOICE_BUTTONS
double buttons (see nbgl_layoutChoiceButtonsStyle_t)
Definition: nbgl_layout.h:471
#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)
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:1521
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:1570
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:1586
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:377
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:275
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:285
bool localized
if set to true, use nameIds and not names
Definition: nbgl_content.h:282
uint8_t initChoice
index of the current choice
Definition: nbgl_content.h:284
const char *const * names
array of strings giving the choices (nbChoices)
Definition: nbgl_content.h:277
uint8_t nbChoices
number of choices
Definition: nbgl_content.h:283
This structure contains info to build a switch (on the right) with a description (on the left),...
Definition: nbgl_content.h:242
const char * text
main text for the switch
Definition: nbgl_content.h:243
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:247
nbgl_state_t initState
initial state of the switch
Definition: nbgl_content.h:246
const char * subText
description under main text (NULL terminated, single line, may be null)
Definition: nbgl_content.h:245
This structure contains a list of [tag,value] pairs.
Definition: nbgl_content.h:181
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
Definition: nbgl_content.h:183
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
Definition: nbgl_content.h:194
uint8_t startIndex
index of the first pair to get with callback
Definition: nbgl_content.h:187
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
Definition: nbgl_content.h:184
This structure contains a [tag,value] pair.
Definition: nbgl_content.h:144
const nbgl_icon_details_t * valueIcon
Definition: nbgl_content.h:149
const char * value
string giving the value name
Definition: nbgl_content.h:146
const char * item
string giving the tag name
Definition: nbgl_content.h:145
const char * text
text of the tip-box
Definition: nbgl_content.h:309
const nbgl_icon_details_t * icon
icon of the tip-box
Definition: nbgl_content.h:310
uint8_t token
token used when tip-box is tapped
Definition: nbgl_content.h:311
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:335
const char * text
button text
Definition: nbgl_layout.h:336
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:338
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon for button
Definition: nbgl_layout.h:337
nbgl_layoutButtonStyle_t style
Definition: nbgl_layout.h:339
bool fittingContent
if set to true, fit the width of button to text, otherwise full width
Definition: nbgl_layout.h:340
This structure contains info to build a pair of buttons, one on top of the other.
Definition: nbgl_layout.h:293
nbgl_layoutChoiceButtonsStyle_t style
the style of the pair
Definition: nbgl_layout.h:298
const nbgl_icon_details_t * topIcon
icon of top button
Definition: nbgl_layout.h:296
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:297
const char * topText
up-button text (index 0)
Definition: nbgl_layout.h:294
const char * bottomText
bottom-button text (index 1)
Definition: nbgl_layout.h:295
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:479
nbgl_layoutChoiceButtons_t choiceButtons
if type is FOOTER_CHOICE_BUTTONS
Definition: nbgl_layout.h:507
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:481
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:506
nbgl_layoutFooterType_t type
type of footer
Definition: nbgl_layout.h:480
nbgl_layoutNavigationBar_t navigation
if type is FOOTER_NAV
Definition: nbgl_layout.h:500
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:419
nbgl_layoutHeaderType_t type
type of header
Definition: nbgl_layout.h:420
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:421
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:310
const nbgl_icon_details_t * leftIcon
a buffer containing the 1BPP icon for left button
Definition: nbgl_layout.h:311
uint8_t leftToken
the token used when left button is pressed
Definition: nbgl_layout.h:313
uint8_t rightToken
the token used when right button is pressed
Definition: nbgl_layout.h:314
const char * rightText
right-button text
Definition: nbgl_layout.h:312
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 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:554
uint8_t percentage
percentage of completion, from 0 to 100.
Definition: nbgl_layout.h:555
const char * text
text in black, on top of progress bar
Definition: nbgl_layout.h:556
const char * subText
text in gray, under progress bar
Definition: nbgl_layout.h:557
This structure contains info to build a centered (vertically and horizontally) area,...
Definition: nbgl_layout.h:266
const char * text2
second text (can be null)
Definition: nbgl_layout.h:269
const char * text1
first text (can be null)
Definition: nbgl_layout.h:268
const char * url
URL for QR code.
Definition: nbgl_layout.h:267
bool largeText1
if set to true, use 32px font for text1
Definition: nbgl_layout.h:272
int16_t offsetY
vertical shift to apply to this info (if > 0, shift to bottom)
Definition: nbgl_layout.h:270
bool centered
if set to true, center vertically
Definition: nbgl_layout.h:271
This structure contains info to build an up-footer (area on top of footer).
Definition: nbgl_layout.h:528
nbgl_layoutButton_t button
if type is UP_FOOTER_BUTTON
Definition: nbgl_layout.h:536
nbgl_contentTipBox_t tipBox
if type is UP_FOOTER_TIP_BOX
Definition: nbgl_layout.h:539
const char * text
text in the long-press button
Definition: nbgl_layout.h:532
nbgl_layoutUpFooterType_t type
type of up-footer
Definition: nbgl_layout.h:529
nbgl_layoutHorizontalButtons_t horizontalButtons
if type is UP_FOOTER_HORIZONTAL_BUTTONS
Definition: nbgl_layout.h:538
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