Skip to content

AlphaNum Keyboard Widget

The AlphaNum keyboard is a full QWERTY text-entry widget — a themed 4×10 key grid across three pages (lower / upper / symbols) for name/label/search fields. Init installs the whole look (theme-tracked SURFACE letter keys, an ACCENT Enter, a press highlight) and the built-in 3-page layout at a settable size; set_font() gives it text and, in its default TEXT mode, the widget collects typed characters into its OWN buffer — set_text_callbacks() wires a preview (fires after every key) and a commit (fires on Enter/OK). enable_header_preview() / enable_ok_cancel() add the same built-in editor chrome as the numpad, and ugui_alphanum_popup_open() raises it as a modal "tap a text field" editor exactly like the numpad's popup mode. An app can also replace the ENTIRE layout — set_layouts() swaps in its own ugui_alphanum_key_t tables (a different language, a PIN pad, a phone dialer) and set_colors() its own fixed palette, all from application code, no library file touched.

Every example below is complete — the file-scope storage, the callbacks and the build calls — beside the exact frame it renders on a 480×320 panel. Each compiles against nothing but the released library: drop it into the Application Skeleton and it runs as-is. The icons come from inc/icons/, the lexend fonts from inc/fonts/ — both ship with the library.

Examples

Default Keyboard

A bare QWERTY keyboard exactly as ugui_widget_alphanum_init() delivers it: every colour comes from the theme roles and the built-in dark/light label set is picked automatically. Text mode is on by default, so the widget collects typed characters into its own buffer; a preview callback echoes that buffer into the readout row.

Default Keyboard

/* --- widget IDs: only need to be unique within the screen (10+ leaves
 *     room for the IDs your app already uses, e.g. the root's) --- */
enum {
    WDGT_ID_DEMO = 10
};

/* --- fonts: each is DEFINED in inc/fonts/<name>.h — #include that
 *     header in exactly one .c of your app; elsewhere just: --- */
extern const ugui_font_t lexend_14pt_2bpp;

/* --- file-scope storage --- */
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_screen_t  s_screen;
static ugui_widget_t   s_root;
static ugui_widget_t   s_readout;
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static char            s_readout_str[40];
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_widget_t                 s_kbd;
static ugui_alphanum_keyboard_ext_t  s_kbd_ext;
#define RD_Y   (38)
#define RD_H   26
#define KB_X   6
#define KB_Y   (RD_Y + RD_H + 6)
#define KB_W   (UGUI_SCREEN_W - 12)
#define KB_H   (UGUI_SCREEN_H - KB_Y - 6)
#endif

/* --- local helpers & event callbacks --- */
static void on_preview(const char* text, void* ctx)
{
    (void)ctx;
#ifdef UGUI_ENABLE_FONT
    (void)snprintf(s_readout_str, sizeof(s_readout_str), "%s",
                   (text[0] != '\0') ? text : "type here...");
    ugui_widget_invalidate(&s_readout);
#endif
    printf("[alphanum.default] text \"%s\"\n", text);
}

/* --- build it (in your screen's init) --- */
ugui_widget_alphanum_init(&s_root, &s_kbd, &s_kbd_ext);
ugui_widget_set_area(&s_kbd, KB_X, KB_Y, (int16_t)KB_W, (int16_t)KB_H);
ugui_widget_set_id(&s_kbd, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_alphanum_set_font(&s_kbd, &lexend_14pt_2bpp);
#endif
ugui_widget_alphanum_set_text_callbacks(&s_kbd, on_preview, NULL, NULL);
ugui_screen_add_widget(&s_screen, &s_kbd);

Built-In Header, Preview & OK/Cancel

enable_header_preview() draws a title bar and a live preview of the edit buffer; enable_ok_cancel() adds the themed OK/Cancel row. In non-popup mode (bg_root = NULL) the widget still does ALL the editing via its built-in text mode — the app only wires OK/Cancel: OK copies the text to the readout, Cancel clears the entry.

Built-In Header, Preview & OK/Cancel

/* --- widget IDs: only need to be unique within the screen (10+ leaves
 *     room for the IDs your app already uses, e.g. the root's) --- */
enum {
    WDGT_ID_DEMO = 10
};

/* --- fonts: each is DEFINED in inc/fonts/<name>.h — #include that
 *     header in exactly one .c of your app; elsewhere just: --- */
extern const ugui_font_t lexend_14pt_2bpp;

/* --- file-scope storage --- */
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_screen_t  s_screen;
static ugui_widget_t   s_root;
static ugui_widget_t   s_readout;
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static char            s_readout_str[40];
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_widget_t                 s_kbd;
static ugui_alphanum_keyboard_ext_t  s_kbd_ext;
#define RD_Y   (38)
#define RD_H   24
#define KB_X   6
#define KB_Y   (RD_Y + RD_H + 6)
#define KB_W   (UGUI_SCREEN_W - 12)
#define KB_H   (UGUI_SCREEN_H - KB_Y - 6)
#endif

/* --- local helpers & event callbacks --- */
static void show_committed(const char* text)
{
#ifdef UGUI_ENABLE_FONT
    (void)snprintf(s_readout_str, sizeof(s_readout_str), "Committed: %s",
                   (text[0] != '\0') ? text : "-");
    ugui_widget_invalidate(&s_readout);
#else
    (void)text;
#endif
}

static void on_commit(const char* text, void* ctx)
{
    (void)ctx;
    show_committed(text);
    printf("[alphanum.entry] commit \"%s\"\n", text);
}

static void on_ok(void* ctx)
{
    (void)ctx;
    show_committed(ugui_widget_alphanum_get_text(&s_kbd));
}

static void on_cancel(void* ctx)
{
    (void)ctx;
    ugui_widget_alphanum_set_text(&s_kbd, "");   /* clear the entry */
    printf("[alphanum.entry] Cancel — entry cleared\n");
}

/* --- build it (in your screen's init) --- */
ugui_widget_alphanum_init(&s_root, &s_kbd, &s_kbd_ext);
ugui_widget_set_area(&s_kbd, KB_X, KB_Y, (int16_t)KB_W, (int16_t)KB_H);
ugui_widget_set_id(&s_kbd, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_alphanum_set_font(&s_kbd, &lexend_14pt_2bpp);
#endif
ugui_widget_alphanum_set_text_callbacks(&s_kbd, NULL, on_commit, NULL);
ugui_widget_alphanum_enable_header_preview(&s_kbd, 18u, 24u, "Enter name");
/* bg_root = NULL keeps the widget visible (no popup); the app owns OK/Cancel. */
ugui_widget_alphanum_enable_ok_cancel(&s_kbd, 26u, NULL);
s_kbd_ext.on_ok     = on_ok;
s_kbd_ext.on_cancel = on_cancel;
ugui_screen_add_widget(&s_screen, &s_kbd);

Tap-to-Edit Popup Form

Two text form fields (name/email); tapping one calls ugui_alphanum_popup_open() — the keyboard appears over the form, pre-filled with the field's current text. The built-in popup handlers do ALL the editing: OK copies the text back into the field and repaints it, Cancel discards.

Tap-to-Edit Popup Form

/* --- widget IDs: only need to be unique within the screen (10+ leaves
 *     room for the IDs your app already uses, e.g. the root's) --- */
enum {
    WDGT_ID_DEMO = 10
};

/* --- fonts: each is DEFINED in inc/fonts/<name>.h — #include that
 *     header in exactly one .c of your app; elsewhere just: --- */
extern const ugui_font_t lexend_14pt_2bpp;

/* --- file-scope storage --- */
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD) && defined(UGUI_WIDGET_ENABLE_TEXTEDIT)
static ugui_screen_t  s_screen;
static ugui_widget_t   s_root;
static ugui_widget_t                 s_kbd;
static ugui_alphanum_keyboard_ext_t  s_kbd_ext;
#define POP_X       4
#define POP_Y       16
#define POP_W       (UGUI_SCREEN_W - 8)
#define POP_H       (UGUI_SCREEN_H - 28)
#endif

/* --- build it (in your screen's init) --- */
ugui_widget_alphanum_init(NULL, &s_kbd, &s_kbd_ext);
ugui_widget_set_area(&s_kbd, POP_X, POP_Y, (int16_t)POP_W, (int16_t)POP_H);
ugui_widget_set_id(&s_kbd, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_alphanum_set_font(&s_kbd, &lexend_14pt_2bpp);
#endif
ugui_widget_alphanum_enable_header_preview(&s_kbd, 20u, 26u, "Edit field");
ugui_widget_alphanum_enable_ok_cancel(&s_kbd, 30u, &s_root);
ugui_screen_add_widget(&s_screen, &s_kbd);

Fully App-Defined Keyboard (QWERTZ)

The template for "I want a different keyboard": a German QWERTZ layout built entirely in application code — flash const key tables, a 3-page layout list, and a fixed palette via set_colors() — handed to the widget with set_layouts(). No uGui library file is touched; Z sits in the top row (tap it here) where Y would be on QWERTY.

Fully App-Defined Keyboard (QWERTZ)

/* --- widget IDs: only need to be unique within the screen (10+ leaves
 *     room for the IDs your app already uses, e.g. the root's) --- */
enum {
    WDGT_ID_DEMO = 10
};

/* --- fonts: each is DEFINED in inc/fonts/<name>.h — #include that
 *     header in exactly one .c of your app; elsewhere just: --- */
extern const ugui_font_t lexend_14pt_2bpp;

/* --- file-scope storage --- */
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_screen_t  s_screen;
static ugui_widget_t   s_root;
static ugui_widget_t   s_readout;
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static char            s_readout_str[40];
#endif
#if defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_widget_t                 s_kbd;
static ugui_alphanum_keyboard_ext_t  s_kbd_ext;
#if defined(UGUI_COLOR_FORMAT_RGB565)
#define LBL_WHITE { .value = (uint16_t)0xFFFFu }
#else
#define LBL_WHITE { .value = 0xFFFFFFFFu }
#endif
#define KW(lbl_, code_)  { (lbl_), LBL_WHITE, (uint32_t)(code_) }
#define KSP              KW(NULL, UGUI_ALNUM_KEY_SPACE)
#define KROW3_TAIL       KW(",",','), KSP, KSP, KSP, KSP, KW(".",'.'), \
                         KW("Enter", UGUI_ALNUM_KEY_ENTER), KW(NULL, UGUI_ALNUM_KEY_ENTER)
static const ugui_alphanum_key_t de_lower[40] = {
    /* Row 0: QWERTZ — note Z here, not Y */
    KW("q",'q'), KW("w",'w'), KW("e",'e'), KW("r",'r'), KW("t",'t'),
    KW("z",'z'), KW("u",'u'), KW("i",'i'), KW("o",'o'), KW("p",'p'),
    /* Row 1 */
    KW("a",'a'), KW("s",'s'), KW("d",'d'), KW("f",'f'), KW("g",'g'),
    KW("h",'h'), KW("j",'j'), KW("k",'k'), KW("l",'l'), KW("'",'\''),
    /* Row 2: shift | y x c v b n m | wide backspace  (Y lives here) */
    KW("aA", UGUI_ALNUM_KEY_SHIFT),
    KW("y",'y'), KW("x",'x'), KW("c",'c'), KW("v",'v'),
    KW("b",'b'), KW("n",'n'), KW("m",'m'),
    KW("<", UGUI_ALNUM_KEY_BACKSPACE), KW(NULL, UGUI_ALNUM_KEY_BACKSPACE),
    /* Row 3: [1#×2] , [space×4] . [Enter×2] */
    KW("1#", UGUI_ALNUM_KEY_LAYOUT_SYMBOL), KW(NULL, UGUI_ALNUM_KEY_LAYOUT_SYMBOL),
    KROW3_TAIL,
};
static const ugui_alphanum_key_t de_upper[40] = {
    KW("Q",'Q'), KW("W",'W'), KW("E",'E'), KW("R",'R'), KW("T",'T'),
    KW("Z",'Z'), KW("U",'U'), KW("I",'I'), KW("O",'O'), KW("P",'P'),
    KW("A",'A'), KW("S",'S'), KW("D",'D'), KW("F",'F'), KW("G",'G'),
    KW("H",'H'), KW("J",'J'), KW("K",'K'), KW("L",'L'), KW("'",'\''),
    KW("Aa", UGUI_ALNUM_KEY_SHIFT),
    KW("Y",'Y'), KW("X",'X'), KW("C",'C'), KW("V",'V'),
    KW("B",'B'), KW("N",'N'), KW("M",'M'),
    KW("<", UGUI_ALNUM_KEY_BACKSPACE), KW(NULL, UGUI_ALNUM_KEY_BACKSPACE),
    KW("1#", UGUI_ALNUM_KEY_LAYOUT_SYMBOL), KW(NULL, UGUI_ALNUM_KEY_LAYOUT_SYMBOL),
    KROW3_TAIL,
};
static const ugui_alphanum_key_t de_symbols[40] = {
    KW("1",'1'), KW("2",'2'), KW("3",'3'), KW("4",'4'), KW("5",'5'),
    KW("6",'6'), KW("7",'7'), KW("8",'8'), KW("9",'9'), KW("0",'0'),
    KW("@",'@'), KW("#",'#'), KW("$",'$'), KW("%",'%'), KW("&",'&'),
    KW("*",'*'), KW("(",'('), KW(")",')'), KW("-",'-'), KW("+",'+'),
    KW("!",'!'), KW("?",'?'), KW("/",'/'), KW("=",'='), KW(":",':'),
    KW(";",';'), KW("_",'_'), KW("\"",'"'),
    KW("<", UGUI_ALNUM_KEY_BACKSPACE), KW(NULL, UGUI_ALNUM_KEY_BACKSPACE),
    KW("abc", UGUI_ALNUM_KEY_LAYOUT_LOWER), KW(NULL, UGUI_ALNUM_KEY_LAYOUT_LOWER),
    KROW3_TAIL,
};
static const ugui_alphanum_layout_t de_pages[3] = {
    { de_lower,   4u, 10u },
    { de_upper,   4u, 10u },
    { de_symbols, 4u, 10u },
};
#define KB_X   6
#define KB_Y   (38 + 32)
#define KB_W   (UGUI_SCREEN_W - 12)
#define KB_H   (UGUI_SCREEN_H - KB_Y - 6)
#endif

/* --- local helpers & event callbacks --- */
static void on_preview(const char* text, void* ctx)
{
    (void)ctx;
#ifdef UGUI_ENABLE_FONT
    (void)snprintf(s_readout_str, sizeof(s_readout_str), "%s",
                   (text[0] != '\0') ? text : "QWERTZ - type here...");
    ugui_widget_invalidate(&s_readout);
#endif
    printf("[alphanum.custom] text \"%s\"\n", text);
}

/* --- build it (in your screen's init) --- */
ugui_widget_alphanum_init(&s_root, &s_kbd, &s_kbd_ext);
ugui_widget_set_area(&s_kbd, KB_X, KB_Y, (int16_t)KB_W, (int16_t)KB_H);
ugui_widget_set_id(&s_kbd, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_alphanum_set_font(&s_kbd, &lexend_14pt_2bpp);
#endif
/* 1) the app's own key tables (German QWERTZ, 3 pages) */
ugui_widget_alphanum_set_layouts(&s_kbd, de_pages, 3u, 0u);
/* 2) the app's own fixed palette — theme-independent, always readable */
ugui_widget_alphanum_set_colors(&s_kbd,
                                ugui_color_hex(0x2B2F3Au),   /* key face  */
                                ugui_color_hex(0x3A4150u),   /* border    */
                                ugui_color_hex(0x4C6EF5u));  /* pressed / Enter */
s_kbd.color = ugui_color_hex(0x1E2230u);                    /* panel gap fill */
/* 3) the app owns key handling (built-in text mode still fills text_buf) */
ugui_widget_alphanum_set_text_callbacks(&s_kbd, on_preview, NULL, NULL);
ugui_screen_add_widget(&s_screen, &s_kbd);


From this widget to a working app

Everything above is the widget-specific code. The scaffolding it drops into — storage, HAL, main loop, display-mode bring-up — is the same for every app: copy it from the Application Skeleton.