it lives!?
This commit is contained in:
parent
056c622895
commit
2abac02c52
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
microgui
|
microgui
|
||||||
*.o
|
*.o
|
||||||
|
test/test
|
10
test/Makefile
Normal file
10
test/Makefile
Normal file
@ -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
|
208
test/main.c
Normal file
208
test/main.c
Normal file
@ -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
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
48
ugui.h
48
ugui.h
@ -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…
Reference in New Issue
Block a user