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