/* * Copyright (C) 2025 dwlr * * 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; buf = ar_push(ui->ar, 512); va_start(ap, fmt); len = vsnprintf(buf, 511, 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);