From 2500b9da8f45b25df10d778c4d29f0eddf6b3b10 Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 13:20:19 +0100 Subject: [PATCH 1/6] Add nbgl_layoutAddChoiceButtonsIcon --- lib_nbgl/include/nbgl_layout.h | 3 +++ lib_nbgl/src/nbgl_layout.c | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h index 3b1971de8..992ee8c4f 100644 --- a/lib_nbgl/include/nbgl_layout.h +++ b/lib_nbgl/include/nbgl_layout.h @@ -320,6 +320,9 @@ int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subT int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoice_t *choices); int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info); int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info); +int nbgl_layoutAddChoiceButtonsIcon(nbgl_layout_t *layout, + const nbgl_layoutChoiceButtons_t *info, + const nbgl_icon_details_t *topIcon); int nbgl_layoutAddTagValueList(nbgl_layout_t *layout, const nbgl_layoutTagValueList_t *list); int nbgl_layoutAddLargeCaseText(nbgl_layout_t *layout, const char *text); int nbgl_layoutAddSeparationLine(nbgl_layout_t *layout); diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index fc0bb4732..118e34267 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -1944,9 +1944,12 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) * * @param layout the current layout * @param info structure giving the description of buttons (texts, icons, layout) + * @param topIcon buffer containing the 1BPP icon for top button * @return >= 0 if OK */ -int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info) +int nbgl_layoutAddChoiceButtonsIcon(nbgl_layout_t *layout, + const nbgl_layoutChoiceButtons_t *info, + const nbgl_icon_details_t *topIcon) { layoutObj_t *obj; nbgl_button_t *topButton, *bottomButton; @@ -2007,6 +2010,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu else { topButton->obj.alignmentMarginY = 4; // 4 pixels from bottom button } + topButton->icon = PIC(topIcon); topButton->innerColor = BLACK; topButton->borderColor = BLACK; topButton->foregroundColor = WHITE; @@ -2023,6 +2027,18 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu return 0; } +/** + * @brief Creates two buttons to make a choice. Both buttons are mandatory + * + * @param layout the current layout + * @param info structure giving the description of buttons (texts, icons, layout) + * @return >= 0 if OK + */ +int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info) +{ + return nbgl_layoutAddChoiceButtonsIcon(layout, info, NULL); +} + /** * @brief Creates a list of [tag,value] pairs * From 3b1f86af24dbdc9016e3cded598c05bf83c916ac Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 13:22:47 +0100 Subject: [PATCH 2/6] Add nbgl_layoutAddQRCodeIcon - Allow text1 and text2, instead of text1 or text2 - Add icon between the QR Code and the text lines - Increase max layout children up tp 4 - Force QR Code V10 (smaller than V4) if icon and text1 and text2 are provided --- lib_nbgl/include/nbgl_layout.h | 3 ++ lib_nbgl/src/nbgl_layout.c | 55 +++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h index 992ee8c4f..c7a836f66 100644 --- a/lib_nbgl/include/nbgl_layout.h +++ b/lib_nbgl/include/nbgl_layout.h @@ -319,6 +319,9 @@ int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switc int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText); int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoice_t *choices); int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info); +int nbgl_layoutAddQRCodeIcon(nbgl_layout_t *layout, + const nbgl_layoutQRCode_t *info, + const nbgl_icon_details_t *icon); int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info); int nbgl_layoutAddChoiceButtonsIcon(nbgl_layout_t *layout, const nbgl_layoutChoiceButtons_t *info, diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 118e34267..3b1688d12 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -1834,13 +1834,17 @@ int nbgl_layoutAddCenteredInfo(nbgl_layout_t *layout, const nbgl_layoutCenteredI * * @param layout the current layout * @param info structure giving the description of buttons (texts, icons, layout) + * @param icon icon between QR code and text line(s) * @return >= 0 if OK */ -int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) +int nbgl_layoutAddQRCodeIcon(nbgl_layout_t *layout, + const nbgl_layoutQRCode_t *info, + const nbgl_icon_details_t *icon) { nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout; nbgl_container_t *container; nbgl_text_area_t *textArea = NULL; + nbgl_image_t *image = NULL; nbgl_qrcode_t *qrcode; uint16_t fullHeight = 0; @@ -1851,13 +1855,14 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer); - // get container children (max 2 (QRCode + text1/text2)) - container->children = nbgl_containerPoolGet(2, layoutInt->layer); + // get container children (max 4: QRCode + icon + text1 + text2) + container->children = nbgl_containerPoolGet(4, layoutInt->layer); container->nbChildren = 0; qrcode = (nbgl_qrcode_t *) nbgl_objPoolGet(QR_CODE, layoutInt->layer); // version is forced to V10 if url is longer than 62 characters - if (strlen(PIC(info->url)) > 62) { + if ((strlen(PIC(info->url)) > 62) + || ((icon != NULL) && (info->text1 != NULL) && (info->text2 != NULL))) { qrcode->version = QRCODE_V10; } else { @@ -1878,6 +1883,19 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) container->children[container->nbChildren] = (nbgl_obj_t *) qrcode; container->nbChildren++; + if (icon != NULL) { + image = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer); + image->foregroundColor = BLACK; + image->buffer = PIC(icon); + image->obj.area.bpp = NBGL_BPP_1; + image->obj.alignment = BOTTOM_MIDDLE; + image->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1]; + image->obj.alignmentMarginY = 16; + + fullHeight += image->buffer->height; + container->children[container->nbChildren] = (nbgl_obj_t *) image; + container->nbChildren++; + } if (info->text1 != NULL) { textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); textArea->textColor = BLACK; @@ -1890,14 +1908,18 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); textArea->obj.alignment = BOTTOM_MIDDLE; textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1]; - textArea->obj.alignmentMarginY = 40; - + if (icon == NULL) { + textArea->obj.alignmentMarginY = 40; + } + else { + textArea->obj.alignmentMarginY = 12; + } fullHeight += textArea->obj.area.height; container->children[container->nbChildren] = (nbgl_obj_t *) textArea; container->nbChildren++; } - else if (info->text2 != NULL) { + if (info->text2 != NULL) { textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); textArea->textColor = DARK_GRAY; textArea->text = PIC(info->text2); @@ -1909,7 +1931,12 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); textArea->obj.alignment = BOTTOM_MIDDLE; textArea->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1]; - textArea->obj.alignmentMarginY = 40; + if (icon == NULL) { + textArea->obj.alignmentMarginY = 40; + } + else { + textArea->obj.alignmentMarginY = 12; + } fullHeight += textArea->obj.area.height; @@ -1936,6 +1963,18 @@ int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) return 0; } +/** + * @brief Creates an area on the center of the main panel, with a QRCode, + * a possible text in black (bold) under it, and a possible text in black under it + * + * @param layout the current layout + * @param info structure giving the description of buttons (texts, icons, layout) + * @return >= 0 if OK + */ +int nbgl_layoutAddQRCode(nbgl_layout_t *layout, const nbgl_layoutQRCode_t *info) +{ + return nbgl_layoutAddQRCodeIcon(layout, info, NULL); +} #endif // NBGL_QRCODE #ifdef HAVE_SE_TOUCH From 54de60d368c50d8f3ac2a2fac6aec3201a495e87 Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 13:32:27 +0100 Subject: [PATCH 3/6] Add nbgl_pageDrawInfoIcon --- lib_nbgl/include/nbgl_page.h | 4 ++++ lib_nbgl/src/nbgl_page.c | 26 ++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib_nbgl/include/nbgl_page.h b/lib_nbgl/include/nbgl_page.h index 9915f7a0a..93299c79c 100644 --- a/lib_nbgl/include/nbgl_page.h +++ b/lib_nbgl/include/nbgl_page.h @@ -203,6 +203,10 @@ nbgl_page_t *nbgl_pageDrawSpinner(nbgl_layoutTouchCallback_t onActionCallback, c nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_screenTickerConfiguration_t *ticker, const nbgl_pageInfoDescription_t *info); +nbgl_page_t *nbgl_pageDrawInfoIcon(nbgl_layoutTouchCallback_t onActionCallback, + const nbgl_screenTickerConfiguration_t *ticker, + const nbgl_pageInfoDescription_t *info, + const nbgl_icon_details_t *topIcon); nbgl_page_t *nbgl_pageDrawConfirmation(nbgl_layoutTouchCallback_t onActionCallback, const nbgl_pageConfirmationDescription_t *info); nbgl_page_t *nbgl_pageDrawGenericContentExt(nbgl_layoutTouchCallback_t onActionCallback, diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index 501819343..c1372c96d 100644 --- a/lib_nbgl/src/nbgl_page.c +++ b/lib_nbgl/src/nbgl_page.c @@ -262,11 +262,13 @@ nbgl_page_t *nbgl_pageDrawSpinner(nbgl_layoutTouchCallback_t onActionCallback, c * @param onActionCallback common callback for all actions on this page * @param ticker ticker configuration, set to NULL to disable it * @param info structure describing the centered info and other controls of this page + * @param topIcon buffer containing the 1BPP icon for top button * @return the page context (or NULL if error) */ -nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, - const nbgl_screenTickerConfiguration_t *ticker, - const nbgl_pageInfoDescription_t *info) +nbgl_page_t *nbgl_pageDrawInfoIcon(nbgl_layoutTouchCallback_t onActionCallback, + const nbgl_screenTickerConfiguration_t *ticker, + const nbgl_pageInfoDescription_t *info, + const nbgl_icon_details_t *topIcon) { nbgl_layoutDescription_t layoutDescription; nbgl_layout_t *layout; @@ -330,7 +332,7 @@ nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionC .token = info->bottomButtonsToken, .style = BOTH_ROUNDED_STYLE, .tuneId = info->tuneId}; - nbgl_layoutAddChoiceButtons(layout, &buttonsInfo); + nbgl_layoutAddChoiceButtonsIcon(layout, &buttonsInfo, topIcon); } else { nbgl_layoutButton_t buttonInfo = {.fittingContent = false, @@ -365,6 +367,22 @@ nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionC return (nbgl_page_t *) layout; } +/** + * @brief draw a page with a centered info (icon and/or texts) with a touchable footer, + * in a potential "tapable" area, with an optional top-right button, with an optional bottom button + * + * @param onActionCallback common callback for all actions on this page + * @param ticker ticker configuration, set to NULL to disable it + * @param info structure describing the centered info and other controls of this page + * @return the page context (or NULL if error) + */ +nbgl_page_t *nbgl_pageDrawInfo(nbgl_layoutTouchCallback_t onActionCallback, + const nbgl_screenTickerConfiguration_t *ticker, + const nbgl_pageInfoDescription_t *info) +{ + return (nbgl_page_t *) nbgl_pageDrawInfoIcon(onActionCallback, ticker, info, NULL); +} + /** * @brief draw a confirmation page, with a centered info (icon and/or text), a button to confirm and * a footer to cancel From 3f3aae16950424b9a0dc56d3bb34b6985fbc8dcf Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 13:35:00 +0100 Subject: [PATCH 4/6] Add nbgl_useCaseHomeExtIcon --- lib_nbgl/include/nbgl_use_case.h | 9 +++++ lib_nbgl/src/nbgl_use_case.c | 58 +++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/lib_nbgl/include/nbgl_use_case.h b/lib_nbgl/include/nbgl_use_case.h index e22d1c03e..d5a0a2296 100644 --- a/lib_nbgl/include/nbgl_use_case.h +++ b/lib_nbgl/include/nbgl_use_case.h @@ -142,6 +142,15 @@ void nbgl_useCaseHomeExt(const char *appName, nbgl_callback_t actionCallback, nbgl_callback_t topRightCallback, nbgl_callback_t quitCallback); +void nbgl_useCaseHomeExtIcon(const char *appName, + const nbgl_icon_details_t *appIcon, + const char *tagline, + bool withSettings, + const char *actionButtonText, + nbgl_callback_t actionCallback, + nbgl_callback_t topRightCallback, + nbgl_callback_t quitCallback, + const nbgl_icon_details_t *icon); void nbgl_useCasePlugInHome(const char *plugInName, const char *appName, const nbgl_icon_details_t *appIcon, diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c index 419a571b1..8b9e10902 100644 --- a/lib_nbgl/src/nbgl_use_case.c +++ b/lib_nbgl/src/nbgl_use_case.c @@ -940,15 +940,17 @@ void nbgl_useCaseHome(const char *appName, * NULL) * @param topRightCallback callback called when top-right button is touched * @param quitCallback callback called when quit button is touched + * @param icon buffer containing the 1BPP icon for action button */ -void nbgl_useCaseHomeExt(const char *appName, - const nbgl_icon_details_t *appIcon, - const char *tagline, - bool withSettings, - const char *actionButtonText, - nbgl_callback_t actionCallback, - nbgl_callback_t topRightCallback, - nbgl_callback_t quitCallback) +void nbgl_useCaseHomeExtIcon(const char *appName, + const nbgl_icon_details_t *appIcon, + const char *tagline, + bool withSettings, + const char *actionButtonText, + nbgl_callback_t actionCallback, + nbgl_callback_t topRightCallback, + nbgl_callback_t quitCallback, + const nbgl_icon_details_t *icon) { reset_callbacks(); @@ -1011,10 +1013,48 @@ void nbgl_useCaseHomeExt(const char *appName, if (actionButtonText != NULL) { info.centeredInfo.offsetY -= 40; } - pageContext = nbgl_pageDrawInfo(&pageCallback, NULL, &info); + pageContext = nbgl_pageDrawInfoIcon(&pageCallback, NULL, &info, icon); nbgl_refreshSpecial(FULL_COLOR_CLEAN_REFRESH); } +/** + * @brief draws the extended version of home page of an app (page on which we land when launching it + * from dashboard) + * @note it enables to use an action button (black) + * + * @param appName app name + * @param appIcon app icon + * @param tagline text under app name (if NULL, it will be "This app enables signing transactions on + * the network.") + * @param withSettings if true, use a "settings" (wheel) icon in bottom button, otherwise a "info" + * (i) + * @param actionButtonText if not NULL, text used for an action button (in black, on top of "Quit + * App" button) + * @param actionCallback callback called when action button is touched (if actionButtonText is not + * NULL) + * @param topRightCallback callback called when top-right button is touched + * @param quitCallback callback called when quit button is touched + */ +void nbgl_useCaseHomeExt(const char *appName, + const nbgl_icon_details_t *appIcon, + const char *tagline, + bool withSettings, + const char *actionButtonText, + nbgl_callback_t actionCallback, + nbgl_callback_t topRightCallback, + nbgl_callback_t quitCallback) +{ + nbgl_useCaseHomeExtIcon(appName, + appIcon, + tagline, + withSettings, + actionButtonText, + actionCallback, + topRightCallback, + quitCallback, + NULL); +} + /** * @brief draws the home page of a plug-in app (page on which we land when launching it from * dashboard) From 55680e3bd68d7455746ebf142a2f8e91a9615040 Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 13:37:19 +0100 Subject: [PATCH 5/6] Define new content type BARS_LIST_ICONS --- lib_nbgl/include/nbgl_content.h | 20 +++++++++++++++++++- lib_nbgl/include/nbgl_page.h | 4 ++++ lib_nbgl/src/nbgl_page.c | 16 ++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib_nbgl/include/nbgl_content.h b/lib_nbgl/include/nbgl_content.h index 60929909f..c7b5a1c36 100644 --- a/lib_nbgl/include/nbgl_content.h +++ b/lib_nbgl/include/nbgl_content.h @@ -241,6 +241,19 @@ typedef struct { #endif // HAVE_PIEZO_SOUND } nbgl_contentBarsList_t; +/** + * @brief This structure contains data to build a @ref BARS_LIST_ICONS content + */ +typedef struct nbgl_contentBarsListIcons_s { + const char *const *barTexts; ///< array of texts for each bar (nbBars items, in black/bold) + const nbgl_icon_details_t *const *barIcons; ///< a buffer containing the 1BPP icons + const uint8_t *tokens; ///< array of tokens, one for each bar (nbBars items) + uint8_t nbBars; ///< number of elements in barTexts and tokens array +#ifdef HAVE_PIEZO_SOUND + tune_index_e tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played when a bar is touched +#endif // HAVE_PIEZO_SOUND +} nbgl_contentBarsListIcons_t; + /** * @brief The different types of predefined contents * @@ -255,11 +268,15 @@ typedef enum { SWITCHES_LIST, ///< list of switches with descriptions INFOS_LIST, ///< list of infos with titles CHOICES_LIST, ///< list of choices through radio buttons - BARS_LIST ///< list of touchable bars (with > on the right to go to sub-pages) + BARS_LIST, ///< list of touchable bars (with > on the right to go to sub-pages) + BARS_LIST_ICONS ///< list of touchable bars (with > on the right and icon on the left) } nbgl_contentType_t; /** * @brief Union of the different type of contents + * + * @note This union is duplicated in nbgl_page.h: @ref nbgl_pageContent_t + * */ typedef union { nbgl_contentCenteredInfo_t centeredInfo; ///< @ref CENTERED_INFO type @@ -272,6 +289,7 @@ typedef union { nbgl_contentInfoList_t infosList; ///< @ref INFOS_LIST type nbgl_contentRadioChoice_t choicesList; ///< @ref CHOICES_LIST type nbgl_contentBarsList_t barsList; ///< @ref BARS_LIST type + nbgl_contentBarsListIcons_t barsListIcons; ///< @ref BARS_LIST_ICONS type } nbgl_content_u; /** diff --git a/lib_nbgl/include/nbgl_page.h b/lib_nbgl/include/nbgl_page.h index 93299c79c..cb63d9310 100644 --- a/lib_nbgl/include/nbgl_page.h +++ b/lib_nbgl/include/nbgl_page.h @@ -48,6 +48,9 @@ typedef nbgl_contentInfoLongPress_t nbgl_pageInfoLongPress_t; /** * @brief This structure contains data to build a page in multi-pages mode (@ref * nbgl_pageDrawGenericContent) + * + * @note This union is duplicated in nbgl_content.h: @ref nbgl_content_u + * */ typedef struct nbgl_pageContent_s { const char *title; ///< text for the title of the page (if NULL, no title) @@ -67,6 +70,7 @@ typedef struct nbgl_pageContent_s { nbgl_contentInfoList_t infosList; ///< @ref INFOS_LIST type nbgl_contentRadioChoice_t choicesList; ///< @ref CHOICES_LIST type nbgl_contentBarsList_t barsList; ///< @ref BARS_LIST type + nbgl_contentBarsListIcons_t barsListIcons; ///< @ref BARS_LIST_ICONS type }; } nbgl_pageContent_t; diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index c1372c96d..1ced3756e 100644 --- a/lib_nbgl/src/nbgl_page.c +++ b/lib_nbgl/src/nbgl_page.c @@ -176,6 +176,22 @@ static void addContent(nbgl_pageContent_t *content, nbgl_layout_t *layout) } break; } + case BARS_LIST_ICONS: { + uint8_t i; + for (i = 0; i < content->barsListIcons.nbBars; i++) { + nbgl_layoutBar_t bar; + bar.text = content->barsListIcons.barTexts[i]; + bar.subText = NULL; + bar.iconRight = &C_Next32px; + bar.iconLeft = content->barsListIcons.barIcons[i]; + bar.token = content->barsListIcons.tokens[i]; + bar.centered = false; + bar.tuneId = content->barsListIcons.tuneId; + nbgl_layoutAddTouchableBar(layout, &bar); + nbgl_layoutAddSeparationLine(layout); + } + break; + } } } From ac955ad8e0da308b9732b0def0f544dac3e39d0b Mon Sep 17 00:00:00 2001 From: Charles-Edouard de la Vergne Date: Mon, 26 Feb 2024 14:48:25 +0100 Subject: [PATCH 6/6] Update nbgl_layoutAddTouchableBar for subtext rendering --- lib_nbgl/src/nbgl_layout.c | 142 ++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 3b1688d12..ca88b04b2 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -937,9 +937,9 @@ int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *ba nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout; layoutObj_t *obj; nbgl_text_area_t *textArea; - nbgl_image_t *imageLeft = NULL, *imageRight = NULL; nbgl_container_t *container; - color_t color = (barLayout->inactive != true) ? BLACK : LIGHT_GRAY; + color_t color = (barLayout->inactive != true) ? BLACK : LIGHT_GRAY; + int16_t usedHeight = 0; LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddTouchableBar():\n"); if (layout == NULL) { @@ -952,12 +952,16 @@ int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *ba return -1; } - // get container children (up to 4) + // get container children (up to 4: text + left+right icons + sub text) container->children = nbgl_containerPoolGet(4, layoutInt->layer); container->nbChildren = 0; - container->obj.area.width = AVAILABLE_WIDTH; - container->obj.area.height = TOUCHABLE_BAR_HEIGHT; + container->obj.area.width = AVAILABLE_WIDTH; + container->obj.area.height = TOUCHABLE_BAR_HEIGHT; + if ((barLayout->iconLeft != NULL) && (barLayout->subText != NULL)) { + // Only for Stax??? + container->obj.area.height -= 32; + } container->layout = HORIZONTAL; container->obj.alignmentMarginX = BORDER_MARGIN; container->obj.alignment = NO_ALIGNMENT; @@ -971,82 +975,88 @@ int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *ba nbTouchableControls++; } + // allocate main text because always present + textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); + textArea->textColor = color; + textArea->text = (barLayout->text != NULL) ? PIC(barLayout->text) : ""; + textArea->onDrawCallback = NULL; + textArea->fontId = SMALL_BOLD_FONT; + textArea->wrapping = true; + textArea->obj.area.width = container->obj.area.width; + if (barLayout->iconLeft != NULL) { + // reduce text width accordingly + textArea->obj.area.width -= ((nbgl_icon_details_t *) PIC(barLayout->iconLeft))->width + 16; + } + if (barLayout->iconRight != NULL) { + // reduce text width accordingly + textArea->obj.area.width -= ((nbgl_icon_details_t *) PIC(barLayout->iconRight))->width; + } + textArea->obj.area.height = nbgl_getTextHeightInWidth( + textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); + usedHeight = textArea->obj.area.height; + textArea->style = NO_STYLE; + textArea->obj.alignment = MID_LEFT; + textArea->textAlignment = MID_LEFT; + container->children[container->nbChildren] = (nbgl_obj_t *) textArea; + container->nbChildren++; + + // allocate left icon if present if (barLayout->iconLeft != NULL) { - imageLeft = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer); + nbgl_image_t *imageLeft = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer); imageLeft->foregroundColor = color; imageLeft->buffer = PIC(barLayout->iconLeft); - imageLeft->obj.alignment = MID_LEFT; - imageLeft->obj.alignTo = (nbgl_obj_t *) NULL; + // align at the left of text + imageLeft->obj.alignment = MID_LEFT; + imageLeft->obj.alignTo = (nbgl_obj_t *) textArea; + imageLeft->obj.alignmentMarginX = 16; container->children[container->nbChildren] = (nbgl_obj_t *) imageLeft; container->nbChildren++; - } - if (barLayout->text != NULL) { - textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); - textArea->textColor = color; - textArea->text = PIC(barLayout->text); - textArea->onDrawCallback = NULL; - textArea->fontId = SMALL_BOLD_FONT; - textArea->obj.area.width = container->obj.area.width; - if (barLayout->iconLeft != NULL) { - textArea->obj.area.width -= imageLeft->buffer->width + 12; - } - if (barLayout->iconRight != NULL) { - textArea->obj.area.width -= ((nbgl_icon_details_t *) PIC(barLayout->iconRight))->width; - } - textArea->obj.area.height = container->obj.area.height; - textArea->style = NO_STYLE; - if ((barLayout->iconLeft != NULL) && (barLayout->centered != true)) { - textArea->obj.alignmentMarginX = 12; - } - if (barLayout->iconLeft != NULL) { - textArea->obj.alignTo = (nbgl_obj_t *) imageLeft; - textArea->obj.alignment = MID_RIGHT; - } - else { - textArea->obj.alignTo = (nbgl_obj_t *) NULL; - textArea->obj.alignment = NO_ALIGNMENT; - } - if (barLayout->centered != true) { - textArea->textAlignment = MID_LEFT; - } - else { - textArea->textAlignment = CENTER; + + textArea->obj.alignmentMarginX = imageLeft->buffer->width + 16; + + if (imageLeft->buffer->height > usedHeight) { + usedHeight = imageLeft->buffer->height; } - textArea->wrapping = true; - container->children[container->nbChildren] = (nbgl_obj_t *) textArea; - container->nbChildren++; } + // allocate right icon if present if (barLayout->iconRight != NULL) { - imageRight = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer); + nbgl_image_t *imageRight = (nbgl_image_t *) nbgl_objPoolGet(IMAGE, layoutInt->layer); imageRight->foregroundColor = color; imageRight->buffer = PIC(barLayout->iconRight); - imageRight->obj.alignment = MID_RIGHT; - if (barLayout->text == NULL) { - imageRight->obj.alignTo = (nbgl_obj_t *) NULL; - } - else { - imageRight->obj.alignTo = (nbgl_obj_t *) container->children[container->nbChildren - 1]; - } + // align at the right of text + imageRight->obj.alignment = MID_RIGHT; + imageRight->obj.alignTo = (nbgl_obj_t *) textArea; + container->children[container->nbChildren] = (nbgl_obj_t *) imageRight; container->nbChildren++; + + if (imageRight->buffer->height > usedHeight) { + usedHeight = imageRight->buffer->height; + } } if (barLayout->subText != NULL) { - textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); - - textArea->textColor = BLACK; - textArea->text = PIC(barLayout->subText); - textArea->textAlignment = MID_LEFT; - textArea->fontId = SMALL_REGULAR_FONT; - textArea->style = NO_STYLE; - textArea->wrapping = true; - textArea->obj.alignment = BOTTOM_LEFT; - textArea->obj.alignmentMarginY = BORDER_MARGIN; - textArea->obj.area.width = container->obj.area.width; - textArea->obj.area.height = nbgl_getTextHeightInWidth( - textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); - container->children[container->nbChildren] = (nbgl_obj_t *) textArea; + nbgl_text_area_t *subTextArea + = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); + + subTextArea->textColor = color; + subTextArea->text = PIC(barLayout->subText); + subTextArea->textAlignment = MID_LEFT; + subTextArea->fontId = SMALL_REGULAR_FONT; + subTextArea->style = NO_STYLE; + subTextArea->wrapping = true; + subTextArea->obj.alignment = MID_LEFT; + subTextArea->obj.area.width = container->obj.area.width; + subTextArea->obj.area.height = nbgl_getTextHeightInWidth(subTextArea->fontId, + subTextArea->text, + subTextArea->obj.area.width, + subTextArea->wrapping); + container->children[container->nbChildren] = (nbgl_obj_t *) subTextArea; container->nbChildren++; - container->obj.area.height += textArea->obj.area.height + 16; + container->obj.area.height += subTextArea->obj.area.height + 4; + + // modify alignments to have sub-text under (icon left - text - icon right) + textArea->obj.alignmentMarginY = -(subTextArea->obj.area.height + 4) / 2; + subTextArea->obj.alignmentMarginY = (usedHeight + 4) / 2; } // set this new container as child of main container