Embedded SDK
Embedded SDK
nbgl_layout_keyboard.c
Go to the documentation of this file.
1 
7 #ifdef HAVE_SE_TOUCH
8 #ifdef NBGL_KEYBOARD
9 /*********************
10  * INCLUDES
11  *********************/
12 #include <string.h>
13 #include <stdlib.h>
14 #include "nbgl_debug.h"
15 #include "nbgl_front.h"
16 #include "nbgl_layout_internal.h"
17 #include "nbgl_obj.h"
18 #include "nbgl_draw.h"
19 #include "nbgl_screen.h"
20 #include "nbgl_touch.h"
21 #include "glyphs.h"
22 #include "os_pic.h"
23 #include "os_helpers.h"
24 
25 /*********************
26  * DEFINES
27  *********************/
28 // for suggestion buttons, on Flex there are other objects than buttons
29 enum {
31 #ifndef TARGET_STAX
32  LEFT_HALF_INDEX, // half disc displayed on the bottom left
33  RIGHT_HALF_INDEX, // half disc displayed on the bottom right
34 #endif // TARGET_STAX
37 #ifdef TARGET_STAX
38  THIRD_BUTTON_INDEX,
39  FOURTH_BUTTON_INDEX,
40 #endif // TARGET_STAX
42 };
43 
44 #ifdef TARGET_STAX
45 #define TEXT_ENTRY_NORMAL_HEIGHT 64
46 #define TEXT_ENTRY_COMPACT_HEIGHT 64
47 #define BOTTOM_NORMAL_MARGIN 24
48 #define BOTTOM_COMPACT_MARGIN 24
49 #define TOP_NORMAL_MARGIN 20
50 #define TOP_COMPACT_MARGIN 20
51 #else // TARGET_STAX
52 #define TEXT_ENTRY_NORMAL_HEIGHT 72
53 #define TEXT_ENTRY_COMPACT_HEIGHT 56
54 #define BOTTOM_NORMAL_MARGIN 24
55 #define BOTTOM_COMPACT_MARGIN 12
56 #define TOP_NORMAL_MARGIN 20
57 #define TOP_COMPACT_MARGIN 12
58 #endif // TARGET_STAX
59 
60 // a horizontal line, even if displayed on 2 pixels, takes 4 pixels
61 #define LINE_REAL_HEIGHT 4
62 
63 #define NUMBER_WIDTH 56
64 
65 // space between number and text
66 #define NUMBER_TEXT_SPACE 8
67 
68 /**********************
69  * MACROS
70  **********************/
71 
72 /**********************
73  * TYPEDEFS
74  **********************/
75 
76 /**********************
77  * VARIABLES
78  **********************/
79 
80 static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS];
81 static char numText[5];
82 static uint8_t nbActiveButtons;
83 #ifndef TARGET_STAX
84 static nbgl_image_t *partialButtonImages[2];
85 #endif // TARGET_STAX
86 
87 /**********************
88  * STATIC PROTOTYPES
89  **********************/
90 
91 // function used on Flex to display (or not) beginning of next button and/or end of
92 // previous button, and update buttons when swipping
93 static bool updateSuggestionButtons(nbgl_container_t *container,
94  nbgl_touchType_t eventType,
95  uint8_t currentLeftButtonIndex)
96 {
97  bool needRefresh = false;
98  uint8_t page = 0;
99  uint32_t i;
100 
101  if ((eventType == SWIPED_LEFT)
102  && (currentLeftButtonIndex
103  < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
104  // shift all buttons on the left if there are still at least
105  // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons to display
106  currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
107  container->children[FIRST_BUTTON_INDEX]
108  = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex];
109 
110  for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
111  if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
112  container->children[FIRST_BUTTON_INDEX + i]
113  = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
114  }
115  else {
116  container->children[FIRST_BUTTON_INDEX + i] = NULL;
117  }
118  }
119  page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
120  needRefresh = true;
121  }
122  else if ((eventType == SWIPED_RIGHT)
123  && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
124  // shift all buttons on the left if we are not already displaying the
125  // NB_MAX_VISIBLE_SUGGESTION_BUTTONS first ones
126  currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
127  for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
128  container->children[FIRST_BUTTON_INDEX + i]
129  = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
130  }
131  page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
132  needRefresh = true;
133  }
134  // align top-left button on the left
135  if (container->children[FIRST_BUTTON_INDEX] != NULL) {
136  container->children[FIRST_BUTTON_INDEX]->alignmentMarginX = BORDER_MARGIN;
137  container->children[FIRST_BUTTON_INDEX]->alignmentMarginY = 0;
138  container->children[FIRST_BUTTON_INDEX]->alignment = TOP_LEFT;
139  container->children[FIRST_BUTTON_INDEX]->alignTo = (nbgl_obj_t *) container;
140  }
141 
142  // align top-right button on top-left one
143  if (container->children[SECOND_BUTTON_INDEX] != NULL) {
144  container->children[SECOND_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
145  container->children[SECOND_BUTTON_INDEX]->alignmentMarginY = 0;
146  container->children[SECOND_BUTTON_INDEX]->alignment = MID_RIGHT;
147  container->children[SECOND_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
148  }
149 #ifdef TARGET_STAX
150  // align bottom-left button on top_left one
151  if (container->children[THIRD_BUTTON_INDEX] != NULL) {
152  container->children[THIRD_BUTTON_INDEX]->alignmentMarginX = 0;
153  container->children[THIRD_BUTTON_INDEX]->alignmentMarginY = INTERNAL_MARGIN;
154  container->children[THIRD_BUTTON_INDEX]->alignment = BOTTOM_MIDDLE;
155  container->children[THIRD_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
156  }
157 
158  // align bottom-right button on bottom-left one
159  if (container->children[FOURTH_BUTTON_INDEX] != NULL) {
160  container->children[FOURTH_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
161  container->children[FOURTH_BUTTON_INDEX]->alignmentMarginY = 0;
162  container->children[FOURTH_BUTTON_INDEX]->alignment = MID_RIGHT;
163  container->children[FOURTH_BUTTON_INDEX]->alignTo = container->children[THIRD_BUTTON_INDEX];
164  }
165 #endif // TARGET_STAX
166 
167  // the first child is used by the progress indicator, displayed if more that
168  // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
169  nbgl_page_indicator_t *indicator
170  = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
171  indicator->activePage = page;
172 
173 #ifndef TARGET_STAX
174  // if not on the first button, display end of previous button
175  if (currentLeftButtonIndex > 0) {
176  container->children[LEFT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[0];
177  }
178  else {
179  container->children[LEFT_HALF_INDEX] = NULL;
180  }
181  // if not on the last button, display beginning of next button
182  if (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
183  container->children[RIGHT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[1];
184  }
185  else {
186  container->children[RIGHT_HALF_INDEX] = NULL;
187  }
188 #endif // TARGET_STAX
189  return needRefresh;
190 }
191 
192 /**********************
193  * GLOBAL INTERNAL FUNCTIONS
194  **********************/
195 
197 {
198  nbgl_container_t *container = (nbgl_container_t *) obj;
199  nbgl_container_t *suggestionsContainer;
200 
201  if ((container->nbChildren < 2) || (container->children[1]->type != CONTAINER)) {
202  return false;
203  }
204  suggestionsContainer = (nbgl_container_t *) container->children[1];
205  // try if suggestions buttons (more than NB_MAX_VISIBLE_SUGGESTION_BUTTONS)
206  if (((eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT))
207  && (suggestionsContainer->nbChildren == (nbActiveButtons + FIRST_BUTTON_INDEX))
208  && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
209  uint32_t i = 0;
210  while (i < (uint32_t) nbActiveButtons) {
211  if (suggestionsContainer->children[FIRST_BUTTON_INDEX]
212  == (nbgl_obj_t *) choiceButtons[i]) {
213  break;
214  }
215  i++;
216  }
217 
218  if (i < (uint32_t) nbActiveButtons) {
219  if (updateSuggestionButtons(suggestionsContainer, eventType, i)) {
220  io_seproxyhal_play_tune(TUNE_TAP_CASUAL);
221  nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
223  }
224 
225  return true;
226  }
227  }
228  return false;
229 }
230 
231 static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt,
232  const char *title,
233  const char *text,
234  bool numbered,
235  uint8_t number,
236  bool grayedOut,
237  int textToken,
238  bool compactMode)
239 {
240  nbgl_container_t *container;
241  nbgl_text_area_t *textArea;
242  layoutObj_t *obj;
243  uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
244 
245  // create a container, to store title, entered text and underline
246  container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
247  container->nbChildren = 4;
248  container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
249  container->obj.area.width = AVAILABLE_WIDTH;
250  container->obj.alignment = CENTER;
251 
252  if (title != NULL) {
253  // create text area for title
254  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
255  textArea->textColor = BLACK;
256  textArea->text = title;
257  textArea->textAlignment = CENTER;
258  textArea->fontId = SMALL_REGULAR_FONT;
259  textArea->wrapping = true;
260  textArea->obj.alignment = TOP_MIDDLE;
261  textArea->obj.area.width = AVAILABLE_WIDTH;
262  textArea->obj.area.height = nbgl_getTextHeightInWidth(
263  textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
264  container->children[0] = (nbgl_obj_t *) textArea;
265  container->obj.area.height = textArea->obj.area.height + 4;
266  }
267 
268  if (numbered) {
269  // create Word num typed text
270  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
271  textArea->textColor = BLACK;
272  snprintf(numText, sizeof(numText), "%d.", number);
273  textArea->text = numText;
274  textArea->textAlignment = CENTER;
275  textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
276  textArea->obj.area.width = NUMBER_WIDTH;
277  if (title != NULL) {
278  textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT;
279  textArea->obj.alignTo = container->children[0];
280  textArea->obj.alignment = BOTTOM_LEFT;
281  }
282  else {
283  textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT;
284  textArea->obj.alignment = TOP_LEFT;
285  }
286  textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT;
287  // set this text area as child of the container
288  container->children[1] = (nbgl_obj_t *) textArea;
289  }
290 
291  // create text area for entered text
292  textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
293  textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK;
294  textArea->text = text;
295  textArea->textAlignment = MID_LEFT;
296  textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
297  if (title != NULL) {
298  textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT;
299  textArea->obj.alignTo = container->children[0];
300  textArea->obj.alignment = BOTTOM_LEFT;
301  }
302  else {
303  textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT;
304  textArea->obj.alignment = TOP_LEFT;
305  }
306  textArea->obj.area.width = AVAILABLE_WIDTH;
307  if (numbered) {
308  textArea->obj.alignmentMarginX = NUMBER_WIDTH + NUMBER_TEXT_SPACE;
309  textArea->obj.area.width -= textArea->obj.alignmentMarginX;
310  }
311  textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT;
312  textArea->autoHideLongLine = true;
313 
314  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) textArea, textToken, NBGL_NO_TUNE);
315  if (obj == NULL) {
316  return NULL;
317  }
318  textArea->obj.touchMask = (1 << TOUCHED);
319  textArea->obj.touchId = ENTERED_TEXT_ID;
320  container->children[2] = (nbgl_obj_t *) textArea;
321  container->obj.area.height += textEntryHeight;
322 
323  // create gray line
324  nbgl_line_t *line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
325  line->lineColor = LIGHT_GRAY;
326  // align on bottom of the container
327  line->obj.alignment = BOTTOM_MIDDLE;
328  line->obj.area.width = AVAILABLE_WIDTH;
329  line->obj.area.height = LINE_REAL_HEIGHT;
330  line->direction = HORIZONTAL;
331  line->thickness = 2;
332  line->offset = 2;
333  // set this line as child of the container
334  container->children[3] = (nbgl_obj_t *) line;
335 
336  return container;
337 }
338 
339 static nbgl_container_t *addSuggestionButtons(nbgl_layoutInternal_t *layoutInt,
340  uint8_t nbUsedButtons,
341  const char **buttonTexts,
342  int firstButtonToken,
343  tune_index_e tuneId,
344  bool compactMode)
345 {
346  nbgl_container_t *suggestionsContainer;
347  layoutObj_t *obj;
348 
349  nbActiveButtons = nbUsedButtons;
350  suggestionsContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
351  suggestionsContainer->layout = VERTICAL;
352  suggestionsContainer->obj.area.width = SCREEN_WIDTH;
353 #ifdef TARGET_STAX
354  // 2 rows of buttons with radius=32, and a intervale of 8px
355  suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT + INTERNAL_MARGIN + 28;
356 #else // TARGET_STAX
357  // 1 row of buttons + 24px + page indicator
358  suggestionsContainer->obj.area.height = SMALL_BUTTON_HEIGHT + 28;
359 #endif // TARGET_STAX
360  suggestionsContainer->nbChildren = nbActiveButtons + FIRST_BUTTON_INDEX;
361  suggestionsContainer->children
363 
364  // put suggestionsContainer at 24px of the bottom of main container
365  suggestionsContainer->obj.alignmentMarginY
367  suggestionsContainer->obj.alignment = BOTTOM_MIDDLE;
368 
369  // create all possible suggestion buttons, even if not displayed at first
371  BUTTON, NB_MAX_SUGGESTION_BUTTONS, layoutInt->layer, (nbgl_obj_t **) &choiceButtons);
372  for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
373  obj = layoutAddCallbackObj(
374  layoutInt, (nbgl_obj_t *) choiceButtons[i], firstButtonToken + i, tuneId);
375  if (obj == NULL) {
376  return NULL;
377  }
378 
379  choiceButtons[i]->innerColor = BLACK;
380  choiceButtons[i]->borderColor = BLACK;
381  choiceButtons[i]->foregroundColor = WHITE;
382  choiceButtons[i]->obj.area.width = (AVAILABLE_WIDTH - INTERNAL_MARGIN) / 2;
383  choiceButtons[i]->obj.area.height = SMALL_BUTTON_HEIGHT;
384  choiceButtons[i]->radius = RADIUS_32_PIXELS;
385  choiceButtons[i]->fontId = SMALL_BOLD_1BPP_FONT;
386  choiceButtons[i]->text = buttonTexts[i];
387  choiceButtons[i]->obj.touchMask = (1 << TOUCHED);
388  choiceButtons[i]->obj.touchId = CONTROLS_ID + i;
389  // some buttons may not be visible
390  if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
391  suggestionsContainer->children[i + FIRST_BUTTON_INDEX]
392  = (nbgl_obj_t *) choiceButtons[i];
393  }
394  }
395  // The first child is used by the progress indicator, if more that
396  // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
397  nbgl_page_indicator_t *indicator
399  indicator->activePage = 0;
400  indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
402  indicator->obj.area.width = 184;
403  indicator->obj.alignment = BOTTOM_MIDDLE;
404  indicator->style = CURRENT_INDICATOR;
405  suggestionsContainer->children[PAGE_INDICATOR_INDEX] = (nbgl_obj_t *) indicator;
406 #ifdef TARGET_FLEX
407  // also allocate the semi disc that may be displayed on the left or right of the full
408  // buttons
409  nbgl_objPoolGetArray(IMAGE, 2, layoutInt->layer, (nbgl_obj_t **) &partialButtonImages);
410  partialButtonImages[0]->buffer = &C_left_half_64px;
411  partialButtonImages[0]->obj.alignment = TOP_LEFT;
412  partialButtonImages[0]->foregroundColor = BLACK;
413  partialButtonImages[0]->transformation = VERTICAL_MIRROR;
414  partialButtonImages[1]->buffer = &C_left_half_64px;
415  partialButtonImages[1]->obj.alignment = TOP_RIGHT;
416  partialButtonImages[1]->foregroundColor = BLACK;
417  partialButtonImages[1]->transformation = NO_TRANSFORMATION;
418  updateSuggestionButtons(suggestionsContainer, 0, 0);
419 #endif // TARGET_STAX
420 
421  return suggestionsContainer;
422 }
423 
424 static nbgl_button_t *addConfirmationButton(nbgl_layoutInternal_t *layoutInt,
425  bool active,
426  const char *text,
427  int token,
428  tune_index_e tuneId,
429  bool compactMode)
430 {
431  nbgl_button_t *button;
432  layoutObj_t *obj;
433 
434  button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
435  obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
436  if (obj == NULL) {
437  return NULL;
438  }
439 
440  // put button at 24px/12px of the keyboard
441  button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
442  button->obj.alignment = BOTTOM_MIDDLE;
443  button->foregroundColor = WHITE;
444  if (active) {
445  button->innerColor = BLACK;
446  button->borderColor = BLACK;
447  button->obj.touchMask = (1 << TOUCHED);
448  button->obj.touchId = BOTTOM_BUTTON_ID;
449  }
450  else {
451  button->borderColor = LIGHT_GRAY;
452  button->innerColor = LIGHT_GRAY;
453  }
454  button->text = PIC(text);
455  button->fontId = SMALL_BOLD_1BPP_FONT;
456  button->obj.area.width = AVAILABLE_WIDTH;
457  button->obj.area.height = BUTTON_DIAMETER;
458  button->radius = BUTTON_RADIUS;
459 
460  return button;
461 }
462 
463 /**********************
464  * GLOBAL API FUNCTIONS
465  **********************/
466 
475 {
476  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
477  nbgl_keyboard_t *keyboard;
478 
479  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboard():\n");
480  if (layout == NULL) {
481  return -1;
482  }
483  // footer must be empty
484  if (layoutInt->footerContainer != NULL) {
485  return -1;
486  }
487 
488  // create keyboard
489  keyboard = (nbgl_keyboard_t *) nbgl_objPoolGet(KEYBOARD, layoutInt->layer);
490  keyboard->obj.area.width = SCREEN_WIDTH;
491  keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
492  if (!kbdInfo->lettersOnly) {
493  keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
494  }
495 #ifdef TARGET_STAX
496  keyboard->obj.alignmentMarginY = 56;
497 #endif // TARGET_STAX
498  keyboard->obj.alignment = BOTTOM_MIDDLE;
499  keyboard->borderColor = LIGHT_GRAY;
500  keyboard->callback = PIC(kbdInfo->callback);
501  keyboard->lettersOnly = kbdInfo->lettersOnly;
502  keyboard->mode = kbdInfo->mode;
503  keyboard->keyMask = kbdInfo->keyMask;
504  keyboard->casing = kbdInfo->casing;
505 
506  // the keyboard occupies the footer
507  layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
508  layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
509  layoutInt->footerContainer->layout = VERTICAL;
510  layoutInt->footerContainer->children
511  = (nbgl_obj_t **) nbgl_containerPoolGet(1, layoutInt->layer);
512  layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
513  layoutInt->footerContainer->obj.area.height
514  = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
515  layoutInt->footerContainer->children[0] = (nbgl_obj_t *) keyboard;
516  layoutInt->footerContainer->nbChildren = 1;
517 
518  // add footer to layout children
519  layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
520 
521  // subtract footer height from main container height
522  layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
523 
524  // create the 2 children for main container (to hold keyboard content)
525  layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
526  layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
527 
528  layoutInt->footerType = KEYBOARD_FOOTER_TYPE;
529 
530  return layoutInt->footerContainer->obj.area.height;
531 }
532 
544  uint8_t index,
545  uint32_t keyMask,
546  bool updateCasing,
547  keyboardCase_t casing)
548 {
549  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
550  nbgl_keyboard_t *keyboard;
551 
552  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboard(): keyMask = 0x%X\n", keyMask);
553  if (layout == NULL) {
554  return -1;
555  }
556  UNUSED(index);
557 
558  // get existing keyboard (in the footer container)
559  keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
560  if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
561  return -1;
562  }
563  keyboard->keyMask = keyMask;
564  if (updateCasing) {
565  keyboard->casing = casing;
566  }
567 
568  nbgl_objDraw((nbgl_obj_t *) keyboard);
569 
570  return 0;
571 }
572 
581 {
582  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
583  nbgl_keyboard_t *keyboard;
584 
585  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutKeyboardNeedsRefresh(): \n");
586  if (layout == NULL) {
587  return -1;
588  }
589  UNUSED(index);
590 
591  // get existing keyboard (in the footer container)
592  keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
593  if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
594  return -1;
595  }
596  if (keyboard->needsRefresh) {
597  keyboard->needsRefresh = false;
598  return true;
599  }
600 
601  return false;
602 }
603 
617  uint8_t nbUsedButtons,
618  const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS],
619  int firstButtonToken,
620  tune_index_e tuneId)
621 {
622  nbgl_container_t *container;
623  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
624  // if a centered info has be used for title, entered text is the second child
625  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
626 
627  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSuggestionButtons():\n");
628  if (layout == NULL) {
629  return -1;
630  }
631 
632  container = addSuggestionButtons(
633  layoutInt, nbUsedButtons, buttonTexts, firstButtonToken, tuneId, false);
634  // set this container as 2nd or 3rd child of the main layout container
635  layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) container;
636  if (layoutInt->container->children[enteredTextIndex] != NULL) {
637  ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
638  ->obj.alignmentMarginY
639  -= (container->obj.area.height + container->obj.alignmentMarginY + 20) / 2;
640  }
641 #ifdef TARGET_FLEX
642  // the main container is swipable on Flex
643  if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
644  == NULL) {
645  return -1;
646  }
647  layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
648  layoutInt->container->obj.touchId = CONTROLS_ID;
649  layoutInt->swipeUsage = SWIPE_USAGE_SUGGESTIONS;
650 #endif // TARGET_FLEX
651  // set this new container as child of the main container
652  layoutAddObject(layoutInt, (nbgl_obj_t *) container);
653 
654  // return index of container to be modified later on
655  return (layoutInt->container->nbChildren - 1);
656 }
657 
670  uint8_t index,
671  uint8_t nbUsedButtons,
672  const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
673 {
674  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
675  nbgl_container_t *container;
676  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
677 
678  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateSuggestionButtons():\n");
679  if (layout == NULL) {
680  return -1;
681  }
682  UNUSED(index);
683 
684  container = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
685  if ((container == NULL) || (container->obj.type != CONTAINER)) {
686  return -1;
687  }
688  nbActiveButtons = nbUsedButtons;
689  container->nbChildren = nbUsedButtons + FIRST_BUTTON_INDEX;
690 
691  // update suggestion buttons
692  for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
693  choiceButtons[i]->text = buttonTexts[i];
694  // some buttons may not be visible
695  if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbUsedButtons)) {
696  if ((i % 2) == 0) {
697  choiceButtons[i]->obj.alignmentMarginX = BORDER_MARGIN;
698 #ifdef TARGET_STAX
699  // second row 8px under the first one
700  if (i != 0) {
701  choiceButtons[i]->obj.alignmentMarginY = INTERNAL_MARGIN;
702  }
703  choiceButtons[i]->obj.alignment = NO_ALIGNMENT;
704 #else // TARGET_STAX
705  if (i == 0) {
706  choiceButtons[i]->obj.alignment = TOP_LEFT;
707  }
708 #endif // TARGET_STAX
709  }
710  else {
711  choiceButtons[i]->obj.alignmentMarginX = INTERNAL_MARGIN;
712  choiceButtons[i]->obj.alignment = MID_RIGHT;
713  choiceButtons[i]->obj.alignTo = (nbgl_obj_t *) choiceButtons[i - 1];
714  }
715  container->children[i + FIRST_BUTTON_INDEX] = (nbgl_obj_t *) choiceButtons[i];
716  }
717  else {
718  container->children[i + FIRST_BUTTON_INDEX] = NULL;
719  }
720  }
721  container->forceClean = true;
722 #ifndef TARGET_STAX
723  // on Flex, the first child is used by the progress indicator, if more that 2 buttons
724  nbgl_page_indicator_t *indicator
725  = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
726  indicator->nbPages = (nbUsedButtons + 1) / 2;
727  indicator->activePage = 0;
728  updateSuggestionButtons(container, 0, 0);
729 #endif // TARGET_STAX
730 
731  nbgl_objDraw((nbgl_obj_t *) container);
732 
733  return 0;
734 }
735 
754  bool numbered,
755  uint8_t number,
756  const char *text,
757  bool grayedOut,
758  int offsetY,
759  int token)
760 {
761  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
762  nbgl_container_t *container;
763  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
764  bool compactMode = ((layoutInt->container->children[enteredTextIndex + 1] != NULL)
765  && (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON)
766  && (layoutInt->container->nbChildren == 3));
767 
768  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddEnteredText():\n");
769  if (layout == NULL) {
770  return -1;
771  }
772  UNUSED(offsetY);
773 
774  container
775  = addTextEntry(layoutInt, NULL, text, numbered, number, grayedOut, token, compactMode);
776 
777  // set this container as first or 2nd child of the main layout container
778  layoutInt->container->children[enteredTextIndex] = (nbgl_obj_t *) container;
779 
780  if (layoutInt->container->children[enteredTextIndex + 1] != NULL) {
781  if (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON) {
782  nbgl_button_t *button
783  = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
784  container->obj.alignmentMarginY
785  -= (button->obj.area.height + button->obj.alignmentMarginY
786  + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
787  / 2;
788  }
789  else if (layoutInt->container->children[enteredTextIndex + 1]->type == CONTAINER) {
790  nbgl_container_t *suggestionContainer
791  = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
792  container->obj.alignmentMarginY
793  -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
794  + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
795  / 2;
796  }
797  }
798  // if a centered info has be used for title, entered text is the second child and we have to
799  // adjust layout
800  if (layoutInt->container->nbChildren == 3) {
801  container->obj.alignmentMarginY += layoutInt->container->children[0]->area.height / 2;
802  }
803 
804  // return 0
805  return 0;
806 }
807 
822  uint8_t index,
823  bool numbered,
824  uint8_t number,
825  const char *text,
826  bool grayedOut)
827 {
828  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
829  nbgl_container_t *container;
830  nbgl_text_area_t *textArea;
831  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
832 
833  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText():\n");
834  if (layout == NULL) {
835  return -1;
836  }
837  UNUSED(index);
838 
839  // update text entry area
840  container = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex];
841  if ((container == NULL) || (container->obj.type != CONTAINER)) {
842  return -1;
843  }
844  textArea = (nbgl_text_area_t *) container->children[2];
845  if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
846  return -1;
847  }
848  textArea->text = text;
849  textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK;
850  textArea->textAlignment = MID_LEFT;
851  nbgl_objDraw((nbgl_obj_t *) textArea);
852 
853  // update number text area
854  if (numbered) {
855  // it is the previously created object
856  textArea = (nbgl_text_area_t *) layoutInt->container->children[1];
857  snprintf(numText, sizeof(numText), "%d.", number);
858  textArea->text = numText;
859  nbgl_objDraw((nbgl_obj_t *) textArea);
860  }
861  // if the text doesn't fit, indicate it by returning 1 instead of 0, for different refresh
862  if (nbgl_getSingleLineTextWidth(textArea->fontId, text) > textArea->obj.area.width) {
863  return 1;
864  }
865  return 0;
866 }
867 
880  bool active,
881  const char *text,
882  int token,
883  tune_index_e tuneId)
884 {
885  nbgl_button_t *button;
886  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
887  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
888  bool compactMode = (layoutInt->container->nbChildren == 3);
889 
890  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddConfirmationButton():\n");
891  if (layout == NULL) {
892  return -1;
893  }
894 
895  button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
896  // set this button as second child of the main layout container
897  layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) button;
898  if (layoutInt->container->children[enteredTextIndex] != NULL) {
899  ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
900  ->obj.alignmentMarginY
901  -= (button->obj.area.height + button->obj.alignmentMarginY
902  + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
903  / 2;
904  }
905  // return 0
906  return 0;
907 }
908 
921  uint8_t index,
922  bool active,
923  const char *text)
924 {
925  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
926  nbgl_button_t *button;
927  uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
928 
929  UNUSED(index);
930 
931  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateConfirmationButton():\n");
932  if (layout == NULL) {
933  return -1;
934  }
935 
936  // update main text area
937  button = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
938  if ((button == NULL) || (button->obj.type != BUTTON)) {
939  return -1;
940  }
941  button->text = text;
942 
943  if (active) {
944  button->innerColor = BLACK;
945  button->borderColor = BLACK;
946  button->obj.touchMask = (1 << TOUCHED);
947  button->obj.touchId = BOTTOM_BUTTON_ID;
948  }
949  else {
950  button->borderColor = LIGHT_GRAY;
951  button->innerColor = LIGHT_GRAY;
952  }
953  nbgl_objDraw((nbgl_obj_t *) button);
954  return 0;
955 }
956 
966 {
967  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
968  nbgl_container_t *container;
969  bool compactMode = ((content->type == KEYBOARD_WITH_BUTTON) && (content->title != NULL));
970 
971  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboardContent():\n");
972  if (layout == NULL) {
973  return -1;
974  }
975 
976  container = addTextEntry(layoutInt,
977  content->title,
978  content->text,
979  content->numbered,
980  content->number,
981  content->grayedOut,
982  content->textToken,
983  compactMode);
984 
985  // set this container as first child of the main layout container
986  layoutInt->container->children[0] = (nbgl_obj_t *) container;
987 
988  if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
989  nbgl_container_t *suggestionsContainer
990  = addSuggestionButtons(layoutInt,
992  content->suggestionButtons.buttons,
994  content->tuneId,
995  compactMode);
996  // set this container as second child of the main layout container
997  layoutInt->container->children[1] = (nbgl_obj_t *) suggestionsContainer;
998  // the main container is swipable on Flex
999  if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
1000  == NULL) {
1001  return -1;
1002  }
1003  layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
1004  layoutInt->container->obj.touchId = CONTROLS_ID;
1005  layoutInt->swipeUsage = SWIPE_USAGE_SUGGESTIONS;
1006  container->obj.alignmentMarginY
1007  -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1008  + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1009  / 2;
1010  }
1011  else if (content->type == KEYBOARD_WITH_BUTTON) {
1012  nbgl_button_t *button = addConfirmationButton(layoutInt,
1013  content->confirmationButton.active,
1014  content->confirmationButton.text,
1015  content->confirmationButton.token,
1016  content->tuneId,
1017  compactMode);
1018  // set this button as second child of the main layout container
1019  layoutInt->container->children[1] = (nbgl_obj_t *) button;
1020  container->obj.alignmentMarginY
1021  -= (button->obj.area.height + button->obj.alignmentMarginY
1022  + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1023  / 2;
1024  }
1025 
1026  return layoutInt->container->obj.area.height;
1027 }
1028 
1040 {
1041  nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1042  nbgl_container_t *container;
1043  nbgl_text_area_t *textArea;
1044 
1045  LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent():\n");
1046  if (layout == NULL) {
1047  return -1;
1048  }
1049 
1050  // get top container from main container (it shall be the 1st object)
1051  container = (nbgl_container_t *) layoutInt->container->children[0];
1052 
1053  if (content->numbered) {
1054  // get Word number typed text
1055  textArea = (nbgl_text_area_t *) container->children[1];
1056  snprintf(numText, sizeof(numText), "%d.", content->number);
1057  nbgl_objDraw((nbgl_obj_t *) textArea);
1058  }
1059 
1060  // get text area for entered text
1061  textArea = (nbgl_text_area_t *) container->children[2];
1062  textArea->textColor = content->grayedOut ? LIGHT_GRAY : BLACK;
1063  textArea->text = content->text;
1064  nbgl_objDraw((nbgl_obj_t *) textArea);
1065 
1066  if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
1067  nbActiveButtons = content->suggestionButtons.nbUsedButtons;
1068  nbgl_container_t *suggestionsContainer
1069  = (nbgl_container_t *) layoutInt->container->children[1];
1070  suggestionsContainer->nbChildren = nbActiveButtons + FIRST_BUTTON_INDEX;
1071 
1072  // update suggestion buttons
1073  for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1074  choiceButtons[i]->text = content->suggestionButtons.buttons[i];
1075  // some buttons may not be visible
1076  if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
1077  suggestionsContainer->children[i + FIRST_BUTTON_INDEX]
1078  = (nbgl_obj_t *) choiceButtons[i];
1079  }
1080  else {
1081  suggestionsContainer->children[i + FIRST_BUTTON_INDEX] = NULL;
1082  }
1083  }
1084  suggestionsContainer->forceClean = true;
1085  // the first child is used by the progress indicator, if more than
1086  // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
1087  nbgl_page_indicator_t *indicator
1088  = (nbgl_page_indicator_t *) suggestionsContainer->children[PAGE_INDICATOR_INDEX];
1089  indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1091  indicator->activePage = 0;
1092  updateSuggestionButtons(suggestionsContainer, 0, 0);
1093 
1094  nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
1095  }
1096  else if (content->type == KEYBOARD_WITH_BUTTON) {
1097  // update main text area
1098  nbgl_button_t *button = (nbgl_button_t *) layoutInt->container->children[1];
1099  if ((button == NULL) || (button->obj.type != BUTTON)) {
1100  return -1;
1101  }
1102  button->text = content->confirmationButton.text;
1103 
1104  if (content->confirmationButton.active) {
1105  button->innerColor = BLACK;
1106  button->borderColor = BLACK;
1107  button->obj.touchMask = (1 << TOUCHED);
1108  button->obj.touchId = BOTTOM_BUTTON_ID;
1109  }
1110  else {
1111  button->borderColor = LIGHT_GRAY;
1112  button->innerColor = LIGHT_GRAY;
1113  }
1114  nbgl_objDraw((nbgl_obj_t *) button);
1115  }
1116 
1117  // if the entered text doesn't fit, indicate it by returning 1 instead of 0, for different
1118  // refresh
1119  if (nbgl_getSingleLineTextWidth(textArea->fontId, content->text) > textArea->obj.area.width) {
1120  return 1;
1121  }
1122  return 0;
1123 }
1124 
1125 #endif // NBGL_KEYBOARD
1126 #endif // HAVE_SE_TOUCH
debug traces management
#define LOG_DEBUG(__logger,...)
Definition: nbgl_debug.h:86
@ LAYOUT_LOGGER
Definition: nbgl_debug.h:33
Middle Level API of the new BOLOS Graphical Library.
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text until the first or \0 is encountered
Definition: nbgl_fonts.c:326
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
return the height of the given multiline text, with the given font.
Definition: nbgl_fonts.c:1040
Font screen low-Level driver API, to draw elementary forms.
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
#define NB_MAX_VISIBLE_SUGGESTION_BUTTONS
Definition: nbgl_layout.h:55
#define AVAILABLE_WIDTH
Definition: nbgl_layout.h:66
#define NB_MAX_SUGGESTION_BUTTONS
Definition: nbgl_layout.h:53
void * nbgl_layout_t
type shared externally
Definition: nbgl_layout.h:96
#define NBGL_NO_TUNE
Definition: nbgl_layout.h:29
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
Definition: nbgl_layout.h:365
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
Definition: nbgl_layout.h:364
Internal functions/constants of NBGL layout layer.
@ SWIPE_USAGE_SUGGESTIONS
@ FOOTER_INDEX
#define SMALL_BUTTON_HEIGHT
#define KEYBOARD_FOOTER_TYPE
#define INTERNAL_MARGIN
int nbgl_layoutUpdateKeyboard(nbgl_layout_t *layout, uint8_t index, uint32_t keyMask, bool updateCasing, keyboardCase_t casing)
Updates an existing keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInfo)
Creates a keyboard on bottom of the screen, with the given configuration.
#define BOTTOM_COMPACT_MARGIN
int nbgl_layoutAddSuggestionButtons(nbgl_layout_t *layout, uint8_t nbUsedButtons, const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS], int firstButtonToken, tune_index_e tuneId)
Adds up to 4 black suggestion buttons under the previously added object.
bool keyboardSwipeCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
#define TEXT_ENTRY_NORMAL_HEIGHT
@ LEFT_HALF_INDEX
@ SECOND_BUTTON_INDEX
@ NB_SUGGESTION_CHILDREN
@ PAGE_INDICATOR_INDEX
@ FIRST_BUTTON_INDEX
@ RIGHT_HALF_INDEX
#define LINE_REAL_HEIGHT
#define BOTTOM_NORMAL_MARGIN
int nbgl_layoutUpdateSuggestionButtons(nbgl_layout_t *layout, uint8_t index, uint8_t nbUsedButtons, const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
Updates the number and/or the text suggestion buttons created with nbgl_layoutAddSuggestionButtons()
int nbgl_layoutAddKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
Adds an area containing a potential title, a text entry and either confirmation or suggestion buttons...
int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, bool numbered, uint8_t number, const char *text, bool grayedOut, int offsetY, int token)
Adds a "text entry" area under the previously entered object. This area can be preceded (beginning of...
int nbgl_layoutUpdateConfirmationButton(nbgl_layout_t *layout, uint8_t index, bool active, const char *text)
Updates an existing black full width confirmation button on top of the previously added keyboard.
int nbgl_layoutUpdateEnteredText(nbgl_layout_t *layout, uint8_t index, bool numbered, uint8_t number, const char *text, bool grayedOut)
Updates an existing "text entry" area, created with nbgl_layoutAddEnteredText()
int nbgl_layoutUpdateKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
Updates an area containing a potential title, a text entry and either confirmation or suggestion butt...
#define NUMBER_WIDTH
#define TOP_NORMAL_MARGIN
#define TEXT_ENTRY_COMPACT_HEIGHT
#define TOP_COMPACT_MARGIN
#define NUMBER_TEXT_SPACE
int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout, bool active, const char *text, int token, tune_index_e tuneId)
Adds a black full width confirmation button on top of the previously added keyboard.
bool nbgl_layoutKeyboardNeedsRefresh(nbgl_layout_t *layout, uint8_t index)
function called to know whether the keyboard has been redrawn and needs a refresh
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_text_area_s nbgl_text_area_t
struct to represent a text area (TEXT_AREA type)
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
Definition: nbgl_obj.c:1522
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.
keyboardCase_t
Letters casing in which to open/set the keyboard.
Definition: nbgl_obj.h:489
struct PACKED__ nbgl_keyboard_s nbgl_keyboard_t
struct to represent a keyboard (KEYBOARD type)
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
Definition: nbgl_obj.c:1571
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
int nbgl_objPoolGetArray(nbgl_obj_type_t type, uint8_t nbObjs, uint8_t layer, nbgl_obj_t **objArray)
Gets nbObjects new graphic object from the pool, with the given type, for the given layer (screen)....
#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
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 KEYBOARD_KEY_HEIGHT
Definition: nbgl_obj.h:35
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
@ CURRENT_INDICATOR
only current page dash is black
Definition: nbgl_obj.h:364
@ CONTROLS_ID
Definition: nbgl_obj.h:563
@ ENTERED_TEXT_ID
Definition: nbgl_obj.h:557
@ BOTTOM_BUTTON_ID
Definition: nbgl_obj.h:545
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
@ WHITE
Definition: nbgl_types.h:105
@ LIGHT_GRAY
Definition: nbgl_types.h:104
@ BLACK
Definition: nbgl_types.h:102
#define VERTICAL_MIRROR
Definition: nbgl_types.h:61
#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_RIGHT
Definition: nbgl_types.h:235
@ TOUCHED
Definition: nbgl_types.h:221
@ VERTICAL
from top to bottom
Definition: nbgl_types.h:170
@ HORIZONTAL
from left to right
Definition: nbgl_types.h:171
#define MIN(x, y)
Definition: nbgl_types.h:79
@ TOP_MIDDLE
Definition: nbgl_types.h:143
@ CENTER
Definition: nbgl_types.h:146
@ 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
@ 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
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition: nbgl_types.h:121
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition: nbgl_types.h:123
@ LINE
Vertical or Horizontal line.
Definition: nbgl_types.h:119
@ KEYBOARD
Keyboard.
Definition: nbgl_types.h:127
@ CONTAINER
Empty container.
Definition: nbgl_types.h:117
@ TEXT_AREA
Area to contain text line(s)
Definition: nbgl_types.h:120
#define NO_TRANSFORMATION
Definition: nbgl_types.h:55
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition: nbgl_types.h:289
int token
token of the button
Definition: nbgl_layout.h:384
const char * text
text of the button
Definition: nbgl_layout.h:383
bool active
if true, button is active, otherwise inactive (grayed-out)
Definition: nbgl_layout.h:385
Structure containing all information about the current layout.
nbgl_container_t * footerContainer
container used to store footer (buttons, nav....)
nbgl_swipe_usage_t swipeUsage
nbgl_container_t * container
nbgl_layoutFooterType_t footerType
type of footer
nbgl_obj_t ** children
children for main screen
This structure contains info to build a keyboard with nbgl_layoutAddKeyboard()
Definition: nbgl_layout.h:575
uint32_t keyMask
Definition: nbgl_layout.h:576
bool lettersOnly
if true, only display letter keys and Backspace
Definition: nbgl_layout.h:580
keyboardCallback_t callback
function called when an active key is pressed
Definition: nbgl_layout.h:579
keyboardMode_t mode
keyboard mode to start with
Definition: nbgl_layout.h:581
keyboardCase_t casing
keyboard casing mode (lower, upper once or upper locked)
Definition: nbgl_layout.h:583
This structure contains info to build a keyboard content (controls that are linked to keyboard)
Definition: nbgl_layout.h:392
uint8_t number
if numbered is true, number used to build 'number.' text
Definition: nbgl_layout.h:397
const char * text
already entered text
Definition: nbgl_layout.h:395
nbgl_layoutKeyboardContentType_t type
type of content
Definition: nbgl_layout.h:393
nbgl_layoutSuggestionButtons_t suggestionButtons
Definition: nbgl_layout.h:403
nbgl_layoutConfirmationButton_t confirmationButton
used if type is KEYBOARD_WITH_SUGGESTIONS
Definition: nbgl_layout.h:405
const char * title
centered title explaining the screen
Definition: nbgl_layout.h:394
bool numbered
if set to true, the text is preceded on the left by 'number.'
Definition: nbgl_layout.h:396
bool grayedOut
if true, the text is grayed out (but not the potential number)
Definition: nbgl_layout.h:398
uint8_t nbUsedButtons
the number of actually used buttons
Definition: nbgl_layout.h:376
const char ** buttons
array of 4 strings for buttons (last ones can be NULL)
Definition: nbgl_layout.h:373
unsigned short uint16_t
Definition: usbd_conf.h:54
unsigned char uint8_t
Definition: usbd_conf.h:53