master
Alessandro Mauri 2 years ago
parent 056c622895
commit 2abac02c52
  1. 3
      .gitignore
  2. 10
      test/Makefile
  3. 208
      test/main.c
  4. 253
      ugui.c
  5. 48
      ugui.h

3
.gitignore vendored

@ -1,2 +1,3 @@
microgui microgui
*.o *.o
test/test

@ -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

@ -0,0 +1,208 @@
#include <stdio.h>
#include <SDL2/SDL.h>
#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;
}

253
ugui.c

@ -1,4 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <err.h> #include <err.h>
@ -16,6 +17,7 @@
#define IS_VALID_UNIT(u) (u==UG_UNIT_PX||u==UG_UNIT_MM||u==UG_UNIT_PT) #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 UG_ERR(...) err(errno, "__FUNCTION__: " __VA_ARGS__)
#define BETWEEN(x, min, max) (x <= max && x >= min) #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 // default style
@ -28,11 +30,12 @@ static const ug_style_t default_style = {
.alt_size = SIZE_PX(12), .alt_size = SIZE_PX(12),
}, },
.cnt = { .cnt = {
.bg_color = RGB_FORMAT(0xaaaaaa), .bg_color = RGB_FORMAT(0x0000ff),
.border.t = SIZE_PX(3), .border.t = SIZE_PX(3),
.border.b = SIZE_PX(3), .border.b = SIZE_PX(3),
.border.l = SIZE_PX(3), .border.l = SIZE_PX(3),
.border.r = SIZE_PX(3), .border.r = SIZE_PX(3),
.border.color = RGB_FORMAT(0x00ff00),
.titlebar.height = SIZE_PX(20), .titlebar.height = SIZE_PX(20),
.titlebar.bg_color = RGB_FORMAT(0xbababa), .titlebar.bg_color = RGB_FORMAT(0xbababa),
}, },
@ -49,7 +52,7 @@ static ug_style_t style_cache = {0};
// grow a stack // grow a stack
#define grow(S) \ #define GROW_STACK(S) \
{ \ { \
S.items = realloc(S.items, (S.size+STACK_STEP)*sizeof(*(S.items))); \ S.items = realloc(S.items, (S.size+STACK_STEP)*sizeof(*(S.items))); \
if(!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 // https://en.wikipedia.org/wiki/Jenkins_hash_function
static ug_id_t hash(const void *data, unsigned int size) 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) static void update_style_cache(ug_ctx_t *ctx)
{ {
const ug_style_t *s = ctx->style; const ug_style_t *s = ctx->style;
// TODO: do this shit // FIME: use the correct units and convert, for now assume default style
(void)s; 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) void push_rect_command(ug_ctx_t *ctx, const ug_rect_t *rect, ug_color_t color)
#define mouseup(ctx, btn) (ctx->mouse.press_mask & ~ctx->mouse.down_mask & btn) {
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() // 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)); ug_ctx_t *ctx = malloc(sizeof(ug_ctx_t));
if (!ctx) 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) { if (!ctx) {
warn("__FUNCTION__:" "Trying to free a null context"); warn("__FUNCTION__:" "Trying to free a null context");
return; return;
} }
// TODO: free stacks free(ctx->cmd_stack.items);
free(ctx->cnt_stack.items);
free(ctx); free(ctx);
// NOTE: do not free style since the default is statically allocated, let // 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 the container was not already there allocate a new one
if (!c) { if (!c)
if(ctx->cnt_stack.idx >= ctx->cnt_stack.size) GET_FROM_STACK(ctx->cnt_stack, c);
grow(ctx->cnt_stack);
c = &(ctx->cnt_stack.items[ctx->cnt_stack.idx++]);
}
return 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 // FIXME: this is the right place to do some optimization, what if the
// context didn't change? // context didn't change?
// the absoulute position of the container // the absoulute position of the container
ug_rect_t rect_abs = cnt->rect; cnt->rect_abs = cnt->rect;
/* /*
* Container style: * 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; const ug_style_t *s = ctx->style_px;
// 0 -> take all the space, <0 -> take absolute // 0 -> take all the space, <0 -> take absolute
if (rect_abs.w < 0) rect_abs.w = -rect_abs.w; if (cnt->rect_abs.w < 0) cnt->rect_abs.w = -cnt->rect_abs.w;
if (rect_abs.h < 0) rect_abs.h = -rect_abs.h; 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.l.size -
s->cnt.border.r.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.t.size -
s->cnt.border.b.size ; s->cnt.border.b.size ;
if (cnt->flags & UG_CNT_MOVABLE) 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 // <0 -> relative to the right margin
if (rect_abs.x < 0) rect_abs.x = ctx->size.x - rect_abs.w + rect_abs.x; if (cnt->rect_abs.x < 0)
if (rect_abs.y < 0) rect_abs.y = ctx->size.y - rect_abs.h + rect_abs.y; 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 // 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 // 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 // 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 // mouse pressed handle resize, for simplicity containers can only
// be resized from the bottom and right border // 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; ug_vec2_t mpos = ctx->mouse.pos;
int minx, maxx, miny, maxy; int minx, maxx, miny, maxy;
// handle movable windows // handle movable windows
minx = rect_abs.x; minx = cnt->rect_abs.x;
maxx = rect_abs.x + rect_abs.w - s->cnt.border.r.size; maxx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.r.size;
miny = rect_abs.y; miny = cnt->rect_abs.y;
maxy = rect_abs.y + s->cnt.titlebar.height.size; maxy = cnt->rect_abs.y + s->cnt.titlebar.height.size;
if (cnt->flags & UG_CNT_MOVABLE && if (cnt->flags & UG_CNT_MOVABLE &&
BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.x, minx, maxx) &&
BETWEEN(mpos.y, miny, maxy)) { BETWEEN(mpos.y, miny, maxy)) {
rect_abs.x += ctx->mouse.delta.x; cnt->rect_abs.x += ctx->mouse.delta.x;
rect_abs.y += ctx->mouse.delta.y; cnt->rect_abs.y += ctx->mouse.delta.y;
cnt->rect.x += ctx->mouse.delta.x; cnt->rect.x += ctx->mouse.delta.x;
cnt->rect.y += ctx->mouse.delta.y; cnt->rect.y += ctx->mouse.delta.y;
} }
// right border resize // right border resize
minx = rect_abs.x + rect_abs.w - s->cnt.border.r.size; minx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.r.size;
maxx = rect_abs.x + rect_abs.w; maxx = cnt->rect_abs.x + cnt->rect_abs.w;
miny = rect_abs.y; miny = cnt->rect_abs.y;
maxy = rect_abs.y + rect_abs.h; maxy = cnt->rect_abs.y + cnt->rect_abs.h;
if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) { 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; cnt->rect.w += ctx->mouse.delta.x;
} }
// bottom border resize // bottom border resize
minx = rect_abs.x; minx = cnt->rect_abs.x;
maxx = rect_abs.x + rect_abs.w; maxx = cnt->rect_abs.x + cnt->rect_abs.w;
miny = rect_abs.y + rect_abs.h - s->cnt.border.b.size; miny = cnt->rect_abs.y + cnt->rect_abs.h - s->cnt.border.b.size;
maxy = rect_abs.y + rect_abs.h; maxy = cnt->rect_abs.y + cnt->rect_abs.h;
if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) { 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; 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 // 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->max_size = max_size;
cnt->rect = rect; cnt->rect = rect;
cnt->unit = ctx->unit; cnt->unit = ctx->unit;
cnt->flags = UG_CNT_MOVABLE | cnt->flags = UG_CNT_MOVABLE | UG_CNT_RESIZABLE |
UG_CNT_RESIZABLE | UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y ;
UG_CNT_SCROLL_X |
UG_CNT_SCROLL_Y ;
} }
update_container(ctx, cnt); update_container(ctx, cnt);
return 0; 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;
}

@ -29,7 +29,7 @@ typedef enum {
typedef struct { typedef struct {
ug_id_t id; ug_id_t id;
ug_unit_t unit; ug_unit_t unit;
ug_rect_t rect; ug_rect_t rect, rect_abs;
ug_vec2_t max_size; ug_vec2_t max_size;
unsigned int flags; unsigned int flags;
} ug_container_t; } ug_container_t;
@ -57,6 +57,7 @@ typedef struct {
ug_color_t bg_color; ug_color_t bg_color;
struct { struct {
ug_size_t t, b, l, r; ug_size_t t, b, l, r;
ug_color_t color;
} border; } border;
// titlebar only gets applied to movable containers // titlebar only gets applied to movable containers
struct { struct {
@ -91,13 +92,30 @@ typedef struct {
} ug_style_t; } 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 // mouse buttons
enum { enum {
UG_BTN_LEFT = BIT(1), UG_BTN_LEFT = BIT(0),
UG_BTN_MIDDLE = BIT(1), UG_BTN_MIDDLE = BIT(1),
UG_BTN_RIGHT = BIT(1), UG_BTN_RIGHT = BIT(2),
UG_BTN_4 = BIT(1), UG_BTN_4 = BIT(3),
UG_BTN_5 = BIT(1), UG_BTN_5 = BIT(4),
}; };
// context // context
@ -116,6 +134,7 @@ typedef struct {
// which context and element we are hovering // which context and element we are hovering
struct { struct {
ug_id_t cnt, elem; ug_id_t cnt, elem;
ug_id_t cnt_last, elem_last;
} hover; } hover;
// the id of the "active" element, active means different things for // the id of the "active" element, active means different things for
// different elements, for exaple active for a button means to be pressed, // different elements, for exaple active for a button means to be pressed,
@ -147,12 +166,13 @@ typedef struct {
char input_text[32]; char input_text[32];
// stacks // stacks
UG_STACK(ug_container_t) cnt_stack; UG_STACK(ug_container_t) cnt_stack;
UG_STACK(ug_cmd_t) cmd_stack;
} ug_ctx_t; } ug_ctx_t;
// context initialization // context initialization
ug_ctx_t *ug_new_ctx(void); ug_ctx_t *ug_ctx_new(void);
void ug_free_ctx(ug_ctx_t *ctx); void ug_ctx_free(ug_ctx_t *ctx);
// updates the context with user information // updates the context with user information
int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi); 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); 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 // be resized
int ug_container_body(ug_ctx_t *ctx, const char *name); 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 UG_STACK
#undef BIT #undef BIT
#endif #endif

Loading…
Cancel
Save