Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_layout_nanos.c
Go to the documentation of this file.
1
6#ifndef HAVE_SE_TOUCH
7/*********************
8 * INCLUDES
9 *********************/
10#include <string.h>
11#include <stdlib.h>
12#include "nbgl_debug.h"
13#include "nbgl_front.h"
15#include "nbgl_obj.h"
16#include "nbgl_draw.h"
17#include "nbgl_screen.h"
18#include "nbgl_touch.h"
19#include "glyphs.h"
20#include "os_pic.h"
21#include "os_helpers.h"
22#include "lcx_rng.h"
23
24/*********************
25 * DEFINES
26 *********************/
27
28#define NB_MAX_LAYOUTS 3
29
30// used by screen
31#define NB_MAX_SCREEN_CHILDREN 7
32
33#define BUTTON_MARGIN_Y 12
34
35// this is the maximum number of chars fitting in a line
36#define NB_MAX_CHAR_IN_LINE 20
37
38#define ELLIPSIS "..."
39#define ELLIPSIS_SIZE sizeof(ELLIPSIS) // includes '\0'
40
41/**********************
42 * MACROS
43 **********************/
44
45/**********************
46 * TYPEDEFS
47 **********************/
48
49/**********************
50 * VARIABLES
51 **********************/
52
57static nbgl_layoutInternal_t gLayout[NB_MAX_LAYOUTS] = {0};
58
59/**********************
60 * STATIC PROTOTYPES
61 **********************/
62
63static void buttonCallback(nbgl_screen_t *screen, nbgl_buttonEvent_t buttonEvent)
64{
65 uint8_t i = NB_MAX_LAYOUTS;
66 nbgl_layoutInternal_t *layout = NULL;
67
68 // parse all layouts (starting with modals) to find the object
69 while (i > 0) {
70 i--;
71 if ((screen->index == gLayout[i].layer) && (gLayout[i].nbChildren > 0)) {
72 // found
73 layout = &gLayout[i];
74 break;
75 }
76 }
77 if (layout == NULL) {
80 "touchCallback(): screen->index = %d, buttonEvent = %d, no matching active layout\n",
81 screen->index,
82 buttonEvent);
83 return;
84 }
85
86#ifdef NBGL_KEYPAD
87 // special case of keypad
89 if (kpd) {
90 nbgl_keypadCallback(kpd, buttonEvent);
91 return;
92 }
93 else
94#endif // NBGL_KEYPAD
95#ifdef NBGL_KEYBOARD
96 {
98 if (kbd) {
99 nbgl_keyboardCallback(kbd, buttonEvent);
100 return;
101 }
102 }
103#endif // NBGL_KEYBOARD
104 if (layout->callback != NULL) {
105 layout->callback((nbgl_layout_t *) layout, buttonEvent);
106 }
107}
108
109/**********************
110 * GLOBAL FUNCTIONS
111 **********************/
112
120{
121 if (layout->nbChildren == NB_MAX_SCREEN_CHILDREN) {
122 LOG_FATAL(LAYOUT_LOGGER, "layoutAddObject(): No more object\n");
123 }
124 layout->children[layout->nbChildren] = obj;
125 layout->nbChildren++;
126}
127
135{
136 nbgl_layoutInternal_t *layout = NULL;
137
138 // find an empty layout in the proper "layer"
139 if (description->modal) {
140 if (gLayout[1].nbChildren == 0) {
141 layout = &gLayout[1];
142 }
143 else if (gLayout[2].nbChildren == 0) {
144 layout = &gLayout[2];
145 }
146 }
147 else {
148 // automatically "release" a potentially opened non-modal layout
149 gLayout[0].nbChildren = 0;
150 layout = &gLayout[0];
151 }
152 if (layout == NULL) {
153 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutGet(): impossible to get a layout!\n");
154 return NULL;
155 }
156
157 // reset globals
158 memset(layout, 0, sizeof(nbgl_layoutInternal_t));
159
160 layout->callback = (nbgl_layoutButtonCallback_t) PIC(description->onActionCallback);
161 layout->modal = description->modal;
162 if (description->modal) {
163 layout->layer = nbgl_screenPush(&layout->children,
165 &description->ticker,
166 (nbgl_buttonCallback_t) buttonCallback);
167 }
168 else {
169 nbgl_screenSet(&layout->children,
171 &description->ticker,
172 (nbgl_buttonCallback_t) buttonCallback);
173 layout->layer = 0;
174 }
175
176 return (nbgl_layout_t *) layout;
177}
178
186int nbgl_layoutAddNavigation(nbgl_layout_t *layout, nbgl_layoutNavigation_t *info)
187{
188 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
189
190 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddNavigation():\n");
191 if (layout == NULL) {
192 return -1;
193 }
194
195 nbgl_image_t *image;
196 if (info->indication & LEFT_ARROW) {
197 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
198 image->foregroundColor = WHITE;
199 image->buffer = (info->direction == HORIZONTAL_NAV) ? &C_icon_left : &C_icon_up;
200 image->obj.area.bpp = NBGL_BPP_1;
201 image->obj.alignment = MID_LEFT;
202 layoutAddObject(layoutInt, (nbgl_obj_t *) image);
203 }
204 if (info->indication & RIGHT_ARROW) {
205 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
206 image->foregroundColor = WHITE;
207 image->buffer = (info->direction == HORIZONTAL_NAV) ? &C_icon_right : &C_icon_down;
208 image->obj.area.bpp = NBGL_BPP_1;
209 image->obj.alignment = MID_RIGHT;
210 layoutAddObject(layoutInt, (nbgl_obj_t *) image);
211 }
212 return 0;
213}
214
226 const char *text,
227 const char *subText,
229{
230 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
231 nbgl_container_t *container;
232 nbgl_text_area_t *textArea;
233 uint16_t fullHeight = 0;
234
235 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddText():\n");
236 if (layout == NULL) {
237 return -1;
238 }
239 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
240
241 // get container children
242 container->nbChildren = 1;
243 if (subText != NULL) {
244 container->nbChildren += 2; // possibly 2 buttons
245 }
246
247 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
248 container->obj.area.width = AVAILABLE_WIDTH;
249
250 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
251 textArea->textColor = WHITE;
252 textArea->text = PIC(text);
253 textArea->textAlignment = CENTER;
254 textArea->fontId = (style == REGULAR_INFO) ? BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
256 textArea->obj.area.width = AVAILABLE_WIDTH;
257
258 uint16_t nbLines
259 = nbgl_getTextNbLinesInWidth(textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
260 // if more than available lines on screen
261 if (nbLines > NB_MAX_LINES) {
262 uint16_t len;
263
264 nbLines = NB_MAX_LINES;
265 textArea->nbMaxLines = NB_MAX_LINES;
267 textArea->fontId, textArea->text, AVAILABLE_WIDTH, nbLines, &len, true);
268 textArea->len = len;
269 }
270 const nbgl_font_t *font = nbgl_getFont(textArea->fontId);
271 textArea->obj.area.height = nbLines * font->line_height;
272 textArea->wrapping = true;
273 textArea->obj.alignment = TOP_MIDDLE;
274 fullHeight += textArea->obj.area.height;
275 container->children[0] = (nbgl_obj_t *) textArea;
276
277 if (subText != NULL) {
278 if (style != BUTTON_INFO) {
279 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
280 textArea->textColor = WHITE;
281 textArea->text = PIC(subText);
282 textArea->wrapping = true;
283 textArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
284 textArea->obj.area.width = AVAILABLE_WIDTH;
286 textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
287 // if more than available lines on screen
288 if (nbLines > (NB_MAX_LINES - 1)) {
289 uint16_t len;
290 nbLines = NB_MAX_LINES - 1;
291 textArea->nbMaxLines = nbLines;
293 textArea->fontId, textArea->text, AVAILABLE_WIDTH, nbLines, &len, true);
294 textArea->len = len;
295 }
296 if (style == REGULAR_INFO) {
297 textArea->obj.area.height = nbLines * font->line_height;
298 }
299 else {
300 // the sub text must be vertically centered in a 3 lines container
301 textArea->obj.area.height = 3 * font->line_height;
302 }
303 textArea->textAlignment = CENTER;
304 textArea->obj.alignment = NO_ALIGNMENT;
305 textArea->obj.alignmentMarginY = 2;
306 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
307 container->children[1] = (nbgl_obj_t *) textArea;
308 }
309 else {
310 nbgl_button_t *button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
311 uint16_t textWidth;
312 uint16_t len = 0;
313 uint16_t width = 0;
314
315 button->foregroundColor = BLACK;
316 button->innerColor = WHITE;
317 button->borderColor = WHITE;
318 button->radius = RADIUS_3_PIXELS;
319 button->text = (const char *) PIC(subText);
321 button->obj.area.height = 14;
322 button->obj.alignment = CENTER;
323
324 textWidth = nbgl_getTextWidth(button->fontId, button->text);
325 if ((textWidth + BUTTON_MARGIN_Y) >= AVAILABLE_WIDTH) {
326 static char tmpString[NB_MAX_CHAR_IN_LINE];
327 nbgl_getTextMaxLenAndWidth(button->fontId,
328 button->text,
329 AVAILABLE_WIDTH - BUTTON_MARGIN_Y,
330 &len,
331 &width,
332 true);
333 button->obj.area.width = width + BUTTON_MARGIN_Y;
334 // copy the first 'len' chars in the tmp string buffer (max is
335 // NB_MAX_CHAR_IN_LINE-1)
336 memcpy(tmpString, button->text, MIN(len, (NB_MAX_CHAR_IN_LINE - 1)));
337 // NULL termination
338 tmpString[MIN(len, (NB_MAX_CHAR_IN_LINE - 1))] = '\0';
339 button->text = PIC(tmpString);
340 button->obj.alignmentMarginY = 8 - 7;
341 }
342 else {
343 button->obj.area.width = textWidth + BUTTON_MARGIN_Y;
344 button->obj.alignmentMarginY = 8;
345 }
346 container->children[1] = (nbgl_obj_t *) button;
347
348 // if too long text, draw a second button under the first one, with the remaining text
349 if (width > 0) {
350 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layoutInt->layer);
351 button->foregroundColor = BLACK;
352 button->innerColor = WHITE;
353 button->borderColor = WHITE;
354 button->radius = RADIUS_3_PIXELS;
355 button->text = (const char *) PIC(subText) + len;
357 button->obj.area.height = 14;
358 button->obj.alignment = CENTER;
359 button->obj.alignmentMarginY = 8 + 7;
360 textWidth = nbgl_getTextWidth(button->fontId, button->text);
361 if ((textWidth + BUTTON_MARGIN_Y) >= AVAILABLE_WIDTH) {
362 static char tmpString2[NB_MAX_CHAR_IN_LINE];
363 const uint16_t ellipsisWidth = nbgl_getTextWidth(button->fontId, ELLIPSIS);
364 nbgl_getTextMaxLenAndWidth(button->fontId,
365 button->text,
366 AVAILABLE_WIDTH - BUTTON_MARGIN_Y - ellipsisWidth,
367 &len,
368 &width,
369 true);
370 button->obj.area.width = width + ellipsisWidth + BUTTON_MARGIN_Y;
371 // copy the first 'len' chars then append ELLIPSIS (ELLIPSIS_SIZE includes '\0')
372 uint16_t copyLen = MIN(len, (NB_MAX_CHAR_IN_LINE - ELLIPSIS_SIZE));
373 memcpy(tmpString2, button->text, copyLen);
374 memcpy(tmpString2 + copyLen, ELLIPSIS, ELLIPSIS_SIZE);
375 button->text = PIC(tmpString2);
376 }
377 else {
378 button->obj.area.width = textWidth + BUTTON_MARGIN_Y;
379 }
380 container->children[2] = (nbgl_obj_t *) button;
381 }
382
383 fullHeight += 44;
384 }
385 }
386 container->obj.area.height = fullHeight;
387 container->layout = VERTICAL;
388 container->obj.alignment = CENTER;
389 // set this new obj as child of main container
390 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
391
392 return 0;
393}
394
403int nbgl_layoutAddMenuList(nbgl_layout_t *layout, nbgl_layoutMenuList_t *list)
404{
405 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
406 uint8_t i;
407
408 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddMenuList():\n");
409 if (layout == NULL) {
410 return -1;
411 }
412 for (i = 0; i < list->nbChoices; i++) {
413 nbgl_text_area_t *textArea;
414
415 // check whether this object is visible or not
416 // only the two objects above or below the selected one are visible
417 if (((list->selectedChoice > 2) && (i < (list->selectedChoice - 2)))
418 || (i > (list->selectedChoice + 2))) {
419 continue;
420 }
421
422 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
423
424 // init text area for this choice
425 textArea->text = list->callback(i);
426 textArea->textAlignment = CENTER;
427 textArea->obj.area.width = AVAILABLE_WIDTH;
428 textArea->obj.area.height = 16;
429 textArea->style = NO_STYLE;
430 textArea->obj.alignment = CENTER;
431 textArea->obj.alignmentMarginY = ((i - list->selectedChoice) * 16);
432 textArea->textColor = WHITE;
433
434 // highlight init choice
435 if (i == list->selectedChoice) {
437 }
438 else {
439 textArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
440 }
441
442 // set this new obj as child of main container
443 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
444 }
445
446 return 0;
447}
448
458{
459 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
460 nbgl_container_t *container;
461 nbgl_text_area_t *textArea = NULL;
462 nbgl_image_t *image = NULL;
463 uint16_t fullHeight = 0;
464
465 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddCenteredInfo():\n");
466 if (layout == NULL) {
467 return -1;
468 }
469
470 // When the caller asks for the icon to be at the screen bottom (and a
471 // primary text is provided), render the texts via nbgl_layoutAddText so
472 // the exact same geometry is used as on non-bottomIcon pages (sibling
473 // CHOICES_LIST entries reach the layout through nbgl_stepDrawText, which
474 // also calls nbgl_layoutAddText). The icon is then appended as a
475 // standalone BOTTOM_MIDDLE element. Falling back to the regular path
476 // when text1 is NULL keeps nbgl_layoutAddText's "main text mandatory"
477 // contract.
478 // Note: nbgl_layoutAddText always centers its container, so this branch
479 // ignores info->onTop — the combination bottomIcon=true && onTop=true is
480 // documented as incompatible on nbgl_contentCenteredInfo_t::bottomIcon.
481 if ((info->icon != NULL) && info->bottomIcon && (info->text1 != NULL)) {
482 // bottomIcon pages put the meaningful content in text1 (the icon is
483 // only a contextual hint at the bottom — selection marker, sub-menu
484 // chevron, ...). Force BOLD_TEXT1_INFO when only text1 is set so the
485 // primary content is visually prominent; when text2 is also set, keep
486 // the caller's style (BOLD_TEXT1_INFO is already implied by the
487 // standard drawStep style selection in that case).
489 if ((style == REGULAR_INFO) && (info->text2 == NULL)) {
490 style = BOLD_TEXT1_INFO;
491 }
492 nbgl_layoutAddText(layout, info->text1, info->text2, style);
493 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
494 image->foregroundColor = WHITE;
495 image->buffer = PIC(info->icon);
496 image->obj.area.bpp = NBGL_BPP_1;
497 image->obj.alignment = BOTTOM_MIDDLE;
498 image->obj.alignTo = NULL;
499 layoutAddObject(layoutInt, (nbgl_obj_t *) image);
500 return 0;
501 }
502
503 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
504
505 // 3 children at max
506 container->children = nbgl_containerPoolGet(3, layoutInt->layer);
507 container->nbChildren = 0;
508 if (info->icon != NULL) {
509 image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer);
510 image->foregroundColor = WHITE;
511 image->buffer = PIC(info->icon);
512 image->obj.area.bpp = NBGL_BPP_1;
513 image->obj.alignment = TOP_MIDDLE;
514 image->obj.alignTo = NULL;
515
516 fullHeight += image->buffer->height;
517 container->children[container->nbChildren] = (nbgl_obj_t *) image;
518 container->nbChildren++;
519 }
520 if (info->text1 != NULL) {
521 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
522 textArea->textColor = WHITE;
523 textArea->text = PIC(info->text1);
524 textArea->textAlignment = CENTER;
525 textArea->fontId = (info->style == REGULAR_INFO) ? BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
527 textArea->obj.area.width = AVAILABLE_WIDTH;
528 textArea->wrapping = true;
529 uint16_t nbLines
530 = nbgl_getTextNbLinesInWidth(textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
531 // if more than available lines on screen
532 if (nbLines > NB_MAX_LINES) {
533 uint16_t len;
534 nbLines = NB_MAX_LINES;
535 textArea->nbMaxLines = NB_MAX_LINES;
537 textArea->fontId, textArea->text, AVAILABLE_WIDTH, nbLines, &len, true);
538 textArea->len = len;
539 }
540 const nbgl_font_t *font = nbgl_getFont(textArea->fontId);
541 textArea->obj.area.height = nbLines * font->line_height;
542 textArea->style = NO_STYLE;
543 if (info->icon != NULL) {
544 textArea->obj.alignment = BOTTOM_MIDDLE; // under icon
545 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
546 textArea->obj.alignmentMarginY = (nbLines < 3) ? 4 : 0;
547 }
548 else if (info->text2 == NULL) {
549 textArea->obj.alignment = CENTER;
550 textArea->obj.alignTo = NULL;
551 }
552 else {
553 textArea->obj.alignment = TOP_MIDDLE;
554 textArea->obj.alignTo = NULL;
555 }
556
557 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
558
559 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
560 container->nbChildren++;
561 }
562 if (info->text2 != NULL) {
563 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
564 textArea->textColor = WHITE;
565 textArea->text = PIC(info->text2);
566 textArea->textAlignment = CENTER;
567 textArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
568 textArea->obj.area.width = AVAILABLE_WIDTH;
569 textArea->wrapping = true;
570 uint16_t nbLines
571 = nbgl_getTextNbLinesInWidth(textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
572 // if more than available lines on screen
573 if (nbLines > (NB_MAX_LINES - 1)) {
574 uint16_t len;
575 nbLines = NB_MAX_LINES - 1;
576 textArea->nbMaxLines = nbLines;
578 textArea->fontId, textArea->text, AVAILABLE_WIDTH, nbLines, &len, true);
579 textArea->len = len;
580 }
581 const nbgl_font_t *font = nbgl_getFont(textArea->fontId);
582 textArea->obj.area.height = nbLines * font->line_height;
583
584 textArea->style = NO_STYLE;
585 textArea->obj.alignment = BOTTOM_MIDDLE;
586 textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1];
587 textArea->obj.alignmentMarginY = 2;
588
589 fullHeight += textArea->obj.area.height + textArea->obj.alignmentMarginY;
590
591 container->children[container->nbChildren] = (nbgl_obj_t *) textArea;
592 container->nbChildren++;
593 }
594 container->obj.area.height = fullHeight;
595 container->layout = VERTICAL;
596 container->obj.alignmentMarginY = 0;
597 if (info->onTop) {
598 container->obj.alignment = TOP_MIDDLE;
599 }
600 else {
601 container->obj.alignment = CENTER;
602 }
603
604 container->obj.area.width = AVAILABLE_WIDTH;
605
606 // set this new container as child of main container
607 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
608
609 return 0;
610}
611
621{
622 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
623 nbgl_progress_bar_t *progress;
624
625 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddProgressBar():\n");
626 if (layout == NULL) {
627 return -1;
628 }
629 if (barLayout->text != NULL) {
630 nbgl_text_area_t *textArea;
631
633 ((nbgl_layoutInternal_t *) layout)->layer);
634 textArea->textColor = WHITE;
635 textArea->text = PIC(barLayout->text);
636 textArea->textAlignment = CENTER;
637 textArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
638 textArea->obj.area.width = AVAILABLE_WIDTH;
639 textArea->obj.area.height = nbgl_getTextHeight(textArea->fontId, textArea->text);
640 textArea->obj.alignment = TOP_MIDDLE;
641 textArea->obj.alignmentMarginX = 0;
642 textArea->obj.alignmentMarginY = 16; // 16 px from top
643 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
644 }
646 ((nbgl_layoutInternal_t *) layout)->layer);
647 progress->foregroundColor = WHITE;
648 progress->withBorder = true;
649 progress->state = barLayout->percentage;
650 progress->obj.area.width = 102;
651 progress->obj.area.height = 14;
652 progress->obj.alignment = TOP_MIDDLE;
653 progress->obj.alignmentMarginX = 0;
654 progress->obj.alignmentMarginY = 33; // 33px from top
655 layoutAddObject(layoutInt, (nbgl_obj_t *) progress);
656
657 if (barLayout->subText != NULL) {
658 nbgl_text_area_t *subTextArea;
659
660 subTextArea = (nbgl_text_area_t *) nbgl_objPoolGet(
661 TEXT_AREA, ((nbgl_layoutInternal_t *) layout)->layer);
662 subTextArea->textColor = WHITE;
663 subTextArea->text = PIC(barLayout->subText);
664 subTextArea->textAlignment = CENTER;
665 subTextArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
666 subTextArea->obj.area.width = AVAILABLE_WIDTH;
667 subTextArea->obj.area.height = nbgl_getTextHeight(subTextArea->fontId, subTextArea->text);
668 subTextArea->obj.alignment = BOTTOM_MIDDLE;
669 subTextArea->obj.alignTo = (nbgl_obj_t *) progress;
670 subTextArea->obj.alignmentMarginX = 0;
671 subTextArea->obj.alignmentMarginY = 4;
672 layoutAddObject(layoutInt, (nbgl_obj_t *) subTextArea);
673 }
674
675 return 0;
676}
677
685int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *buttonInfo)
686{
687 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
688 nbgl_button_t *button;
689
690 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddButton():\n");
691 if (layout == NULL) {
692 return -1;
693 }
694 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, ((nbgl_layoutInternal_t *) layout)->layer);
695 button->foregroundColor = BLACK;
696 button->innerColor = WHITE;
697 button->borderColor = WHITE;
698 button->radius = RADIUS_3_PIXELS;
699 button->text = (const char *) PIC(buttonInfo->text);
701 button->icon = (const nbgl_icon_details_t *) PIC(buttonInfo->icon);
702 button->obj.area.width = nbgl_getTextWidth(button->fontId, button->text) + BUTTON_MARGIN_Y;
703 button->obj.area.height = 14;
704 layoutAddObject(layoutInt, (nbgl_obj_t *) button);
705
706 return 0;
707}
708
716int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
717{
718 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
719 nbgl_button_t *button;
720 nbgl_text_area_t *textArea;
721
722 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSwitch():\n");
723 if (layout == NULL) {
724 return -1;
725 }
726 // add switch name as title
727 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
728 textArea->textColor = WHITE;
729 textArea->text = PIC(switchLayout->text);
730 textArea->textAlignment = CENTER;
732 textArea->obj.area.width = AVAILABLE_WIDTH;
733 textArea->wrapping = true;
734 uint16_t nbLines
735 = nbgl_getTextNbLinesInWidth(textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
736 // if more than 1 line on screen
737 if (nbLines > 1) {
738 // TODO: warning for screenshots
739 return -1;
740 }
741 textArea->obj.area.height = nbgl_getFontLineHeight(textArea->fontId);
742 textArea->obj.alignment = TOP_MIDDLE;
743 textArea->obj.alignmentMarginY = 3;
744 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
745
746 if (switchLayout->subText != NULL) {
747 // add switch description
748 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
749 textArea->textColor = WHITE;
750 textArea->text = PIC(switchLayout->subText);
751 textArea->textAlignment = CENTER;
752 textArea->fontId = BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp;
753 textArea->obj.area.width = AVAILABLE_WIDTH;
754 textArea->obj.area.height = 2 * nbgl_getFontLineHeight(textArea->fontId);
755 textArea->wrapping = true;
756 nbLines
757 = nbgl_getTextNbLinesInWidth(textArea->fontId, textArea->text, AVAILABLE_WIDTH, true);
758 // if more than 2 lines on screen
759 if (nbLines > 2) {
760 // TODO: warning for screenshots
761 return -1;
762 }
763 textArea->obj.alignment = CENTER;
764 textArea->obj.alignmentMarginY = 1; // not exactly centered
765 layoutAddObject(layoutInt, (nbgl_obj_t *) textArea);
766 }
767
768 button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, ((nbgl_layoutInternal_t *) layout)->layer);
769 button->foregroundColor = BLACK;
770 button->innerColor = WHITE;
771 button->borderColor = WHITE;
772 button->radius = RADIUS_3_PIXELS;
773 button->text = (switchLayout->initState == ON_STATE) ? "Enabled" : "Disabled";
775 button->icon = (switchLayout->initState == ON_STATE) ? &C_Switch_On_8px : &C_Switch_Off_8px;
776 // 2 pixels between icon & text, and 4 pixels on each side
777 button->obj.area.width
778 = nbgl_getTextWidth(button->fontId, button->text) + 2 + C_Switch_Off_8px.width + 8;
779 button->obj.area.height = 12;
780 button->obj.alignment = BOTTOM_MIDDLE;
781 button->obj.alignmentMarginY = 3;
782 layoutAddObject(layoutInt, (nbgl_obj_t *) button);
783
784 return 0;
785}
786
793int nbgl_layoutDraw(nbgl_layout_t *layoutParam)
794{
795 nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
796
797 if (layout == NULL) {
798 return -1;
799 }
800 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutDraw(): layout->nbChildren = %d\n", layout->nbChildren);
802
803 return 0;
804}
805
812int nbgl_layoutRelease(nbgl_layout_t *layoutParam)
813{
814 nbgl_layoutInternal_t *layout = (nbgl_layoutInternal_t *) layoutParam;
815 LOG_DEBUG(PAGE_LOGGER, "nbgl_layoutRelease(): \n");
816 if (layout == NULL) {
817 return -1;
818 }
819 // if modal
820 if (layout->modal) {
821 nbgl_screenPop(layout->layer);
822 }
823 layout->nbChildren = 0;
824 return 0;
825}
826#endif // HAVE_SE_TOUCH
Random Number Generation.
nbgl_contentCenteredInfoStyle_t
possible styles for Centered Info Area
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
#define LOG_FATAL(__logger,...)
Definition nbgl_debug.h:88
@ LAYOUT_LOGGER
Definition nbgl_debug.h:33
@ PAGE_LOGGER
Definition nbgl_debug.h:34
Middle Level API of the new BOLOS Graphical Library.
void nbgl_getTextMaxLenAndWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t *len, uint16_t *width, bool wrapping)
bool nbgl_getTextMaxLenInNbLines(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t maxNbLines, uint16_t *len, bool wrapping)
@ BAGL_FONT_OPEN_SANS_REGULAR_11px_1bpp
Definition nbgl_fonts.h:150
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:148
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
const nbgl_font_t * nbgl_getFont(nbgl_font_id_e fontId)
uint16_t nbgl_getTextHeight(nbgl_font_id_e fontId, const char *text)
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
Font screen low-Level driver API, to draw elementary forms.
#define NB_MAX_LAYOUTS
Definition nbgl_layout.c:41
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the main container
#define NB_MAX_LINES
@ HORIZONTAL_NAV
'<' and '>' are displayed, to navigate between pages and steps
int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText)
Creates an area with given text (in bold) and sub text (in regular)
@ LEFT_ARROW
left arrow is used
@ RIGHT_ARROW
right arrow is used
int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredInfo_t *info)
Creates an area on the center of the main panel, with a possible icon/image, a possible text in black...
int nbgl_layoutDraw(nbgl_layout_t *layout)
Applies given layout. The screen will be redrawn.
#define AVAILABLE_WIDTH
void * nbgl_layout_t
type shared externally
int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout)
Creates a switch with the given text and its state.
int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *buttonInfo)
Creates a rounded button in the main container.
nbgl_layout_t * nbgl_layoutGet(const nbgl_layoutDescription_t *description)
returns a layout of the given type. The layout is reset
int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const char *text, const char *subText, uint8_t percentage)
Creates an area in main panel to display a progress bar, with a title text and a subtext if needed.
void(* nbgl_layoutButtonCallback_t)(nbgl_layout_t *layout, nbgl_buttonEvent_t event)
prototype of function to be called when buttons are touched on a screen
int nbgl_layoutRelease(nbgl_layout_t *layout)
Release the layout obtained with nbgl_layoutGet()
@ NB_MAX_SCREEN_CHILDREN
Internal functions/constants of NBGL layout layer.
API to draw all basic graphic objects.
struct PACKED__ nbgl_text_area_s nbgl_text_area_t
struct to represent a text area (TEXT_AREA type)
struct PACKED__ nbgl_progress_bar_s nbgl_progress_bar_t
struct to represent a progress bar (PROGRESS_BAR type)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
nbgl_buttonEvent_t
Definition nbgl_obj.h:315
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
struct PACKED__ nbgl_button_s nbgl_button_t
struct to represent a button (BUTTON type) that can contain a text and/or an icon
void(* nbgl_buttonCallback_t)(void *obj, nbgl_buttonEvent_t buttonEvent)
prototype of function to be called when a button event is received by an object (TODO: change to scre...
Definition nbgl_obj.h:333
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
int nbgl_screenSet(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t touchCallback)
int nbgl_screenPush(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t touchCallback)
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
int nbgl_screenPop(uint8_t screenIndex)
nbgl_obj_t * nbgl_screenContainsObjType(nbgl_screen_t *screen, nbgl_obj_type_t type)
void nbgl_screenRedraw(void)
@ WHITE
Definition nbgl_types.h:144
@ BLACK
Definition nbgl_types.h:141
@ ON_STATE
Definition nbgl_types.h:201
@ VERTICAL
from top to bottom
Definition nbgl_types.h:209
#define MIN(x, y)
Definition nbgl_types.h:118
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
@ TOP_MIDDLE
Definition nbgl_types.h:182
@ CENTER
Definition nbgl_types.h:185
@ NO_ALIGNMENT
used when parent container layout is used
Definition nbgl_types.h:180
@ MID_RIGHT
Definition nbgl_types.h:186
@ MID_LEFT
Definition nbgl_types.h:184
@ BOTTOM_MIDDLE
Definition nbgl_types.h:188
@ KEYPAD
Keypad.
Definition nbgl_types.h:167
@ 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
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
Definition nbgl_types.h:163
@ 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
@ NBGL_BPP_1
1 bit per pixel
Definition nbgl_types.h:283
@ NO_STYLE
no border
Definition nbgl_types.h:218
This structure contains info to build a centered (vertically and horizontally) area,...
const char * text2
second text (can be null)
const char * text1
first text (can be null)
bool onTop
if set to true, align only horizontally
nbgl_contentCenteredInfoStyle_t style
style to apply to this info
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon
This structure contains info to build a switch (on the right) with a description (on the left),...
const char * text
main text for the switch
nbgl_state_t initState
initial state of the switch
const char * subText
description under main text (NULL terminated, single line, may be null)
structure defining an ASCII font
Definition nbgl_fonts.h:86
uint8_t line_height
height of a line for all characters in pixels
Definition nbgl_fonts.h:91
This structure contains info to build a single button.
const char * text
button text
const nbgl_icon_details_t * icon
a buffer containing the 1BPP icon for button
Structure containing all information when creating a layout. This structure must be passed as argumen...
nbgl_screenTickerConfiguration_t ticker
nbgl_layoutTouchCallback_t onActionCallback
the callback to be called on any action on the layout
Structure containing all information about the current layout.
uint8_t layer
layer in screen stack
nbgl_layoutTouchCallback_t callback
user callback for all controls
uint8_t nbChildren
number of children in above array
uint8_t modal
if true, means the screen is a modal
nbgl_obj_t ** children
children for main screen
This structure contains a list of names to build a menu list on Nanos, with for each item a descripti...
nbgl_menuListCallback_t callback
function to call to retrieve a menu list item text
uint8_t nbChoices
total number of choices in the menu list
uint8_t selectedChoice
index of the selected choice (centered, in bold)
This structure contains info to build a navigation bar at the bottom of the screen.
nbgl_layoutNavDirection_t direction
vertical or horizontal navigation
nbgl_layoutNavIndication_t indication
specifies which arrows to use (left or right)
This structure contains info to build a progress bar with info. The progress bar itself is 120px widt...
uint8_t percentage
percentage of completion, from 0 to 100.
const char * text
text in black, on top of progress bar
const char * subText
text in gray, under progress bar