#include <u.h>#include <libc.h>#include <draw.h>#include <microui.h> #define MU_REAL_FMT "%g"#define MU_SLIDER_FMT "%.2f" #define MIN(a, b) ((a) < (b) ? (a) : (b))#define MAX(a, b) ((a) > (b) ? (a) : (b))#define CLAMP(x, a, b) MIN(b, MAX(a, x)) static mu_Rect unclipped_rect = { 0, 0, 0x1000000, 0x1000000 }; static u8int atlasraw[] = { 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x38, 0x67, 0x38, 0x62, 0x38, 0x61, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x33, 0x39, 0x20, 0x80, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x34, 0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x13, 0x7c, 0x00, 0x3c, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0x04, 0x07, 0x44, 0x1f, 0x80, 0x5e, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x70, 0x00, 0x00, 0x34, 0x1b, 0x04, 0x13, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x17, 0x7c, 0x00, 0x2c, 0x00, 0x80, 0x21, 0x00, 0x00, 0x80, 0xe0, 0x00, 0x00, 0x80, 0xea, 0x00, 0x00, 0x80, 0x2c, 0x00, 0x00, 0x54, 0x27, 0x14, 0x6f, 0x24, 0x8b, 0x44, 0x13, 0x14, 0x00, 0x7c, 0x00, 0x4c, 0x83, 0x80, 0x2d, 0x00, 0x00, 0x74, 0x2f, 0x24, 0x77, 0x74, 0x83, 0x7c, 0x00, 0x1c, 0x83, 0x80, 0xe1, 0x00, 0x00, 0x80, 0xeb, 0x00, 0x00, 0x7c, 0x83, 0x3c, 0x8b, 0x74, 0x83, 0x24, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x83, 0x7c, 0x87, 0x3c, 0x00, 0x14, 0x00, 0x80, 0x3d, 0x00, 0x00, 0x80, 0xed, 0x00, 0x00, 0x80, 0x45, 0x00, 0x00, 0x24, 0x17, 0x80, 0x22, 0x00, 0x00, 0x7c, 0x83, 0x7d, 0x97, 0x75, 0x97, 0x14, 0x00, 0x80, 0x13, 0x00, 0x00, 0x80, 0xd0, 0x00, 0x00, 0x80, 0xf6, 0x00, 0x00, 0x14, 0x8b, 0x24, 0x83, 0x80, 0x2e, 0x00, 0x00, 0x7c, 0x79, 0x7e, 0xa7, 0x54, 0x8b, 0x54, 0x8b, 0x80, 0x63, 0x00, 0x00, 0x7c, 0x83, 0x4c, 0x00, 0x7f, 0xb7, 0x3f, 0xb7, 0x54, 0x8b, 0x04, 0x2b, 0x80, 0xec, 0x00, 0x00, 0x7c, 0x83, 0x3c, 0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x13, 0x54, 0x8b, 0x80, 0xbc, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x00, 0x7c, 0x00, 0x0c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x5a, 0x00, 0x00, 0x06, 0x6b, 0x14, 0x07, 0x80, 0x8f, 0x00, 0x00, 0x44, 0x27, 0x7c, 0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x3c, 0x00, 0x00, 0x80, 0xaa, 0x00, 0x00, 0x04, 0x07, 0x04, 0x83, 0x54, 0x8b, 0x44, 0x17, 0x14, 0x2f, 0x7c, 0x65, 0x7c, 0x00, 0x34, 0x00, 0x54, 0x8b, 0x34, 0x17, 0x64, 0xb3, 0x7c, 0x00, 0x0c, 0x00, 0x80, 0x6e, 0x00, 0x00, 0x05, 0x03, 0x35, 0x0f, 0x64, 0x8b, 0x34, 0x17, 0x7c, 0x83, 0x7c, 0x00, 0x80, 0xa5, 0x00, 0x00, 0x15, 0x4f, 0x26, 0x1f, 0x64, 0x83, 0x74, 0xa3, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x63, 0x81, 0x00, 0x00, 0x34, 0x27, 0x7c, 0x4d, 0x4c, 0x00, 0x80, 0x55, 0x00, 0x00, 0x80, 0x37, 0x00, 0x00, 0x04, 0x0b, 0x04, 0x07, 0x04, 0x0f, 0x04, 0x0b, 0x80, 0x1e, 0x00, 0x00, 0x04, 0x0b, 0x04, 0x07, 0x64, 0x83, 0x7c, 0x00, 0x7c, 0x00, 0x16, 0xef, 0x05, 0x8f, 0x75, 0x97, 0x54, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x0f, 0x0d, 0x0f, 0x64, 0x3f,}; static mu_Rect default_atlas_icons[] = { [MU_ICON_CHECK] = {0, 0, 18, 18}, [MU_ICON_CLOSE] = {18, 0, 16, 16}, [MU_ICON_COLLAPSED] = {27, 16, 5, 7}, [MU_ICON_EXPANDED] = {0, 18, 7, 5}, [MU_ICON_RESIZE] = {18, 16, 9, 9}, [ATLAS_DIMENSIONS] = {0, 0, 34, 25},}; mu_Context mu_ctx;mu_Style mu_style = { .font = nil, .size = { 68, 10 }, .padding = 6, .spacing = 4, .indent = 24, .title_height = 26, .scrollbar_size = 12, .thumb_size = 8, .colors = {nil},}; Image *atlasimage = nil;mu_Rect *atlasicons = default_atlas_icons;u8int defaultcolors[MU_COLOR_MAX][4] = { [MU_COLOR_BG] = {119, 119, 119, 255}, [MU_COLOR_TEXT] = {230, 230, 230, 255}, [MU_COLOR_BORDER] = {25, 25, 25, 255}, [MU_COLOR_WINDOWBG] = {50, 50, 50, 255}, [MU_COLOR_TITLEBG] = {25, 25, 25, 255}, [MU_COLOR_TITLETEXT] = {240, 240, 240, 255}, [MU_COLOR_PANELBG] = {0, 0, 0, 0}, [MU_COLOR_BUTTON] = {75, 75, 75, 255}, [MU_COLOR_BUTTONHOVER] = {95, 95, 95, 255}, [MU_COLOR_BUTTONFOCUS] = {115, 115, 115, 255}, [MU_COLOR_BASE] = {30, 30, 30, 255}, [MU_COLOR_BASEHOVER] = {35, 35, 35, 255}, [MU_COLOR_BASEFOCUS] = {40, 40, 40, 255}, [MU_COLOR_SCROLLBASE] = {43, 43, 43, 255}, [MU_COLOR_SCROLLTHUMB] = {30, 30, 30, 255},}; static voidbuffer_grow(void **buf, int onesz, int *bufmax, int bufnum){ while (*bufmax <= bufnum) { *bufmax = MAX(16, *bufmax) * 2; if ((*buf = realloc(*buf, *bufmax*onesz)) == nil) sysfatal("not enough memory for %d items (%d bytes)", *bufmax, *bufmax*onesz); }} mu_Rectmu_rect(int x, int y, int w, int h){ mu_Rect res; res.x = x, res.y = y, res.w = w, res.h = h; return res;} Image *mu_color(u8int r, u8int g, u8int b, u8int a){ Image *c; if ((c = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, setalpha(r<<24 | g<<16 | b<<8, a))) == nil) sysfatal("couldn't allocate color"); return c;} static Rectanglescreenrect(mu_Rect r){ Rectangle rect; rect.min = screen->r.min; rect.min.x += r.x; rect.min.y += r.y; rect.max = rect.min; rect.max.x += r.w; rect.max.y += r.h; return rect;} static mu_Rectexpand_rect(mu_Rect rect, int n) { return mu_rect(rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2);} static mu_Rectclip_rect(mu_Rect r1, mu_Rect r2){ int x1 = MAX(r1.x, r2.x); int y1 = MAX(r1.y, r2.y); int x2 = MAX(MIN(r1.x + r1.w, r2.x + r2.w), x1); int y2 = MAX(MIN(r1.y + r1.h, r2.y + r2.h), y1); return mu_rect(x1, y1, x2 - x1, y2 - y1);} static intrect_overlaps_vec2(mu_Rect r, Point p){ return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h;} static voiddraw_frame(mu_Rect rect, int colorid){ mu_draw_rect(rect, mu_style.colors[colorid]); if (colorid == MU_COLOR_SCROLLBASE || colorid == MU_COLOR_SCROLLTHUMB || colorid == MU_COLOR_TITLEBG) return; /* draw border */ mu_draw_box(expand_rect(rect, 1), mu_style.colors[MU_COLOR_BORDER]);} static inttext_width(Font *font, const char *text, int len){ return stringnwidth(font, text, len >= 0 ? len : strlen(text));} voidmu_init(void){ Rectangle r; int res, i; if (atlasimage == nil) { r = Rect(0, 0, atlasicons[ATLAS_DIMENSIONS].w, atlasicons[ATLAS_DIMENSIONS].h); atlasimage = allocimage(display, r, RGBA32, 1, DTransparent); if (memcmp(atlasraw, "compressed\n", 11) == 0) res = cloadimage(atlasimage, r, atlasraw+11+5*12, sizeof(atlasraw)-11-5*12); else res = loadimage(atlasimage, r, atlasraw, sizeof(atlasraw)); if (res < 0) sysfatal("failed to load atlas: %r"); } if (mu_style.colors[0] == nil) { for (i = 0; i < MU_COLOR_MAX; i++) { mu_style.colors[i] = mu_color( defaultcolors[i][0], defaultcolors[i][1], defaultcolors[i][2], defaultcolors[i][3] ); } }} voidmu_begin(void){ mu_ctx.cmdsnum = mu_ctx.rootnum = 0; mu_ctx.strnum = 0; mu_ctx.scroll_target = nil; mu_ctx.last_hover_root = mu_ctx.hover_root; mu_ctx.hover_root = nil; mu_ctx.mouse_delta.x = mu_ctx.mouse_pos.x - mu_ctx.last_mouse_pos.x; mu_ctx.mouse_delta.y = mu_ctx.mouse_pos.y - mu_ctx.last_mouse_pos.y;} static intcompare_zindex(const void *a, const void *b){ return (*(mu_Container**)a)->zindex - (*(mu_Container**)b)->zindex;} voidmu_end(void){ int i, n; /* check stacks */ assert(mu_ctx.cntnum == 0); assert(mu_ctx.clipnum == 0); assert(mu_ctx.idsnum == 0); assert(mu_ctx.layoutsnum == 0); /* handle scroll input */ if (mu_ctx.scroll_target) { mu_ctx.scroll_target->scroll.x += mu_ctx.scroll_delta.x; mu_ctx.scroll_target->scroll.y += mu_ctx.scroll_delta.y; } /* unset focus if focus id was not touched this frame */ if (!mu_ctx.updated_focus) mu_ctx.focus = 0; mu_ctx.updated_focus = 0; /* bring hover root to front if mouse was pressed */ if (mu_ctx.mouse_pressed && mu_ctx.hover_root && mu_ctx.hover_root->zindex < mu_ctx.last_zindex) mu_bring_to_front(mu_ctx.hover_root); /* reset input state */ mu_ctx.key_pressed = 0; mu_ctx.text_input[0] = 0; mu_ctx.mouse_pressed = 0; mu_ctx.scroll_delta = ZP; mu_ctx.last_mouse_pos = mu_ctx.mouse_pos; /* sort root containers by zindex */ n = mu_ctx.rootnum; qsort(mu_ctx.root, n, sizeof(*mu_ctx.root), compare_zindex); /* set root container jump commands */ for (i = 0; i < n; i++) { mu_Container *cnt = mu_ctx.root[i]; /* if this is the first container then make the first command jump to it. ** otherwise set the previous container's tail to jump to this one */ if (i == 0) mu_ctx.cmds[0].jump.dst = cnt->head + 1; else mu_ctx.cmds[mu_ctx.root[i - 1]->tail].jump.dst = cnt->head + 1; /* make the last container's tail jump to the end of command list */ if (i == n - 1) mu_ctx.cmds[cnt->tail].jump.dst = mu_ctx.cmdsnum; }} voidmu_set_focus(mu_Id id){ mu_ctx.focus = id; mu_ctx.updated_focus = 1;} /* 32bit fnv-1a hash */#define HASH_INITIAL 2166136261U static voidhash(mu_Id *hash, const void *data, int size){ const unsigned char *p = data; while (size--) { *hash = (*hash ^ *p++) * 16777619; }} mu_Idmu_get_id(const void *data, int size){ int idx = mu_ctx.idsnum; mu_Id res = (idx > 0) ? mu_ctx.ids[idx - 1] : HASH_INITIAL; hash(&res, data, size); mu_ctx.last_id = res; return res;} voidmu_push_id(const void *data, int size){ buffer_grow(&mu_ctx.ids, sizeof(*mu_ctx.ids), &mu_ctx.idsmax, mu_ctx.idsnum); mu_ctx.ids[mu_ctx.idsnum++] = mu_get_id(data, size);} voidmu_pop_id(void){ mu_ctx.idsnum--;} voidmu_push_clip_rect(mu_Rect rect){ mu_Rect last = mu_get_clip_rect(); buffer_grow(&mu_ctx.clip, sizeof(*mu_ctx.clip), &mu_ctx.clipmax, mu_ctx.clipnum); mu_ctx.clip[mu_ctx.clipnum++] = clip_rect(rect, last);} voidmu_pop_clip_rect(void){ mu_ctx.clipnum--;} mu_Rectmu_get_clip_rect(void){ assert(mu_ctx.clipnum > 0); return mu_ctx.clip[mu_ctx.clipnum - 1];} intmu_check_clip(mu_Rect r){ mu_Rect cr = mu_get_clip_rect(); if (r.x > cr.x + cr.w || r.x + r.w < cr.x || r.y > cr.y + cr.h || r.y + r.h < cr.y) return MU_CLIP_ALL; if (r.x >= cr.x && r.x + r.w <= cr.x + cr.w && r.y >= cr.y && r.y + r.h <= cr.y + cr.h) return MU_CLIP_NONE; return MU_CLIP_PART;} static voidpush_layout(mu_Rect body, Point scroll){ mu_Layout layout; int width = 0; memset(&layout, 0, sizeof(mu_Layout)); layout.body = mu_rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h); layout.max = Pt(-0x1000000, -0x1000000); buffer_grow(&mu_ctx.layouts, sizeof(*mu_ctx.layouts), &mu_ctx.layoutsmax, mu_ctx.layoutsnum); mu_ctx.layouts[mu_ctx.layoutsnum++] = layout; mu_layout_row(1, &width, 0);} static mu_Layout *get_layout(void){ return &mu_ctx.layouts[mu_ctx.layoutsnum - 1];} static voidpush_container(mu_Container *cnt){ buffer_grow(&mu_ctx.cnt, sizeof(*mu_ctx.cnt), &mu_ctx.cntmax, mu_ctx.cntnum); mu_ctx.cnt[mu_ctx.cntnum++] = cnt; mu_push_id(&cnt, sizeof(mu_Container*));} static voidpop_container(void){ mu_Container *cnt = mu_get_container(); mu_Layout *layout = get_layout(); cnt->content_size.x = layout->max.x - layout->body.x; cnt->content_size.y = layout->max.y - layout->body.y; mu_ctx.cntnum--; mu_ctx.layoutsnum--; mu_pop_id();} mu_Container *mu_get_container(void){ assert(mu_ctx.cntnum > 0); return mu_ctx.cnt[mu_ctx.cntnum - 1];} voidmu_init_window(mu_Container *cnt, int opt){ memset(cnt, 0, sizeof(*cnt)); cnt->inited = 1; cnt->open = opt & MU_OPT_CLOSED ? 0 : 1; cnt->rect = mu_rect(100, 100, 300, 300); mu_bring_to_front(cnt);} voidmu_bring_to_front(mu_Container *cnt){ cnt->zindex = ++mu_ctx.last_zindex;} /*============================================================================** input handlers**============================================================================*/ voidmu_input_mousemove(int x, int y){ mu_ctx.mouse_pos = Pt(x, y);} voidmu_input_mousedown(int x, int y, int btn){ mu_input_mousemove(x, y); mu_ctx.mouse_down |= btn; mu_ctx.mouse_pressed |= btn;} voidmu_input_mouseup(int x, int y, int btn){ mu_input_mousemove(x, y); mu_ctx.mouse_down &= ~btn;} voidmu_input_scroll(int x, int y){ mu_ctx.scroll_delta.x += x; mu_ctx.scroll_delta.y += y;} voidmu_input_keydown(int key){ mu_ctx.key_pressed |= key; mu_ctx.key_down |= key;} voidmu_input_keyup(int key){ mu_ctx.key_down &= ~key;} voidmu_input_text(const char *text){ int len = strlen(mu_ctx.text_input); int size = strlen(text) + 1; assert(len + size <= (int) sizeof(mu_ctx.text_input)); memcpy(mu_ctx.text_input + len, text, size);} /*============================================================================** commandlist**============================================================================*/ mu_Command *mu_push_command(int type){ mu_Command *cmd; buffer_grow(&mu_ctx.cmds, sizeof(mu_Command), &mu_ctx.cmdsmax, mu_ctx.cmdsnum); cmd = &mu_ctx.cmds[mu_ctx.cmdsnum++]; memset(cmd, 0, sizeof(*cmd)); cmd->type = type; return cmd;} static intpush_jump(int dst){Lines 1–500 of 1503. Load more
#include <u.h> #include <libc.h> #include <draw.h> #include <microui.h> #define MU_REAL_FMT "%g" #define MU_SLIDER_FMT "%.2f" #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define CLAMP(x, a, b) MIN(b, MAX(a, x)) static mu_Rect unclipped_rect = { 0, 0, 0x1000000, 0x1000000 }; static u8int atlasraw[] = { 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x38, 0x67, 0x38, 0x62, 0x38, 0x61, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x33, 0x39, 0x20, 0x80, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x34, 0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x13, 0x7c, 0x00, 0x3c, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0x04, 0x07, 0x44, 0x1f, 0x80, 0x5e, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x70, 0x00, 0x00, 0x34, 0x1b, 0x04, 0x13, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x17, 0x7c, 0x00, 0x2c, 0x00, 0x80, 0x21, 0x00, 0x00, 0x80, 0xe0, 0x00, 0x00, 0x80, 0xea, 0x00, 0x00, 0x80, 0x2c, 0x00, 0x00, 0x54, 0x27, 0x14, 0x6f, 0x24, 0x8b, 0x44, 0x13, 0x14, 0x00, 0x7c, 0x00, 0x4c, 0x83, 0x80, 0x2d, 0x00, 0x00, 0x74, 0x2f, 0x24, 0x77, 0x74, 0x83, 0x7c, 0x00, 0x1c, 0x83, 0x80, 0xe1, 0x00, 0x00, 0x80, 0xeb, 0x00, 0x00, 0x7c, 0x83, 0x3c, 0x8b, 0x74, 0x83, 0x24, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x83, 0x7c, 0x87, 0x3c, 0x00, 0x14, 0x00, 0x80, 0x3d, 0x00, 0x00, 0x80, 0xed, 0x00, 0x00, 0x80, 0x45, 0x00, 0x00, 0x24, 0x17, 0x80, 0x22, 0x00, 0x00, 0x7c, 0x83, 0x7d, 0x97, 0x75, 0x97, 0x14, 0x00, 0x80, 0x13, 0x00, 0x00, 0x80, 0xd0, 0x00, 0x00, 0x80, 0xf6, 0x00, 0x00, 0x14, 0x8b, 0x24, 0x83, 0x80, 0x2e, 0x00, 0x00, 0x7c, 0x79, 0x7e, 0xa7, 0x54, 0x8b, 0x54, 0x8b, 0x80, 0x63, 0x00, 0x00, 0x7c, 0x83, 0x4c, 0x00, 0x7f, 0xb7, 0x3f, 0xb7, 0x54, 0x8b, 0x04, 0x2b, 0x80, 0xec, 0x00, 0x00, 0x7c, 0x83, 0x3c, 0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x13, 0x54, 0x8b, 0x80, 0xbc, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x00, 0x7c, 0x00, 0x0c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x5a, 0x00, 0x00, 0x06, 0x6b, 0x14, 0x07, 0x80, 0x8f, 0x00, 0x00, 0x44, 0x27, 0x7c, 0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x3c, 0x00, 0x00, 0x80, 0xaa, 0x00, 0x00, 0x04, 0x07, 0x04, 0x83, 0x54, 0x8b, 0x44, 0x17, 0x14, 0x2f, 0x7c, 0x65, 0x7c, 0x00, 0x34, 0x00, 0x54, 0x8b, 0x34, 0x17, 0x64, 0xb3, 0x7c, 0x00, 0x0c, 0x00, 0x80, 0x6e, 0x00, 0x00, 0x05, 0x03, 0x35, 0x0f, 0x64, 0x8b, 0x34, 0x17, 0x7c, 0x83, 0x7c, 0x00, 0x80, 0xa5, 0x00, 0x00, 0x15, 0x4f, 0x26, 0x1f, 0x64, 0x83, 0x74, 0xa3, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x63, 0x81, 0x00, 0x00, 0x34, 0x27, 0x7c, 0x4d, 0x4c, 0x00, 0x80, 0x55, 0x00, 0x00, 0x80, 0x37, 0x00, 0x00, 0x04, 0x0b, 0x04, 0x07, 0x04, 0x0f, 0x04, 0x0b, 0x80, 0x1e, 0x00, 0x00, 0x04, 0x0b, 0x04, 0x07, 0x64, 0x83, 0x7c, 0x00, 0x7c, 0x00, 0x16, 0xef, 0x05, 0x8f, 0x75, 0x97, 0x54, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x0f, 0x0d, 0x0f, 0x64, 0x3f, }; static mu_Rect default_atlas_icons[] = { [MU_ICON_CHECK] = {0, 0, 18, 18}, [MU_ICON_CLOSE] = {18, 0, 16, 16}, [MU_ICON_COLLAPSED] = {27, 16, 5, 7}, [MU_ICON_EXPANDED] = {0, 18, 7, 5}, [MU_ICON_RESIZE] = {18, 16, 9, 9}, [ATLAS_DIMENSIONS] = {0, 0, 34, 25}, }; mu_Context mu_ctx; mu_Style mu_style = { .font = nil, .size = { 68, 10 }, .padding = 6, .spacing = 4, .indent = 24, .title_height = 26, .scrollbar_size = 12, .thumb_size = 8, .colors = {nil}, }; Image *atlasimage = nil; mu_Rect *atlasicons = default_atlas_icons; u8int defaultcolors[MU_COLOR_MAX][4] = { [MU_COLOR_BG] = {119, 119, 119, 255}, [MU_COLOR_TEXT] = {230, 230, 230, 255}, [MU_COLOR_BORDER] = {25, 25, 25, 255}, [MU_COLOR_WINDOWBG] = {50, 50, 50, 255}, [MU_COLOR_TITLEBG] = {25, 25, 25, 255}, [MU_COLOR_TITLETEXT] = {240, 240, 240, 255}, [MU_COLOR_PANELBG] = {0, 0, 0, 0}, [MU_COLOR_BUTTON] = {75, 75, 75, 255}, [MU_COLOR_BUTTONHOVER] = {95, 95, 95, 255}, [MU_COLOR_BUTTONFOCUS] = {115, 115, 115, 255}, [MU_COLOR_BASE] = {30, 30, 30, 255}, [MU_COLOR_BASEHOVER] = {35, 35, 35, 255}, [MU_COLOR_BASEFOCUS] = {40, 40, 40, 255}, [MU_COLOR_SCROLLBASE] = {43, 43, 43, 255}, [MU_COLOR_SCROLLTHUMB] = {30, 30, 30, 255}, }; static void buffer_grow(void **buf, int onesz, int *bufmax, int bufnum) { while (*bufmax <= bufnum) { *bufmax = MAX(16, *bufmax) * 2; if ((*buf = realloc(*buf, *bufmax*onesz)) == nil) sysfatal("not enough memory for %d items (%d bytes)", *bufmax, *bufmax*onesz); } } mu_Rect mu_rect(int x, int y, int w, int h) { mu_Rect res; res.x = x, res.y = y, res.w = w, res.h = h; return res; } Image * mu_color(u8int r, u8int g, u8int b, u8int a) { Image *c; if ((c = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, setalpha(r<<24 | g<<16 | b<<8, a))) == nil) sysfatal("couldn't allocate color"); return c; } static Rectangle screenrect(mu_Rect r) { Rectangle rect; rect.min = screen->r.min; rect.min.x += r.x; rect.min.y += r.y; rect.max = rect.min; rect.max.x += r.w; rect.max.y += r.h; return rect; } static mu_Rect expand_rect(mu_Rect rect, int n) { return mu_rect(rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2); } static mu_Rect clip_rect(mu_Rect r1, mu_Rect r2) { int x1 = MAX(r1.x, r2.x); int y1 = MAX(r1.y, r2.y); int x2 = MAX(MIN(r1.x + r1.w, r2.x + r2.w), x1); int y2 = MAX(MIN(r1.y + r1.h, r2.y + r2.h), y1); return mu_rect(x1, y1, x2 - x1, y2 - y1); } static int rect_overlaps_vec2(mu_Rect r, Point p) { return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h; } static void draw_frame(mu_Rect rect, int colorid) { mu_draw_rect(rect, mu_style.colors[colorid]); if (colorid == MU_COLOR_SCROLLBASE || colorid == MU_COLOR_SCROLLTHUMB || colorid == MU_COLOR_TITLEBG) return; /* draw border */ mu_draw_box(expand_rect(rect, 1), mu_style.colors[MU_COLOR_BORDER]); } static int text_width(Font *font, const char *text, int len) { return stringnwidth(font, text, len >= 0 ? len : strlen(text)); } void mu_init(void) { Rectangle r; int res, i; if (atlasimage == nil) { r = Rect(0, 0, atlasicons[ATLAS_DIMENSIONS].w, atlasicons[ATLAS_DIMENSIONS].h); atlasimage = allocimage(display, r, RGBA32, 1, DTransparent); if (memcmp(atlasraw, "compressed\n", 11) == 0) res = cloadimage(atlasimage, r, atlasraw+11+5*12, sizeof(atlasraw)-11-5*12); else res = loadimage(atlasimage, r, atlasraw, sizeof(atlasraw)); if (res < 0) sysfatal("failed to load atlas: %r"); } if (mu_style.colors[0] == nil) { for (i = 0; i < MU_COLOR_MAX; i++) { mu_style.colors[i] = mu_color( defaultcolors[i][0], defaultcolors[i][1], defaultcolors[i][2], defaultcolors[i][3] ); } } } void mu_begin(void) { mu_ctx.cmdsnum = mu_ctx.rootnum = 0; mu_ctx.strnum = 0; mu_ctx.scroll_target = nil; mu_ctx.last_hover_root = mu_ctx.hover_root; mu_ctx.hover_root = nil; mu_ctx.mouse_delta.x = mu_ctx.mouse_pos.x - mu_ctx.last_mouse_pos.x; mu_ctx.mouse_delta.y = mu_ctx.mouse_pos.y - mu_ctx.last_mouse_pos.y; } static int compare_zindex(const void *a, const void *b) { return (*(mu_Container**)a)->zindex - (*(mu_Container**)b)->zindex; } void mu_end(void) { int i, n; /* check stacks */ assert(mu_ctx.cntnum == 0); assert(mu_ctx.clipnum == 0); assert(mu_ctx.idsnum == 0); assert(mu_ctx.layoutsnum == 0); /* handle scroll input */ if (mu_ctx.scroll_target) { mu_ctx.scroll_target->scroll.x += mu_ctx.scroll_delta.x; mu_ctx.scroll_target->scroll.y += mu_ctx.scroll_delta.y; } /* unset focus if focus id was not touched this frame */ if (!mu_ctx.updated_focus) mu_ctx.focus = 0; mu_ctx.updated_focus = 0; /* bring hover root to front if mouse was pressed */ if (mu_ctx.mouse_pressed && mu_ctx.hover_root && mu_ctx.hover_root->zindex < mu_ctx.last_zindex) mu_bring_to_front(mu_ctx.hover_root); /* reset input state */ mu_ctx.key_pressed = 0; mu_ctx.text_input[0] = 0; mu_ctx.mouse_pressed = 0; mu_ctx.scroll_delta = ZP; mu_ctx.last_mouse_pos = mu_ctx.mouse_pos; /* sort root containers by zindex */ n = mu_ctx.rootnum; qsort(mu_ctx.root, n, sizeof(*mu_ctx.root), compare_zindex); /* set root container jump commands */ for (i = 0; i < n; i++) { mu_Container *cnt = mu_ctx.root[i]; /* if this is the first container then make the first command jump to it. ** otherwise set the previous container's tail to jump to this one */ if (i == 0) mu_ctx.cmds[0].jump.dst = cnt->head + 1; else mu_ctx.cmds[mu_ctx.root[i - 1]->tail].jump.dst = cnt->head + 1; /* make the last container's tail jump to the end of command list */ if (i == n - 1) mu_ctx.cmds[cnt->tail].jump.dst = mu_ctx.cmdsnum; } } void mu_set_focus(mu_Id id) { mu_ctx.focus = id; mu_ctx.updated_focus = 1; } /* 32bit fnv-1a hash */ #define HASH_INITIAL 2166136261U static void hash(mu_Id *hash, const void *data, int size) { const unsigned char *p = data; while (size--) { *hash = (*hash ^ *p++) * 16777619; } } mu_Id mu_get_id(const void *data, int size) { int idx = mu_ctx.idsnum; mu_Id res = (idx > 0) ? mu_ctx.ids[idx - 1] : HASH_INITIAL; hash(&res, data, size); mu_ctx.last_id = res; return res; } void mu_push_id(const void *data, int size) { buffer_grow(&mu_ctx.ids, sizeof(*mu_ctx.ids), &mu_ctx.idsmax, mu_ctx.idsnum); mu_ctx.ids[mu_ctx.idsnum++] = mu_get_id(data, size); } void mu_pop_id(void) { mu_ctx.idsnum--; } void mu_push_clip_rect(mu_Rect rect) { mu_Rect last = mu_get_clip_rect(); buffer_grow(&mu_ctx.clip, sizeof(*mu_ctx.clip), &mu_ctx.clipmax, mu_ctx.clipnum); mu_ctx.clip[mu_ctx.clipnum++] = clip_rect(rect, last); } void mu_pop_clip_rect(void) { mu_ctx.clipnum--; } mu_Rect mu_get_clip_rect(void) { assert(mu_ctx.clipnum > 0); return mu_ctx.clip[mu_ctx.clipnum - 1]; } int mu_check_clip(mu_Rect r) { mu_Rect cr = mu_get_clip_rect(); if (r.x > cr.x + cr.w || r.x + r.w < cr.x || r.y > cr.y + cr.h || r.y + r.h < cr.y) return MU_CLIP_ALL; if (r.x >= cr.x && r.x + r.w <= cr.x + cr.w && r.y >= cr.y && r.y + r.h <= cr.y + cr.h) return MU_CLIP_NONE; return MU_CLIP_PART; } static void push_layout(mu_Rect body, Point scroll) { mu_Layout layout; int width = 0; memset(&layout, 0, sizeof(mu_Layout)); layout.body = mu_rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h); layout.max = Pt(-0x1000000, -0x1000000); buffer_grow(&mu_ctx.layouts, sizeof(*mu_ctx.layouts), &mu_ctx.layoutsmax, mu_ctx.layoutsnum); mu_ctx.layouts[mu_ctx.layoutsnum++] = layout; mu_layout_row(1, &width, 0); } static mu_Layout * get_layout(void) { return &mu_ctx.layouts[mu_ctx.layoutsnum - 1]; } static void push_container(mu_Container *cnt) { buffer_grow(&mu_ctx.cnt, sizeof(*mu_ctx.cnt), &mu_ctx.cntmax, mu_ctx.cntnum); mu_ctx.cnt[mu_ctx.cntnum++] = cnt; mu_push_id(&cnt, sizeof(mu_Container*)); } static void pop_container(void) { mu_Container *cnt = mu_get_container(); mu_Layout *layout = get_layout(); cnt->content_size.x = layout->max.x - layout->body.x; cnt->content_size.y = layout->max.y - layout->body.y; mu_ctx.cntnum--; mu_ctx.layoutsnum--; mu_pop_id(); } mu_Container * mu_get_container(void) { assert(mu_ctx.cntnum > 0); return mu_ctx.cnt[mu_ctx.cntnum - 1]; } void mu_init_window(mu_Container *cnt, int opt) { memset(cnt, 0, sizeof(*cnt)); cnt->inited = 1; cnt->open = opt & MU_OPT_CLOSED ? 0 : 1; cnt->rect = mu_rect(100, 100, 300, 300); mu_bring_to_front(cnt); } void mu_bring_to_front(mu_Container *cnt) { cnt->zindex = ++mu_ctx.last_zindex; } /*============================================================================ ** input handlers **============================================================================*/ void mu_input_mousemove(int x, int y) { mu_ctx.mouse_pos = Pt(x, y); } void mu_input_mousedown(int x, int y, int btn) { mu_input_mousemove(x, y); mu_ctx.mouse_down |= btn; mu_ctx.mouse_pressed |= btn; } void mu_input_mouseup(int x, int y, int btn) { mu_input_mousemove(x, y); mu_ctx.mouse_down &= ~btn; } void mu_input_scroll(int x, int y) { mu_ctx.scroll_delta.x += x; mu_ctx.scroll_delta.y += y; } void mu_input_keydown(int key) { mu_ctx.key_pressed |= key; mu_ctx.key_down |= key; } void mu_input_keyup(int key) { mu_ctx.key_down &= ~key; } void mu_input_text(const char *text) { int len = strlen(mu_ctx.text_input); int size = strlen(text) + 1; assert(len + size <= (int) sizeof(mu_ctx.text_input)); memcpy(mu_ctx.text_input + len, text, size); } /*============================================================================ ** commandlist **============================================================================*/ mu_Command * mu_push_command(int type) { mu_Command *cmd; buffer_grow(&mu_ctx.cmds, sizeof(mu_Command), &mu_ctx.cmdsmax, mu_ctx.cmdsnum); cmd = &mu_ctx.cmds[mu_ctx.cmdsnum++]; memset(cmd, 0, sizeof(*cmd)); cmd->type = type; return cmd; } static int push_jump(int dst) {