Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_screen.c
Go to the documentation of this file.
1
6/*********************
7 * INCLUDES
8 *********************/
9#include "app_config.h"
10#include "nbgl_front.h"
11#include "nbgl_screen.h"
12#include "nbgl_debug.h"
13#include "nbgl_touch.h"
14#include "os_pic.h"
15#include "os_io_seph_ux.h"
16#include "os_task.h"
17
18/*********************
19 * DEFINES
20 *********************/
21
39#define SCREEN_STACK_SIZE 4
40
41/**********************
42 * TYPEDEFS
43 **********************/
44
45/**********************
46 * VARIABLES
47 **********************/
48static nbgl_screen_t screenStack[SCREEN_STACK_SIZE];
49// number of screens in the stack
50static uint8_t nbScreensOnStack = 0;
51// this is a pointer of the current top of stack screen
52static nbgl_screen_t *topOfStack;
53
54/**********************
55 * STATIC PROTOTYPES
56 **********************/
57
58/**********************
59 * GLOBAL FUNCTIONS
60 **********************/
61
67{
68 if (nbScreensOnStack == 0) {
69 LOG_WARN(SCREEN_LOGGER, "nbgl_screenRedraw(): no screen to redraw\n");
70 return;
71 }
72 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenRedraw(): nbScreensOnStack = %d\n", nbScreensOnStack);
73#ifdef TARGET_STAX
74 // by default, exclude only left border from touch
75 // if any sub-object is a keyboard, this will be modified when drawing it
76 touch_exclude_borders(OS_IO_TOUCH_AREA_LEFT_BORDER);
77#endif // TARGET_STAX
78
80 nbgl_objDraw((nbgl_obj_t *) topOfStack);
81}
82
88nbgl_obj_t *nbgl_screenGetAt(uint8_t screenIndex)
89{
90 if (screenIndex < nbScreensOnStack) {
91 return (nbgl_obj_t *) &screenStack[screenIndex];
92 }
93 else {
94 return NULL;
95 }
96}
97
103{
104 if (nbScreensOnStack > 0) {
105 return (nbgl_obj_t *) topOfStack;
106 }
107 else {
108 return NULL;
109 }
110}
111
117{
118 if ((nbScreensOnStack == 1) && (screenStack[0].container.nbChildren == 0)) {
119 return 0;
120 }
121 return nbScreensOnStack;
122}
123
129{
130 uint8_t nbUxScreens = 0;
131 nbgl_screen_t *screen = (nbgl_screen_t *) topOfStack;
132
134 return 0;
135 }
136 while (screen != NULL) {
137 if (screen->isUxScreen) {
138 nbUxScreens++;
139 }
140 screen = screen->previous;
141 }
142 return nbUxScreens;
143}
144
161static int nbgl_screenSetAt(uint8_t screenIndex,
162 nbgl_obj_t ***children,
163 uint8_t nbChildren,
165#ifdef HAVE_SE_TOUCH
166 nbgl_touchCallback_t callback)
167{
168#else // HAVE_SE_TOUCH
169 nbgl_buttonCallback_t callback)
170{
171#endif // HAVE_SE_TOUCH
172 if (screenIndex >= SCREEN_STACK_SIZE) {
173 LOG_WARN(SCREEN_LOGGER, "nbgl_screenSetAt(): forbidden screenIndex (%d)\n", screenIndex);
174 return -1;
175 }
176 *children = nbgl_containerPoolGet(nbChildren, screenIndex);
177 screenStack[screenIndex].container.obj.type = SCREEN;
178#ifdef HAVE_SE_TOUCH
179 screenStack[screenIndex].container.obj.area.backgroundColor = WHITE;
180#else // HAVE_SE_TOUCH
181 screenStack[screenIndex].container.obj.area.backgroundColor = BLACK;
182#endif // HAVE_SE_TOUCH
183 screenStack[screenIndex].container.obj.area.height = SCREEN_HEIGHT;
184 screenStack[screenIndex].container.obj.area.width = SCREEN_WIDTH;
185 screenStack[screenIndex].container.obj.area.x0 = 0;
186 screenStack[screenIndex].container.obj.area.y0 = 0;
187 screenStack[screenIndex].container.obj.rel_x0 = 0;
188 screenStack[screenIndex].container.obj.rel_y0 = 0;
189 screenStack[screenIndex].index = screenIndex;
190 screenStack[screenIndex].container.layout = VERTICAL;
191 screenStack[screenIndex].container.children = *children;
192 screenStack[screenIndex].container.nbChildren = nbChildren;
193#ifdef HAVE_SE_TOUCH
194 screenStack[screenIndex].touchCallback = callback;
195#else // HAVE_SE_TOUCH
196 screenStack[screenIndex].buttonCallback = callback;
197#endif // HAVE_SE_TOUCH
198 if (ticker != NULL) {
199 screenStack[screenIndex].ticker.tickerCallback
200 = (nbgl_tickerCallback_t) PIC(ticker->tickerCallback);
201 screenStack[screenIndex].ticker.tickerIntervale = ticker->tickerIntervale;
202 screenStack[screenIndex].ticker.tickerValue = ticker->tickerValue;
203 }
204 else {
205 screenStack[screenIndex].ticker.tickerCallback = NULL;
206 }
207 screenStack[screenIndex].isUxScreen = (os_sched_current_task() == TASK_BOLOS_UX);
208 return 0;
209}
210
226 uint8_t nbElements,
228#ifdef HAVE_SE_TOUCH
229 nbgl_touchCallback_t callback)
230{
231#else // HAVE_SE_TOUCH
232 nbgl_buttonCallback_t callback)
233{
234#endif // HAVE_SE_TOUCH
235 // if no screen, consider it as a first fake push
236 if (nbScreensOnStack == 0) {
237 nbScreensOnStack++;
238 topOfStack = &screenStack[0];
239 }
240 // release used objects and containers
243 // always use the first layer (background) for user application
244 int ret = nbgl_screenSetAt(0, elements, nbElements, ticker, callback);
245#ifdef HAVE_SE_TOUCH
246 // if it's the only screen on stack, clear the touch automatum to avoid fake touch
247 if (nbScreensOnStack == 1) {
248 nbgl_touchClear(topOfStack->isUxScreen);
249 }
250#endif // HAVE_SE_TOUCH
251 return ret;
252}
253
264int nbgl_screenUpdateNbElements(uint8_t screenIndex, uint8_t nbElements)
265{
266 screenStack[screenIndex].container.nbChildren = nbElements;
267 return 0;
268}
269
280int nbgl_screenUpdateBackgroundColor(uint8_t screenIndex, color_t color)
281{
282 screenStack[screenIndex].container.obj.area.backgroundColor = color;
283 return 0;
284}
285
296int nbgl_screenUpdateTicker(uint8_t screenIndex, const nbgl_screenTickerConfiguration_t *ticker)
297{
298 if (ticker != NULL) {
299 screenStack[screenIndex].ticker.tickerCallback
300 = (nbgl_tickerCallback_t) PIC(ticker->tickerCallback);
301 screenStack[screenIndex].ticker.tickerIntervale = ticker->tickerIntervale;
302 screenStack[screenIndex].ticker.tickerValue = ticker->tickerValue;
303 }
304 else {
305 screenStack[screenIndex].ticker.tickerCallback = NULL;
306 }
307 return 0;
308}
309
319nbgl_obj_t **nbgl_screenGetElements(uint8_t screenIndex)
320{
321 return screenStack[screenIndex].container.children;
322}
323
338 uint8_t nbElements,
340#ifdef HAVE_SE_TOUCH
341 nbgl_touchCallback_t callback)
342{
343#else // HAVE_SE_TOUCH
344 nbgl_buttonCallback_t callback)
345{
346#endif // HAVE_SE_TOUCH
347 uint8_t screenIndex;
348 if (nbScreensOnStack >= SCREEN_STACK_SIZE) {
350 "nbgl_screenPush(): already in highest index in the stack(%d)\n",
351 nbScreensOnStack - 1);
352 return -1;
353 }
354 // if no screen, consider it as a first fake push
355 if (nbScreensOnStack == 0) {
356 screenIndex = 1; // push at position 1 because 0 is reserved for background
357 topOfStack = &screenStack[screenIndex];
358 topOfStack->next = NULL;
359 // link top of stack to background (even if empty)
360 topOfStack->previous = &screenStack[0];
361 screenStack[0].next = topOfStack;
362 screenStack[0].container.nbChildren = 0;
363 // count empty background as an active screen
364 nbScreensOnStack++;
365 }
366 else {
367 // find a non used screen in the array
368 for (screenIndex = 1; screenIndex < SCREEN_STACK_SIZE; screenIndex++) {
369 if (screenStack[screenIndex].previous == NULL) {
370 // if no previous, means unused, so take it
371 // update previous topOfStack
372 topOfStack->next = &screenStack[screenIndex];
373 screenStack[screenIndex].previous = topOfStack;
374 // search for a potential progress bar in current topOfStack to reset it if needed
375 nbgl_progress_bar_t *progress
377 if ((progress != NULL) && (progress->resetIfOverriden)) {
378 progress->state = 0;
379 }
380 // new top of stack
381 topOfStack = &screenStack[screenIndex];
382 topOfStack->next = NULL;
383 break;
384 }
385 }
386 if (screenIndex == SCREEN_STACK_SIZE) {
387 // should never happen
388 LOG_WARN(SCREEN_LOGGER, "nbgl_screenPush(): corruption in stack\n");
389 }
390 }
391 if (nbgl_screenSetAt(screenIndex, elements, nbElements, ticker, callback) >= 0) {
392 nbScreensOnStack++;
393 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenPush(): screen %d is now top of stack\n", screenIndex);
394#ifdef HAVE_SE_TOUCH
395 // clear the touch automatum to avoid fake touch
396 nbgl_touchClear(topOfStack->isUxScreen);
397#endif // HAVE_SE_TOUCH
398 return screenIndex;
399 }
400 else {
401 return -1;
402 }
403}
404
414int nbgl_screenPop(uint8_t screenIndex)
415{
416 if (nbScreensOnStack == 0) {
417 LOG_WARN(SCREEN_LOGGER, "nbgl_screenPop(): already in lowest index in the stack\n");
418 return -1;
419 }
420 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenPop(): at index %d\n", screenIndex);
421 nbScreensOnStack--;
422 // move top of stack if needed
423 if (&screenStack[screenIndex] == topOfStack) {
424 if (nbScreensOnStack == 0) {
425 topOfStack = NULL;
426 }
427 else {
428 topOfStack = topOfStack->previous;
429 }
430 }
431 else {
432 // connect previous to next
433 if (screenStack[screenIndex].previous != NULL) {
434 screenStack[screenIndex].previous->next = screenStack[screenIndex].next;
435 }
436 if (screenStack[screenIndex].next != NULL) {
437 screenStack[screenIndex].next->previous = screenStack[screenIndex].previous;
438 }
439 }
440 // free slot
441 screenStack[screenIndex].previous = NULL;
442 screenStack[screenIndex].next = NULL;
443 screenStack[screenIndex].container.nbChildren = 0;
444 screenStack[screenIndex].container.children = NULL;
445 // release used objects and containers
446 nbgl_objPoolRelease(screenIndex);
447 nbgl_containerPoolRelease(screenIndex);
448
449 // special case when we pop the only modal and no real background is under it
450 if ((nbScreensOnStack == 1) && (screenStack[0].container.nbChildren == 0)) {
451 nbScreensOnStack = 0;
452 topOfStack = NULL;
453 }
454 return 0;
455}
456
464{
465 uint8_t screenIndex;
466 for (screenIndex = 0; screenIndex < SCREEN_STACK_SIZE; screenIndex++) {
467 if ((screenStack[screenIndex].previous != NULL)
468 || (screenStack[screenIndex].next != NULL)) {
469 // release used objects and containers
470 nbgl_objPoolRelease(screenIndex);
471 nbgl_containerPoolRelease(screenIndex);
472 }
473 screenStack[screenIndex].container.children = NULL;
474 screenStack[screenIndex].container.nbChildren = 0;
475 }
476 nbScreensOnStack = 0;
477 topOfStack = NULL;
478 return 1;
479}
480
486void nbgl_screenHandler(uint32_t intervaleMs)
487{
488 // ensure a screen exists
489 if (nbScreensOnStack == 0) {
490 return;
491 }
492 // call ticker callback of top of stack if active and not expired yet (for a non periodic)
493 if ((topOfStack->ticker.tickerCallback != NULL) && (topOfStack->ticker.tickerValue != 0)) {
494 topOfStack->ticker.tickerValue -= MIN(topOfStack->ticker.tickerValue, intervaleMs);
495 if (topOfStack->ticker.tickerValue == 0) {
496 // rearm if intervale is not null, and call the registered function
497 topOfStack->ticker.tickerValue = topOfStack->ticker.tickerIntervale;
498 topOfStack->ticker.tickerCallback();
499 }
500 }
501}
502
510static bool objIsIn(nbgl_obj_t *refObj, nbgl_obj_t *obj)
511{
512 uint8_t i;
513
514 if (obj == NULL) {
515 return false;
516 }
517 if ((nbgl_obj_t *) refObj == obj) {
518 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenContainsObj(): yes\n");
519 return true;
520 }
521
522 if ((refObj->type == SCREEN) || (refObj->type == CONTAINER)) {
523 nbgl_container_t *container = (nbgl_container_t *) refObj;
524 // draw the children, if any
525 if (container->children != NULL) {
526 for (i = 0; i < container->nbChildren; i++) {
527 nbgl_obj_t *current = container->children[i];
528 if (current != NULL) {
529 if (objIsIn(current, obj) == true) {
530 return true;
531 }
532 }
533 }
534 }
535 }
536 return false;
537}
538
546static nbgl_obj_t *objIsOfType(nbgl_obj_t *refObj, nbgl_obj_type_t type)
547{
548 uint8_t i;
549
550 if (refObj->type == type) {
551 LOG_DEBUG(SCREEN_LOGGER, "objIsOfType(): yes\n");
552 return refObj;
553 }
554
555 if ((refObj->type == SCREEN) || (refObj->type == CONTAINER)) {
556 nbgl_container_t *container = (nbgl_container_t *) refObj;
557 // draw the children, if any
558 if (container->children != NULL) {
559 for (i = 0; i < container->nbChildren; i++) {
560 nbgl_obj_t *current = container->children[i];
561 if (current != NULL) {
562 nbgl_obj_t *found = objIsOfType(current, type);
563 if (found) {
564 return found;
565 }
566 }
567 }
568 }
569 }
570 return NULL;
571}
572
580{
581 if (nbScreensOnStack == 0) {
582 return false;
583 }
584 return objIsIn((nbgl_obj_t *) topOfStack, obj);
585}
586
595{
596 if (nbScreensOnStack == 0) {
597 return NULL;
598 }
599
600 return objIsOfType((nbgl_obj_t *) screen, type);
601}
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
@ SCREEN_LOGGER
Definition nbgl_debug.h:32
Font screen low-Level driver API, to draw elementary forms.
void(* nbgl_touchCallback_t)(void *obj, nbgl_touchType_t eventType)
prototype of function to be called when a touch event is received by an object
Definition nbgl_obj.h:346
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
Definition nbgl_obj.c:1662
struct PACKED__ nbgl_progress_bar_s nbgl_progress_bar_t
struct to represent a progress bar (PROGRESS_BAR type)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
Gets a new container from the pool, with the given number of obj pointers.
void nbgl_containerPoolRelease(uint8_t layer)
Release the objects pointers from the pool for the given layer.
void(* nbgl_buttonCallback_t)(void *obj, nbgl_buttonEvent_t buttonEvent)
prototype of function to be called when a button event is received by an object (TODO: change to scre...
Definition nbgl_obj.h:325
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
void nbgl_objPoolRelease(uint8_t layer)
Release the objects from the pool for the given layer.
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
#define SCREEN_STACK_SIZE
Max number of stackable screens.
Definition nbgl_screen.c:39
int nbgl_screenSet(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t callback)
Configures the lowest layer screen. To be used by applications A nbgl_screenRedraw() can be called af...
int nbgl_screenPush(nbgl_obj_t ***elements, uint8_t nbElements, const nbgl_screenTickerConfiguration_t *ticker, nbgl_touchCallback_t callback)
Pushes a screen on top of the stack, with the given number of elements, if possible....
int nbgl_screenUpdateNbElements(uint8_t screenIndex, uint8_t nbElements)
Updates the number of children on given layer. can only be smaller than the number given in nbgl_scre...
int nbgl_screenUpdateTicker(uint8_t screenIndex, const nbgl_screenTickerConfiguration_t *ticker)
Updates the ticker configuration of the screen at the given screenIndex, always set at WHITE in.
bool nbgl_screenContainsObj(nbgl_obj_t *obj)
return true if the given obj can be found in refObj or any of its children
nbgl_obj_t * nbgl_screenGetAt(uint8_t screenIndex)
Returns the screen on the given layer index, as a generic object.
Definition nbgl_screen.c:88
int nbgl_screenReset(void)
Releases all screens and objects and resets the screen stack. It is supposed to be called before runn...
nbgl_obj_t ** nbgl_screenGetElements(uint8_t screenIndex)
Returns the array of elements (children) of the screen at the given index (return value of nbgl_scree...
uint8_t nbgl_screenGetUxStackSize(void)
Returns the number of used UX screens on stack.
nbgl_obj_t * nbgl_screenGetTop(void)
Returns the screen on top layer, as a generic object.
int nbgl_screenPop(uint8_t screenIndex)
Release the screen at the given index in screen array (index returned by nbgl_screenPush())....
uint8_t nbgl_screenGetCurrentStackSize(void)
Returns the number of used screens on stack.
int nbgl_screenUpdateBackgroundColor(uint8_t screenIndex, color_t color)
Updates the background color of the screen at the given screenIndex, always set at WHITE in.
nbgl_obj_t * nbgl_screenContainsObjType(nbgl_screen_t *screen, nbgl_obj_type_t type)
return an object of the given type in the given screen
void nbgl_screenRedraw(void)
This function redraws the whole screen on top of stack and its children.
Definition nbgl_screen.c:66
void nbgl_screenHandler(uint32_t intervaleMs)
Function to be called periodically by system to enable using ticker.
API to manage screens.
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
void(* nbgl_tickerCallback_t)(void)
prototype of function to be called when a timer on screen is fired
Definition nbgl_screen.h:32
struct PACKED__ nbgl_screenTickerConfiguration_s nbgl_screenTickerConfiguration_t
struct to configure a screen layer
void nbgl_screen_reinit(void)
void nbgl_touchClear(bool fromUx)
Clears the context (to be used when the screen is set/pushed)
Definition nbgl_touch.c:460
color_t
Definition nbgl_types.h:140
@ WHITE
Definition nbgl_types.h:144
@ BLACK
Definition nbgl_types.h:141
@ VERTICAL
from top to bottom
Definition nbgl_types.h:209
#define MIN(x, y)
Definition nbgl_types.h:118
nbgl_obj_type_t
All types of graphical objects.
Definition nbgl_types.h:154
@ PROGRESS_BAR
horizontal bar to indicate progression of something (between 0% and 100%)
Definition nbgl_types.h:163
@ CONTAINER
Empty container.
Definition nbgl_types.h:156
@ SCREEN
Main screen.
Definition nbgl_types.h:155