Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_layout_keypad.c
Go to the documentation of this file.
1
7#ifdef HAVE_SE_TOUCH
8#ifdef NBGL_KEYPAD
9/*********************
10 * INCLUDES
11 *********************/
12#include <string.h>
13#include <stdlib.h>
14#include "nbgl_debug.h"
15#include "nbgl_front.h"
17#include "nbgl_obj.h"
18#include "nbgl_draw.h"
19#include "nbgl_screen.h"
20#include "nbgl_touch.h"
21#include "glyphs.h"
22#include "os_pic.h"
23#include "os_helpers.h"
24#include "os.h"
25
26/*********************
27 * DEFINES
28 *********************/
29
30enum {
34};
35
36#if defined(TARGET_STAX)
37#define ENTRY_DIGITS_LINE_WIDTH 288
38#define ENTRY_DIGITS_CONTAINER_HEIGHT 52
39#define INTER_ENTRY_DIGITS 10
40#define TITLE_MARGIN_Y 8
41#define TITLE_MARGIN_Y_SMALL 8
42#elif defined(TARGET_FLEX)
43#define ENTRY_DIGITS_CONTAINER_HEIGHT 64
44#define INTER_ENTRY_DIGITS 12
45#define TITLE_MARGIN_Y 8
46#define TITLE_MARGIN_Y_SMALL 8
47#elif defined(TARGET_APEX)
48#define ENTRY_DIGITS_CONTAINER_HEIGHT 40
49#define INTER_ENTRY_DIGITS 8
50#define TITLE_MARGIN_Y 13
51#define TITLE_MARGIN_Y_SMALL 2
52#endif // TARGETS
53
54/**********************
55 * MACROS
56 **********************/
57
58/**********************
59 * TYPEDEFS
60 **********************/
61
62/**********************
63 * VARIABLES
64 **********************/
65
66/**********************
67 * STATIC PROTOTYPES
68 **********************/
69
70/**********************
71 * GLOBAL API FUNCTIONS
72 **********************/
73
84int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
85{
86 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
87 nbgl_keypad_t *keypad;
88
89 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeypad():\n");
90 if (layout == NULL) {
91 return -1;
92 }
93 // footer must be empty
94 if (layoutInt->footerContainer != NULL) {
95 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutAddKeypad(): footer already set\n");
96 return -1;
97 }
98
99 // create keypad
100 keypad = (nbgl_keypad_t *) nbgl_objPoolGet(KEYPAD, layoutInt->layer);
101 keypad->obj.alignmentMarginY = 0;
102 keypad->obj.alignment = BOTTOM_MIDDLE;
103 keypad->obj.alignTo = NULL;
104 keypad->obj.area.width = SCREEN_WIDTH;
105 keypad->obj.area.height = 4 * KEYPAD_KEY_HEIGHT;
106 keypad->callback = PIC(callback);
107 keypad->enableDigits = true;
108 keypad->enableBackspace = false;
109 keypad->enableValidate = false;
110 keypad->shuffled = shuffled;
111 keypad->digitsChanged = true;
112 keypad->validateChanged = true;
113
114 // the keypad occupies the footer
115 layoutInt->footerContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
116 layoutInt->footerContainer->obj.area.width = SCREEN_WIDTH;
117 layoutInt->footerContainer->layout = VERTICAL;
118 layoutInt->footerContainer->children
119 = (nbgl_obj_t **) nbgl_containerPoolGet(1, layoutInt->layer);
120 layoutInt->footerContainer->obj.alignment = BOTTOM_MIDDLE;
121 layoutInt->footerContainer->obj.area.height = keypad->obj.area.height;
122 layoutInt->footerContainer->children[layoutInt->footerContainer->nbChildren]
123 = (nbgl_obj_t *) keypad;
124 layoutInt->footerContainer->nbChildren++;
125
126 // add to layout children
127 layoutInt->children[FOOTER_INDEX] = (nbgl_obj_t *) layoutInt->footerContainer;
128
129 // subtract footer height from main container height
130 layoutInt->container->obj.area.height -= layoutInt->footerContainer->obj.area.height;
131
132 layoutInt->footerType = KEYPAD_FOOTER_TYPE;
133
134 return layoutInt->footerContainer->obj.area.height;
135}
136
148 uint8_t index,
149 bool enableValidate,
150 bool enableBackspace,
151 bool enableDigits)
152{
153 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
154 nbgl_keypad_t *keypad;
155
157 "nbgl_layoutUpdateKeypad(): enableValidate = %d, enableBackspace = %d\n",
158 enableValidate,
159 enableBackspace);
160 if (layout == NULL) {
161 return -1;
162 }
163 UNUSED(index);
164
165 // get existing keypad (in the footer container)
166 keypad = (nbgl_keypad_t *) layoutInt->footerContainer->children[0];
167 if ((keypad == NULL) || (keypad->obj.type != KEYPAD)) {
168 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypad(): keypad not found at index %d\n", index);
169 return -1;
170 }
171 // partial redraw only if only validate and backspace have changed
172 keypad->digitsChanged = (keypad->enableDigits != enableDigits);
173 keypad->validateChanged = (keypad->enableValidate != enableValidate);
174 keypad->enableValidate = enableValidate;
175 keypad->enableBackspace = enableBackspace;
176 keypad->enableDigits = enableDigits;
177
178 nbgl_objDraw((nbgl_obj_t *) keypad);
179
180 return 0;
181}
182
191int nbgl_layoutUpdateKeypadValidation(nbgl_layout_t *layout, bool softValidation)
192{
193 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
194 nbgl_keypad_t *keypad;
195
196 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypad(): softValidation = %d,\n", softValidation);
197 if (layout == NULL) {
198 return -1;
199 }
200 UNUSED(index);
201
202 // get existing keypad (in the footer container)
203 keypad = (nbgl_keypad_t *) layoutInt->footerContainer->children[0];
204 if ((keypad == NULL) || (keypad->obj.type != KEYPAD)) {
205 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypadValidation(): keypad not found\n");
206 return -1;
207 }
208 keypad->softValidation = softValidation;
209
210 return 0;
211}
212
230 const char *title,
231 bool hidden,
232 uint8_t nbDigits,
233 const char *text)
234{
235 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
236 nbgl_container_t *container;
237 nbgl_text_area_t *textArea;
238
239 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddKeypadContent():\n");
240 if (layout == NULL) {
241 return -1;
242 }
243 // create a container, to store both title and "digits" (and line on Stax)
244 container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
245 container->nbChildren = NB_CHILDREN;
246 container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer);
247 container->obj.area.width = AVAILABLE_WIDTH;
248 container->obj.alignment = TOP_MIDDLE;
249
250 // create text area for title
251 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
252 textArea->textColor = BLACK;
253 textArea->text = title;
254 textArea->textAlignment = CENTER;
255 textArea->fontId = SMALL_REGULAR_FONT;
256 textArea->wrapping = true;
257 textArea->obj.alignment = TOP_MIDDLE;
258 textArea->obj.area.width = AVAILABLE_WIDTH;
259 textArea->obj.area.height = nbgl_getTextHeightInWidth(
260 textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping);
261 if (textArea->obj.area.height > nbgl_getFontHeight(textArea->fontId)) {
262 container->obj.alignmentMarginY = TITLE_MARGIN_Y_SMALL;
263 }
264 else {
265 container->obj.alignmentMarginY = TITLE_MARGIN_Y;
266 }
267 container->children[TITLE_INDEX] = (nbgl_obj_t *) textArea;
268 container->obj.area.height += textArea->obj.area.height;
269
270 if (hidden) {
271 nbgl_container_t *digitsContainer;
272 uint8_t space;
273
274 if (nbDigits > KEYPAD_MAX_DIGITS) {
276 "nbgl_layoutAddKeypadContent(): nbDigits %d > KEYPAD_MAX_DIGITS %d\n",
277 nbDigits,
279 return -1;
280 }
281 // space between "digits"
282 if (nbDigits > 8) {
283 space = 4;
284 }
285 else {
286 space = INTER_ENTRY_DIGITS;
287 }
288
289 // create digits container, to store "discs"
290 digitsContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer);
291 digitsContainer->nbChildren = nbDigits;
292#ifdef TARGET_STAX
293 // for stax, add line as child
294 digitsContainer->nbChildren++;
295#endif // TARGET_STAX
296 digitsContainer->children
297 = nbgl_containerPoolGet(digitsContainer->nbChildren, layoutInt->layer);
298 // <space> pixels between each icon (knowing that the effective round are 18px large and the
299 // icon 24px)
300#ifdef TARGET_STAX
301 digitsContainer->obj.area.width = ENTRY_DIGITS_LINE_WIDTH;
302#else // TARGET_STAX
303 digitsContainer->obj.area.width = nbDigits * DIGIT_ICON.width + (nbDigits - 1) * space;
304#endif // TARGET_STAX
305 digitsContainer->obj.area.height = ENTRY_DIGITS_CONTAINER_HEIGHT;
306 // align at the bottom of title
307 digitsContainer->obj.alignTo = container->children[0];
308 digitsContainer->obj.alignment = BOTTOM_MIDDLE;
309 container->children[INPUT_INDEX] = (nbgl_obj_t *) digitsContainer;
310 container->obj.area.height += digitsContainer->obj.area.height;
311
312 // create children of the container, as images (empty circles)
314 IMAGE, nbDigits, layoutInt->layer, (nbgl_obj_t **) digitsContainer->children);
315 for (int i = 0; i < nbDigits; i++) {
316 nbgl_image_t *image = (nbgl_image_t *) digitsContainer->children[i];
317 image->buffer = &DIGIT_ICON;
318 image->foregroundColor = WHITE;
319 if (i > 0) {
320 image->obj.alignment = MID_RIGHT;
321 image->obj.alignTo = (nbgl_obj_t *) digitsContainer->children[i - 1];
322 image->obj.alignmentMarginX = space;
323 }
324 else {
325 image->obj.alignment = MID_LEFT;
326 }
327 }
328#ifdef TARGET_STAX
329 nbgl_line_t *line;
330 // create gray line
331 line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer);
332 line->lineColor = LIGHT_GRAY;
333 line->obj.alignTo = container->children[INPUT_INDEX];
334 line->obj.alignment = BOTTOM_MIDDLE;
335 line->obj.area.width = ENTRY_DIGITS_LINE_WIDTH;
336 line->obj.area.height = 4;
337 line->direction = HORIZONTAL;
338 line->thickness = 2;
339 line->offset = 2;
340 digitsContainer->children[nbDigits] = (nbgl_obj_t *) line;
341 digitsContainer->children[0]->alignmentMarginX
342 = (line->obj.area.width - (nbDigits * DIGIT_ICON.width + (nbDigits - 1) * space)) / 2;
343#endif // TARGET_STAX
344 }
345 else {
346 // create text area
347 textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer);
348 textArea->textColor = BLACK;
349 textArea->text = text;
350 textArea->textAlignment = MID_LEFT;
351 textArea->fontId = LARGE_MEDIUM_1BPP_FONT;
352 textArea->obj.area.width = container->obj.area.width;
353 textArea->obj.area.height = nbgl_getFontLineHeight(textArea->fontId);
354 textArea->autoHideLongLine = true;
355 // align at the bottom of title
356 textArea->obj.alignTo = container->children[TITLE_INDEX];
357 textArea->obj.alignment = BOTTOM_MIDDLE;
358#ifdef TARGET_STAX
359 textArea->obj.alignmentMarginY = 24;
360#endif // TARGET_STAX
361 container->children[INPUT_INDEX] = (nbgl_obj_t *) textArea;
362 container->obj.area.height += textArea->obj.area.height;
363 }
364
365 // set this new container as child of the main container
366 layoutAddObject(layoutInt, (nbgl_obj_t *) container);
367
368 // return height of the area
369 return container->obj.area.height;
370}
371
385 bool hidden,
386 uint8_t nbActiveDigits,
387 const char *text)
388{
389 nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout;
390 nbgl_container_t *container;
391 nbgl_image_t *image;
392
393 LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutUpdateHiddenDigits(): nbActive = %d\n", nbActiveDigits);
394 if (layout == NULL) {
395 return -1;
396 }
397
398 UNUSED(index);
399
400 if (hidden) {
401 // get digits container (second child of the main container)
402 container = (nbgl_container_t *) ((nbgl_container_t *) layoutInt->container->children[0])
403 ->children[1];
404 // sanity check
405 if ((container == NULL) || (container->obj.type != CONTAINER)) {
406 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypadContent(): container not found\n");
407 return -1;
408 }
409 if (nbActiveDigits > container->nbChildren) {
411 "nbgl_layoutUpdateKeypadContent(): nbActive %d > nbChildren %d\n",
412 nbActiveDigits,
413 container->nbChildren);
414 return -1;
415 }
416 if (nbActiveDigits == 0) {
417 // deactivate the first digit
418 image = (nbgl_image_t *) container->children[0];
419 if ((image == NULL) || (image->obj.type != IMAGE)) {
420 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypadContent(): image not found\n");
421 return -1;
422 }
423 image->foregroundColor = WHITE;
424 }
425 else {
426 image = (nbgl_image_t *) container->children[nbActiveDigits - 1];
427 if ((image == NULL) || (image->obj.type != IMAGE)) {
428 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypadContent(): image not found\n");
429 return -1;
430 }
431 // if the last "active" is already active, it means that we are decreasing the number of
432 // active otherwise we are increasing it
433 if (image->foregroundColor == BLACK) {
434 // all digits are already active
435 if (nbActiveDigits == container->nbChildren) {
436 return 0;
437 }
438 // deactivate the next digit by turning it to white
439 image = (nbgl_image_t *) container->children[nbActiveDigits];
440 image->foregroundColor = WHITE;
441 }
442 else {
443 // activate it the last digit by turning it to black
444 image->foregroundColor = BLACK;
445 }
446 }
447
448 nbgl_objDraw((nbgl_obj_t *) image);
449 }
450 else {
451 // update main text area (second child of the main container)
452 nbgl_text_area_t *textArea
453 = (nbgl_text_area_t *) ((nbgl_container_t *) layoutInt->container->children[0])
454 ->children[1];
455 if ((textArea == NULL) || (textArea->obj.type != TEXT_AREA)) {
456 LOG_WARN(LAYOUT_LOGGER, "nbgl_layoutUpdateKeypadContent(): text area not found\n");
457 return -1;
458 }
459 textArea->text = text;
460 textArea->textColor = BLACK;
461 textArea->textAlignment = MID_LEFT;
462 nbgl_objDraw((nbgl_obj_t *) textArea);
463
464 // if the text doesn't fit, indicate it by returning 1 instead of 0, for different refresh
465 if (nbgl_getSingleLineTextWidth(textArea->fontId, text) > textArea->obj.area.width) {
466 return 1;
467 }
468 }
469
470 return 0;
471}
472#endif // NBGL_KEYPAD
473#endif // HAVE_SE_TOUCH
debug traces management
#define LOG_WARN(__logger,...)
Definition nbgl_debug.h:87
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
@ LAYOUT_LOGGER
Definition nbgl_debug.h:33
Middle Level API of the new BOLOS Graphical Library.
uint16_t nbgl_getSingleLineTextWidth(nbgl_font_id_e fontId, const char *text)
uint8_t nbgl_getFontHeight(nbgl_font_id_e fontId)
uint16_t nbgl_getTextHeightInWidth(nbgl_font_id_e fontId, const char *text, uint16_t maxWidth, bool wrapping)
uint8_t nbgl_getFontLineHeight(nbgl_font_id_e fontId)
Font screen low-Level driver API, to draw elementary forms.
void layoutAddObject(nbgl_layoutInternal_t *layout, nbgl_obj_t *obj)
adds the given obj to the main container
#define AVAILABLE_WIDTH
void * nbgl_layout_t
type shared externally
Internal functions/constants of NBGL layout layer.
@ FOOTER_INDEX
#define KEYPAD_FOOTER_TYPE
int nbgl_layoutUpdateKeypad(nbgl_layout_t *layout, uint8_t index, bool enableValidate, bool enableBackspace, bool enableDigits)
Updates an existing keypad on bottom of the screen, with the given configuration.
int nbgl_layoutUpdateKeypadValidation(nbgl_layout_t *layout, bool softValidation)
Updates an existing keypad on bottom of the screen, with the given configuration, without redraw.
int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, const char *title, bool hidden, uint8_t nbDigits, const char *text)
Adds an area with a title and a placeholder for hidden digits on top of a keypad, to represent the en...
int nbgl_layoutUpdateKeypadContent(nbgl_layout_t *layout, bool hidden, uint8_t nbActiveDigits, const char *text)
Updates an existing set of hidden digits, with the given configuration.
@ INPUT_INDEX
@ NB_CHILDREN
@ TITLE_INDEX
int nbgl_layoutAddKeypad(nbgl_layout_t *layout, keyboardCallback_t callback, bool shuffled)
Adds a keypad on bottom of the screen, with the associated callback.
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_text_area_s nbgl_text_area_t
struct to represent a text area (TEXT_AREA type)
void nbgl_objDraw(nbgl_obj_t *obj)
nbgl_obj_t ** nbgl_containerPoolGet(uint8_t nbObjs, uint8_t layer)
struct PACKED__ nbgl_keypad_s nbgl_keypad_t
struct to represent a keypad (KEYPAD type)
nbgl_obj_t * nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer)
#define KEYPAD_MAX_DIGITS
Definition nbgl_obj.h:73
struct PACKED__ nbgl_image_s nbgl_image_t
struct to represent an image (IMAGE type)
int nbgl_objPoolGetArray(nbgl_obj_type_t type, uint8_t nbObjs, uint8_t layer, nbgl_obj_t **objArray)
void(* keyboardCallback_t)(char touchedKey)
prototype of function to be called when a valid key is pressed on keyboard Backspace is equal to 0x8 ...
Definition nbgl_obj.h:477
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
@ WHITE
Definition nbgl_types.h:156
@ LIGHT_GRAY
Definition nbgl_types.h:155
@ BLACK
Definition nbgl_types.h:153
@ VERTICAL
from top to bottom
Definition nbgl_types.h:221
@ HORIZONTAL
from left to right
Definition nbgl_types.h:222
@ TOP_MIDDLE
Definition nbgl_types.h:194
@ CENTER
Definition nbgl_types.h:197
@ MID_RIGHT
Definition nbgl_types.h:198
@ MID_LEFT
Definition nbgl_types.h:196
@ BOTTOM_MIDDLE
Definition nbgl_types.h:200
@ KEYPAD
Keypad.
Definition nbgl_types.h:179
@ IMAGE
Bitmap (y and height must be multiple of 4 on Stax)
Definition nbgl_types.h:169
@ LINE
Vertical or Horizontal line.
Definition nbgl_types.h:170
@ CONTAINER
Empty container.
Definition nbgl_types.h:168
@ TEXT_AREA
Area to contain text line(s)
Definition nbgl_types.h:171
Structure containing all information about the current layout.
nbgl_container_t * footerContainer
container used to store footer (buttons, nav....)
uint8_t layer
layer in screen stack
nbgl_container_t * container
nbgl_layoutFooterType_t footerType
type of footer
nbgl_obj_t ** children
children for main screen