Skip to content

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().

Default Calendar

/* --- 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.

Custom Theme & Configuration

/* --- 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

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.

Modal Date Picker

/* --- 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.