From 8d2793e9ef7cf7f742ec23e77c44ac21a624d01f Mon Sep 17 00:00:00 2001 From: iamcheeseman Date: Wed, 13 May 2026 21:24:21 -0400 Subject: start ui --- teensy/teensy_ui.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 teensy/teensy_ui.c (limited to 'teensy/teensy_ui.c') diff --git a/teensy/teensy_ui.c b/teensy/teensy_ui.c new file mode 100644 index 0000000..af3e78f --- /dev/null +++ b/teensy/teensy_ui.c @@ -0,0 +1,277 @@ +#include "teensy_ui.h" + +#include + +#include "teensy_list.h" + +#define TITLE_BAR_HEIGHT (8) +#define TEXT_HEIGHT (8) + +enum { + CMD_RECT, + CMD_TEXT, + CMD_TARGET, + CMD_IMAGE, +}; +typedef uint8_t Cmd_Kind; + +typedef struct { + const char *text; + ty_Recti rect; + ty_Color color; + const ty_Image *img; + Cmd_Kind kind; +} Cmd; + +typedef struct { + const char *title; + ty_Recti rect; + ty_Image content; + uint32_t flags; + + ty_Vec2i next_pos; +} Window; + +typedef struct { + Window *active; + Window root; + Window windows[255]; + int window_count; + tyui_Style style; + const ty_Font *font; + Cmd *cmds; + + ty_Vec2i prev_mouse_pos; +} Ctx; + +static +tyui_Style default_style = { + .fg_normal = ty_color(200, 200, 200), + .bg_normal = ty_color(64, 64, 64), + .fg_hover = ty_color(255, 255, 255), + .bg_hover = ty_color(100, 100, 100), + .win_bg = ty_color(48, 48, 48), + .win_title = ty_color(64, 128, 128), +}; + +static +Ctx uictx; + +static +void rect_cmd(ty_Recti rect, ty_Color color) +{ + Cmd cmd = {}; + cmd.kind = CMD_RECT; + cmd.rect = rect; + cmd.color = color; + + ty_list_append(uictx.cmds, cmd); +} + +static +void text_cmd(const char *text, ty_Vec2i pos) +{ + Cmd cmd = {}; + cmd.kind = CMD_TEXT; + cmd.text = text; + cmd.rect.x = pos.x; + cmd.rect.y = pos.y; + + ty_list_append(uictx.cmds, cmd); +} + +static +void image_cmd(const ty_Image *img, ty_Vec2i pos) +{ + Cmd cmd = {}; + cmd.kind = CMD_IMAGE; + cmd.img = img; + cmd.rect.x = pos.x; + cmd.rect.y = pos.y; + ty_list_append(uictx.cmds, cmd); +} + +static +void target_cmd(const ty_Image *target) +{ + Cmd cmd = {}; + cmd.kind = CMD_TARGET; + cmd.img = target; + ty_list_append(uictx.cmds, cmd); +} + +static +ty_Vec2i next_pos(int height) +{ + ty_Vec2i next = uictx.active->next_pos; + uictx.active->next_pos.y += height; + return next; +} + +static +ty_Vec2i mouse_delta(void) +{ + ty_Vec2i cur = ty_mouse_pos(); + return ty_vec2i( + cur.x - uictx.prev_mouse_pos.x, + cur.y - uictx.prev_mouse_pos.y + ); +} + +static +Window create_window(const char *title, ty_Recti rect, uint32_t flags) +{ + Window win = {}; + win.title = title; + win.rect = rect; + win.flags = flags; + win.content = ty_create_image(rect.w, rect.h, NULL); + return win; +} + +void tyui_init(const ty_Font *font) +{ + assert(font); + + uictx.cmds = ty_list_create(); + ty_list_reserve(uictx.cmds, 256); + + uint32_t root_flags = 0; + root_flags |= TYUI_WIN_NORESIZE; + root_flags |= TYUI_WIN_NOCLOSE; + root_flags |= TYUI_WIN_NOMOVE; + root_flags |= TYUI_WIN_INVISIBLE; + + uictx.root = create_window( + "__ROOT__", + ty_recti(0, 0, 256, 256), + root_flags + ); + + uictx.style = default_style; + uictx.font = font; + + uictx.active = &uictx.root; +} + +void tyui_deinit(void) +{ + ty_list_free(uictx.cmds); + + ty_free_image(uictx.root.content); + for (int i = 0; i < uictx.window_count; i++) { + ty_free_image(uictx.windows[i].content); + } +} + +void tyui_draw(void) +{ + for (size_t i = 0; i < ty_list_len(uictx.cmds); i++) { + Cmd cmd = uictx.cmds[i]; + switch (cmd.kind) { + case CMD_RECT: + ty_draw_rect(cmd.rect, cmd.color); + break; + case CMD_TEXT: + ty_draw_text(uictx.font, ty_recti_start(cmd.rect), cmd.text); + break; + case CMD_IMAGE: + ty_draw_image(*cmd.img, ty_recti_start(cmd.rect)); + break; + case CMD_TARGET: + ty_draw_set_target(cmd.img); + if (cmd.img != NULL) ty_draw_clear(TY_COLOR_MAGENTA); + break; + } + } + ty_list_clear(uictx.cmds); + + uictx.prev_mouse_pos = ty_mouse_pos(); +} + +bool tyui_begin_window_ex( + const char *title, + ty_Recti rect, + tyui_Id *id, + uint32_t flags, + bool *closed_ptr +) { + assert(id); + + bool closed = false; + + if (closed_ptr) + closed = *closed_ptr; + + if (uictx.active != &uictx.root) { + ty_log_err("cannot create window within another window"); + return false; + } + + if (closed) + return !closed; + + if (*id == 0) { + *id = ++uictx.window_count; + uictx.windows[*id - 1] = create_window(title, rect, flags); + } + + Window *win = &uictx.windows[*id - 1]; + uictx.active = win; + + win->next_pos = ty_vec2i(0, 0); + + if (win->flags & TYUI_WIN_INVISIBLE) + goto done; + + ty_Recti title_rect = win->rect; + title_rect.h = TEXT_HEIGHT; + + ty_Vec2i mouse_pos = ty_mouse_pos(); + ty_Vec2i md = mouse_delta(); + mouse_pos.x -= md.x; + mouse_pos.y -= md.y; + + if (ty_button_down(TY_BTN_DB_LMB) && + ty_pointi_in_recti(mouse_pos, title_rect) + ) { + ty_Vec2i md = mouse_delta(); + win->rect.x += md.x; + win->rect.y += md.y; + + title_rect = win->rect; + title_rect.h = TEXT_HEIGHT; + } + + rect_cmd(title_rect, uictx.style.win_title); + text_cmd(win->title, ty_recti_start(title_rect)); + + ty_Recti body_rect = win->rect; + body_rect.y += TEXT_HEIGHT; + rect_cmd(body_rect, uictx.style.win_bg); + + target_cmd(&win->content); + +done: + return !closed; +} + +void tyui_end_window(void) +{ + if (uictx.active == &uictx.root) { + ty_log_err("ending window with no window open"); + return; + } + + target_cmd(NULL); + ty_Vec2i content_pos = ty_recti_start(uictx.active->rect); + content_pos.y += TITLE_BAR_HEIGHT; + image_cmd(&uictx.active->content, content_pos); + + uictx.active = &uictx.root; +} + +void tyui_text(const char *text) +{ + text_cmd(text, next_pos(TEXT_HEIGHT)); +} -- cgit v1.3-2-g0d8e