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 <stdio.h>
15#include "nbgl_debug.h"
16#include "nbgl_front.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_io_seph_cmd.h"
24#include "os_io_seph_ux.h"
25#include "os_pic.h"
26#include "os_helpers.h"
27
28/*********************
29 * DEFINES
30 *********************/
31#if defined(TARGET_FLEX) || defined(TARGET_APEX)
32#define USE_PARTIAL_BUTTONS 1
33#endif // TARGET_FLEX
34
35// for suggestion buttons, on Flex there are other objects than buttons
36enum {
38#ifdef USE_PARTIAL_BUTTONS
39 LEFT_HALF_INDEX, // half disc displayed on the bottom left
40 RIGHT_HALF_INDEX, // half disc displayed on the bottom right
41#endif // USE_PARTIAL_BUTTONS
44#ifndef USE_PARTIAL_BUTTONS
47#endif // !USE_PARTIAL_BUTTONS
49};
50
51// Keyboard Text Entry container children
52enum {
57};
58
59#if defined(TARGET_STAX)
60#define TEXT_ENTRY_NORMAL_HEIGHT 64
61#define TEXT_ENTRY_COMPACT_HEIGHT 64
62#define BOTTOM_NORMAL_MARGIN 24
63#define BOTTOM_CONFIRM_MARGIN 24
64#define BOTTOM_COMPACT_MARGIN 24
65#define TOP_NORMAL_MARGIN 20
66#define TOP_CONFIRM_MARGIN 20
67#define TOP_COMPACT_MARGIN 20
68#define TITLE_ENTRY_MARGIN_Y 4
69#define TEXT_ENTRY_FONT LARGE_MEDIUM_1BPP_FONT
70#define TEXT_ENTRY_FONT_OBFUSCATED LARGE_OBFUSCATED_MEDIUM_1BPP_FONT
71// #define TEXT_ENTRY_FONT_OBFUSCATED LARGE_MEDIUM_
72// space between number and text
73#define NUMBER_TEXT_SPACE 8
74#define NUMBER_WIDTH 56
75#define DELETE_ICON C_Close_32px
76#elif defined(TARGET_FLEX)
77#define TEXT_ENTRY_NORMAL_HEIGHT 72
78#define TEXT_ENTRY_COMPACT_HEIGHT 56
79#define BOTTOM_NORMAL_MARGIN 24
80#define BOTTOM_CONFIRM_MARGIN 24
81#define BOTTOM_COMPACT_MARGIN 12
82#define TOP_NORMAL_MARGIN 20
83#define TOP_CONFIRM_MARGIN 20
84#define TOP_COMPACT_MARGIN 12
85#define TITLE_ENTRY_MARGIN_Y 4
86#define TEXT_ENTRY_FONT LARGE_MEDIUM_1BPP_FONT
87#define TEXT_ENTRY_FONT_OBFUSCATED LARGE_OBFUSCATED_MEDIUM_1BPP_FONT
88// space between number and text
89#define NUMBER_TEXT_SPACE 8
90#define NUMBER_WIDTH 56
91#define DELETE_ICON C_Close_40px
92#elif defined(TARGET_APEX)
93#define TEXT_ENTRY_NORMAL_HEIGHT 44
94#define TEXT_ENTRY_COMPACT_HEIGHT 44
95#define BOTTOM_NORMAL_MARGIN 20
96#define BOTTOM_CONFIRM_MARGIN 16
97#define BOTTOM_COMPACT_MARGIN 8
98#define TOP_NORMAL_MARGIN 20
99#define TOP_CONFIRM_MARGIN 12
100#define TOP_COMPACT_MARGIN 8
101#define TITLE_ENTRY_MARGIN_Y 4
102#define TEXT_ENTRY_FONT LARGE_MEDIUM_1BPP_FONT
103#define TEXT_ENTRY_FONT_OBFUSCATED LARGE_OBFUSCATED_MEDIUM_1BPP_FONT
104// space between number and text
105#define NUMBER_TEXT_SPACE 4
106#define NUMBER_WIDTH 40
107#define DELETE_ICON C_Close_Tiny_24px
108#endif // TARGETS
109
110#ifdef USE_PARTIAL_BUTTONS
111#if defined(TARGET_FLEX)
112#define LEFT_HALF_ICON C_left_half_64px
113#define SUGGESTION_CONTAINER_HEIGHT 92
114#elif defined(TARGET_APEX)
115#define LEFT_HALF_ICON C_half_disc_left_40px_1bpp
116#define SUGGESTION_CONTAINER_HEIGHT 56
117#endif // TARGETS
118#endif // USE_PARTIAL_BUTTONS
119
120// space on left and right of suggestion buttons
121#define SUGGESTION_BUTTONS_SIDE_MARGIN BORDER_MARGIN
122#if defined(TARGET_APEX)
123#define LINE_THICKNESS 1
124#define LINE_COLOR BLACK
125#else
126#define LINE_THICKNESS 2
127#define LINE_COLOR LIGHT_GRAY
128#endif // TARGETS
129
130/**********************
131 * MACROS
132 **********************/
133
134/**********************
135 * TYPEDEFS
136 **********************/
137
138/**********************
139 * VARIABLES
140 **********************/
141
142static const char *choiceTexts[NB_MAX_SUGGESTION_BUTTONS];
143static char numText[5];
144static uint8_t nbActiveButtons;
146#ifdef USE_PARTIAL_BUTTONS
147static nbgl_image_t *partialButtonImages[2];
148#endif // USE_PARTIAL_BUTTONS
149
150/**********************
151 * STATIC PROTOTYPES
152 **********************/
153
154// function used on Flex to display (or not) beginning of next button and/or end of
155// previous button, and update buttons when swipping
157 nbgl_container_t *container,
158 nbgl_touchType_t eventType,
159 uint8_t currentLeftButtonIndex)
160{
161 bool needRefresh = false;
162 uint8_t page = 0;
163 uint32_t i = 0;
164 nbgl_button_t *button = NULL;
165
166 if ((eventType == SWIPED_LEFT) && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)
167 && (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
168 // shift all buttons on the left if there are still at least
169 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons to display
170 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
171
172 // Button to be updated
173 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX];
174
175 // Update button text and touch token
176 button->text = choiceTexts[currentLeftButtonIndex];
178 layoutInt, (nbgl_obj_t *) button, currentFirstButtonToken + currentLeftButtonIndex);
179
180 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
181 // Button to be updated
182 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX + i];
183
184 if ((uint32_t) currentLeftButtonIndex + i < (uint32_t) nbActiveButtons) {
185 button->text = choiceTexts[currentLeftButtonIndex + i];
187 (nbgl_obj_t *) button,
188 currentFirstButtonToken + currentLeftButtonIndex + i);
189 }
190 else {
191 button->text = NULL;
193 }
194 }
195 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
196 needRefresh = true;
197 }
198 else if ((eventType == SWIPED_RIGHT)
199 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
200 // shift all buttons on the left if we are not already displaying the
201 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS first ones
202 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
203 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
204 // Button to be updated
205 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX + i];
206
207 // Update button text and touch token
208 button->text = choiceTexts[currentLeftButtonIndex + i];
210 (nbgl_obj_t *) button,
211 currentFirstButtonToken + currentLeftButtonIndex + i);
212 }
213 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
214 needRefresh = true;
215 }
216 // align top-left button on the left
217 if (container->children[FIRST_BUTTON_INDEX] != NULL) {
218 container->children[FIRST_BUTTON_INDEX]->alignmentMarginX = SUGGESTION_BUTTONS_SIDE_MARGIN;
219 container->children[FIRST_BUTTON_INDEX]->alignmentMarginY = 0;
220 container->children[FIRST_BUTTON_INDEX]->alignment = TOP_LEFT;
221 container->children[FIRST_BUTTON_INDEX]->alignTo = (nbgl_obj_t *) container;
222 }
223
224 // align top-right button on top-left one
225 if (container->children[SECOND_BUTTON_INDEX] != NULL) {
226 container->children[SECOND_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
227 container->children[SECOND_BUTTON_INDEX]->alignmentMarginY = 0;
228 container->children[SECOND_BUTTON_INDEX]->alignment = MID_RIGHT;
229 container->children[SECOND_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
230 }
231#ifndef USE_PARTIAL_BUTTONS
232 // align bottom-left button on top_left one
233 if (container->children[THIRD_BUTTON_INDEX] != NULL) {
234 container->children[THIRD_BUTTON_INDEX]->alignmentMarginX = 0;
235 container->children[THIRD_BUTTON_INDEX]->alignmentMarginY = INTERNAL_MARGIN;
236 container->children[THIRD_BUTTON_INDEX]->alignment = BOTTOM_MIDDLE;
237 container->children[THIRD_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
238 }
239
240 // align bottom-right button on bottom-left one
241 if (container->children[FOURTH_BUTTON_INDEX] != NULL) {
242 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
243 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginY = 0;
244 container->children[FOURTH_BUTTON_INDEX]->alignment = MID_RIGHT;
245 container->children[FOURTH_BUTTON_INDEX]->alignTo = container->children[THIRD_BUTTON_INDEX];
246 }
247#endif // !USE_PARTIAL_BUTTONS
248
249 // the first child is used by the progress indicator, displayed if more that
250 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
251 nbgl_page_indicator_t *indicator
252 = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
253 indicator->activePage = page;
254
255#ifdef USE_PARTIAL_BUTTONS
256 // if not on the first button, display end of previous button
257 if (currentLeftButtonIndex > 0) {
258 container->children[LEFT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[0];
259 }
260 else {
261 container->children[LEFT_HALF_INDEX] = NULL;
262 }
263 // if not on the last button, display beginning of next button
264 if ((nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)
265 && (currentLeftButtonIndex < (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
266 container->children[RIGHT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[1];
267 }
268 else {
269 container->children[RIGHT_HALF_INDEX] = NULL;
270 }
271#endif // USE_PARTIAL_BUTTONS
272 return needRefresh;
273}
274
275/**********************
276 * GLOBAL INTERNAL FUNCTIONS
277 **********************/
278
280 nbgl_obj_t *obj,
281 nbgl_touchType_t eventType)
282{
283 nbgl_container_t *container = (nbgl_container_t *) obj;
284 nbgl_container_t *suggestionsContainer;
285
286 if ((container->nbChildren < 2) || (container->children[1]->type != CONTAINER)) {
287 return false;
288 }
289 suggestionsContainer = (nbgl_container_t *) container->children[1];
290 // try if suggestions buttons (more than NB_MAX_VISIBLE_SUGGESTION_BUTTONS)
291 if (((eventType == SWIPED_LEFT) || (eventType == SWIPED_RIGHT))
292 && (suggestionsContainer->nbChildren == NB_SUGGESTION_CHILDREN)
293 && (nbActiveButtons > NB_MAX_VISIBLE_SUGGESTION_BUTTONS)) {
294 uint32_t i = 0;
295 while (i < (uint32_t) nbActiveButtons) {
296 if (((nbgl_button_t *) suggestionsContainer->children[FIRST_BUTTON_INDEX])->text
297 == choiceTexts[i]) {
298 break;
299 }
300 i++;
301 }
302
303 if (i < (uint32_t) nbActiveButtons) {
304 if (updateSuggestionButtons(layoutInt, suggestionsContainer, eventType, i)) {
305 os_io_seph_cmd_piezo_play_tune(TUNE_TAP_CASUAL);
306 nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
308 }
309
310 return true;
311 }
312 }
313 return false;
314}
315
317 const char *title,
318 const char *text,
319 bool numbered,
320 uint8_t number,
321 int textToken,
322 bool compactMode,
323 bool obfuscated)
324{
325 nbgl_container_t *mainContainer, *container;
326 nbgl_text_area_t *textArea;
327 layoutObj_t *obj;
328 uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT);
329 bool withCross = ((text != NULL) && (strlen(text) > 0));
330
331 // create a main container, to store title, and text-entry container
332 mainContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
333 mainContainer->nbChildren = 2;
334 mainContainer->children = nbgl_containerPoolGet(mainContainer->nbChildren, layoutInt->layer);
335 mainContainer->obj.area.width = AVAILABLE_WIDTH;
336 mainContainer->obj.alignment = CENTER;
337
338 if (title != NULL) {
339 // create text area for title
340 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
341 textArea->textColor = BLACK;
342 textArea->text = title;
343 textArea->textAlignment = CENTER;
344 textArea->fontId = SMALL_REGULAR_FONT;
345 textArea->wrapping = true;
346 textArea->obj.alignment = TOP_MIDDLE;
347 textArea->obj.area.width = AVAILABLE_WIDTH;
348 textArea->obj.area.height = nbgl_getTextHeightInWidth(
349 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
350 mainContainer->children[0] = (nbgl_obj_t *) textArea;
351 mainContainer->obj.area.height = textArea->obj.area.height + TITLE_ENTRY_MARGIN_Y;
352 }
353
354 // create a text-entry container number, entered text, potential cross and underline
355 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
356 container->nbChildren = 4;
357 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
358 container->obj.area.width = AVAILABLE_WIDTH;
359 container->obj.alignment = BOTTOM_MIDDLE;
360
361 if (numbered) {
362 // create Word num typed text
363 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
364 textArea->textColor = BLACK;
365 snprintf(numText, sizeof(numText), "%d.", number);
366 textArea->text = numText;
367 textArea->textAlignment = CENTER;
368 textArea->fontId = TEXT_ENTRY_FONT;
369 textArea->obj.area.width = NUMBER_WIDTH;
370 textArea->obj.alignment = MID_LEFT;
371 textArea->obj.area.height = nbgl_getFontHeight(textArea->fontId);
372 // set this text area as child of the container
373 container->children[NUMBER_INDEX] = (nbgl_obj_t *) textArea;
374 }
375
376 nbgl_font_id_e enteredTextFont = TEXT_ENTRY_FONT;
377 if (obfuscated) {
378 enteredTextFont = TEXT_ENTRY_FONT_OBFUSCATED;
379 }
380
381 // create text area for entered text
382 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
383 textArea->textColor = BLACK;
384 textArea->text = text;
385 textArea->textAlignment = MID_LEFT;
386 textArea->fontId = enteredTextFont;
387 textArea->obj.area.width = AVAILABLE_WIDTH - DELETE_ICON.width - NUMBER_TEXT_SPACE;
388 if (numbered) {
389 textArea->obj.alignmentMarginX = NUMBER_TEXT_SPACE;
390 textArea->obj.alignTo = container->children[0];
391 textArea->obj.alignment = MID_RIGHT;
392 textArea->obj.area.width -= textArea->obj.alignmentMarginX + NUMBER_WIDTH;
393 }
394 else {
395 textArea->obj.alignment = MID_LEFT;
396 }
397 textArea->obj.area.height = nbgl_getFontHeight(textArea->fontId);
398 textArea->autoHideLongLine = true;
399
400 container->children[TEXT_INDEX] = (nbgl_obj_t *) textArea;
401 container->obj.area.height = textEntryHeight;
402
403 // Create Cross
404 nbgl_image_t *image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
405 image->buffer = &DELETE_ICON;
406 // only display it if text non empty
407 image->foregroundColor = withCross ? BLACK : WHITE;
408 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) image, textToken, NBGL_NO_TUNE);
409 if (obj == NULL) {
410 return NULL;
411 }
412 image->obj.alignment = MID_RIGHT;
413 image->obj.alignTo = container->children[TEXT_INDEX];
414 image->obj.alignmentMarginX = NUMBER_TEXT_SPACE;
415 image->obj.touchMask = (1 << TOUCHED);
416 image->obj.touchId = ENTERED_TEXT_ID;
417 container->children[DELETE_INDEX] = (nbgl_obj_t *) image;
418
419 // create gray line
420 nbgl_line_t *line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
421 line->lineColor = LINE_COLOR;
422 // align on bottom of the text entry container
423 line->obj.alignment = BOTTOM_MIDDLE;
424 line->obj.area.width = AVAILABLE_WIDTH;
425 line->obj.area.height = LINE_THICKNESS;
426 line->direction = HORIZONTAL;
427 line->thickness = LINE_THICKNESS;
428 // set this line as child of the text entry container
429 container->children[LINE_INDEX] = (nbgl_obj_t *) line;
430
431 // set this text entry container as child of the main container
432 mainContainer->children[1] = (nbgl_obj_t *) container;
433 mainContainer->obj.area.height += container->obj.area.height;
434
435 return mainContainer;
436}
437
439 uint8_t nbUsedButtons,
440 const char **buttonTexts,
441 int firstButtonToken,
442 tune_index_e tuneId,
443 bool obfuscated)
444{
445 nbgl_container_t *suggestionsContainer;
446 layoutObj_t *obj;
447
448 nbActiveButtons = nbUsedButtons;
449 currentFirstButtonToken = firstButtonToken;
450 suggestionsContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
451 suggestionsContainer->layout = VERTICAL;
452 suggestionsContainer->obj.area.width = SCREEN_WIDTH;
453#ifndef USE_PARTIAL_BUTTONS
454 // 2 rows of buttons with radius=32, and a intervale of 8px
455 suggestionsContainer->obj.area.height = 2 * SMALL_BUTTON_HEIGHT + INTERNAL_MARGIN + 28;
456#else // USE_PARTIAL_BUTTONS
457 // 1 row of buttons + 24px + page indicator
458 suggestionsContainer->obj.area.height = SUGGESTION_CONTAINER_HEIGHT;
459#endif // USE_PARTIAL_BUTTONS
460 suggestionsContainer->nbChildren = NB_SUGGESTION_CHILDREN;
461 suggestionsContainer->children
463
464 // put suggestionsContainer at the bottom of main container
465 suggestionsContainer->obj.alignmentMarginY = BOTTOM_NORMAL_MARGIN;
466 suggestionsContainer->obj.alignment = BOTTOM_MIDDLE;
467
468 nbgl_font_id_e suggestionsFontId = SMALL_BOLD_1BPP_FONT;
469 if (obfuscated) {
470 suggestionsFontId = SMALL_OBFUSCATED_BOLD_1BPP_FONT;
471 }
472
473 // create all possible suggestion buttons, even if not displayed at first
474 for (int i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
475 nbgl_button_t *button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
476
477 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, firstButtonToken + i, tuneId);
478 if (obj == NULL) {
479 return NULL;
480 }
481
482 button->innerColor = BLACK;
483 button->borderColor = BLACK;
484 button->foregroundColor = WHITE;
485 button->obj.area.width
486 = (SCREEN_WIDTH - (2 * SUGGESTION_BUTTONS_SIDE_MARGIN) - INTERNAL_MARGIN) / 2;
487 button->obj.area.height = SMALL_BUTTON_HEIGHT;
488 button->radius = SMALL_BUTTON_RADIUS_INDEX;
489 button->fontId = suggestionsFontId;
490 button->text = buttonTexts[i];
491 button->obj.touchMask = (1 << TOUCHED);
492 button->obj.touchId = CONTROLS_ID + i;
493
494 suggestionsContainer->children[i + FIRST_BUTTON_INDEX] = (nbgl_obj_t *) button;
495 }
496 // The first child is used by the progress indicator, if more that
497 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
498 nbgl_page_indicator_t *indicator
500 indicator->activePage = 0;
501 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
502 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
503 indicator->obj.area.width
504 = (indicator->nbPages < 3) ? STEPPER_2_PAGES_WIDTH : STEPPER_N_PAGES_WIDTH;
505 indicator->obj.alignment = BOTTOM_MIDDLE;
506 indicator->style = CURRENT_INDICATOR;
507 suggestionsContainer->children[PAGE_INDICATOR_INDEX] = (nbgl_obj_t *) indicator;
508#ifdef USE_PARTIAL_BUTTONS
509 // also allocate the semi disc that may be displayed on the left or right of the full
510 // buttons
511 nbgl_objPoolGetArray(IMAGE, 2, layoutInt->layer, (nbgl_obj_t **) &partialButtonImages);
512 partialButtonImages[0]->buffer = &LEFT_HALF_ICON;
513 partialButtonImages[0]->obj.alignment = TOP_LEFT;
514 partialButtonImages[0]->foregroundColor = BLACK;
515 partialButtonImages[0]->transformation = VERTICAL_MIRROR;
516 partialButtonImages[1]->buffer = &LEFT_HALF_ICON;
517 partialButtonImages[1]->obj.alignment = TOP_RIGHT;
518 partialButtonImages[1]->foregroundColor = BLACK;
519 partialButtonImages[1]->transformation = NO_TRANSFORMATION;
520 updateSuggestionButtons(layoutInt, suggestionsContainer, 0, 0);
521#endif // USE_PARTIAL_BUTTONS
522
523 return suggestionsContainer;
524}
525
527 bool active,
528 const char *text,
529 int token,
530 tune_index_e tuneId,
531 bool compactMode)
532{
533 nbgl_button_t *button;
534 layoutObj_t *obj;
535
536 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
537 obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) button, token, tuneId);
538 if (obj == NULL) {
539 return NULL;
540 }
541
542 // put button at the bottom of the main container
543 button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_CONFIRM_MARGIN;
544 button->obj.alignment = BOTTOM_MIDDLE;
545 button->foregroundColor = WHITE;
546 if (active) {
547 button->innerColor = BLACK;
548 button->borderColor = BLACK;
549 button->obj.touchMask = (1 << TOUCHED);
550 button->obj.touchId = BOTTOM_BUTTON_ID;
551 }
552 else {
553 button->borderColor = INACTIVE_COLOR;
554 button->innerColor = INACTIVE_COLOR;
555 }
556 button->text = PIC(text);
557 button->fontId = SMALL_BOLD_1BPP_FONT;
558 button->obj.area.width = AVAILABLE_WIDTH;
559 button->obj.area.height = BUTTON_DIAMETER;
560 button->radius = BUTTON_RADIUS;
561
562 return button;
563}
564
565/**********************
566 * GLOBAL API FUNCTIONS
567 **********************/
568
577{
578 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
579 nbgl_keyboard_t *keyboard = NULL;
580
581 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboard():\n");
582 if (layout == NULL) {
583 return -1;
584 }
585 // footer must be empty
586 if (layoutInt->footerContainer != NULL) {
587 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutAddKeyboard(): footer already set\n");
588 return -1;
589 }
590
591 // create keyboard
592 keyboard = (nbgl_keyboard_t *) nbgl_objPoolGet(KEYBOARD, layoutInt->layer);
593 keyboard->obj.area.width = SCREEN_WIDTH;
594 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
595 if (!kbdInfo->lettersOnly) {
596 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
597 }
598#ifdef TARGET_STAX
599 keyboard->obj.alignmentMarginY = 56;
600#endif // TARGET_STAX
601 keyboard->obj.alignment = BOTTOM_MIDDLE;
602 keyboard->borderColor = LIGHT_GRAY;
603 keyboard->callback = PIC(kbdInfo->callback);
604 keyboard->lettersOnly = kbdInfo->lettersOnly;
605 keyboard->mode = kbdInfo->mode;
606 keyboard->keyMask = kbdInfo->keyMask;
607 keyboard->casing = kbdInfo->casing;
608
609 // the keyboard occupies the footer
610 layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
611 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
612 layoutInt->footerContainer->layout = VERTICAL;
613 layoutInt->footerContainer->children
614 = (nbgl_obj_t **) nbgl_containerPoolGet(1, layoutInt->layer);
615 layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
616 layoutInt->footerContainer->obj.area.height
617 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
618 layoutInt->footerContainer->children[0] = (nbgl_obj_t *) keyboard;
619 layoutInt->footerContainer->nbChildren = 1;
620
621 // add footer to layout children
622 layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
623
624 // subtract footer height from main container height
625 layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
626
627 // create the 2 children for main container (to hold keyboard content)
628 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
629 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
630
631 layoutInt->footerType = KEYBOARD_FOOTER_TYPE;
632
633 return layoutInt->footerContainer->obj.area.height;
634}
635
647 uint8_t index,
648 uint32_t keyMask,
649 bool updateCasing,
650 keyboardCase_t casing)
651{
652 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
653 nbgl_keyboard_t *keyboard;
654
655 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboard(): keyMask = 0x%X\n", keyMask);
656 if (layout == NULL) {
657 return -1;
658 }
659 UNUSED(index);
660
661 // get existing keyboard (in the footer container)
662 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
663 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
664 LOG_WARN(
665 LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboard(): keyboard not found at index %d\n", index);
666 return -1;
667 }
668 keyboard->keyMask = keyMask;
669 if (updateCasing) {
670 keyboard->casing = casing;
671 }
672
673 nbgl_objDraw((nbgl_obj_t *) keyboard);
674
675 return 0;
676}
677
686{
687 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
688 nbgl_keyboard_t *keyboard;
689
690 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutKeyboardNeedsRefresh(): \n");
691 if (layout == NULL) {
692 return -1;
693 }
694 UNUSED(index);
695
696 // get existing keyboard (in the footer container)
697 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
698 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
700 "nbgl_layoutKeyboardNeedsRefresh(): keyboard not found at index %d\n",
701 index);
702 return -1;
703 }
704 if (keyboard->needsRefresh) {
705 keyboard->needsRefresh = false;
706 return true;
707 }
708
709 return false;
710}
711
730 bool numbered,
731 uint8_t number,
732 const char *text,
733 bool grayedOut,
734 int offsetY,
735 int token)
736{
737 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
738 nbgl_container_t *container;
739 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
740 bool compactMode = ((layoutInt->container->children[enteredTextIndex + 1] != NULL)
741 && (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON)
742 && (layoutInt->container->nbChildren == 3));
743
744 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddEnteredText():\n");
745 if (layout == NULL) {
746 return -1;
747 }
748 UNUSED(offsetY);
749 UNUSED(grayedOut);
750
751 container = addTextEntry(layoutInt, NULL, text, numbered, number, token, compactMode, false);
752 if (container == NULL) {
753 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutAddEnteredText(): addTextEntry failed\n");
754 return -1;
755 }
756
757 // set this container as first or 2nd child of the main layout container
758 layoutInt->container->children[enteredTextIndex] = (nbgl_obj_t *) container;
759
760 if (layoutInt->container->children[enteredTextIndex + 1] != NULL) {
761 if (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON) {
762 nbgl_button_t *button
763 = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
764 container->obj.alignmentMarginY
765 -= (button->obj.area.height + button->obj.alignmentMarginY
766 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
767 / 2;
768 }
769 else if (layoutInt->container->children[enteredTextIndex + 1]->type == CONTAINER) {
770 nbgl_container_t *suggestionContainer
771 = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
772 container->obj.alignmentMarginY
773 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
774 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
775 / 2;
776 }
777 }
778 // if a centered info has be used for title, entered text is the second child and we have to
779 // adjust layout
780 if (layoutInt->container->nbChildren == 3) {
781 container->obj.alignmentMarginY += layoutInt->container->children[0]->area.height / 2;
782 }
783
784 // return 0
785 return 0;
786}
787
802 uint8_t index,
803 bool numbered,
804 uint8_t number,
805 const char *text,
806 bool grayedOut)
807{
808 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
809 nbgl_container_t *container;
810 nbgl_text_area_t *textArea;
811 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
812
813 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText():\n");
814 if (layout == NULL) {
815 return -1;
816 }
817 UNUSED(index);
818
819 // update text entry area
820 // container->children[enteredTextIndex] is the mainContainer built by addTextEntry(),
821 // which has 2 children: [0]=title (optional) and [1]=inner text-entry container.
822 // The inner container holds NUMBER_INDEX, TEXT_INDEX, DELETE_INDEX, LINE_INDEX children.
823 nbgl_container_t *mainContainer
824 = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex];
825 if ((mainContainer == NULL) || (mainContainer->obj.type != CONTAINER)) {
826 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText(): main container not found\n");
827 return -1;
828 }
829 container = (nbgl_container_t *) mainContainer->children[1];
830 if ((container == NULL) || (container->obj.type != CONTAINER)) {
831 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText(): text entry container not found\n");
832 return -1;
833 }
834 textArea = (nbgl_text_area_t *) container->children[TEXT_INDEX];
835 if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
836 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText(): text area not found\n");
837 return -1;
838 }
839 textArea->text = text;
840 textArea->textColor = grayedOut ? INACTIVE_TEXT_COLOR : BLACK;
841 textArea->textAlignment = MID_LEFT;
842 nbgl_objDraw((nbgl_obj_t *) textArea);
843
844 // update number text area
845 if (numbered) {
846 textArea = (nbgl_text_area_t *) container->children[NUMBER_INDEX];
847 if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
848 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText(): number area not found\n");
849 return -1;
850 }
851 snprintf(numText, sizeof(numText), "%d.", number);
852 textArea->text = numText;
853 nbgl_objDraw((nbgl_obj_t *) textArea);
854 }
855 // if the text doesn't fit, indicate it by returning 1 instead of 0, for different refresh
856 if (nbgl_getSingleLineTextWidth(textArea->fontId, text) > textArea->obj.area.width) {
857 return 1;
858 }
859 return 0;
860}
861
874 bool active,
875 const char *text,
876 int token,
877 tune_index_e tuneId)
878{
879 nbgl_button_t *button;
880 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
881 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
882 bool compactMode = (layoutInt->container->nbChildren == 3);
883
884 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddConfirmationButton():\n");
885 if (layout == NULL) {
886 return -1;
887 }
888
889 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
890 if (button == NULL) {
892 "nbgl_layoutAddConfirmationButton(): addConfirmationButton failed\n");
893 return -1;
894 }
895 // set this button as second child of the main layout container
896 layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) button;
897 if (layoutInt->container->children[enteredTextIndex] != NULL) {
898 ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
899 ->obj.alignmentMarginY
900 -= (button->obj.area.height + button->obj.alignmentMarginY
901 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
902 / 2;
903 }
904 // return 0
905 return 0;
906}
907
920 uint8_t index,
921 bool active,
922 const char *text)
923{
924 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
925 nbgl_button_t *button;
926 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
927
928 UNUSED(index);
929
930 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateConfirmationButton():\n");
931 if (layout == NULL) {
932 return -1;
933 }
934
935 // update main text area
936 button = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
937 if ((button == NULL) || (button->obj.type != BUTTON)) {
938 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateConfirmationButton(): button not found\n");
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 = INACTIVE_COLOR;
951 button->innerColor = INACTIVE_COLOR;
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 *textEntryContainer;
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 textEntryContainer = addTextEntry(layoutInt,
977 content->title,
978 content->text,
979 content->numbered,
980 content->number,
981 content->textToken,
982 compactMode,
983 content->obfuscated);
984 if (textEntryContainer == NULL) {
985 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutAddKeyboardContent(): addTextEntry failed\n");
986 return -1;
987 }
988
989 // set this container as first child of the main layout container
990 layoutInt->container->children[0] = (nbgl_obj_t *) textEntryContainer;
991
992 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
993 nbgl_container_t *suggestionsContainer
994 = addSuggestionButtons(layoutInt,
996 content->suggestionButtons.buttons,
998 content->tuneId,
999 content->obfuscated);
1000 if (suggestionsContainer == NULL) {
1002 "nbgl_layoutAddKeyboardContent(): addSuggestionButtons failed\n");
1003 return -1;
1004 }
1005
1006 // set this container as second child of the main layout container
1007 layoutInt->container->children[1] = (nbgl_obj_t *) suggestionsContainer;
1008 // the main container is swipable on Flex
1009 if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
1010 == NULL) {
1012 "nbgl_layoutAddKeyboardContent(): cannot add callback object\n");
1013 return -1;
1014 }
1015 layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
1016 layoutInt->container->obj.touchId = CONTROLS_ID;
1018 textEntryContainer->obj.alignmentMarginY
1019 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
1020 + 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 (content->title != NULL));
1030 if (button == NULL) {
1032 "nbgl_layoutAddKeyboardContent(): addConfirmationButton failed\n");
1033 return -1;
1034 }
1035 // set this button as second child of the main layout container
1036 layoutInt->container->children[1] = (nbgl_obj_t *) button;
1037 textEntryContainer->obj.alignmentMarginY
1038 -= (button->obj.area.height + button->obj.alignmentMarginY
1039 + ((content->title != NULL) ? TOP_COMPACT_MARGIN : TOP_CONFIRM_MARGIN))
1040 / 2;
1041 }
1042 return layoutInt->container->obj.area.height;
1043}
1044
1056{
1057 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1058 nbgl_container_t *mainContainer, *container;
1059 nbgl_text_area_t *textArea;
1060 nbgl_image_t *image;
1061 int ret = 0;
1062
1063 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent():\n");
1064 if (layout == NULL) {
1065 return -1;
1066 }
1067
1068 // get top container from main container (it shall be the 1st object)
1069 mainContainer = (nbgl_container_t *) layoutInt->container->children[0];
1070 if ((mainContainer == NULL) || (mainContainer->obj.type != CONTAINER)) {
1071 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent(): main container not found\n");
1072 return -1;
1073 }
1074 container = (nbgl_container_t *) mainContainer->children[1];
1075 if ((container == NULL) || (container->obj.type != CONTAINER)) {
1077 "nbgl_layoutUpdateKeyboardContent(): text entry container not found\n");
1078 return -1;
1079 }
1080
1081 if (content->numbered) {
1082 // get Word number typed text
1083 textArea = (nbgl_text_area_t *) container->children[NUMBER_INDEX];
1084 snprintf(numText, sizeof(numText), "%d.", content->number);
1085 nbgl_objDraw((nbgl_obj_t *) textArea);
1086 }
1087
1088 // get text area for entered text
1089 textArea = (nbgl_text_area_t *) container->children[TEXT_INDEX];
1090 textArea->text = content->text;
1091 textArea->fontId = content->obfuscated ? TEXT_ENTRY_FONT_OBFUSCATED : TEXT_ENTRY_FONT;
1092 nbgl_objDraw((nbgl_obj_t *) textArea);
1093
1094 // get delete cross
1095 image = (nbgl_image_t *) container->children[DELETE_INDEX];
1096 if ((textArea->text != NULL) && (strlen(textArea->text) > 0)) {
1097 if (image->foregroundColor == WHITE) {
1098 image->foregroundColor = BLACK;
1099 nbgl_objDraw((nbgl_obj_t *) image);
1100 }
1101 }
1102 else {
1103 if (image->foregroundColor == BLACK) {
1104 image->foregroundColor = WHITE;
1105 nbgl_objDraw((nbgl_obj_t *) image);
1106 }
1107 }
1108
1109 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
1110 uint8_t i = 0;
1112 nbgl_container_t *suggestionsContainer
1113 = (nbgl_container_t *) layoutInt->container->children[1];
1114 if ((suggestionsContainer == NULL) || (suggestionsContainer->obj.type != CONTAINER)) {
1116 "nbgl_layoutUpdateKeyboardContent(): suggestions container not found\n");
1117 return -1;
1118 }
1119
1120 // update suggestion texts
1121 for (i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1122 choiceTexts[i] = content->suggestionButtons.buttons[i];
1123 }
1124 // update suggestion buttons
1125 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
1126 // some buttons may not be visible
1127 // Button to be updated
1128 nbgl_button_t *button
1129 = (nbgl_button_t *) suggestionsContainer->children[i + FIRST_BUTTON_INDEX];
1130
1131 if (i < nbActiveButtons) {
1132 // Update button text and touch token
1133 button->text = choiceTexts[i];
1135 layoutInt, (nbgl_obj_t *) button, currentFirstButtonToken + i);
1136 }
1137 else {
1138 button->text = NULL;
1140 }
1141 }
1142 suggestionsContainer->forceClean = true;
1143 // the first child is used by the progress indicator, if more than
1144 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
1145 nbgl_page_indicator_t *indicator
1146 = (nbgl_page_indicator_t *) suggestionsContainer->children[PAGE_INDICATOR_INDEX];
1147 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1148 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1149 indicator->activePage = 0;
1150 updateSuggestionButtons(layoutInt, suggestionsContainer, 0, 0);
1151
1152 nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
1153 }
1154 else if (content->type == KEYBOARD_WITH_BUTTON) {
1155 // update main text area
1156 nbgl_button_t *button = (nbgl_button_t *) layoutInt->container->children[1];
1157 if ((button == NULL) || (button->obj.type != BUTTON)) {
1158 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent(): button not found\n");
1159 return -1;
1160 }
1161 button->text = content->confirmationButton.text;
1162
1163 if (content->confirmationButton.active) {
1164#if NB_COLOR_BITS == 4
1165 // if the button was inactive (in grey), a non-fast refresh will be necessary
1166 if (button->innerColor == INACTIVE_COLOR) {
1167 ret = 1;
1168 }
1169#endif
1170 button->innerColor = BLACK;
1171 button->borderColor = BLACK;
1172 button->obj.touchMask = (1 << TOUCHED);
1173 button->obj.touchId = BOTTOM_BUTTON_ID;
1174 }
1175 else {
1176 button->borderColor = INACTIVE_COLOR;
1177 button->innerColor = INACTIVE_COLOR;
1178 }
1179 nbgl_objDraw((nbgl_obj_t *) button);
1180 }
1181
1182 // if the entered text doesn't fit, indicate it by returning 1 instead of 0, for different
1183 // refresh
1184 if (nbgl_getSingleLineTextWidth(textArea->fontId, content->text) > textArea->obj.area.width) {
1185 ret = 1;
1186 }
1187 return ret;
1188}
1189
1190#endif // NBGL_KEYBOARD
1191#endif // HAVE_SE_TOUCH
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
@ LAYOUT_LOGGER
Definition nbgl_debug.h:33
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
Middle Level API of the new BOLOS Graphical Library.
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
nbgl_font_id_e
Definition nbgl_fonts.h:141
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
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
void layoutUpdateCallbackObjToken(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token)
Update the token associated with a specific object in a layout.
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
#define AVAILABLE_WIDTH
void * nbgl_layout_t
type shared externally
#define NBGL_INVALID_TOKEN
Definition nbgl_layout.h:30
#define NBGL_NO_TUNE
Definition nbgl_layout.h:26
@ 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
#define KEYBOARD_FOOTER_TYPE
#define INTERNAL_MARGIN
@ FOOTER_INDEX
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.
static nbgl_container_t * addTextEntry(nbgl_layoutInternal_t *layoutInt, const char *title, const char *text, bool numbered, uint8_t number, int textToken, bool compactMode, bool obfuscated)
static char numText[5]
static bool updateSuggestionButtons(nbgl_layoutInternal_t *layoutInt, nbgl_container_t *container, nbgl_touchType_t eventType, uint8_t currentLeftButtonIndex)
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()
#define LINE_THICKNESS
#define SUGGESTION_BUTTONS_SIDE_MARGIN
static nbgl_button_t * addConfirmationButton(nbgl_layoutInternal_t *layoutInt, bool active, const char *text, int token, tune_index_e tuneId, bool compactMode)
bool keyboardSwipeCallback(nbgl_layoutInternal_t *layoutInt, nbgl_obj_t *obj, nbgl_touchType_t eventType)
static uint8_t currentFirstButtonToken
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...
static nbgl_container_t * addSuggestionButtons(nbgl_layoutInternal_t *layoutInt, uint8_t nbUsedButtons, const char **buttonTexts, int firstButtonToken, tune_index_e tuneId, bool obfuscated)
static const char * choiceTexts[NB_MAX_SUGGESTION_BUTTONS]
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.
@ SECOND_BUTTON_INDEX
@ NB_SUGGESTION_CHILDREN
@ PAGE_INDICATOR_INDEX
@ FIRST_BUTTON_INDEX
@ THIRD_BUTTON_INDEX
@ FOURTH_BUTTON_INDEX
#define LINE_COLOR
bool nbgl_layoutKeyboardNeedsRefresh(nbgl_layout_t *layout, uint8_t index)
function called to know whether the keyboard has been redrawn and needs a refresh
@ DELETE_INDEX
@ NUMBER_INDEX
static uint8_t nbActiveButtons
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)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
@ CONTROLS_ID
Definition nbgl_obj.h:579
@ ENTERED_TEXT_ID
Definition nbgl_obj.h:573
@ BOTTOM_BUTTON_ID
Definition nbgl_obj.h:560
keyboardCase_t
Letters casing in which to open/set the keyboard.
Definition nbgl_obj.h:500
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
struct PACKED__ nbgl_keyboard_s nbgl_keyboard_t
struct to represent a keyboard (KEYBOARD type)
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
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)
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 INACTIVE_COLOR
Definition nbgl_obj.h:166
#define INACTIVE_TEXT_COLOR
Definition nbgl_obj.h:167
#define BUTTON_DIAMETER
Definition nbgl_obj.h:105
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:374
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
@ WHITE
Definition nbgl_types.h:156
@ LIGHT_GRAY
Definition nbgl_types.h:155
@ BLACK
Definition nbgl_types.h:153
#define VERTICAL_MIRROR
Definition nbgl_types.h:109
nbgl_touchType_t
The different types of Touchscreen events.
Definition nbgl_types.h:271
@ SWIPED_LEFT
Definition nbgl_types.h:286
@ SWIPED_RIGHT
Definition nbgl_types.h:285
@ TOUCHED
Definition nbgl_types.h:272
@ VERTICAL
from top to bottom
Definition nbgl_types.h:221
@ HORIZONTAL
from left to right
Definition nbgl_types.h:222
@ TOP_MIDDLE
Definition nbgl_types.h:194
@ CENTER
Definition nbgl_types.h:197
@ TOP_LEFT
Definition nbgl_types.h:193
@ MID_RIGHT
Definition nbgl_types.h:198
@ TOP_RIGHT
Definition nbgl_types.h:195
@ MID_LEFT
Definition nbgl_types.h:196
@ BOTTOM_MIDDLE
Definition nbgl_types.h:200
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:169
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition nbgl_types.h:172
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition nbgl_types.h:174
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:170
@ KEYBOARD
Keyboard.
Definition nbgl_types.h:178
@ CONTAINER
Empty container.
Definition nbgl_types.h:168
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:171
#define NO_TRANSFORMATION
Definition nbgl_types.h:103
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition nbgl_types.h:339
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....)
uint8_t layer
layer in screen stack
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
tune_index_e tuneId
if not NBGL_NO_TUNE, a tune will be played
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.'
uint8_t nbUsedButtons
the number of actually used (displayed) buttons
const char ** buttons
array of 4 strings for buttons (last ones can be NULL)