Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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"
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_io_seph_cmd.h"
23#include "os_io_seph_ux.h"
24#include "os_pic.h"
25#include "os_helpers.h"
26
27/*********************
28 * DEFINES
29 *********************/
30#if defined(TARGET_FLEX)
31#define USE_PARTIAL_BUTTONS 1
32#endif // TARGET_FLEX
33
34// for suggestion buttons, on Flex there are other objects than buttons
35enum {
37#ifdef USE_PARTIAL_BUTTONS
38 LEFT_HALF_INDEX, // half disc displayed on the bottom left
39 RIGHT_HALF_INDEX, // half disc displayed on the bottom right
40#endif // USE_PARTIAL_BUTTONS
43#ifndef USE_PARTIAL_BUTTONS
46#endif // !USE_PARTIAL_BUTTONS
48};
49
50#if defined(TARGET_STAX)
51#define TEXT_ENTRY_NORMAL_HEIGHT 64
52#define TEXT_ENTRY_COMPACT_HEIGHT 64
53#define BOTTOM_NORMAL_MARGIN 24
54#define BOTTOM_COMPACT_MARGIN 24
55#define TOP_NORMAL_MARGIN 20
56#define TOP_COMPACT_MARGIN 20
57#elif defined(TARGET_FLEX)
58#define TEXT_ENTRY_NORMAL_HEIGHT 72
59#define TEXT_ENTRY_COMPACT_HEIGHT 56
60#define BOTTOM_NORMAL_MARGIN 24
61#define BOTTOM_COMPACT_MARGIN 12
62#define TOP_NORMAL_MARGIN 20
63#define TOP_COMPACT_MARGIN 12
64#endif // TARGETS
65
66#ifdef USE_PARTIAL_BUTTONS
67#if defined(TARGET_FLEX)
68#define LEFT_HALF_ICON C_left_half_64px
69#endif // TARGETS
70#endif // USE_PARTIAL_BUTTONS
71
72// a horizontal line, even if displayed on 2 pixels, takes 4 pixels
73#define LINE_REAL_HEIGHT 4
74
75#define NUMBER_WIDTH 56
76
77// space between number and text
78#define NUMBER_TEXT_SPACE 8
79
80/**********************
81 * MACROS
82 **********************/
83
84/**********************
85 * TYPEDEFS
86 **********************/
87
88/**********************
89 * VARIABLES
90 **********************/
91
92static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS];
93static char numText[5];
94static uint8_t nbActiveButtons;
95#ifdef USE_PARTIAL_BUTTONS
96static nbgl_image_t *partialButtonImages[2];
97#endif // USE_PARTIAL_BUTTONS
98
99/**********************
100 * STATIC PROTOTYPES
101 **********************/
102
103// function used on Flex to display (or not) beginning of next button and/or end of
104// previous button, and update buttons when swipping
105static bool updateSuggestionButtons(nbgl_container_t *container,
106 nbgl_touchType_t eventType,
107 uint8_t currentLeftButtonIndex)
108{
109 bool needRefresh = false;
110 uint8_t page = 0;
111 uint32_t i;
112
113 if ((eventType == SWIPED_LEFT)
114 && (currentLeftButtonIndex
115 < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
116 // shift all buttons on the left if there are still at least
117 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons to display
118 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
119 container->children[FIRST_BUTTON_INDEX]
120 = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex];
121
122 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
123 if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
124 container->children[FIRST_BUTTON_INDEX + i]
125 = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
126 }
127 else {
128 container->children[FIRST_BUTTON_INDEX + i] = NULL;
129 }
130 }
131 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
132 needRefresh = true;
133 }
134 else if ((eventType == SWIPED_RIGHT)
135 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
136 // shift all buttons on the left if we are not already displaying the
137 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS first ones
138 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
139 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
140 container->children[FIRST_BUTTON_INDEX + i]
141 = (nbgl_obj_t *) choiceButtons[currentLeftButtonIndex + i];
142 }
143 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
144 needRefresh = true;
145 }
146 // align top-left button on the left
147 if (container->children[FIRST_BUTTON_INDEX] != NULL) {
148 container->children[FIRST_BUTTON_INDEX]->alignmentMarginX = BORDER_MARGIN;
149 container->children[FIRST_BUTTON_INDEX]->alignmentMarginY = 0;
150 container->children[FIRST_BUTTON_INDEX]->alignment = TOP_LEFT;
151 container->children[FIRST_BUTTON_INDEX]->alignTo = (nbgl_obj_t *) container;
152 }
153
154 // align top-right button on top-left one
155 if (container->children[SECOND_BUTTON_INDEX] != NULL) {
156 container->children[SECOND_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
157 container->children[SECOND_BUTTON_INDEX]->alignmentMarginY = 0;
158 container->children[SECOND_BUTTON_INDEX]->alignment = MID_RIGHT;
159 container->children[SECOND_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
160 }
161#ifndef USE_PARTIAL_BUTTONS
162 // align bottom-left button on top_left one
163 if (container->children[THIRD_BUTTON_INDEX] != NULL) {
164 container->children[THIRD_BUTTON_INDEX]->alignmentMarginX = 0;
165 container->children[THIRD_BUTTON_INDEX]->alignmentMarginY = INTERNAL_MARGIN;
166 container->children[THIRD_BUTTON_INDEX]->alignment = BOTTOM_MIDDLE;
167 container->children[THIRD_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
168 }
169
170 // align bottom-right button on bottom-left one
171 if (container->children[FOURTH_BUTTON_INDEX] != NULL) {
172 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
173 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginY = 0;
174 container->children[FOURTH_BUTTON_INDEX]->alignment = MID_RIGHT;
175 container->children[FOURTH_BUTTON_INDEX]->alignTo = container->children[THIRD_BUTTON_INDEX];
176 }
177#endif // !USE_PARTIAL_BUTTONS
178
179 // the first child is used by the progress indicator, displayed if more that
180 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
181 nbgl_page_indicator_t *indicator
182 = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
183 indicator->activePage = page;
184
185#ifdef USE_PARTIAL_BUTTONS
186 // if not on the first button, display end of previous button
187 if (currentLeftButtonIndex > 0) {
188 container->children[LEFT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[0];
189 }
190 else {
191 container->children[LEFT_HALF_INDEX] = NULL;
192 }
193 // if not on the last button, display beginning of next button
194 if (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
195 container->children[RIGHT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[1];
196 }
197 else {
198 container->children[RIGHT_HALF_INDEX] = NULL;
199 }
200#endif // USE_PARTIAL_BUTTONS
201 return needRefresh;
202}
203
204/**********************
205 * GLOBAL INTERNAL FUNCTIONS
206 **********************/
207
209{
210 nbgl_container_t *container = (nbgl_container_t *) obj;
211 nbgl_container_t *suggestionsContainer;
212
213 if ((container->nbChildren < 2) || (container->children[1]->type != CONTAINER)) {
214 return false;
215 }
216 suggestionsContainer = (nbgl_container_t *) container->children[1];
217 // try if suggestions buttons (more than NB_MAX_VISIBLE_SUGGESTION_BUTTONS)
218 if (((eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT))
219 && (suggestionsContainer->nbChildren == (nbActiveButtons + FIRST_BUTTON_INDEX))
220 && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
221 uint32_t i = 0;
222 while (i < (uint32_t) nbActiveButtons) {
223 if (suggestionsContainer->children[FIRST_BUTTON_INDEX]
224 == (nbgl_obj_t *) choiceButtons[i]) {
225 break;
226 }
227 i++;
228 }
229
230 if (i < (uint32_t) nbActiveButtons) {
231 if (updateSuggestionButtons(suggestionsContainer, eventType, i)) {
232 os_io_seph_cmd_piezo_play_tune(TUNE_TAP_CASUAL);
233 nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
235 }
236
237 return true;
238 }
239 }
240 return false;
241}
242
243static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt,
244 const char *title,
245 const char *text,
246 bool numbered,
247 uint8_t number,
248 bool grayedOut,
249 int textToken,
250 bool compactMode)
251{
252 nbgl_container_t *container;
253 nbgl_text_area_t *textArea;
254 layoutObj_t *obj;
255 uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
256
257 // create a container, to store title, entered text and underline
258 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
259 container->nbChildren = 4;
260 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
261 container->obj.area.width = AVAILABLE_WIDTH;
262 container->obj.alignment = CENTER;
263
264 if (title != NULL) {
265 // create text area for title
266 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
267 textArea->textColor = BLACK;
268 textArea->text = title;
269 textArea->textAlignment = CENTER;
270 textArea->fontId = SMALL_REGULAR_FONT;
271 textArea->wrapping = true;
272 textArea->obj.alignment = TOP_MIDDLE;
273 textArea->obj.area.width = AVAILABLE_WIDTH;
274 textArea->obj.area.height = nbgl_getTextHeightInWidth(
275 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
276 container->children[0] = (nbgl_obj_t *) textArea;
277 container->obj.area.height = textArea->obj.area.height + 4;
278 }
279
280 if (numbered) {
281 // create Word num typed text
282 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
283 textArea->textColor = BLACK;
284 snprintf(numText, sizeof(numText), "%d.", number);
285 textArea->text = numText;
286 textArea->textAlignment = CENTER;
287 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
288 textArea->obj.area.width = NUMBER_WIDTH;
289 if (title != NULL) {
290 textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT;
291 textArea->obj.alignTo = container->children[0];
292 textArea->obj.alignment = BOTTOM_LEFT;
293 }
294 else {
295 textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT;
296 textArea->obj.alignment = TOP_LEFT;
297 }
298 textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT;
299 // set this text area as child of the container
300 container->children[1] = (nbgl_obj_t *) textArea;
301 }
302
303 // create text area for entered text
304 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
305 textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK;
306 textArea->text = text;
307 textArea->textAlignment = MID_LEFT;
308 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
309 if (title != NULL) {
310 textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT;
311 textArea->obj.alignTo = container->children[0];
312 textArea->obj.alignment = BOTTOM_LEFT;
313 }
314 else {
315 textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT;
316 textArea->obj.alignment = TOP_LEFT;
317 }
318 textArea->obj.area.width = AVAILABLE_WIDTH;
319 if (numbered) {
320 textArea->obj.alignmentMarginX = NUMBER_WIDTH + NUMBER_TEXT_SPACE;
321 textArea->obj.area.width -= textArea->obj.alignmentMarginX;
322 }
323 textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT;
324 textArea->autoHideLongLine = true;
325
326 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) textArea, textToken, NBGL_NO_TUNE);
327 if (obj == NULL) {
328 return NULL;
329 }
330 textArea->obj.touchMask = (1 << TOUCHED);
331 textArea->obj.touchId = ENTERED_TEXT_ID;
332 container->children[2] = (nbgl_obj_t *) textArea;
333 container->obj.area.height += textEntryHeight;
334
335 // create gray line
336 nbgl_line_t *line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
337 line->lineColor = LIGHT_GRAY;
338 // align on bottom of the container
339 line->obj.alignment = BOTTOM_MIDDLE;
340 line->obj.area.width = AVAILABLE_WIDTH;
341 line->obj.area.height = LINE_REAL_HEIGHT;
342 line->direction = HORIZONTAL;
343 line->thickness = 2;
344 line->offset = 2;
345 // set this line as child of the container
346 container->children[3] = (nbgl_obj_t *) line;
347
348 return container;
349}
350
351static nbgl_container_t *addSuggestionButtons(nbgl_layoutInternal_t *layoutInt,
352 uint8_t nbUsedButtons,
353 const char **buttonTexts,
354 int firstButtonToken,
355 tune_index_e tuneId,
356 bool compactMode)
357{
358 nbgl_container_t *suggestionsContainer;
359 layoutObj_t *obj;
360
361 nbActiveButtons = nbUsedButtons;
362 suggestionsContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
363 suggestionsContainer->layout = VERTICAL;
364 suggestionsContainer->obj.area.width = SCREEN_WIDTH;
365#ifndef USE_PARTIAL_BUTTONS
366 // 2 rows of buttons with radius=32, and a intervale of 8px
367 suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT + INTERNAL_MARGIN + 28;
368#else // USE_PARTIAL_BUTTONS
369 // 1 row of buttons + 24px + page indicator
370 suggestionsContainer->obj.area.height = SMALL_BUTTON_HEIGHT + 28;
371#endif // USE_PARTIAL_BUTTONS
372 suggestionsContainer->nbChildren = nbActiveButtons + FIRST_BUTTON_INDEX;
373 suggestionsContainer->children
375
376 // put suggestionsContainer at 24px of the bottom of main container
377 suggestionsContainer->obj.alignmentMarginY
378 = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
379 suggestionsContainer->obj.alignment = BOTTOM_MIDDLE;
380
381 // create all possible suggestion buttons, even if not displayed at first
383 BUTTON, NB_MAX_SUGGESTION_BUTTONS, layoutInt->layer, (nbgl_obj_t **) &choiceButtons);
384 for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
386 layoutInt, (nbgl_obj_t *) choiceButtons[i], firstButtonToken + i, tuneId);
387 if (obj == NULL) {
388 return NULL;
389 }
390
391 choiceButtons[i]->innerColor = BLACK;
392 choiceButtons[i]->borderColor = BLACK;
393 choiceButtons[i]->foregroundColor = WHITE;
394 choiceButtons[i]->obj.area.width = (AVAILABLE_WIDTH - INTERNAL_MARGIN) / 2;
395 choiceButtons[i]->obj.area.height = SMALL_BUTTON_HEIGHT;
396 choiceButtons[i]->radius = SMALL_BUTTON_RADIUS_INDEX;
397 choiceButtons[i]->fontId = SMALL_BOLD_1BPP_FONT;
398 choiceButtons[i]->text = buttonTexts[i];
399 choiceButtons[i]->obj.touchMask = (1 << TOUCHED);
400 choiceButtons[i]->obj.touchId = CONTROLS_ID + i;
401 // some buttons may not be visible
402 if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
403 suggestionsContainer->children[i + FIRST_BUTTON_INDEX]
404 = (nbgl_obj_t *) choiceButtons[i];
405 }
406 }
407 // The first child is used by the progress indicator, if more that
408 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
409 nbgl_page_indicator_t *indicator
411 indicator->activePage = 0;
412 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
413 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
414 indicator->obj.area.width = 184;
415 indicator->obj.alignment = BOTTOM_MIDDLE;
416 indicator->style = CURRENT_INDICATOR;
417 suggestionsContainer->children[PAGE_INDICATOR_INDEX] = (nbgl_obj_t *) indicator;
418#ifdef USE_PARTIAL_BUTTONS
419 // also allocate the semi disc that may be displayed on the left or right of the full
420 // buttons
421 nbgl_objPoolGetArray(IMAGE, 2, layoutInt->layer, (nbgl_obj_t **) &partialButtonImages);
422 partialButtonImages[0]->buffer = &LEFT_HALF_ICON;
423 partialButtonImages[0]->obj.alignment = TOP_LEFT;
424 partialButtonImages[0]->foregroundColor = BLACK;
425 partialButtonImages[0]->transformation = VERTICAL_MIRROR;
426 partialButtonImages[1]->buffer = &LEFT_HALF_ICON;
427 partialButtonImages[1]->obj.alignment = TOP_RIGHT;
428 partialButtonImages[1]->foregroundColor = BLACK;
429 partialButtonImages[1]->transformation = NO_TRANSFORMATION;
430 updateSuggestionButtons(suggestionsContainer, 0, 0);
431#endif // USE_PARTIAL_BUTTONS
432
433 return suggestionsContainer;
434}
435
436static nbgl_button_t *addConfirmationButton(nbgl_layoutInternal_t *layoutInt,
437 bool active,
438 const char *text,
439 int token,
440 tune_index_e tuneId,
441 bool compactMode)
442{
443 nbgl_button_t *button;
444 layoutObj_t *obj;
445
446 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
447 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
448 if (obj == NULL) {
449 return NULL;
450 }
451
452 // put button at 24px/12px of the keyboard
453 button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN;
454 button->obj.alignment = BOTTOM_MIDDLE;
455 button->foregroundColor = WHITE;
456 if (active) {
457 button->innerColor = BLACK;
458 button->borderColor = BLACK;
459 button->obj.touchMask = (1 << TOUCHED);
460 button->obj.touchId = BOTTOM_BUTTON_ID;
461 }
462 else {
463 button->borderColor = LIGHT_GRAY;
464 button->innerColor = LIGHT_GRAY;
465 }
466 button->text = PIC(text);
467 button->fontId = SMALL_BOLD_1BPP_FONT;
468 button->obj.area.width = AVAILABLE_WIDTH;
469 button->obj.area.height = BUTTON_DIAMETER;
470 button->radius = BUTTON_RADIUS;
471
472 return button;
473}
474
475/**********************
476 * GLOBAL API FUNCTIONS
477 **********************/
478
487{
488 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
489 nbgl_keyboard_t *keyboard;
490
491 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboard():\n");
492 if (layout == NULL) {
493 return -1;
494 }
495 // footer must be empty
496 if (layoutInt->footerContainer != NULL) {
497 return -1;
498 }
499
500 // create keyboard
501 keyboard = (nbgl_keyboard_t *) nbgl_objPoolGet(KEYBOARD, layoutInt->layer);
502 keyboard->obj.area.width = SCREEN_WIDTH;
503 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
504 if (!kbdInfo->lettersOnly) {
505 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
506 }
507#ifdef TARGET_STAX
508 keyboard->obj.alignmentMarginY = 56;
509#endif // TARGET_STAX
510 keyboard->obj.alignment = BOTTOM_MIDDLE;
511 keyboard->borderColor = LIGHT_GRAY;
512 keyboard->callback = PIC(kbdInfo->callback);
513 keyboard->lettersOnly = kbdInfo->lettersOnly;
514 keyboard->mode = kbdInfo->mode;
515 keyboard->keyMask = kbdInfo->keyMask;
516 keyboard->casing = kbdInfo->casing;
517
518 // the keyboard occupies the footer
519 layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
520 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
521 layoutInt->footerContainer->layout = VERTICAL;
522 layoutInt->footerContainer->children
523 = (nbgl_obj_t **) nbgl_containerPoolGet(1, layoutInt->layer);
524 layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
525 layoutInt->footerContainer->obj.area.height
526 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
527 layoutInt->footerContainer->children[0] = (nbgl_obj_t *) keyboard;
528 layoutInt->footerContainer->nbChildren = 1;
529
530 // add footer to layout children
531 layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
532
533 // subtract footer height from main container height
534 layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
535
536 // create the 2 children for main container (to hold keyboard content)
537 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
538 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
539
540 layoutInt->footerType = KEYBOARD_FOOTER_TYPE;
541
542 return layoutInt->footerContainer->obj.area.height;
543}
544
556 uint8_t index,
557 uint32_t keyMask,
558 bool updateCasing,
559 keyboardCase_t casing)
560{
561 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
562 nbgl_keyboard_t *keyboard;
563
564 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboard(): keyMask = 0x%X\n", keyMask);
565 if (layout == NULL) {
566 return -1;
567 }
568 UNUSED(index);
569
570 // get existing keyboard (in the footer container)
571 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
572 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
573 return -1;
574 }
575 keyboard->keyMask = keyMask;
576 if (updateCasing) {
577 keyboard->casing = casing;
578 }
579
580 nbgl_objDraw((nbgl_obj_t *) keyboard);
581
582 return 0;
583}
584
593{
594 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
595 nbgl_keyboard_t *keyboard;
596
597 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutKeyboardNeedsRefresh(): \n");
598 if (layout == NULL) {
599 return -1;
600 }
601 UNUSED(index);
602
603 // get existing keyboard (in the footer container)
604 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
605 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
606 return -1;
607 }
608 if (keyboard->needsRefresh) {
609 keyboard->needsRefresh = false;
610 return true;
611 }
612
613 return false;
614}
615
629 uint8_t nbUsedButtons,
630 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS],
631 int firstButtonToken,
632 tune_index_e tuneId)
633{
634 nbgl_container_t *container;
635 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
636 // if a centered info has be used for title, entered text is the second child
637 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
638
639 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSuggestionButtons():\n");
640 if (layout == NULL) {
641 return -1;
642 }
643
644 container = addSuggestionButtons(
645 layoutInt, nbUsedButtons, buttonTexts, firstButtonToken, tuneId, false);
646 // set this container as 2nd or 3rd child of the main layout container
647 layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) container;
648 if (layoutInt->container->children[enteredTextIndex] != NULL) {
649 ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
650 ->obj.alignmentMarginY
651 -= (container->obj.area.height + container->obj.alignmentMarginY + 20) / 2;
652 }
653#ifdef USE_PARTIAL_BUTTONS
654 // the main container is swipable on Flex
655 if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
656 == NULL) {
657 return -1;
658 }
659 layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
660 layoutInt->container->obj.touchId = CONTROLS_ID;
662#endif // USE_PARTIAL_BUTTONS
663 // set this new container as child of the main container
664 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
665
666 // return index of container to be modified later on
667 return (layoutInt->container->nbChildren - 1);
668}
669
682 uint8_t index,
683 uint8_t nbUsedButtons,
684 const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS])
685{
686 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
687 nbgl_container_t *container;
688 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
689
690 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateSuggestionButtons():\n");
691 if (layout == NULL) {
692 return -1;
693 }
694 UNUSED(index);
695
696 container = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
697 if ((container == NULL) || (container->obj.type != CONTAINER)) {
698 return -1;
699 }
700 nbActiveButtons = nbUsedButtons;
701 container->nbChildren = nbUsedButtons + FIRST_BUTTON_INDEX;
702
703 // update suggestion buttons
704 for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
705 choiceButtons[i]->text = buttonTexts[i];
706 // some buttons may not be visible
707 if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbUsedButtons)) {
708 if ((i % 2) == 0) {
709 choiceButtons[i]->obj.alignmentMarginX = BORDER_MARGIN;
710#ifndef USE_PARTIAL_BUTTONS
711 // second row 8px under the first one
712 if (i != 0) {
713 choiceButtons[i]->obj.alignmentMarginY = INTERNAL_MARGIN;
714 }
715 choiceButtons[i]->obj.alignment = NO_ALIGNMENT;
716#else // USE_PARTIAL_BUTTONS
717 if (i == 0) {
718 choiceButtons[i]->obj.alignment = TOP_LEFT;
719 }
720#endif // USE_PARTIAL_BUTTONS
721 }
722 else {
723 choiceButtons[i]->obj.alignmentMarginX = INTERNAL_MARGIN;
724 choiceButtons[i]->obj.alignment = MID_RIGHT;
725 choiceButtons[i]->obj.alignTo = (nbgl_obj_t *) choiceButtons[i - 1];
726 }
727 container->children[i + FIRST_BUTTON_INDEX] = (nbgl_obj_t *) choiceButtons[i];
728 }
729 else {
730 container->children[i + FIRST_BUTTON_INDEX] = NULL;
731 }
732 }
733 container->forceClean = true;
734#ifdef USE_PARTIAL_BUTTONS
735 // on Flex, the first child is used by the progress indicator, if more that 2 buttons
736 nbgl_page_indicator_t *indicator
737 = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
738 indicator->nbPages = (nbUsedButtons + 1) / 2;
739 indicator->activePage = 0;
740 updateSuggestionButtons(container, 0, 0);
741#endif // USE_PARTIAL_BUTTONS
742
743 nbgl_objDraw((nbgl_obj_t *) container);
744
745 return 0;
746}
747
766 bool numbered,
767 uint8_t number,
768 const char *text,
769 bool grayedOut,
770 int offsetY,
771 int token)
772{
773 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
774 nbgl_container_t *container;
775 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
776 bool compactMode = ((layoutInt->container->children[enteredTextIndex + 1] != NULL)
777 && (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON)
778 && (layoutInt->container->nbChildren == 3));
779
780 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddEnteredText():\n");
781 if (layout == NULL) {
782 return -1;
783 }
784 UNUSED(offsetY);
785
786 container
787 = addTextEntry(layoutInt, NULL, text, numbered, number, grayedOut, token, compactMode);
788
789 // set this container as first or 2nd child of the main layout container
790 layoutInt->container->children[enteredTextIndex] = (nbgl_obj_t *) container;
791
792 if (layoutInt->container->children[enteredTextIndex + 1] != NULL) {
793 if (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON) {
794 nbgl_button_t *button
795 = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
796 container->obj.alignmentMarginY
797 -= (button->obj.area.height + button->obj.alignmentMarginY
798 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
799 / 2;
800 }
801 else if (layoutInt->container->children[enteredTextIndex + 1]->type == CONTAINER) {
802 nbgl_container_t *suggestionContainer
803 = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
804 container->obj.alignmentMarginY
805 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
806 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
807 / 2;
808 }
809 }
810 // if a centered info has be used for title, entered text is the second child and we have to
811 // adjust layout
812 if (layoutInt->container->nbChildren == 3) {
813 container->obj.alignmentMarginY += layoutInt->container->children[0]->area.height / 2;
814 }
815
816 // return 0
817 return 0;
818}
819
834 uint8_t index,
835 bool numbered,
836 uint8_t number,
837 const char *text,
838 bool grayedOut)
839{
840 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
841 nbgl_container_t *container;
842 nbgl_text_area_t *textArea;
843 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
844
845 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText():\n");
846 if (layout == NULL) {
847 return -1;
848 }
849 UNUSED(index);
850
851 // update text entry area
852 container = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex];
853 if ((container == NULL) || (container->obj.type != CONTAINER)) {
854 return -1;
855 }
856 textArea = (nbgl_text_area_t *) container->children[2];
857 if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
858 return -1;
859 }
860 textArea->text = text;
861 textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK;
862 textArea->textAlignment = MID_LEFT;
863 nbgl_objDraw((nbgl_obj_t *) textArea);
864
865 // update number text area
866 if (numbered) {
867 // it is the previously created object
868 textArea = (nbgl_text_area_t *) layoutInt->container->children[1];
869 snprintf(numText, sizeof(numText), "%d.", number);
870 textArea->text = numText;
871 nbgl_objDraw((nbgl_obj_t *) textArea);
872 }
873 // if the text doesn't fit, indicate it by returning 1 instead of 0, for different refresh
874 if (nbgl_getSingleLineTextWidth(textArea->fontId, text) > textArea->obj.area.width) {
875 return 1;
876 }
877 return 0;
878}
879
892 bool active,
893 const char *text,
894 int token,
895 tune_index_e tuneId)
896{
897 nbgl_button_t *button;
898 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
899 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
900 bool compactMode = (layoutInt->container->nbChildren == 3);
901
902 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddConfirmationButton():\n");
903 if (layout == NULL) {
904 return -1;
905 }
906
907 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
908 // set this button as second child of the main layout container
909 layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) button;
910 if (layoutInt->container->children[enteredTextIndex] != NULL) {
911 ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
912 ->obj.alignmentMarginY
913 -= (button->obj.area.height + button->obj.alignmentMarginY
914 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
915 / 2;
916 }
917 // return 0
918 return 0;
919}
920
933 uint8_t index,
934 bool active,
935 const char *text)
936{
937 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
938 nbgl_button_t *button;
939 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
940
941 UNUSED(index);
942
943 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateConfirmationButton():\n");
944 if (layout == NULL) {
945 return -1;
946 }
947
948 // update main text area
949 button = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
950 if ((button == NULL) || (button->obj.type != BUTTON)) {
951 return -1;
952 }
953 button->text = text;
954
955 if (active) {
956 button->innerColor = BLACK;
957 button->borderColor = BLACK;
958 button->obj.touchMask = (1 << TOUCHED);
959 button->obj.touchId = BOTTOM_BUTTON_ID;
960 }
961 else {
962 button->borderColor = LIGHT_GRAY;
963 button->innerColor = LIGHT_GRAY;
964 }
965 nbgl_objDraw((nbgl_obj_t *) button);
966 return 0;
967}
968
978{
979 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
980 nbgl_container_t *container;
981 bool compactMode = ((content->type == KEYBOARD_WITH_BUTTON) && (content->title != NULL));
982
983 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboardContent():\n");
984 if (layout == NULL) {
985 return -1;
986 }
987
988 container = addTextEntry(layoutInt,
989 content->title,
990 content->text,
991 content->numbered,
992 content->number,
993 content->grayedOut,
994 content->textToken,
995 compactMode);
996
997 // set this container as first child of the main layout container
998 layoutInt->container->children[0] = (nbgl_obj_t *) container;
999
1000 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
1001 nbgl_container_t *suggestionsContainer
1002 = addSuggestionButtons(layoutInt,
1004 content->suggestionButtons.buttons,
1006 content->tuneId,
1007 compactMode);
1008 // set this container as second child of the main layout container
1009 layoutInt->container->children[1] = (nbgl_obj_t *) suggestionsContainer;
1010 // the main container is swipable on Flex
1011 if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
1012 == NULL) {
1013 return -1;
1014 }
1015 layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
1016 layoutInt->container->obj.touchId = CONTROLS_ID;
1018 container->obj.alignmentMarginY
1019 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1020 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1021 / 2;
1022 }
1023 else if (content->type == KEYBOARD_WITH_BUTTON) {
1024 nbgl_button_t *button = addConfirmationButton(layoutInt,
1025 content->confirmationButton.active,
1026 content->confirmationButton.text,
1027 content->confirmationButton.token,
1028 content->tuneId,
1029 compactMode);
1030 // set this button as second child of the main layout container
1031 layoutInt->container->children[1] = (nbgl_obj_t *) button;
1032 container->obj.alignmentMarginY
1033 -= (button->obj.area.height + button->obj.alignmentMarginY
1034 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
1035 / 2;
1036 }
1037
1038 return layoutInt->container->obj.area.height;
1039}
1040
1052{
1053 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1054 nbgl_container_t *container;
1055 nbgl_text_area_t *textArea;
1056
1057 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent():\n");
1058 if (layout == NULL) {
1059 return -1;
1060 }
1061
1062 // get top container from main container (it shall be the 1st object)
1063 container = (nbgl_container_t *) layoutInt->container->children[0];
1064
1065 if (content->numbered) {
1066 // get Word number typed text
1067 textArea = (nbgl_text_area_t *) container->children[1];
1068 snprintf(numText, sizeof(numText), "%d.", content->number);
1069 nbgl_objDraw((nbgl_obj_t *) textArea);
1070 }
1071
1072 // get text area for entered text
1073 textArea = (nbgl_text_area_t *) container->children[2];
1074 textArea->textColor = content->grayedOut ? LIGHT_GRAY : BLACK;
1075 textArea->text = content->text;
1076 nbgl_objDraw((nbgl_obj_t *) textArea);
1077
1078 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
1079 nbActiveButtons = content->suggestionButtons.nbUsedButtons;
1080 nbgl_container_t *suggestionsContainer
1081 = (nbgl_container_t *) layoutInt->container->children[1];
1082 suggestionsContainer->nbChildren = nbActiveButtons + FIRST_BUTTON_INDEX;
1083
1084 // update suggestion buttons
1085 for (int i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1086 choiceButtons[i]->text = content->suggestionButtons.buttons[i];
1087 // some buttons may not be visible
1088 if (i < MIN(NB_MAX_VISIBLE_SUGGESTION_BUTTONS, nbActiveButtons)) {
1089 suggestionsContainer->children[i + FIRST_BUTTON_INDEX]
1090 = (nbgl_obj_t *) choiceButtons[i];
1091 }
1092 else {
1093 suggestionsContainer->children[i + FIRST_BUTTON_INDEX] = NULL;
1094 }
1095 }
1096 suggestionsContainer->forceClean = true;
1097 // the first child is used by the progress indicator, if more than
1098 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
1099 nbgl_page_indicator_t *indicator
1100 = (nbgl_page_indicator_t *) suggestionsContainer->children[PAGE_INDICATOR_INDEX];
1101 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1102 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1103 indicator->activePage = 0;
1104 updateSuggestionButtons(suggestionsContainer, 0, 0);
1105
1106 nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
1107 }
1108 else if (content->type == KEYBOARD_WITH_BUTTON) {
1109 // update main text area
1110 nbgl_button_t *button = (nbgl_button_t *) layoutInt->container->children[1];
1111 if ((button == NULL) || (button->obj.type != BUTTON)) {
1112 return -1;
1113 }
1114 button->text = content->confirmationButton.text;
1115
1116 if (content->confirmationButton.active) {
1117 button->innerColor = BLACK;
1118 button->borderColor = BLACK;
1119 button->obj.touchMask = (1 << TOUCHED);
1120 button->obj.touchId = BOTTOM_BUTTON_ID;
1121 }
1122 else {
1123 button->borderColor = LIGHT_GRAY;
1124 button->innerColor = LIGHT_GRAY;
1125 }
1126 nbgl_objDraw((nbgl_obj_t *) button);
1127 }
1128
1129 // if the entered text doesn't fit, indicate it by returning 1 instead of 0, for different
1130 // refresh
1131 if (nbgl_getSingleLineTextWidth(textArea->fontId, content->text) > textArea->obj.area.width) {
1132 return 1;
1133 }
1134 return 0;
1135}
1136
1137#endif // NBGL_KEYBOARD
1138#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:324
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.
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
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
#define AVAILABLE_WIDTH
Definition nbgl_layout.h:93
void * nbgl_layout_t
type shared externally
#define NBGL_NO_TUNE
Definition nbgl_layout.h:28
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
Internal functions/constants of NBGL layout layer.
@ SWIPE_USAGE_SUGGESTIONS
@ FOOTER_INDEX
#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.
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 LINE_REAL_HEIGHT
@ SECOND_BUTTON_INDEX
@ NB_SUGGESTION_CHILDREN
@ PAGE_INDICATOR_INDEX
@ FIRST_BUTTON_INDEX
@ THIRD_BUTTON_INDEX
@ FOURTH_BUTTON_INDEX
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 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:1621
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:514
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.
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:1670
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)....
struct PACKED__ nbgl_button_s nbgl_button_t
struct to represent a button (BUTTON type) that can contain a text and/or an icon
@ CONTROLS_ID
Definition nbgl_obj.h:589
@ ENTERED_TEXT_ID
Definition nbgl_obj.h:583
@ BOTTOM_BUTTON_ID
Definition nbgl_obj.h:570
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:389
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
@ WHITE
Definition nbgl_types.h:126
@ LIGHT_GRAY
Definition nbgl_types.h:125
@ BLACK
Definition nbgl_types.h:123
#define VERTICAL_MIRROR
Definition nbgl_types.h:82
nbgl_touchType_t
The different types of Touchscreen events.
Definition nbgl_types.h:241
@ SWIPED_LEFT
Definition nbgl_types.h:257
@ SWIPED_RIGHT
Definition nbgl_types.h:256
@ TOUCHED
Definition nbgl_types.h:242
@ VERTICAL
from top to bottom
Definition nbgl_types.h:191
@ HORIZONTAL
from left to right
Definition nbgl_types.h:192
#define MIN(x, y)
Definition nbgl_types.h:100
@ TOP_MIDDLE
Definition nbgl_types.h:164
@ CENTER
Definition nbgl_types.h:167
@ TOP_LEFT
Definition nbgl_types.h:163
@ NO_ALIGNMENT
used when parent container layout is used
Definition nbgl_types.h:162
@ BOTTOM_LEFT
Definition nbgl_types.h:169
@ MID_RIGHT
Definition nbgl_types.h:168
@ TOP_RIGHT
Definition nbgl_types.h:165
@ MID_LEFT
Definition nbgl_types.h:166
@ BOTTOM_MIDDLE
Definition nbgl_types.h:170
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:139
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition nbgl_types.h:142
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition nbgl_types.h:144
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:140
@ KEYBOARD
Keyboard.
Definition nbgl_types.h:148
@ CONTAINER
Empty container.
Definition nbgl_types.h:138
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:141
#define NO_TRANSFORMATION
Definition nbgl_types.h:76
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition nbgl_types.h:310
int token
token of the button
const char * text
text of the button
bool active
if true, button is active, otherwise inactive (grayed-out)
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()
bool lettersOnly
if true, only display letter keys and Backspace
keyboardCallback_t callback
function called when an active key is pressed
keyboardMode_t mode
keyboard mode to start with
keyboardCase_t casing
keyboard casing mode (lower, upper once or upper locked)
This structure contains info to build a keyboard content (controls that are linked to keyboard)
uint8_t number
if numbered is true, number used to build 'number.' text
const char * text
already entered text
nbgl_layoutKeyboardContentType_t type
type of content
nbgl_layoutSuggestionButtons_t suggestionButtons
nbgl_layoutConfirmationButton_t confirmationButton
used if type is KEYBOARD_WITH_SUGGESTIONS
const char * title
centered title explaining the screen
bool numbered
if set to true, the text is preceded on the left by 'number.'
bool grayedOut
if true, the text is grayed out (but not the potential number)
uint8_t nbUsedButtons
the number of actually used buttons
const char ** buttons
array of 4 strings for buttons (last ones can be NULL)