Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_obj.c
Go to the documentation of this file.
1
6/*********************
7 * INCLUDES
8 *********************/
9#include <string.h>
10
11#include "app_config.h"
12#include "nbgl_obj.h"
13#include "nbgl_draw.h"
14#include "nbgl_front.h"
15#include "nbgl_debug.h"
16#include "nbgl_screen.h"
17#include "nbgl_touch.h"
18#include "os_print.h"
19#include "os_helpers.h"
20#include "os_pic.h"
21#include "os_task.h"
22#include "glyphs.h"
23#include "os_io_seph_ux.h"
24#ifdef HAVE_SERIALIZED_NBGL
25#include "nbgl_serialize.h"
26#endif
27#ifdef BUILD_SCREENSHOTS
28#include "json_scenario.h"
29#endif // BUILD_SCREENSHOTS
30
31/*********************
32 * DEFINES
33 *********************/
34// max number of letters in TEXT_ENTRY
35#define NB_MAX_LETTERS 9
36
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)
44#define INTER_DASHES 8
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)
50#define INTER_DASHES 8
51#define SPINNER_DASH_WIDTH 15
52#define SPINNER_DASH_HEIGHT 10
53#define SPINNER_DASH_STROKE 2
54#define PROGRESS_STROKE 2
55#endif // TARGETS
56
57/**********************
58 * TYPEDEFS
59 **********************/
60typedef void (*draw_function_t)(nbgl_obj_t *obj, nbgl_obj_t *prevObj, bool computePosition);
61
62/**********************
63 * STATIC PROTOTYPES
64 **********************/
65static void draw_screen(nbgl_container_t *obj, nbgl_obj_t *prevObj, bool computePosition);
66static void draw_container(nbgl_container_t *obj, nbgl_obj_t *prevObj, bool computePosition);
67static void draw_image(nbgl_image_t *obj, nbgl_obj_t *prevObj, bool computePosition);
68static void draw_button(nbgl_button_t *obj, nbgl_obj_t *prevObj, bool computePosition);
69#ifdef HAVE_SE_TOUCH
70static void draw_line(nbgl_line_t *obj, nbgl_obj_t *prevObj, bool computePosition);
71static void draw_switch(nbgl_switch_t *obj, nbgl_obj_t *prevObj, bool computePosition);
72static void draw_radioButton(nbgl_radio_t *obj, nbgl_obj_t *prevObj, bool computePosition);
73static void draw_pageIndicator(nbgl_page_indicator_t *obj,
74 nbgl_obj_t *prevObj,
75 bool computePosition);
76static void draw_spinner(nbgl_spinner_t *obj, nbgl_obj_t *prevObj, bool computePosition);
77#else // HAVE_SE_TOUCH
78static void draw_textEntry(nbgl_text_entry_t *obj, nbgl_obj_t *prevObj, bool computePosition);
79#endif // HAVE_SE_TOUCH
80static void draw_progressBar(nbgl_progress_bar_t *obj, nbgl_obj_t *prevObj, bool computePosition);
81static void draw_textArea(nbgl_text_area_t *obj, nbgl_obj_t *prevObj, bool computePosition);
82#ifdef NBGL_QRCODE
83static void draw_qrCode(nbgl_qrcode_t *obj, nbgl_obj_t *prevObj, bool computePosition);
84#endif // NBGL_QRCODE
85#ifdef NBGL_KEYBOARD
86static void draw_keyboard(nbgl_keyboard_t *obj, nbgl_obj_t *prevObj, bool computePosition);
87#endif // NBGL_KEYBOARD
88#ifdef NBGL_KEYPAD
89static void draw_keypad(nbgl_keypad_t *obj, nbgl_obj_t *prevObj, bool computePosition);
90#endif // NBGL_KEYPAD
91static void draw_image_file(nbgl_image_file_t *obj, nbgl_obj_t *prevObj, bool computePosition);
92#ifdef NBGL_MASKING
93static void draw_mask_control(nbgl_mask_control_t *obj, nbgl_obj_t *prevObj, bool computePosition);
94#endif // NBGL_MASKING
95
96static void extendRefreshArea(nbgl_area_t *obj);
97
98/**********************
99 * STATIC VARIABLES
100 **********************/
101// area to resfresh
102static nbgl_area_t refreshArea;
103
104// boolean used to enable/forbid drawing/refresh by Application
105static bool objDrawingDisabled;
106
107// boolean used to indicate a manual refresh area extension
108static bool objRefreshAreaDone;
109
110// indexed by nbgl_obj_type_t
111static const draw_function_t draw_functions[NB_OBJ_TYPES] = {
112 [SCREEN] = (draw_function_t) draw_screen,
113 [CONTAINER] = (draw_function_t) draw_container,
114 [IMAGE] = (draw_function_t) draw_image,
115 [TEXT_AREA] = (draw_function_t) draw_textArea,
116 [BUTTON] = (draw_function_t) draw_button,
117#ifdef HAVE_SE_TOUCH
118 [LINE] = (draw_function_t) draw_line,
119 [SWITCH] = (draw_function_t) draw_switch,
120 [PAGE_INDICATOR] = (draw_function_t) draw_pageIndicator,
121 [RADIO_BUTTON] = (draw_function_t) draw_radioButton,
122#ifdef NBGL_QRCODE
123 [QR_CODE] = (draw_function_t) draw_qrCode,
124#endif // NBGL_QRCODE
125 [SPINNER] = (draw_function_t) draw_spinner,
126#endif // HAVE_SE_TOUCH
127 [PROGRESS_BAR] = (draw_function_t) draw_progressBar,
128#ifdef NBGL_KEYBOARD
129 [KEYBOARD] = (draw_function_t) draw_keyboard,
130#endif // NBGL_KEYBOARD
131#ifdef NBGL_KEYPAD
132 [KEYPAD] = (draw_function_t) draw_keypad,
133#endif // NBGL_KEYPAD
134 [IMAGE_FILE] = (draw_function_t) draw_image_file,
135#ifndef HAVE_SE_TOUCH
136 [TEXT_ENTRY] = (draw_function_t) draw_textEntry,
137#endif // HAVE_SE_TOUCH
138#ifdef NBGL_MASKING
139 [MASK_CONTROL] = (draw_function_t) draw_mask_control,
140#endif // NBGL_MASKING
141};
142/**********************
143 * VARIABLES
144 **********************/
145// buffer used either for image file uncompression and side screen string drawing
147
148#ifdef BUILD_SCREENSHOTS
149// Variables used to store important values (nb lines, bold state etc)
150extern uint16_t last_nb_lines, last_nb_pages;
151extern bool last_bold_state, verbose;
152#endif // BUILD_SCREENSHOTS
153
154/**********************
155 * STATIC PROTOTYPES
156 **********************/
157
158/**********************
159 * GLOBAL FUNCTIONS
160 **********************/
161
162static void compute_relativePosition(nbgl_obj_t *obj, nbgl_obj_t *prevObj)
163{
164 nbgl_container_t *parent = (nbgl_container_t *) (obj->parent);
165 // LOG_DEBUG(OBJ_LOGGER,"compute_relativePosition()\n");
166 // compute object absolute position thanks to layout/alignment
167 if (obj->alignment == NO_ALIGNMENT) {
168 LOG_DEBUG(
170 "compute_relativePosition() without align to, parent->layout = %d, prevObj = %p\n",
171 parent->layout,
172 prevObj);
173 // align to parent, depending of layout
174 if (parent->layout == VERTICAL) {
175 obj->rel_x0 = obj->alignmentMarginX;
176 if (prevObj != NULL) {
177 obj->rel_y0 = prevObj->rel_y0 + prevObj->area.height + obj->alignmentMarginY;
178 }
179 else {
180 obj->rel_y0 = obj->alignmentMarginY;
181 }
182 }
183 else { // HORIZONTAL
184 if (prevObj != NULL) {
185 obj->rel_x0 = prevObj->rel_x0 + prevObj->area.width + obj->alignmentMarginX;
186 }
187 else {
188 obj->rel_x0 = obj->alignmentMarginX;
189 }
190 obj->rel_y0 = obj->alignmentMarginY;
191 }
192 }
193 else {
194 nbgl_obj_t *alignToObj = obj->alignTo;
195 if (alignToObj == NULL) {
196 alignToObj = obj->parent;
197 LOG_DEBUG(OBJ_LOGGER, "compute_relativePosition() with align to parent\n");
198 }
199 else {
200 LOG_DEBUG(OBJ_LOGGER, "compute_relativePosition() with align to = %p\n", alignToObj);
201 }
202 // align to the given object, with the given constraints
203 if (alignToObj == obj->parent) {
204 // align inside if the reference is the parent
205 switch (obj->alignment) {
206 case TOP_LEFT:
207 obj->rel_x0 = obj->alignmentMarginX;
208 obj->rel_y0 = obj->alignmentMarginY;
209 break;
210 case TOP_MIDDLE:
211 obj->rel_x0
212 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
213 obj->rel_y0 = obj->alignmentMarginY;
214 break;
215 case TOP_RIGHT:
216 obj->rel_x0
217 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
218 obj->rel_y0 = obj->alignmentMarginY;
219 break;
220 case MID_LEFT:
221 obj->rel_x0 = obj->alignmentMarginX;
222 obj->rel_y0
223 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
224 break;
225 case CENTER:
226 obj->rel_x0
227 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
228 obj->rel_y0
229 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
230 break;
231 case MID_RIGHT:
232 obj->rel_x0
233 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
234 obj->rel_y0
235 = (parent->obj.area.height - obj->area.height) / 2 + obj->alignmentMarginY;
236 break;
237 case BOTTOM_LEFT:
238 obj->rel_x0 = obj->alignmentMarginX;
239 obj->rel_y0
240 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
241 break;
242 case BOTTOM_MIDDLE:
243 obj->rel_x0
244 = (parent->obj.area.width - obj->area.width) / 2 + obj->alignmentMarginX;
245 obj->rel_y0
246 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
247 break;
248 case BOTTOM_RIGHT:
249 obj->rel_x0
250 = (parent->obj.area.width - obj->area.width) - obj->alignmentMarginX;
251 obj->rel_y0
252 = (parent->obj.area.height - obj->area.height) - obj->alignmentMarginY;
253 break;
254 default:
255 // not supported
256 break;
257 }
258 }
259 else {
260 // align outside if the reference is a "brother"
261 switch (obj->alignment) {
262 case TOP_LEFT:
263 obj->rel_x0 = alignToObj->rel_x0 + obj->alignmentMarginX;
264 obj->rel_y0 = alignToObj->rel_y0 - obj->area.height - obj->alignmentMarginY;
265 break;
266 case TOP_MIDDLE:
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;
271 break;
272 case TOP_RIGHT:
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;
276 break;
277
278 case LEFT_TOP:
279 obj->rel_x0 = alignToObj->rel_x0 - obj->area.width - obj->alignmentMarginX;
280 obj->rel_y0 = alignToObj->rel_y0 + obj->alignmentMarginY;
281 break;
282 case MID_LEFT:
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;
287 break;
288 case LEFT_BOTTOM:
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;
292 break;
293
294 case RIGHT_TOP:
295 obj->rel_x0
296 = alignToObj->rel_x0 + alignToObj->area.width + obj->alignmentMarginX;
297 obj->rel_y0 = alignToObj->rel_y0 + obj->alignmentMarginY;
298 break;
299 case MID_RIGHT:
300 obj->rel_x0
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;
305 break;
306 case RIGHT_BOTTOM:
307 obj->rel_x0
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;
311 break;
312
313 case BOTTOM_LEFT:
314 obj->rel_x0 = alignToObj->rel_x0 + obj->alignmentMarginX;
315 obj->rel_y0
316 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
317 break;
318 case BOTTOM_MIDDLE:
319 obj->rel_x0 = alignToObj->rel_x0
320 + (alignToObj->area.width - obj->area.width) / 2
321 + obj->alignmentMarginX;
322 obj->rel_y0
323 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
324 break;
325 case BOTTOM_RIGHT:
326 obj->rel_x0 = alignToObj->rel_x0 + (alignToObj->area.width - obj->area.width)
327 - obj->alignmentMarginX;
328 obj->rel_y0
329 = alignToObj->rel_y0 + alignToObj->area.height + obj->alignmentMarginY;
330 break;
331 default:
332 // not supported
333 break;
334 }
335 }
336 }
337}
338
339static void compute_position(nbgl_obj_t *obj, nbgl_obj_t *prevObj)
340{
341 nbgl_container_t *parent = (nbgl_container_t *) (obj->parent);
342
343 compute_relativePosition(obj, prevObj);
344
345 if (parent == NULL) {
346 // HUGE issue
347 return;
348 }
349 // LOG_DEBUG(OBJ_LOGGER,"compute_position(), parent.type = %d, parent->obj.area.x0 = %d,
350 // obj->rel_x0=%d\n",parent->type,parent->obj.area.x0,obj->rel_x0);
351 // LOG_DEBUG(OBJ_LOGGER,"compute_position(), parent->obj.area.y0 = %d,
352 // obj->rel_y0=%d\n",parent->obj.area.y0,obj->rel_y0);
353
354 obj->area.x0 = parent->obj.area.x0 + obj->rel_x0;
355 obj->area.y0 = parent->obj.area.y0 + obj->rel_y0;
356
357 if ((obj->area.x0 + obj->area.width) > SCREEN_WIDTH) {
358#ifdef BUILD_SCREENSHOTS
359 obj->area.width = SCREEN_WIDTH - obj->area.x0;
360 // Be sure the area is not empty
361 if (!obj->area.width) {
362 obj->area.width = 1;
363 obj->area.x0 -= 1;
364 }
365#else // BUILD_SCREENSHOTS
367 "compute_position(), forbidden width, obj->type = %d, x0=%d, width=%d\n",
368 obj->type,
369 obj->area.x0,
370 obj->area.width);
371#endif // BUILD_SCREENSHOTS
372 }
373#ifdef HAVE_SE_TOUCH
374 if ((obj->area.y0 + obj->area.height) > SCREEN_HEIGHT) {
375#ifdef BUILD_SCREENSHOTS
376 obj->area.height = SCREEN_HEIGHT - obj->area.y0;
377 // Be sure the area is not empty
378 if (!obj->area.height) {
379 obj->area.height = 1;
380 obj->area.y0 -= 1;
381 }
382#else // BUILD_SCREENSHOTS
384 "compute_position(), forbidden height, obj->type = %d, y0=%d, height=%d\n",
385 obj->type,
386 obj->area.y0,
387 obj->area.height);
388#endif // BUILD_SCREENSHOTS
389 }
390#endif // HAVE_SE_TOUCH
391}
392
393static void draw_screen(nbgl_container_t *obj, nbgl_obj_t *prevObj, bool computePosition)
394{
395 nbgl_area_t rectArea;
396
397 UNUSED(prevObj);
398 UNUSED(computePosition);
399
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;
405 nbgl_frontDrawRect(&rectArea);
406}
407
408static void draw_container(nbgl_container_t *obj, nbgl_obj_t *prevObj, bool computePosition)
409{
410 if (computePosition) {
411 compute_position((nbgl_obj_t *) obj, prevObj);
412 }
414 "draw_container(), x0 = %d, y0 = %d, width = %d, height = %d\n",
415 obj->obj.area.x0,
416 obj->obj.area.y0,
417 obj->obj.area.width,
418 obj->obj.area.height);
419 // inherit background from parent
420 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
421 if (obj->forceClean) {
423 }
424}
425
426#ifdef HAVE_SE_TOUCH
435static void draw_button(nbgl_button_t *obj, nbgl_obj_t *prevObj, bool computePosition)
436{
437 uint16_t textWidth = 0;
438 const char *text = NULL;
439#define ICON_TEXT_SPACE 12
440
441 if (computePosition) {
442 compute_position((nbgl_obj_t *) obj, prevObj);
443 }
445 "draw_button(), x0 = %d, y0 = %d, width = %d, height = %d\n",
446 obj->obj.area.x0,
447 obj->obj.area.y0,
448 obj->obj.area.width,
449 obj->obj.area.height);
450
451 // inherit background from parent
452 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
453 // draw the rounded corner rectangle if necessary
454 if ((obj->innerColor == obj->borderColor)
455 && (obj->innerColor != obj->obj.area.backgroundColor)) {
456 nbgl_drawRoundedRect((nbgl_area_t *) obj, obj->radius, obj->innerColor);
457 }
458 else {
459#ifdef TARGET_APEX
460 // on Apex, top-right button (54x56) is drawned as an icon
461 if ((obj->radius == RADIUS_28_PIXELS) && (obj->obj.area.width == BUTTON_WIDTH)) {
462 nbgl_drawIcon(&obj->obj.area, NO_TRANSFORMATION, BLACK, &C_dashed_button_56px);
463 }
464 else {
466 (nbgl_area_t *) obj, obj->radius, BUTTON_STROKE, obj->innerColor, obj->borderColor);
467 }
468#else // TARGET_APEX
470 (nbgl_area_t *) obj, obj->radius, BUTTON_STROKE, obj->innerColor, obj->borderColor);
471#endif // TARGET_APEX
472 }
473 // get the text of the button from the callback if not NULL
474 if (obj->onDrawCallback != NULL) {
475 obj->text = obj->onDrawCallback(obj->token);
476 }
477 text = obj->text;
478 // draw the text (right of the icon, with 8 pixels between them)
479 if (text != NULL) {
480 nbgl_area_t rectArea;
481 // Compute available with & height to display the text
482 rectArea.x0 = obj->obj.area.x0;
483 rectArea.y0 = obj->obj.area.y0;
484 // Only one line of text
485 rectArea.height = nbgl_getFontHeight(obj->fontId);
486 rectArea.y0 += (obj->obj.area.height - rectArea.height) / 2;
487 rectArea.width = obj->obj.area.width;
488 if (obj->icon != NULL) {
489 rectArea.x0 += obj->icon->width + ICON_TEXT_SPACE;
490 rectArea.width -= obj->icon->width + ICON_TEXT_SPACE;
491 }
492 // Compute the width & number of characters displayed on first line
493 uint16_t textLen;
494 nbgl_getTextMaxLenAndWidth(obj->fontId, text, rectArea.width, &textLen, &textWidth, true);
495
496#ifdef BUILD_SCREENSHOTS
497 // Use the area of the button, to check if we overlap any text!
498 store_string_infos(text, obj->fontId, &obj->obj.area, true, 1, 0, false);
499#endif // BUILD_SCREENSHOTS
500
501 // Center the text, horizontally
502 if (textWidth < rectArea.width) {
503 rectArea.x0 += (rectArea.width - textWidth) / 2;
504 }
505 LOG_DEBUG(OBJ_LOGGER, "draw_button(), text = %s\n", text);
506 rectArea.backgroundColor = obj->innerColor;
507 nbgl_drawText(&rectArea, text, textLen, obj->fontId, obj->foregroundColor);
508 }
509#ifdef BUILD_SCREENSHOTS
510 else {
511 // If we are drawing a button without text, check if we don't overlap any text
512 if ((obj->innerColor == obj->borderColor)
513 && (obj->innerColor != obj->obj.area.backgroundColor)) {
514 store_button_infos(&obj->obj.area);
515 }
516 }
517#endif // BUILD_SCREENSHOTS
518 // draw the icon, if any
519 if (obj->icon != NULL) {
520 uint16_t iconX0, iconY0;
521 nbgl_area_t rectArea;
522
523 if (text != NULL) {
524 iconX0 = obj->obj.area.x0
525 + (obj->obj.area.width - (textWidth + obj->icon->width + ICON_TEXT_SPACE)) / 2;
526 }
527 else {
528 iconX0 = obj->obj.area.x0 + (obj->obj.area.width - obj->icon->width) / 2;
529 }
531 "draw_button(), obj->obj.area.height = %d, obj->iconHeight = %d\n",
532 obj->obj.area.height,
533 obj->icon->height);
534 iconY0 = obj->obj.area.y0 + (obj->obj.area.height - obj->icon->height) / 2;
535
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;
542
543 nbgl_drawIcon(&rectArea, NO_TRANSFORMATION, obj->foregroundColor, obj->icon);
544 }
545}
546
555static void draw_line(nbgl_line_t *obj, nbgl_obj_t *prevObj, bool computePosition)
556{
557 nbgl_area_t rectArea;
558 if (computePosition) {
559 compute_position((nbgl_obj_t *) obj, prevObj);
560 }
561 LOG_DEBUG(OBJ_LOGGER, "draw_line(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
562 // inherit background from parent
563 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
565 "draw_line(), backgroundColor = %d, lineColor = %d\n",
566 obj->obj.area.backgroundColor,
567 obj->lineColor);
568 rectArea.x0 = obj->obj.area.x0;
569 rectArea.y0 = obj->obj.area.y0;
570 rectArea.backgroundColor = obj->obj.area.backgroundColor;
571 if (obj->direction == VERTICAL) {
572 rectArea.width = obj->obj.area.width = obj->thickness;
573 rectArea.height = obj->obj.area.height;
574 nbgl_frontDrawLine(&rectArea, 0, obj->lineColor);
575 }
576 else {
577 rectArea.width = obj->obj.area.width;
578 rectArea.height = obj->obj.area.height = obj->thickness;
579 nbgl_frontDrawLine(&rectArea, 0, obj->lineColor);
580 }
581}
582#else // HAVE_SE_TOUCH
591static void draw_button(nbgl_button_t *obj, nbgl_obj_t *prevObj, bool computePosition)
592{
593 uint16_t textWidth = 0;
594 const char *text = NULL;
595#define ICON_TEXT_SPACE 2
596
597 if (computePosition) {
598 compute_position((nbgl_obj_t *) obj, prevObj);
599 }
601 "draw_button(), x0 = %d, y0 = %d, width = %d, height = %d\n",
602 obj->obj.area.x0,
603 obj->obj.area.y0,
604 obj->obj.area.width,
605 obj->obj.area.height);
606
607 // inherit background from parent
608 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
609 // draw the rounded corner rectangle if necessary
610 nbgl_drawRoundedRect((nbgl_area_t *) obj, obj->radius, obj->innerColor);
611
612 // get the text of the button from the callback if not NULL
613 if (obj->onDrawCallback != NULL) {
614 obj->text = obj->onDrawCallback(obj->token);
615 }
616 text = obj->text;
617 // draw the text (right of the icon, with ICON_TEXT_SPACE pixels between them)
618 if (text != NULL) {
619 nbgl_area_t rectArea;
620 // Compute available with & height to display the text
621 rectArea.x0 = obj->obj.area.x0;
622 rectArea.y0 = obj->obj.area.y0;
623 // Only one line of text is allowed
624 rectArea.height = nbgl_getFontHeight(obj->fontId);
625 rectArea.y0 += (obj->obj.area.height - rectArea.height) / 2;
626 rectArea.width = obj->obj.area.width;
627 if (obj->icon != NULL) {
628 rectArea.x0 += obj->icon->width + ICON_TEXT_SPACE;
629 rectArea.width -= obj->icon->width + ICON_TEXT_SPACE;
630 }
631 // Compute the width & number of characters displayed on first line
632 uint16_t textLen;
633 nbgl_getTextMaxLenAndWidth(obj->fontId, text, rectArea.width, &textLen, &textWidth, true);
634
635 // Center the text, horizontally
636 if (textWidth < rectArea.width) {
637 rectArea.x0 += (rectArea.width - textWidth) / 2;
638 }
639 LOG_DEBUG(OBJ_LOGGER, "draw_button(), text = %s\n", text);
640 rectArea.backgroundColor = obj->innerColor;
641 nbgl_drawText(&rectArea, text, textLen, obj->fontId, obj->foregroundColor);
642 }
643 // draw the icon, if any
644 if (obj->icon != NULL) {
645 uint16_t iconX0, iconY0;
646 nbgl_area_t rectArea;
647
648 if (text != NULL) {
649 iconX0 = obj->obj.area.x0
650 + (obj->obj.area.width - (textWidth + obj->icon->width + ICON_TEXT_SPACE)) / 2;
651 }
652 else {
653 iconX0 = obj->obj.area.x0 + (obj->obj.area.width - obj->icon->width) / 2;
654 }
656 "draw_button(), obj->obj.area.height = %d, obj->iconHeight = %d\n",
657 obj->obj.area.height,
658 obj->icon->height);
659 iconY0 = obj->obj.area.y0 + (obj->obj.area.height - obj->icon->height) / 2;
660
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;
667
668 nbgl_drawIcon(&rectArea, NO_TRANSFORMATION, obj->foregroundColor, obj->icon);
669 }
670}
671#endif // HAVE_SE_TOUCH
672
673static void draw_image(nbgl_image_t *obj, nbgl_obj_t *prevObj, bool computePosition)
674{
675 const nbgl_icon_details_t *iconDetails;
676 nbgl_color_map_t colorMap;
677
678 // if buffer is NULL, let's try to call onDrawCallback, if not NULL, to get it
679 if (obj->buffer == NULL) {
680 if (obj->onDrawCallback != NULL) {
681 iconDetails = obj->onDrawCallback(obj->token);
682 }
683 else {
684 return;
685 }
686 }
687 else {
688 iconDetails = obj->buffer;
689 }
690 if (iconDetails == NULL) {
691 return;
692 }
693
694 // use dimension and bpp from the icon details
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);
700 }
701 LOG_DEBUG(OBJ_LOGGER, "draw_image(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
702 // inherit background from parent
703 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
704 if (obj->obj.area.bpp == NBGL_BPP_1) {
705 colorMap = obj->foregroundColor;
706 }
707 else if (obj->obj.area.bpp == NBGL_BPP_2) {
708 colorMap = ((WHITE << 6) | (LIGHT_GRAY << 4) | (DARK_GRAY << 2) | BLACK);
709 }
710 else {
711 colorMap = obj->foregroundColor;
712 }
713
714 nbgl_drawIcon((nbgl_area_t *) obj, obj->transformation, colorMap, iconDetails);
715}
716
717#ifdef HAVE_SE_TOUCH
718static void draw_switch(nbgl_switch_t *obj, nbgl_obj_t *prevObj, bool computePosition)
719{
720 nbgl_area_t rectArea;
721
722 // force dimensions
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);
727 }
728 LOG_DEBUG(OBJ_LOGGER, "draw_switch(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
729
730 // inherit background from parent
731 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
732
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;
738 rectArea.bpp = NBGL_BPP_1;
739 if (obj->state == OFF_STATE) {
740#if NB_COLOR_BITS == 1
741 nbgl_drawIcon(&rectArea, NO_TRANSFORMATION, obj->onColor, &C_switch_off_24px);
742#else
743 nbgl_frontDrawImage(&rectArea, SWITCH_ICON.bitmap, NO_TRANSFORMATION, obj->offColor);
744#endif
745 }
746 else {
747#if NB_COLOR_BITS == 1
748 nbgl_drawIcon(&rectArea, NO_TRANSFORMATION, obj->onColor, &C_switch_on_24px);
749#else
750 nbgl_frontDrawImage(&rectArea, SWITCH_ICON.bitmap, VERTICAL_MIRROR, obj->onColor);
751#endif
752 }
753}
754
755static void draw_radioButton(nbgl_radio_t *obj, nbgl_obj_t *prevObj, bool computePosition)
756{
757 nbgl_area_t rectArea;
758 const nbgl_icon_details_t *icon;
759 nbgl_color_map_t color_map;
760
761 // force dimensions
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);
766 }
768 "draw_radioButton(), x0 = %d, y0 = %d, state = %d\n",
769 obj->obj.area.x0,
770 obj->obj.area.y0,
771 obj->state);
772
773 // inherit background from parent
774 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
775
776 if (obj->state == OFF_STATE) {
777 icon = &RADIO_OFF_ICON;
778#if NB_COLOR_BITS == 1
779 color_map = obj->activeColor;
780#else
781 color_map = obj->borderColor;
782#endif
783 }
784 else {
785 icon = &RADIO_ON_ICON;
786 color_map = obj->activeColor;
787 }
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;
794 nbgl_drawIcon(&rectArea, NO_TRANSFORMATION, color_map, icon);
795}
796#endif // HAVE_SE_TOUCH
797
805static void draw_progressBar(nbgl_progress_bar_t *obj, nbgl_obj_t *prevObj, bool computePosition)
806{
807#ifdef HAVE_SE_TOUCH
808
809 uint8_t stroke = PROGRESS_STROKE; // pixels for border
810 nbgl_area_t barArea;
811 uint16_t barWidth = ((obj->state * obj->obj.area.width)) / 100;
812
813 if (computePosition) {
814 compute_position((nbgl_obj_t *) obj, prevObj);
815 }
817 "draw_progressBar(), x0 = %d, y0 = %d, level = %d %%\n",
818 obj->obj.area.x0,
819 obj->obj.area.y0,
820 obj->state);
821 memcpy(&barArea, &obj->obj.area, sizeof(nbgl_area_t));
822
823 // inherit background from parent
824 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
825
826 if (obj->partialRedraw == false) {
827 // Case of progress bar full draw
828 if (obj->withBorder) {
831 stroke,
832 obj->obj.area.backgroundColor,
833 obj->foregroundColor);
834 }
835 else {
837 (nbgl_area_t *) obj, RADIUS_0_PIXELS, obj->obj.area.backgroundColor);
838 }
839 // also reset previous width to be sure to clean up everything
840 obj->previousWidth = 0;
841 if (obj->state == 0) {
842 goto end;
843 }
844 }
845 // Setup bar draw
846 int barDiffWith = barWidth - obj->previousWidth;
847 color_t barColor;
848
849 if (barDiffWith > 0) {
850 // Drawing "forward"
851 barArea.x0 = obj->obj.area.x0 + obj->previousWidth;
852 barArea.width = barDiffWith;
853 barColor = obj->foregroundColor;
854 }
855 else if (barDiffWith < 0) {
856 // Drawing "backward"
857 barArea.x0 = obj->obj.area.x0 + obj->previousWidth + barDiffWith;
858 barArea.width = -barDiffWith;
859 barColor = obj->obj.area.backgroundColor;
860 }
861
862 if (barDiffWith != 0) {
863 nbgl_drawRoundedRect((nbgl_area_t *) &barArea, RADIUS_0_PIXELS, barColor);
864 }
865
866 // reset partialRedraw to be sure that in case of full redraw of the screen we redraw the
867 // full bar
868 if (obj->partialRedraw == true) {
869 obj->partialRedraw = false;
870 }
871 obj->previousWidth = barWidth;
872
873end:
874 extendRefreshArea(&barArea);
875 objRefreshAreaDone = true;
876#else // HAVE_SE_TOUCH
877 uint8_t stroke = 1; // 1 pixels for border
878 uint16_t levelWidth;
879
880 if (computePosition) {
881 compute_position((nbgl_obj_t *) obj, prevObj);
882 }
884 "draw_progressBar(), x0 = %d, y0 = %d, level = %d %%\n",
885 obj->obj.area.x0,
886 obj->obj.area.y0,
887 obj->state);
888
889 // inherit background from parent
890 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
891
892 // draw external part if necessary
893 if (obj->withBorder) {
895 RADIUS_3_PIXELS,
896 stroke,
897 obj->obj.area.backgroundColor,
898 obj->foregroundColor);
899 }
900 else {
901 nbgl_drawRoundedRect((nbgl_area_t *) obj, RADIUS_3_PIXELS, obj->obj.area.backgroundColor);
902 }
903 // draw level
904 levelWidth = MIN((obj->obj.area.width - 2) * obj->state / 100, (obj->obj.area.width - 2));
905 if (levelWidth > 0) {
906 nbgl_area_t rectArea;
907 rectArea.width = levelWidth;
908 rectArea.height = obj->obj.area.height - 2;
909 rectArea.backgroundColor = obj->foregroundColor;
910 rectArea.bpp = NBGL_BPP_1;
911 rectArea.x0 = obj->obj.area.x0 + 1;
912 rectArea.y0 = obj->obj.area.y0 + 1;
913
914 nbgl_frontDrawRect(&rectArea);
915 }
916#endif // HAVE_SE_TOUCH
917}
918
919#ifdef HAVE_SE_TOUCH
928static void draw_pageIndicator(nbgl_page_indicator_t *obj,
929 nbgl_obj_t *prevObj,
930 bool computePosition)
931{
932 nbgl_area_t rectArea;
933 uint16_t dashWidth;
934
935 // display nothing if less than two pages
936 if (obj->nbPages < 2) {
937 return;
938 }
939
940 if (obj->nbPages <= NB_MAX_PAGES_WITH_DASHES) {
941 int i;
942 // force height
943 obj->obj.area.height = 4;
944
945 if (computePosition) {
946 compute_position((nbgl_obj_t *) obj, prevObj);
947 }
949 "draw_pageIndicator(), x0 = %d, y0 = %d, page = %d/%d\n",
950 obj->obj.area.x0,
951 obj->obj.area.y0,
952 obj->activePage,
953 obj->nbPages);
954
955 // inherit background from parent
956 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
957
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;
962 rectArea.height = 4;
963 rectArea.backgroundColor = obj->obj.area.backgroundColor;
964 rectArea.bpp = NBGL_BPP_1;
965 // draw dashes
966 for (i = 0; i < obj->activePage; i++) {
968 &rectArea, 0, (obj->style == PROGRESSIVE_INDICATOR) ? BLACK : LIGHT_GRAY);
969 rectArea.x0 += dashWidth + INTER_DASHES;
970 }
971 nbgl_frontDrawLine(&rectArea, 0, BLACK);
972 rectArea.x0 += dashWidth + INTER_DASHES;
973 i++;
974
975 for (; i < obj->nbPages; i++) {
976 nbgl_frontDrawLine(&rectArea, 0, LIGHT_GRAY);
977 rectArea.x0 += dashWidth + INTER_DASHES;
978 }
979 }
980 else {
981 char navText[11]; // worst case is "ccc of nnn"
982
983 SPRINTF(navText, "%d of %d", obj->activePage + 1, obj->nbPages);
984 // force height
985 obj->obj.area.height = nbgl_getFontHeight(SMALL_REGULAR_FONT);
986 // the width must be at least 80
987 obj->obj.area.width = nbgl_getTextWidth(SMALL_REGULAR_FONT, navText);
988
989 if (computePosition) {
990 compute_position((nbgl_obj_t *) obj, prevObj);
991 }
993 "draw_pageIndicator(), x0 = %d, y0 = %d, page = %d/%d\n",
994 obj->obj.area.x0,
995 obj->obj.area.y0,
996 obj->activePage,
997 obj->nbPages);
998
999 // inherit background from parent
1000 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1001
1002 // draw active page
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;
1008 rectArea.bpp = NBGL_BPP_1;
1009 nbgl_drawText(&rectArea, navText, strlen(navText), SMALL_REGULAR_FONT, LIGHT_TEXT_COLOR);
1010 }
1011}
1012#endif // HAVE_SE_TOUCH
1013
1022static void draw_textArea(nbgl_text_area_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1023{
1024 nbgl_area_t rectArea;
1025 uint16_t textWidth, fontHeight, lineHeight, textHeight, midHeight;
1026 uint8_t line, nbLines;
1027 const char *text;
1028 nbgl_font_id_e fontId = obj->fontId;
1029
1030 if (computePosition) {
1031 compute_position((nbgl_obj_t *) obj, prevObj);
1032 }
1033 // get the text of the button from the callback if not NULL
1034 if (obj->onDrawCallback != NULL) {
1035 obj->text = obj->onDrawCallback(obj->token);
1036 }
1037 text = obj->text;
1038 if (text == NULL) {
1039 return;
1040 }
1041
1042 LOG_DEBUG(
1043 OBJ_LOGGER,
1044 "draw_textArea(), wrapping = %d, x0 = %d, y0 = %d, width = %d, height = %d, text = %s\n",
1045 obj->wrapping,
1046 obj->obj.area.x0,
1047 obj->obj.area.y0,
1048 obj->obj.area.width,
1049 obj->obj.area.height,
1050 text);
1051
1052 // inherit background from parent
1053 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1054
1055 // draw background to make sure it's clean
1056#ifdef SCREEN_SIZE_NANO
1057 if (obj->style == INVERTED_COLORS) {
1058 obj->obj.area.backgroundColor = WHITE;
1059 rectArea.backgroundColor = BLACK;
1060 }
1061 else
1062#endif // SCREEN_SIZE_NANO
1063 {
1064 // inherit background from parent
1065 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1066 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1067 }
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) {
1074 nbgl_drawRoundedRect(&rectArea, RADIUS_1_PIXEL, WHITE);
1075 }
1076 else
1077#endif // SCREEN_SIZE_NANO
1078 {
1079 nbgl_frontDrawRect(&rectArea);
1080 }
1081
1082 fontHeight = nbgl_getFontHeight(fontId);
1083 lineHeight = nbgl_getFontLineHeight(fontId);
1084 // special case of autoHideLongLine, when the text is too long for a line, draw '...' at the
1085 // beginning
1086 if (obj->autoHideLongLine == true) {
1087#ifdef BUILD_SCREENSHOTS
1088 nbgl_getTextNbLinesInWidth(fontId, text, obj->obj.area.width, obj->wrapping);
1089 store_string_infos(text,
1090 fontId,
1091 &obj->obj.area,
1092 obj->wrapping,
1093 last_nb_lines,
1094 last_nb_pages,
1095 last_bold_state);
1096#endif // BUILD_SCREENSHOTS
1097 textWidth = nbgl_getSingleLineTextWidth(fontId, text);
1098 if (textWidth > obj->obj.area.width) {
1099 uint16_t lineWidth, lineLen;
1100 uint16_t dotsWidth;
1101
1102 dotsWidth = nbgl_getTextWidth(fontId, "...");
1103 rectArea.x0 = obj->obj.area.x0;
1104 rectArea.y0 = obj->obj.area.y0 + (obj->obj.area.height - fontHeight) / 2;
1105 rectArea.width = dotsWidth;
1106 nbgl_drawText(&rectArea, "...", 3, fontId, obj->textColor);
1107 // then draw the end of text
1109 fontId, text, obj->obj.area.width - dotsWidth, &lineLen, &lineWidth);
1110 rectArea.x0 += dotsWidth;
1111 rectArea.width = lineWidth;
1112 nbgl_drawText(&rectArea,
1113 &text[nbgl_getTextLength(text) - lineLen],
1114 lineLen,
1115 obj->fontId,
1116 obj->textColor);
1117 return;
1118 }
1119 }
1120
1121 // get nb lines in the given width (depending of wrapping)
1122 nbLines = nbgl_getTextNbLinesInWidth(fontId, text, obj->obj.area.width, obj->wrapping);
1123#ifdef BUILD_SCREENSHOTS
1124 store_string_infos(
1125 text, fontId, &obj->obj.area, obj->wrapping, last_nb_lines, last_nb_pages, last_bold_state);
1126#endif // BUILD_SCREENSHOTS
1127 // saturate nb lines if nbMaxLines is greater than 0
1128 if ((obj->nbMaxLines > 0) && (obj->nbMaxLines < nbLines)) {
1129 nbLines = obj->nbMaxLines;
1130 }
1131
1132 textHeight = (nbLines - 1) * lineHeight + fontHeight;
1133
1134 midHeight = (obj->obj.area.height - textHeight) / 2;
1135#ifdef SCREEN_SIZE_NANO
1136 if (obj->style == INVERTED_COLORS) {
1137 midHeight--;
1138 }
1139#endif // SCREEN_SIZE_NANO
1140
1141 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1142 rectArea.height = fontHeight;
1143 // draw each line
1144 for (line = 0; line < nbLines; line++) {
1145 uint16_t lineWidth, lineLen;
1146
1148 fontId, text, obj->obj.area.width, &lineLen, &lineWidth, obj->wrapping);
1149 if (obj->textAlignment == MID_LEFT) {
1150 rectArea.x0 = obj->obj.area.x0;
1151 }
1152 else if (obj->textAlignment == CENTER) {
1153 rectArea.x0 = obj->obj.area.x0 + (obj->obj.area.width - lineWidth) / 2;
1154 }
1155 else if (obj->textAlignment == MID_RIGHT) {
1156 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - lineWidth;
1157 }
1158 else {
1159 LOG_FATAL(OBJ_LOGGER, "Forbidden obj->textAlignment = %d\n", obj->textAlignment);
1160 }
1161 rectArea.y0 = obj->obj.area.y0 + midHeight + line * lineHeight;
1162 rectArea.width = lineWidth;
1163
1165 "draw_textArea(), [%s] line %d, lineLen %d lineWidth = %d, obj.area.height = %d, "
1166 "textHeight = %d, nbMaxLines = %d, wrapping = %d\n",
1167 text,
1168 line,
1169 lineLen,
1170 lineWidth,
1171 obj->obj.area.height,
1172 textHeight,
1173 obj->nbMaxLines,
1174 obj->wrapping);
1175 if ((obj->nbMaxLines == 0) || (line < (obj->nbMaxLines - 1))) {
1176 fontId = nbgl_drawText(&rectArea, text, lineLen, fontId, obj->textColor);
1177 }
1178 else {
1179#ifdef HAVE_SE_TOUCH
1180 // for last chunk, if nbMaxLines is used, replace the 3 last chars by "..."
1181 // only if the line doesn't end with a '\n'
1182 if (text[lineLen] != '\n') {
1183 uint16_t dotsWidth = nbgl_getSingleLineTextWidth(obj->fontId, "...");
1184 if ((lineWidth + dotsWidth) >= obj->obj.area.width) {
1185 lineLen -= 3;
1186 }
1187 nbgl_drawText(&rectArea, text, lineLen, obj->fontId, obj->textColor);
1188 rectArea.x0 += nbgl_getSingleLineTextWidthInLen(obj->fontId, text, lineLen);
1189
1190 // draw "..." after the other chars
1191 rectArea.width = dotsWidth;
1192 nbgl_drawText(&rectArea, "...", 3, obj->fontId, obj->textColor);
1193 }
1194 else {
1195 nbgl_drawText(&rectArea, text, lineLen, obj->fontId, obj->textColor);
1196 }
1197#else // HAVE_SE_TOUCH
1198 nbgl_drawText(&rectArea, text, lineLen, fontId, obj->textColor);
1199#endif // HAVE_SE_TOUCH
1200 return;
1201 }
1202 text += lineLen;
1203 /* skip trailing \n */
1204 if (*text == '\n') {
1205 text++;
1206 }
1207 }
1208}
1209
1210#ifdef NBGL_QRCODE
1219static void draw_qrCode(nbgl_qrcode_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1220{
1221 nbgl_area_t rectArea;
1222
1223 if (computePosition) {
1224 compute_position((nbgl_obj_t *) obj, prevObj);
1225 }
1226 // be sure to align vertical position on multiple of 4
1227 obj->obj.area.y0 &= ~0x3;
1229 "draw_qrCode(), x0 = %d, y0 = %d, width = %d, height = %d, text = %s\n",
1230 obj->obj.area.x0,
1231 obj->obj.area.y0,
1232 obj->obj.area.width,
1233 obj->obj.area.height,
1234 obj->text);
1235
1236 // inherit background from parent
1237 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1238
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);
1245}
1246#endif // NBGL_QRCODE
1247
1248#ifdef NBGL_KEYBOARD
1256static void draw_keyboard(nbgl_keyboard_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1257{
1258#ifndef HAVE_SE_TOUCH
1259 obj->obj.area.width = KEYBOARD_WIDTH;
1260 obj->obj.area.height = KEYBOARD_KEY_HEIGHT;
1261#endif // HAVE_SE_TOUCH
1262
1263 if (computePosition) {
1264 compute_position((nbgl_obj_t *) obj, prevObj);
1265 }
1266 LOG_DEBUG(
1267 OBJ_LOGGER, "draw_keyboard(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1268
1269 // inherit background from parent
1270 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1271
1273}
1274#endif // NBGL_KEYBOARD
1275
1276#ifdef NBGL_KEYPAD
1284static void draw_keypad(nbgl_keypad_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1285{
1286#ifndef HAVE_SE_TOUCH
1287 obj->obj.area.height = KEYPAD_HEIGHT;
1288 obj->obj.area.width = KEYPAD_WIDTH;
1289#endif // HAVE_SE_TOUCH
1290
1291 if (computePosition) {
1292 compute_position((nbgl_obj_t *) obj, prevObj);
1293 }
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);
1296
1297 // inherit background from parent
1298 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1299
1300 nbgl_objDrawKeypad(obj);
1301}
1302#endif // NBGL_KEYPAD
1303
1304#ifdef HAVE_SE_TOUCH
1312static void draw_spinner(nbgl_spinner_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1313{
1314 nbgl_area_t rectArea;
1315 color_t foreColor;
1316
1317 obj->obj.area.width = SPINNER_WIDTH;
1318 obj->obj.area.height = SPINNER_HEIGHT;
1319
1320 if (computePosition) {
1321 compute_position((nbgl_obj_t *) obj, prevObj);
1322 }
1323 LOG_DEBUG(OBJ_LOGGER, "draw_spinner(), x0 = %d, y0 = %d\n", obj->obj.area.x0, obj->obj.area.y0);
1324
1325 // inherit background from parent
1326 obj->obj.area.backgroundColor = obj->obj.parent->area.backgroundColor;
1327 // foreground color is the opposite of background one
1328 foreColor = (obj->obj.area.backgroundColor == WHITE) ? BLACK : WHITE;
1329
1330 rectArea.bpp = NBGL_BPP_1;
1331 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1332 // if position is OxFF, it means "fixed" so draw 4 corners
1333 if (obj->position == 0xFF) {
1334 // draw horizontal segments
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;
1339 nbgl_frontDrawLine(&rectArea, 0, foreColor); // top left
1340 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1341 nbgl_frontDrawLine(&rectArea, 0, foreColor); // top right
1342 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1343 nbgl_frontDrawLine(&rectArea, 0, foreColor); // bottom right
1344 rectArea.x0 = obj->obj.area.x0;
1345 nbgl_frontDrawLine(&rectArea, 0, foreColor); // bottom left
1346 // draw vertical segments
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;
1351 nbgl_frontDrawLine(&rectArea, 0, foreColor); // top left
1352 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1353 nbgl_frontDrawLine(&rectArea, 0, foreColor); // top right
1354 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1355 nbgl_frontDrawLine(&rectArea, 0, foreColor); // bottom right
1356 rectArea.x0 = obj->obj.area.x0;
1357 nbgl_frontDrawLine(&rectArea, 0, foreColor); // bottom left
1358 }
1359 else {
1360 // clean up full rectangle
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;
1366 nbgl_frontDrawRect(&rectArea); // top left
1367
1368 // draw horizontal segment in foreColor
1369 rectArea.width = SPINNER_DASH_WIDTH;
1370 rectArea.height = SPINNER_DASH_STROKE;
1371 switch (obj->position) {
1372 case 0: // top left corner
1373 rectArea.x0 = obj->obj.area.x0;
1374 rectArea.y0 = obj->obj.area.y0;
1375 break;
1376 case 1: // top right
1377 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1378 rectArea.y0 = obj->obj.area.y0;
1379 break;
1380 case 2: // bottom right
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;
1383 break;
1384 case 3: // bottom left
1385 rectArea.x0 = obj->obj.area.x0;
1386 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - 3;
1387 break;
1388 default:
1389 return;
1390 }
1391 nbgl_frontDrawLine(&rectArea, 0, foreColor);
1392
1393 // draw vertical segment in foreColor
1394 rectArea.width = SPINNER_DASH_STROKE;
1395 rectArea.height = SPINNER_DASH_HEIGHT;
1396 rectArea.backgroundColor = foreColor;
1397 switch (obj->position) {
1398 case 0: // top left corner
1399 rectArea.x0 = obj->obj.area.x0;
1400 rectArea.y0 = obj->obj.area.y0;
1401 break;
1402 case 1: // top right corner
1403 rectArea.x0 = obj->obj.area.x0 + obj->obj.area.width - rectArea.width;
1404 rectArea.y0 = obj->obj.area.y0;
1405 break;
1406 case 2: // bottom right corner
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;
1409 break;
1410 case 3: // bottom left corner
1411 rectArea.x0 = obj->obj.area.x0;
1412 rectArea.y0 = obj->obj.area.y0 + obj->obj.area.height - rectArea.height;
1413 break;
1414 default:
1415 return;
1416 }
1417 nbgl_frontDrawRect(&rectArea);
1418 }
1419}
1420
1421#else // HAVE_SE_TOUCH
1422
1430static void draw_textEntry(nbgl_text_entry_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1431{
1432 nbgl_area_t rectArea;
1433 int textLen = strlen(obj->text);
1434 uint32_t offsetX;
1435
1436 if (computePosition) {
1437 compute_position((nbgl_obj_t *) obj, prevObj);
1438 }
1439
1441 "draw_textEntry(), x0 = %d, y0 = %d, width = %d, height = %d\n",
1442 obj->obj.area.x0,
1443 obj->obj.area.y0,
1444 obj->obj.area.width,
1445 obj->obj.area.height);
1446
1447 // draw background to make sure it's clean
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;
1454 rectArea.bpp = NBGL_BPP_1;
1455 nbgl_drawRoundedRect(&rectArea, RADIUS_3_PIXELS, WHITE);
1456
1457 rectArea.backgroundColor = obj->obj.area.backgroundColor;
1458 rectArea.height = nbgl_getFontHeight(obj->fontId);
1459 if (obj->nbChars > NB_MAX_LETTERS) {
1460 return;
1461 }
1462 offsetX = (obj->obj.area.width - (obj->nbChars * 10)) / 2;
1463 // draw each of the nb chars
1464 for (int i = 0; i < obj->nbChars; i++) {
1465 char digit;
1466 rectArea.x0 = obj->obj.area.x0 + offsetX + (i * 10);
1467 rectArea.y0 = obj->obj.area.y0 - 2;
1468 rectArea.width = 8;
1469 if (textLen < obj->nbChars) {
1470 if (i < textLen) {
1471 digit = obj->text[i];
1472 }
1473 else {
1474 digit = '_';
1475 }
1476 }
1477 else {
1478 // first char is '..' to notify continuing
1479 if (i == 0) {
1481 continue;
1482 }
1483 else if (i < (obj->nbChars - 1)) {
1484 digit = obj->text[textLen - obj->nbChars + 1 + i];
1485 }
1486 else {
1487 digit = '_';
1488 }
1489 }
1491 }
1492}
1493#endif // HAVE_SE_TOUCH
1494
1502static void draw_image_file(nbgl_image_file_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1503{
1504 if (obj->buffer == NULL) {
1505 return;
1506 }
1507 if (computePosition) {
1508 compute_position((nbgl_obj_t *) obj, prevObj);
1509 }
1510
1511 LOG_DEBUG(
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;
1514 nbgl_frontDrawImageFile((nbgl_area_t *) obj, obj->buffer, BLACK, ramBuffer);
1515}
1516
1517#ifdef NBGL_MASKING
1518static void draw_mask_control(nbgl_mask_control_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1519{
1520 if (computePosition) {
1521 compute_position((nbgl_obj_t *) obj, prevObj);
1522 }
1523
1524 if (obj->enableMasking) {
1525 nbgl_frontControlAreaMasking(obj->maskIndex, &obj->obj.area);
1526 }
1527 else {
1528 nbgl_frontControlAreaMasking(obj->maskIndex, NULL);
1529 }
1530}
1531#endif // NBGL_MASKING
1532
1540static void draw_object(nbgl_obj_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1541{
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)) {
1546 LOG_WARN(OBJ_LOGGER, "object with type [%d] has not parent\n", obj->type);
1547 return;
1548 }
1549#ifdef SCREEN_SIZE_WALLET
1550 // if the type is KEYPAD, force digitsChanged to be sure to redraw the full keypad if the
1551 // full screen is redrawn
1552 if (computePosition && (obj->type == KEYPAD)) {
1553 nbgl_keypad_t *keypad = (nbgl_keypad_t *) obj;
1554 keypad->digitsChanged = true;
1555 }
1556#endif // SCREEN_SIZE_WALLET
1557 draw_function_t func = (draw_function_t) PIC(draw_functions[obj->type]);
1558 func(obj, prevObj, computePosition);
1559 }
1560 else {
1561 LOG_WARN(OBJ_LOGGER, "Not existing object type [%d]\n", obj->type);
1562 return;
1563 }
1564
1565#ifdef HAVE_SERIALIZED_NBGL
1566 io_seph_ux_send_nbgl_serialized(NBGL_DRAW_OBJ, obj);
1567#endif
1568 if (!objRefreshAreaDone) {
1569 extendRefreshArea(&obj->area);
1570 }
1571}
1572
1582static void draw_obj_and_chidren(nbgl_obj_t *obj, nbgl_obj_t *prevObj, bool computePosition)
1583{
1584 uint8_t i = 0;
1585 LOG_DEBUG(OBJ_LOGGER, "draw_obj_and_chidren(): obj = %p\n", obj);
1586 // draw the object itself
1587 draw_object(obj, prevObj, computePosition);
1588
1589 if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
1590 nbgl_container_t *container = (nbgl_container_t *) obj;
1591 nbgl_obj_t *prev = NULL;
1592 LOG_DEBUG(
1593 OBJ_LOGGER, "draw_obj_and_chidren(): container->children = %p\n", container->children);
1594 // draw the children, if any
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) {
1599 current->parent = (nbgl_obj_t *) container;
1600 draw_obj_and_chidren(current, prev, true);
1601 if (current->alignTo == NULL) {
1602 prev = current;
1603 }
1604 }
1605 }
1606 }
1607 }
1608}
1609
1616static void extendRefreshArea(nbgl_area_t *area)
1617{
1618 int16_t x1, y1; // bottom right corner
1619 x1 = refreshArea.x0 + refreshArea.width;
1620 y1 = refreshArea.y0 + refreshArea.height;
1621
1622 // if obj top-left is on left of current top-left corner, move top-left corner
1623 if (area->x0 < refreshArea.x0) {
1624 // No negative coordinates
1625 refreshArea.x0 = MAX(0, area->x0);
1626 }
1627 // if obj bottom-right is on right of current bottom-right corner, move bottom-right corner
1628 if (((area->x0 + area->width) > x1) || (refreshArea.width == 0)) {
1629 // Not beyond width
1630 x1 = MIN(SCREEN_WIDTH, area->x0 + area->width);
1631 }
1632 // if obj top-left is on top of current top-left corner, move top-left corner
1633 if (area->y0 < refreshArea.y0) {
1634 // No negative coordinates and align on lower multiple of alignment
1635 refreshArea.y0 = MAX(0, area->y0) & ~(VERTICAL_ALIGNMENT - 1);
1636 }
1637 // if obj bottom-right is on bottom of current bottom-right corner, move bottom-right corner
1638 if (((area->y0 + area->height) > y1) || (refreshArea.height == 0)) {
1639 // Not beyond height
1640 y1 = MIN(SCREEN_HEIGHT, area->y0 + area->height);
1641 // align on upper multiple of alignment
1642 y1 = (y1 + (VERTICAL_ALIGNMENT - 1)) & ~(VERTICAL_ALIGNMENT - 1);
1643 }
1644
1645 // sanity check
1646 if (x1 > SCREEN_WIDTH) {
1648 "extendRefreshArea: Impossible area x0 = %d width %d\n",
1649 refreshArea.x0,
1650 refreshArea.width);
1651 }
1652 if (y1 > SCREEN_HEIGHT) {
1653#ifdef HAVE_SE_TOUCH
1655 "extendRefreshArea: Impossible area y0 = %d height %d\n",
1656 refreshArea.y0,
1657 refreshArea.height);
1658#else // HAVE_SE_TOUCH
1659 y1 = SCREEN_HEIGHT;
1660#endif // HAVE_SE_TOUCH
1661 }
1662 // recompute width and height
1663 refreshArea.width = x1 - refreshArea.x0;
1664 refreshArea.height = y1 - refreshArea.y0;
1665
1666 // revaluate area bpp
1667 if (area->bpp > refreshArea.bpp) {
1668 refreshArea.bpp = area->bpp;
1669 }
1670}
1671
1678{
1679 bool computePosition = false;
1680 bool fromApp = false;
1681
1682 LOG_DEBUG(OBJ_LOGGER, "nbgl_objDraw(): obj = %p\n", obj);
1683 // check whether it's necessary to compute position, and if this object belongs to
1684 // an Application screen
1685 if (obj->type == SCREEN) {
1686 // always compute position for screen and all sub-objects
1687 computePosition = true;
1688 fromApp = !(((nbgl_screen_t *) obj)->isUxScreen);
1689 }
1690 else {
1691 nbgl_obj_t *parent = obj;
1692 // search screen in parenthood
1693 while (parent->parent != NULL) {
1694 parent = parent->parent;
1695 }
1696 if (parent->type == SCREEN) {
1697 fromApp = !(((nbgl_screen_t *) parent)->isUxScreen);
1698 }
1699 else {
1700 // should never happen
1701 fromApp = false;
1702 }
1703 }
1704 // forbid redrawing App screens by UX or vice versa
1705 if ((os_sched_current_task() == TASK_BOLOS_UX) == fromApp) {
1706 return;
1707 }
1708 // actually draw the object and its children, if it is allowed
1709 if (objDrawingDisabled && fromApp) {
1710 return;
1711 }
1712 draw_obj_and_chidren(obj, NULL, computePosition);
1713}
1714
1724
1731{
1732 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1733 return;
1734 }
1735
1738 "nbgl_refreshSpecial(), x0,y0 = [%d, %d], w,h = [%d, %d]\n",
1739 refreshArea.x0,
1740 refreshArea.y0,
1741 refreshArea.width,
1742 refreshArea.height);
1744}
1745
1747{
1748 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1749 return;
1750 }
1751
1752 nbgl_frontRefreshArea(&refreshArea, mode, post_refresh);
1754 "nbgl_refreshSpecialNoPoff(), x0,y0 = [%d, %d], w,h = [%d, %d]\n",
1755 refreshArea.x0,
1756 refreshArea.y0,
1757 refreshArea.width,
1758 refreshArea.height);
1760}
1761
1767{
1768 if ((refreshArea.width == 0) || (refreshArea.height == 0)) {
1769 return false;
1770 }
1771 return true;
1772}
1773
1779{
1780#ifdef HAVE_SERIALIZED_NBGL
1781 io_seph_ux_send_nbgl_serialized(NBGL_REFRESH_AREA, (nbgl_obj_t *) &refreshArea);
1782#endif
1783 refreshArea.x0 = SCREEN_WIDTH - 1;
1784 refreshArea.width = 0;
1785 refreshArea.y0 = SCREEN_HEIGHT - 1;
1786 refreshArea.height = 0;
1787 refreshArea.bpp = NBGL_BPP_2;
1788}
1789
1796{
1797 // init area to the smallest size
1799 objDrawingDisabled = false;
1800#ifdef HAVE_SE_TOUCH
1801 nbgl_touchInit(false);
1802#endif
1803}
1804
1810void nbgl_objAllowDrawing(bool enable)
1811{
1812 objDrawingDisabled = !enable;
1813}
1814
1821{
1822 return ramBuffer;
1823}
1824
1831{
1832 nbgl_obj_t *parent = obj;
1833 // search screen in parenthood
1834 while (parent->parent != NULL) {
1835 parent = parent->parent;
1836 }
1837 if (parent->type == SCREEN) {
1838 return (((nbgl_screen_t *) parent)->isUxScreen);
1839 }
1840 else {
1841 // should never happen
1842 return true;
1843 }
1844}
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
@ OBJ_LOGGER
Definition nbgl_debug.h:30
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.
Definition nbgl_draw.c:535
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.
Definition nbgl_draw.c:584
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.
Definition nbgl_draw.c:369
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...
Definition nbgl_draw.c:857
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.
Definition nbgl_draw.c:270
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
Definition nbgl_fonts.c:477
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:329
nbgl_font_id_e
Definition nbgl_fonts.h:143
@ BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp
Definition nbgl_fonts.h:150
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
Definition nbgl_fonts.c:677
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
return the height in pixels of the font with the given font ID
Definition nbgl_fonts.c:393
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)
Definition nbgl_fonts.c:355
uint16_t nbgl_getTextLength(const char *text)
return the number of bytes of the given text, excluding final ' ' or '\0'
Definition nbgl_fonts.c:449
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
Definition nbgl_fonts.c:727
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
return the height in pixels of the line of font with the given font ID
Definition nbgl_fonts.c:405
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,...
Definition nbgl_fonts.c:343
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)
#define ICON_TEXT_SPACE
#define NB_MAX_LETTERS
Definition nbgl_obj.c:35
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
Definition nbgl_obj.c:1677
void nbgl_refresh(void)
This functions refreshes the actual screen on display with what has changed since the last refresh.
Definition nbgl_obj.c:1720
void nbgl_refreshReset(void)
This functions resets all changes since the last refresh.
Definition nbgl_obj.c:1778
void nbgl_objAllowDrawing(bool enable)
This functions enables or disables drawing/refresh for all further calls.
Definition nbgl_obj.c:1810
void(* draw_function_t)(nbgl_obj_t *obj, nbgl_obj_t *prevObj, bool computePosition)
Definition nbgl_obj.c:60
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:1730
bool nbgl_objIsUx(nbgl_obj_t *obj)
This function returns true if the object belongs to a UxScreen.
Definition nbgl_obj.c:1830
void nbgl_refreshSpecialWithPostRefresh(nbgl_refresh_mode_t mode, nbgl_post_refresh_t post_refresh)
Definition nbgl_obj.c:1746
uint8_t * nbgl_objGetRAMBuffer(void)
This function is used to get the all purpose RAM buffer.
Definition nbgl_obj.c:1820
uint8_t ramBuffer[GZLIB_UNCOMPRESSED_CHUNK]
Definition nbgl_obj.c:146
bool nbgl_refreshIsNeeded(void)
This functions returns true if there is something to refresh.
Definition nbgl_obj.c:1766
void nbgl_objInit(void)
This functions inits all internal of nbgl objects layer.
Definition nbgl_obj.c:1795
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)
#define LIGHT_TEXT_COLOR
Definition nbgl_obj.h:282
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
Definition nbgl_obj.h:261
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
Definition nbgl_obj.h:490
#define BUTTON_STROKE
Definition nbgl_obj.h:283
#define BUTTON_WIDTH
Definition nbgl_obj.h:104
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
API to manage screens.
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
@ NBGL_DRAW_OBJ
@ NBGL_REFRESH_AREA
void nbgl_touchInit(bool fromUx)
Function to initialize the touch context.
Definition nbgl_touch.c:274
color_t
Definition nbgl_types.h:140
@ WHITE
Definition nbgl_types.h:144
@ DARK_GRAY
Definition nbgl_types.h:142
@ LIGHT_GRAY
Definition nbgl_types.h:143
@ BLACK
Definition nbgl_types.h:141
@ OFF_STATE
Definition nbgl_types.h:200
nbgl_post_refresh_t
Post refresh modes.
Definition nbgl_types.h:352
@ POST_REFRESH_FORCE_POWER_OFF
Force screen power off after refresh.
Definition nbgl_types.h:353
#define VERTICAL_MIRROR
Definition nbgl_types.h:97
uint8_t nbgl_color_map_t
Represents the color_map to be used for 2BPP image, or the foreground color for 1BPP image.
Definition nbgl_types.h:390
@ RADIUS_0_PIXELS
no radius (square angle)
Definition nbgl_types.h:376
@ RADIUS_28_PIXELS
Definition nbgl_types.h:366
@ 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.
#define GZLIB_UNCOMPRESSED_CHUNK
size of gzlib uncompression buffer in bytes
Definition nbgl_types.h:305
@ TOP_MIDDLE
Definition nbgl_types.h:182
@ CENTER
Definition nbgl_types.h:185
@ BOTTOM_RIGHT
Definition nbgl_types.h:189
@ TOP_LEFT
Definition nbgl_types.h:181
@ NO_ALIGNMENT
used when parent container layout is used
Definition nbgl_types.h:180
@ BOTTOM_LEFT
Definition nbgl_types.h:187
@ LEFT_TOP
on outside left
Definition nbgl_types.h:190
@ LEFT_BOTTOM
on outside left
Definition nbgl_types.h:191
@ MID_RIGHT
Definition nbgl_types.h:186
@ RIGHT_TOP
on outside right
Definition nbgl_types.h:192
@ TOP_RIGHT
Definition nbgl_types.h:183
@ MID_LEFT
Definition nbgl_types.h:184
@ BOTTOM_MIDDLE
Definition nbgl_types.h:188
@ RIGHT_BOTTOM
on outside right
Definition nbgl_types.h:193
@ KEYPAD
Keypad.
Definition nbgl_types.h:167
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:157
@ IMAGE_FILE
Image file (with Ledger compression)
Definition nbgl_types.h:169
@ TEXT_ENTRY
area for entered text, only for Nanos
Definition nbgl_types.h:170
@ NB_OBJ_TYPES
Definition nbgl_types.h:172
@ SWITCH
Switch to turn on/off something.
Definition nbgl_types.h:161
@ RADIO_BUTTON
Indicator to inform whether something is on or off.
Definition nbgl_types.h:164
@ SPINNER
Spinner.
Definition nbgl_types.h:168
@ 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
@ QR_CODE
QR Code.
Definition nbgl_types.h:165
@ PAGE_INDICATOR
horizontal bar to indicate position within pages
Definition nbgl_types.h:162
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:158
@ KEYBOARD
Keyboard.
Definition nbgl_types.h:166
@ MASK_CONTROL
OS-specific object to enable/disable masked area.
Definition nbgl_types.h:171
@ CONTAINER
Empty container.
Definition nbgl_types.h:156
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:159
@ SCREEN
Main screen.
Definition nbgl_types.h:155
#define MAX(x, y)
Definition nbgl_types.h:121
#define NO_TRANSFORMATION
Definition nbgl_types.h:91
@ NBGL_BPP_1
1 bit per pixel
Definition nbgl_types.h:284
@ NBGL_BPP_2
2 bits per pixel
Definition nbgl_types.h:285
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()
Definition nbgl_types.h:326
@ FULL_COLOR_CLEAN_REFRESH
to be used for lock screen display (cleaner but longer refresh)
Definition nbgl_types.h:329