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 {
37 PAGE_INDICATOR_INDEX = 0,
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
42 FIRST_BUTTON_INDEX,
43 SECOND_BUTTON_INDEX,
44#ifndef USE_PARTIAL_BUTTONS
45 THIRD_BUTTON_INDEX,
46 FOURTH_BUTTON_INDEX,
47#endif // !USE_PARTIAL_BUTTONS
48 NB_SUGGESTION_CHILDREN
49};
50
51// Keyboard Text Entry container children
52enum {
53 NUMBER_INDEX = 0,
54 TEXT_INDEX,
55 DELETE_INDEX,
56 LINE_INDEX
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;
145static uint8_t currentFirstButtonToken;
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
156static bool updateSuggestionButtons(nbgl_layoutInternal_t *layoutInt,
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)
167 && (currentLeftButtonIndex
168 < (uint32_t) (nbActiveButtons - NB_MAX_VISIBLE_SUGGESTION_BUTTONS))) {
169 // shift all buttons on the left if there are still at least
170 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons to display
171 currentLeftButtonIndex += NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
172
173 // Button to be updated
174 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX];
175
176 // Update button text and touch token
177 button->text = choiceTexts[currentLeftButtonIndex];
179 layoutInt, (nbgl_obj_t *) button, currentFirstButtonToken + currentLeftButtonIndex);
180
181 for (i = 1; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
182 // Button to be updated
183 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX + i];
184
185 if (currentLeftButtonIndex < (uint32_t) (nbActiveButtons - i)) {
186 button->text = choiceTexts[currentLeftButtonIndex + i];
188 (nbgl_obj_t *) button,
189 currentFirstButtonToken + currentLeftButtonIndex + i);
190 }
191 else {
192 button->text = NULL;
194 }
195 }
196 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
197 needRefresh = true;
198 }
199 else if ((eventType == SWIPED_RIGHT)
200 && (currentLeftButtonIndex > (NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1))) {
201 // shift all buttons on the left if we are not already displaying the
202 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS first ones
203 currentLeftButtonIndex -= NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
204 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
205 // Button to be updated
206 button = (nbgl_button_t *) container->children[FIRST_BUTTON_INDEX + i];
207
208 // Update button text and touch token
209 button->text = choiceTexts[currentLeftButtonIndex + i];
211 (nbgl_obj_t *) button,
212 currentFirstButtonToken + currentLeftButtonIndex + i);
213 }
214 page = currentLeftButtonIndex / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
215 needRefresh = true;
216 }
217 // align top-left button on the left
218 if (container->children[FIRST_BUTTON_INDEX] != NULL) {
219 container->children[FIRST_BUTTON_INDEX]->alignmentMarginX = SUGGESTION_BUTTONS_SIDE_MARGIN;
220 container->children[FIRST_BUTTON_INDEX]->alignmentMarginY = 0;
221 container->children[FIRST_BUTTON_INDEX]->alignment = TOP_LEFT;
222 container->children[FIRST_BUTTON_INDEX]->alignTo = (nbgl_obj_t *) container;
223 }
224
225 // align top-right button on top-left one
226 if (container->children[SECOND_BUTTON_INDEX] != NULL) {
227 container->children[SECOND_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
228 container->children[SECOND_BUTTON_INDEX]->alignmentMarginY = 0;
229 container->children[SECOND_BUTTON_INDEX]->alignment = MID_RIGHT;
230 container->children[SECOND_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
231 }
232#ifndef USE_PARTIAL_BUTTONS
233 // align bottom-left button on top_left one
234 if (container->children[THIRD_BUTTON_INDEX] != NULL) {
235 container->children[THIRD_BUTTON_INDEX]->alignmentMarginX = 0;
236 container->children[THIRD_BUTTON_INDEX]->alignmentMarginY = INTERNAL_MARGIN;
237 container->children[THIRD_BUTTON_INDEX]->alignment = BOTTOM_MIDDLE;
238 container->children[THIRD_BUTTON_INDEX]->alignTo = container->children[FIRST_BUTTON_INDEX];
239 }
240
241 // align bottom-right button on bottom-left one
242 if (container->children[FOURTH_BUTTON_INDEX] != NULL) {
243 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginX = INTERNAL_MARGIN;
244 container->children[FOURTH_BUTTON_INDEX]->alignmentMarginY = 0;
245 container->children[FOURTH_BUTTON_INDEX]->alignment = MID_RIGHT;
246 container->children[FOURTH_BUTTON_INDEX]->alignTo = container->children[THIRD_BUTTON_INDEX];
247 }
248#endif // !USE_PARTIAL_BUTTONS
249
250 // the first child is used by the progress indicator, displayed if more that
251 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
252 nbgl_page_indicator_t *indicator
253 = (nbgl_page_indicator_t *) container->children[PAGE_INDICATOR_INDEX];
254 indicator->activePage = page;
255
256#ifdef USE_PARTIAL_BUTTONS
257 // if not on the first button, display end of previous button
258 if (currentLeftButtonIndex > 0) {
259 container->children[LEFT_HALF_INDEX] = (nbgl_obj_t *) partialButtonImages[0];
260 }
261 else {
262 container->children[LEFT_HALF_INDEX] = NULL;
263 }
264 // if not on the last button, display beginning of next button
265 if (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
316static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt,
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
438static nbgl_container_t *addSuggestionButtons(nbgl_layoutInternal_t *layoutInt,
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
462 = (nbgl_obj_t **) nbgl_containerPoolGet(NB_SUGGESTION_CHILDREN, layoutInt->layer);
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
526static nbgl_button_t *addConfirmationButton(nbgl_layoutInternal_t *layoutInt,
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
576int nbgl_layoutAddKeyboard(nbgl_layout_t *layout, const nbgl_layoutKbd_t *kbdInfo)
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 return -1;
588 }
589
590 // create keyboard
591 keyboard = (nbgl_keyboard_t *) nbgl_objPoolGet(KEYBOARD, layoutInt->layer);
592 keyboard->obj.area.width = SCREEN_WIDTH;
593 keyboard->obj.area.height = 3 * KEYBOARD_KEY_HEIGHT;
594 if (!kbdInfo->lettersOnly) {
595 keyboard->obj.area.height += KEYBOARD_KEY_HEIGHT;
596 }
597#ifdef TARGET_STAX
598 keyboard->obj.alignmentMarginY = 56;
599#endif // TARGET_STAX
600 keyboard->obj.alignment = BOTTOM_MIDDLE;
601 keyboard->borderColor = LIGHT_GRAY;
602 keyboard->callback = PIC(kbdInfo->callback);
603 keyboard->lettersOnly = kbdInfo->lettersOnly;
604 keyboard->mode = kbdInfo->mode;
605 keyboard->keyMask = kbdInfo->keyMask;
606 keyboard->casing = kbdInfo->casing;
607
608 // the keyboard occupies the footer
609 layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
610 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
611 layoutInt->footerContainer->layout = VERTICAL;
612 layoutInt->footerContainer->children
613 = (nbgl_obj_t **) nbgl_containerPoolGet(1, layoutInt->layer);
614 layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
615 layoutInt->footerContainer->obj.area.height
616 = keyboard->obj.area.height + keyboard->obj.alignmentMarginY;
617 layoutInt->footerContainer->children[0] = (nbgl_obj_t *) keyboard;
618 layoutInt->footerContainer->nbChildren = 1;
619
620 // add footer to layout children
621 layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
622
623 // subtract footer height from main container height
624 layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
625
626 // create the 2 children for main container (to hold keyboard content)
627 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
628 layoutAddObject(layoutInt, (nbgl_obj_t *) NULL);
629
630 layoutInt->footerType = KEYBOARD_FOOTER_TYPE;
631
632 return layoutInt->footerContainer->obj.area.height;
633}
634
646 uint8_t index,
647 uint32_t keyMask,
648 bool updateCasing,
649 keyboardCase_t casing)
650{
651 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
652 nbgl_keyboard_t *keyboard;
653
654 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboard(): keyMask = 0x%X\n", keyMask);
655 if (layout == NULL) {
656 return -1;
657 }
658 UNUSED(index);
659
660 // get existing keyboard (in the footer container)
661 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
662 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
663 return -1;
664 }
665 keyboard->keyMask = keyMask;
666 if (updateCasing) {
667 keyboard->casing = casing;
668 }
669
670 nbgl_objDraw((nbgl_obj_t *) keyboard);
671
672 return 0;
673}
674
682bool nbgl_layoutKeyboardNeedsRefresh(nbgl_layout_t *layout, uint8_t index)
683{
684 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
685 nbgl_keyboard_t *keyboard;
686
687 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutKeyboardNeedsRefresh(): \n");
688 if (layout == NULL) {
689 return -1;
690 }
691 UNUSED(index);
692
693 // get existing keyboard (in the footer container)
694 keyboard = (nbgl_keyboard_t *) layoutInt->footerContainer->children[0];
695 if ((keyboard == NULL) || (keyboard->obj.type != KEYBOARD)) {
696 return -1;
697 }
698 if (keyboard->needsRefresh) {
699 keyboard->needsRefresh = false;
700 return true;
701 }
702
703 return false;
704}
705
724 bool numbered,
725 uint8_t number,
726 const char *text,
727 bool grayedOut,
728 int offsetY,
729 int token)
730{
731 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
732 nbgl_container_t *container;
733 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
734 bool compactMode = ((layoutInt->container->children[enteredTextIndex + 1] != NULL)
735 && (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON)
736 && (layoutInt->container->nbChildren == 3));
737
738 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddEnteredText():\n");
739 if (layout == NULL) {
740 return -1;
741 }
742 UNUSED(offsetY);
743 UNUSED(grayedOut);
744
745 container = addTextEntry(layoutInt, NULL, text, numbered, number, token, compactMode, false);
746
747 // set this container as first or 2nd child of the main layout container
748 layoutInt->container->children[enteredTextIndex] = (nbgl_obj_t *) container;
749
750 if (layoutInt->container->children[enteredTextIndex + 1] != NULL) {
751 if (layoutInt->container->children[enteredTextIndex + 1]->type == BUTTON) {
752 nbgl_button_t *button
753 = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
754 container->obj.alignmentMarginY
755 -= (button->obj.area.height + button->obj.alignmentMarginY
756 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
757 / 2;
758 }
759 else if (layoutInt->container->children[enteredTextIndex + 1]->type == CONTAINER) {
760 nbgl_container_t *suggestionContainer
761 = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1];
762 container->obj.alignmentMarginY
763 -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY
764 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
765 / 2;
766 }
767 }
768 // if a centered info has be used for title, entered text is the second child and we have to
769 // adjust layout
770 if (layoutInt->container->nbChildren == 3) {
771 container->obj.alignmentMarginY += layoutInt->container->children[0]->area.height / 2;
772 }
773
774 // return 0
775 return 0;
776}
777
792 uint8_t index,
793 bool numbered,
794 uint8_t number,
795 const char *text,
796 bool grayedOut)
797{
798 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
799 nbgl_container_t *container;
800 nbgl_text_area_t *textArea;
801 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
802
803 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateEnteredText():\n");
804 if (layout == NULL) {
805 return -1;
806 }
807 UNUSED(index);
808
809 // update text entry area
810 container = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex];
811 if ((container == NULL) || (container->obj.type != CONTAINER)) {
812 return -1;
813 }
814 textArea = (nbgl_text_area_t *) container->children[2];
815 if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
816 return -1;
817 }
818 textArea->text = text;
819 textArea->textColor = grayedOut ? INACTIVE_TEXT_COLOR : BLACK;
820 textArea->textAlignment = MID_LEFT;
821 nbgl_objDraw((nbgl_obj_t *) textArea);
822
823 // update number text area
824 if (numbered) {
825 // it is the previously created object
826 textArea = (nbgl_text_area_t *) layoutInt->container->children[1];
827 snprintf(numText, sizeof(numText), "%d.", number);
828 textArea->text = numText;
829 nbgl_objDraw((nbgl_obj_t *) textArea);
830 }
831 // if the text doesn't fit, indicate it by returning 1 instead of 0, for different refresh
832 if (nbgl_getSingleLineTextWidth(textArea->fontId, text) > textArea->obj.area.width) {
833 return 1;
834 }
835 return 0;
836}
837
849int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout,
850 bool active,
851 const char *text,
852 int token,
853 tune_index_e tuneId)
854{
855 nbgl_button_t *button;
856 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
857 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
858 bool compactMode = (layoutInt->container->nbChildren == 3);
859
860 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddConfirmationButton():\n");
861 if (layout == NULL) {
862 return -1;
863 }
864
865 button = addConfirmationButton(layoutInt, active, text, token, tuneId, compactMode);
866 // set this button as second child of the main layout container
867 layoutInt->container->children[enteredTextIndex + 1] = (nbgl_obj_t *) button;
868 if (layoutInt->container->children[enteredTextIndex] != NULL) {
869 ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex])
870 ->obj.alignmentMarginY
871 -= (button->obj.area.height + button->obj.alignmentMarginY
872 + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN))
873 / 2;
874 }
875 // return 0
876 return 0;
877}
878
890int nbgl_layoutUpdateConfirmationButton(nbgl_layout_t *layout,
891 uint8_t index,
892 bool active,
893 const char *text)
894{
895 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
896 nbgl_button_t *button;
897 uint8_t enteredTextIndex = (layoutInt->container->nbChildren == 2) ? 0 : 1;
898
899 UNUSED(index);
900
901 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateConfirmationButton():\n");
902 if (layout == NULL) {
903 return -1;
904 }
905
906 // update main text area
907 button = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1];
908 if ((button == NULL) || (button->obj.type != BUTTON)) {
909 return -1;
910 }
911 button->text = text;
912
913 if (active) {
914 button->innerColor = BLACK;
915 button->borderColor = BLACK;
916 button->obj.touchMask = (1 << TOUCHED);
917 button->obj.touchId = BOTTOM_BUTTON_ID;
918 }
919 else {
920 button->borderColor = INACTIVE_COLOR;
921 button->innerColor = INACTIVE_COLOR;
922 }
923 nbgl_objDraw((nbgl_obj_t *) button);
924 return 0;
925}
926
935int nbgl_layoutAddKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
936{
937 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
938 nbgl_container_t *textEntryContainer;
939 bool compactMode = ((content->type == KEYBOARD_WITH_BUTTON) && (content->title != NULL));
940
941 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeyboardContent():\n");
942 if (layout == NULL) {
943 return -1;
944 }
945
946 textEntryContainer = addTextEntry(layoutInt,
947 content->title,
948 content->text,
949 content->numbered,
950 content->number,
951 content->textToken,
952 compactMode,
953 content->obfuscated);
954
955 // set this container as first child of the main layout container
956 layoutInt->container->children[0] = (nbgl_obj_t *) textEntryContainer;
957
958 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
959 nbgl_container_t *suggestionsContainer
960 = addSuggestionButtons(layoutInt,
962 content->suggestionButtons.buttons,
964 content->tuneId,
965 content->obfuscated);
966
967 // set this container as second child of the main layout container
968 layoutInt->container->children[1] = (nbgl_obj_t *) suggestionsContainer;
969 // the main container is swipable on Flex
970 if (layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->container, 0, NBGL_NO_TUNE)
971 == NULL) {
972 return -1;
973 }
974 layoutInt->container->obj.touchMask = (1 << SWIPED_LEFT) | (1 << SWIPED_RIGHT);
975 layoutInt->container->obj.touchId = CONTROLS_ID;
977 textEntryContainer->obj.alignmentMarginY
978 -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY
979 + TOP_NORMAL_MARGIN)
980 / 2;
981 }
982 else if (content->type == KEYBOARD_WITH_BUTTON) {
983 nbgl_button_t *button = addConfirmationButton(layoutInt,
984 content->confirmationButton.active,
985 content->confirmationButton.text,
986 content->confirmationButton.token,
987 content->tuneId,
988 (content->title != NULL));
989 // set this button as second child of the main layout container
990 layoutInt->container->children[1] = (nbgl_obj_t *) button;
991 textEntryContainer->obj.alignmentMarginY
992 -= (button->obj.area.height + button->obj.alignmentMarginY
993 + ((content->title != NULL) ? TOP_COMPACT_MARGIN : TOP_CONFIRM_MARGIN))
994 / 2;
995 }
996 return layoutInt->container->obj.area.height;
997}
998
1009int nbgl_layoutUpdateKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardContent_t *content)
1010{
1011 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
1012 nbgl_container_t *mainContainer, *container;
1013 nbgl_text_area_t *textArea;
1014 nbgl_image_t *image;
1015 int ret = 0;
1016
1017 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeyboardContent():\n");
1018 if (layout == NULL) {
1019 return -1;
1020 }
1021
1022 // get top container from main container (it shall be the 1st object)
1023 mainContainer = (nbgl_container_t *) layoutInt->container->children[0];
1024 container = (nbgl_container_t *) mainContainer->children[1];
1025
1026 if (content->numbered) {
1027 // get Word number typed text
1028 textArea = (nbgl_text_area_t *) container->children[NUMBER_INDEX];
1029 snprintf(numText, sizeof(numText), "%d.", content->number);
1030 nbgl_objDraw((nbgl_obj_t *) textArea);
1031 }
1032
1033 // get text area for entered text
1034 textArea = (nbgl_text_area_t *) container->children[TEXT_INDEX];
1035 textArea->text = content->text;
1036 textArea->fontId = content->obfuscated ? TEXT_ENTRY_FONT_OBFUSCATED : TEXT_ENTRY_FONT;
1037 nbgl_objDraw((nbgl_obj_t *) textArea);
1038
1039 // get delete cross
1040 image = (nbgl_image_t *) container->children[DELETE_INDEX];
1041 if ((textArea->text != NULL) && (strlen(textArea->text) > 0)) {
1042 if (image->foregroundColor == WHITE) {
1043 image->foregroundColor = BLACK;
1044 nbgl_objDraw((nbgl_obj_t *) image);
1045 }
1046 }
1047 else {
1048 if (image->foregroundColor == BLACK) {
1049 image->foregroundColor = WHITE;
1050 nbgl_objDraw((nbgl_obj_t *) image);
1051 }
1052 }
1053
1054 if (content->type == KEYBOARD_WITH_SUGGESTIONS) {
1055 uint8_t i = 0;
1056 nbActiveButtons = content->suggestionButtons.nbUsedButtons;
1057 nbgl_container_t *suggestionsContainer
1058 = (nbgl_container_t *) layoutInt->container->children[1];
1059
1060 // update suggestion texts
1061 for (i = 0; i < NB_MAX_SUGGESTION_BUTTONS; i++) {
1062 choiceTexts[i] = content->suggestionButtons.buttons[i];
1063 }
1064 // update suggestion buttons
1065 for (i = 0; i < NB_MAX_VISIBLE_SUGGESTION_BUTTONS; i++) {
1066 // some buttons may not be visible
1067 // Button to be updated
1068 nbgl_button_t *button
1069 = (nbgl_button_t *) suggestionsContainer->children[i + FIRST_BUTTON_INDEX];
1070
1071 if (i < nbActiveButtons) {
1072 // Update button text and touch token
1073 button->text = choiceTexts[i];
1075 layoutInt, (nbgl_obj_t *) button, currentFirstButtonToken + i);
1076 }
1077 else {
1078 button->text = NULL;
1080 }
1081 }
1082 suggestionsContainer->forceClean = true;
1083 // the first child is used by the progress indicator, if more than
1084 // NB_MAX_VISIBLE_SUGGESTION_BUTTONS buttons
1085 nbgl_page_indicator_t *indicator
1086 = (nbgl_page_indicator_t *) suggestionsContainer->children[PAGE_INDICATOR_INDEX];
1087 indicator->nbPages = (nbActiveButtons + NB_MAX_VISIBLE_SUGGESTION_BUTTONS - 1)
1088 / NB_MAX_VISIBLE_SUGGESTION_BUTTONS;
1089 indicator->activePage = 0;
1090 updateSuggestionButtons(layoutInt, suggestionsContainer, 0, 0);
1091
1092 nbgl_objDraw((nbgl_obj_t *) suggestionsContainer);
1093 }
1094 else if (content->type == KEYBOARD_WITH_BUTTON) {
1095 // update main text area
1096 nbgl_button_t *button = (nbgl_button_t *) layoutInt->container->children[1];
1097 if ((button == NULL) || (button->obj.type != BUTTON)) {
1098 return -1;
1099 }
1100 button->text = content->confirmationButton.text;
1101
1102 if (content->confirmationButton.active) {
1103#if NB_COLOR_BITS == 4
1104 // if the button was inactive (in grey), a non-fast refresh will be necessary
1105 if (button->innerColor == INACTIVE_COLOR) {
1106 ret = 1;
1107 }
1108#endif
1109 button->innerColor = BLACK;
1110 button->borderColor = BLACK;
1111 button->obj.touchMask = (1 << TOUCHED);
1112 button->obj.touchId = BOTTOM_BUTTON_ID;
1113 }
1114 else {
1115 button->borderColor = INACTIVE_COLOR;
1116 button->innerColor = INACTIVE_COLOR;
1117 }
1118 nbgl_objDraw((nbgl_obj_t *) button);
1119 }
1120
1121 // if the entered text doesn't fit, indicate it by returning 1 instead of 0, for different
1122 // refresh
1123 if (nbgl_getSingleLineTextWidth(textArea->fontId, content->text) > textArea->obj.area.width) {
1124 ret = 1;
1125 }
1126 return ret;
1127}
1128
1129#endif // NBGL_KEYBOARD
1130#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)
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.
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_layoutUpdateKeyboard(nbgl_layout_t *layout, uint8_t index, uint32_t keyMask)
Updates an existing keyboard on bottom of the screen, with the given configuration.
int nbgl_layoutUpdateEnteredText(nbgl_layout_t *layout, uint8_t index, const char *text)
Updates an existing "text entry" area, created with nbgl_layoutAddEnteredText()
int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, const char *text, bool lettersOnly)
Adds a "text entry" area under the previously entered object. The max number of really displayable ch...
#define AVAILABLE_WIDTH
#define NB_MAX_SUGGESTION_BUTTONS
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
bool keyboardSwipeCallback(nbgl_layoutInternal_t *layoutInt, nbgl_obj_t *obj, nbgl_touchType_t eventType)
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the layout
void layoutUpdateCallbackObjToken(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token)
#define INTERNAL_MARGIN
@ FOOTER_INDEX
layoutObj_t * layoutAddCallbackObj(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj, uint8_t token, tune_index_e tuneId)
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)
keyboardCase_t
Letters casing in which to open/set the keyboard.
Definition nbgl_obj.h:620
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:281
#define INACTIVE_TEXT_COLOR
Definition nbgl_obj.h:282
#define KEYBOARD_KEY_HEIGHT
Definition nbgl_obj.h:49
@ CONTROLS_ID
Definition nbgl_obj.h:699
@ ENTERED_TEXT_ID
Definition nbgl_obj.h:693
@ BOTTOM_BUTTON_ID
Definition nbgl_obj.h:680
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:494
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
@ WHITE
Definition nbgl_types.h:144
@ LIGHT_GRAY
Definition nbgl_types.h:143
@ BLACK
Definition nbgl_types.h:141
#define VERTICAL_MIRROR
Definition nbgl_types.h:97
#define SCREEN_WIDTH
Definition nbgl_types.h:77
nbgl_touchType_t
The different types of Touchscreen events.
Definition nbgl_types.h:259
@ SWIPED_LEFT
Definition nbgl_types.h:274
@ SWIPED_RIGHT
Definition nbgl_types.h:273
@ TOUCHED
Definition nbgl_types.h:260
@ VERTICAL
from top to bottom
Definition nbgl_types.h:209
@ HORIZONTAL
from left to right
Definition nbgl_types.h:210
@ TOP_MIDDLE
Definition nbgl_types.h:182
@ CENTER
Definition nbgl_types.h:185
@ TOP_LEFT
Definition nbgl_types.h:181
@ MID_RIGHT
Definition nbgl_types.h:186
@ TOP_RIGHT
Definition nbgl_types.h:183
@ MID_LEFT
Definition nbgl_types.h:184
@ BOTTOM_MIDDLE
Definition nbgl_types.h:188
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:157
@ BUTTON
Rounded rectangle button with icon and/or text.
Definition nbgl_types.h:160
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition nbgl_types.h:162
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:158
@ KEYBOARD
Keyboard.
Definition nbgl_types.h:166
@ CONTAINER
Empty container.
Definition nbgl_types.h:156
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:159
#define NO_TRANSFORMATION
Definition nbgl_types.h:91
@ FULL_COLOR_PARTIAL_REFRESH
to be used for small partial refresh (radio buttons, switches)
Definition nbgl_types.h:327
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
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.'
uint8_t nbUsedButtons
the number of actually used buttons
const char ** buttons
array of 4 strings for buttons (last ones can be NULL)