TextEdit Widget¶
The TextEdit widget is a single-line input field — a numeric entry, a
username, a password. Init installs theme-tracked background/border/cursor
colours, default border width, corner radius and padding, the CLICK/LEFT/
RIGHT/CONFIRM event mask, and (with UGUI_ENABLE_DEFAULTS) a visible
default size; set_font() gives it a glyph set. The blinking cursor runs
from the library's own tick — there is no on-screen keyboard built in, so an
app drives input_char()/delete_char()/clear() from its own keys or a
popup keyboard. set_mask() renders every glyph as a fixed character (the
buffer itself is never touched — masking is display-only), and
set_enabled(false) turns a field into a locked, read-only value display.
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 Field (numeric keypad)¶
A field created with nothing but ugui_widget_textedit_init() + set_font() — every colour, the border, radius, padding and size come from the library defaults. A numeric keypad drives the widget's own editing API directly: input_char() per digit, delete_char() for backspace, clear() for Clr.

/* --- 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_SLOT0 = 10, WDGT_ID_DEMO, WDGT_ID_CLEAR
};
/* --- 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_TEXTEDIT)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static ugui_widget_t s_edit;
static ugui_textedit_ext_t s_edit_ext;
static char s_edit_buf[16] = "12.5";
#define KEY_N 12u
static ugui_widget_t s_key[KEY_N];
static ugui_button_ext_t s_key_ext[KEY_N];
static ugui_widget_t s_clr;
static ugui_button_ext_t s_clr_ext;
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT)
static ugui_text_cfg_t s_key_text[KEY_N];
static ugui_text_cfg_t s_clr_text;
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT)
static const char k_key_char[KEY_N] = {
'7','8','9',
'4','5','6',
'1','2','3',
'.','0','\b'
};
static const char* const k_key_label[KEY_N] = {
"7","8","9", "4","5","6", "1","2","3", ".","0","<X"
};
#define FLD_W 300
#define FLD_H 36
#define FLD_X ((int16_t)((UGUI_SCREEN_W - FLD_W) / 2))
#define FLD_Y 50
#define PAD_KW 70
#define PAD_KH 34
#define PAD_GAP 8
#define PAD_W ((int16_t)(3 * PAD_KW + 2 * PAD_GAP))
#define PAD_X0 ((int16_t)((UGUI_SCREEN_W - PAD_W) / 2))
#define PAD_Y0 ((int16_t)(FLD_Y + FLD_H + 12))
#endif
/* --- local helpers & event callbacks --- */
static void on_key(uint8_t widget_id, ugui_event_t event)
{
if (event != UGUI_EVENT_CLICK) { return; }
uint8_t idx = (uint8_t)(widget_id - (uint8_t)WDGT_ID_SLOT0);
if (idx >= KEY_N) { return; }
char c = k_key_char[idx];
if (c == '\b') { ugui_textedit_delete_char(&s_edit); }
else { (void)ugui_textedit_input_char(&s_edit, c); }
#if UGUI_ENABLE_KEYPAD
ugui_set_focus(&s_edit); /* keep the field focused so the cursor stays */
#endif
}
static void on_clear(uint8_t widget_id, ugui_event_t event)
{
(void)widget_id;
if (event != UGUI_EVENT_CLICK) { return; }
ugui_textedit_clear(&s_edit);
#if UGUI_ENABLE_KEYPAD
ugui_set_focus(&s_edit);
#endif
}
static void add_button(ugui_widget_t* w, ugui_button_ext_t* ext, ugui_text_cfg_t* text,
uint8_t id, int16_t x, int16_t y, int16_t bw, int16_t bh,
ugui_color_t fill, const char* str, ugui_event_cb_t cb)
{
ugui_widget_button_init(&s_root, w, ext);
ugui_widget_set_area(w, x, y, bw, bh);
ugui_widget_set_id(w, id);
ugui_widget_button_set_style(w, true, 5u, 1u, fill, UGUI_THEME_ACCENT);
#ifdef UGUI_ENABLE_FONT
ugui_text_cfg_init(text, str, &lexend_14pt_2bpp, UGUI_THEME_TEXT,
UGUI_ALIGN_CENTER, (ugui_point_t){ 0, 0 }, 1u);
ugui_widget_button_set_text(w, text);
#endif
ugui_widget_set_event_cb(w, cb,
UGUI_EMASK_CLICK | UGUI_EMASK_DOWN | UGUI_EMASK_UP
| UGUI_EMASK_KEY_CONFIRM);
ugui_screen_add_widget(&s_screen, w);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, w);
#endif
}
/* --- build it (in your screen's init) --- */
ugui_widget_textedit_init(&s_root, &s_edit, &s_edit_ext,
s_edit_buf, (uint8_t)sizeof(s_edit_buf));
ugui_widget_set_area(&s_edit, FLD_X, FLD_Y, FLD_W, FLD_H);
ugui_widget_set_id(&s_edit, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_edit, &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
ugui_screen_add_widget(&s_screen, &s_edit);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, &s_edit);
#endif
/* Numeric keypad — each key calls the widget's editing API directly. */
uint8_t i;
for (i = 0u; i < KEY_N; i++) {
int16_t col = (int16_t)(i % 3u);
int16_t row = (int16_t)(i / 3u);
int16_t kx = (int16_t)(PAD_X0 + col * (PAD_KW + PAD_GAP));
int16_t ky = (int16_t)(PAD_Y0 + row * (PAD_KH + PAD_GAP));
add_button(&s_key[i], &s_key_ext[i], &s_key_text[i],
(uint8_t)(WDGT_ID_SLOT0 + i), kx, ky, PAD_KW, PAD_KH,
UGUI_THEME_SURFACE, k_key_label[i], on_key);
}
/* Full-width Clear under the grid. */
{
int16_t clr_y = (int16_t)(PAD_Y0 + 4 * (PAD_KH + PAD_GAP));
add_button(&s_clr, &s_clr_ext, &s_clr_text, WDGT_ID_CLEAR,
PAD_X0, clr_y, PAD_W, 28, ugui_color_blend(UGUI_THEME_SURFACE, UGUI_THEME_BG, 96u), "Clear", on_clear);
}
Cursor Movement & Read-Only¶
A compact key row fires ugui_textedit_on_event(KEY_LEFT/RIGHT) to move the insertion cursor and input_char()/delete_char() to edit at it — so a typed character lands mid-string, not just at the end. Below it, a second field with set_enabled(false): the central dispatcher drops every event before the widget sees it, so it never focuses (no cursor) and ignores taps — a locked, read-only display.

/* --- 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_SLOT0 = 10, WDGT_ID_DEMO, WDGT_ID_CLEAR,
WDGT_ID_READONLY
};
/* --- 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_TEXTEDIT)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static ugui_widget_t s_edit;
static ugui_textedit_ext_t s_edit_ext;
static char s_edit_buf[16] = "Hello";
static ugui_widget_t s_ro;
static ugui_textedit_ext_t s_ro_ext;
static char s_ro_buf[16] = "read-only";
#define KEY_N 7u
static ugui_widget_t s_key[KEY_N];
static ugui_button_ext_t s_key_ext[KEY_N];
static ugui_widget_t s_clr;
static ugui_button_ext_t s_clr_ext;
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT)
static ugui_text_cfg_t s_key_text[KEY_N];
static ugui_text_cfg_t s_clr_text;
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT)
#define ACT_LEFT 0x01
#define ACT_RIGHT 0x02
static const char k_key_act[KEY_N] = {
ACT_LEFT, ACT_RIGHT, '\b', 'X', 'Y', 'Z', ' '
};
static const char* const k_key_label[KEY_N] = {
"<", ">", "<X", "X", "Y", "Z", "sp"
};
#define FLD_W ((int16_t)(UGUI_SCREEN_W - 2 * 10))
#define FLD_H 36
#define EDIT_Y ((int16_t)(38 + 20))
#define KEYROW_Y ((int16_t)(EDIT_Y + FLD_H + 14))
#define KEY_H 36
#define CLR_Y ((int16_t)(KEYROW_Y + KEY_H + 8))
#define CLR_H 26
#define RO_Y ((int16_t)(CLR_Y + CLR_H + 30))
#endif
/* --- local helpers & event callbacks --- */
static void on_key(uint8_t widget_id, ugui_event_t event)
{
if (event != UGUI_EVENT_CLICK) { return; }
uint8_t idx = (uint8_t)(widget_id - (uint8_t)WDGT_ID_SLOT0);
if (idx >= KEY_N) { return; }
char a = k_key_act[idx];
switch (a) {
case ACT_LEFT: ugui_textedit_on_event(&s_edit, (ugui_event_t)UGUI_KEY_LEFT); break;
case ACT_RIGHT: ugui_textedit_on_event(&s_edit, (ugui_event_t)UGUI_KEY_RIGHT); break;
case '\b': ugui_textedit_delete_char(&s_edit); break;
default: (void)ugui_textedit_input_char(&s_edit, a); break;
}
#if UGUI_ENABLE_KEYPAD
ugui_set_focus(&s_edit);
#endif
}
static void on_clear(uint8_t widget_id, ugui_event_t event)
{
(void)widget_id;
if (event != UGUI_EVENT_CLICK) { return; }
ugui_textedit_clear(&s_edit);
#if UGUI_ENABLE_KEYPAD
ugui_set_focus(&s_edit);
#endif
}
static void add_button(ugui_widget_t* w, ugui_button_ext_t* ext, ugui_text_cfg_t* text,
uint8_t id, int16_t x, int16_t y, int16_t bw, int16_t bh,
ugui_color_t fill, const char* str, ugui_event_cb_t cb)
{
ugui_widget_button_init(&s_root, w, ext);
ugui_widget_set_area(w, x, y, bw, bh);
ugui_widget_set_id(w, id);
ugui_widget_button_set_style(w, true, 5u, 1u, fill, UGUI_THEME_ACCENT);
#ifdef UGUI_ENABLE_FONT
ugui_text_cfg_init(text, str, &lexend_14pt_2bpp, UGUI_THEME_TEXT,
UGUI_ALIGN_CENTER, (ugui_point_t){ 0, 0 }, 1u);
ugui_widget_button_set_text(w, text);
#endif
ugui_widget_set_event_cb(w, cb,
UGUI_EMASK_CLICK | UGUI_EMASK_DOWN | UGUI_EMASK_UP
| UGUI_EMASK_KEY_CONFIRM);
ugui_screen_add_widget(&s_screen, w);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, w);
#endif
}
/* --- build it (in your screen's init) --- */
/* Editable field. */
ugui_widget_textedit_init(&s_root, &s_edit, &s_edit_ext,
s_edit_buf, (uint8_t)sizeof(s_edit_buf));
ugui_widget_set_area(&s_edit, 10, EDIT_Y, FLD_W, FLD_H);
ugui_widget_set_id(&s_edit, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_edit, &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
/* Cursor starts at the end of "Hello". */
ugui_screen_add_widget(&s_screen, &s_edit);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, &s_edit);
#endif
/* Key row. */
{
int16_t avail = (int16_t)(UGUI_SCREEN_W - 2 * 10);
int16_t kw = (int16_t)((avail - (int16_t)(KEY_N) * 6 + 6) / (int16_t)KEY_N);
uint8_t i;
for (i = 0u; i < KEY_N; i++) {
int16_t kx = (int16_t)(10 + (int16_t)i * (kw + 6));
add_button(&s_key[i], &s_key_ext[i], &s_key_text[i],
(uint8_t)(WDGT_ID_SLOT0 + i), kx, KEYROW_Y, kw, KEY_H,
UGUI_THEME_SURFACE, k_key_label[i], on_key);
}
}
add_button(&s_clr, &s_clr_ext, &s_clr_text, WDGT_ID_CLEAR,
10, CLR_Y, FLD_W, CLR_H, ugui_color_blend(UGUI_THEME_SURFACE, UGUI_THEME_BG, 96u), "Clear", on_clear);
ugui_widget_textedit_init(&s_root, &s_ro, &s_ro_ext,
s_ro_buf, (uint8_t)sizeof(s_ro_buf));
ugui_widget_set_area(&s_ro, 10, RO_Y, FLD_W, FLD_H);
ugui_widget_set_id(&s_ro, WDGT_ID_READONLY);
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_ro, &lexend_14pt_2bpp, ugui_color_blend(UGUI_THEME_TEXT, UGUI_THEME_BG, 110u));
#endif
ugui_textedit_set_colors(&s_ro, UGUI_THEME_BG, UGUI_THEME_BORDER, UGUI_THEME_BORDER);
ugui_widget_set_enabled(&s_ro, false); /* locked: never focuses, no cursor */
ugui_screen_add_widget(&s_screen, &s_ro);
Colours, Sizes & Password Masking¶
A colour column (three set_colors() presets), a size column (the same field at three border/radius/padding/height combos — plain ext fields, no dedicated setter), and a password field with set_mask('*') — the buffer still holds the real text (get_text() returns it), but every glyph renders as *.

/* --- 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_SLOT0 = 10, WDGT_ID_SLOT3, WDGT_ID_DEMO
};
/* --- 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_TEXTEDIT)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
#define COL_N 3u
static ugui_widget_t s_col_w [COL_N];
static ugui_textedit_ext_t s_col_ext[COL_N];
static char s_col_buf[COL_N][12] = { "Accent", "Success", "Alert" };
#define SIZE_N 3u
static ugui_widget_t s_size_w [SIZE_N];
static ugui_textedit_ext_t s_size_ext[SIZE_N];
static char s_size_buf[SIZE_N][12] = { "Small", "Medium", "Large" };
static const uint8_t k_size_border[SIZE_N] = { 1u, 2u, 3u };
static const uint8_t k_size_radius[SIZE_N] = { 2u, 6u, 12u };
static const uint8_t k_size_pad [SIZE_N] = { 3u, 6u, 10u };
static const int16_t k_size_h [SIZE_N] = { 26, 34, 44 };
static ugui_widget_t s_pw_w;
static ugui_textedit_ext_t s_pw_ext;
static char s_pw_buf[16] = "secret";
#define HDR_Y 38
#define COL_X 10
#define COL_W 200
#define COL_ROW0 ((int16_t)(HDR_Y + 22))
#define COL_STEP 44
#define SIZE_X ((int16_t)(COL_X + COL_W + 24))
#define SIZE_W 190
#define PW_Y ((int16_t)(UGUI_SCREEN_H - 54))
#define PW_H 36
#endif
/* --- build it (in your screen's init) --- */
ugui_color_t border_col[COL_N];
border_col[0] = UGUI_THEME_ACCENT;
border_col[1] = UGUI_THEME_OK;
border_col[2] = UGUI_THEME_CANCEL;
uint8_t i;
for (i = 0u; i < COL_N; i++) {
int16_t y = (int16_t)(COL_ROW0 + (int16_t)i * COL_STEP);
ugui_widget_textedit_init(&s_root, &s_col_w[i], &s_col_ext[i],
s_col_buf[i], (uint8_t)sizeof(s_col_buf[i]));
ugui_widget_set_area(&s_col_w[i], COL_X, y, COL_W, 34);
ugui_widget_set_id(&s_col_w[i], (uint8_t)(WDGT_ID_SLOT0 + i));
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_col_w[i], &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
ugui_textedit_set_colors(&s_col_w[i], UGUI_THEME_SURFACE, border_col[i], border_col[i]);
ugui_widget_set_enabled(&s_col_w[i], false); /* display-only */
ugui_screen_add_widget(&s_screen, &s_col_w[i]);
}
int16_t sy = COL_ROW0;
for (i = 0u; i < SIZE_N; i++) {
int16_t h = k_size_h[i];
ugui_widget_textedit_init(&s_root, &s_size_w[i], &s_size_ext[i],
s_size_buf[i], (uint8_t)sizeof(s_size_buf[i]));
ugui_widget_set_area(&s_size_w[i], SIZE_X, sy, SIZE_W, h);
ugui_widget_set_id(&s_size_w[i], (uint8_t)(WDGT_ID_SLOT3 + i));
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_size_w[i], &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
s_size_ext[i].border_width = k_size_border[i];
s_size_ext[i].corner_radius = k_size_radius[i];
s_size_ext[i].padding_x = k_size_pad[i];
ugui_widget_set_enabled(&s_size_w[i], false);
ugui_screen_add_widget(&s_screen, &s_size_w[i]);
sy = (int16_t)(sy + h + 8);
}
ugui_widget_textedit_init(&s_root, &s_pw_w, &s_pw_ext,
s_pw_buf, (uint8_t)sizeof(s_pw_buf));
ugui_widget_set_area(&s_pw_w, COL_X, PW_Y,
(int16_t)(UGUI_SCREEN_W - 2 * 10), PW_H);
ugui_widget_set_id(&s_pw_w, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(&s_pw_w, &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
ugui_textedit_set_mask(&s_pw_w, '*'); /* render every glyph as '*' */
ugui_widget_set_enabled(&s_pw_w, false);
ugui_screen_add_widget(&s_screen, &s_pw_w);
Login Form (keyboard popup)¶
Two fields — Username (plain) and Password (masked) — plus a docked alphanum keyboard in popup mode. Tapping a field opens the keyboard targeting that field's own buffer; on OK the built-in popup handlers copy the edited text back and repaint the field (the password field re-renders masked). Submit reads both values with get_text() — the real password included, proving masking is display-only.

/* --- 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, WDGT_ID_SLOT0, WDGT_ID_SLOT8,
WDGT_ID_SUBMIT, WDGT_ID_STATUS, WDGT_ID_KEYBOARD
};
/* --- 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_TEXTEDIT) && defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static ugui_widget_t s_user_lbl;
static ugui_label_ext_t s_user_lbl_ext;
static ugui_widget_t s_user_w;
static ugui_textedit_ext_t s_user_ext;
static char s_user_buf[24] = "admin";
static ugui_widget_t s_pass_lbl;
static ugui_label_ext_t s_pass_lbl_ext;
static ugui_widget_t s_pass_w;
static ugui_textedit_ext_t s_pass_ext;
static char s_pass_buf[24] = "pw123";
static ugui_widget_t s_submit;
static ugui_button_ext_t s_submit_ext;
static ugui_widget_t s_status;
static ugui_label_ext_t s_status_ext;
static ugui_widget_t s_kbd;
static ugui_alphanum_keyboard_ext_t s_kbd_ext;
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT) && defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
static ugui_text_cfg_t s_submit_text;
static char s_status_buf[40];
#endif
#if defined(UGUI_WIDGET_ENABLE_TEXTEDIT) && defined(UGUI_WIDGET_ENABLE_ALPHANUM_KEYBOARD)
#define LBL_X 10
#define LBL_W 96
#define FLD_X ((int16_t)(LBL_X + LBL_W + 8))
#define FLD_W ((int16_t)(UGUI_SCREEN_W - FLD_X - 10))
#define FLD_H 34
#define ROW0_Y ((int16_t)(38 + 16))
#define ROW_STEP 46
#define SUBMIT_Y ((int16_t)(ROW0_Y + 2 * ROW_STEP + 6))
#define SUBMIT_H 34
#define STATUS_Y ((int16_t)(SUBMIT_Y + SUBMIT_H + 12))
#define POP_X 4
#define POP_Y 16
#define POP_W (UGUI_SCREEN_W - 8)
#define POP_H (UGUI_SCREEN_H - 28)
#endif
/* --- local helpers & event callbacks --- */
static void on_field_click(uint8_t widget_id, ugui_event_t event)
{
if (event != UGUI_EVENT_CLICK) { return; }
switch (widget_id) {
case WDGT_ID_DEMO: /* Username */
ugui_alphanum_popup_open(&s_kbd, &s_user_w, s_user_buf,
(uint8_t)sizeof(s_user_buf));
break;
case WDGT_ID_SLOT0: /* Password */
ugui_alphanum_popup_open(&s_kbd, &s_pass_w, s_pass_buf,
(uint8_t)sizeof(s_pass_buf));
break;
default:
break;
}
}
static void on_submit(uint8_t widget_id, ugui_event_t event)
{
(void)widget_id;
if (event != UGUI_EVENT_CLICK) { return; }
const char* user = ugui_textedit_get_text(&s_user_w);
const char* pass = ugui_textedit_get_text(&s_pass_w);
/* Password is masked on screen but readable here — masking is display-only. */
printf("[textedit.form] submit: user='%s' pass='%s'\n",
(user != NULL) ? user : "", (pass != NULL) ? pass : "");
#ifdef UGUI_ENABLE_FONT
(void)snprintf(s_status_buf, sizeof(s_status_buf), "Signed in as %s",
(user != NULL) ? user : "");
ugui_widget_label_update_text_str(&s_status, s_status_buf);
#endif
}
static void add_label(ugui_widget_t* w, ugui_label_ext_t* ext, uint8_t id,
int16_t x, int16_t y, int16_t cw, int16_t ch,
const char* str, ugui_align_t align)
{
ugui_widget_label_init(&s_root, w, ext);
ugui_widget_set_area(w, x, y, cw, ch);
ugui_widget_set_id (w, id);
ugui_widget_label_set_style(w, /*bg_fill=*/false, UGUI_THEME_BG, str,
&lexend_14pt_2bpp, UGUI_THEME_TEXT, align, 1u);
ugui_screen_add_widget(&s_screen, w);
}
static void add_button(ugui_widget_t* w, ugui_button_ext_t* ext, ugui_text_cfg_t* text,
uint8_t id, int16_t x, int16_t y, int16_t bw, int16_t bh,
const char* str, ugui_event_cb_t cb)
{
ugui_widget_button_init(&s_root, w, ext);
ugui_widget_set_area(w, x, y, bw, bh);
ugui_widget_set_id(w, id);
ugui_widget_button_set_style(w, true, 5u, 1u, UGUI_THEME_ACCENT, UGUI_THEME_ACCENT);
#ifdef UGUI_ENABLE_FONT
ugui_text_cfg_init(text, str, &lexend_14pt_2bpp, UGUI_THEME_TEXT,
UGUI_ALIGN_CENTER, (ugui_point_t){ 0, 0 }, 1u);
ugui_widget_button_set_text(w, text);
#endif
ugui_widget_set_event_cb(w, cb,
UGUI_EMASK_CLICK | UGUI_EMASK_DOWN | UGUI_EMASK_UP
| UGUI_EMASK_KEY_CONFIRM);
ugui_screen_add_widget(&s_screen, w);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, w);
#endif
}
static void make_field(ugui_widget_t* lbl, ugui_label_ext_t* lbl_ext,
ugui_widget_t* fw, ugui_textedit_ext_t* fe,
char* buf, uint8_t cap, int16_t y,
const char* caption, uint8_t id, char mask)
{
add_label(lbl, lbl_ext, (uint8_t)(WDGT_ID_SLOT8 + id),
LBL_X, y, LBL_W, FLD_H, caption,
(ugui_align_t)(UGUI_ALIGN_LEFT | UGUI_ALIGN_V_CENTER));
ugui_widget_textedit_init(&s_root, fw, fe, buf, cap);
ugui_widget_set_area(fw, FLD_X, y, FLD_W, FLD_H);
ugui_widget_set_id(fw, id);
#ifdef UGUI_ENABLE_FONT
ugui_textedit_set_font(fw, &lexend_14pt_2bpp, UGUI_THEME_TEXT);
#endif
if (mask != 0) { ugui_textedit_set_mask(fw, mask); }
/* Tap (or ENTER on a focused field) opens the keyboard popup for this field. */
ugui_widget_set_event_cb(fw, on_field_click, UGUI_EMASK_CLICK | UGUI_EMASK_KEY_CONFIRM);
ugui_screen_add_widget(&s_screen, fw);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, fw);
#endif
}
/* --- build it (in your screen's init) --- */
make_field(&s_user_lbl, &s_user_lbl_ext, &s_user_w, &s_user_ext,
s_user_buf, (uint8_t)sizeof(s_user_buf),
ROW0_Y + 0 * ROW_STEP, "Username", WDGT_ID_DEMO, 0);
make_field(&s_pass_lbl, &s_pass_lbl_ext, &s_pass_w, &s_pass_ext,
s_pass_buf, (uint8_t)sizeof(s_pass_buf),
ROW0_Y + 1 * ROW_STEP, "Password", WDGT_ID_SLOT0, '*');
/* Submit button. */
add_button(&s_submit, &s_submit_ext, &s_submit_text, WDGT_ID_SUBMIT,
FLD_X, SUBMIT_Y, FLD_W, SUBMIT_H, "Sign in", on_submit);
/* Status line. */
add_label(&s_status, &s_status_ext, WDGT_ID_STATUS,
LBL_X, STATUS_Y, (int16_t)(UGUI_SCREEN_W - 2 * 10), 22,
"Tap a field to edit | Sign in reads both values",
UGUI_ALIGN_CENTER);
/* Popup keyboard — added LAST so it draws on top. */
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_KEYBOARD);
#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);
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.