Skip to content

0xAnto/lighTUI

Repository files navigation

lightui

A terminal UI library in C11. No external dependencies. No dynamic memory allocation. Single write() per frame.

Runs on Linux, macOS, BSDs, and embedded Linux (Raspberry Pi and smaller).

Build

make          # builds liblightui.a
make test     # runs all tests
make examples # builds examples/hello and examples/sysmon

Requires a C11 compiler (gcc or clang) and POSIX.

Usage

Provide your own buffers. lightui allocates nothing.

#include "lightui.h"

static lightui_cell_t front[220 * 50], back[220 * 50];
static uint8_t        wbuf[LIGHTUI_WRITE_BUF_MIN(220, 50)];
static lightui_event_t evq[64];

int main(void) {
    lightui_config_t cfg = {
        .cells_front      = front,
        .cells_back       = back,
        .width            = 220,
        .height           = 50,
        .write_buf        = wbuf,
        .write_buf_size   = sizeof(wbuf),
        .event_queue      = evq,
        .event_queue_size = 64,
        .esc_timeout_ms   = 50,
    };

    lightui_t ctx;
    if (lightui_init(&ctx, &cfg) != LIGHTUI_OK) return 1;

    lightui_event_t ev;
    while (lightui_wait_event(&ctx, &ev, -1)) {
        lightui_clear_back_buffer(&ctx);
        lightui_canvas_t cv; lightui_canvas_fullscreen(&cv, &ctx);

        lightui_draw_box(&cv, (lightui_rect_t){2, 1, 30, 5}, LIGHTUI_BOX_ROUNDED);
        lightui_draw_text(&cv, 4, 2, "hello", LIGHTUI_STYLE_DEFAULT);
        lightui_flush(&ctx);

        if (ev.type == LIGHTUI_EVENT_KEY && ev.key.codepoint == 'q') break;
        if (ev.type == LIGHTUI_EVENT_SIGNAL) break;
    }

    lightui_shutdown(&ctx);
}

API

Init / shutdown

lightui_result_t lightui_init    (lightui_t *ctx, const lightui_config_t *cfg);
void             lightui_shutdown(lightui_t *ctx);
uint16_t         lightui_cols    (const lightui_t *ctx);
uint16_t         lightui_rows    (const lightui_t *ctx);

Frame loop

void lightui_clear_back_buffer(lightui_t *ctx);
void lightui_flush            (lightui_t *ctx);
bool lightui_poll_event       (lightui_t *ctx, lightui_event_t *ev);
bool lightui_wait_event       (lightui_t *ctx, lightui_event_t *ev, int timeout_ms);

Drawing

void lightui_canvas_fullscreen(lightui_canvas_t *c, lightui_t *ctx);
void lightui_canvas_clip      (lightui_canvas_t *c, lightui_t *ctx, lightui_rect_t r);
void lightui_draw_text        (lightui_canvas_t *c, int16_t x, int16_t y, const char *s, lightui_style_t style);
void lightui_draw_box         (lightui_canvas_t *c, lightui_rect_t r, lightui_box_style_t style);
void lightui_fill             (lightui_canvas_t *c, lightui_rect_t r, uint32_t cp, lightui_style_t style);
void lightui_draw_hline       (lightui_canvas_t *c, int16_t x, int16_t y, int16_t len, lightui_style_t style);
void lightui_draw_vline       (lightui_canvas_t *c, int16_t x, int16_t y, int16_t len, lightui_style_t style);

Plugins

lightui_result_t lightui_plugin_register(lightui_t *ctx, const lightui_plugin_t *plugin);
typedef struct {
    const char *name;
    uint32_t    version;
    void (*init)     (lightui_t *ctx, const lightui_allocator_t *alloc, void **state);
    void (*destroy)  (lightui_t *ctx, void *state);
    void (*render)   (lightui_t *ctx, lightui_canvas_t *canvas, void *state);
    bool (*on_event) (lightui_t *ctx, const lightui_event_t *ev, void *state);
    void (*on_resize)(lightui_t *ctx, uint16_t cols, uint16_t rows, void *state);
} lightui_plugin_t;

Plugins registered first get highest event priority and render at the bottom layer. The app renders on top.

Events

// ev.type is one of:
LIGHTUI_EVENT_KEY     // ev.key.codepoint, ev.key.mods
LIGHTUI_EVENT_MOUSE   // ev.mouse.x, .y, .btn, .mods, .kind
LIGHTUI_EVENT_RESIZE  // ev.resize.cols, ev.resize.rows
LIGHTUI_EVENT_SIGNAL  // ev.signal.signum

Mouse reporting uses xterm SGR protocol (ESC[<...M). Coordinates are 0-based.

Constraints

  • One active lightui_t per process (signal pipe is process-global).
  • Buffer dimensions are fixed at init time. lightui_cols()/lightui_rows() return init-time values; live terminal size comes via LIGHTUI_EVENT_RESIZE.
  • Maximum 256 rows (LIGHTUI_MAX_ROWS), 512 columns (LIGHTUI_MAX_COLS).

About

C11 terminal UI library — zero deps, zero malloc, single write() per frame. POSIX only.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors