summaryrefslogtreecommitdiff
path: root/sources/iui.c
diff options
context:
space:
mode:
Diffstat (limited to 'sources/iui.c')
-rw-r--r--sources/iui.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/sources/iui.c b/sources/iui.c
new file mode 100644
index 0000000..6f82ad1
--- /dev/null
+++ b/sources/iui.c
@@ -0,0 +1,300 @@
+/*
+ * 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;
+
+ 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);