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