Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
Predefined Application Use-cases API

Introduction

This chapter describes the Application Use-cases API of Advanced BOLOS Graphic Library.

This layer offers a simplified view of some typical use-cases of display in an Application running on Stax. For example, a use-case can be:

  • Reviewing a transaction/message
  • Reviewing details on a given data of a transaction/message
  • Displaying pages of settings

A full description of each predefined use-case can be found in this document

Concepts

This layer uses the high-level API described in Predefined Step API, but offers to developer more than a single step.

The goal is to simplify the usage of NBGL, but also to offer a better homogeneity across applications, by pushing developers to use common API for common use-cases.

So that not only the look of the pages but also their transitions look the same. Which should be a real help for end-users, getting more and more familiar with the user experience of applications.

Example 1: transaction review

In this example, a transaction review consists in 5 successive pages, and can be seen as a use-case

Example 2: Settings pages

In this example, the settings (accessed from Settings in Home, single level) consists in 3 pages, and can be seen as another use-case.

Use Cases

A few APIs are available to draw typical Use-Cases, such as:

Home & Settings screen Use Case

Ledger would like all application to have the same layout for home screen and settings/info, so the nbgl_useCaseHomeAndSettings() function enables to create such a set of page, the configurable parameters being:

  • The application name (appName)
  • The application icon (appIcon)
  • The tagline, a text under app name (if NULL, it will be "<appName> is ready")
  • The callback when touching quit application button
  • The settings pages description
  • The info pages description
extern const nbgl_icon_details_t *app_icon;
enum {
SWITCH1_TOKEN = FIRST_USER_TOKEN,
SWITCH2_TOKEN
};
static const nbgl_layoutSwitch_t switches[] = {
{.initState = false,
.text = "Dummy 1",
.subText = "Allow dummy 1\nin transactions",
.token = SWITCH1_TOKEN},
{.initState = true,
.text = "Dummy 2",
.subText = "Allow dummy 2\nin transactions",
.token = SWITCH2_TOKEN}
};
static const char *infoTypes[] = {"Version", "Developer"};
static const char *infoContents[] = {"1.1.0", "Ledger"};
// function called in case of action on switches
static void controlsCallback(int token, uint8_t index, int page) {
if (token == SWITCH1_TOKEN) {
if (index == 0) {
// deactivate something related with Dummy1
}
else {
// activate something related with Dummy1
}
}
else if (token == SWITCH2_TOKEN) {
if (index == 0) {
// deactivate something related with Dummy2
}
else {
// activate something related with Dummy2
}
}
}
static const nbgl_content_t contentsList = {
.content.switchesList.switches = switches,
.type = SWITCHES_LIST,
.contentActionCallback = controlsCallback
};
static const nbgl_genericContents_t settingContents = {
.contentsList = &contentsList,
.nbContents = 1
};
static const nbgl_contentInfoList_t infosList = {
.nbInfos = 2,
.infoTypes = infoTypes,
.infoContents = infoContents
};
void onQuit(void) {
// exit app here
}
void appMain(void) {
app_icon,
NULL, // use default tag line
INIT_HOME_PAGE, // start at home page
&esettingContents, // description of settings
&infosList, // description of app info
NULL, // no action button on home screen
onQuit); // when quitting
}
@ SWITCHES_LIST
list of switches with descriptions
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
void nbgl_useCaseHomeAndSettings(const char *appName, const nbgl_icon_details_t *appIcon, const char *tagline, const uint8_t initSettingPage, const nbgl_genericContents_t *settingContents, const nbgl_contentInfoList_t *infosList, const nbgl_homeAction_t *action, nbgl_callback_t quitCallback)
#define INIT_HOME_PAGE
Value to pass to nbgl_useCaseHomeAndSettings() initSettingPage parameter to initialize the use case o...
#define FIRST_USER_TOKEN
when using controls in page content (nbgl_pageContent_t), this is the first token value usable for th...
This structure contains data to build a INFOS_LIST content.
uint8_t nbInfos
number of elements in infoTypes and infoContents array
This structure contains info to build a switch (on the right) with a description (on the left),...
nbgl_state_t initState
initial state of the switch
This structure contains data to build a content.
nbgl_content_u content
const nbgl_content_t * contentsList
array of nbgl_content_t (nbContents items).
uint8_t nbSwitches
number of elements in switches and tokens array
nbgl_contentSwitchesList_t switchesList
SWITCHES_LIST type

Home & Settings screen with action button Use Case

For some rare applications, one may need an action button in the Home screen, to perform either:

  • The main action of the Application
  • Or an side-action, as to display an address

The action argument of nbgl_useCaseHomeAndSettings() can be used for that. This structure (nbgl_homeAction_t) enables to specify:

  • A text
  • An optional icon
  • A function to be called when the buttons are pressed

Confirmation Use Case

A confirmation use-case consists in 3 modal pages sequence:

  • 1st page containing a fixed icon, a configurable message
  • 2nd page to confirm (pressing both buttons)
  • 3rd page to reject (pressing both buttons)

The nbgl_useCaseConfirm() function enables to create such a page.

The callback argument is called upon confirmation.

When rejected, this modal screen is simply dismissed, revealing the previous page on background.

Here is the code to display the example picture (and a status page for confirmation)

static void confirmationCallback(void) {
// draw a status screen which continues by returning to appMain
}
void onRejectTransaction(void) {
nbgl_useCaseConfirm("Do you confirm\nThis message?",
"Confirm",
"Cancel",
confirmationCallback);
}
void nbgl_useCaseConfirm(const char *message, const char *subMessage, const char *confirmText, const char *rejectText, nbgl_callback_t callback)

Choice Use Case

A choice use-case consists in a 4-page sequence:

  • 1st page containing a configurable icon and a configurable title
  • 2nd page containing a configurable message (text and subText)
  • 3rd page to confirm, with a configurable message (pressing both buttons)
  • 4th page to reject, with a configurable message (preesing both buttons)

The nbgl_useCaseChoice() function enables to create such a page.

The callback argument is called when a choice is done. Its argument is a boolean which is true upon confirmation, else false.

Here is the code to display the example picture

static void onChoice(bool confirm) {
if (confirm) {
// do something
}
else {
// do something
}
}
void onRejectTransaction(void) {
nbgl_useCaseChoice(&C_icon_warning,
"Dummy 2",
"Are you sure to\nallow dummy 2\nin transactions?",
"I understand, confirm",
"Cancel",
onChoice);
}
void nbgl_useCaseChoice(const nbgl_icon_details_t *icon, const char *message, const char *subMessage, const char *confirmText, const char *rejectString, nbgl_choiceCallback_t callback)

Advanced Choice with Details Use Case

A variant of the Choice Use Case with an optional details modal page, accessible by an extra navigation step. The nbgl_useCaseAdvancedChoiceWithDetails() function enables to create such a sequence.

On Nano, the header_icon and subMessage arguments are ignored (no top-right icon button, and only one text line below the title is displayed). When details is non-NULL, an additional page is inserted in the navigation to display the details content.

The callback argument is called when a choice is done. Its argument is a boolean which is true upon confirmation, else false.

Here is an example of usage:

static void onChoice(bool confirm) {
if (confirm) {
// confirmed
}
else {
// cancelled
}
}
static const char *detailTexts[] = {"Address"};
static const char *detailSubTexts[] = {"0x1234...5678"};
static nbgl_warningDetails_t details = {
.title = "My Ledger Account",
.barList.nbBars = 1,
.barList.texts = detailTexts,
.barList.subTexts = detailSubTexts,
};
void displayAccountConfirm(void) {
NULL,
"Confirm name?",
"My Ledger Account",
NULL,
"Confirm",
"Cancel",
&details,
onChoice);
}
@ BAR_LIST_WARNING
list of touchable bars, to display sub-pages
void nbgl_useCaseAdvancedChoiceWithDetails(const nbgl_icon_details_t *centerIcon, const nbgl_icon_details_t *headerIcon, const char *title, const char *message, const char *subMessage, const char *confirmText, const char *cancelText, nbgl_warningDetails_t *details, nbgl_choiceCallback_t callback)
The necessary parameters to build the page(s) displayed when the top-right button is touched in intro...
const char * title
text of the page (used to go back)

Status Use Case

A status is a transient page, without control, to display during a short time, for example when a transaction is successfully signed. The nbgl_useCaseStatus() function enables to create such a page, with the following arguments:

  • A message string to set in middle of page
  • A boolean to indicate if true (to determine the icon)
  • A quit callback, called when timer times out (or both buttons are pressed)

Pre-defined review status Use Case

Similar as Status Use Case, this is used to display transient page, without control, during a short time, for example when a transaction is successfully signed. The nbgl_useCaseReviewStatus() function enables to create such a page, with the following arguments:

  • A type of status (with predefined message and icon)
  • A quit callback, called when timer times out (or both buttons are pressed)

Review Use Case

In most cases, the developer may know all tag/value pairs of a transaction when it is submitted.

Thus, the number of pages is computed automatically and pages can be navigated forward and backward.

Note
In case of a tag/value pair too long to be fully displayed, the value is automatically split on successive pages, adding an indication (n/m) in the name.

At the end of the review flow, the user has 2 pages to Approve or Reject the transaction. Finally, the given callback is called and it's up to app's developer to call nbgl_useCaseReviewStatus().

The API to initiate the display of the series of pages is nbgl_useCaseReview(), providing:

  • The type of operation to review (transaction, message or generic operation)
  • The title and icon for the presentation page
  • The list of tag/value pairs (or a callback to get them one by one)
  • A callback called when the review is Approved or Rejected. The callback's param is true for approval, false for rejection.

Here is the code to display something similar to example picture:

extern const nbgl_icon_details_t *app_icon;
// pairs of tag/value to display
static nbgl_layoutTagValue_t pairs[2];
static const nbgl_contentTagValueList_t pairList = {
.nbPairs = 2,
.pairs = (nbgl_layoutTagValue_t*)pairs
};
// called when review is approved or rejected
static void review_choice(bool confirm) {
// display a status page and go back to main
if (confirm) {
}
else {
}
}
void startReview(void) {
// Setup data to display
pairs[0].item = "Amount";
pairs[0].value = "NBT 0.99";
pairs[1].item = "Address";
pairs[1].value = "0x1234567890";
// standard review, providing the whole list of pairs
nbgl_useCaseReview(TYPE_TRANSACTION, // type of operation
&pairList, // list of tag/value pairs
app_icon, // icon of the coin
"Review transaction\nto send NBT", // title of the first page
NULL, // sub-title of the first page
NULL, // title of the last page
review_choice); // callback on result of the review
}
void nbgl_useCaseReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStatus(nbgl_reviewStatusType_t reviewStatusType, nbgl_callback_t quitCallback)
@ STATUS_TYPE_TRANSACTION_REJECTED
@ STATUS_TYPE_TRANSACTION_SIGNED
@ TYPE_TRANSACTION
For operations transferring a coin or taken from an account to another.
This structure contains a list of [tag,value] pairs.
This structure contains a [tag,value] pair and possible extensions.
const char * value
string giving the value name
const char * item
string giving the tag name

Here is another version of the example code, using a callback mechanism to get tag/value pairs:

extern const nbgl_icon_details_t *app_icon;
// common tag/value pair to return
static nbgl_layoutTagValue_t* getPair(uint8_t index);
static const nbgl_contentTagValueList_t pairList = {
.nbPairs = 2,
.pairs = NULL, // to indicate that callback should be used
.callback = getPair,
};
// called when review is approved or rejected
static void review_choice(bool confirm) {
// display a status page and go back to main
if (confirm) {
}
else {
}
}
// function called by NBGL to get the pair indexed by "index"
static nbgl_layoutTagValue_t* getPair(uint8_t index) {
switch (index) {
case 0:
pair.item = "Amount";
pair.value = "NBT 0.99";
break;
case 1:
pair.item = "Address";
pair.value = "0x1234567890";
break;
}
return &pair;
}
void startReview(void) {
// standard review, providing the whole list of pairs
nbgl_useCaseReview(TYPE_TRANSACTION, // type of operation
&pairList, // list of tag/value pairs
app_icon, // icon of the coin
"Review transaction\nto send NBT", // title of the first page
NULL, // sub-title of the first page
NULL, // title of the last page
review_choice); // callback on result of the review
}

Light review Use Case

Not really useful on Nano devices, and thus, directly mapped to Review Use Case.

Streaming review Use Case

In some cases, the application cannot know all tag/value pairs of a transaction when the review is started.

In this case, what we call a streaming review can be used. The pages to display for each stream are computed automatically and pages can be navigated forward and backward.

In case of a tag/value pair too long to be fully displayed, the value is automatically split on successive pages, adding an indication (n/m) in the name.

At the end of the review flow, the user has 2 pages to Approve or Reject the transaction. Finally, the given callback is called and it's up to app's developer to call nbgl_useCaseReviewStatus().

The API to initiate the display of the series of pages is nbgl_useCaseReviewStreamingStart(), providing:

  • The type of operation to review (transaction, message or generic operation)
  • The title and icon for the presentation page
  • A callback with one boolean parameter:
    • If this parameter is false, it means that the transaction is rejected.
    • If this parameter is true, it means that NBGL is waiting for new data, sent with nbgl_useCaseReviewStreamingContinue()

As long as there are new tag/value pairs to send, the API to call is nbgl_useCaseReviewStreamingContinue(), providing:

  • The list of tag/value pairs (or a callback to get them one by one)
  • A callback with one boolean parameter:
    • If this parameter is false, it means that the transaction is rejected.
    • If this parameter is true, it means that NBGL is waiting for new data, to be sent with nbgl_useCaseReviewStreamingContinue()
Note
Considering skip is not available on Nano device, nbgl_useCaseReviewStreamingContinueExt() is useless and directly mapped to nbgl_useCaseReviewStreamingContinue()

When there is no more data to send, the API to call is nbgl_useCaseReviewStreamingFinish(), providing:

  • A callback called when the review is Approved or Rejected. The callback's param is true for approval, false for rejection.

Here is the code to display something similar to example picture:

extern const nbgl_icon_details_t *app_icon;
// called when long press button on last page is long-touched or when reject footer is touched
static void onReviewResult(bool confirm) {
// display a status page and go back to main
if (confirm) {
}
else {
}
}
static void onTransactionContinue(bool askMore)
{
if (askMore) {
// try to get more data
if (moreDataToSend(&pairsToSend)) {
nbgl_useCaseReviewStreamingContinue(&pairsToSend, onTransactionContinue);
}
else {
// all data sent, so finish
nbgl_useCaseReviewStreamingFinish("Sign transaction?", // title on last page
onReviewResult); // callback to handle reject/accept
}
}
else {
onReviewResult(false);
}
}
void startReview(void) {
// initiate the streaming review
app_icon, // icon on first page
"Review transaction\nto send NBT", // title of the first page
NULL, // sub-title
onTransactionContinue); // callback to reject or ask more data
}
void nbgl_useCaseReviewStreamingStart(nbgl_operationType_t operationType, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStreamingFinish(const char *finishTitle, nbgl_choiceCallback_t choiceCallback)
void nbgl_useCaseReviewStreamingContinue(const nbgl_contentTagValueList_t *tagValueList, nbgl_choiceCallback_t choiceCallback)

Review with warning Use Case

The review itself behaves like in Review Use Case. The main differences is:

  • The review itself is preceded by a warning page

The API to initiate the display of the series of pages is nbgl_useCaseAdvancedReview(), providing:

  • the type of operation to review (transaction, message or generic operation)
  • the list of tag/value pairs (or a callback to get them one by one)
  • the texts/icon to use in presentation page and in last page
  • the configuration to use for the warning (see nbgl_warning_t structure)
  • a callback called when the long press button on last page or reject confirmation is used. The callback's param is true for confirmation, false for rejection.
Note
the recommended configuration for warning is the predefined one. In this case, one just has to fill the predefinedSet field of nbgl_warning_t with the appropriate warning causes (bitfield) and the reportProvider field with the name of the 3rd party providing the Web3Checks report, if necessary.

Here is a code sample:

// 4 pairs of tag/value to display
static nbgl_layoutTagValue_t pairs[4];
static const nbgl_contentTagValueList_t pairList = {
.nbPairs = 4,
.pairs = (nbgl_layoutTagValue_t*)pairs
};
// warning description (cannot be in call stack)
static nbgl_warning_t warningDesc;
// called when long press button on 3rd page is long-touched or when reject footer is touched
static void onReviewResult(bool confirm) {
// display a status page and go back to main
if (confirm) {
}
else {
}
}
void staticReview(void) {
warningDesc.predefinedSet = 1 << BLIND_SIGNING_WARN;
// static review, providing the whole list of pairs
&pairList, // list of tag/value pairs
coinIcon, // icon of the coin
"Review transaction\nto send coin", // title of the first page
NULL, // sub-title of the first page
"Sign transaction to\nsend coin?", // title of the last page
NULL, // no tip-box in first page of review
&warningDesc, // description of warning causes
onReviewResult); // callback on result of the review
}
@ BLIND_SIGNING_WARN
Blind signing.
void nbgl_useCaseAdvancedReview(nbgl_operationType_t operationType, const nbgl_contentTagValueList_t *tagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, const char *finishTitle, const nbgl_tipBox_t *tipBox, const nbgl_warning_t *warning, nbgl_choiceCallback_t choiceCallback)
uint8_t nbMaxLinesForValue
if > 0, set the max number of lines for value field.
The necessary parameters to build a warning page preceding a review. One can either use predefinedSet...
uint32_t predefinedSet

Address Review Use Case

When an address needs to be confirmed, it can be displayed in a Address Review Use Case.

After a title page, a second page is displayed with the raw address (as text).

Moreover, if extra information need to be displayed, in the form of tags/values, they are show in successive pages.

Note
In case of a tag/value pair too long to be fully displayed, the value is automatically split on successive pages, adding an indication (n/m) in the name.

At the end of the review flow, the user has 2 pages to Approve or Reject the review. Finally, the given callback is called and it's up to app's developer to call nbgl_useCaseReviewStatus().

The nbgl_useCaseAddressReview() function enables to create such a set of pages, with the following parameters:

  • The address to confirm (NULL terminated string)
  • A callback called when the review is Approved or Rejected
  • The optional list of extra tag/value pairs

Here is the code to display something similar to example picture:

// 2 pairs of tag/value to display in second page
static nbgl_layoutTagValue_t pairs[2];
static const nbgl_contentTagValueList_t pairList = {
.nbPairs = 2,
.pairs = (nbgl_layoutTagValue_t*)pairs
};
// called when either confirm button or reject token is called
static void review_choice(bool confirm) {
if (confirm) {
}
else {
}
}
void app_ethereumVerifyAddress(void) {
// Setup data to display
pairs[0].item = "Type address";
pairs[0].value = "dummy type";
pairs[1].item = "Sub address";
pairs[1].value = "dummy sub address";
// Setup list
pairList.nbMaxLinesForValue = 0;
pairList.nbPairs = 2;
pairList.pairs = pairs;
"5A8FgbMkmG2e3J41sBdjvjaBUyz8qHohsQcGtRf63qEUTMBvmA45fpp5pSacMdSg7A3b71RejLzB8EkGbfjp5PELVHCRUaE",
&pairList,
&ICON_APP,
"Verify NBT address",
NULL,
review_choice);
}
@ STATUS_TYPE_ADDRESS_REJECTED
@ STATUS_TYPE_ADDRESS_VERIFIED
void nbgl_useCaseAddressReview(const char *address, const nbgl_contentTagValueList_t *additionalTagValueList, const nbgl_icon_details_t *icon, const char *reviewTitle, const char *reviewSubTitle, nbgl_choiceCallback_t choiceCallback)
const nbgl_contentTagValue_t * pairs
array of [tag,value] pairs (nbPairs items). If NULL, callback is used instead

Spinner Use Case

This Use Case is simply to display a static waiting page

The nbgl_useCaseSpinner() function enables to create such a page, without any parameters.

Keypad Use Case

We have here 2 different variants, allowing to show or hide the entered digits.

When a pincode is requested, a default keypad can be displayed, with hidden digits.

The nbgl_useCaseKeypad() function enables to create such page, with the following parameters:

  • A title
  • The min and max lengths
  • A boolean to request a shuffled keypad
  • A boolean to request hidden digits
  • Callbacks for navigation and pin validation
Note
The backspace and validate buttons will be shown or hidden automatically.
The backspace button is also used as a cancel button, when no digits are selected.
The max nb of supported digits is 12.

Here is the code to display something similar to example picture:

static void validate_pin(const uint8_t *pinentry, uint8_t length) {
// Code to validate the entered pin code
}
static void quit_cb() {
// Back to the main app menu
}
void ui_menu_pinentry_display(unsigned int value) {
// Draw the keypad
nbgl_useCaseKeypad("PIN Keypad (5555)",
4,
4,
false,
true,
validate_pin,
quit_cb);
}
void nbgl_useCaseKeypad(const char *title, uint8_t minDigits, uint8_t maxDigits, bool shuffled, bool hidden, nbgl_pinValidCallback_t validatePinCallback, nbgl_callback_t backCallback)

Keyboard Use Case

When text input is required (not just digits), a full keyboard can be displayed on Nano devices. The keyboard is navigable using the physical buttons, and supports different modes (lowercase, uppercase, digits, special characters).

The keyboard can be configured with either a confirmation button or dynamic suggestion buttons.

The nbgl_useCaseKeyboard() function enables to create such page, with the following parameters:

Keyboard with Confirmation Button (Nano)

This variant is used when you simply need to validate the entered text with a button.

Here is an example code to create a password nickname:

static char password_name[MAX_METANAME + 1] = {0};
static void create_password(void) {
// Process the entered password name
if (strlen(password_name) == 0) {
nbgl_useCaseStatus("The nickname\ncan't be empty", false, &display_menu);
} else {
// Create the password with the entered name
// ...
}
}
static void back_to_menu(void) {
// Return to main menu
}
void display_create_pwd(void) {
nbgl_kbdButtonParams_t confirmParams = {
.onButtonCallback = &create_password,
};
nbgl_keyboardParams_t keyboardParams = {
.title = "Create password",
.entryBuffer = password_name,
.entryMaxLen = sizeof(password_name),
.lettersOnly = false,
.mode = MODE_NONE,
.confirmationParams = confirmParams,
};
password_name[0] = '\0';
nbgl_useCaseKeyboard(&keyboardParams, &back_to_menu);
}
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
@ MODE_NONE
no mode defined (only for Nanos)
Definition nbgl_obj.h:612
void nbgl_useCaseStatus(const char *message, bool isSuccess, nbgl_callback_t quitCallback)
void nbgl_useCaseKeyboard(const nbgl_keyboardParams_t *params, nbgl_callback_t backCallback)
Structure containing configuration for keyboard with confirmation button.
nbgl_callback_t onButtonCallback
callback to call when the button is pressed
Structure containing all parameters for keyboard use case.
nbgl_layoutKeyboardContentType_t type
type of content

Keyboard with Suggestions (Nano)

This variant is used when you want to provide dynamic suggestions as the user types. This is particularly useful for word-by-word input, like entering a BIP39 recovery phrase.

Note
On Nano devices, suggestions are navigated using the same buttons as the keyboard.

Here is an example code for entering BIP39 words:

#define MAX_WORD_LENGTH 8
#define NB_MAX_SUGGESTION_BUTTONS 4
static char textToEnter[MAX_WORD_LENGTH + 1] = {0};
static char wordCandidates[(MAX_WORD_LENGTH + 1) * NB_MAX_SUGGESTION_BUTTONS] = {0};
static const char *buttonTexts[NB_MAX_SUGGESTION_BUTTONS] = {0};
enum {
FIRST_SUGGESTION_TOKEN = FIRST_USER_TOKEN + 10,
};
static void keyboard_dispatcher(const int token, uint8_t index) {
if (token >= FIRST_SUGGESTION_TOKEN) {
// On Nano, use both token and index to identify the suggestion
int buttonIndex = token - FIRST_SUGGESTION_TOKEN + index;
// Process the selected suggestion
add_word_to_phrase(buttonTexts[buttonIndex]);
// Continue to next word or finish
// ...
}
}
static void update_buttons_callback(nbgl_layoutKeyboardContent_t *content, uint32_t *mask) {
size_t textLen = strlen(textToEnter);
content->number = get_current_word_number() + 1;
if (textLen < 2) {
// No suggestions for less than 2 characters
} else {
// Fill suggestions based on BIP39 word list
const size_t nbMatchingWords = bolos_ux_bip39_fill_with_candidates(
(unsigned char *)textToEnter,
textLen,
wordCandidates,
buttonTexts);
content->suggestionButtons.nbUsedButtons = nbMatchingWords;
}
if (textLen > 0) {
// Update keyboard mask to show only valid next characters
*mask = bolos_ux_bip39_get_keyboard_mask((unsigned char *)textToEnter, textLen);
}
}
static void keyboard_back(void) {
// Handle back action (go to previous word or cancel)
}
void display_keyboard_page(void) {
nbgl_kbdSuggestParams_t suggestParams = {
.buttons = buttonTexts,
.firstButtonToken = FIRST_SUGGESTION_TOKEN,
.onButtonCallback = &keyboard_dispatcher,
.updateButtonsCallback = &update_buttons_callback,
};
nbgl_keyboardParams_t keyboardParams = {
.title = "Enter word #1",
.entryBuffer = textToEnter,
.entryMaxLen = sizeof(textToEnter),
.lettersOnly = true,
.suggestionParams = suggestParams,
};
textToEnter[0] = '\0';
memset(buttonTexts, 0, sizeof(buttonTexts[0]) * NB_MAX_SUGGESTION_BUTTONS);
nbgl_useCaseKeyboard(&keyboardParams, &keyboard_back);
}
#define NB_MAX_SUGGESTION_BUTTONS
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
@ MODE_LOWER_LETTERS
lower case letters mode
Definition nbgl_obj.h:609
Structure containing configuration for keyboard with suggestion buttons.
const char ** buttons
array of strings for buttons (last ones can be NULL)
This structure contains info to build a keyboard content (controls that are linked to keyboard)
uint8_t number
if numbered is true, number used to build 'number.' text
nbgl_layoutSuggestionButtons_t suggestionButtons
uint8_t nbUsedButtons
the number of actually used buttons

Refreshing screen

After having drawn graphic objects in framebuffer, all functions of this API automatically refresh the screen. So no need to call nbgl_refresh().