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:
- For Home Screen & Settings:
- For Individual pages:
- For most used reviews:
- for reviews with a warning prolog:
- For address verification:
- For keypad:
- For keyboard:
- For generic navigable content:
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
enum {
SWITCH2_TOKEN
};
.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"};
static void controlsCallback(int token, uint8_t index, int page) {
if (token == SWITCH1_TOKEN) {
if (index == 0) {
}
else {
}
}
else if (token == SWITCH2_TOKEN) {
if (index == 0) {
}
else {
}
}
}
.content.switchesList.switches = switches,
.contentActionCallback = controlsCallback
};
.nbContents = 1
};
.infoTypes = infoTypes,
.infoContents = infoContents
};
void onQuit(void) {
}
void appMain(void) {
app_icon,
NULL,
&esettingContents,
&infosList,
NULL,
onQuit);
}
@ 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.
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) {
}
void onRejectTransaction(void) {
"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) {
}
else {
}
}
void onRejectTransaction(void) {
"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) {
}
else {
}
}
static const char *detailTexts[] = {"Address"};
static const char *detailSubTexts[] = {"0x1234...5678"};
.
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:
};
static void review_choice(bool confirm) {
if (confirm) {
}
else {
}
}
void startReview(void) {
pairs[0].
item =
"Amount";
pairs[0].
value =
"NBT 0.99";
pairs[1].
item =
"Address";
pairs[1].
value =
"0x1234567890";
&pairList,
app_icon,
"Review transaction\nto send NBT",
NULL,
NULL,
review_choice);
}
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:
.pairs = NULL,
.callback = getPair,
};
static void review_choice(bool confirm) {
if (confirm) {
}
else {
}
}
switch (index) {
case 0:
break;
case 1:
pair.
value =
"0x1234567890";
break;
}
return &pair;
}
void startReview(void) {
&pairList,
app_icon,
"Review transaction\nto send NBT",
NULL,
NULL,
review_choice);
}
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:
static void onReviewResult(bool confirm) {
if (confirm) {
}
else {
}
}
static void onTransactionContinue(bool askMore)
{
if (askMore) {
if (moreDataToSend(&pairsToSend)) {
}
else {
onReviewResult);
}
}
else {
onReviewResult(false);
}
}
void startReview(void) {
app_icon,
"Review transaction\nto send NBT",
NULL,
onTransactionContinue);
}
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:
.nbPairs = 4,
};
static void onReviewResult(bool confirm) {
if (confirm) {
}
else {
}
}
void staticReview(void) {
&pairList,
coinIcon,
"Review transaction\nto send coin",
NULL,
"Sign transaction to\nsend coin?",
NULL,
&warningDesc,
onReviewResult);
}
@ 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...
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:
};
static void review_choice(bool confirm) {
if (confirm) {
}
else {
}
}
void app_ethereumVerifyAddress(void) {
pairs[0].
item =
"Type address";
pairs[0].
value =
"dummy type";
pairs[1].
item =
"Sub address";
pairs[1].
value =
"dummy sub address";
"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) {
}
static void quit_cb() {
}
void ui_menu_pinentry_display(unsigned int value) {
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) {
if (strlen(password_name) == 0) {
} else {
}
}
static void back_to_menu(void) {
}
void display_create_pwd(void) {
};
.title = "Create password",
.entryBuffer = password_name,
.entryMaxLen = sizeof(password_name),
.lettersOnly = false,
.confirmationParams = confirmParams,
};
password_name[0] = '\0';
}
@ KEYBOARD_WITH_BUTTON
text entry area + confirmation button
@ MODE_NONE
no mode defined (only for Nanos)
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 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};
enum {
};
static void keyboard_dispatcher(const int token, uint8_t index) {
if (token >= FIRST_SUGGESTION_TOKEN) {
int buttonIndex = token - FIRST_SUGGESTION_TOKEN + index;
add_word_to_phrase(buttonTexts[buttonIndex]);
}
}
size_t textLen = strlen(textToEnter);
content->
number = get_current_word_number() + 1;
if (textLen < 2) {
} else {
const size_t nbMatchingWords = bolos_ux_bip39_fill_with_candidates(
(unsigned char *)textToEnter,
textLen,
wordCandidates,
buttonTexts);
}
if (textLen > 0) {
*mask = bolos_ux_bip39_get_keyboard_mask((unsigned char *)textToEnter, textLen);
}
}
static void keyboard_back(void) {
}
void display_keyboard_page(void) {
.firstButtonToken = FIRST_SUGGESTION_TOKEN,
.onButtonCallback = &keyboard_dispatcher,
.updateButtonsCallback = &update_buttons_callback,
};
.title = "Enter word #1",
.entryBuffer = textToEnter,
.entryMaxLen = sizeof(textToEnter),
.lettersOnly = true,
.suggestionParams = suggestParams,
};
textToEnter[0] = '\0';
}
#define NB_MAX_SUGGESTION_BUTTONS
@ KEYBOARD_WITH_SUGGESTIONS
text entry area + suggestion buttons
@ MODE_LOWER_LETTERS
lower case letters mode
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
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().