Embedded SDK
Embedded SDK
nbgl_layout.c
Go to the documentation of this file.
1 
7 #include "app_config.h"
8 
9 #ifdef HAVE_SE_TOUCH
10 /*********************
11  * INCLUDES
12  *********************/
13 #include <string.h>
14 #include <stdlib.h>
15 #include "nbgl_debug.h"
16 #include "nbgl_front.h"
17 #include "nbgl_layout_internal.h"
18 #include "nbgl_obj.h"
19 #include "nbgl_draw.h"
20 #include "nbgl_screen.h"
21 #include "nbgl_touch.h"
22 #include "glyphs.h"
23 #include "os_pic.h"
24 #include "os_helpers.h"
25 #include "lcx_rng.h"
26 
27 /*********************
28  * DEFINES
29  *********************/
30 // half internal margin, between items
31 #define INTERNAL_SPACE 16
32 // inner margin, between buttons
33 #define INNER_MARGIN 12
34 
35 #define NB_MAX_LAYOUTS 3
36 
37 // used by container
38 #define NB_MAX_CONTAINER_CHILDREN 20
39 
40 #define TAG_VALUE_ICON_WIDTH 32
41 
42 #ifdef TARGET_STAX
43 #define RADIO_CHOICE_HEIGHT 96
44 #define FOOTER_HEIGHT 80
45 #define BAR_INTERVALE 12
46 #define BACK_KEY_WIDTH 88
47 #define FOOTER_BUTTON_HEIGHT 128
48 #define UP_FOOTER_BUTTON_HEIGHT 120
49 #define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 192
50 #define ACTION_AND_FOOTER_FOOTER_HEIGHT 216
51 #else // TARGET_STAX
52 #define RADIO_CHOICE_HEIGHT 92
53 #define FOOTER_HEIGHT 80
54 #define BAR_INTERVALE 16
55 #define BACK_KEY_WIDTH 104
56 #define FOOTER_BUTTON_HEIGHT 136
57 #define UP_FOOTER_BUTTON_HEIGHT 136
58 #define ROUNDED_AND_FOOTER_FOOTER_HEIGHT 208
59 #define ACTION_AND_FOOTER_FOOTER_HEIGHT 232
60 #endif // TARGET_STAX
61 
62 // refresh period of the spinner, in ms
63 #define SPINNER_REFRESH_PERIOD 400
64 
65 #ifdef TARGET_STAX
66 #define FIRST_BUTTON_INDEX 0
67 #else // TARGET_STAX
68 // for suggestion buttons, on Flex there are other objects than buttons
69 enum {
71  LEFT_HALF_INDEX, // half disc displayed on the bottom left
72  RIGHT_HALF_INDEX, // half disc displayed on the bottom right
74 };
75 #endif // TARGET_STAX
76 
77 /**********************
78  * MACROS
79  **********************/
80 
81 /**********************
82  * TYPEDEFS
83  **********************/
84 
85 typedef enum {
90 
91 // used to build either a touchable bar or a switch
92 typedef struct {
94  const nbgl_icon_details_t *iconLeft; // a buffer containing the 1BPP icon for icon on
95  // left (can be NULL)
96  const nbgl_icon_details_t *iconRight; // a buffer containing the 1BPP icon for icon 2 (can be
97  // NULL). Dimensions must be the same as iconLeft
98  const char *text; // text (can be NULL)
99  const char *subText; // sub text (can be NULL)
100  uint8_t token; // the token that will be used as argument of the callback
101  nbgl_state_t state; // state of the item
102  bool large; // set to true only for the main level of OS settings
103 #ifdef HAVE_PIEZO_SOUND
104  tune_index_e tuneId; // if not @ref NBGL_NO_TUNE, a tune will be played
105 #endif // HAVE_PIEZO_SOUND
106 } listItem_t;
107 
108 /**********************
109  * VARIABLES
110  **********************/
111 
116 static nbgl_layoutInternal_t gLayout[NB_MAX_LAYOUTS] = {0};
117 
118 // numbers of touchable controls for the whole page
119 static uint8_t nbTouchableControls = 0;
120 
121 /**********************
122  * STATIC PROTOTYPES
123  **********************/
124 extern const char *get_ux_loc_string(uint32_t index);
125 
126 #ifdef HAVE_FAST_HOLD_TO_APPROVE
127 // Unit step in % of touchable progress bar
128 #define HOLD_TO_APPROVE_STEP_PERCENT (7)
129 // Duration in ms the user must hold the progress bar
130 // to make it progress HOLD_TO_APPROVE_STEP_PERCENT %.
131 // This duration must be higher than the screen refresh duration.
132 #define HOLD_TO_APPROVE_STEP_DURATION_MS (100)
133 #else
134 #define HOLD_TO_APPROVE_STEP_PERCENT (25)
135 #define HOLD_TO_APPROVE_STEP_DURATION_MS (400)
136 #endif // HAVE_FAST_HOLD_TO_APPROVE
137 
138 static inline uint8_t get_hold_to_approve_percent(uint32_t touch_duration)
139 {
140 #ifdef HAVE_FAST_HOLD_TO_APPROVE
141  uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS);
142 #else
143  uint8_t current_step_nb = (touch_duration / HOLD_TO_APPROVE_STEP_DURATION_MS) + 1;
144 #endif
145  return (current_step_nb * HOLD_TO_APPROVE_STEP_PERCENT);
146 }
147 
148 // function used to retrieve the concerned layout and layout obj matching the given touched obj
149 static bool getLayoutAndLayoutObj(nbgl_obj_t *obj,
150  nbgl_layoutInternal_t **layout,
151  layoutObj_t **layoutObj)
152 {
154 
155  // parse all layouts (starting with modals) to find the object
156  *layout = NULL;
157  while (i > 0) {
158  i--;
159  if (gLayout[i].nbChildren > 0) {
160  uint8_t j;
161 
162  // search index of obj in this layout
163  for (j = 0; j < gLayout[i].nbUsedCallbackObjs; j++) {
164  if (obj == gLayout[i].callbackObjPool[j].obj) {
166  "getLayoutAndLayoutObj(): obj found in layout[%d], index = %d, "
167  "nbUsedCallbackObjs = %d\n",
168  i,
169  j,
170  gLayout[i].nbUsedCallbackObjs);
171  *layout = &gLayout[i];
172  *layoutObj = &(gLayout[i].callbackObjPool[j]);
173  return true;
174  }
175  }
176  }
177  }
178  // not found
179  return false;
180 }
181 
182 static void radioTouchCallback(nbgl_obj_t *obj,
183  nbgl_touchType_t eventType,
184  nbgl_layoutInternal_t *layout);
185 static void longTouchCallback(nbgl_obj_t *obj,
186  nbgl_touchType_t eventType,
187  nbgl_layoutInternal_t *layout,
188  layoutObj_t *layoutObj);
189 
190 // callback for most touched object
191 static void touchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
192 {
193  nbgl_layoutInternal_t *layout;
194  layoutObj_t *layoutObj;
195  bool needRefresh = false;
196 
197  if (obj == NULL) {
198  return;
199  }
200  LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): eventType = %d, obj = %p\n", eventType, obj);
201  if (getLayoutAndLayoutObj(obj, &layout, &layoutObj) == false) {
202  // try with parent, if existing
203  if (getLayoutAndLayoutObj(obj->parent, &layout, &layoutObj) == false) {
204  LOG_WARN(
206  "touchCallback(): eventType = %d, obj = %p, no active layout or obj not found\n",
207  eventType,
208  obj);
209  return;
210  }
211  }
212 
213  // case of swipe
214  if (((eventType == SWIPED_UP) || (eventType == SWIPED_DOWN) || (eventType == SWIPED_LEFT)
215  || (eventType == SWIPED_RIGHT))
216  && (obj->type == CONTAINER)) {
217 #ifdef NBGL_KEYBOARD
218  if (layout->swipeUsage == SWIPE_USAGE_SUGGESTIONS) {
219  keyboardSwipeCallback(obj, eventType);
220  return;
221  }
222 #endif // NBGL_KEYBOARD
223  if (layout->swipeUsage == SWIPE_USAGE_CUSTOM) {
224  layoutObj->index = eventType;
225  }
226  else if ((layout->swipeUsage == SWIPE_USAGE_NAVIGATION)
227  && ((nbgl_obj_t *) layout->container == obj)) {
228  nbgl_container_t *navContainer;
229  if (layout->footerType == FOOTER_NAV) {
230  navContainer = (nbgl_container_t *) layout->footerContainer;
231  }
232  else if (layout->footerType == FOOTER_TEXT_AND_NAV) {
233  navContainer = (nbgl_container_t *) layout->footerContainer->children[1];
234  }
235  else {
236  return;
237  }
238 
240  (nbgl_obj_t *) navContainer, eventType, layout->nbPages, &layout->activePage)
241  == false) {
242  // navigation was impossible
243  return;
244  }
245  layoutObj->index = layout->activePage;
246  }
247  }
248 
249  // case of navigation bar
250  if (((obj->parent == (nbgl_obj_t *) layout->footerContainer)
251  && (layout->footerType == FOOTER_NAV))
252  || ((obj->parent->type == CONTAINER)
253  && (obj->parent->parent == (nbgl_obj_t *) layout->footerContainer)
254  && (layout->footerType == FOOTER_TEXT_AND_NAV))) {
255  if (layoutNavigationCallback(obj, eventType, layout->nbPages, &layout->activePage)
256  == false) {
257  // navigation was impossible
258  return;
259  }
260  layoutObj->index = layout->activePage;
261  }
262 
263  // case of switch
264  if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren >= 2)
265  && (((nbgl_container_t *) obj)->children[1] != NULL)
266  && (((nbgl_container_t *) obj)->children[1]->type == SWITCH)) {
267  nbgl_switch_t *lSwitch = (nbgl_switch_t *) ((nbgl_container_t *) obj)->children[1];
268  lSwitch->state = (lSwitch->state == ON_STATE) ? OFF_STATE : ON_STATE;
269  nbgl_objDraw((nbgl_obj_t *) lSwitch);
270  // refresh will be done after tune playback
271  needRefresh = true;
272  // index is used for state
273  layoutObj->index = lSwitch->state;
274  }
275  // case of radio
276  else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 2)
277  && (((nbgl_container_t *) obj)->children[1] != NULL)
278  && (((nbgl_container_t *) obj)->children[1]->type == RADIO_BUTTON)) {
279  radioTouchCallback(obj, eventType, layout);
280  return;
281  }
282  // case of long press
283  else if ((obj->type == CONTAINER) && (((nbgl_container_t *) obj)->nbChildren == 4)
284  && (((nbgl_container_t *) obj)->children[3] != NULL)
285  && (((nbgl_container_t *) obj)->children[3]->type == PROGRESS_BAR)) {
286  longTouchCallback(obj, eventType, layout, layoutObj);
287  return;
288  }
289  LOG_DEBUG(LAYOUT_LOGGER, "touchCallback(): layout->callback = %p\n", layout->callback);
290  if (layout->callback != NULL) {
291 #ifdef HAVE_PIEZO_SOUND
292  if (layoutObj->tuneId < NBGL_NO_TUNE) {
293  io_seproxyhal_play_tune(layoutObj->tuneId);
294  }
295 #endif // HAVE_PIEZO_SOUND
296  if (needRefresh) {
298  }
299  layout->callback(layoutObj->token, layoutObj->index);
300  }
301 }
302 
303 // callback for long press button
304 static void longTouchCallback(nbgl_obj_t *obj,
305  nbgl_touchType_t eventType,
306  nbgl_layoutInternal_t *layout,
307  layoutObj_t *layoutObj)
308 {
309  nbgl_container_t *container = (nbgl_container_t *) obj;
310  // 4th child of container is the progress bar
311  nbgl_progress_bar_t *progressBar = (nbgl_progress_bar_t *) container->children[3];
312 
314  "longTouchCallback(): eventType = %d, obj = %p, gLayout[1].nbChildren = %d\n",
315  eventType,
316  obj,
317  gLayout[1].nbChildren);
318 
319  // case of pressing a long press button
320  if (eventType == TOUCHING) {
321  uint32_t touchDuration = nbgl_touchGetTouchDuration(obj);
322 
323  // Compute the new progress bar state in %
324  uint8_t new_state = get_hold_to_approve_percent(touchDuration);
325 
326  // Ensure the callback is triggered once,
327  // when the progress bar state reaches 100%
328  bool trigger_callback = (new_state >= 100) && (progressBar->state < 100);
329 
330  // Cap progress bar state at 100%
331  if (new_state >= 100) {
332  new_state = 100;
333  }
334 
335  // Update progress bar state
336  if (new_state != progressBar->state) {
337  progressBar->partialRedraw = true;
338  progressBar->state = new_state;
339 
340  nbgl_objDraw((nbgl_obj_t *) progressBar);
341  // Ensure progress bar is fully drawn
342  // before calling the callback.
345  }
346 
347  if (trigger_callback) {
348  // End of progress bar reached: trigger callback
349  if (layout->callback != NULL) {
350  layout->callback(layoutObj->token, layoutObj->index);
351  }
352  }
353  }
354  // case of releasing a long press button (or getting out of it)
355  else if ((eventType == TOUCH_RELEASED) || (eventType == OUT_OF_TOUCH)
356  || (eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT)) {
358  progressBar->partialRedraw = true;
359  progressBar->state = 0;
360  nbgl_objDraw((nbgl_obj_t *) progressBar);
362  }
363 }
364 
365 // callback for radio button touch
366 static void radioTouchCallback(nbgl_obj_t *obj,
367  nbgl_touchType_t eventType,
368  nbgl_layoutInternal_t *layout)
369 {
370  uint8_t i = NB_MAX_LAYOUTS, radioIndex = 0, foundRadio = 0xFF, foundRadioIndex;
371 
372  if (eventType != TOUCHED) {
373  return;
374  }
375 
376  i = 0;
377  // parse all objs to find all containers of radio buttons
378  while (i < layout->nbUsedCallbackObjs) {
379  if ((obj == (nbgl_obj_t *) layout->callbackObjPool[i].obj)
380  && (layout->callbackObjPool[i].obj->type == CONTAINER)) {
381  nbgl_radio_t *radio
382  = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
383  ->children[1];
384  nbgl_text_area_t *textArea
386  ->children[0];
387  foundRadio = i;
388  foundRadioIndex = radioIndex;
389  // set text as active (black and bold)
390  textArea->textColor = BLACK;
391  textArea->fontId = SMALL_BOLD_FONT;
392  // ensure that radio button is ON
393  radio->state = ON_STATE;
394  // redraw container
395  nbgl_objDraw((nbgl_obj_t *) obj);
396  }
397  else if ((layout->callbackObjPool[i].obj->type == CONTAINER)
398  && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->nbChildren == 2)
399  && (((nbgl_container_t *) layout->callbackObjPool[i].obj)->children[1]->type
400  == RADIO_BUTTON)) {
401  nbgl_radio_t *radio
402  = (nbgl_radio_t *) ((nbgl_container_t *) layout->callbackObjPool[i].obj)
403  ->children[1];
404  nbgl_text_area_t *textArea
406  ->children[0];
407  radioIndex++;
408  // set to OFF the one that was in ON
409  if (radio->state == ON_STATE) {
410  radio->state = OFF_STATE;
411  // set text it as inactive (gray and normal)
412  textArea->textColor = DARK_GRAY;
413  textArea->fontId = SMALL_REGULAR_FONT;
414  // redraw container
415  nbgl_objDraw((nbgl_obj_t *) layout->callbackObjPool[i].obj);
416  }
417  }
418  i++;
419  }
420  // call callback after redraw to avoid asynchronicity
421  if (foundRadio != 0xFF) {
422  if (layout->callback != NULL) {
423 #ifdef HAVE_PIEZO_SOUND
424  if (layout->callbackObjPool[foundRadio].tuneId < NBGL_NO_TUNE) {
425  io_seproxyhal_play_tune(layout->callbackObjPool[foundRadio].tuneId);
426  }
428 #endif // HAVE_PIEZO_SOUND
429  layout->callback(layout->callbackObjPool[foundRadio].token, foundRadioIndex);
430  }
431  }
432 }
433 
434 // callback for spinner ticker
435 static void spinnerTickerCallback(void)
436 {
437  nbgl_spinner_t *spinner;
438  uint8_t i = 0;
439  nbgl_layoutInternal_t *layout;
440 
441  // gLayout[1] is on top of gLayout[0] so if gLayout[1] is active, it must catch the event
442  if (gLayout[1].nbChildren > 0) {
443  layout = &gLayout[1];
444  }
445  else {
446  layout = &gLayout[0];
447  }
448 
449  // get index of obj
450  while (i < layout->container->nbChildren) {
451  if (layout->container->children[i]->type == SPINNER) {
452  spinner = (nbgl_spinner_t *) layout->container->children[i];
453  spinner->position++;
454  spinner->position &= 3; // modulo 4
455  nbgl_objDraw((nbgl_obj_t *) spinner);
457  return;
458  }
459  i++;
460  }
461 }
462 
463 static nbgl_line_t *createHorizontalLine(uint8_t layer)
464 {
465  nbgl_line_t *line;
466 
467  line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
468  line->lineColor = LIGHT_GRAY;
469  line->obj.area.width = SCREEN_WIDTH;
470  line->obj.area.height = 4;
471  line->direction = HORIZONTAL;
472  line->thickness = 1;
473  return line;
474 }
475 
476 static nbgl_line_t *createLeftVerticalLine(uint8_t layer)
477 {
478  nbgl_line_t *line;
479 
480  line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layer);
481  line->lineColor = LIGHT_GRAY;
482  line->obj.area.width = 1;
483  line->obj.area.height = SCREEN_HEIGHT;
484  line->direction = VERTICAL;
485  line->thickness = 1;
486  line->obj.alignment = MID_LEFT;
487  return line;
488 }
489 
490 // function adding a layout object in the callbackObjPool array for the given layout, and
491 // configuring it
493  nbgl_obj_t *obj,
494  uint8_t token,
495  tune_index_e tuneId)
496 {
497  layoutObj_t *layoutObj = NULL;
498 
499  if (layout->nbUsedCallbackObjs < (LAYOUT_OBJ_POOL_LEN - 1)) {
500  layoutObj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
501  layout->nbUsedCallbackObjs++;
502  layoutObj->obj = obj;
503  layoutObj->token = token;
504  layoutObj->tuneId = tuneId;
505  }
506  else {
507  LOG_FATAL(LAYOUT_LOGGER, "layoutAddCallbackObj: no more callback obj\n");
508  }
509 
510  return layoutObj;
511 }
512 
520 {
521  if (layout->container->nbChildren == NB_MAX_CONTAINER_CHILDREN) {
522  LOG_FATAL(LAYOUT_LOGGER, "layoutAddObject(): No more object\n");
523  }
524  layout->container->children[layout->container->nbChildren] = obj;
525  layout->container->nbChildren++;
526 }
527 
537 static int addSwipeInternal(nbgl_layoutInternal_t *layoutInt,
538  uint16_t swipesMask,
539  nbgl_swipe_usage_t usage,
540  uint8_t token,
541  tune_index_e tuneId)
542 {
543  layoutObj_t *obj;
544 
545  if ((swipesMask & SWIPE_MASK) == 0) {
546  return -1;
547  }
548 
549  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, token, tuneId);
550  if (obj == NULL) {
551  return -1;
552  }
553  layoutInt->container->obj.touchMask = swipesMask;
554  layoutInt->swipeUsage = usage;
555 
556  return 0;
557 }
558 
566 static nbgl_container_t *addListItem(nbgl_layoutInternal_t *layoutInt, const listItem_t *itemDesc)
567 {
568  layoutObj_t *obj;
569  nbgl_text_area_t *textArea;
570  nbgl_container_t *container;
571  color_t color = ((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == OFF_STATE))
572  ? LIGHT_GRAY
573  : BLACK;
574  int16_t usedHeight = 40;
575 
576  LOG_DEBUG(LAYOUT_LOGGER, "addListItem():\n");
577 
578  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
579  obj = layoutAddCallbackObj(
580  layoutInt, (nbgl_obj_t *) container, itemDesc->token, itemDesc->tuneId);
581  if (obj == NULL) {
582  return NULL;
583  }
584 
585  // get container children (up to 4: text + left+right icons + sub text)
586  container->children = nbgl_containerPoolGet(4, layoutInt->layer);
587  container->nbChildren = 0;
588 
589  container->obj.area.width = AVAILABLE_WIDTH;
590  container->obj.area.height = itemDesc->large ? TOUCHABLE_MAIN_BAR_HEIGHT : TOUCHABLE_BAR_HEIGHT;
591  container->layout = HORIZONTAL;
592  container->obj.alignmentMarginX = BORDER_MARGIN;
593  container->obj.alignment = NO_ALIGNMENT;
594  container->obj.alignTo = NULL;
595  // the bar can only be touched if not inactive AND if one of the icon is present
596  // otherwise it is seen as a title
597  if (((itemDesc->type == TOUCHABLE_BAR_ITEM) && (itemDesc->state == ON_STATE))
598  || (itemDesc->type == SWITCH_ITEM)) {
599  container->obj.touchMask = (1 << TOUCHED);
600  container->obj.touchId = CONTROLS_ID + nbTouchableControls;
601  nbTouchableControls++;
602  }
603 
604  // allocate main text because always present
605  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
606  textArea->textColor = color;
607  textArea->text = PIC(itemDesc->text);
608  textArea->onDrawCallback = NULL;
609  textArea->fontId = SMALL_BOLD_FONT;
610  textArea->wrapping = true;
611  textArea->obj.area.width = container->obj.area.width;
612  if (itemDesc->iconLeft != NULL) {
613  // reduce text width accordingly
614  textArea->obj.area.width
615  -= ((nbgl_icon_details_t *) PIC(itemDesc->iconLeft))->width + BAR_INTERVALE;
616  }
617  if (itemDesc->iconRight != NULL) {
618  // reduce text width accordingly
619  textArea->obj.area.width
620  -= ((nbgl_icon_details_t *) PIC(itemDesc->iconRight))->width + BAR_INTERVALE;
621  }
622  else if (itemDesc->type == SWITCH_ITEM) {
623  textArea->obj.area.width -= 60 + BAR_INTERVALE;
624  }
625  textArea->obj.area.height = nbgl_getTextHeightInWidth(
626  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
627  usedHeight = MAX(usedHeight, textArea->obj.area.height);
628  textArea->style = NO_STYLE;
629  textArea->obj.alignment = MID_LEFT;
630  textArea->textAlignment = MID_LEFT;
631  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
632  container->nbChildren++;
633 
634  // allocate left icon if present
635  if (itemDesc->iconLeft != NULL) {
636  nbgl_image_t *imageLeft = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
637  imageLeft->foregroundColor = color;
638  imageLeft->buffer = PIC(itemDesc->iconLeft);
639  // align at the left of text
640  imageLeft->obj.alignment = MID_LEFT;
641  imageLeft->obj.alignTo = (nbgl_obj_t *) textArea;
642  imageLeft->obj.alignmentMarginX = BAR_INTERVALE;
643  container->children[container->nbChildren] = (nbgl_obj_t *) imageLeft;
644  container->nbChildren++;
645 
646  textArea->obj.alignmentMarginX = imageLeft->buffer->width + BAR_INTERVALE;
647 
648  usedHeight = MAX(usedHeight, imageLeft->buffer->height);
649  }
650  // allocate right icon if present
651  if (itemDesc->iconRight != NULL) {
652  nbgl_image_t *imageRight = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
653  imageRight->foregroundColor = color;
654  imageRight->buffer = PIC(itemDesc->iconRight);
655  // align at the right of text
656  imageRight->obj.alignment = MID_RIGHT;
657  imageRight->obj.alignmentMarginX = BAR_INTERVALE;
658  imageRight->obj.alignTo = (nbgl_obj_t *) textArea;
659 
660  container->children[container->nbChildren] = (nbgl_obj_t *) imageRight;
661  container->nbChildren++;
662 
663  usedHeight = MAX(usedHeight, imageRight->buffer->height);
664  }
665  else if (itemDesc->type == SWITCH_ITEM) {
666  nbgl_switch_t *switchObj = (nbgl_switch_t *) nbgl_objPoolGet(SWITCH, layoutInt->layer);
667  switchObj->onColor = BLACK;
668  switchObj->offColor = LIGHT_GRAY;
669  switchObj->state = itemDesc->state;
670  switchObj->obj.alignment = MID_RIGHT;
671  switchObj->obj.alignmentMarginX = BAR_INTERVALE;
672  switchObj->obj.alignTo = (nbgl_obj_t *) textArea;
673 
674  container->children[container->nbChildren] = (nbgl_obj_t *) switchObj;
675  container->nbChildren++;
676  }
677 
678  if (itemDesc->subText != NULL) {
679  nbgl_text_area_t *subTextArea
680  = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
681 
682  subTextArea->textColor = color;
683  subTextArea->text = PIC(itemDesc->subText);
684  subTextArea->textAlignment = MID_LEFT;
685  subTextArea->fontId = SMALL_REGULAR_FONT;
686  subTextArea->style = NO_STYLE;
687  subTextArea->wrapping = true;
688  subTextArea->obj.alignment = MID_LEFT;
689  subTextArea->obj.area.width = container->obj.area.width;
690  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
691  subTextArea->text,
692  subTextArea->obj.area.width,
693  subTextArea->wrapping);
694  container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
695  container->nbChildren++;
696  container->obj.area.height += subTextArea->obj.area.height + 12;
697 
698  // modify alignments to have sub-text under (icon left - text - icon right)
699  textArea->obj.alignmentMarginY = -(subTextArea->obj.area.height + 12) / 2;
700  subTextArea->obj.alignmentMarginY = (usedHeight + 12) / 2;
701  }
702 
703  // set this new container as child of main container
704  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
705 
706  return container;
707 }
708 
717 static nbgl_container_t *addContentCenter(nbgl_layoutInternal_t *layoutInt,
718  const nbgl_contentCenter_t *info)
719 {
720  nbgl_container_t *container;
721  nbgl_text_area_t *textArea = NULL;
722  nbgl_image_t *image = NULL;
723  uint16_t fullHeight = 0;
724 
725  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
726 
727  // get container children
728  container->nbChildren = 0;
729  container->children = nbgl_containerPoolGet(5, layoutInt->layer);
730 
731  // add icon if present
732  if (info->icon != NULL) {
733  image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
734  image->foregroundColor = BLACK;
735  image->buffer = PIC(info->icon);
736  image->obj.alignment = TOP_MIDDLE;
737  image->obj.alignmentMarginY = info->iconHug;
738 
739  fullHeight += image->buffer->height + info->iconHug;
740  container->children[container->nbChildren] = (nbgl_obj_t *) image;
741  container->nbChildren++;
742  }
743  // add title if present
744  if (info->title != NULL) {
745  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
746  textArea->textColor = BLACK;
747  textArea->text = PIC(info->title);
748  textArea->textAlignment = CENTER;
749  textArea->fontId = LARGE_MEDIUM_FONT;
750  textArea->wrapping = true;
751  textArea->obj.area.width = AVAILABLE_WIDTH;
752  textArea->obj.area.height = nbgl_getTextHeightInWidth(
753  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
754 
755  // if not the first child, put on bottom of the previous, with a margin
756  if (container->nbChildren > 0) {
757  textArea->obj.alignment = BOTTOM_MIDDLE;
758  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
759  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
760  }
761  else {
762  textArea->obj.alignment = TOP_MIDDLE;
763  }
764 
765  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
766 
767  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
768  container->nbChildren++;
769  }
770  // add small title if present
771  if (info->smallTitle != NULL) {
772  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
773  textArea->textColor = BLACK;
774  textArea->text = PIC(info->smallTitle);
775  textArea->textAlignment = CENTER;
776  textArea->fontId = SMALL_BOLD_FONT;
777  textArea->wrapping = true;
778  textArea->obj.area.width = AVAILABLE_WIDTH;
779  textArea->obj.area.height = nbgl_getTextHeightInWidth(
780  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
781 
782  // if not the first child, put on bottom of the previous, with a margin
783  if (container->nbChildren > 0) {
784  textArea->obj.alignment = BOTTOM_MIDDLE;
785  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
786  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN;
787  if (container->children[container->nbChildren - 1]->type == IMAGE) {
788  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
789  }
790  else {
791  textArea->obj.alignmentMarginY = 16;
792  }
793  }
794  else {
795  textArea->obj.alignment = TOP_MIDDLE;
796  }
797 
798  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
799 
800  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
801  container->nbChildren++;
802  }
803  // add description if present
804  if (info->description != NULL) {
805  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
806  textArea->textColor = BLACK;
807  textArea->text = PIC(info->description);
808  textArea->textAlignment = CENTER;
809  textArea->fontId = SMALL_REGULAR_FONT;
810  textArea->wrapping = true;
811  textArea->obj.area.width = AVAILABLE_WIDTH;
812  textArea->obj.area.height = nbgl_getTextHeightInWidth(
813  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
814 
815  // if not the first child, put on bottom of the previous, with a margin
816  if (container->nbChildren > 0) {
817  textArea->obj.alignment = BOTTOM_MIDDLE;
818  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
819  if (container->children[container->nbChildren - 1]->type == TEXT_AREA) {
820  // if previous element is text, only space of 16 px
821  textArea->obj.alignmentMarginY = 16;
822  }
823  else {
824  textArea->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN + info->iconHug;
825  }
826  }
827  else {
828  textArea->obj.alignment = TOP_MIDDLE;
829  }
830 
831  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
832 
833  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
834  container->nbChildren++;
835  }
836  // add sub-text if present
837  if (info->subText != NULL) {
838  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
839  textArea->textColor = DARK_GRAY;
840  textArea->text = PIC(info->subText);
841  textArea->textAlignment = CENTER;
842  textArea->fontId = SMALL_REGULAR_FONT;
843  textArea->wrapping = true;
844  textArea->obj.area.width = AVAILABLE_WIDTH;
845  textArea->obj.area.height = nbgl_getTextHeightInWidth(
846  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
847  // sub-text is included in a hug of 8px
848  textArea->obj.area.height += 2 * 8;
849  // if not the first child, put on bottom of the previous, with a margin
850  if (container->nbChildren > 0) {
851  textArea->obj.alignment = BOTTOM_MIDDLE;
852  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
853  textArea->obj.alignmentMarginY = 16;
854  if (container->children[container->nbChildren - 1]->type == IMAGE) {
855  textArea->obj.alignmentMarginY += info->iconHug;
856  }
857  }
858  else {
859  textArea->obj.alignment = TOP_MIDDLE;
860  }
861 
862  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
863 
864  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
865  container->nbChildren++;
866  }
867  container->layout = VERTICAL;
868  container->obj.alignment = CENTER;
869  container->obj.area.width = AVAILABLE_WIDTH;
870  container->obj.area.height = fullHeight;
871  if (info->padding) {
872  container->obj.area.height += 40;
873  }
874 
875  // set this new container as child of main container
876  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
877 
878  return container;
879 }
880 
881 static int addText(nbgl_layout_t *layout,
882  const char *text,
883  const char *subText,
884  uint8_t token,
885  uint8_t index,
886  bool withAlias)
887 {
888  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
889  nbgl_container_t *container;
890  nbgl_text_area_t *textArea;
891  nbgl_text_area_t *subTextArea;
892  uint16_t fullHeight = 0;
893 
894  if (layout == NULL) {
895  return -1;
896  }
897  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
898 
899  // get container children
900  container->children = nbgl_containerPoolGet(withAlias ? 3 : 2, layoutInt->layer);
901  container->obj.area.width = AVAILABLE_WIDTH;
902 
903  if (text != NULL) {
904  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
905 
906  textArea->textColor = BLACK;
907  textArea->text = PIC(text);
908  textArea->textAlignment = MID_LEFT;
909  textArea->fontId = SMALL_BOLD_FONT;
910  textArea->style = NO_STYLE;
911  textArea->wrapping = true;
912  textArea->obj.alignment = NO_ALIGNMENT;
913  textArea->obj.alignmentMarginY = PRE_TEXT_MARGIN;
914  textArea->obj.area.width = container->obj.area.width;
915  if (withAlias == true) {
916  textArea->obj.area.width -= 12 + MINI_PUSH_ICON.width;
917  }
918  textArea->obj.area.height = nbgl_getTextHeightInWidth(
919  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
920  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
921  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
922  container->nbChildren++;
923  if (withAlias == true) {
924  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
925  layoutObj_t *obj
926  = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) image, token, TUNE_TAP_CASUAL);
927  obj->index = index;
928  image->foregroundColor = BLACK;
929  image->buffer = &MINI_PUSH_ICON;
930  image->obj.alignment = RIGHT_TOP;
931  image->obj.alignmentMarginX = 12;
932  image->obj.alignTo = (nbgl_obj_t *) textArea;
933  image->obj.touchMask = (1 << TOUCHED);
934  image->obj.touchId = VALUE_BUTTON_1_ID + index;
935 
936  container->children[container->nbChildren] = (nbgl_obj_t *) image;
937  container->nbChildren++;
938  }
939  }
940  if (subText != NULL) {
941  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
942  subTextArea->textColor = BLACK;
943  subTextArea->text = PIC(subText);
944  subTextArea->fontId = SMALL_REGULAR_FONT;
945  subTextArea->style = NO_STYLE;
946  subTextArea->wrapping = true;
947  subTextArea->obj.area.width = container->obj.area.width;
948  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
949  subTextArea->text,
950  subTextArea->obj.area.width,
951  subTextArea->wrapping);
952  subTextArea->textAlignment = MID_LEFT;
953  subTextArea->obj.alignment = NO_ALIGNMENT;
954  if (text != NULL) {
955  subTextArea->obj.alignmentMarginY = TEXT_SUBTEXT_MARGIN;
956  fullHeight += POST_SUBTEXT_MARGIN; // under the subText
957  }
958  else {
959 #ifdef TARGET_STAX
960  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
961  fullHeight += BORDER_MARGIN;
962 #else // TARGET_STAX
963  subTextArea->obj.alignmentMarginY = 26;
964  fullHeight += 26; // under the subText
965 #endif // TARGET_STAX
966  }
967  container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea;
968  container->nbChildren++;
969  fullHeight += subTextArea->obj.area.height + subTextArea->obj.alignmentMarginY;
970  }
971  else {
972  fullHeight += PRE_TEXT_MARGIN;
973  }
974  container->obj.area.height = fullHeight;
975  container->layout = VERTICAL;
976  container->obj.alignmentMarginX = BORDER_MARGIN;
977  container->obj.alignment = NO_ALIGNMENT;
978  // set this new obj as child of main container
979  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
980 
981  return container->obj.area.height;
982 }
983 
984 /**********************
985  * GLOBAL FUNCTIONS
986  **********************/
987 
995 {
996  nbgl_layoutInternal_t *layout = NULL;
997 
998  // find an empty layout in the proper "layer"
999  if (description->modal) {
1000  if (gLayout[1].nbChildren == 0) {
1001  layout = &gLayout[1];
1002  }
1003  else if (gLayout[2].nbChildren == 0) {
1004  layout = &gLayout[2];
1005  }
1006  }
1007  else {
1008  // automatically "release" a potentially opened non-modal layout
1009  gLayout[0].nbChildren = 0;
1010  layout = &gLayout[0];
1011  }
1012  if (layout == NULL) {
1013  LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutGet(): impossible to get a layout!\n");
1014  return NULL;
1015  }
1016 
1017  // reset globals
1018  memset(layout, 0, sizeof(nbgl_layoutInternal_t));
1019 
1020  nbTouchableControls = 0;
1021 
1022  layout->callback = (nbgl_layoutTouchCallback_t) PIC(description->onActionCallback);
1023  layout->modal = description->modal;
1024  layout->withLeftBorder = description->withLeftBorder;
1025  if (description->modal) {
1026  layout->layer = nbgl_screenPush(&layout->children,
1028  &description->ticker,
1029  (nbgl_touchCallback_t) touchCallback);
1030  }
1031  else {
1032  nbgl_screenSet(&layout->children,
1034  &description->ticker,
1035  (nbgl_touchCallback_t) touchCallback);
1036  layout->layer = 0;
1037  }
1038  layout->container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layout->layer);
1039  layout->container->obj.area.width = SCREEN_WIDTH;
1040  layout->container->obj.area.height = SCREEN_HEIGHT;
1041  layout->container->layout = VERTICAL;
1042  layout->container->children = nbgl_containerPoolGet(NB_MAX_CONTAINER_CHILDREN, layout->layer);
1043  // by default, if no header, main container is aligned on top-left
1044  layout->container->obj.alignment = TOP_LEFT;
1045  // main container is always the second object, leaving space for header
1046  layout->children[MAIN_CONTAINER_INDEX] = (nbgl_obj_t *) layout->container;
1048 
1049  // if a tap text is defined, make the container tapable and display this text in gray
1050  if (description->tapActionText != NULL) {
1051  layoutObj_t *obj;
1052 
1053  obj = &layout->callbackObjPool[layout->nbUsedCallbackObjs];
1054  layout->nbUsedCallbackObjs++;
1055  obj->obj = (nbgl_obj_t *) layout->container;
1056  obj->token = description->tapActionToken;
1057  obj->tuneId = description->tapTuneId;
1058  layout->container->obj.touchMask = (1 << TOUCHED);
1059  layout->container->obj.touchId = WHOLE_SCREEN_ID;
1060 
1061  nbgl_layoutUpFooter_t footerDesc;
1062  footerDesc.type = UP_FOOTER_TEXT;
1063  footerDesc.text.text = PIC(description->tapActionText);
1064  footerDesc.text.token = description->tapActionToken;
1065  footerDesc.text.tuneId = description->tapTuneId;
1066  nbgl_layoutAddUpFooter((nbgl_layout_t *) layout, &footerDesc);
1067  }
1068 
1069  return (nbgl_layout_t *) layout;
1070 }
1071 
1084  uint16_t swipesMask,
1085  const char *text,
1086  uint8_t token,
1087  tune_index_e tuneId)
1088 {
1089  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1090 
1091  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwipe():\n");
1092  if (layout == NULL) {
1093  return -1;
1094  }
1095 
1096  if (text) {
1097  // create 'tap to continue' text area
1098  layoutInt->tapText = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0);
1099  layoutInt->tapText->text = PIC(text);
1100  layoutInt->tapText->textColor = DARK_GRAY;
1101  layoutInt->tapText->fontId = SMALL_REGULAR_FONT;
1102  layoutInt->tapText->obj.area.width = AVAILABLE_WIDTH;
1103  layoutInt->tapText->obj.area.height = nbgl_getFontLineHeight(layoutInt->tapText->fontId);
1104  layoutInt->tapText->textAlignment = CENTER;
1105 #ifdef TARGET_STAX
1106  layoutInt->tapText->obj.alignmentMarginY = BORDER_MARGIN;
1107 #else // TARGET_STAX
1108  layoutInt->tapText->obj.alignmentMarginY = 30;
1109 #endif // TARGET_STAX
1110  layoutInt->tapText->obj.alignment = BOTTOM_MIDDLE;
1111  }
1112  return addSwipeInternal(layoutInt, swipesMask, SWIPE_USAGE_CUSTOM, token, tuneId);
1113 }
1114 
1125  const nbgl_icon_details_t *icon,
1126  uint8_t token,
1127  tune_index_e tuneId)
1128 {
1129  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1130  layoutObj_t *obj;
1131  nbgl_button_t *button;
1132 
1133  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTopRightButton():\n");
1134  if (layout == NULL) {
1135  return -1;
1136  }
1137  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
1138  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
1139  if (obj == NULL) {
1140  return -1;
1141  }
1142 
1143  button->obj.area.width = BUTTON_DIAMETER;
1144  button->obj.area.height = BUTTON_DIAMETER;
1145  button->radius = BUTTON_RADIUS;
1146  button->obj.alignmentMarginX = BORDER_MARGIN;
1147  button->obj.alignmentMarginY = BORDER_MARGIN;
1148  button->foregroundColor = BLACK;
1149  button->innerColor = WHITE;
1150  button->borderColor = LIGHT_GRAY;
1151  button->obj.touchMask = (1 << TOUCHED);
1152  button->obj.touchId = TOP_RIGHT_BUTTON_ID;
1153  button->icon = PIC(icon);
1154  button->obj.alignment = TOP_RIGHT;
1155 
1156  // add to screen
1157  layoutInt->children[TOP_RIGHT_BUTTON_INDEX] = (nbgl_obj_t *) button;
1158 
1159  return 0;
1160 }
1161 
1170 {
1171  nbgl_layoutFooter_t footerDesc;
1172  footerDesc.type = FOOTER_NAV;
1173  footerDesc.separationLine = info->withSeparationLine;
1174  footerDesc.navigation.activePage = info->activePage;
1175  footerDesc.navigation.nbPages = info->nbPages;
1176  footerDesc.navigation.withExitKey = info->withExitKey;
1177  footerDesc.navigation.withBackKey = info->withBackKey;
1178  footerDesc.navigation.withPageIndicator = false;
1179  footerDesc.navigation.token = info->token;
1180  footerDesc.navigation.tuneId = info->tuneId;
1181  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1182 }
1183 
1196  const nbgl_icon_details_t *icon,
1197  uint8_t token,
1198  bool separationLine,
1199  tune_index_e tuneId)
1200 {
1201  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddBottomButton():\n");
1202  nbgl_layoutFooter_t footerDesc;
1203  footerDesc.type = FOOTER_SIMPLE_BUTTON;
1204  footerDesc.separationLine = separationLine;
1205  footerDesc.button.fittingContent = false;
1206  footerDesc.button.icon = PIC(icon);
1207  footerDesc.button.text = NULL;
1208  footerDesc.button.token = token;
1209  footerDesc.button.tuneId = tuneId;
1210  footerDesc.button.style = WHITE_BACKGROUND;
1211  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1212 }
1213 
1222 {
1223  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1224  nbgl_container_t *container;
1225  listItem_t itemDesc;
1226 
1227  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar():\n");
1228  if (layout == NULL) {
1229  return -1;
1230  }
1231  // main text is mandatory
1232  if (barLayout->text == NULL) {
1233  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar(): main text is mandatory\n");
1234  }
1235 
1236  itemDesc.iconLeft = barLayout->iconLeft;
1237  itemDesc.iconRight = barLayout->iconRight;
1238  itemDesc.text = barLayout->text;
1239  itemDesc.subText = barLayout->subText;
1240  itemDesc.token = barLayout->token;
1241  itemDesc.tuneId = barLayout->tuneId;
1242  itemDesc.state = (barLayout->inactive) ? OFF_STATE : ON_STATE;
1243  itemDesc.large = barLayout->large;
1244  itemDesc.type = TOUCHABLE_BAR_ITEM;
1245  container = addListItem(layoutInt, &itemDesc);
1246 
1247  if (container == NULL) {
1248  return -1;
1249  }
1250  return container->obj.area.height;
1251 }
1252 
1260 int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
1261 {
1262  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1263  nbgl_container_t *container;
1264  listItem_t itemDesc;
1265 
1266  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwitch():\n");
1267  if (layout == NULL) {
1268  return -1;
1269  }
1270  // main text is mandatory
1271  if (switchLayout->text == NULL) {
1272  LOG_FATAL(LAYOUT_LOGGER, "nbgl_layoutAddSwitch(): main text is mandatory\n");
1273  }
1274 
1275  itemDesc.iconLeft = NULL;
1276  itemDesc.iconRight = NULL;
1277  itemDesc.text = switchLayout->text;
1278  itemDesc.subText = switchLayout->subText;
1279  itemDesc.token = switchLayout->token;
1280  itemDesc.tuneId = switchLayout->tuneId;
1281  itemDesc.state = switchLayout->initState;
1282  itemDesc.large = false;
1283  itemDesc.type = SWITCH_ITEM;
1284  container = addListItem(layoutInt, &itemDesc);
1285 
1286  if (container == NULL) {
1287  return -1;
1288  }
1289  return container->obj.area.height;
1290 }
1291 
1300 int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
1301 {
1302  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddText():\n");
1303  return addText(layout, text, subText, 0, 0, false);
1304 }
1305 
1318  const char *text,
1319  const char *subText,
1320  uint8_t token,
1321  uint8_t index)
1322 {
1323  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextWithAlias():\n");
1324  return addText(layout, text, subText, token, index, true);
1325 }
1326 
1334 int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text)
1335 {
1336  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1337  nbgl_text_area_t *textArea;
1338 
1339  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSubHeaderText():\n");
1340  if (layout == NULL) {
1341  return -1;
1342  }
1343  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1344 
1345  textArea->textColor = BLACK;
1346  textArea->text = PIC(text);
1347  textArea->textAlignment = MID_LEFT;
1348  textArea->fontId = SMALL_REGULAR_FONT;
1349  textArea->style = NO_STYLE;
1350  textArea->wrapping = true;
1351  textArea->obj.alignment = NO_ALIGNMENT;
1352  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1353  textArea->obj.area.width = AVAILABLE_WIDTH;
1354  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1355  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1356 #ifdef TARGET_STAX
1357  textArea->obj.area.height += 2 * 24;
1358 #else // TARGET_STAX
1359  textArea->obj.area.height += 2 * 28;
1360 #endif // TARGET_STAX
1361 
1362  // set this new obj as child of main container
1363  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1364 
1365  return textArea->obj.area.height;
1366 }
1367 
1375 int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text)
1376 {
1377  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1378  nbgl_text_area_t *textArea;
1379 
1380  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLargeCaseText():\n");
1381  if (layout == NULL) {
1382  return -1;
1383  }
1384  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1385 
1386  textArea->textColor = BLACK;
1387  textArea->text = PIC(text);
1388  textArea->textAlignment = MID_LEFT;
1389  textArea->fontId = LARGE_MEDIUM_FONT;
1390  textArea->obj.area.width = AVAILABLE_WIDTH;
1391  textArea->wrapping = true;
1392  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1393  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1394  textArea->style = NO_STYLE;
1395  textArea->obj.alignment = NO_ALIGNMENT;
1396  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1397 #ifdef TARGET_STAX
1398  // if first object of container, increase the margin from top
1399  if (layoutInt->container->nbChildren == 0) {
1400  textArea->obj.alignmentMarginY += BORDER_MARGIN;
1401  }
1402 #endif // TARGET_STAX
1403 
1404  // set this new obj as child of main container
1405  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1406 
1407  return 0;
1408 }
1409 
1423  const char *title,
1424  const char *description,
1425  const char *info)
1426 {
1427  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1428  nbgl_text_area_t *textArea;
1429 
1430  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTextContent():\n");
1431  if (layout == NULL) {
1432  return -1;
1433  }
1434 
1435  // create title
1436  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1437  textArea->textColor = BLACK;
1438  textArea->text = PIC(title);
1439  textArea->textAlignment = MID_LEFT;
1440  textArea->fontId = LARGE_MEDIUM_FONT;
1441  textArea->style = NO_STYLE;
1442  textArea->wrapping = true;
1443  textArea->obj.alignment = NO_ALIGNMENT;
1444  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1445 #ifdef TARGET_STAX
1446  textArea->obj.alignmentMarginY = 24;
1447 #else // TARGET_STAX
1448  textArea->obj.alignmentMarginY = 16;
1449 #endif // TARGET_STAX
1450  textArea->obj.area.width = AVAILABLE_WIDTH;
1451  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1452  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1453  // set this new obj as child of main container
1454  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1455 
1456  // create description
1457  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1458  textArea->textColor = BLACK;
1459  textArea->text = PIC(description);
1460  textArea->fontId = SMALL_REGULAR_FONT;
1461  textArea->style = NO_STYLE;
1462  textArea->wrapping = true;
1463  textArea->obj.area.width = AVAILABLE_WIDTH;
1464  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1465  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1466  textArea->textAlignment = MID_LEFT;
1467  textArea->obj.alignment = NO_ALIGNMENT;
1468  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1469 #ifdef TARGET_STAX
1470  textArea->obj.alignmentMarginY = 16;
1471 #else // TARGET_STAX
1472  textArea->obj.alignmentMarginY = 24;
1473 #endif // TARGET_STAX
1474  // set this new obj as child of main container
1475  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1476 
1477  // create info on the bottom
1478  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1479  textArea->textColor = DARK_GRAY;
1480  textArea->text = PIC(info);
1481  textArea->fontId = SMALL_REGULAR_FONT;
1482  textArea->style = NO_STYLE;
1483  textArea->wrapping = true;
1484  textArea->obj.area.width = AVAILABLE_WIDTH;
1485  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1486  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1487  textArea->textAlignment = MID_LEFT;
1488  textArea->obj.alignment = BOTTOM_LEFT;
1489  textArea->obj.alignmentMarginX = BORDER_MARGIN;
1490  textArea->obj.alignmentMarginY = 40;
1491  // set this new obj as child of main container
1492  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
1493 
1494  return layoutInt->container->obj.area.height;
1495 }
1496 
1505 {
1506  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1507  layoutObj_t *obj;
1508  uint8_t i;
1509 
1510  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddRadioChoice():\n");
1511  if (layout == NULL) {
1512  return -1;
1513  }
1514  for (i = 0; i < choices->nbChoices; i++) {
1515  nbgl_container_t *container;
1516  nbgl_text_area_t *textArea;
1517  nbgl_radio_t *button;
1518  nbgl_line_t *line;
1519 
1520  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1521  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1522  button = (nbgl_radio_t *) nbgl_objPoolGet(RADIO_BUTTON, layoutInt->layer);
1523 
1524  obj = layoutAddCallbackObj(
1525  layoutInt, (nbgl_obj_t *) container, choices->token, choices->tuneId);
1526  if (obj == NULL) {
1527  return -1;
1528  }
1529 
1530  // get container children (max 2)
1531  container->nbChildren = 2;
1532  container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
1533  container->obj.area.width = AVAILABLE_WIDTH;
1534  container->obj.area.height = RADIO_CHOICE_HEIGHT;
1535  container->obj.alignment = NO_ALIGNMENT;
1536  container->obj.alignmentMarginX = BORDER_MARGIN;
1537  container->obj.alignTo = (nbgl_obj_t *) NULL;
1538 
1539  // init button for this choice
1540  button->activeColor = BLACK;
1541  button->borderColor = LIGHT_GRAY;
1542  button->obj.alignTo = (nbgl_obj_t *) container;
1543  button->obj.alignment = MID_RIGHT;
1544  button->state = OFF_STATE;
1545  container->children[1] = (nbgl_obj_t *) button;
1546 
1547  // init text area for this choice
1548  if (choices->localized == true) {
1549 #ifdef HAVE_LANGUAGE_PACK
1550  textArea->text = get_ux_loc_string(choices->nameIds[i]);
1551 #endif // HAVE_LANGUAGE_PACK
1552  }
1553  else {
1554  textArea->text = PIC(choices->names[i]);
1555  }
1556  textArea->textAlignment = MID_LEFT;
1557  textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH;
1558  textArea->style = NO_STYLE;
1559  textArea->obj.alignment = MID_LEFT;
1560  textArea->obj.alignTo = (nbgl_obj_t *) container;
1561  container->children[0] = (nbgl_obj_t *) textArea;
1562 
1563  // whole container should be touchable
1564  container->obj.touchMask = (1 << TOUCHED);
1565  container->obj.touchId = CONTROLS_ID + nbTouchableControls;
1566  nbTouchableControls++;
1567 
1568  // highlight init choice
1569  if (i == choices->initChoice) {
1570  button->state = ON_STATE;
1571  textArea->textColor = BLACK;
1572  textArea->fontId = SMALL_BOLD_FONT;
1573  }
1574  else {
1575  button->state = OFF_STATE;
1576  textArea->textColor = DARK_GRAY;
1577  textArea->fontId = SMALL_REGULAR_FONT;
1578  }
1579  textArea->obj.area.height = nbgl_getFontHeight(textArea->fontId);
1580 
1581  line = createHorizontalLine(layoutInt->layer);
1582  line->obj.alignmentMarginY = -4;
1583  line->offset = 3;
1584 
1585  // set these new objs as child of main container
1586  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1587  layoutAddObject(layoutInt, (nbgl_obj_t *) line);
1588  }
1589 
1590  return 0;
1591 }
1592 
1602 {
1603  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1604  nbgl_container_t *container;
1605  nbgl_contentCenter_t centeredInfo = {.icon = info->icon,
1606  .title = NULL,
1607  .smallTitle = NULL,
1608  .description = NULL,
1609  .subText = NULL,
1610  .iconHug = 0,
1611  .padding = false};
1612 
1613  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddCenteredInfo():\n");
1614  if (layout == NULL) {
1615  return -1;
1616  }
1617 
1618  if (info->text1 != NULL) {
1619  if (info->style != NORMAL_INFO) {
1620  centeredInfo.title = info->text1;
1621  }
1622  else {
1623  centeredInfo.smallTitle = info->text1;
1624  }
1625  }
1626  if (info->text2 != NULL) {
1627  if (info->style != LARGE_CASE_BOLD_INFO) {
1628  centeredInfo.description = info->text2;
1629  }
1630  else {
1631  centeredInfo.smallTitle = info->text2;
1632  }
1633  }
1634  if (info->text3 != NULL) {
1635  if (info->style == LARGE_CASE_GRAY_INFO) {
1636  centeredInfo.subText = info->text3;
1637  }
1638  else {
1639  centeredInfo.description = info->text3;
1640  }
1641  }
1642  container = addContentCenter(layoutInt, &centeredInfo);
1643 
1644  if (info->onTop) {
1645  container->obj.alignmentMarginX = BORDER_MARGIN;
1646  container->obj.alignmentMarginY = BORDER_MARGIN + info->offsetY;
1647  container->obj.alignment = NO_ALIGNMENT;
1648  }
1649  else {
1650  container->obj.alignmentMarginY = info->offsetY;
1651  }
1652 
1653  return container->obj.area.height;
1654 }
1655 
1665 {
1666  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1667  nbgl_container_t *container;
1668 
1669  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddContentCenter():\n");
1670  if (layout == NULL) {
1671  return -1;
1672  }
1673 
1674  container = addContentCenter(layoutInt, info);
1675 
1676  return container->obj.area.height;
1677 }
1678 
1679 #ifdef NBGL_QRCODE
1689 {
1690  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1691  nbgl_container_t *container;
1692  nbgl_text_area_t *textArea = NULL;
1694  uint16_t fullHeight = 0;
1695 
1696  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddQRCode():\n");
1697  if (layout == NULL) {
1698  return -1;
1699  }
1700 
1701  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1702 
1703  // get container children (max 2 (QRCode + text1 + text2))
1704  container->children = nbgl_containerPoolGet(3, layoutInt->layer);
1705  container->nbChildren = 0;
1706 
1707  qrcode = (nbgl_qrcode_t *) nbgl_objPoolGet(QR_CODE, layoutInt->layer);
1708  // version is forced to V10 if url is longer than 62 characters
1709  if (strlen(PIC(info->url)) > 62) {
1710  qrcode->version = QRCODE_V10;
1711  }
1712  else {
1713  qrcode->version = QRCODE_V4;
1714  }
1715  qrcode->foregroundColor = BLACK;
1716  // in QR V4, we use 8*8 screen pixels for one QR pixel
1717  // in QR V10, we use 4*4 screen pixels for one QR pixel
1718  qrcode->obj.area.width
1719  = (qrcode->version == QRCODE_V4) ? (QR_V4_NB_PIX_SIZE * 8) : (QR_V10_NB_PIX_SIZE * 4);
1720  qrcode->obj.area.height = qrcode->obj.area.width;
1721  qrcode->text = PIC(info->url);
1722  qrcode->obj.area.bpp = NBGL_BPP_1;
1723  qrcode->obj.alignment = TOP_MIDDLE;
1724 
1725  fullHeight += qrcode->obj.area.height;
1726  container->children[container->nbChildren] = (nbgl_obj_t *) qrcode;
1727  container->nbChildren++;
1728 
1729  if (info->text1 != NULL) {
1730  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1731  textArea->textColor = BLACK;
1732  textArea->text = PIC(info->text1);
1733  textArea->textAlignment = CENTER;
1734  textArea->fontId = (info->largeText1 == true) ? LARGE_MEDIUM_FONT : SMALL_REGULAR_FONT;
1735  textArea->wrapping = true;
1736  textArea->obj.area.width = AVAILABLE_WIDTH;
1737  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1738  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1739  textArea->obj.alignment = BOTTOM_MIDDLE;
1740  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1741  textArea->obj.alignmentMarginY = 24;
1742 
1743  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1744 
1745  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1746  container->nbChildren++;
1747  }
1748  if (info->text2 != NULL) {
1749  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1750  textArea->textColor = DARK_GRAY;
1751  textArea->text = PIC(info->text2);
1752  textArea->textAlignment = CENTER;
1753  textArea->fontId = SMALL_REGULAR_FONT;
1754  textArea->wrapping = true;
1755  textArea->obj.area.width = AVAILABLE_WIDTH;
1756  textArea->obj.area.height = nbgl_getTextHeightInWidth(
1757  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
1758  textArea->obj.alignment = BOTTOM_MIDDLE;
1759  textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
1760  if (info->text1 != NULL) {
1761 #ifdef TARGET_STAX
1762  textArea->obj.alignmentMarginY = 40;
1763 #else // TARGET_STAX
1764  textArea->obj.alignmentMarginY = 28;
1765 #endif // TARGET_STAX
1766  }
1767  else {
1768  textArea->obj.alignmentMarginY = 32;
1769  fullHeight += 8;
1770  }
1771 
1772  fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
1773 
1774  container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
1775  container->nbChildren++;
1776  }
1777  // ensure that fullHeight is fitting in main container height (with 16 px margin)
1778  if ((fullHeight >= (layoutInt->container->obj.area.height - 16))
1779  && (qrcode->version == QRCODE_V4)) {
1780  qrcode->version = QRCODE_V4_SMALL;
1781  // in QR V4 small, we use 4*4 screen pixels for one QR pixel
1782  qrcode->obj.area.width = QR_V4_NB_PIX_SIZE * 4;
1783  qrcode->obj.area.height = qrcode->obj.area.width;
1784  fullHeight -= QR_V4_NB_PIX_SIZE * 4;
1785  }
1786  container->obj.area.height = fullHeight;
1787  container->layout = VERTICAL;
1788  if (info->centered) {
1789  container->obj.alignment = CENTER;
1790  }
1791  else {
1792  container->obj.alignment = BOTTOM_MIDDLE;
1793  container->obj.alignTo
1794  = layoutInt->container->children[layoutInt->container->nbChildren - 1];
1795  }
1796  container->obj.alignmentMarginY = info->offsetY;
1797 
1798  container->obj.area.width = AVAILABLE_WIDTH;
1799 
1800  // set this new container as child of main container
1801  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1802 
1803  return fullHeight;
1804 }
1805 #endif // NBGL_QRCODE
1806 
1816 {
1817  nbgl_layoutFooter_t footerDesc;
1818  footerDesc.type = FOOTER_CHOICE_BUTTONS;
1819  footerDesc.separationLine = false;
1820  footerDesc.choiceButtons.bottomText = info->bottomText;
1821  footerDesc.choiceButtons.token = info->token;
1822  footerDesc.choiceButtons.topText = info->topText;
1823  footerDesc.choiceButtons.topIcon = info->topIcon;
1824  footerDesc.choiceButtons.style = info->style;
1825  footerDesc.choiceButtons.tuneId = info->tuneId;
1826  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
1827 }
1828 
1839  const nbgl_layoutHorizontalButtons_t *info)
1840 {
1842  .horizontalButtons.leftIcon = info->leftIcon,
1843  .horizontalButtons.leftToken = info->leftToken,
1844  .horizontalButtons.rightText = info->rightText,
1845  .horizontalButtons.rightToken = info->rightToken,
1846  .horizontalButtons.tuneId = info->tuneId};
1847 
1848  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHorizontalButtons():\n");
1849  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
1850 }
1851 
1860 {
1861  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1862  nbgl_text_area_t *itemTextArea;
1863  nbgl_text_area_t *valueTextArea;
1864  nbgl_container_t *container;
1865  uint8_t i;
1866 
1867  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTagValueList():\n");
1868  if (layout == NULL) {
1869  return -1;
1870  }
1871 
1872  for (i = 0; i < list->nbPairs; i++) {
1873  const nbgl_layoutTagValue_t *pair;
1874  uint16_t fullHeight = 0;
1875  const nbgl_icon_details_t *valueIcon = NULL;
1876 
1877  if (list->pairs != NULL) {
1878  pair = &list->pairs[i];
1879  }
1880  else {
1881  pair = list->callback(list->startIndex + i);
1882  }
1883 
1884  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
1885 
1886  // get container children (max 3 if a valueIcon, otherwise 2)
1887  container->children
1888  = nbgl_containerPoolGet((pair->valueIcon != NULL) ? 3 : 2, layoutInt->layer);
1889 
1890  itemTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1891  valueTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
1892 
1893  // init text area for this choice
1894  itemTextArea->textColor = DARK_GRAY;
1895  itemTextArea->text = PIC(pair->item);
1896  itemTextArea->textAlignment = MID_LEFT;
1897  itemTextArea->fontId = SMALL_REGULAR_FONT;
1898  itemTextArea->wrapping = true;
1899  itemTextArea->obj.area.width = AVAILABLE_WIDTH;
1900  itemTextArea->obj.area.height = nbgl_getTextHeightInWidth(
1901  itemTextArea->fontId, itemTextArea->text, AVAILABLE_WIDTH, itemTextArea->wrapping);
1902  itemTextArea->style = NO_STYLE;
1903  itemTextArea->obj.alignment = NO_ALIGNMENT;
1904  itemTextArea->obj.alignmentMarginX = 0;
1905  itemTextArea->obj.alignmentMarginY = 0;
1906  itemTextArea->obj.alignTo = NULL;
1907  container->children[container->nbChildren] = (nbgl_obj_t *) itemTextArea;
1908  container->nbChildren++;
1909 
1910  fullHeight += itemTextArea->obj.area.height;
1911 
1912  // init button for this choice
1913  valueTextArea->textColor = BLACK;
1914  valueTextArea->text = PIC(pair->value);
1915  valueTextArea->textAlignment = MID_LEFT;
1916  if (list->smallCaseForValue) {
1917  valueTextArea->fontId = SMALL_BOLD_FONT;
1918  }
1919  else {
1920  valueTextArea->fontId = LARGE_MEDIUM_FONT;
1921  }
1922  if ((pair->aliasValue == 0) && (pair->valueIcon == NULL)) {
1923  valueTextArea->obj.area.width = AVAILABLE_WIDTH;
1924  }
1925  else {
1926  if (pair->aliasValue) {
1927  // if the value is an alias, we automatically display a (>) icon
1928  valueIcon = &MINI_PUSH_ICON;
1929  }
1930  else {
1931  // otherwise use the provided icon
1932  valueIcon = PIC(pair->valueIcon);
1933  }
1934  // decrease the available width for value text
1935  valueTextArea->obj.area.width = AVAILABLE_WIDTH - valueIcon->width - 12;
1936  }
1937 
1938  // handle the nbMaxLinesForValue parameter, used to automatically keep only
1939  // nbMaxLinesForValue lines
1940  uint16_t nbLines = nbgl_getTextNbLinesInWidth(valueTextArea->fontId,
1941  valueTextArea->text,
1942  valueTextArea->obj.area.width,
1943  list->wrapping);
1944  // use this nbMaxLinesForValue parameter only if >0
1945  if ((list->nbMaxLinesForValue > 0) && (nbLines > list->nbMaxLinesForValue)) {
1946  nbLines = list->nbMaxLinesForValue;
1947  valueTextArea->nbMaxLines = list->nbMaxLinesForValue;
1948  }
1949  const nbgl_font_t *font = nbgl_getFont(valueTextArea->fontId);
1950  valueTextArea->obj.area.height = nbLines * font->line_height;
1951  valueTextArea->style = NO_STYLE;
1952  valueTextArea->obj.alignment = BOTTOM_LEFT;
1953  valueTextArea->obj.alignmentMarginY = 4;
1954  valueTextArea->obj.alignTo = (nbgl_obj_t *) itemTextArea;
1955  valueTextArea->wrapping = list->wrapping;
1956  container->children[container->nbChildren] = (nbgl_obj_t *) valueTextArea;
1957  container->nbChildren++;
1958 
1959  fullHeight += valueTextArea->obj.area.height + valueTextArea->obj.alignmentMarginY;
1960  if (valueIcon != NULL) {
1961  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
1963  layoutInt, (nbgl_obj_t *) image, list->token, TUNE_TAP_CASUAL);
1964  obj->index = i;
1965  image->foregroundColor = BLACK;
1966  image->buffer = valueIcon;
1967  image->obj.alignment = RIGHT_TOP;
1968  image->obj.alignmentMarginX = 12;
1969  image->obj.alignTo = (nbgl_obj_t *) valueTextArea;
1970  image->obj.touchMask = (1 << TOUCHED);
1971  image->obj.touchId = VALUE_BUTTON_1_ID + i;
1972 
1973  container->children[container->nbChildren] = (nbgl_obj_t *) image;
1974  container->nbChildren++;
1975  }
1976 
1977  container->obj.area.width = AVAILABLE_WIDTH;
1978  container->obj.area.height = fullHeight;
1979  container->layout = VERTICAL;
1980  container->obj.alignmentMarginX = BORDER_MARGIN;
1981 #ifdef TARGET_STAX
1982  // On Stax, 12 px between each tag/value pair
1983  if (i > 0) {
1984  container->obj.alignmentMarginY = 12;
1985  }
1986  else {
1987  container->obj.alignmentMarginY = 24;
1988  }
1989 #else // TARGET_STAX
1990  // On Flex, 24 px between each tag/value pair
1991  if (i > 0) {
1992  container->obj.alignmentMarginY = 24;
1993  }
1994 #endif // TARGET_STAX
1995  container->obj.alignment = NO_ALIGNMENT;
1996 
1997  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
1998  }
1999 
2000  return 0;
2001 }
2002 
2012 {
2013  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2014  nbgl_progress_bar_t *progress;
2015 
2016  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressBar():\n");
2017  if (layout == NULL) {
2018  return -1;
2019  }
2020  if (barLayout->text != NULL) {
2021  nbgl_text_area_t *textArea;
2022 
2024  ((nbgl_layoutInternal_t *) layout)->layer);
2025  textArea->textColor = BLACK;
2026  textArea->text = PIC(barLayout->text);
2027  textArea->textAlignment = MID_LEFT;
2028  textArea->fontId = SMALL_REGULAR_FONT;
2029  textArea->wrapping = true;
2030  textArea->obj.area.width = AVAILABLE_WIDTH;
2031  textArea->obj.area.height = nbgl_getTextHeightInWidth(
2032  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
2033  textArea->style = NO_STYLE;
2034  textArea->obj.alignment = NO_ALIGNMENT;
2035  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2036  textArea->obj.alignmentMarginY = BORDER_MARGIN;
2037  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
2038  }
2040  ((nbgl_layoutInternal_t *) layout)->layer);
2041  progress->foregroundColor = BLACK;
2042  progress->withBorder = true;
2043  progress->state = barLayout->percentage;
2044  progress->obj.area.width = 120;
2045  progress->obj.area.height = 12;
2046  progress->obj.alignment = NO_ALIGNMENT;
2047  progress->obj.alignmentMarginX = (AVAILABLE_WIDTH - progress->obj.area.width) / 2;
2048  progress->obj.alignmentMarginY = BORDER_MARGIN;
2049  layoutAddObject(layoutInt, (nbgl_obj_t *) progress);
2050 
2051  if (barLayout->subText != NULL) {
2052  nbgl_text_area_t *subTextArea;
2053 
2054  subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(
2055  TEXT_AREA, ((nbgl_layoutInternal_t *) layout)->layer);
2056  subTextArea->textColor = LIGHT_GRAY;
2057  subTextArea->text = PIC(barLayout->subText);
2058  subTextArea->textAlignment = MID_LEFT;
2059  subTextArea->fontId = SMALL_REGULAR_FONT;
2060  subTextArea->wrapping = true;
2061  subTextArea->obj.area.width = AVAILABLE_WIDTH;
2062  subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId,
2063  subTextArea->text,
2064  subTextArea->obj.area.width,
2065  subTextArea->wrapping);
2066  subTextArea->style = NO_STYLE;
2067  subTextArea->obj.alignment = NO_ALIGNMENT;
2068  subTextArea->obj.alignmentMarginX = BORDER_MARGIN;
2069  subTextArea->obj.alignmentMarginY = BORDER_MARGIN;
2070  layoutAddObject(layoutInt, (nbgl_obj_t *) subTextArea);
2071  }
2072 
2073  return 0;
2074 }
2075 
2083 {
2084  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2085  nbgl_line_t *line;
2086 
2087  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSeparationLine():\n");
2088  line = createHorizontalLine(layoutInt->layer);
2089  line->obj.alignmentMarginY = -4;
2090  line->offset = 3;
2091  layoutAddObject(layoutInt, (nbgl_obj_t *) line);
2092  return 0;
2093 }
2094 
2103 {
2104  layoutObj_t *obj;
2105  nbgl_button_t *button;
2106  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2107 
2108  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddButton():\n");
2109  if (layout == NULL) {
2110  return -1;
2111  }
2112 
2113  // Add in footer if matching
2114  if ((buttonInfo->onBottom) && (!buttonInfo->fittingContent)) {
2115  if (layoutInt->footerContainer == NULL) {
2116  nbgl_layoutFooter_t footerDesc;
2117  footerDesc.type = FOOTER_SIMPLE_BUTTON;
2118  footerDesc.separationLine = false;
2119  footerDesc.button.text = buttonInfo->text;
2120  footerDesc.button.token = buttonInfo->token;
2121  footerDesc.button.tuneId = buttonInfo->tuneId;
2122  footerDesc.button.icon = buttonInfo->icon;
2123  footerDesc.button.style = buttonInfo->style;
2124  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2125  }
2126  else {
2127  nbgl_layoutUpFooter_t upFooterDesc;
2128  upFooterDesc.type = UP_FOOTER_BUTTON;
2129  upFooterDesc.button.text = buttonInfo->text;
2130  upFooterDesc.button.token = buttonInfo->token;
2131  upFooterDesc.button.tuneId = buttonInfo->tuneId;
2132  upFooterDesc.button.icon = buttonInfo->icon;
2133  upFooterDesc.button.style = buttonInfo->style;
2134  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2135  }
2136  }
2137 
2138  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2139  obj = layoutAddCallbackObj(
2140  layoutInt, (nbgl_obj_t *) button, buttonInfo->token, buttonInfo->tuneId);
2141  if (obj == NULL) {
2142  return -1;
2143  }
2144 
2145  button->obj.alignmentMarginX = BORDER_MARGIN;
2146  button->obj.alignmentMarginY = 12;
2147  button->obj.alignment = NO_ALIGNMENT;
2148  if (buttonInfo->style == BLACK_BACKGROUND) {
2149  button->innerColor = BLACK;
2150  button->foregroundColor = WHITE;
2151  }
2152  else {
2153  button->innerColor = WHITE;
2154  button->foregroundColor = BLACK;
2155  }
2156  if (buttonInfo->style == NO_BORDER) {
2157  button->borderColor = WHITE;
2158  }
2159  else {
2160  if (buttonInfo->style == BLACK_BACKGROUND) {
2161  button->borderColor = BLACK;
2162  }
2163  else {
2164  button->borderColor = LIGHT_GRAY;
2165  }
2166  }
2167  button->text = PIC(buttonInfo->text);
2168  button->fontId = SMALL_BOLD_FONT;
2169  button->icon = PIC(buttonInfo->icon);
2170  if (buttonInfo->fittingContent == true) {
2171  button->obj.area.width = nbgl_getTextWidth(button->fontId, button->text)
2173  + ((button->icon) ? (button->icon->width + 12) : 0);
2174  button->obj.area.height = SMALL_BUTTON_HEIGHT;
2175  button->radius = RADIUS_32_PIXELS;
2176  if (buttonInfo->onBottom != true) {
2177  button->obj.alignmentMarginX
2178  += (SCREEN_WIDTH - 2 * BORDER_MARGIN - button->obj.area.width) / 2;
2179  }
2180  }
2181  else {
2182  button->obj.area.width = AVAILABLE_WIDTH;
2183  button->obj.area.height = BUTTON_DIAMETER;
2184  button->radius = BUTTON_RADIUS;
2185  }
2186  button->obj.alignTo = NULL;
2187  button->obj.touchMask = (1 << TOUCHED);
2188  button->obj.touchId = (buttonInfo->fittingContent) ? EXTRA_BUTTON_ID : SINGLE_BUTTON_ID;
2189  // set this new button as child of the container
2190  layoutAddObject(layoutInt, (nbgl_obj_t *) button);
2191 
2192  return 0;
2193 }
2194 
2205  const char *text,
2206  uint8_t token,
2207  tune_index_e tuneId)
2208 {
2209  nbgl_layoutUpFooter_t upFooterDesc = {.type = UP_FOOTER_LONG_PRESS,
2210  .longPress.text = text,
2211  .longPress.token = token,
2212  .longPress.tuneId = tuneId};
2213 
2214  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLongPressButton():\n");
2215  if (layout == NULL) {
2216  return -1;
2217  }
2218 
2219  return nbgl_layoutAddUpFooter(layout, &upFooterDesc);
2220 }
2221 
2233  const char *text,
2234  uint8_t token,
2235  tune_index_e tuneId)
2236 {
2237  nbgl_layoutFooter_t footerDesc;
2238  footerDesc.type = FOOTER_SIMPLE_TEXT;
2239  footerDesc.separationLine = true;
2240  footerDesc.simpleText.text = text;
2241  footerDesc.simpleText.mutedOut = false;
2242  footerDesc.simpleText.token = token;
2243  footerDesc.simpleText.tuneId = tuneId;
2244  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2245 }
2246 
2260  const char *leftText,
2261  uint8_t leftToken,
2262  const char *rightText,
2263  uint8_t rightToken,
2264  tune_index_e tuneId)
2265 {
2266  nbgl_layoutFooter_t footerDesc;
2267  footerDesc.type = FOOTER_DOUBLE_TEXT;
2268  footerDesc.separationLine = true;
2269  footerDesc.doubleText.leftText = leftText;
2270  footerDesc.doubleText.leftToken = leftToken;
2271  footerDesc.doubleText.rightText = rightText;
2272  footerDesc.doubleText.rightToken = rightToken;
2273  footerDesc.doubleText.tuneId = tuneId;
2274  return nbgl_layoutAddExtendedFooter(layout, &footerDesc);
2275 }
2276 
2286 {
2287  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2288  layoutObj_t *obj;
2289  nbgl_text_area_t *textArea;
2290  nbgl_line_t *line, *separationLine = NULL;
2291  ;
2292  nbgl_button_t *button;
2293 
2294  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddHeader():\n");
2295  if (layout == NULL) {
2296  return -1;
2297  }
2298  if ((headerDesc == NULL) || (headerDesc->type >= NB_HEADER_TYPES)) {
2299  return -2;
2300  }
2301 
2302  layoutInt->headerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2303  layoutInt->headerContainer->obj.area.width = SCREEN_WIDTH;
2304  layoutInt->headerContainer->layout = VERTICAL;
2305  layoutInt->headerContainer->children
2306  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2307  layoutInt->headerContainer->obj.alignment = TOP_MIDDLE;
2308 
2309  switch (headerDesc->type) {
2310  case HEADER_EMPTY: {
2311  layoutInt->headerContainer->obj.area.height = headerDesc->emptySpace.height;
2312  break;
2313  }
2314  case HEADER_BACK_AND_TEXT:
2315  case HEADER_EXTENDED_BACK: {
2316  const char *text = (headerDesc->type == HEADER_EXTENDED_BACK)
2317  ? PIC(headerDesc->extendedBack.text)
2318  : PIC(headerDesc->backAndText.text);
2319  // add back button
2320  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2321  obj = layoutAddCallbackObj(
2322  layoutInt,
2323  (nbgl_obj_t *) button,
2324  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.backToken
2325  : headerDesc->backAndText.token,
2326  (headerDesc->type == HEADER_EXTENDED_BACK) ? headerDesc->extendedBack.tuneId
2327  : headerDesc->backAndText.tuneId);
2328  if (obj == NULL) {
2329  return -1;
2330  }
2331 
2332  button->obj.alignment = MID_LEFT;
2333  button->innerColor = WHITE;
2334  button->foregroundColor = BLACK;
2335  button->borderColor = WHITE;
2336  button->obj.area.width = BACK_KEY_WIDTH;
2337  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2338  button->text = NULL;
2339  button->icon = PIC(&LEFT_ARROW_ICON);
2340  button->obj.touchMask = (1 << TOUCHED);
2341  button->obj.touchId = BACK_BUTTON_ID;
2342  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2343  = (nbgl_obj_t *) button;
2344  layoutInt->headerContainer->nbChildren++;
2345 
2346  // add optional text if needed
2347  if (text != NULL) {
2348  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2349  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2350  && (headerDesc->extendedBack.textToken != NBGL_INVALID_TOKEN)) {
2351  obj = layoutAddCallbackObj(layoutInt,
2352  (nbgl_obj_t *) textArea,
2353  headerDesc->extendedBack.textToken,
2354  headerDesc->extendedBack.tuneId);
2355  if (obj == NULL) {
2356  return -1;
2357  }
2358  textArea->obj.touchMask = (1 << TOUCHED);
2359  }
2360  textArea->obj.alignment = CENTER;
2361  textArea->textColor = BLACK;
2362  textArea->obj.area.width
2363  = layoutInt->headerContainer->obj.area.width - 2 * BACK_KEY_WIDTH;
2364  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2365  textArea->text = text;
2366  textArea->fontId = SMALL_BOLD_FONT;
2367  textArea->textAlignment = CENTER;
2368  textArea->wrapping = true;
2369  // ensure that text fits on 2 lines maximum
2370  if (nbgl_getTextNbLinesInWidth(textArea->fontId,
2371  textArea->text,
2372  textArea->obj.area.width,
2373  textArea->wrapping)
2374  > 2) {
2376  "nbgl_layoutAddHeader: text [%s] is too long for header\n",
2377  text);
2378  }
2379  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2380  = (nbgl_obj_t *) textArea;
2381  layoutInt->headerContainer->nbChildren++;
2382  }
2383  // add action key if the type is HEADER_EXTENDED_BACK
2384  if ((headerDesc->type == HEADER_EXTENDED_BACK)
2385  && (headerDesc->extendedBack.actionIcon)) {
2386  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2387  // if token is valid
2388  if (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) {
2389  obj = layoutAddCallbackObj(layoutInt,
2390  (nbgl_obj_t *) button,
2391  headerDesc->extendedBack.actionToken,
2392  headerDesc->extendedBack.tuneId);
2393  if (obj == NULL) {
2394  return -1;
2395  }
2396  button->obj.touchMask = (1 << TOUCHED);
2397  }
2398 
2399  button->obj.alignment = MID_RIGHT;
2400  button->innerColor = WHITE;
2401  button->foregroundColor
2402  = (headerDesc->extendedBack.actionToken != NBGL_INVALID_TOKEN) ? BLACK
2403  : LIGHT_GRAY;
2404  button->borderColor = WHITE;
2405  button->obj.area.width = BACK_KEY_WIDTH;
2406  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2407  button->text = NULL;
2408  button->icon = PIC(headerDesc->extendedBack.actionIcon);
2409  button->obj.touchId = EXTRA_BUTTON_ID;
2410  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2411  = (nbgl_obj_t *) button;
2412  layoutInt->headerContainer->nbChildren++;
2413  }
2414 
2415  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2416  break;
2417  }
2418  case HEADER_BACK_AND_PROGRESS: {
2419 #ifdef TARGET_STAX
2420  // add optional back button
2421  if (headerDesc->progressAndBack.withBack) {
2422  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2423  obj = layoutAddCallbackObj(layoutInt,
2424  (nbgl_obj_t *) button,
2425  headerDesc->progressAndBack.token,
2426  headerDesc->progressAndBack.tuneId);
2427  if (obj == NULL) {
2428  return -1;
2429  }
2430 
2431  button->obj.alignment = MID_LEFT;
2432  button->innerColor = WHITE;
2433  button->foregroundColor = BLACK;
2434  button->borderColor = WHITE;
2435  button->obj.area.width = BACK_KEY_WIDTH;
2436  button->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2437  button->text = NULL;
2438  button->icon = PIC(&LEFT_ARROW_ICON);
2439  button->obj.touchMask = (1 << TOUCHED);
2440  button->obj.touchId = BACK_BUTTON_ID;
2441  // add to container
2442  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2443  = (nbgl_obj_t *) button;
2444  layoutInt->headerContainer->nbChildren++;
2445  }
2446 
2447  // add progress indicator
2448  if (headerDesc->progressAndBack.nbPages > 1
2449  && headerDesc->progressAndBack.nbPages != NBGL_NO_PROGRESS_INDICATOR) {
2450  nbgl_page_indicator_t *progress;
2451 
2452  progress
2454  progress->activePage = headerDesc->progressAndBack.activePage;
2455  progress->nbPages = headerDesc->progressAndBack.nbPages;
2456  progress->obj.area.width = 224;
2457  progress->obj.alignment = CENTER;
2458  // add to container
2459  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2460  = (nbgl_obj_t *) progress;
2461  layoutInt->headerContainer->nbChildren++;
2462  }
2463  layoutInt->activePage = headerDesc->progressAndBack.activePage;
2464  layoutInt->nbPages = headerDesc->progressAndBack.nbPages;
2465  layoutInt->headerContainer->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2466 #endif // TARGET_STAX
2467  break;
2468  }
2469  case HEADER_TITLE: {
2470  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2471  textArea->textColor = BLACK;
2472  textArea->obj.area.width = AVAILABLE_WIDTH;
2473  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2474  textArea->text = PIC(headerDesc->title.text);
2475  textArea->fontId = SMALL_BOLD_FONT;
2476  textArea->textAlignment = CENTER;
2477  textArea->wrapping = true;
2478  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2479  = (nbgl_obj_t *) textArea;
2480  layoutInt->headerContainer->nbChildren++;
2481  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2482  break;
2483  }
2484  case HEADER_RIGHT_TEXT: {
2485  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2486  obj = layoutAddCallbackObj(layoutInt,
2487  (nbgl_obj_t *) textArea,
2488  headerDesc->rightText.token,
2489  headerDesc->rightText.tuneId);
2490  if (obj == NULL) {
2491  return -1;
2492  }
2493  textArea->obj.alignment = MID_RIGHT;
2494  textArea->obj.alignmentMarginX = BORDER_MARGIN;
2495  textArea->textColor = BLACK;
2496  textArea->obj.area.width = AVAILABLE_WIDTH;
2497  textArea->obj.area.height = TOUCHABLE_HEADER_BAR_HEIGHT;
2498  textArea->text = PIC(headerDesc->rightText.text);
2499  textArea->fontId = SMALL_BOLD_FONT;
2500  textArea->textAlignment = MID_RIGHT;
2501  textArea->obj.touchMask = (1 << TOUCHED);
2502  textArea->obj.touchId = TOP_RIGHT_BUTTON_ID;
2503  // add to bottom container
2504  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2505  = (nbgl_obj_t *) textArea;
2506  layoutInt->headerContainer->nbChildren++;
2507  layoutInt->headerContainer->obj.area.height = textArea->obj.area.height;
2508  break;
2509  }
2510  default:
2511  return -2;
2512  }
2513 
2514  if (headerDesc->separationLine) {
2515  line = createHorizontalLine(layoutInt->layer);
2516  line->obj.alignment = BOTTOM_MIDDLE;
2517  line->offset = 3;
2518  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2519  = (nbgl_obj_t *) line;
2520  layoutInt->headerContainer->nbChildren++;
2521  }
2522  if (separationLine != NULL) {
2523  layoutInt->headerContainer->children[layoutInt->headerContainer->nbChildren]
2524  = (nbgl_obj_t *) separationLine;
2525  layoutInt->headerContainer->nbChildren++;
2526  }
2527  // header must be the first child
2528  layoutInt->children[HEADER_INDEX] = (nbgl_obj_t *) layoutInt->headerContainer;
2529 
2530  // subtract header height from main container height
2531  layoutInt->container->obj.area.height -= layoutInt->headerContainer->obj.area.height;
2532  layoutInt->container->obj.alignTo = (nbgl_obj_t *) layoutInt->headerContainer;
2533  layoutInt->container->obj.alignment = BOTTOM_LEFT;
2534 
2535  layoutInt->headerType = headerDesc->type;
2536 
2537  return layoutInt->headerContainer->obj.area.height;
2538 }
2539 
2549 {
2550  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2551  layoutObj_t *obj;
2552  nbgl_text_area_t *textArea;
2553  nbgl_line_t *line, *separationLine = NULL;
2554  nbgl_button_t *button;
2555 
2556  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddExtendedFooter():\n");
2557  if (layout == NULL) {
2558  return -1;
2559  }
2560  if ((footerDesc == NULL) || (footerDesc->type >= NB_FOOTER_TYPES)) {
2561  return -2;
2562  }
2563 
2564  layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2565  layoutInt->footerContainer->obj.area.width = AVAILABLE_WIDTH;
2566  layoutInt->footerContainer->layout = VERTICAL;
2567  layoutInt->footerContainer->children
2568  = (nbgl_obj_t **) nbgl_containerPoolGet(5, layoutInt->layer);
2569  layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
2570 
2571  switch (footerDesc->type) {
2572  case FOOTER_EMPTY: {
2573  layoutInt->footerContainer->obj.area.height = footerDesc->emptySpace.height;
2574  break;
2575  }
2576  case FOOTER_SIMPLE_TEXT: {
2577  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2578  obj = layoutAddCallbackObj(layoutInt,
2579  (nbgl_obj_t *) textArea,
2580  footerDesc->simpleText.token,
2581  footerDesc->simpleText.tuneId);
2582  if (obj == NULL) {
2583  return -1;
2584  }
2585 
2586  textArea->obj.alignment = BOTTOM_MIDDLE;
2587  textArea->textColor = (footerDesc->simpleText.mutedOut) ? DARK_GRAY : BLACK;
2588  textArea->obj.area.width = AVAILABLE_WIDTH;
2589  textArea->obj.area.height
2590  = (footerDesc->simpleText.mutedOut) ? SMALL_FOOTER_HEIGHT : SIMPLE_FOOTER_HEIGHT;
2591  textArea->text = PIC(footerDesc->simpleText.text);
2592  textArea->fontId
2593  = (footerDesc->simpleText.mutedOut) ? SMALL_REGULAR_FONT : SMALL_BOLD_FONT;
2594  textArea->textAlignment = CENTER;
2595  textArea->obj.touchMask = (1 << TOUCHED);
2596  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2597  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2598  = (nbgl_obj_t *) textArea;
2599  layoutInt->footerContainer->nbChildren++;
2600  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2601  break;
2602  }
2603  case FOOTER_DOUBLE_TEXT: {
2604  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2605  obj = layoutAddCallbackObj(layoutInt,
2606  (nbgl_obj_t *) textArea,
2607  footerDesc->doubleText.leftToken,
2608  footerDesc->doubleText.tuneId);
2609  if (obj == NULL) {
2610  return -1;
2611  }
2612  textArea->obj.alignment = BOTTOM_LEFT;
2613  textArea->textColor = BLACK;
2614  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2615  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2616  textArea->text = PIC(footerDesc->doubleText.leftText);
2617  textArea->fontId = SMALL_BOLD_FONT;
2618  textArea->textAlignment = CENTER;
2619  textArea->obj.touchMask = (1 << TOUCHED);
2620  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2621  // add to bottom container
2622  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2623  = (nbgl_obj_t *) textArea;
2624  layoutInt->footerContainer->nbChildren++;
2625 
2626  // create right touchable text
2627  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2628  obj = layoutAddCallbackObj(layoutInt,
2629  (nbgl_obj_t *) textArea,
2630  footerDesc->doubleText.rightToken,
2631  footerDesc->doubleText.tuneId);
2632  if (obj == NULL) {
2633  return -1;
2634  }
2635 
2636  textArea->obj.alignment = BOTTOM_RIGHT;
2637  textArea->textColor = BLACK;
2638  textArea->obj.area.width = AVAILABLE_WIDTH / 2;
2639  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2640  textArea->text = PIC(footerDesc->doubleText.rightText);
2641  textArea->fontId = SMALL_BOLD_FONT;
2642  textArea->textAlignment = CENTER;
2643  textArea->obj.touchMask = (1 << TOUCHED);
2644  textArea->obj.touchId = RIGHT_BUTTON_ID;
2645  // add to bottom container
2646  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2647  = (nbgl_obj_t *) textArea;
2648  layoutInt->footerContainer->nbChildren++;
2649  layoutInt->footerContainer->obj.area.height = textArea->obj.area.height;
2650 
2651  // create vertical line separating texts
2652  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2653  separationLine->lineColor = LIGHT_GRAY;
2654  separationLine->obj.area.width = 1;
2655  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2656  separationLine->direction = VERTICAL;
2657  separationLine->thickness = 1;
2658  separationLine->obj.alignment = MID_LEFT;
2659  separationLine->obj.alignTo = (nbgl_obj_t *) textArea;
2660  separationLine->obj.alignmentMarginX = -1;
2661  break;
2662  }
2663  case FOOTER_TEXT_AND_NAV: {
2664  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2665  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2666  // add touchable text on the left
2667  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2668  obj = layoutAddCallbackObj(layoutInt,
2669  (nbgl_obj_t *) textArea,
2670  footerDesc->textAndNav.token,
2671  footerDesc->textAndNav.tuneId);
2672  if (obj == NULL) {
2673  return -1;
2674  }
2675  textArea->obj.alignment = BOTTOM_LEFT;
2676  textArea->textColor = BLACK;
2677 #ifdef TARGET_STAX
2678  textArea->obj.area.width = 160;
2679 #else // TARGET_STAX
2680  textArea->obj.area.width = 192;
2681 #endif // TARGET_STAX
2682  textArea->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2683  textArea->text = PIC(footerDesc->textAndNav.text);
2684  textArea->fontId = SMALL_BOLD_FONT;
2685  textArea->textAlignment = CENTER;
2686  textArea->obj.touchMask = (1 << TOUCHED);
2687  textArea->obj.touchId = BOTTOM_BUTTON_ID;
2688  // add to bottom container
2689  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2690  = (nbgl_obj_t *) textArea;
2691  layoutInt->footerContainer->nbChildren++;
2692 
2693  // add navigation on the right
2694  nbgl_container_t *navContainer
2695  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2696  navContainer->obj.area.width = AVAILABLE_WIDTH;
2697  navContainer->layout = VERTICAL;
2698  navContainer->nbChildren = 4;
2699  navContainer->children
2700  = (nbgl_obj_t **) nbgl_containerPoolGet(navContainer->nbChildren, layoutInt->layer);
2701  navContainer->obj.alignment = BOTTOM_RIGHT;
2702  navContainer->obj.area.width = SCREEN_WIDTH - textArea->obj.area.width;
2703  navContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2704  layoutNavigationPopulate(navContainer, &footerDesc->navigation, layoutInt->layer);
2705  obj = layoutAddCallbackObj(layoutInt,
2706  (nbgl_obj_t *) navContainer,
2707  footerDesc->textAndNav.navigation.token,
2708  footerDesc->textAndNav.navigation.tuneId);
2709  if (obj == NULL) {
2710  return -1;
2711  }
2712 
2713  // create vertical line separating text from nav
2714  separationLine = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
2715  separationLine->lineColor = LIGHT_GRAY;
2716  separationLine->obj.area.width = 1;
2717  separationLine->obj.area.height = layoutInt->footerContainer->obj.area.height;
2718  separationLine->direction = VERTICAL;
2719  separationLine->thickness = 1;
2720  separationLine->obj.alignment = MID_LEFT;
2721  separationLine->obj.alignTo = (nbgl_obj_t *) navContainer;
2722  separationLine->obj.alignmentMarginX = -1;
2723 
2724  layoutInt->activePage = footerDesc->textAndNav.navigation.activePage;
2725  layoutInt->nbPages = footerDesc->textAndNav.navigation.nbPages;
2726  // add to bottom container
2727  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2728  = (nbgl_obj_t *) navContainer;
2729  layoutInt->footerContainer->nbChildren++;
2730  break;
2731  }
2732  case FOOTER_NAV: {
2733  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
2734  layoutInt->footerContainer->obj.area.height = SIMPLE_FOOTER_HEIGHT;
2736  layoutInt->footerContainer, &footerDesc->navigation, layoutInt->layer);
2737  layoutInt->footerContainer->nbChildren = 4;
2738  obj = layoutAddCallbackObj(layoutInt,
2739  (nbgl_obj_t *) layoutInt->footerContainer,
2740  footerDesc->navigation.token,
2741  footerDesc->navigation.tuneId);
2742  if (obj == NULL) {
2743  return -1;
2744  }
2745 
2746  layoutInt->activePage = footerDesc->navigation.activePage;
2747  layoutInt->nbPages = footerDesc->navigation.nbPages;
2748  break;
2749  }
2750  case FOOTER_SIMPLE_BUTTON: {
2751  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2752  obj = layoutAddCallbackObj(layoutInt,
2753  (nbgl_obj_t *) button,
2754  footerDesc->button.token,
2755  footerDesc->button.tuneId);
2756  if (obj == NULL) {
2757  return -1;
2758  }
2759 
2760  button->obj.alignment = CENTER;
2761  if (footerDesc->button.style == BLACK_BACKGROUND) {
2762  button->innerColor = BLACK;
2763  button->foregroundColor = WHITE;
2764  }
2765  else {
2766  button->innerColor = WHITE;
2767  button->foregroundColor = BLACK;
2768  }
2769 
2770  if (footerDesc->button.style == NO_BORDER) {
2771  button->borderColor = WHITE;
2772  }
2773  else {
2774  if (footerDesc->button.style == BLACK_BACKGROUND) {
2775  button->borderColor = BLACK;
2776  }
2777  else {
2778  button->borderColor = LIGHT_GRAY;
2779  }
2780  }
2781  button->text = PIC(footerDesc->button.text);
2782  button->fontId = SMALL_BOLD_FONT;
2783  button->icon = PIC(footerDesc->button.icon);
2784  button->radius = BUTTON_RADIUS;
2785  button->obj.area.height = BUTTON_DIAMETER;
2786  layoutInt->footerContainer->obj.area.height = FOOTER_BUTTON_HEIGHT;
2787  if (footerDesc->button.text == NULL) {
2788  button->obj.area.width = BUTTON_DIAMETER;
2789  }
2790  else {
2791  button->obj.area.width = AVAILABLE_WIDTH;
2792  }
2793  button->obj.touchMask = (1 << TOUCHED);
2794  button->obj.touchId = button->text ? SINGLE_BUTTON_ID : BOTTOM_BUTTON_ID;
2795  // add to bottom container
2796  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2797  = (nbgl_obj_t *) button;
2798  layoutInt->footerContainer->nbChildren++;
2799  break;
2800  }
2801  case FOOTER_CHOICE_BUTTONS: {
2802  // texts cannot be NULL
2803  if ((footerDesc->choiceButtons.bottomText == NULL)
2804  || (footerDesc->choiceButtons.topText == NULL)) {
2805  return -1;
2806  }
2807 
2808  // create bottom button (footer) at first
2809  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2810  obj = layoutAddCallbackObj(layoutInt,
2811  (nbgl_obj_t *) button,
2812  footerDesc->choiceButtons.token,
2813  footerDesc->choiceButtons.tuneId);
2814  if (obj == NULL) {
2815  return -1;
2816  }
2817  // associate with with index 1
2818  obj->index = 1;
2819  // put at the bottom of the container
2820  button->obj.alignment = BOTTOM_MIDDLE;
2821  button->obj.alignmentMarginY = 4; // 4 pixels from screen bottom
2822  button->borderColor = WHITE;
2823  button->innerColor = WHITE;
2824  button->foregroundColor = BLACK;
2825  button->obj.area.width = AVAILABLE_WIDTH;
2826  button->obj.area.height = BUTTON_DIAMETER;
2827  button->radius = BUTTON_RADIUS;
2828  button->text = PIC(footerDesc->choiceButtons.bottomText);
2829  button->fontId = SMALL_BOLD_FONT;
2830  button->obj.touchMask = (1 << TOUCHED);
2831  button->obj.touchId = CHOICE_2_ID;
2832  // add to bottom container
2833  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2834  = (nbgl_obj_t *) button;
2835  layoutInt->footerContainer->nbChildren++;
2836 
2837  // add line if needed
2838  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2839  line = createHorizontalLine(layoutInt->layer);
2840  line->obj.alignment = TOP_MIDDLE;
2841  line->obj.alignmentMarginY = 4;
2842  line->obj.alignTo = (nbgl_obj_t *) button;
2843  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2844  = (nbgl_obj_t *) line;
2845  layoutInt->footerContainer->nbChildren++;
2846  }
2847 
2848  // then top button, on top of it
2849  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2850  obj = layoutAddCallbackObj(layoutInt,
2851  (nbgl_obj_t *) button,
2852  footerDesc->choiceButtons.token,
2853  footerDesc->choiceButtons.tuneId);
2854  if (obj == NULL) {
2855  return -1;
2856  }
2857  // associate with with index 0
2858  obj->index = 0;
2859  button->obj.alignment = TOP_MIDDLE;
2860  button->obj.alignmentMarginY = BOTTOM_BORDER_MARGIN; // 24 pixels from top of container
2861  if (footerDesc->choiceButtons.style == SOFT_ACTION_AND_FOOTER_STYLE) {
2862  button->innerColor = WHITE;
2863  button->borderColor = LIGHT_GRAY;
2864  button->foregroundColor = BLACK;
2865  }
2866  else {
2867  button->innerColor = BLACK;
2868  button->borderColor = BLACK;
2869  button->foregroundColor = WHITE;
2870  }
2871  button->obj.area.width = AVAILABLE_WIDTH;
2872  button->obj.area.height = BUTTON_DIAMETER;
2873  button->radius = BUTTON_RADIUS;
2874  button->text = PIC(footerDesc->choiceButtons.topText);
2875  button->icon = (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE)
2876  ? PIC(footerDesc->choiceButtons.topIcon)
2877  : NULL;
2878  button->fontId = SMALL_BOLD_FONT;
2879  button->obj.touchMask = (1 << TOUCHED);
2880  button->obj.touchId = CHOICE_1_ID;
2881  // add to bottom container
2882  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2883  = (nbgl_obj_t *) button;
2884  layoutInt->footerContainer->nbChildren++;
2885 
2886  if (footerDesc->choiceButtons.style != ROUNDED_AND_FOOTER_STYLE) {
2887  layoutInt->footerContainer->obj.area.height = ACTION_AND_FOOTER_FOOTER_HEIGHT;
2888  }
2889  else {
2890  layoutInt->footerContainer->obj.area.height = ROUNDED_AND_FOOTER_FOOTER_HEIGHT;
2891  }
2892 
2893  break;
2894  }
2895  default:
2896  return -2;
2897  }
2898 
2899  // add swipable feature for navigation
2900  if ((footerDesc->type == FOOTER_NAV) || (footerDesc->type == FOOTER_TEXT_AND_NAV)) {
2901  addSwipeInternal(layoutInt,
2902  ((1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT)),
2904  (footerDesc->type == FOOTER_NAV) ? footerDesc->navigation.token
2905  : footerDesc->textAndNav.navigation.token,
2906  (footerDesc->type == FOOTER_NAV)
2907  ? footerDesc->navigation.tuneId
2908  : footerDesc->textAndNav.navigation.tuneId);
2909  }
2910 
2911  if (footerDesc->separationLine) {
2912  line = createHorizontalLine(layoutInt->layer);
2913  line->obj.alignment = TOP_MIDDLE;
2914  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2915  = (nbgl_obj_t *) line;
2916  layoutInt->footerContainer->nbChildren++;
2917  }
2918  if (separationLine != NULL) {
2919  layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
2920  = (nbgl_obj_t *) separationLine;
2921  layoutInt->footerContainer->nbChildren++;
2922  }
2923 
2924  layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
2925 
2926  // subtract footer height from main container height
2927  layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
2928 
2929  layoutInt->footerType = footerDesc->type;
2930 
2931  return layoutInt->footerContainer->obj.area.height;
2932 }
2933 
2943 {
2944  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
2945  layoutObj_t *obj;
2946  nbgl_text_area_t *textArea;
2947  nbgl_line_t *line;
2948  nbgl_button_t *button;
2949 
2950  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddUpFooter():\n");
2951  if (layout == NULL) {
2952  return -1;
2953  }
2954  if ((upFooterDesc == NULL) || (upFooterDesc->type >= NB_UP_FOOTER_TYPES)) {
2955  return -2;
2956  }
2957 
2958  layoutInt->upFooterContainer
2959  = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
2960  layoutInt->upFooterContainer->obj.area.width = SCREEN_WIDTH;
2961  layoutInt->upFooterContainer->layout = VERTICAL;
2962  // maximum 4 children for long press button
2963  layoutInt->upFooterContainer->children
2964  = (nbgl_obj_t **) nbgl_containerPoolGet(4, layoutInt->layer);
2965  layoutInt->upFooterContainer->obj.alignTo = (nbgl_obj_t *) layoutInt->container;
2966  layoutInt->upFooterContainer->obj.alignment = BOTTOM_MIDDLE;
2967 
2968  switch (upFooterDesc->type) {
2969  case UP_FOOTER_LONG_PRESS: {
2970  nbgl_progress_bar_t *progressBar;
2971 
2972  obj = layoutAddCallbackObj(layoutInt,
2973  (nbgl_obj_t *) layoutInt->upFooterContainer,
2974  upFooterDesc->longPress.token,
2975  upFooterDesc->longPress.tuneId);
2976  if (obj == NULL) {
2977  return -1;
2978  }
2979  layoutInt->upFooterContainer->nbChildren = 4;
2980  layoutInt->upFooterContainer->obj.area.height = LONG_PRESS_BUTTON_HEIGHT;
2981  layoutInt->upFooterContainer->obj.touchId = LONG_PRESS_BUTTON_ID;
2982  layoutInt->upFooterContainer->obj.touchMask
2983  = ((1 << TOUCHING) | (1 << TOUCH_RELEASED) | (1 << OUT_OF_TOUCH)
2984  | (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT));
2985 
2986  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
2987  button->obj.alignmentMarginX = BORDER_MARGIN;
2988  button->obj.alignment = MID_RIGHT;
2989  button->innerColor = BLACK;
2990  button->foregroundColor = WHITE;
2991  button->borderColor = BLACK;
2992  button->obj.area.width = BUTTON_DIAMETER;
2993  button->obj.area.height = BUTTON_DIAMETER;
2994  button->radius = BUTTON_RADIUS;
2995  button->icon = PIC(&VALIDATE_ICON);
2996  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
2997 
2998  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
2999  textArea->textColor = BLACK;
3000  textArea->text = PIC(upFooterDesc->longPress.text);
3001  textArea->textAlignment = MID_LEFT;
3002  textArea->fontId = LARGE_MEDIUM_FONT;
3003  textArea->wrapping = true;
3004  textArea->obj.area.width = SCREEN_WIDTH - 3 * BORDER_MARGIN - button->obj.area.width;
3005  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3006  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3007  textArea->style = NO_STYLE;
3008  textArea->obj.alignment = MID_LEFT;
3009  textArea->obj.alignmentMarginX = BORDER_MARGIN;
3010  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) textArea;
3011 
3012  line = createHorizontalLine(layoutInt->layer);
3013  line->offset = 3;
3014  line->obj.alignment = TOP_MIDDLE;
3015  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) line;
3016 
3017  progressBar = (nbgl_progress_bar_t *) nbgl_objPoolGet(PROGRESS_BAR, layoutInt->layer);
3018  progressBar->withBorder = false;
3019  progressBar->obj.area.width = SCREEN_WIDTH;
3020  progressBar->obj.area.height = 8;
3021  progressBar->obj.alignment = TOP_MIDDLE;
3022  progressBar->obj.alignmentMarginY = 4;
3023  progressBar->obj.alignTo = NULL;
3024  layoutInt->upFooterContainer->children[3] = (nbgl_obj_t *) progressBar;
3025  break;
3026  }
3027  case UP_FOOTER_BUTTON: {
3028  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3029  obj = layoutAddCallbackObj(layoutInt,
3030  (nbgl_obj_t *) button,
3031  upFooterDesc->button.token,
3032  upFooterDesc->button.tuneId);
3033  if (obj == NULL) {
3034  return -1;
3035  }
3036 
3037  layoutInt->upFooterContainer->nbChildren = 1;
3038  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3039  button->obj.alignment = CENTER;
3040 
3041  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3042  button->innerColor = BLACK;
3043  button->foregroundColor = WHITE;
3044  }
3045  else {
3046  button->innerColor = WHITE;
3047  button->foregroundColor = BLACK;
3048  }
3049  if (upFooterDesc->button.style == NO_BORDER) {
3050  button->borderColor = WHITE;
3051  }
3052  else {
3053  if (upFooterDesc->button.style == BLACK_BACKGROUND) {
3054  button->borderColor = BLACK;
3055  }
3056  else {
3057  button->borderColor = LIGHT_GRAY;
3058  }
3059  }
3060  button->text = PIC(upFooterDesc->button.text);
3061  button->fontId = SMALL_BOLD_FONT;
3062  button->icon = PIC(upFooterDesc->button.icon);
3063  button->obj.area.width = AVAILABLE_WIDTH;
3064  button->obj.area.height = BUTTON_DIAMETER;
3065  button->radius = BUTTON_RADIUS;
3066 
3067  button->obj.alignTo = NULL;
3068  button->obj.touchMask = (1 << TOUCHED);
3069  button->obj.touchId = SINGLE_BUTTON_ID;
3070  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3071  break;
3072  }
3074  // icon & text cannot be NULL
3075  if ((upFooterDesc->horizontalButtons.leftIcon == NULL)
3076  || (upFooterDesc->horizontalButtons.rightText == NULL)) {
3077  return -1;
3078  }
3079 
3080  layoutInt->upFooterContainer->nbChildren = 2;
3081  layoutInt->upFooterContainer->obj.area.height = UP_FOOTER_BUTTON_HEIGHT;
3082 
3083  // create left button (in white) at first
3084  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3085  obj = layoutAddCallbackObj(layoutInt,
3086  (nbgl_obj_t *) button,
3087  upFooterDesc->horizontalButtons.leftToken,
3088  upFooterDesc->horizontalButtons.tuneId);
3089  if (obj == NULL) {
3090  return -1;
3091  }
3092  // associate with with index 1
3093  obj->index = 1;
3094  button->obj.alignment = MID_LEFT;
3095  button->obj.alignmentMarginX = BORDER_MARGIN;
3096  button->borderColor = LIGHT_GRAY;
3097  button->innerColor = WHITE;
3098  button->foregroundColor = BLACK;
3099  button->obj.area.width = BUTTON_DIAMETER;
3100  button->obj.area.height = BUTTON_DIAMETER;
3101  button->radius = BUTTON_RADIUS;
3102  button->icon = PIC(upFooterDesc->horizontalButtons.leftIcon);
3103  button->fontId = SMALL_BOLD_FONT;
3104  button->obj.touchMask = (1 << TOUCHED);
3105  button->obj.touchId = CHOICE_2_ID;
3106  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) button;
3107 
3108  // then black button, on right
3109  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
3110  obj = layoutAddCallbackObj(layoutInt,
3111  (nbgl_obj_t *) button,
3112  upFooterDesc->horizontalButtons.rightToken,
3113  upFooterDesc->horizontalButtons.tuneId);
3114  if (obj == NULL) {
3115  return -1;
3116  }
3117  // associate with with index 0
3118  obj->index = 0;
3119  button->obj.alignment = MID_RIGHT;
3120  button->obj.alignmentMarginX = BORDER_MARGIN;
3121  button->innerColor = BLACK;
3122  button->borderColor = BLACK;
3123  button->foregroundColor = WHITE;
3124  button->obj.area.width = AVAILABLE_WIDTH - BUTTON_DIAMETER - 16;
3125  button->obj.area.height = BUTTON_DIAMETER;
3126  button->radius = BUTTON_RADIUS;
3127  button->text = PIC(upFooterDesc->horizontalButtons.rightText);
3128  button->fontId = SMALL_BOLD_FONT;
3129  button->obj.touchMask = (1 << TOUCHED);
3130  button->obj.touchId = CHOICE_1_ID;
3131  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) button;
3132  break;
3133  }
3134  case UP_FOOTER_TIP_BOX: {
3135  // text cannot be NULL
3136  if (upFooterDesc->tipBox.text == NULL) {
3137  return -1;
3138  }
3139  obj = layoutAddCallbackObj(layoutInt,
3140  (nbgl_obj_t *) layoutInt->upFooterContainer,
3141  upFooterDesc->tipBox.token,
3142  upFooterDesc->tipBox.tuneId);
3143  if (obj == NULL) {
3144  return -1;
3145  }
3146  layoutInt->upFooterContainer->nbChildren = 3;
3147  layoutInt->upFooterContainer->obj.touchId = TIP_BOX_ID;
3148  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3149 
3150  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3151  textArea->textColor = BLACK;
3152  textArea->text = PIC(upFooterDesc->tipBox.text);
3153  textArea->textAlignment = MID_LEFT;
3154  textArea->fontId = SMALL_REGULAR_FONT;
3155  textArea->wrapping = true;
3156  textArea->obj.area.width = AVAILABLE_WIDTH;
3157  if (upFooterDesc->tipBox.icon != NULL) {
3158  textArea->obj.area.width
3159  -= ((nbgl_icon_details_t *) PIC(upFooterDesc->tipBox.icon))->width
3160  + BORDER_MARGIN;
3161  }
3162  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3163  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3164  textArea->obj.alignment = MID_LEFT;
3165  textArea->obj.alignmentMarginX = BORDER_MARGIN;
3166  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3167  layoutInt->upFooterContainer->obj.area.height = textArea->obj.area.height;
3168 
3169  line = createHorizontalLine(layoutInt->layer);
3170  line->offset = 3;
3171  line->obj.alignment = TOP_MIDDLE;
3172  layoutInt->upFooterContainer->children[1] = (nbgl_obj_t *) line;
3173 
3174  if (upFooterDesc->tipBox.icon != NULL) {
3175  nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
3176  image->obj.alignmentMarginX = BORDER_MARGIN;
3177  image->obj.alignment = MID_RIGHT;
3178  image->foregroundColor = BLACK;
3179  image->buffer = PIC(upFooterDesc->tipBox.icon);
3180  layoutInt->upFooterContainer->children[2] = (nbgl_obj_t *) image;
3181  if (layoutInt->upFooterContainer->obj.area.height < image->buffer->height) {
3182  layoutInt->upFooterContainer->obj.area.height = image->buffer->height;
3183  }
3184  }
3185  layoutInt->upFooterContainer->obj.area.height += 2 * BOTTOM_BORDER_MARGIN;
3186 
3187  break;
3188  }
3189  case UP_FOOTER_TEXT: {
3190  obj = layoutAddCallbackObj(layoutInt,
3191  (nbgl_obj_t *) layoutInt->upFooterContainer,
3192  upFooterDesc->text.token,
3193  upFooterDesc->text.tuneId);
3194  if (obj == NULL) {
3195  return -1;
3196  }
3197  layoutInt->upFooterContainer->nbChildren = 1;
3198  layoutInt->upFooterContainer->obj.area.height = SMALL_FOOTER_HEIGHT;
3199  layoutInt->upFooterContainer->obj.touchId = WHOLE_SCREEN_ID;
3200  layoutInt->upFooterContainer->obj.touchMask = (1 << TOUCHED);
3201 
3202  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3203  textArea->textColor = DARK_GRAY;
3204  textArea->text = PIC(upFooterDesc->text.text);
3205  textArea->textAlignment = CENTER;
3206  textArea->fontId = SMALL_REGULAR_FONT;
3207  textArea->wrapping = true;
3208  textArea->obj.area.width = AVAILABLE_WIDTH;
3209  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3210  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3211  textArea->obj.alignment = CENTER;
3212  layoutInt->upFooterContainer->children[0] = (nbgl_obj_t *) textArea;
3213  break;
3214  }
3215  default:
3216  return -2;
3217  }
3218 
3219  // subtract up footer height from main container height
3220  layoutInt->container->obj.area.height -= layoutInt->upFooterContainer->obj.area.height;
3221 
3222  layoutInt->children[UP_FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->upFooterContainer;
3223 
3224  layoutInt->upFooterType = upFooterDesc->type;
3225 
3226  return layoutInt->upFooterContainer->obj.area.height;
3227 }
3228 
3243  uint8_t activePage,
3244  uint8_t nbPages,
3245  bool withBack,
3246  uint8_t backToken,
3247  tune_index_e tuneId)
3248 {
3250  .separationLine = false,
3251  .progressAndBack.activePage = activePage,
3252  .progressAndBack.nbPages = nbPages,
3253  .progressAndBack.token = backToken,
3254  .progressAndBack.tuneId = tuneId,
3255  .progressAndBack.withBack = withBack,
3256  .progressAndBack.actionIcon = NULL,
3257  .progressAndBack.actionToken = NBGL_INVALID_TOKEN};
3258  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressIndicator():\n");
3259 
3260  return nbgl_layoutAddHeader(layout, &headerDesc);
3261 }
3262 
3271 int nbgl_layoutAddSpinner(nbgl_layout_t *layout, const char *text, bool fixed)
3272 {
3273  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
3274  nbgl_text_area_t *textArea;
3275  nbgl_spinner_t *spinner;
3276 
3277  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSpinner():\n");
3278  if (layout == NULL) {
3279  return -1;
3280  }
3281 
3282  // create spinner
3283  spinner = (nbgl_spinner_t *) nbgl_objPoolGet(SPINNER, layoutInt->layer);
3284  spinner->position = fixed ? 0xFF : 0;
3285  spinner->obj.alignmentMarginY = -20;
3286  spinner->obj.alignTo = NULL;
3287  spinner->obj.alignment = CENTER;
3288  // set this new spinner as child of the container
3289  layoutAddObject(layoutInt, (nbgl_obj_t *) spinner);
3290 
3291  // create text area
3292  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
3293  textArea->textColor = BLACK;
3294  textArea->text = PIC(text);
3295  textArea->textAlignment = CENTER;
3296  textArea->fontId = SMALL_REGULAR_FONT;
3297  textArea->wrapping = true;
3298 #ifdef TARGET_STAX
3299  textArea->obj.alignmentMarginY = 20;
3300 #else // TARGET_STAX
3301  textArea->obj.alignmentMarginY = 24;
3302 #endif // TARGET_STAX
3303  textArea->obj.alignTo = (nbgl_obj_t *) spinner;
3304  textArea->obj.alignment = BOTTOM_MIDDLE;
3305  textArea->obj.area.width = AVAILABLE_WIDTH;
3306  textArea->obj.area.height = nbgl_getTextHeightInWidth(
3307  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
3308  textArea->style = NO_STYLE;
3309 
3310  // center spinner + text vertically
3311  spinner->obj.alignmentMarginY
3312  = -(textArea->obj.alignmentMarginY + textArea->obj.area.height) / 2;
3313 
3314  // set this new spinner as child of the container
3315  layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
3316 
3317  if (!fixed) {
3318  // update ticker to update the spinner periodically
3320 
3321  tickerCfg.tickerIntervale = SPINNER_REFRESH_PERIOD; // ms
3322  tickerCfg.tickerValue = SPINNER_REFRESH_PERIOD; // ms
3323  tickerCfg.tickerCallback = &spinnerTickerCallback;
3324  nbgl_screenUpdateTicker(layoutInt->layer, &tickerCfg);
3325  }
3326 
3327  return 0;
3328 }
3329 
3337 {
3338  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3339 
3340  if (layout == NULL) {
3341  return -1;
3342  }
3344  "nbgl_layoutDraw(): container.nbChildren =%d, layout->nbChildren = %d\n",
3345  layout->container->nbChildren,
3346  layout->nbChildren);
3347  if (layout->tapText) {
3348  // set this new container as child of main container
3349  layoutAddObject(layout, (nbgl_obj_t *) layout->tapText);
3350  }
3351  if (layout->withLeftBorder == true) {
3352  // draw now the line
3353  nbgl_line_t *line = createLeftVerticalLine(layout->layer);
3354  layout->children[LEFT_BORDER_INDEX] = (nbgl_obj_t *) line;
3355  }
3357 
3358  return 0;
3359 }
3360 
3368 {
3369  nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
3370  LOG_DEBUG(PAGE_LOGGER, "nbgl_layoutRelease(): \n");
3371  if (layout == NULL) {
3372  return -1;
3373  }
3374  // if modal
3375  if (layout->modal) {
3376  nbgl_screenPop(layout->layer);
3377  }
3378  layout->nbChildren = 0;
3379  return 0;
3380 }
3381 
3382 #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:1859
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:1664
#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:2942
int nbgl_layoutDraw(nbgl_layout_t *layoutParam)
Applies given layout. The screen will be redrawn.
Definition: nbgl_layout.c:3336
#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:1422
int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
Creates an area with given text (in bold) and sub text (in regular)
Definition: nbgl_layout.c:1300
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:3242
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:1169
#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:2082
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:1688
#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:1504
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:1601
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:2259
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:2011
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:1334
int nbgl_layoutAddTextWithAlias(nbgl_layout_t *layout, const char *text, const char *subText, uint8_t token, uint8_t index)
Creates an area with given text (in bold) and sub text (in regular), with a icon on right of text to ...
Definition: nbgl_layout.c:1317
int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout)
Creates a touchable bar in main panel.
Definition: nbgl_layout.c:1221
#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:1124
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:1083
#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:1260
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:1838
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:2102
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:2548
#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:1815
int nbgl_layoutRelease(nbgl_layout_t *layoutParam)
Release the layout obtained with nbgl_layoutGet()
Definition: nbgl_layout.c:3367
#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:2204
@ 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:2285
#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:1195
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:1375
#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:2232
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:3271
#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:994
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:286
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:296
bool localized
if set to true, use nameIds and not names
Definition: nbgl_content.h:293
uint8_t initChoice
index of the current choice
Definition: nbgl_content.h:295
const char *const * names
array of strings giving the choices (nbChoices)
Definition: nbgl_content.h:288
uint8_t nbChoices
number of choices
Definition: nbgl_content.h:294
This structure contains info to build a switch (on the right) with a description (on the left),...
Definition: nbgl_content.h:246
const char * text
main text for the switch
Definition: nbgl_content.h:247
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_content.h:251
nbgl_state_t initState
initial state of the switch
Definition: nbgl_content.h:250
const char * subText
description under main text (NULL terminated, single line, may be null)
Definition: nbgl_content.h:249
This structure contains a list of [tag,value] pairs.
Definition: nbgl_content.h:185
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead
Definition: nbgl_content.h:187
bool wrapping
if set to true, value text will be wrapped on ' ' to avoid cutting words
Definition: nbgl_content.h:198
uint8_t startIndex
index of the first pair to get with callback
Definition: nbgl_content.h:191
nbgl_contentTagValueCallback_t callback
function to call to retrieve a given pair
Definition: nbgl_content.h:188
This structure contains a [tag,value] pair.
Definition: nbgl_content.h:148
const nbgl_icon_details_t * valueIcon
Definition: nbgl_content.h:153
const char * value
string giving the value name
Definition: nbgl_content.h:150
const char * item
string giving the tag name
Definition: nbgl_content.h:149
const char * text
text of the tip-box
Definition: nbgl_content.h:320
const nbgl_icon_details_t * icon
icon of the tip-box
Definition: nbgl_content.h:321
uint8_t token
token used when tip-box is tapped
Definition: nbgl_content.h:322
structure defining an ASCII font
Definition: nbgl_fonts.h:80
uint8_t line_height
height of a line for all characters in pixels
Definition: nbgl_fonts.h:85
This structure contains info to build a clickable "bar" with a text and an icon.
Definition: nbgl_layout.h:197
bool inactive
if set to true, the bar is grayed-out and cannot be touched
Definition: nbgl_layout.h:206
const char * text
text (can be NULL)
Definition: nbgl_layout.h:200
uint8_t token
the token that will be used as argument of the callback
Definition: nbgl_layout.h:205
bool large
set to true only for the main level of OS settings
Definition: nbgl_layout.h:204
const char * subText
sub text (can be NULL)
Definition: nbgl_layout.h:203
const nbgl_icon_details_t * iconLeft
a buffer containing the 1BPP icon for icon on left (can be NULL)
Definition: nbgl_layout.h:199
const nbgl_icon_details_t * iconRight
Definition: nbgl_layout.h:201
This structure contains info to build a single button.
Definition: nbgl_layout.h: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