diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h index c414ed91..d1c17f49 100644 --- a/lib_nbgl/include/nbgl_layout.h +++ b/lib_nbgl/include/nbgl_layout.h @@ -255,6 +255,17 @@ typedef nbgl_contentTagValueList_t nbgl_layoutTagValueList_t; */ typedef nbgl_contentCenteredInfo_t nbgl_layoutCenteredInfo_t; +/** + * @brief This structure contains info to build a left content area. + * + */ +typedef struct { + uint8_t nbRows; ///< number of rows in the area + const char *title; ///< title of area in bold + const char **rowTexts; ///< array of nbRows texts (displayed in regular) + const nbgl_icon_details_t **rowIcons; ///< array of nbRows icon +} nbgl_layoutLeftContent_t; + #ifdef HAVE_SE_TOUCH /** @@ -583,6 +594,7 @@ typedef struct { nbgl_layout_t *nbgl_layoutGet(const nbgl_layoutDescription_t *description); int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredInfo_t *info); int nbgl_layoutAddContentCenter(nbgl_layout_t *layout, const nbgl_contentCenter_t *info); +int nbgl_layoutAddLeftContent(nbgl_layout_t *layout, const nbgl_layoutLeftContent_t *info); int nbgl_layoutAddProgressBar(nbgl_layout_t *layout, const nbgl_layoutProgressBar_t *barLayout); #ifdef HAVE_SE_TOUCH @@ -605,7 +617,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu int nbgl_layoutAddHorizontalButtons(nbgl_layout_t *layout, const nbgl_layoutHorizontalButtons_t *info); int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueList_t *list); -int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text); +int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text, bool grayedOut); int nbgl_layoutAddTextContent(nbgl_layout_t *layout, const char *title, const char *description, diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 6d0907d0..c4e96137 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -1367,13 +1367,14 @@ int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text) } /** - * @brief Creates an area with given text in 32px font (in Black) + * @brief Creates an area with given text in 32px font (in Black or Light Gray) * * @param layout the current layout * @param text text to be displayed (auto-wrap) + * @param grayedOut if true, use light-gray instead of black * @return >= 0 if OK */ -int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text) +int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text, bool grayedOut) { nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout; nbgl_text_area_t *textArea; @@ -1384,7 +1385,7 @@ int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text) } textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); - textArea->textColor = BLACK; + textArea->textColor = grayedOut ? LIGHT_GRAY : BLACK; textArea->text = PIC(text); textArea->textAlignment = MID_LEFT; textArea->fontId = LARGE_MEDIUM_FONT; @@ -1395,12 +1396,19 @@ int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text) textArea->style = NO_STYLE; textArea->obj.alignment = NO_ALIGNMENT; textArea->obj.alignmentMarginX = BORDER_MARGIN; -#ifdef TARGET_STAX - // if first object of container, increase the margin from top if (layoutInt->container->nbChildren == 0) { +#ifdef TARGET_STAX + // if first object of container, increase the margin from top textArea->obj.alignmentMarginY += BORDER_MARGIN; - } #endif // TARGET_STAX + } + else { +#ifdef TARGET_STAX + textArea->obj.alignmentMarginY = 40; // 40px between paragraphs +#else // TARGET_STAX + textArea->obj.alignmentMarginY = 24; // 24px between paragraphs +#endif // TARGET_STAX + } // set this new obj as child of main container layoutAddObject(layoutInt, (nbgl_obj_t *) textArea); @@ -1677,6 +1685,98 @@ int nbgl_layoutAddContentCenter(nbgl_layout_t *layout, const nbgl_contentCenter_ return container->obj.area.height; } +/** + * @brief Creates an area with a title, and rows of icon + text, left aligned + * + * @param layout the current layout + * @param info structure giving the description of rows (number of rows, title, icons, texts) + * @return >= 0 if OK + */ +int nbgl_layoutAddLeftContent(nbgl_layout_t *layout, const nbgl_layoutLeftContent_t *info) +{ + nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout; + nbgl_container_t *container; + nbgl_text_area_t *textArea; + uint8_t row; + + LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddLeftContent():\n"); + if (layout == NULL) { + return -1; + } + container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer); + + // get container children + container->nbChildren = info->nbRows + 1; + container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer); + container->layout = VERTICAL; + container->obj.area.width = AVAILABLE_WIDTH; + container->obj.alignmentMarginX = BORDER_MARGIN; + + // create title + textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); + textArea->textColor = BLACK; + textArea->text = PIC(info->title); + textArea->textAlignment = MID_LEFT; + textArea->fontId = LARGE_MEDIUM_FONT; + textArea->wrapping = true; + textArea->obj.area.width = AVAILABLE_WIDTH; + textArea->obj.area.height = nbgl_getTextHeightInWidth( + textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); + + container->obj.area.height += textArea->obj.area.height; + + container->children[0] = (nbgl_obj_t *) textArea; + + for (row = 0; row < info->nbRows; row++) { + nbgl_container_t *rowContainer; + nbgl_image_t *image; + + // create a grid with 1 icon on the left column and 1 text on the right one + rowContainer = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, 0); + rowContainer->nbChildren = 2; // 1 icon + 1 text + rowContainer->children = nbgl_containerPoolGet(rowContainer->nbChildren, 0); + rowContainer->obj.area.width = AVAILABLE_WIDTH; + + image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, 0); + image->foregroundColor = BLACK; + image->buffer = info->rowIcons[row]; + rowContainer->children[0] = (nbgl_obj_t *) image; + + textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0); + textArea->textColor = BLACK; + textArea->text = info->rowTexts[row]; + textArea->textAlignment = MID_LEFT; + textArea->fontId = SMALL_REGULAR_FONT; + textArea->wrapping = true; + textArea->obj.alignmentMarginX = 16; + textArea->obj.area.width + = AVAILABLE_WIDTH - image->buffer->width - textArea->obj.alignmentMarginX; + textArea->obj.area.height = nbgl_getTextHeightInWidth( + textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); + textArea->obj.alignment = RIGHT_TOP; + textArea->obj.alignTo = (nbgl_obj_t *) image; + rowContainer->children[1] = (nbgl_obj_t *) textArea; + rowContainer->obj.area.height = MAX(image->buffer->height, textArea->obj.area.height); + + if (row == 0) { + rowContainer->obj.alignmentMarginY = 32; + } + else { +#ifdef TARGET_STAX + rowContainer->obj.alignmentMarginY = 16; +#else // TARGET_STAX + rowContainer->obj.alignmentMarginY = 26; +#endif // TARGET_STAX + } + container->children[1 + row] = (nbgl_obj_t *) rowContainer; + container->obj.area.height + += rowContainer->obj.area.height + rowContainer->obj.alignmentMarginY; + } + layoutAddObject(layoutInt, (nbgl_obj_t *) container); + + return container->obj.area.height; +} + #ifdef NBGL_QRCODE /** * @brief Creates an area on the center of the main panel, with a QRCode, diff --git a/lib_nbgl/src/nbgl_touch.c b/lib_nbgl/src/nbgl_touch.c index b2f2c25a..26be441d 100644 --- a/lib_nbgl/src/nbgl_touch.c +++ b/lib_nbgl/src/nbgl_touch.c @@ -330,6 +330,7 @@ void nbgl_touchHandler(bool fromUx, nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &ctx->firstTouchedPosition); bool consumed = false; + ctx->lastState = touchStatePosition->state; if (swipe != NB_TOUCH_TYPES) { // Swipe detected nbgl_obj_t *swipedObj = getSwipableObject( @@ -359,6 +360,7 @@ void nbgl_touchHandler(bool fromUx, } else { // PRESSED if ((ctx->lastState == PRESSED) && (ctx->lastPressedObj != NULL)) { + ctx->lastState = touchStatePosition->state; if (foundObj != ctx->lastPressedObj) { // finger has moved out of an object // make sure lastPressedObj still belongs to current screen before warning it @@ -373,6 +375,7 @@ void nbgl_touchHandler(bool fromUx, } } else if (ctx->lastState == RELEASED) { + ctx->lastState = touchStatePosition->state; // newly touched object ctx->lastPressedObj = foundObj; ctx->lastPressedTime = currentTime; @@ -380,8 +383,6 @@ void nbgl_touchHandler(bool fromUx, applytouchStatePosition(foundObj, TOUCHING); } } - - ctx->lastState = touchStatePosition->state; } bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj,