From 2abac02c52d4501094b9afcfd67bd95ad42789d0 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Tue, 6 Dec 2022 20:49:34 +0100 Subject: [PATCH] it lives!? --- .gitignore | 3 +- test/Makefile | 10 ++ test/main.c | 208 +++++++++++++++++++++++++++++++++++++++++ ugui.c | 253 +++++++++++++++++++++++++++++++++++++++++--------- ugui.h | 48 ++++++++-- 5 files changed, 468 insertions(+), 54 deletions(-) create mode 100644 test/Makefile create mode 100644 test/main.c diff --git a/.gitignore b/.gitignore index 3964cac..42881b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ microgui -*.o \ No newline at end of file +*.o +test/test \ No newline at end of file diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..7df0c19 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g +LDFLAGS = -lSDL2 + +test: main.c ../ugui.c ../ugui.h + gcc ${CFLAGS} -c ../ugui.c -o ugui.o + gcc ${CFLAGS} -c main.c -o main.o + gcc ${LDFLAGS} main.o ugui.o -o test + +clean: + rm -f main.o ugui.o diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..058f932 --- /dev/null +++ b/test/main.c @@ -0,0 +1,208 @@ +#include +#include + +#include "../ugui.h" + +int main(void) +{ + SDL_DisplayMode dm; + + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); + SDL_EnableScreenSaver(); + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + SDL_EventState(SDL_DROPTEXT, SDL_ENABLE); + + SDL_GetDesktopDisplayMode(0, &dm); + +#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* Available since 2.0.8 */ + SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 5) + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); +#endif + + SDL_Window *w; + w = SDL_CreateWindow("test", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + dm.w*0.8, dm.h*0.8, + SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | + SDL_WINDOW_OPENGL ); + + //SDL_Surface *s; + //s = SDL_GetWindowSurface(w); + SDL_Renderer *r; + r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED); + + + ug_vec2_t size, dsize; + SDL_GetWindowSize(w, &size.w, &size.h); + SDL_GL_GetDrawableSize(w, &dsize.w, &dsize.h); + float scale = 1.0; + scale = ((float)(size.w+size.h)/2)/((float)(dsize.w+dsize.h)/2); + + float dpi; + int idx; + idx = SDL_GetWindowDisplayIndex(w); + SDL_GetDisplayDPI(idx, &dpi, NULL, NULL); + + + ug_ctx_t *ctx = ug_ctx_new(); + ug_ctx_set_displayinfo(ctx, scale, dpi); + ug_ctx_set_drawableregion(ctx, dsize); + + + SDL_Event event; + + char button_map[] = { + [SDL_BUTTON_LEFT & 0xff] = UG_BTN_LEFT, + [SDL_BUTTON_MIDDLE & 0xff] = UG_BTN_MIDDLE, + [SDL_BUTTON_RIGHT & 0xff] = UG_BTN_RIGHT, + [SDL_BUTTON_X1 & 0xff] = UG_BTN_4, + [SDL_BUTTON_X2 & 0xff] = UG_BTN_5, + }; + + do { + SDL_WaitEvent(&event); + + switch (event.type) { + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_SHOWN: + (SDL_Log("Window %d shown", event.window.windowID)); + break; + case SDL_WINDOWEVENT_HIDDEN: + (SDL_Log("Window %d hidden", event.window.windowID)); + break; + case SDL_WINDOWEVENT_EXPOSED: + (SDL_Log("Window %d exposed", event.window.windowID)); + break; + case SDL_WINDOWEVENT_MOVED: + (SDL_Log("Window %d moved to %d,%d", + event.window.windowID, event.window.data1, + event.window.data2)); + break; + case SDL_WINDOWEVENT_RESIZED: + (SDL_Log("Window %d resized to %dx%d", + event.window.windowID, event.window.data1, + event.window.data2)); + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + (SDL_Log("Window %d size changed to %dx%d", + event.window.windowID, event.window.data1, + event.window.data2)); + + size.w = event.window.data1; + size.h = event.window.data2; + // surface is invalidated every time the window + // is resized + //s = SDL_GetWindowSurface(w); + ug_ctx_set_drawableregion(ctx, size); + + break; + case SDL_WINDOWEVENT_MINIMIZED: + (SDL_Log("Window %d minimized", event.window.windowID)); + break; + case SDL_WINDOWEVENT_MAXIMIZED: + (SDL_Log("Window %d maximized", event.window.windowID)); + break; + case SDL_WINDOWEVENT_RESTORED: + (SDL_Log("Window %d restored", event.window.windowID)); + break; + case SDL_WINDOWEVENT_ENTER: + (SDL_Log("Mouse entered window %d", + event.window.windowID)); + break; + case SDL_WINDOWEVENT_LEAVE: + (SDL_Log("Mouse left window %d", event.window.windowID)); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + (SDL_Log("Window %d gained keyboard focus", + event.window.windowID)); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + (SDL_Log("Window %d lost keyboard focus", + event.window.windowID)); + break; + case SDL_WINDOWEVENT_CLOSE: + (SDL_Log("Window %d closed", event.window.windowID)); + break; +#if SDL_VERSION_ATLEAST(2, 0, 5) + case SDL_WINDOWEVENT_TAKE_FOCUS: + (SDL_Log("Window %d is offered a focus", event.window.windowID)); + break; + case SDL_WINDOWEVENT_HIT_TEST: + (SDL_Log("Window %d has a special hit test", event.window.windowID)); + break; +#endif + default: + (SDL_Log("Window %d got unknown event %d", + event.window.windowID, event.window.event)); + break; + } + break; + case SDL_QUIT: + (printf("Quitting\n")); + break; + case SDL_MOUSEMOTION: + + ug_input_mousemove(ctx, event.motion.x, event.motion.y); + + break; + case SDL_MOUSEBUTTONDOWN: + ug_input_mousemove(ctx, event.button.x, event.button.y); + ug_input_mousedown(ctx, button_map[event.button.button & 0xff]); + + break; + case SDL_MOUSEBUTTONUP: + + ug_input_mousemove(ctx, event.button.x, event.button.y); + ug_input_mouseup(ctx, button_map[event.button.button & 0xff]); + + break; + default: + (printf("Unknown event: %d\n", event.type)); + break; + } + + + ug_frame_begin(ctx); + + ug_container_floating(ctx, "stupid name", + (ug_rect_t){.x = 0, .y = 0, .w = 100, .h = 300}); + ug_container_floating(ctx, "better name", + (ug_rect_t){.x = -20, .y = -10, .w = 100, .h = 200}); + + ug_frame_end(ctx); + + // fill background + SDL_SetRenderDrawColor(r, 0, 0, 0, 0xff); + SDL_RenderClear(r); + for (int i = 0; i < ctx->cmd_stack.idx; i++) { + ug_cmd_t cmd = ctx->cmd_stack.items[i]; + ug_color_t col = cmd.rect.color; + SDL_Rect sr = { + .x = cmd.rect.x, + .y = cmd.rect.y, + .w = cmd.rect.w, + .h = cmd.rect.h, + }; + printf("DRAWING: x=%d, y=%d, w=%d, h=%d\n", sr.x, sr.y, sr.w, sr.h); + printf("COLOR: #%.8X\n", *((unsigned int *)&col)); + SDL_SetRenderDrawColor(r, col.r, col.g, col.b, col.a); + SDL_RenderFillRect(r, &sr); + } + SDL_RenderPresent(r); + + printf("-------------------FRAME DONE--------------------\n"); + + } while (event.type != SDL_QUIT); + + + ug_ctx_free(ctx); + + SDL_DestroyRenderer(r); + SDL_DestroyWindow(w); + SDL_Quit(); + return 0; +} \ No newline at end of file diff --git a/ugui.c b/ugui.c index 4ecee5b..8a9b8af 100644 --- a/ugui.c +++ b/ugui.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,6 +17,7 @@ #define IS_VALID_UNIT(u) (u==UG_UNIT_PX||u==UG_UNIT_MM||u==UG_UNIT_PT) #define UG_ERR(...) err(errno, "__FUNCTION__: " __VA_ARGS__) #define BETWEEN(x, min, max) (x <= max && x >= min) +#define INTERSECTS(v, r) (BETWEEN(v.x, r.x, r.x+r.w) && BETWEEN(v.y, r.y, r.y+r.h)) // default style @@ -28,11 +30,12 @@ static const ug_style_t default_style = { .alt_size = SIZE_PX(12), }, .cnt = { - .bg_color = RGB_FORMAT(0xaaaaaa), + .bg_color = RGB_FORMAT(0x0000ff), .border.t = SIZE_PX(3), .border.b = SIZE_PX(3), .border.l = SIZE_PX(3), .border.r = SIZE_PX(3), + .border.color = RGB_FORMAT(0x00ff00), .titlebar.height = SIZE_PX(20), .titlebar.bg_color = RGB_FORMAT(0xbababa), }, @@ -49,7 +52,7 @@ static ug_style_t style_cache = {0}; // grow a stack -#define grow(S) \ +#define GROW_STACK(S) \ { \ S.items = realloc(S.items, (S.size+STACK_STEP)*sizeof(*(S.items))); \ if(!S.items) \ @@ -59,6 +62,25 @@ static ug_style_t style_cache = {0}; } +#define GET_FROM_STACK(S, c) \ +{ \ + if (S.idx >= S.size) \ + GROW_STACK(S); \ + c = &(S.items[S.idx++]); \ +} + + +#define RESET_STACK(S) \ +{ \ + memset(S.items, 0, S.idx*sizeof(*(S.items))); \ + S.idx = 0; \ +} + + +#define MOUSEDOWN(ctx, btn) (ctx->mouse.press_mask & ctx->mouse.down_mask & btn) +#define MOUSEUP(ctx, btn) (ctx->mouse.press_mask & ~ctx->mouse.down_mask & btn) + + // https://en.wikipedia.org/wiki/Jenkins_hash_function static ug_id_t hash(const void *data, unsigned int size) { @@ -84,8 +106,8 @@ static ug_id_t hash(const void *data, unsigned int size) static void update_style_cache(ug_ctx_t *ctx) { const ug_style_t *s = ctx->style; - // TODO: do this shit - (void)s; + // FIME: use the correct units and convert, for now assume default style + style_cache = *s; } @@ -113,8 +135,17 @@ ug_rect_t rect_to_px(ug_ctx_t *ctx, ug_rect_t rect) } -#define mousedown(ctx, btn) (ctx->mouse.press_mask & ctx->mouse.down_mask & btn) -#define mouseup(ctx, btn) (ctx->mouse.press_mask & ~ctx->mouse.down_mask & btn) +void push_rect_command(ug_ctx_t *ctx, const ug_rect_t *rect, ug_color_t color) +{ + ug_cmd_t *c; + GET_FROM_STACK(ctx->cmd_stack, c); + c->type = UG_CMD_RECT; + c->rect.x = rect->x; + c->rect.y = rect->y; + c->rect.w = rect->w; + c->rect.h = rect->h; + c->rect.color = color; +} /*=============================================================================* @@ -123,7 +154,7 @@ ug_rect_t rect_to_px(ug_ctx_t *ctx, ug_rect_t rect) // creates a new context, fills with default values, ctx is ready for ug_start() -ug_ctx_t *ug_new_ctx(void) +ug_ctx_t *ug_ctx_new(void) { ug_ctx_t *ctx = malloc(sizeof(ug_ctx_t)); if (!ctx) @@ -144,14 +175,16 @@ ug_ctx_t *ug_new_ctx(void) } -void ug_free_ctx(ug_ctx_t *ctx) +void ug_ctx_free(ug_ctx_t *ctx) { if (!ctx) { warn("__FUNCTION__:" "Trying to free a null context"); return; } - // TODO: free stacks + free(ctx->cmd_stack.items); + free(ctx->cnt_stack.items); + free(ctx); // NOTE: do not free style since the default is statically allocated, let @@ -236,11 +269,8 @@ static ug_container_t *get_container(ug_ctx_t *ctx, ug_id_t id) } } // if the container was not already there allocate a new one - if (!c) { - if(ctx->cnt_stack.idx >= ctx->cnt_stack.size) - grow(ctx->cnt_stack); - c = &(ctx->cnt_stack.items[ctx->cnt_stack.idx++]); - } + if (!c) + GET_FROM_STACK(ctx->cnt_stack, c); return c; } @@ -263,7 +293,7 @@ static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) // FIXME: this is the right place to do some optimization, what if the // context didn't change? // the absoulute position of the container - ug_rect_t rect_abs = cnt->rect; + cnt->rect_abs = cnt->rect; /* * Container style: @@ -296,63 +326,79 @@ static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) const ug_style_t *s = ctx->style_px; // 0 -> take all the space, <0 -> take absolute - if (rect_abs.w < 0) rect_abs.w = -rect_abs.w; - if (rect_abs.h < 0) rect_abs.h = -rect_abs.h; + if (cnt->rect_abs.w < 0) cnt->rect_abs.w = -cnt->rect_abs.w; + if (cnt->rect_abs.h < 0) cnt->rect_abs.h = -cnt->rect_abs.h; - if (rect_abs.w == 0) rect_abs.w = ctx->size.w - + if (cnt->rect_abs.w == 0) cnt->rect_abs.w = ctx->size.w - s->cnt.border.l.size - s->cnt.border.r.size ; - if (rect_abs.h == 0) rect_abs.h = ctx->size.h - + if (cnt->rect_abs.h == 0) cnt->rect_abs.h = ctx->size.h - s->cnt.border.t.size - s->cnt.border.b.size ; if (cnt->flags & UG_CNT_MOVABLE) - rect_abs.h -= s->cnt.titlebar.height.size; + cnt->rect_abs.h += s->cnt.titlebar.height.size; // <0 -> relative to the right margin - if (rect_abs.x < 0) rect_abs.x = ctx->size.x - rect_abs.w + rect_abs.x; - if (rect_abs.y < 0) rect_abs.y = ctx->size.y - rect_abs.h + rect_abs.y; + if (cnt->rect_abs.x < 0) + cnt->rect_abs.x = ctx->size.x - cnt->rect_abs.w + cnt->rect_abs.x; + if (cnt->rect_abs.y < 0) + cnt->rect_abs.y = ctx->size.y - cnt->rect_abs.h + cnt->rect_abs.y; // if we had focus the frame before, then do shit // FIXME: if this is a brand new container then do we need to handle user // inputs, since all inputs lag one frame, then it would make no sense - if (ctx->hover.cnt == cnt->id) { + if (ctx->hover.cnt_last == cnt->id) { // mouse pressed handle resize, for simplicity containers can only // be resized from the bottom and right border - if (mousedown(ctx, UG_BTN_RIGHT)) { + +#define BIN_PATTERN "%c%c%c%c%c%c%c%c" +#define BYTE_TO_BINARY(byte) \ + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') + + printf("mousemask = "BIN_PATTERN"\n", BYTE_TO_BINARY(ctx->mouse.down_mask)); + if (ctx->mouse.down_mask & UG_BTN_LEFT) { + printf("MOUSEDOWN\n"); ug_vec2_t mpos = ctx->mouse.pos; int minx, maxx, miny, maxy; // handle movable windows - minx = rect_abs.x; - maxx = rect_abs.x + rect_abs.w - s->cnt.border.r.size; - miny = rect_abs.y; - maxy = rect_abs.y + s->cnt.titlebar.height.size; + minx = cnt->rect_abs.x; + maxx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.r.size; + miny = cnt->rect_abs.y; + maxy = cnt->rect_abs.y + s->cnt.titlebar.height.size; if (cnt->flags & UG_CNT_MOVABLE && BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) { - rect_abs.x += ctx->mouse.delta.x; - rect_abs.y += ctx->mouse.delta.y; + cnt->rect_abs.x += ctx->mouse.delta.x; + cnt->rect_abs.y += ctx->mouse.delta.y; cnt->rect.x += ctx->mouse.delta.x; cnt->rect.y += ctx->mouse.delta.y; } // right border resize - minx = rect_abs.x + rect_abs.w - s->cnt.border.r.size; - maxx = rect_abs.x + rect_abs.w; - miny = rect_abs.y; - maxy = rect_abs.y + rect_abs.h; + minx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.r.size; + maxx = cnt->rect_abs.x + cnt->rect_abs.w; + miny = cnt->rect_abs.y; + maxy = cnt->rect_abs.y + cnt->rect_abs.h; if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) { - rect_abs.w += ctx->mouse.delta.x; + cnt->rect_abs.w += ctx->mouse.delta.x; cnt->rect.w += ctx->mouse.delta.x; } // bottom border resize - minx = rect_abs.x; - maxx = rect_abs.x + rect_abs.w; - miny = rect_abs.y + rect_abs.h - s->cnt.border.b.size; - maxy = rect_abs.y + rect_abs.h; + minx = cnt->rect_abs.x; + maxx = cnt->rect_abs.x + cnt->rect_abs.w; + miny = cnt->rect_abs.y + cnt->rect_abs.h - s->cnt.border.b.size; + maxy = cnt->rect_abs.y + cnt->rect_abs.h; if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) { - rect_abs.h += ctx->mouse.delta.y; + cnt->rect_abs.h += ctx->mouse.delta.y; cnt->rect.h += ctx->mouse.delta.y; } } @@ -365,7 +411,29 @@ static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) } // push the appropriate rectangles to the drawing stack - // TODO: ^ This ^ + // push outline + push_rect_command(ctx, &cnt->rect_abs, s->cnt.border.color); + // push titlebar + ug_rect_t titlebar = { + .x = (cnt->rect_abs.x + s->cnt.border.l.size), + .y = (cnt->rect_abs.y + s->cnt.border.t.size), + .w = (cnt->rect_abs.w - s->cnt.border.r.size - s->cnt.border.l.size), + .h = s->cnt.titlebar.height.size, + }; + push_rect_command(ctx, &titlebar, s->cnt.titlebar.bg_color); + // push main body + ug_rect_t body = { + .x = (cnt->rect_abs.x + s->cnt.border.l.size), + .y = (cnt->rect_abs.y + s->cnt.border.t.size), + .w = (cnt->rect_abs.w - s->cnt.border.l.size - s->cnt.border.r.size), + .h = (cnt->rect_abs.h - s->cnt.border.t.size - s->cnt.border.b.size), + }; + if (cnt->flags & UG_CNT_MOVABLE) { + body.y += s->cnt.titlebar.height.size + s->cnt.border.t.size; + body.h -= s->cnt.titlebar.height.size + s->cnt.border.t.size; + } + push_rect_command(ctx, &body, s->cnt.bg_color); + // TODO: push other rects } @@ -386,13 +454,108 @@ int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_rect_t rect) cnt->max_size = max_size; cnt->rect = rect; cnt->unit = ctx->unit; - cnt->flags = UG_CNT_MOVABLE | - UG_CNT_RESIZABLE | - UG_CNT_SCROLL_X | - UG_CNT_SCROLL_Y ; + cnt->flags = UG_CNT_MOVABLE | UG_CNT_RESIZABLE | + UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y ; } update_container(ctx, cnt); return 0; } + + +/*=============================================================================* + * Input Handling * + *=============================================================================*/ + + +int ug_input_mousemove(ug_ctx_t *ctx, int x, int y) +{ + TEST_CTX(ctx) + if (x < 0 || y < 0) + return 0; + + ctx->mouse.pos = (ug_vec2_t){.x = x, .y = y}; + + return 0; +} + + +int ug_input_mousedown(ug_ctx_t *ctx, unsigned int mask) +{ + TEST_CTX(ctx); + + ctx->mouse.press_mask |= mask; + ctx->mouse.down_mask |= mask; + + return 0; +} + + +int ug_input_mouseup(ug_ctx_t *ctx, unsigned int mask) +{ + TEST_CTX(ctx); + + ctx->mouse.down_mask &= ~mask; + + return 0; +} + + + +/*=============================================================================* + * Frame Handling * + *=============================================================================*/ + + +// At the beginning of a frame assume that all input has been passed to the context +// update the mouse delta and reset the command stack +int ug_frame_begin(ug_ctx_t *ctx) +{ + TEST_CTX(ctx); + + // TODO: add a way to mark a container for removal from the stack, and then + // remove it here to save space + + // update mouse delta + ctx->mouse.delta.x = ctx->mouse.pos.x - ctx->mouse.last_pos.x; + ctx->mouse.delta.y = ctx->mouse.pos.y - ctx->mouse.last_pos.y; + + // clear command stack + RESET_STACK(ctx->cmd_stack); + + // update hover index + ug_vec2_t v = ctx->mouse.pos; +// printf("mouse: x=%d, y=%d\n", ctx->mouse.pos.x, ctx->mouse.pos.x); + for (int i = 0; i < ctx->cnt_stack.idx; i++) { + ug_rect_t r = ctx->cnt_stack.items[i].rect_abs; + if (INTERSECTS(v, r)) { + ctx->hover.cnt = ctx->cnt_stack.items[i].id; +// printf("intersects! %.8x\n", ctx->hover.cnt); + } + } + + return 0; +} + + +// At the end of a frame reset inputs +int ug_frame_end(ug_ctx_t *ctx) +{ + TEST_CTX(ctx); + + ctx->input_text[0] = '\0'; + ctx->key.press_mask = 0; + ctx->mouse.press_mask = 0; + ctx->mouse.scroll_delta = (ug_vec2_t){0}; + ctx->mouse.last_pos = ctx->mouse.pos; + + // reset hover, it has to be calculated at frame beginning + ctx->hover.cnt_last = ctx->hover.cnt; + ctx->hover.elem_last = ctx->hover.elem; + ctx->hover.cnt = 0; + ctx->hover.elem = 0; + + return 0; +} + diff --git a/ugui.h b/ugui.h index 0e10bbb..7a86d34 100644 --- a/ugui.h +++ b/ugui.h @@ -29,7 +29,7 @@ typedef enum { typedef struct { ug_id_t id; ug_unit_t unit; - ug_rect_t rect; + ug_rect_t rect, rect_abs; ug_vec2_t max_size; unsigned int flags; } ug_container_t; @@ -57,6 +57,7 @@ typedef struct { ug_color_t bg_color; struct { ug_size_t t, b, l, r; + ug_color_t color; } border; // titlebar only gets applied to movable containers struct { @@ -91,13 +92,30 @@ typedef struct { } ug_style_t; +// render commands +typedef struct { + unsigned int type; + union { + struct { + int x, y, w, h; + ug_color_t color; + } rect; + }; +} ug_cmd_t; + +typedef enum { + UG_CMD_NULL = 0, + UG_CMD_RECT, +} ug_cmd_type_t; + + // mouse buttons enum { - UG_BTN_LEFT = BIT(1), + UG_BTN_LEFT = BIT(0), UG_BTN_MIDDLE = BIT(1), - UG_BTN_RIGHT = BIT(1), - UG_BTN_4 = BIT(1), - UG_BTN_5 = BIT(1), + UG_BTN_RIGHT = BIT(2), + UG_BTN_4 = BIT(3), + UG_BTN_5 = BIT(4), }; // context @@ -116,6 +134,7 @@ typedef struct { // which context and element we are hovering struct { ug_id_t cnt, elem; + ug_id_t cnt_last, elem_last; } hover; // the id of the "active" element, active means different things for // different elements, for exaple active for a button means to be pressed, @@ -147,12 +166,13 @@ typedef struct { char input_text[32]; // stacks UG_STACK(ug_container_t) cnt_stack; + UG_STACK(ug_cmd_t) cmd_stack; } ug_ctx_t; // context initialization -ug_ctx_t *ug_new_ctx(void); -void ug_free_ctx(ug_ctx_t *ctx); +ug_ctx_t *ug_ctx_new(void); +void ug_ctx_free(ug_ctx_t *ctx); // updates the context with user information int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi); int ug_ctx_set_drawableregion(ug_ctx_t *ctx, ug_vec2_t size); @@ -177,7 +197,19 @@ int ug_container_sidebar(ug_ctx_t *ctx, const char *name, int width); // be resized int ug_container_body(ug_ctx_t *ctx, const char *name); +// Input functions +int ug_input_mousemove(ug_ctx_t *ctx, int x, int y); +int ug_input_mousedown(ug_ctx_t *ctx, unsigned int mask); +int ug_input_mouseup(ug_ctx_t *ctx, unsigned int mask); +int ug_input_scroll(ug_ctx_t *ctx, int x, int y); +// TODO: other input functions + +// Frame handling +int ug_frame_begin(ug_ctx_t *ctx); +int ug_frame_end(ug_ctx_t *ctx); + + #undef UG_STACK #undef BIT -#endif \ No newline at end of file +#endif