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.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(LEFT_BORDER);
77#endif // TARGET_STAX
78
80 nbgl_objDraw((nbgl_obj_t *) topOfStack);
81}
82
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 return nbgl_screenSetAt(0, elements, nbElements, ticker, callback);
245}
246
257int nbgl_screenUpdateNbElements(uint8_t screenIndex, uint8_t nbElements)
258{
259 screenStack[screenIndex].container.nbChildren = nbElements;
260 return 0;
261}
262
274{
275 screenStack[screenIndex].container.obj.area.backgroundColor = color;
276 return 0;
277}
278
290{
291 if (ticker != NULL) {
292 screenStack[screenIndex].ticker.tickerCallback
293 = (nbgl_tickerCallback_t) PIC(ticker->tickerCallback);
294 screenStack[screenIndex].ticker.tickerIntervale = ticker->tickerIntervale;
295 screenStack[screenIndex].ticker.tickerValue = ticker->tickerValue;
296 }
297 else {
298 screenStack[screenIndex].ticker.tickerCallback = NULL;
299 }
300 return 0;
301}
302
313{
314 return screenStack[screenIndex].container.children;
315}
316
331 uint8_t nbElements,
333#ifdef HAVE_SE_TOUCH
334 nbgl_touchCallback_t callback)
335{
336#else // HAVE_SE_TOUCH
337 nbgl_buttonCallback_t callback)
338{
339#endif // HAVE_SE_TOUCH
340 uint8_t screenIndex;
341 if (nbScreensOnStack >= SCREEN_STACK_SIZE) {
343 "nbgl_screenPush(): already in highest index in the stack(%d)\n",
344 nbScreensOnStack - 1);
345 return -1;
346 }
347 // if no screen, consider it as a first fake push
348 if (nbScreensOnStack == 0) {
349 screenIndex = 1; // push at position 1 because 0 is reserved for background
350 topOfStack = &screenStack[screenIndex];
351 topOfStack->next = NULL;
352 // link top of stack to background (even if empty)
353 topOfStack->previous = &screenStack[0];
354 screenStack[0].next = topOfStack;
355 screenStack[0].container.nbChildren = 0;
356 // count empty background as an active screen
357 nbScreensOnStack++;
358 }
359 else {
360 // find a non used screen in the array
361 for (screenIndex = 1; screenIndex < SCREEN_STACK_SIZE; screenIndex++) {
362 if (screenStack[screenIndex].previous == NULL) {
363 // if no previous, means unused, so take it
364 // update previous topOfStack
365 topOfStack->next = &screenStack[screenIndex];
366 screenStack[screenIndex].previous = topOfStack;
367#ifdef HAVE_SE_TOUCH
368 nbgl_touchStatePosition_t touchStatePosition = {.state = RELEASED, .x = 0, .y = 0};
369 // make a fake touch release for the current top-of-stack to avoid issue
370 // (for example in long-touch press)
371 nbgl_touchHandler(topOfStack->isUxScreen, &touchStatePosition, 0);
372#endif // HAVE_SE_TOUCH
373 // new top of stack
374 topOfStack = &screenStack[screenIndex];
375 topOfStack->next = NULL;
376 break;
377 }
378 }
379 if (screenIndex == SCREEN_STACK_SIZE) {
380 // should never happen
381 LOG_WARN(SCREEN_LOGGER, "nbgl_screenPush(): corruption in stack\n");
382 }
383 }
384 if (nbgl_screenSetAt(screenIndex, elements, nbElements, ticker, callback) >= 0) {
385 nbScreensOnStack++;
386 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenPush(): screen %d is now top of stack\n", screenIndex);
387 return screenIndex;
388 }
389 else {
390 return -1;
391 }
392}
393
403int nbgl_screenPop(uint8_t screenIndex)
404{
405 if (nbScreensOnStack == 0) {
406 LOG_WARN(SCREEN_LOGGER, "nbgl_screenPop(): already in lowest index in the stack\n");
407 return -1;
408 }
409 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenPop(): at index %d\n", screenIndex);
410 nbScreensOnStack--;
411 // move top of stack if needed
412 if (&screenStack[screenIndex] == topOfStack) {
413 if (nbScreensOnStack == 0) {
414 topOfStack = NULL;
415 }
416 else {
417 topOfStack = topOfStack->previous;
418 }
419 }
420 else {
421 // connect previous to next
422 if (screenStack[screenIndex].previous != NULL) {
423 screenStack[screenIndex].previous->next = screenStack[screenIndex].next;
424 }
425 if (screenStack[screenIndex].next != NULL) {
426 screenStack[screenIndex].next->previous = screenStack[screenIndex].previous;
427 }
428 }
429 // free slot
430 screenStack[screenIndex].previous = NULL;
431 screenStack[screenIndex].next = NULL;
432 screenStack[screenIndex].container.nbChildren = 0;
433 screenStack[screenIndex].container.children = NULL;
434 // release used objects and containers
435 nbgl_objPoolRelease(screenIndex);
436 nbgl_containerPoolRelease(screenIndex);
437
438 // special case when we pop the only modal and no real background is under it
439 if ((nbScreensOnStack == 1) && (screenStack[0].container.nbChildren == 0)) {
440 nbScreensOnStack = 0;
441 topOfStack = NULL;
442 }
443 return 0;
444}
445
453{
454 uint8_t screenIndex;
455 for (screenIndex = 0; screenIndex < SCREEN_STACK_SIZE; screenIndex++) {
456 if ((screenStack[screenIndex].previous != NULL)
457 || (screenStack[screenIndex].next != NULL)) {
458 // release used objects and containers
459 nbgl_objPoolRelease(screenIndex);
460 nbgl_containerPoolRelease(screenIndex);
461 }
462 screenStack[screenIndex].container.children = NULL;
463 screenStack[screenIndex].container.nbChildren = 0;
464 }
465 nbScreensOnStack = 0;
466 topOfStack = NULL;
467 return 1;
468}
469
475void nbgl_screenHandler(uint32_t intervaleMs)
476{
477 // ensure a screen exists
478 if (nbScreensOnStack == 0) {
479 return;
480 }
481 // call ticker callback of top of stack if active and not expired yet (for a non periodic)
482 if ((topOfStack->ticker.tickerCallback != NULL) && (topOfStack->ticker.tickerValue != 0)) {
483 topOfStack->ticker.tickerValue -= MIN(topOfStack->ticker.tickerValue, intervaleMs);
484 if (topOfStack->ticker.tickerValue == 0) {
485 // rearm if intervale is not null, and call the registered function
486 topOfStack->ticker.tickerValue = topOfStack->ticker.tickerIntervale;
487 topOfStack->ticker.tickerCallback();
488 }
489 }
490}
491
499static bool objIsIn(nbgl_obj_t *refObj, nbgl_obj_t *obj)
500{
501 uint8_t i;
502
503 if (obj == NULL) {
504 return false;
505 }
506 if ((nbgl_obj_t *) refObj == obj) {
507 LOG_DEBUG(SCREEN_LOGGER, "nbgl_screenContainsObj(): yes\n");
508 return true;
509 }
510
511 if ((refObj->type == SCREEN) || (refObj->type == CONTAINER)) {
512 nbgl_container_t *container = (nbgl_container_t *) refObj;
513 // draw the children, if any
514 if (container->children != NULL) {
515 for (i = 0; i < container->nbChildren; i++) {
516 nbgl_obj_t *current = container->children[i];
517 if (current != NULL) {
518 if (objIsIn(current, obj) == true) {
519 return true;
520 }
521 }
522 }
523 }
524 }
525 return false;
526}
527
535static nbgl_obj_t *objIsOfType(nbgl_obj_t *refObj, nbgl_obj_type_t type)
536{
537 uint8_t i;
538
539 if (refObj->type == type) {
540 LOG_DEBUG(SCREEN_LOGGER, "objIsOfType(): yes\n");
541 return refObj;
542 }
543
544 if ((refObj->type == SCREEN) || (refObj->type == CONTAINER)) {
545 nbgl_container_t *container = (nbgl_container_t *) refObj;
546 // draw the children, if any
547 if (container->children != NULL) {
548 for (i = 0; i < container->nbChildren; i++) {
549 nbgl_obj_t *current = container->children[i];
550 if (current != NULL) {
551 nbgl_obj_t *found = objIsOfType(current, type);
552 if (found) {
553 return found;
554 }
555 }
556 }
557 }
558 }
559 return NULL;
560}
561
569{
570 if (nbScreensOnStack == 0) {
571 return false;
572 }
573 return objIsIn((nbgl_obj_t *) topOfStack, obj);
574}
575
584{
585 if (nbScreensOnStack == 0) {
586 return NULL;
587 }
588
589 return objIsOfType((nbgl_obj_t *) screen, type);
590}
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:242
void nbgl_objDraw(nbgl_obj_t *obj)
This function draws or redraws the given object and its children (recursive version)
Definition nbgl_obj.c:1520
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:221
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_touchHandler(bool fromUx, nbgl_touchStatePosition_t *touchEvent, uint32_t currentTimeMs)
Function to be called periodically to check touchscreen state and coordinates.
Definition nbgl_touch.c:285
color_t
Definition nbgl_types.h:120
@ WHITE
Definition nbgl_types.h:124
@ BLACK
Definition nbgl_types.h:121
@ VERTICAL
from top to bottom
Definition nbgl_types.h:189
#define MIN(x, y)
Definition nbgl_types.h:98
nbgl_obj_type_t
All types of graphical objects.
Definition nbgl_types.h:134
@ CONTAINER
Empty container.
Definition nbgl_types.h:136
@ SCREEN
Main screen.
Definition nbgl_types.h:135
@ RELEASED
the finger has been released from the screen
Definition nbgl_types.h:220
The low level Touchscreen event, coming from driver.
Definition nbgl_obj.h:227
nbgl_touchState_t state
state of the touch event, e.g PRESSED or RELEASED
Definition nbgl_obj.h:228
unsigned char uint8_t
Definition usbd_conf.h:53