diff --git a/lib_nbgl/include/nbgl_layout.h b/lib_nbgl/include/nbgl_layout.h index 87ece8178..9ebb6bb9c 100644 --- a/lib_nbgl/include/nbgl_layout.h +++ b/lib_nbgl/include/nbgl_layout.h @@ -542,6 +542,7 @@ int nbgl_layoutAddTopRightButton(nbgl_layout_t *layout, int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *barLayout); int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switchLayout); int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subText); +int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text); 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); diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 5aade0ef8..ef58a05f7 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -1108,6 +1108,47 @@ int nbgl_layoutAddText(nbgl_layout_t *layout, const char *text, const char *subT return container->obj.area.height; } +/** + * @brief Creates an area with given text in small regular font, under the header + * + * @param layout the current layout + * @param text main text in small regular font + * @return height of the control if OK + */ +int nbgl_layoutAddSubHeaderText(nbgl_layout_t *layout, const char *text) +{ + nbgl_layoutInternal_t *layoutInt = (nbgl_layoutInternal_t *) layout; + nbgl_text_area_t *textArea; + + LOG_DEBUG(LAYOUT_LOGGER, "nbgl_layoutAddSubHeaderText():\n"); + if (layout == NULL) { + return -1; + } + textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); + + textArea->textColor = BLACK; + textArea->text = PIC(text); + textArea->textAlignment = MID_LEFT; + textArea->fontId = SMALL_REGULAR_FONT; + textArea->style = NO_STYLE; + textArea->wrapping = true; + textArea->obj.alignment = NO_ALIGNMENT; + textArea->obj.alignmentMarginX = BORDER_MARGIN; + textArea->obj.area.width = AVAILABLE_WIDTH; + textArea->obj.area.height = nbgl_getTextHeightInWidth( + textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); +#ifdef TARGET_STAX + textArea->obj.area.height += 2 * 24; +#else // TARGET_STAX + textArea->obj.area.height += 2 * 28; +#endif // TARGET_STAX + + // set this new obj as child of main container + layoutAddObject(layoutInt, (nbgl_obj_t *) textArea); + + return textArea->obj.area.height; +} + /** * @brief Creates an area with given text in 32px font (in Black) * @@ -1280,11 +1321,8 @@ int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoic container->obj.alignTo = (nbgl_obj_t *) NULL; // init button for this choice - button->activeColor = BLACK; - button->borderColor = LIGHT_GRAY; -#ifdef TARGET_STAX - button->obj.alignmentMarginX = 4; -#endif // TARGET_STAX + button->activeColor = BLACK; + button->borderColor = LIGHT_GRAY; button->obj.alignTo = (nbgl_obj_t *) container; button->obj.alignment = MID_RIGHT; button->state = OFF_STATE; @@ -1300,16 +1338,12 @@ int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoic else { textArea->text = PIC(choices->names[i]); } - textArea->textAlignment = MID_LEFT; -#ifdef TARGET_STAX - textArea->obj.area.width = container->obj.area.width - 40 - 16; -#else // TARGET_STAX - textArea->obj.area.width = container->obj.area.width - 40; -#endif // TARGET_STAX - textArea->style = NO_STYLE; - textArea->obj.alignment = MID_LEFT; - textArea->obj.alignTo = (nbgl_obj_t *) container; - container->children[0] = (nbgl_obj_t *) textArea; + textArea->textAlignment = MID_LEFT; + textArea->obj.area.width = container->obj.area.width - RADIO_WIDTH; + textArea->style = NO_STYLE; + textArea->obj.alignment = MID_LEFT; + textArea->obj.alignTo = (nbgl_obj_t *) container; + container->children[0] = (nbgl_obj_t *) textArea; // whole container should be touchable container->obj.touchMask = (1 << TOUCHED); diff --git a/lib_nbgl/src/nbgl_layout_keyboard.c b/lib_nbgl/src/nbgl_layout_keyboard.c index 26c660254..3c01dacd5 100644 --- a/lib_nbgl/src/nbgl_layout_keyboard.c +++ b/lib_nbgl/src/nbgl_layout_keyboard.c @@ -41,8 +41,29 @@ enum { NB_SUGGESTION_CHILDREN }; +#ifdef TARGET_STAX #define TEXT_ENTRY_NORMAL_HEIGHT 64 +#define TEXT_ENTRY_COMPACT_HEIGHT 64 +#define BOTTOM_NORMAL_MARGIN 24 +#define BOTTOM_COMPACT_MARGIN 24 +#define TOP_NORMAL_MARGIN 20 +#define TOP_COMPACT_MARGIN 20 +#else // TARGET_STAX +#define TEXT_ENTRY_NORMAL_HEIGHT 72 #define TEXT_ENTRY_COMPACT_HEIGHT 56 +#define BOTTOM_NORMAL_MARGIN 24 +#define BOTTOM_COMPACT_MARGIN 12 +#define TOP_NORMAL_MARGIN 20 +#define TOP_COMPACT_MARGIN 12 +#endif // TARGET_STAX + +// a horizontal line, even if displayed on 2 pixels, takes 4 pixels +#define LINE_REAL_HEIGHT 4 + +#define NUMBER_WIDTH 56 + +// space between number and text +#define NUMBER_TEXT_SPACE 8 /********************** * MACROS @@ -219,8 +240,7 @@ static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt, nbgl_container_t *container; nbgl_text_area_t *textArea; layoutObj_t *obj; - uint16_t textEntryHeight - = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT) - 8; + uint16_t textEntryHeight = (compactMode ? TEXT_ENTRY_COMPACT_HEIGHT : TEXT_ENTRY_NORMAL_HEIGHT); // create a container, to store title, entered text and underline container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer); @@ -242,7 +262,7 @@ static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt, textArea->obj.area.height = nbgl_getTextHeightInWidth( textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); container->children[0] = (nbgl_obj_t *) textArea; - container->obj.area.height = textArea->obj.area.height; + container->obj.area.height = textArea->obj.area.height + 4; } if (numbered) { @@ -250,23 +270,20 @@ static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt, textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); textArea->textColor = BLACK; snprintf(numText, sizeof(numText), "%d.", number); - textArea->text = numText; - textArea->textAlignment = CENTER; - textArea->fontId = LARGE_MEDIUM_1BPP_FONT; -#ifdef TARGET_STAX - textArea->obj.area.width = 50; -#else // TARGET_STAX - textArea->obj.area.width = 66; -#endif // TARGET_STAX + textArea->text = numText; + textArea->textAlignment = CENTER; + textArea->fontId = LARGE_MEDIUM_1BPP_FONT; + textArea->obj.area.width = NUMBER_WIDTH; if (title != NULL) { - textArea->obj.alignmentMarginY = 8; + textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT; textArea->obj.alignTo = container->children[0]; textArea->obj.alignment = BOTTOM_LEFT; } else { - textArea->obj.alignment = TOP_LEFT; + textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT; + textArea->obj.alignment = TOP_LEFT; } - textArea->obj.area.height = textEntryHeight; + textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT; // set this text area as child of the container container->children[1] = (nbgl_obj_t *) textArea; } @@ -278,23 +295,20 @@ static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt, textArea->textAlignment = MID_LEFT; textArea->fontId = LARGE_MEDIUM_1BPP_FONT; if (title != NULL) { - textArea->obj.alignmentMarginY = 8; + textArea->obj.alignmentMarginY = 4 + LINE_REAL_HEIGHT; textArea->obj.alignTo = container->children[0]; textArea->obj.alignment = BOTTOM_LEFT; } else { - textArea->obj.alignment = TOP_LEFT; + textArea->obj.alignmentMarginY = LINE_REAL_HEIGHT; + textArea->obj.alignment = TOP_LEFT; } textArea->obj.area.width = AVAILABLE_WIDTH; if (numbered) { -#ifdef TARGET_STAX - textArea->obj.alignmentMarginX = 50; -#else // TARGET_STAX - textArea->obj.alignmentMarginX = 66; -#endif // TARGET_STAX + textArea->obj.alignmentMarginX = NUMBER_WIDTH + NUMBER_TEXT_SPACE; textArea->obj.area.width -= textArea->obj.alignmentMarginX; } - textArea->obj.area.height = textEntryHeight; + textArea->obj.area.height = textEntryHeight - 2 * LINE_REAL_HEIGHT; textArea->autoHideLongLine = true; obj = layoutAddCallbackObj(layoutInt, (nbgl_obj_t *) textArea, textToken, NBGL_NO_TUNE); @@ -304,16 +318,15 @@ static nbgl_container_t *addTextEntry(nbgl_layoutInternal_t *layoutInt, textArea->obj.touchMask = (1 << TOUCHED); textArea->obj.touchId = ENTERED_TEXT_ID; container->children[2] = (nbgl_obj_t *) textArea; - container->obj.area.height - += textArea->obj.area.height + textArea->obj.alignmentMarginY + ((title != NULL) ? 4 : 8); + container->obj.area.height += textEntryHeight; // create gray line nbgl_line_t *line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer); line->lineColor = LIGHT_GRAY; // align on bottom of the container line->obj.alignment = BOTTOM_MIDDLE; - line->obj.area.width = SCREEN_WIDTH - 2 * 32; - line->obj.area.height = 4; + line->obj.area.width = AVAILABLE_WIDTH; + line->obj.area.height = LINE_REAL_HEIGHT; line->direction = HORIZONTAL; line->thickness = 2; line->offset = 2; @@ -349,8 +362,9 @@ static nbgl_container_t *addSuggestionButtons(nbgl_layoutInternal_t *layoutInt, = (nbgl_obj_t **) nbgl_containerPoolGet(NB_SUGGESTION_CHILDREN, layoutInt->layer); // put suggestionsContainer at 24px of the bottom of main container - suggestionsContainer->obj.alignmentMarginY = compactMode ? 12 : 24; - suggestionsContainer->obj.alignment = BOTTOM_MIDDLE; + suggestionsContainer->obj.alignmentMarginY + = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN; + suggestionsContainer->obj.alignment = BOTTOM_MIDDLE; // create all possible suggestion buttons, even if not displayed at first nbgl_objPoolGetArray( @@ -423,8 +437,8 @@ static nbgl_button_t *addConfirmationButton(nbgl_layoutInternal_t *layoutInt, return NULL; } - // put button at 24px of the bottom of main container - button->obj.alignmentMarginY = compactMode ? 12 : 24; + // put button at 24px/12px of the keyboard + button->obj.alignmentMarginY = compactMode ? BOTTOM_COMPACT_MARGIN : BOTTOM_NORMAL_MARGIN; button->obj.alignment = BOTTOM_MIDDLE; button->foregroundColor = WHITE; if (active) { @@ -769,7 +783,7 @@ int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, = (nbgl_button_t *) layoutInt->container->children[enteredTextIndex + 1]; container->obj.alignmentMarginY -= (button->obj.area.height + button->obj.alignmentMarginY - + (compactMode ? 12 : 20)) + + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN)) / 2; } else if (layoutInt->container->children[enteredTextIndex + 1]->type == CONTAINER) { @@ -777,7 +791,7 @@ int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, = (nbgl_container_t *) layoutInt->container->children[enteredTextIndex + 1]; container->obj.alignmentMarginY -= (suggestionContainer->obj.area.height + suggestionContainer->obj.alignmentMarginY - + (compactMode ? 12 : 20)) + + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN)) / 2; } } @@ -884,7 +898,8 @@ int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout, if (layoutInt->container->children[enteredTextIndex] != NULL) { ((nbgl_container_t *) layoutInt->container->children[enteredTextIndex]) ->obj.alignmentMarginY - -= (button->obj.area.height + button->obj.alignmentMarginY + (compactMode ? 12 : 20)) + -= (button->obj.area.height + button->obj.alignmentMarginY + + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN)) / 2; } // return 0 @@ -990,7 +1005,7 @@ int nbgl_layoutAddKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardCont layoutInt->swipeUsage = SWIPE_USAGE_SUGGESTIONS; container->obj.alignmentMarginY -= (suggestionsContainer->obj.area.height + suggestionsContainer->obj.alignmentMarginY - + (compactMode ? 12 : 20)) + + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN)) / 2; } else if (content->type == KEYBOARD_WITH_BUTTON) { @@ -1003,7 +1018,8 @@ int nbgl_layoutAddKeyboardContent(nbgl_layout_t *layout, nbgl_layoutKeyboardCont // set this button as second child of the main layout container layoutInt->container->children[1] = (nbgl_obj_t *) button; container->obj.alignmentMarginY - -= (button->obj.area.height + button->obj.alignmentMarginY + (compactMode ? 12 : 20)) + -= (button->obj.area.height + button->obj.alignmentMarginY + + (compactMode ? TOP_COMPACT_MARGIN : TOP_NORMAL_MARGIN)) / 2; } diff --git a/lib_nbgl/src/nbgl_layout_keypad.c b/lib_nbgl/src/nbgl_layout_keypad.c index b776eb15c..33589682e 100644 --- a/lib_nbgl/src/nbgl_layout_keypad.c +++ b/lib_nbgl/src/nbgl_layout_keypad.c @@ -31,6 +31,13 @@ #define DIGIT_ICON C_pin_24 #endif // TARGET_STAX +enum { + TITLE_INDEX = 0, + INPUT_INDEX, + LINE_INDEX, + NB_CHILDREN +}; + /********************** * MACROS **********************/ @@ -342,14 +349,12 @@ int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, return -1; } // create a container, to store both title and "digits" (and line on Stax) - container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer); - container->nbChildren = 2; -#ifdef TARGET_STAX - container->nbChildren++; // +1 for the line -#endif // TARGET_STAX + container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layoutInt->layer); + container->nbChildren = NB_CHILDREN; container->children = nbgl_containerPoolGet(container->nbChildren, layoutInt->layer); container->obj.area.width = AVAILABLE_WIDTH; - container->obj.alignment = CENTER; + container->obj.alignment = TOP_MIDDLE; + container->obj.alignmentMarginY = 8; // create text area for title textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); @@ -362,7 +367,7 @@ int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, textArea->obj.area.width = AVAILABLE_WIDTH; textArea->obj.area.height = nbgl_getTextHeightInWidth( textArea->fontId, textArea->text, textArea->obj.area.width, textArea->wrapping); - container->children[0] = (nbgl_obj_t *) textArea; + container->children[TITLE_INDEX] = (nbgl_obj_t *) textArea; container->obj.area.height += textArea->obj.area.height; if (hidden) { @@ -391,12 +396,19 @@ int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, = nbgl_containerPoolGet(digitsContainer->nbChildren, layoutInt->layer); // pixels between each icon (knowing that the effective round are 18px large and the // icon 24px) - digitsContainer->obj.area.width = nbDigits * DIGIT_ICON.width + (nbDigits - 1) * space; + digitsContainer->obj.area.width = nbDigits * DIGIT_ICON.width + (nbDigits - 1) * space; +#ifdef TARGET_STAX + digitsContainer->obj.area.height = 44; +#else // TARGET_STAX digitsContainer->obj.area.height = 64; +#endif // TARGET_STAX // align at the bottom of title digitsContainer->obj.alignTo = container->children[0]; digitsContainer->obj.alignment = BOTTOM_MIDDLE; - container->children[1] = (nbgl_obj_t *) digitsContainer; +#ifdef TARGET_STAX + digitsContainer->obj.alignmentMarginY = 28; +#endif // TARGET_STAX + container->children[INPUT_INDEX] = (nbgl_obj_t *) digitsContainer; container->obj.area.height += digitsContainer->obj.area.height; // create children of the container, as images (empty circles) @@ -427,9 +439,12 @@ int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, textArea->obj.area.height = nbgl_getFontLineHeight(textArea->fontId); textArea->autoHideLongLine = true; // align at the bottom of title - textArea->obj.alignTo = container->children[0]; + textArea->obj.alignTo = container->children[TITLE_INDEX]; textArea->obj.alignment = BOTTOM_MIDDLE; - container->children[1] = (nbgl_obj_t *) textArea; +#ifdef TARGET_STAX + textArea->obj.alignmentMarginY = 24; +#endif // TARGET_STAX + container->children[INPUT_INDEX] = (nbgl_obj_t *) textArea; container->obj.area.height += textArea->obj.area.height; } @@ -438,17 +453,16 @@ int nbgl_layoutAddKeypadContent(nbgl_layout_t *layout, #ifdef TARGET_STAX nbgl_line_t *line; // create gray line - line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer); - line->lineColor = LIGHT_GRAY; - line->obj.alignmentMarginY = 0; - line->obj.alignTo = container->children[1]; - line->obj.alignment = BOTTOM_MIDDLE; - line->obj.area.width = 288; - line->obj.area.height = 4; - line->direction = HORIZONTAL; - line->thickness = 2; - line->offset = 2; - container->children[2] = (nbgl_obj_t *) line; + line = (nbgl_line_t *) nbgl_objPoolGet(LINE, layoutInt->layer); + line->lineColor = LIGHT_GRAY; + line->obj.alignTo = container->children[INPUT_INDEX]; + line->obj.alignment = BOTTOM_MIDDLE; + line->obj.area.width = 288; + line->obj.area.height = 4; + line->direction = HORIZONTAL; + line->thickness = 2; + line->offset = 2; + container->children[LINE_INDEX] = (nbgl_obj_t *) line; #endif // TARGET_STAX // return height of the area diff --git a/lib_nbgl/src/nbgl_layout_navigation.c b/lib_nbgl/src/nbgl_layout_navigation.c index 05dfb7fad..c11836e46 100644 --- a/lib_nbgl/src/nbgl_layout_navigation.c +++ b/lib_nbgl/src/nbgl_layout_navigation.c @@ -148,14 +148,16 @@ void layoutNavigationPopulate(nbgl_container_t *navContainer, nbgl_button_t *button; if (navConfig->withExitKey) { - button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layer); - button->innerColor = WHITE; - button->borderColor = BORDER_COLOR; - button->obj.area.width = BUTTON_DIAMETER; - button->obj.area.height = BUTTON_DIAMETER; - button->radius = BUTTON_RADIUS; - button->icon = &CLOSE_ICON; + button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layer); + button->innerColor = WHITE; + button->borderColor = BORDER_COLOR; + button->obj.area.width = BUTTON_DIAMETER; + button->obj.area.height = BUTTON_DIAMETER; + button->radius = BUTTON_RADIUS; + button->icon = &CLOSE_ICON; +#ifdef TARGET_FLEX button->obj.alignmentMarginX = (navConfig->nbPages > 1) ? 8 : 0; +#endif // TARGET_FLEX button->obj.alignment = (navConfig->nbPages > 1) ? MID_LEFT : CENTER; button->obj.touchMask = (1 << TOUCHED); diff --git a/lib_nbgl/src/nbgl_page.c b/lib_nbgl/src/nbgl_page.c index cecf32500..5229a08f7 100644 --- a/lib_nbgl/src/nbgl_page.c +++ b/lib_nbgl/src/nbgl_page.c @@ -47,6 +47,7 @@ static void addContent(nbgl_pageContent_t *content, .backAndText.tuneId = content->tuneId, .backAndText.text = content->title}; nbgl_layoutAddHeader(layout, &headerDesc); + headerAdded = true; } if (content->topRightIcon != NULL) { nbgl_layoutAddTopRightButton( diff --git a/lib_nbgl/src/nbgl_use_case.c b/lib_nbgl/src/nbgl_use_case.c index 64d28369d..44c447964 100644 --- a/lib_nbgl/src/nbgl_use_case.c +++ b/lib_nbgl/src/nbgl_use_case.c @@ -808,8 +808,6 @@ static bool genericContextPreparePageContent(const nbgl_content_t *p_content, pageContent->type = CENTERED_INFO; prepareReviewFirstPage( &pageContent->centeredInfo, pair->valueIcon, pair->item, pair->value); - // use "Swipe to continue" instead of "Swipe to review" for intermediate pages - pageContent->centeredInfo.text3 = "Swipe to continue"; // Skip population of nbgl_contentTagValueList_t structure p_tagValueList = NULL; @@ -2924,9 +2922,10 @@ void nbgl_useCaseAddressReview(const char *address, memset(&addressConfirmationContext, 0, sizeof(addressConfirmationContext)); // save context - onChoice = choiceCallback; - navType = GENERIC_NAV; - pageTitle = NULL; + onChoice = choiceCallback; + navType = GENERIC_NAV; + pageTitle = NULL; + bundleNavContext.review.operationType = TYPE_OPERATION; genericContext.genericContents.contentsList = localContentsList; genericContext.genericContents.nbContents = (additionalTagValueList == NULL) ? 2 : 3; @@ -2936,6 +2935,7 @@ void nbgl_useCaseAddressReview(const char *address, STARTING_CONTENT.type = CENTERED_INFO; prepareReviewFirstPage( &STARTING_CONTENT.content.centeredInfo, icon, reviewTitle, reviewSubTitle); + STARTING_CONTENT.content.centeredInfo.text3 = "Swipe to continue"; // Then the address confirmation pages prepareAddressConfirmationPages(