Skip to content

Getting Started

This page takes you from nothing to a widget on your screen, in four steps. You don't need to know anything about μGui yet — every piece of code is copy-paste, and each step tells you exactly where to paste it.

The whole journey:

  1. Get the library and add it to your project.
  2. Copy the Application Skeleton — a complete, working main.c.
  3. Connect your display — fill in two small functions.
  4. Add your first widget — copy it from any widget page.

Once you've done this once, building every future screen is just step 4 again, with a different widget.


Step 1 — Get the library

Get μGui on GitHub

μGui ships as prebuilt packages, one per target. In the repository, pick the folder that matches your hardware — M0, M4, M7, RISC, ESP32S3, or Host for the PC simulator — then your colour format (RGB565 / ARGB8888), input model and display method. Each configuration folder is a complete, ready-to-build package:

In the package What it is
inc/ All μGui headers, plus the fonts, icons and images used across this site — the widget-page examples work out of the box.
src/libugui.a The library itself, prebuilt for that target and configuration.
main.c The Application Skeleton from step 2, already in place.
CMakeLists.txt A working build — link libugui.a and go.

Wherever you build UI, one include brings in everything:

#include "ugui.h"   /* core + every widget + fonts/icons API — one include */

Step 2 — Copy the Application Skeleton

Every μGui application — from a single button to a full patient monitor — has the same shape. That shape is written down once, as one complete file: the Application Skeleton.

Go to the skeleton page, copy the whole skeleton into a new file in your project, and you have a compiling μGui app. Inside it you will find four clearly marked parts:

Part What it is
Storage File-scope variables for the screen and each widget. You declare them; the library never allocates memory — there is no heap, no malloc.
screen_init() The function where widgets get built. It's almost empty in the skeleton — your widgets go here in step 4.
The HAL Seven small functions that connect μGui to your hardware. Step 3 fills in the two that matter.
main() Bring-up plus the loop: read input, call ugui_task_execute(), repeat. Already written — you don't touch it.

Don't try to write this file yourself

The skeleton already handles the things that are easy to get wrong — init order, input injection, the render loop. Start from the copy, not from a blank file.


Step 3 — Connect your display (the HAL)

μGui never touches your hardware directly. Instead, it calls a handful of small functions that you write — the HAL. The skeleton contains all of them as empty stubs, and only two need real code before you see pixels:

Function What you write in it
ugui_hal_flush_buffer() Send the strip of finished pixels μGui hands you to your panel — usually a SPI/8080 window-set followed by a (DMA) pixel write.
ugui_hal_get_tick_ms() Return your board's millisecond counter (e.g. from SysTick). μGui uses it for animations and press-and-hold timing.

The rest (init, deinit, debug print, …) can stay empty until you need them. If you forget one entirely, the build fails at link time — so nothing can go missing silently.

Different display setups

The default drawing mode renders through one small line buffer — the lowest-RAM option, right for most SPI panels. If your hardware has framebuffers or hardware layers, the skeleton lists the bring-up for all seven display modes — only two lines change.


Step 4 — Add your first widget

Every page in the Widget Catalog shows complete, copy-paste examples next to the exact frame they render. Adding a widget to your skeleton is always the same two pastes.

Using the Button as the example:

Paste 1 — the storage, at file scope, next to the skeleton's s_screen and s_root:

static ugui_widget_t      s_demo_btn;
static ugui_button_ext_t  s_demo_btn_ext;

Paste 2 — the build calls, inside screen_init(), where the skeleton says /* --- your widgets go here --- */:

ugui_widget_button_init(&s_root, &s_demo_btn, &s_demo_btn_ext);
ugui_screen_add_widget(&s_screen, &s_demo_btn);

Build and run. A themed, rounded, centred button appears — no colors, sizes or positions needed, because *_init() applies good defaults for everything. Every setter you see on the widget pages (set_text, set_area, set_style, …) is an optional refinement on top.

Want the button to say something and react to taps? The Button page's second example adds a caption and a click callback — copy it the same way. And that's the entire workflow for all 35 widget families.


Three rules that explain everything

If you remember only three things about μGui, make them these:

  1. A widget is two structs, and you own both. The generic ugui_widget_t plus a small per-family _ext struct (ugui_button_ext_t, ugui_slider_ext_t, …), declared at file scope. The library never allocates — your RAM budget is known at link time.
  2. *_init() already looks right. Every widget comes out themed, sized and anti-aliased. Style setters are opt-in, which is why the examples are so short.
  3. Register every widget. ugui_screen_add_widget() after every *_init() — a widget that isn't registered is never drawn and never receives touch. If something doesn't show up, check this first.

More gotchas (frozen animations, unresponsive touch) are collected in the skeleton's Things people miss.


Where to next

  • Application Skeleton — the file from step 2, with display-mode bring-ups, widget IDs and multi-screen apps explained.
  • Widget Catalog — all documented families, each with screenshots and complete copy-paste examples.
  • Examples — four complete products (patient monitor, automotive cluster, coffee machine, smart home) built from the same widgets you just used.
  • Tools — the designer, font and image pipeline that ship alongside the library.