diff --git a/lib_nbgl/include/nbgl_obj.h b/lib_nbgl/include/nbgl_obj.h index 150206204..b9a1a4e26 100644 --- a/lib_nbgl/include/nbgl_obj.h +++ b/lib_nbgl/include/nbgl_obj.h @@ -192,7 +192,6 @@ typedef void (*nbgl_touchCallback_t)(void *obj, nbgl_touchType_t eventType); typedef struct PACKED__ nbgl_obj_s { nbgl_area_t area; ///< absolute position, backGround color and size of the object. DO NOT MOVE ///< THIS FIELD - nbgl_obj_type_t type; ///< type of the graphical object, must be explicitly set int16_t rel_x0; ///< horizontal position of top-left corner relative to parent's top-left corner int16_t rel_y0; ///< vertical position of top-left corner relative to parent's top-left corner, @@ -202,7 +201,10 @@ typedef struct PACKED__ nbgl_obj_s { nbgl_aligment_t alignment; ///< type of alignment int16_t alignmentMarginX; ///< horizontal margin when aligning int16_t alignmentMarginY; ///< vertical margin when aligning + nbgl_obj_type_t type; ///< type of the graphical object, must be explicitly set uint8_t touchMask; ///< bit mask to tell engine which touch events are handled by this object + uint8_t touchId; ///< a unique identifier (by screen) to be used by external test environment + ///< (TTYT or Screenshots) } nbgl_obj_t; /** @@ -457,6 +459,27 @@ typedef struct PACKED__ nbgl_keypad_s { keyboardCallback_t callback; ///< function called when an active key is pressed } nbgl_keypad_t; +/** + * @brief ids of touchable objects, for external stimulus (by Testing environment) + * + */ +enum { + BOTTOM_BUTTON_ID = 1, + LEFT_BUTTON_ID, + RIGHT_BUTTON_ID, + WHOLE_SCREEN_ID, + TOP_RIGHT_BUTTON_ID, + BACK_BUTTON_ID, + SINGLE_BUTTON_ID, + CHOICE_1_ID, + CHOICE_2_ID, + KEYPAD_ID, + KEYBOARD_ID, + ENTERED_TEXT_ID, + CONTROLS_ID, // when multiple controls in the same pages (buttons, switches, radios) + NB_CONTROL_IDS +}; + /********************** * GLOBAL PROTOTYPES **********************/ @@ -491,9 +514,6 @@ bool nbgl_navigationCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType, uint8_t nbPages, uint8_t *activePage); -nbgl_container_t *nbgl_bottomButtonPopulate(const nbgl_icon_details_t *icon, - bool separationLine, - uint8_t layer); // for internal use void nbgl_objDrawKeyboard(nbgl_keyboard_t *kbd); @@ -501,6 +521,9 @@ void nbgl_objDrawKeypad(nbgl_keypad_t *kbd); void nbgl_keyboardTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType); void nbgl_keypadTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType); +bool nbgl_keyboardGetPosition(nbgl_keyboard_t *kbd, char index, uint16_t *x, uint16_t *y); +bool nbgl_keypadGetPosition(nbgl_keypad_t *kbd, char index, uint16_t *x, uint16_t *y); + /********************** * MACROS **********************/ diff --git a/lib_nbgl/include/nbgl_touch.h b/lib_nbgl/include/nbgl_touch.h index 32c37fc5d..03e95df84 100644 --- a/lib_nbgl/include/nbgl_touch.h +++ b/lib_nbgl/include/nbgl_touch.h @@ -31,11 +31,12 @@ extern "C" { /********************** * GLOBAL PROTOTYPES **********************/ -void nbgl_touchHandler(nbgl_touchStatePosition_t *touchEvent, uint32_t currentTimeMs); -bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, - nbgl_touchStatePosition_t **firstPos, - nbgl_touchStatePosition_t **lastPos); -uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj); +void nbgl_touchHandler(nbgl_touchStatePosition_t *touchEvent, uint32_t currentTimeMs); +bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, + nbgl_touchStatePosition_t **firstPos, + nbgl_touchStatePosition_t **lastPos); +uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj); +nbgl_obj_t *nbgl_touchGetObjectFromId(nbgl_obj_t *obj, uint8_t id); /********************** * MACROS diff --git a/lib_nbgl/src/nbgl_bottom_button.c b/lib_nbgl/src/nbgl_bottom_button.c deleted file mode 100644 index e798a592a..000000000 --- a/lib_nbgl/src/nbgl_bottom_button.c +++ /dev/null @@ -1,96 +0,0 @@ - -/** - * @file nbgl_bottom_button.c - * @brief The construction of a bottom area with a centered button - * - */ - -/********************* - * INCLUDES - *********************/ -#include "nbgl_debug.h" -#include "nbgl_draw.h" -#include "nbgl_obj.h" -#include "glyphs.h" - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ -enum { - QUIT_BUTTON_INDEX = 0, - LINE_INDEX, - NB_MAX_CHILDREN -}; - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * VARIABLES - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -/** - * @brief This function creates a bottom area with a centered button and a top line. Returns it as a - * container - * - * @param icon icon to place in centered button - * @param separationLine if set to true, adds a light gray separation line on top of the container - * @param layer screen layer to use - * @return the created container object - */ -nbgl_container_t *nbgl_bottomButtonPopulate(const nbgl_icon_details_t *icon, - bool separationLine, - uint8_t layer) -{ - nbgl_button_t *button; - nbgl_container_t *container; - - container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layer); - container->obj.area.width = SCREEN_WIDTH; - container->obj.area.height = BUTTON_DIAMETER + 2 * BORDER_MARGIN; - container->layout = HORIZONTAL; - container->nbChildren = NB_MAX_CHILDREN; - container->children = (nbgl_obj_t **) nbgl_containerPoolGet(container->nbChildren, layer); - container->obj.alignment = NO_ALIGNMENT; - - button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layer); - button->innerColor = WHITE; - button->borderColor = LIGHT_GRAY; - button->obj.area.width = BUTTON_DIAMETER; - button->obj.area.height = BUTTON_DIAMETER; - button->radius = BUTTON_RADIUS; - button->icon = icon; - button->obj.alignment = CENTER; - button->obj.touchMask = (1 << TOUCHED); - container->children[QUIT_BUTTON_INDEX] = (nbgl_obj_t *) button; - - if (separationLine) { - nbgl_line_t *line; - // create horizontal line - line = (nbgl_line_t *) nbgl_objPoolGet(LINE, 0); - line->lineColor = LIGHT_GRAY; - line->obj.area.width = SCREEN_WIDTH; - line->obj.area.height = 4; - line->direction = HORIZONTAL; - line->thickness = 1; - line->obj.alignmentMarginY = BORDER_MARGIN - 4; - line->obj.alignTo = (nbgl_obj_t *) button; - line->obj.alignment = TOP_MIDDLE; - container->children[LINE_INDEX] = (nbgl_obj_t *) line; - } - - return container; -} diff --git a/lib_nbgl/src/nbgl_layout.c b/lib_nbgl/src/nbgl_layout.c index 0ff49ddc9..dc90ebc44 100644 --- a/lib_nbgl/src/nbgl_layout.c +++ b/lib_nbgl/src/nbgl_layout.c @@ -120,6 +120,9 @@ static nbgl_button_t *choiceButtons[NB_MAX_SUGGESTION_BUTTONS]; static char numText[5]; #endif +// numbers of touchable controls for the whole page +static uint8_t nbTouchableControls = 0; + /********************** * STATIC PROTOTYPES **********************/ @@ -438,6 +441,60 @@ static nbgl_line_t *createLeftVerticalLine(uint8_t layer) return line; } +/** + * @brief This function creates a bottom area with a centered button and a top line. Returns it as a + * container + * + * @param icon icon to place in centered button + * @param separationLine if set to true, adds a light gray separation line on top of the container + * @param layer screen layer to use + * @return the created container object + */ +static nbgl_container_t *createBottomButton(const nbgl_icon_details_t *icon, + bool separationLine, + uint8_t layer) +{ + nbgl_button_t *button; + nbgl_container_t *container; + + container = (nbgl_container_t *) nbgl_objPoolGet(CONTAINER, layer); + container->obj.area.width = SCREEN_WIDTH; + container->obj.area.height = BUTTON_DIAMETER + 2 * BORDER_MARGIN; + container->layout = HORIZONTAL; + container->nbChildren = 2; + container->children = (nbgl_obj_t **) nbgl_containerPoolGet(container->nbChildren, layer); + container->obj.alignment = NO_ALIGNMENT; + + button = (nbgl_button_t *) nbgl_objPoolGet(BUTTON, layer); + button->innerColor = WHITE; + button->borderColor = LIGHT_GRAY; + button->obj.area.width = BUTTON_DIAMETER; + button->obj.area.height = BUTTON_DIAMETER; + button->radius = BUTTON_RADIUS; + button->icon = icon; + button->obj.alignment = CENTER; + button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = BOTTOM_BUTTON_ID; + container->children[0] = (nbgl_obj_t *) button; + + if (separationLine) { + nbgl_line_t *line; + // create horizontal line + line = (nbgl_line_t *) nbgl_objPoolGet(LINE, 0); + line->lineColor = LIGHT_GRAY; + line->obj.area.width = SCREEN_WIDTH; + line->obj.area.height = 4; + line->direction = HORIZONTAL; + line->thickness = 1; + line->obj.alignmentMarginY = BORDER_MARGIN - 4; + line->obj.alignTo = (nbgl_obj_t *) button; + line->obj.alignment = TOP_MIDDLE; + container->children[1] = (nbgl_obj_t *) line; + } + + return container; +} + // function adding a layout object in the callbackObjPool array for the given layout, and // configuring it static layoutObj_t *addCallbackObj(nbgl_layoutInternal_t *layout, @@ -506,6 +563,8 @@ nbgl_layout_t *nbgl_layoutGet(const nbgl_layoutDescription_t *description) // reset globals memset(layout, 0, sizeof(nbgl_layoutInternal_t)); + nbTouchableControls = 0; + layout->callback = (nbgl_layoutTouchCallback_t) PIC(description->onActionCallback); layout->modal = description->modal; layout->withLeftBorder = description->withLeftBorder; @@ -540,6 +599,7 @@ nbgl_layout_t *nbgl_layoutGet(const nbgl_layoutDescription_t *description) obj->token = description->tapActionToken; obj->tuneId = description->tapTuneId; layout->container->obj.touchMask = (1 << TOUCHED); + layout->container->obj.touchId = WHOLE_SCREEN_ID; // create 'tap to continue' text area layout->tapText = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, 0); @@ -595,6 +655,7 @@ int nbgl_layoutAddTopRightButton(nbgl_layout_t *layout, button->innerColor = WHITE; button->borderColor = LIGHT_GRAY; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = TOP_RIGHT_BUTTON_ID; button->icon = PIC(icon); button->obj.alignment = TOP_RIGHT; @@ -674,7 +735,7 @@ int nbgl_layoutAddBottomButton(nbgl_layout_t *layout, return -1; } - layoutInt->bottomContainer = nbgl_bottomButtonPopulate(icon, separationLine, layoutInt->layer); + layoutInt->bottomContainer = createBottomButton(icon, separationLine, layoutInt->layer); obj = addCallbackObj(layoutInt, (nbgl_obj_t *) layoutInt->bottomContainer, token, tuneId); if (obj == NULL) { return -1; @@ -731,6 +792,8 @@ int nbgl_layoutAddTouchableBar(nbgl_layout_t *layout, const nbgl_layoutBar_t *ba if ((barLayout->inactive != true) && ((barLayout->iconLeft != NULL) || (barLayout->iconRight != NULL))) { container->obj.touchMask = (1 << TOUCHED); + container->obj.touchId = CONTROLS_ID + nbTouchableControls; + nbTouchableControls++; } if (barLayout->iconLeft != NULL) { @@ -852,6 +915,8 @@ int nbgl_layoutAddSwitch(nbgl_layout_t *layout, const nbgl_layoutSwitch_t *switc container->obj.alignmentMarginX = BORDER_MARGIN; container->obj.alignment = NO_ALIGNMENT; container->obj.touchMask = (1 << TOUCHED); + container->obj.touchId = CONTROLS_ID + nbTouchableControls; + nbTouchableControls++; textArea = (nbgl_text_area_t *) nbgl_objPoolGet(TEXT_AREA, layoutInt->layer); textArea->textColor = BLACK; @@ -1096,6 +1161,8 @@ int nbgl_layoutAddRadioChoice(nbgl_layout_t *layout, const nbgl_layoutRadioChoic container->obj.alignTo = (nbgl_obj_t *) NULL; // whole container should be touchable container->obj.touchMask = (1 << TOUCHED); + container->obj.touchId = CONTROLS_ID + nbTouchableControls; + nbTouchableControls++; // highlight init choice if (i == choices->initChoice) { @@ -1473,6 +1540,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu bottomButton->text = PIC(info->bottomText); bottomButton->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; bottomButton->obj.touchMask = (1 << TOUCHED); + bottomButton->obj.touchId = CHOICE_2_ID; // set this new button as child of the container addObjectToLayout(layoutInt, (nbgl_obj_t *) bottomButton); @@ -1501,6 +1569,7 @@ int nbgl_layoutAddChoiceButtons(nbgl_layout_t *layout, const nbgl_layoutChoiceBu topButton->text = PIC(info->topText); topButton->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; topButton->obj.touchMask = (1 << TOUCHED); + topButton->obj.touchId = CHOICE_1_ID; // set this new button as child of the container addObjectToLayout(layoutInt, (nbgl_obj_t *) topButton); @@ -1798,6 +1867,7 @@ int nbgl_layoutAddButton(nbgl_layout_t *layout, const nbgl_layoutButton_t *butto } button->obj.alignTo = NULL; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = SINGLE_BUTTON_ID; // set this new button as child of the container addObjectToLayout(layoutInt, (nbgl_obj_t *) button); @@ -1932,6 +2002,7 @@ int nbgl_layoutAddFooter(nbgl_layout_t *layout, textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; textArea->textAlignment = CENTER; textArea->obj.touchMask = (1 << TOUCHED); + textArea->obj.touchId = BOTTOM_BUTTON_ID; layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) textArea; layoutInt->nbChildren++; @@ -1990,6 +2061,7 @@ int nbgl_layoutAddSplitFooter(nbgl_layout_t *layout, textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; textArea->textAlignment = CENTER; textArea->obj.touchMask = (1 << TOUCHED); + textArea->obj.touchId = BOTTOM_BUTTON_ID; layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) textArea; layoutInt->nbChildren++; @@ -2008,6 +2080,7 @@ int nbgl_layoutAddSplitFooter(nbgl_layout_t *layout, textArea->fontId = BAGL_FONT_INTER_SEMIBOLD_24px; textArea->textAlignment = CENTER; textArea->obj.touchMask = (1 << TOUCHED); + textArea->obj.touchId = RIGHT_BUTTON_ID; layoutInt->children[layoutInt->nbChildren] = (nbgl_obj_t *) textArea; layoutInt->nbChildren++; @@ -2101,6 +2174,7 @@ int nbgl_layoutAddProgressIndicator(nbgl_layout_t *layout, button->text = NULL; button->icon = PIC(&C_leftArrow32px); button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = BACK_BUTTON_ID; container->children[1] = (nbgl_obj_t *) button; } @@ -2341,6 +2415,7 @@ int nbgl_layoutAddSuggestionButtons(nbgl_layout_t *layout, } choiceButtons[i]->text = buttonTexts[i]; choiceButtons[i]->obj.touchMask = (1 << TOUCHED); + choiceButtons[i]->obj.touchId = CONTROLS_ID + i; // some buttons may not be visible if (i < nbUsedButtons) { container->children[i] = (nbgl_obj_t *) choiceButtons[i]; @@ -2491,6 +2566,7 @@ int nbgl_layoutAddEnteredText(nbgl_layout_t *layout, } textArea->token = token; textArea->obj.touchMask = (1 << TOUCHED); + textArea->obj.touchId = ENTERED_TEXT_ID; // set this new text area as child of the container addObjectToLayout(layoutInt, (nbgl_obj_t *) textArea); @@ -2589,6 +2665,7 @@ int nbgl_layoutAddConfirmationButton(nbgl_layout_t *layout, button->innerColor = BLACK; button->borderColor = BLACK; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = BOTTOM_BUTTON_ID; } else { button->borderColor = LIGHT_GRAY; @@ -2641,6 +2718,7 @@ int nbgl_layoutUpdateConfirmationButton(nbgl_layout_t *layout, button->innerColor = BLACK; button->borderColor = BLACK; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = BOTTOM_BUTTON_ID; } else { button->borderColor = LIGHT_GRAY; diff --git a/lib_nbgl/src/nbgl_navigation.c b/lib_nbgl/src/nbgl_navigation.c index 32887760d..a21775b81 100644 --- a/lib_nbgl/src/nbgl_navigation.c +++ b/lib_nbgl/src/nbgl_navigation.c @@ -140,6 +140,7 @@ nbgl_container_t *nbgl_navigationPopulate(uint8_t nbPages, button->obj.alignment = (nbPages > 1) ? MID_LEFT : CENTER; button->obj.alignTo = NULL; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = BOTTOM_BUTTON_ID; navContainer->children[EXIT_BUTTON_INDEX] = (nbgl_obj_t *) button; } if (nbPages > 1) { @@ -168,6 +169,7 @@ nbgl_container_t *nbgl_navigationPopulate(uint8_t nbPages, button->obj.alignTo = NULL; } button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = LEFT_BUTTON_ID; navContainer->children[PREVIOUS_PAGE_INDEX] = (nbgl_obj_t *) button; // create next page button @@ -190,6 +192,7 @@ nbgl_container_t *nbgl_navigationPopulate(uint8_t nbPages, button->obj.alignment = MID_RIGHT; button->obj.alignTo = navContainer->children[PREVIOUS_PAGE_INDEX]; button->obj.touchMask = (1 << TOUCHED); + button->obj.touchId = RIGHT_BUTTON_ID; navContainer->children[NEXT_PAGE_INDEX] = (nbgl_obj_t *) button; configButtons(navContainer, nbPages, activePage); diff --git a/lib_nbgl/src/nbgl_obj.c b/lib_nbgl/src/nbgl_obj.c index e4f98371a..9afe3d5e4 100644 --- a/lib_nbgl/src/nbgl_obj.c +++ b/lib_nbgl/src/nbgl_obj.c @@ -6,6 +6,7 @@ /********************* * INCLUDES *********************/ +#include #include "nbgl_obj.h" #include "nbgl_draw.h" #include "nbgl_front.h" @@ -704,7 +705,7 @@ static void draw_pageIndicator(nbgl_page_indicator_t *obj, rectArea.height = obj->obj.area.height; rectArea.backgroundColor = obj->obj.area.backgroundColor; rectArea.bpp = NBGL_BPP_1; - nbgl_drawText(&rectArea, navText, 9, BAGL_FONT_INTER_REGULAR_24px, DARK_GRAY); + nbgl_drawText(&rectArea, navText, strlen(navText), BAGL_FONT_INTER_REGULAR_24px, DARK_GRAY); } } diff --git a/lib_nbgl/src/nbgl_obj_keyboard.c b/lib_nbgl/src/nbgl_obj_keyboard.c index 82afb7660..10b253178 100644 --- a/lib_nbgl/src/nbgl_obj_keyboard.c +++ b/lib_nbgl/src/nbgl_obj_keyboard.c @@ -637,6 +637,59 @@ void nbgl_keyboardTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType) } } +/** + * @brief This function gets the position (top-left corner) of the key at the + * given index. (to be used for Testing purpose) + * + * @param kbd the object to be drawned + * @param index ascii character (in lower-case) + * @param x [out] the top-left position + * @param y [out] the top-left position + * @return true if found, false otherwise + */ +bool nbgl_keyboardGetPosition(nbgl_keyboard_t *kbd, char index, uint16_t *x, uint16_t *y) +{ + uint8_t charIndex = 0; + + while (charIndex < 26) { + if (index == kbd_chars[charIndex]) { + break; + } + charIndex++; + } + + // if in first line + if (charIndex < FIRST_LINE_CHAR_COUNT) { + *x = kbd->obj.area.x0 + charIndex * NORMAL_KEY_WIDTH; + *y = kbd->obj.area.y0; + } + else if (charIndex < (FIRST_LINE_CHAR_COUNT + SECOND_LINE_CHAR_COUNT)) { + *x = kbd->obj.area.x0 + (charIndex - FIRST_LINE_CHAR_COUNT) * NORMAL_KEY_WIDTH + + SECOND_LINE_OFFSET; + *y = kbd->obj.area.y0 + KEYBOARD_KEY_HEIGHT; + } + else if (charIndex < sizeof(kbd_chars)) { + if (kbd->mode == MODE_LETTERS) { + *x = kbd->obj.area.x0 + + (charIndex - FIRST_LINE_CHAR_COUNT - SECOND_LINE_CHAR_COUNT) * NORMAL_KEY_WIDTH; + // shift does not exist in letters only mode + if (!kbd->lettersOnly) { + *x = *x + SHIFT_KEY_WIDTH; + } + } + else { + *x = kbd->obj.area.x0 + + (charIndex - FIRST_LINE_CHAR_COUNT - SECOND_LINE_CHAR_COUNT) * NORMAL_KEY_WIDTH + + SPECIAL_CHARS_KEY_WIDTH; + } + *y = kbd->obj.area.y0 + 2 * KEYBOARD_KEY_HEIGHT; + } + else { + return false; + } + return true; +} + /** * @brief This function draws a keyboard object * @@ -645,6 +698,7 @@ void nbgl_keyboardTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType) void nbgl_objDrawKeyboard(nbgl_keyboard_t *kbd) { kbd->obj.touchMask = (1 << TOUCHED); + kbd->obj.touchId = KEYBOARD_ID; kbd->needsRefresh = false; keyboardDraw(kbd); diff --git a/lib_nbgl/src/nbgl_obj_keypad.c b/lib_nbgl/src/nbgl_obj_keypad.c index cf37331f8..fd28a7930 100644 --- a/lib_nbgl/src/nbgl_obj_keypad.c +++ b/lib_nbgl/src/nbgl_obj_keypad.c @@ -314,6 +314,49 @@ void nbgl_keypadTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType) } } +/** + * @brief This function gets the position (top-left corner) of the key at the + * given index. (to be used for Testing purpose). Only works without shuffling + * + * @param kpd the object to be drawned + * @param index the char of the key + * @param x [out] the top-left position + * @param y [out] the top-left position + * @return true if found, false otherwise + */ +bool nbgl_keypadGetPosition(nbgl_keypad_t *kpd, char index, uint16_t *x, uint16_t *y) +{ + // if in first line + if ((index >= '1') && (index <= '3')) { + *x = kpd->obj.area.x0 + (index - '1') * KEY_WIDTH; + *y = kpd->obj.area.y0; + } + else if ((index >= '4') && (index <= '6')) { + *x = kpd->obj.area.x0 + (index - '4') * KEY_WIDTH; + *y = kpd->obj.area.y0 + KEYPAD_KEY_HEIGHT; + } + else if ((index >= '7') && (index <= '9')) { + *x = kpd->obj.area.x0 + (index - '7') * KEY_WIDTH; + *y = kpd->obj.area.y0 + (2 * KEYPAD_KEY_HEIGHT); + } + else if (index == BACKSPACE_KEY) { // backspace + *x = kpd->obj.area.x0; + *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT); + } + else if (index == '0') { + *x = kpd->obj.area.x0 + KEY_WIDTH; + *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT); + } + else if (index == VALIDATE_KEY) { // validate + *x = kpd->obj.area.x0 + (2 * KEY_WIDTH); + *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT); + } + else { + return false; + } + return true; +} + /** * @brief This function draws a keypad object * @@ -323,6 +366,7 @@ void nbgl_keypadTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType) void nbgl_objDrawKeypad(nbgl_keypad_t *kpd) { kpd->obj.touchMask = (1 << TOUCHED) | (1 << TOUCH_PRESSED); + kpd->obj.touchId = KEYPAD_ID; // if the object has not been already used, prepare indexes of digits if (kpd->digitIndexes[0] == 0) { diff --git a/lib_nbgl/src/nbgl_touch.c b/lib_nbgl/src/nbgl_touch.c index 471eaa332..766c07c37 100644 --- a/lib_nbgl/src/nbgl_touch.c +++ b/lib_nbgl/src/nbgl_touch.c @@ -169,6 +169,7 @@ void nbgl_touchHandler(nbgl_touchStatePosition_t *touchStatePosition, uint32_t c applytouchStatePosition(lastPressedObj, OUT_OF_TOUCH); } } + // Released event has been handled, forget lastPressedObj lastPressedObj = NULL; lastState = touchStatePosition->state; return; @@ -241,3 +242,43 @@ uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj) } return 0; } + +/** + * @brief if the given obj contains the coordinates of the given event, parse + * all its children with the same criterion. + * If no children or none concerned, check whether this object can process the event or not + * + * @param obj + * @param event + * @return the concerned object or NULL if not found + */ +nbgl_obj_t *nbgl_touchGetObjectFromId(nbgl_obj_t *obj, uint8_t id) +{ + if (obj == NULL) { + return NULL; + } + if ((obj->type == SCREEN) || (obj->type == CONTAINER)) { + nbgl_container_t *container = (nbgl_container_t *) obj; + // parse the children, if any + if (container->children != NULL) { + uint8_t i; + for (i = 0; i < container->nbChildren; i++) { + nbgl_obj_t *current = container->children[i]; + if (current != NULL) { + current = nbgl_touchGetObjectFromId(current, id); + if (current != NULL) { + return current; + } + } + } + } + } + /* now see if the object is interested by touch events (any of them) */ + if ((obj->touchMask != 0) && (obj->touchId == id)) { + LOG_DEBUG(TOUCH_LOGGER, "found %p: id = %d, type = %d \n", obj, obj->touchId, obj->type); + return obj; + } + else { + return NULL; + } +}