11#include "app_config.h"
19#include "os_helpers.h"
23#include "os_io_seph_ux.h"
24#ifdef HAVE_SERIALIZED_NBGL
27#ifdef BUILD_SCREENSHOTS
28#include "json_scenario.h"
35#define NB_MAX_LETTERS 9
37#if defined(TARGET_STAX)
38#define INTER_DASHES 10
39#define SPINNER_DASH_WIDTH 22
40#define SPINNER_DASH_HEIGHT 14
41#define SPINNER_DASH_STROKE 4
42#define PROGRESS_STROKE 3
43#elif defined(TARGET_FLEX)
45#define SPINNER_DASH_WIDTH 24
46#define SPINNER_DASH_HEIGHT 16
47#define SPINNER_DASH_STROKE 4
48#define PROGRESS_STROKE 3
49#elif defined(TARGET_APEX)
51#define SPINNER_DASH_WIDTH 15
52#define SPINNER_DASH_HEIGHT 10
53#define SPINNER_DASH_STROKE 2
54#define PROGRESS_STROKE 2
75 bool computePosition);
105static bool objDrawingDisabled;
108static bool objRefreshAreaDone;
148#ifdef BUILD_SCREENSHOTS
150extern uint16_t last_nb_lines, last_nb_pages;
151extern bool last_bold_state, verbose;
170 "compute_relativePosition() without align to, parent->layout = %d, prevObj = %p\n",
175 obj->rel_x0 = obj->alignmentMarginX;
176 if (prevObj != NULL) {
177 obj->rel_y0 = prevObj->rel_y0 + prevObj->area.height + obj->alignmentMarginY;
180 obj->rel_y0 = obj->alignmentMarginY;
184 if (prevObj != NULL) {
185 obj->rel_x0 = prevObj->rel_x0 + prevObj->area.width + obj->alignmentMarginX;
188 obj->rel_x0 = obj->alignmentMarginX;
190 obj->rel_y0 = obj->alignmentMarginY;
195 if (alignToObj == NULL) {
196 alignToObj = obj->parent;
203 if (alignToObj == obj->parent) {
205 switch (obj->alignment) {
207 obj->rel_x0 = obj->alignmentMarginX;
208 obj->rel_y0 = obj->alignmentMarginY;
212 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
213 obj->rel_y0 = obj->alignmentMarginY;
217 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
218 obj->rel_y0 = obj->alignmentMarginY;
221 obj->rel_x0 = obj->alignmentMarginX;
223 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
227 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
229 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
233 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
235 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
238 obj->rel_x0 = obj->alignmentMarginX;
240 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
244 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
246 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
250 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
252 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
261 switch (obj->alignment) {
263 obj->rel_x0 = alignToObj->rel_x0 + obj->alignmentMarginX;
264 obj->rel_y0 = alignToObj->rel_y0 - obj->area.height - obj->alignmentMarginY;
267 obj->rel_x0 = alignToObj->rel_x0
268 + (alignToObj->area.width - obj->area.width) / 2
269 + obj->alignmentMarginX;
270 obj->rel_y0 = alignToObj->rel_y0 - obj->area.height - obj->alignmentMarginY;
273 obj->rel_x0 = alignToObj->rel_x0 + (alignToObj->area.width - obj->area.width)
274 - obj->alignmentMarginX;
275 obj->rel_y0 = alignToObj->rel_y0 - obj->area.height - obj->alignmentMarginY;
279 obj->rel_x0 = alignToObj->rel_x0 - obj->area.width - obj->alignmentMarginX;
280 obj->rel_y0 = alignToObj->rel_y0 + obj->alignmentMarginY;
283 obj->rel_x0 = alignToObj->rel_x0 - obj->area.width - obj->alignmentMarginX;
284 obj->rel_y0 = alignToObj->rel_y0
285 + (alignToObj->area.height - obj->area.height) / 2
286 + obj->alignmentMarginY;
289 obj->rel_x0 = alignToObj->rel_x0 - obj->area.width - obj->alignmentMarginX;
290 obj->rel_y0 = alignToObj->rel_y0 + (alignToObj->area.height - obj->area.height)
291 + obj->alignmentMarginY;
296 = alignToObj->rel_x0 + alignToObj->area.width + obj->alignmentMarginX;
297 obj->rel_y0 = alignToObj->rel_y0 + obj->alignmentMarginY;
301 = alignToObj->rel_x0 + alignToObj->area.width + obj->alignmentMarginX;
302 obj->rel_y0 = alignToObj->rel_y0
303 + (alignToObj->area.height - obj->area.height) / 2
304 + obj->alignmentMarginY;
308 = alignToObj->rel_x0 + alignToObj->area.width + obj->alignmentMarginX;
309 obj->rel_y0 = alignToObj->rel_y0 + (alignToObj->area.height - obj->area.height)
310 + obj->alignmentMarginY;
314 obj->rel_x0 = alignToObj->rel_x0 + obj->alignmentMarginX;
316 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
319 obj->rel_x0 = alignToObj->rel_x0
320 + (alignToObj->area.width - obj->area.width) / 2
321 + obj->alignmentMarginX;
323 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
326 obj->rel_x0 = alignToObj->rel_x0 + (alignToObj->area.width - obj->area.width)
327 - obj->alignmentMarginX;
329 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
343 compute_relativePosition(obj, prevObj);
345 if (parent == NULL) {
354 obj->area.x0 = parent->obj.area.x0 + obj->rel_x0;
355 obj->area.y0 = parent->obj.area.y0 + obj->rel_y0;
357 if ((obj->area.x0 + obj->area.width) > SCREEN_WIDTH) {
358#ifdef BUILD_SCREENSHOTS
359 obj->area.width = SCREEN_WIDTH - obj->area.x0;
361 if (!obj->area.width) {
367 "compute_position(), forbidden width, obj->type = %d, x0=%d, width=%d\n",
374 if ((obj->area.y0 + obj->area.height) > SCREEN_HEIGHT) {
375#ifdef BUILD_SCREENSHOTS
376 obj->area.height = SCREEN_HEIGHT - obj->area.y0;
378 if (!obj->area.height) {
379 obj->area.height = 1;
384 "compute_position(), forbidden height, obj->type = %d, y0=%d, height=%d\n",
398 UNUSED(computePosition);
400 rectArea.backgroundColor = obj->obj.area.backgroundColor;
401 rectArea.x0 = obj->obj.area.x0;
402 rectArea.y0 = obj->obj.area.y0;
403 rectArea.width = obj->obj.area.width;
404 rectArea.height = obj->obj.area.height;
410 if (computePosition) {
411 compute_position((
nbgl_obj_t *) obj, prevObj);
414 "draw_container(), x0 = %d, y0 = %d, width = %d, height = %d\n",
418 obj->obj.area.height);
420 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
421 if (obj->forceClean) {
437 uint16_t textWidth = 0;
438 const char *text = NULL;
439#define ICON_TEXT_SPACE 12
441 if (computePosition) {
442 compute_position((
nbgl_obj_t *) obj, prevObj);
445 "draw_button(), x0 = %d, y0 = %d, width = %d, height = %d\n",
449 obj->obj.area.height);
452 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
454 if ((obj->innerColor == obj->borderColor)
455 && (obj->innerColor != obj->obj.area.backgroundColor)) {
474 if (obj->onDrawCallback != NULL) {
475 obj->text = obj->onDrawCallback(obj->token);
482 rectArea.x0 = obj->obj.area.x0;
483 rectArea.y0 = obj->obj.area.y0;
486 rectArea.y0 += (obj->obj.area.height - rectArea.height) / 2;
487 rectArea.width = obj->obj.area.width;
488 if (obj->icon != NULL) {
496#ifdef BUILD_SCREENSHOTS
498 store_string_infos(text, obj->fontId, &obj->obj.area,
true, 1, 0,
false);
502 if (textWidth < rectArea.width) {
503 rectArea.x0 += (rectArea.width - textWidth) / 2;
506 rectArea.backgroundColor = obj->innerColor;
507 nbgl_drawText(&rectArea, text, textLen, obj->fontId, obj->foregroundColor);
509#ifdef BUILD_SCREENSHOTS
512 if ((obj->innerColor == obj->borderColor)
513 && (obj->innerColor != obj->obj.area.backgroundColor)) {
514 store_button_infos(&obj->obj.area);
519 if (obj->icon != NULL) {
520 uint16_t iconX0, iconY0;
524 iconX0 = obj->obj.area.x0
525 + (obj->obj.area.width - (textWidth + obj->icon->width +
ICON_TEXT_SPACE)) / 2;
528 iconX0 = obj->obj.area.x0 + (obj->obj.area.width - obj->icon->width) / 2;
531 "draw_button(), obj->obj.area.height = %d, obj->iconHeight = %d\n",
532 obj->obj.area.height,
534 iconY0 = obj->obj.area.y0 + (obj->obj.area.height - obj->icon->height) / 2;
536 rectArea.backgroundColor = obj->innerColor;
537 rectArea.x0 = iconX0;
538 rectArea.y0 = iconY0;
539 rectArea.width = obj->icon->width;
540 rectArea.height = obj->icon->height;
541 rectArea.bpp = obj->icon->bpp;
558 if (computePosition) {
559 compute_position((
nbgl_obj_t *) obj, prevObj);
561 LOG_DEBUG(
OBJ_LOGGER,
"draw_line(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
563 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
565 "draw_line(), backgroundColor = %d, lineColor = %d\n",
566 obj->obj.area.backgroundColor,
568 rectArea.x0 = obj->obj.area.x0;
569 rectArea.y0 = obj->obj.area.y0;
570 rectArea.backgroundColor = obj->obj.area.backgroundColor;
572 rectArea.width = obj->obj.area.width = obj->thickness;
573 rectArea.height = obj->obj.area.height;
577 rectArea.width = obj->obj.area.width;
578 rectArea.height = obj->obj.area.height = obj->thickness;
591static void draw_button(nbgl_button_t *obj, nbgl_obj_t *prevObj, bool computePosition)
593 uint16_t textWidth = 0;
594 const char *text = NULL;
595#define ICON_TEXT_SPACE 2
597 if (computePosition) {
598 compute_position((
nbgl_obj_t *) obj, prevObj);
601 "draw_button(), x0 = %d, y0 = %d, width = %d, height = %d\n",
605 obj->obj.area.height);
608 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
613 if (obj->onDrawCallback != NULL) {
614 obj->text = obj->onDrawCallback(obj->token);
621 rectArea.x0 = obj->obj.area.x0;
622 rectArea.y0 = obj->obj.area.y0;
625 rectArea.y0 += (obj->obj.area.height - rectArea.height) / 2;
626 rectArea.width = obj->obj.area.width;
627 if (obj->icon != NULL) {
636 if (textWidth < rectArea.width) {
637 rectArea.x0 += (rectArea.width - textWidth) / 2;
640 rectArea.backgroundColor = obj->innerColor;
641 nbgl_drawText(&rectArea, text, textLen, obj->fontId, obj->foregroundColor);
644 if (obj->icon != NULL) {
645 uint16_t iconX0, iconY0;
649 iconX0 = obj->obj.area.x0
650 + (obj->obj.area.width - (textWidth + obj->icon->width +
ICON_TEXT_SPACE)) / 2;
653 iconX0 = obj->obj.area.x0 + (obj->obj.area.width - obj->icon->width) / 2;
656 "draw_button(), obj->obj.area.height = %d, obj->iconHeight = %d\n",
657 obj->obj.area.height,
659 iconY0 = obj->obj.area.y0 + (obj->obj.area.height - obj->icon->height) / 2;
661 rectArea.backgroundColor = obj->innerColor;
662 rectArea.x0 = iconX0;
663 rectArea.y0 = iconY0;
664 rectArea.width = obj->icon->width;
665 rectArea.height = obj->icon->height;
666 rectArea.bpp = obj->icon->bpp;
679 if (obj->buffer == NULL) {
680 if (obj->onDrawCallback != NULL) {
681 iconDetails = obj->onDrawCallback(obj->token);
688 iconDetails = obj->buffer;
690 if (iconDetails == NULL) {
695 obj->obj.area.width = iconDetails->width;
696 obj->obj.area.height = iconDetails->height;
697 obj->obj.area.bpp = iconDetails->bpp;
698 if (computePosition) {
699 compute_position((
nbgl_obj_t *) obj, prevObj);
701 LOG_DEBUG(
OBJ_LOGGER,
"draw_image(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
703 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
705 colorMap = obj->foregroundColor;
711 colorMap = obj->foregroundColor;
723 obj->obj.area.width = SWITCH_ICON.width;
724 obj->obj.area.height = SWITCH_ICON.height;
725 if (computePosition) {
726 compute_position((
nbgl_obj_t *) obj, prevObj);
728 LOG_DEBUG(
OBJ_LOGGER,
"draw_switch(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
731 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
733 rectArea.x0 = obj->obj.area.x0;
734 rectArea.y0 = obj->obj.area.y0;
735 rectArea.width = obj->obj.area.width;
736 rectArea.height = obj->obj.area.height;
737 rectArea.backgroundColor = obj->obj.area.backgroundColor;
740#if NB_COLOR_BITS == 1
747#if NB_COLOR_BITS == 1
762 obj->obj.area.width = RADIO_WIDTH;
763 obj->obj.area.height = RADIO_HEIGHT;
764 if (computePosition) {
765 compute_position((
nbgl_obj_t *) obj, prevObj);
768 "draw_radioButton(), x0 = %d, y0 = %d, state = %d\n",
774 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
777 icon = &RADIO_OFF_ICON;
778#if NB_COLOR_BITS == 1
779 color_map = obj->activeColor;
781 color_map = obj->borderColor;
785 icon = &RADIO_ON_ICON;
786 color_map = obj->activeColor;
788 rectArea.x0 = obj->obj.area.x0;
789 rectArea.y0 = obj->obj.area.y0;
790 rectArea.width = obj->obj.area.width;
791 rectArea.height = obj->obj.area.height;
792 rectArea.backgroundColor = obj->obj.area.backgroundColor;
793 rectArea.bpp = icon->bpp;
809 uint8_t stroke = PROGRESS_STROKE;
811 uint16_t barWidth = ((obj->state * obj->obj.area.width)) / 100;
813 if (computePosition) {
814 compute_position((
nbgl_obj_t *) obj, prevObj);
817 "draw_progressBar(), x0 = %d, y0 = %d, level = %d %%\n",
821 memcpy(&barArea, &obj->obj.area,
sizeof(
nbgl_area_t));
824 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
826 if (obj->partialRedraw ==
false) {
828 if (obj->withBorder) {
832 obj->obj.area.backgroundColor,
833 obj->foregroundColor);
840 obj->previousWidth = 0;
841 if (obj->state == 0) {
846 int barDiffWith = barWidth - obj->previousWidth;
849 if (barDiffWith > 0) {
851 barArea.x0 = obj->obj.area.x0 + obj->previousWidth;
852 barArea.width = barDiffWith;
853 barColor = obj->foregroundColor;
855 else if (barDiffWith < 0) {
857 barArea.x0 = obj->obj.area.x0 + obj->previousWidth + barDiffWith;
858 barArea.width = -barDiffWith;
859 barColor = obj->obj.area.backgroundColor;
862 if (barDiffWith != 0) {
868 if (obj->partialRedraw ==
true) {
869 obj->partialRedraw =
false;
871 obj->previousWidth = barWidth;
874 extendRefreshArea(&barArea);
875 objRefreshAreaDone =
true;
880 if (computePosition) {
881 compute_position((
nbgl_obj_t *) obj, prevObj);
884 "draw_progressBar(), x0 = %d, y0 = %d, level = %d %%\n",
890 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
893 if (obj->withBorder) {
897 obj->obj.area.backgroundColor,
898 obj->foregroundColor);
904 levelWidth =
MIN((obj->obj.area.width - 2) * obj->state / 100, (obj->obj.area.width - 2));
905 if (levelWidth > 0) {
907 rectArea.width = levelWidth;
908 rectArea.height = obj->obj.area.height - 2;
909 rectArea.backgroundColor = obj->foregroundColor;
911 rectArea.x0 = obj->obj.area.x0 + 1;
912 rectArea.y0 = obj->obj.area.y0 + 1;
930 bool computePosition)
936 if (obj->nbPages < 2) {
943 obj->obj.area.height = 4;
945 if (computePosition) {
946 compute_position((
nbgl_obj_t *) obj, prevObj);
949 "draw_pageIndicator(), x0 = %d, y0 = %d, page = %d/%d\n",
956 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
958 dashWidth = (obj->obj.area.width - ((obj->nbPages - 1) * INTER_DASHES)) / obj->nbPages;
959 rectArea.x0 = obj->obj.area.x0;
960 rectArea.y0 = obj->obj.area.y0;
961 rectArea.width = dashWidth;
963 rectArea.backgroundColor = obj->obj.area.backgroundColor;
966 for (i = 0; i < obj->activePage; i++) {
969 rectArea.x0 += dashWidth + INTER_DASHES;
972 rectArea.x0 += dashWidth + INTER_DASHES;
975 for (; i < obj->nbPages; i++) {
977 rectArea.x0 += dashWidth + INTER_DASHES;
983 SPRINTF(navText,
"%d of %d", obj->activePage + 1, obj->nbPages);
989 if (computePosition) {
990 compute_position((
nbgl_obj_t *) obj, prevObj);
993 "draw_pageIndicator(), x0 = %d, y0 = %d, page = %d/%d\n",
1000 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1003 rectArea.x0 = obj->obj.area.x0;
1004 rectArea.y0 = obj->obj.area.y0;
1005 rectArea.width = obj->obj.area.width;
1006 rectArea.height = obj->obj.area.height;
1007 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1025 uint16_t textWidth, fontHeight, lineHeight, textHeight, midHeight;
1026 uint8_t line, nbLines;
1030 if (computePosition) {
1031 compute_position((
nbgl_obj_t *) obj, prevObj);
1034 if (obj->onDrawCallback != NULL) {
1035 obj->text = obj->onDrawCallback(obj->token);
1044 "draw_textArea(), wrapping = %d, x0 = %d, y0 = %d, width = %d, height = %d, text = %s\n",
1048 obj->obj.area.width,
1049 obj->obj.area.height,
1053 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1056#ifdef SCREEN_SIZE_NANO
1057 if (obj->style == INVERTED_COLORS) {
1058 obj->obj.area.backgroundColor =
WHITE;
1059 rectArea.backgroundColor =
BLACK;
1065 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1066 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1068 rectArea.x0 = obj->obj.area.x0;
1069 rectArea.y0 = obj->obj.area.y0;
1070 rectArea.width = obj->obj.area.width;
1071 rectArea.height = obj->obj.area.height;
1072#ifdef SCREEN_SIZE_NANO
1073 if (obj->style == INVERTED_COLORS) {
1086 if (obj->autoHideLongLine ==
true) {
1087#ifdef BUILD_SCREENSHOTS
1089 store_string_infos(text,
1098 if (textWidth > obj->obj.area.width) {
1099 uint16_t lineWidth, lineLen;
1103 rectArea.x0 = obj->obj.area.x0;
1104 rectArea.y0 = obj->obj.area.y0 + (obj->obj.area.height - fontHeight) / 2;
1105 rectArea.width = dotsWidth;
1109 fontId, text, obj->obj.area.width - dotsWidth, &lineLen, &lineWidth);
1110 rectArea.x0 += dotsWidth;
1111 rectArea.width = lineWidth;
1123#ifdef BUILD_SCREENSHOTS
1125 text, fontId, &obj->obj.area, obj->wrapping, last_nb_lines, last_nb_pages, last_bold_state);
1128 if ((obj->nbMaxLines > 0) && (obj->nbMaxLines < nbLines)) {
1129 nbLines = obj->nbMaxLines;
1132 textHeight = (nbLines - 1) * lineHeight + fontHeight;
1134 midHeight = (obj->obj.area.height - textHeight) / 2;
1135#ifdef SCREEN_SIZE_NANO
1136 if (obj->style == INVERTED_COLORS) {
1141 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1142 rectArea.height = fontHeight;
1144 for (line = 0; line < nbLines; line++) {
1145 uint16_t lineWidth, lineLen;
1148 fontId, text, obj->obj.area.width, &lineLen, &lineWidth, obj->wrapping);
1149 if (obj->textAlignment ==
MID_LEFT) {
1150 rectArea.x0 = obj->obj.area.x0;
1152 else if (obj->textAlignment ==
CENTER) {
1153 rectArea.x0 = obj->obj.area.x0 + (obj->obj.area.width - lineWidth) / 2;
1155 else if (obj->textAlignment ==
MID_RIGHT) {
1156 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - lineWidth;
1161 rectArea.y0 = obj->obj.area.y0 + midHeight + line * lineHeight;
1162 rectArea.width = lineWidth;
1165 "draw_textArea(), [%s] line %d, lineLen %d lineWidth = %d, obj.area.height = %d, "
1166 "textHeight = %d, nbMaxLines = %d, wrapping = %d\n",
1171 obj->obj.area.height,
1175 if ((obj->nbMaxLines == 0) || (line < (obj->nbMaxLines - 1))) {
1176 fontId =
nbgl_drawText(&rectArea, text, lineLen, fontId, obj->textColor);
1182 if (text[lineLen] !=
'\n') {
1184 if ((lineWidth + dotsWidth) >= obj->obj.area.width) {
1187 nbgl_drawText(&rectArea, text, lineLen, obj->fontId, obj->textColor);
1191 rectArea.width = dotsWidth;
1192 nbgl_drawText(&rectArea,
"...", 3, obj->fontId, obj->textColor);
1195 nbgl_drawText(&rectArea, text, lineLen, obj->fontId, obj->textColor);
1198 nbgl_drawText(&rectArea, text, lineLen, fontId, obj->textColor);
1204 if (*text ==
'\n') {
1223 if (computePosition) {
1224 compute_position((
nbgl_obj_t *) obj, prevObj);
1227 obj->obj.area.y0 &= ~0x3;
1229 "draw_qrCode(), x0 = %d, y0 = %d, width = %d, height = %d, text = %s\n",
1232 obj->obj.area.width,
1233 obj->obj.area.height,
1237 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1239 rectArea.x0 = obj->obj.area.x0;
1240 rectArea.y0 = obj->obj.area.y0;
1241 rectArea.width = obj->obj.area.width;
1242 rectArea.height = obj->obj.area.height;
1243 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1244 nbgl_drawQrCode(&rectArea, obj->version, obj->text, obj->foregroundColor);
1258#ifndef HAVE_SE_TOUCH
1259 obj->obj.area.width = KEYBOARD_WIDTH;
1260 obj->obj.area.height = KEYBOARD_KEY_HEIGHT;
1263 if (computePosition) {
1264 compute_position((
nbgl_obj_t *) obj, prevObj);
1267 OBJ_LOGGER,
"draw_keyboard(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1270 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1286#ifndef HAVE_SE_TOUCH
1287 obj->obj.area.height = KEYPAD_HEIGHT;
1288 obj->obj.area.width = KEYPAD_WIDTH;
1291 if (computePosition) {
1292 compute_position((
nbgl_obj_t *) obj, prevObj);
1294 obj->obj.area.y0 &= ~0x3;
1295 LOG_DEBUG(
OBJ_LOGGER,
"draw_keypad(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1298 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1317 obj->obj.area.width = SPINNER_WIDTH;
1318 obj->obj.area.height = SPINNER_HEIGHT;
1320 if (computePosition) {
1321 compute_position((
nbgl_obj_t *) obj, prevObj);
1323 LOG_DEBUG(
OBJ_LOGGER,
"draw_spinner(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1326 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1331 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1333 if (obj->position == 0xFF) {
1335 rectArea.x0 = obj->obj.area.x0;
1336 rectArea.y0 = obj->obj.area.y0;
1337 rectArea.width = SPINNER_DASH_WIDTH;
1338 rectArea.height = SPINNER_DASH_STROKE;
1340 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1342 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1344 rectArea.x0 = obj->obj.area.x0;
1347 rectArea.x0 = obj->obj.area.x0;
1348 rectArea.y0 = obj->obj.area.y0;
1349 rectArea.width = SPINNER_DASH_STROKE;
1350 rectArea.height = SPINNER_DASH_HEIGHT;
1352 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1354 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1356 rectArea.x0 = obj->obj.area.x0;
1361 rectArea.x0 = obj->obj.area.x0;
1362 rectArea.y0 = obj->obj.area.y0;
1363 rectArea.width = obj->obj.area.width;
1364 rectArea.height = obj->obj.area.height;
1365 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1369 rectArea.width = SPINNER_DASH_WIDTH;
1370 rectArea.height = SPINNER_DASH_STROKE;
1371 switch (obj->position) {
1373 rectArea.x0 = obj->obj.area.x0;
1374 rectArea.y0 = obj->obj.area.y0;
1377 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1378 rectArea.y0 = obj->obj.area.y0;
1381 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1382 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - 3;
1385 rectArea.x0 = obj->obj.area.x0;
1386 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - 3;
1394 rectArea.width = SPINNER_DASH_STROKE;
1395 rectArea.height = SPINNER_DASH_HEIGHT;
1396 rectArea.backgroundColor = foreColor;
1397 switch (obj->position) {
1399 rectArea.x0 = obj->obj.area.x0;
1400 rectArea.y0 = obj->obj.area.y0;
1403 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1404 rectArea.y0 = obj->obj.area.y0;
1407 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1408 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1411 rectArea.x0 = obj->obj.area.x0;
1412 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1433 int textLen = strlen(obj->text);
1436 if (computePosition) {
1437 compute_position((
nbgl_obj_t *) obj, prevObj);
1441 "draw_textEntry(), x0 = %d, y0 = %d, width = %d, height = %d\n",
1444 obj->obj.area.width,
1445 obj->obj.area.height);
1448 obj->obj.area.backgroundColor =
WHITE;
1449 rectArea.backgroundColor =
BLACK;
1450 rectArea.x0 = obj->obj.area.x0;
1451 rectArea.y0 = obj->obj.area.y0;
1452 rectArea.width = obj->obj.area.width;
1453 rectArea.height = obj->obj.area.height;
1457 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1462 offsetX = (obj->obj.area.width - (obj->nbChars * 10)) / 2;
1464 for (
int i = 0; i < obj->nbChars; i++) {
1466 rectArea.x0 = obj->obj.area.x0 + offsetX + (i * 10);
1467 rectArea.y0 = obj->obj.area.y0 - 2;
1469 if (textLen < obj->nbChars) {
1471 digit = obj->text[i];
1483 else if (i < (obj->nbChars - 1)) {
1484 digit = obj->text[textLen - obj->nbChars + 1 + i];
1504 if (obj->buffer == NULL) {
1507 if (computePosition) {
1508 compute_position((
nbgl_obj_t *) obj, prevObj);
1512 OBJ_LOGGER,
"draw_image_file(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1513 obj->obj.area.backgroundColor =
WHITE;
1520 if (computePosition) {
1521 compute_position((
nbgl_obj_t *) obj, prevObj);
1524 if (obj->enableMasking) {
1542 LOG_DEBUG(
OBJ_LOGGER,
"draw_object() obj->type = %d, prevObj = %p\n", obj->type, prevObj);
1543 objRefreshAreaDone =
false;
1544 if ((obj->type <
NB_OBJ_TYPES) && (draw_functions[obj->type] != NULL)) {
1545 if ((obj->type !=
SCREEN) && (obj->parent == NULL)) {
1549#ifdef SCREEN_SIZE_WALLET
1552 if (computePosition && (obj->type ==
KEYPAD)) {
1554 keypad->digitsChanged =
true;
1558 func(obj, prevObj, computePosition);
1565#ifdef HAVE_SERIALIZED_NBGL
1568 if (!objRefreshAreaDone) {
1569 extendRefreshArea(&obj->area);
1587 draw_object(obj, prevObj, computePosition);
1593 OBJ_LOGGER,
"draw_obj_and_chidren(): container->children = %p\n", container->children);
1595 if (container->children != NULL) {
1596 for (i = 0; i < container->nbChildren; i++) {
1597 nbgl_obj_t *current = container->children[i];
1598 if (current != NULL) {
1600 draw_obj_and_chidren(current, prev,
true);
1601 if (current->alignTo == NULL) {
1619 x1 = refreshArea.x0 + refreshArea.width;
1620 y1 = refreshArea.y0 + refreshArea.height;
1623 if (area->x0 < refreshArea.x0) {
1625 refreshArea.x0 =
MAX(0, area->x0);
1628 if (((area->x0 + area->width) > x1) || (refreshArea.width == 0)) {
1630 x1 =
MIN(SCREEN_WIDTH, area->x0 + area->width);
1633 if (area->y0 < refreshArea.y0) {
1635 refreshArea.y0 =
MAX(0, area->y0) & ~(VERTICAL_ALIGNMENT - 1);
1638 if (((area->y0 + area->height) > y1) || (refreshArea.height == 0)) {
1640 y1 =
MIN(SCREEN_HEIGHT, area->y0 + area->height);
1642 y1 = (y1 + (VERTICAL_ALIGNMENT - 1)) & ~(VERTICAL_ALIGNMENT - 1);
1646 if (x1 > SCREEN_WIDTH) {
1648 "extendRefreshArea: Impossible area x0 = %d width %d\n",
1652 if (y1 > SCREEN_HEIGHT) {
1655 "extendRefreshArea: Impossible area y0 = %d height %d\n",
1657 refreshArea.height);
1663 refreshArea.width = x1 - refreshArea.x0;
1664 refreshArea.height = y1 - refreshArea.y0;
1667 if (area->bpp > refreshArea.bpp) {
1668 refreshArea.bpp = area->bpp;
1679 bool computePosition =
false;
1680 bool fromApp =
false;
1685 if (obj->type ==
SCREEN) {
1687 computePosition =
true;
1693 while (parent->parent != NULL) {
1694 parent = parent->parent;
1696 if (parent->type ==
SCREEN) {
1705 if ((os_sched_current_task() == TASK_BOLOS_UX) == fromApp) {
1709 if (objDrawingDisabled && fromApp) {
1712 draw_obj_and_chidren(obj, NULL, computePosition);
1732 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1738 "nbgl_refreshSpecial(), x0,y0 = [%d, %d], w,h = [%d, %d]\n",
1742 refreshArea.height);
1748 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1754 "nbgl_refreshSpecialNoPoff(), x0,y0 = [%d, %d], w,h = [%d, %d]\n",
1758 refreshArea.height);
1768 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1780#ifdef HAVE_SERIALIZED_NBGL
1783 refreshArea.x0 = SCREEN_WIDTH - 1;
1784 refreshArea.width = 0;
1785 refreshArea.y0 = SCREEN_HEIGHT - 1;
1786 refreshArea.height = 0;
1799 objDrawingDisabled =
false;
1812 objDrawingDisabled = !enable;
1834 while (parent->parent != NULL) {
1835 parent = parent->parent;
1837 if (parent->type ==
SCREEN) {
#define LOG_WARN(__logger,...)
#define LOG_DEBUG(__logger,...)
#define LOG_FATAL(__logger,...)
Middle Level API of the new BOLOS Graphical Library.
void nbgl_drawIcon(nbgl_area_t *area, nbgl_transformation_t transformation, nbgl_color_map_t color_map, const nbgl_icon_details_t *icon)
Helper function to render an icon directly from its nbgl_icon_details_t structure.
nbgl_font_id_e nbgl_drawText(const nbgl_area_t *area, const char *text, uint16_t textLen, nbgl_font_id_e fontId, color_t fontColor)
This function draws the given single-line text, with the given parameters.
void nbgl_drawRoundedBorderedRect(const nbgl_area_t *area, nbgl_radius_t radius, uint8_t stroke, color_t innerColor, color_t borderColor)
This functions draws a rounded corners rectangle with a border, with the given parameters.
void nbgl_drawQrCode(const nbgl_area_t *area, nbgl_qrcode_version_t version, const char *text, color_t backgroundColor)
Draws the given text into a V10 QR code (QR code version is fixed using qrcodegen_VERSION_MIN/qrcodeg...
void nbgl_drawRoundedRect(const nbgl_area_t *area, nbgl_radius_t radius, color_t innerColor)
This functions draws a rounded corners rectangle (without border), with the given parameters.
void nbgl_getTextMaxLenAndWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t *len, uint16_t *width, bool wrapping)
compute the max width of the first line of the given text fitting in maxWidth
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
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
bool nbgl_getTextMaxLenAndWidthFromEnd(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, uint16_t *len, uint16_t *width)
compute the len and width of the given text fitting in the maxWidth, starting from end of text
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
return the height in pixels of the font with the given font ID
uint16_t nbgl_getTextWidth(nbgl_font_id_e fontId, const char *text)
return the max width in pixels of the given text (can be multiline)
uint16_t nbgl_getTextLength(const char *text)
return the number of bytes of the given text, excluding final ' ' or '\0'
uint16_t nbgl_getTextNbLinesInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
compute the number of lines of the given text fitting in the given maxWidth
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
return the height in pixels of the line of font with the given font ID
uint16_t nbgl_getSingleLineTextWidthInLen(nbgl_font_id_e fontId, const char *text, uint16_t maxLen)
return the max width in pixels of the given text until the first or \0 is encountered,...
Font screen low-Level driver API, to draw elementary forms.
void nbgl_frontDrawLine(const nbgl_area_t *area, uint8_t dotStartIdx, color_t lineColor)
void nbgl_frontControlAreaMasking(uint8_t mask_index, nbgl_area_t *masked_area_or_null)
void nbgl_frontDrawImage(const nbgl_area_t *area, const uint8_t *buffer, nbgl_transformation_t transformation, nbgl_color_map_t colorMap)
void nbgl_frontDrawImageFile(const nbgl_area_t *area, const uint8_t *buffer, nbgl_color_map_t colorMap, const uint8_t *uzlib_chunk_buffer)
void nbgl_frontRefreshArea(const nbgl_area_t *area, nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
void nbgl_frontDrawRect(const nbgl_area_t *area)
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
void nbgl_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
void nbgl_refreshReset(void)
This functions resets all changes since the last refresh.
void nbgl_objAllowDrawing(bool enable)
This functions enables or disables drawing/refresh for all further calls.
void(* draw_function_t)(nbgl_obj_t *obj, nbgl_obj_t *prevObj, bool computePosition)
void nbgl_refreshSpecial(nbgl_refresh_mode_t mode)
This functions refreshes the actual screen on display with what has changed since the last refresh,...
bool nbgl_objIsUx(nbgl_obj_t *obj)
This function returns true if the object belongs to a UxScreen.
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
uint8_t * nbgl_objGetRAMBuffer(void)
This function is used to get the all purpose RAM buffer.
uint8_t ramBuffer[GZLIB_UNCOMPRESSED_CHUNK]
bool nbgl_refreshIsNeeded(void)
This functions returns true if there is something to refresh.
void nbgl_objInit(void)
This functions inits all internal of nbgl objects layer.
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_radio_s nbgl_radio_t
struct to represent a radio button (RADIO_BUTTON type)
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)
struct PACKED__ nbgl_keypad_s nbgl_keypad_t
struct to represent a keypad (KEYPAD type)
struct PACKED__ nbgl_mask_control_s nbgl_mask_control_t
struct PACKED__ nbgl_text_entry_s nbgl_text_entry_t
struct to represent a text entry area (TEXT_ENTRY type)
struct PACKED__ nbgl_keyboard_s nbgl_keyboard_t
struct to represent a keyboard (KEYBOARD type)
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_objDrawKeyboard(nbgl_keyboard_t *kbd)
This function draws a keyboard object.
#define NB_MAX_PAGES_WITH_DASHES
void nbgl_objDrawKeypad(nbgl_keypad_t *kbd)
This function draws a keypad object.
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
@ PROGRESSIVE_INDICATOR
all dashes before active page are black
struct PACKED__ nbgl_switch_s nbgl_switch_t
struct to represent a switch (size is fixed) (SWITCH type)
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
struct PACKED__ nbgl_spinner_s nbgl_spinner_t
struct to represent a "spinner", represented by the Ledger corners, in gray, with one of the corners ...
struct PACKED__ nbgl_image_file_s nbgl_image_file_t
struct to represent an image file object (IMAGE_FILE type) The source of the data is an image file wi...
struct PACKED__ nbgl_qrcode_s nbgl_qrcode_t
struct to represent a QR code (QR_CODE type), whose size is fixed
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
void nbgl_touchInit(bool fromUx)
Function to initialize the touch context.
nbgl_post_refresh_t
Post refresh modes.
@ POST_REFRESH_FORCE_POWER_OFF
Force screen power off after refresh.
uint8_t nbgl_color_map_t
Represents the color_map to be used for 2BPP image, or the foreground color for 1BPP image.
@ RADIUS_0_PIXELS
no radius (square angle)
@ VERTICAL
from top to bottom
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
#define GZLIB_UNCOMPRESSED_CHUNK
size of gzlib uncompression buffer in bytes
@ NO_ALIGNMENT
used when parent container layout is used
@ LEFT_TOP
on outside left
@ LEFT_BOTTOM
on outside left
@ RIGHT_TOP
on outside right
@ RIGHT_BOTTOM
on outside right
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
@ IMAGE_FILE
Image file (with Ledger compression)
@ TEXT_ENTRY
area for entered text, only for Nanos
@ SWITCH
Switch to turn on/off something.
@ RADIO_BUTTON
Indicator to inform whether something is on or off.
@ BUTTON
Rounded rectangle button with icon and/or text.
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
@ LINE
Vertical or Horizontal line.
@ MASK_CONTROL
OS-specific object to enable/disable masked area.
@ CONTAINER
Empty container.
@ TEXT_AREA
Area to contain text line(s)
#define NO_TRANSFORMATION
@ NBGL_BPP_1
1 bit per pixel
@ NBGL_BPP_2
2 bits per pixel
struct PACKED__ nbgl_area_s nbgl_area_t
Represents a rectangle area of the screen.
nbgl_refresh_mode_t
different modes of refresh for nbgl_refreshSpecial()
@ FULL_COLOR_CLEAN_REFRESH
to be used for lock screen display (cleaner but longer refresh)