Calendar Widget¶
The Calendar is an inline (or modal) month-grid date picker — a header
with month/year navigation arrows, a weekday row, and a 6×7 day grid. Init
installs the whole look (theme-tracked SURFACE panel, ACCENT header/
selection, GREEN "today" marker, keypad-focus fill) at a settable size;
set_font() gives it text and set_on_select() fires with the committed
(year, month, day) whenever a day is tapped or CONFIRMed. set_theme()
replaces every element's colour with a fixed ten-colour palette that ignores
the app theme, set_week_start() picks Sunday- or Monday-first columns,
set_year_range() clamps the year arrows, set_today() places the green
marker, and set_date() pre-selects a day. ugui_widget_calendar_open() /
_close() raise it as a full-screen modal overlay (the same mechanism the
message box uses) — the pattern for a "tap a date field" form.
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 Calendar¶
An inline calendar exactly as ugui_widget_calendar_init() delivers it: every colour comes from the theme roles. Tap a ‹ › arrow to change month/year, tap a day to pick it — the readout beside it echoes the committed date via set_on_select().

/* --- 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_CALENDAR)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static ugui_widget_t s_readout;
#endif
#if defined(UGUI_WIDGET_ENABLE_CALENDAR)
static char s_readout_str[16];
#endif
#if defined(UGUI_WIDGET_ENABLE_CALENDAR)
static ugui_widget_t s_cal;
static ugui_calendar_ext_t s_cal_ext;
#define CAL_X 8
#define CAL_Y (38 + 2)
#define CAL_W (UGUI_SCREEN_W - 108) /* 212 on a 320 panel */
#define CAL_H (UGUI_SCREEN_H - CAL_Y - 8)
#endif
/* --- local helpers & event callbacks --- */
static void on_select(uint16_t year, uint8_t month, uint8_t day, void* ctx)
{
(void)ctx;
#ifdef UGUI_ENABLE_FONT
(void)snprintf(s_readout_str, sizeof(s_readout_str), "%04u-%02u-%02u",
(unsigned)year, (unsigned)month, (unsigned)day);
ugui_widget_invalidate(&s_readout);
#else
(void)year; (void)month; (void)day;
#endif
printf("[calendar.default] pick %04u-%02u-%02u\n",
(unsigned)year, (unsigned)month, (unsigned)day);
}
/* --- build it (in your screen's init) --- */
ugui_widget_calendar_init(&s_root, &s_cal, &s_cal_ext);
ugui_widget_set_area(&s_cal, CAL_X, CAL_Y, (int16_t)CAL_W, (int16_t)CAL_H);
ugui_widget_set_id(&s_cal, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_calendar_set_font(&s_cal, &lexend_14pt_2bpp);
#endif
ugui_widget_calendar_set_on_select(&s_cal, on_select, NULL);
ugui_screen_add_widget(&s_screen, &s_cal);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, &s_cal);
#endif
Custom Theme & Configuration¶
The same widget driven through its setters: set_theme() for a full custom "amber on slate" palette, set_week_start(0) for Sunday-first columns, set_year_range() to clamp the year arrows, set_today() for a green marker on today, and set_date() for a pre-selected day — selection, today and keypad-focus each use a distinct colour so they read apart.

/* --- 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_CALENDAR)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static ugui_widget_t s_readout;
#endif
#if defined(UGUI_WIDGET_ENABLE_CALENDAR)
static char s_readout_str[16];
#endif
#if defined(UGUI_WIDGET_ENABLE_CALENDAR)
static ugui_widget_t s_cal;
static ugui_calendar_ext_t s_cal_ext;
#define CAL_X 8
#define CAL_Y (38 + 2)
#define CAL_W (UGUI_SCREEN_W - 108)
#define CAL_H (UGUI_SCREEN_H - CAL_Y - 8)
#define CAL_COL_SURFACE ugui_color_hex(0x1E2233u) /* card surface / bg */
#define CAL_COL_HEADERBG ugui_color_hex(0x161A28u) /* header strip fill */
#define CAL_COL_AMBER ugui_color_hex(0xFFB000u) /* header text + arrows + selection + border */
#define CAL_COL_WEEKDAY ugui_color_hex(0x7A88A8u) /* weekday labels */
#define CAL_COL_DAY ugui_color_hex(0xE6E9F0u) /* normal day text */
#define CAL_COL_SELTEXT ugui_color_hex(0x161A28u) /* dark on amber */
#define CAL_COL_TODAY ugui_color_hex(0x35D07Fu) /* today marker (green) */
#define CAL_COL_FOCUS ugui_color_hex(0x3B4A78u) /* keypad-focus fill */
#endif
/* --- local helpers & event callbacks --- */
static void on_select(uint16_t year, uint8_t month, uint8_t day, void* ctx)
{
(void)ctx;
#ifdef UGUI_ENABLE_FONT
(void)snprintf(s_readout_str, sizeof(s_readout_str), "%04u-%02u-%02u",
(unsigned)year, (unsigned)month, (unsigned)day);
ugui_widget_invalidate(&s_readout);
#else
(void)year; (void)month; (void)day;
#endif
printf("[calendar.cfg] pick %04u-%02u-%02u\n",
(unsigned)year, (unsigned)month, (unsigned)day);
}
/* --- build it (in your screen's init) --- */
ugui_widget_calendar_init(&s_root, &s_cal, &s_cal_ext);
ugui_widget_set_area(&s_cal, CAL_X, CAL_Y, (int16_t)CAL_W, (int16_t)CAL_H);
ugui_widget_set_id(&s_cal, WDGT_ID_DEMO);
#ifdef UGUI_ENABLE_FONT
ugui_widget_calendar_set_font(&s_cal, &lexend_14pt_2bpp);
#endif
/* Custom colours for every element (one call, order = header .. border). */
ugui_widget_calendar_set_theme(&s_cal,
CAL_COL_SURFACE, /* bg */
CAL_COL_HEADERBG, /* header bg */
CAL_COL_AMBER, /* header text + arrows */
CAL_COL_WEEKDAY, /* weekday */
CAL_COL_DAY, /* day */
CAL_COL_AMBER, /* selection fill */
CAL_COL_SELTEXT, /* selected-day text */
CAL_COL_TODAY, /* today */
CAL_COL_FOCUS, /* keypad focus fill */
CAL_COL_AMBER); /* border */
ugui_widget_calendar_set_week_start(&s_cal, 0u); /* Sunday-first */
ugui_widget_calendar_set_year_range(&s_cal, 2020u, 2030u); /* clamp arrows */
ugui_widget_calendar_set_today(&s_cal, 2026u, 6u, 14u); /* green marker */
ugui_widget_calendar_set_date(&s_cal, 2026u, 6u, 20u); /* pre-selected */
ugui_widget_calendar_set_on_select(&s_cal, on_select, NULL);
ugui_screen_add_widget(&s_screen, &s_cal);
#if UGUI_ENABLE_KEYPAD
ugui_screen_add_focus(&s_screen, &s_cal);
#endif
Modal Date Picker¶
The realistic case: tapping a date field calls ugui_widget_calendar_open() — a full-screen dim overlay absorbs off-panel taps and the calendar floats on top (the same modal mechanism the message box uses). Picking a day writes the date back into the field and auto-closes; the ✕ (or CANCEL) dismisses without changing anything.

/* --- 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
};
/* --- 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_CALENDAR)
static ugui_screen_t s_screen;
static ugui_widget_t s_root;
static char s_field_buf[20] = "tap to set";
static ugui_widget_t s_field;
static ugui_widget_t s_overlay;
static ugui_box_ext_t s_overlay_ext;
static ugui_widget_t s_cal;
static ugui_calendar_ext_t s_cal_ext;
#define POP_W 232
#define POP_H 196
#define POP_X ((UGUI_SCREEN_W - POP_W) / 2)
#define POP_Y ((UGUI_SCREEN_H - POP_H) / 2)
#endif
/* --- local helpers & event callbacks --- */
static void on_select(uint16_t year, uint8_t month, uint8_t day, void* ctx)
{
(void)ctx;
#ifdef UGUI_ENABLE_FONT
(void)snprintf(s_field_buf, sizeof(s_field_buf), "%04u-%02u-%02u",
(unsigned)year, (unsigned)month, (unsigned)day);
ugui_widget_invalidate(&s_field);
#else
(void)year; (void)month; (void)day;
#endif
printf("[calendar.popup] pick %04u-%02u-%02u\n",
(unsigned)year, (unsigned)month, (unsigned)day);
}
/* --- build it (in your screen's init) --- */
ugui_widget_box_init(&s_root, &s_overlay, &s_overlay_ext);
ugui_widget_set_area(&s_overlay, 0, 0,
(int16_t)UGUI_SCREEN_W, (int16_t)UGUI_SCREEN_H);
ugui_widget_box_set_style(&s_overlay, true, 0u, 0u,
ugui_color_hex(0x0A0A14u), ugui_color_hex(0x0A0A14u));
ugui_widget_set_visible(&s_overlay, false);
ugui_screen_add_widget(&s_screen, &s_overlay);
ugui_widget_calendar_init(&s_root, &s_cal, &s_cal_ext);
ugui_widget_set_area(&s_cal, POP_X, POP_Y, POP_W, POP_H);
ugui_widget_set_id(&s_cal, WDGT_ID_SLOT0);
#ifdef UGUI_ENABLE_FONT
ugui_widget_calendar_set_font(&s_cal, &lexend_14pt_2bpp);
#endif
ugui_widget_calendar_set_today(&s_cal, 2026u, 6u, 14u);
ugui_widget_calendar_set_date(&s_cal, 2026u, 6u, 14u);
ugui_widget_calendar_set_on_select(&s_cal, on_select, NULL);
ugui_widget_calendar_set_close_button(&s_cal, true, NULL); /* ✕ dismisses */
ugui_widget_set_visible(&s_cal, false);
ugui_screen_add_widget(&s_screen, &s_cal);
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.