diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h index 29020d148..b985c7659 100644 --- a/lib_nbgl/include/nbgl_layout.h +++ b/lib_nbgl/include/nbgl_layout.h @@ -407,6 +407,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 *icon); 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/include/nbgl_page.h b/lib_nbgl/include/nbgl_page.h index b14a8bbe8..829afd771 100644 --- a/lib_nbgl/include/nbgl_page.h +++ b/lib_nbgl/include/nbgl_page.h @@ -53,7 +53,9 @@ 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 to go to sub-pages and icons + ///< on the left) } nbgl_pageContentType_t; /** @@ -143,6 +145,17 @@ typedef struct nbgl_pageBarsList_s { tune_index_e tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played when a bar is touched } nbgl_pageBarsList_t; +/** + * @brief This structure contains data to build a @ref BARS_LIST page content + */ +typedef struct nbgl_pageBarsListIcons_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 + tune_index_e tuneId; ///< if not @ref NBGL_NO_TUNE, a tune will be played when a bar is touched +} nbgl_pageBarsListIcons_t; + /** * @brief This structure contains data to build a page in multi-pages mode (@ref * nbgl_pageDrawGenericContent) @@ -165,6 +178,7 @@ typedef struct nbgl_pageContent_s { nbgl_pageInfoList_t infosList; ///< @ref INFOS_LIST type nbgl_layoutRadioChoice_t choicesList; ///< @ref CHOICES_LIST type nbgl_pageBarsList_t barsList; ///< @ref BARS_LIST type + nbgl_pageBarsListIcons_t barsListIcons; ///< @ref BARS_LIST type with icons }; } nbgl_pageContent_t; @@ -301,6 +315,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/include/nbgl_use_case.h b/lib_nbgl/include/nbgl_use_case.h index 2b2998f5f..3ff193eaf 100644 --- a/lib_nbgl/include/nbgl_use_case.h +++ b/lib_nbgl/include/nbgl_use_case.h @@ -141,6 +141,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_layout.c b/lib_nbgl/src/nbgl_layout.c index 60b8d4576..068114d10 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 icon a 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 *icon) { 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 = icon; 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 * diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index 501819343..3f758acd6 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; + } } } @@ -262,11 +278,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 a 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 +348,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 +383,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 diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c index 419a571b1..c4bd65eb7 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 a buffer containing the 1BPP icon for top 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)