diff options
Diffstat (limited to 'sources/iui.c')
-rw-r--r-- | sources/iui.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/sources/iui.c b/sources/iui.c new file mode 100644 index 0000000..4e656c6 --- /dev/null +++ b/sources/iui.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2025 dwlr <dweller@cabin.digital> + * + * BSD 3-Clause License (BSD-3-Clause) + * See LICENSE for details + */ + + +#define IUI_TXT_CENTER bit(0) +#define IUI_CLIP_CLEAR bit(0) + +typedef struct +{ + enum + { + IUI_ILL, + IUI_BOX, + IUI_FILL, + IUI_LINE, + IUI_TEXT, + IUI_CLIP, + + } type; + + u32 color; + u16 x, y, w, h; + u16 size; + u16 flags; + char* text; + +} iui_cmd; + +#define IUI_CMDBUF_LEN 512 +typedef struct +{ + arena* ar; + void* usr; + + usize hot; + usize active; + usize kbdfocus; + + /* mouse */ + u16 x; + u16 y; + + u8 pbtns; + u8 btns; + + /* TODO: event pump */ + + usize ncmds; + iui_cmd cmds[IUI_CMDBUF_LEN]; /* TODO: arena? */ + +} iui; + + +void iui_init(iui* ui, arena* ar, void* usr) +{ + if(!ui) + { + report(WARN, "iui: iui_init() ui == NULL!\n"); + return; + } + + ui->ar = ar; + ui->usr = usr; +} + +void iui_start(iui* ui) +{ + assert(ui); + ui->hot = 0; + + ar_clear(ui->ar); +} + +void iui_end(iui* ui) +{ + assert(ui); + + if(!ui->btns) ui->active = 0; + else if(!ui->active) ui->kbdfocus = 0; + + ui->pbtns = ui->btns; +} + +bool iui_mouse_inside(iui* ui, u16 x, u16 y, u16 w, u16 h) +{ + return !(ui->x < x || ui->y < y || ui->x >= x + w || ui->y >= y + h); +} + +int iui_button(iui* ui, u16 x, u16 y, int w, int h, char* label) +{ + xctx* x11 = (xctx*)ui->usr; + usize id = (usize)label; + bool imhot, imactive; + + if(iui_mouse_inside(ui, x, y, w, h)) + { + bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1)); + if(!ui->active && click) ui->active = id; + ui->hot = id; + } + + imhot = ui->hot == id; + imactive = ui->active == id; + + { + iui_cmd cmd = {0}; + cmd.type = IUI_FILL; + + cmd.x = x; + cmd.y = y; + cmd.w = w; + cmd.h = h; + + if(imhot) cmd.size = 2; + else cmd.size = 1; + + if(imactive) cmd.color = x11->cols.as.fg; + else cmd.color = x11->cols.as.bg; + + ui->cmds[ui->ncmds++] = cmd; + + cmd.type = IUI_BOX; + cmd.color = x11->cols.as.fg; + ui->cmds[ui->ncmds++] = cmd; + + cmd.type = IUI_TEXT; + cmd.size = 14; + cmd.text = label; + cmd.flags = IUI_TXT_CENTER; + + if(imactive) cmd.color = x11->cols.as.bg; + else cmd.color = x11->cols.as.fg; + + ui->cmds[ui->ncmds++] = cmd; + } + + return imhot && imactive && !(ui->btns & bit(1)); +} + +void iui_label(iui* ui, u16 x, u16 y, int w, int h, char* fmt, ...) +{ + int len = 0; + char* buf = NULL; + va_list ap = {0}; + xctx* x11 = (xctx*)ui->usr; + + + va_start(ap, fmt); + len = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if(len) len++; + buf = ar_push(ui->ar, len); + + va_start(ap, fmt); + len = vsnprintf(buf, len, fmt, ap); + va_end(ap); + + { + iui_cmd cmd = {0}; + cmd.type = IUI_FILL; + + cmd.x = x; + cmd.y = y; + cmd.w = w; + cmd.h = h; + + { + iui_cmd clip = cmd; + clip.type = IUI_CLIP; + clip.flags = 0; + clip.x++; + clip.y++; + clip.w--; + clip.h--; + + ui->cmds[ui->ncmds++] = clip; + } + + { + cmd.type = IUI_TEXT; + cmd.size = 14; + cmd.text = buf; + cmd.flags = 0; + + cmd.x = x + 6; + cmd.y = y; + cmd.w = w; + cmd.h = h; + + cmd.color = x11->cols.as.fg; + + ui->cmds[ui->ncmds++] = cmd; + } + + cmd.type = IUI_CLIP; + cmd.flags = IUI_CLIP_CLEAR; + ui->cmds[ui->ncmds++] = cmd; + } +} + +int iui_editbox(iui* ui, u16 x, u16 y, int w, int h, char* buf, usize buflen) +{ + xctx* x11 = (xctx*)ui->usr; + usize id = (usize)buf; + bool imhot, imactive; + usize len; + + len = strlen(buf); + + if(iui_mouse_inside(ui, x, y, w, h)) + { + bool click = ui->btns & bit(1) && !(ui->pbtns & bit(1)); + if(!ui->active && click) ui->active = id; + ui->hot = id; + } + + imhot = ui->hot == id; + imactive = ui->active == id; + + { + iui_cmd cmd = {0}; + cmd.type = IUI_FILL; + + cmd.x = x; + cmd.y = y; + cmd.w = w; + cmd.h = h; + + if(imhot) cmd.size = 2; + else cmd.size = 1; + + cmd.color = x11->cols.as.bg; + ui->cmds[ui->ncmds++] = cmd; + + cmd.type = IUI_BOX; + cmd.color = x11->cols.as.fg; + ui->cmds[ui->ncmds++] = cmd; + + { + iui_cmd clip = cmd; + clip.type = IUI_CLIP; + clip.flags = 0; + clip.x++; + clip.y++; + clip.w--; + clip.h--; + + ui->cmds[ui->ncmds++] = clip; + } + + if(imactive) ui->kbdfocus = id; + if(ui->kbdfocus == id) + { + cmd.type = IUI_FILL; + cmd.x = x + 6 + 6 * len; + cmd.y = y + 6; + cmd.w = 10; + cmd.h = h - 12; + cmd.color = x11->cols.as.fg; + + ui->cmds[ui->ncmds++] = cmd; + } + else + { + cmd.type = IUI_BOX; + cmd.x = x + 6 + 6 * len; + cmd.y = y + 6; + cmd.w = 9; + cmd.h = h - 13; + cmd.color = x11->cols.as.fg; + cmd.size = 1; + + ui->cmds[ui->ncmds++] = cmd; + } + + { + cmd.type = IUI_TEXT; + cmd.size = 14; + cmd.text = buf; + cmd.flags = 0; + + cmd.x = x + 6; + cmd.y = y; + cmd.w = w; + cmd.h = h; + + cmd.color = x11->cols.as.fg; + + ui->cmds[ui->ncmds++] = cmd; + } + + cmd.type = IUI_CLIP; + cmd.flags = IUI_CLIP_CLEAR; + ui->cmds[ui->ncmds++] = cmd; + } + + return imhot && imactive && !(ui->btns & bit(1)); +} + + +void iui_draw(iui* ui); |