Compare commits

..

No commits in common. "17a2bc32b88ee19494c5171b476d2b7610db2369" and "2abac02c52d4501094b9afcfd67bd95ad42789d0" have entirely different histories.

4 changed files with 152 additions and 174 deletions

View File

@ -1,5 +1,5 @@
CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g
LDFLAGS = -lSDL2 -lm LDFLAGS = -lSDL2
test: main.c ../ugui.c ../ugui.h test: main.c ../ugui.c ../ugui.h
gcc ${CFLAGS} -c ../ugui.c -o ugui.o gcc ${CFLAGS} -c ../ugui.c -o ugui.o

View File

@ -3,13 +3,6 @@
#include "../ugui.h" #include "../ugui.h"
SDL_Window *w;
SDL_Renderer *r;
ug_ctx_t *ctx;
void cleanup(void);
int main(void) int main(void)
{ {
SDL_DisplayMode dm; SDL_DisplayMode dm;
@ -29,6 +22,7 @@ int main(void)
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif #endif
SDL_Window *w;
w = SDL_CreateWindow("test", w = SDL_CreateWindow("test",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
dm.w*0.8, dm.h*0.8, dm.w*0.8, dm.h*0.8,
@ -37,6 +31,7 @@ int main(void)
//SDL_Surface *s; //SDL_Surface *s;
//s = SDL_GetWindowSurface(w); //s = SDL_GetWindowSurface(w);
SDL_Renderer *r;
r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED); r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED);
@ -52,13 +47,11 @@ int main(void)
SDL_GetDisplayDPI(idx, &dpi, NULL, NULL); SDL_GetDisplayDPI(idx, &dpi, NULL, NULL);
ctx = ug_ctx_new(); ug_ctx_t *ctx = ug_ctx_new();
ug_ctx_set_displayinfo(ctx, scale, dpi); ug_ctx_set_displayinfo(ctx, scale, dpi);
ug_ctx_set_drawableregion(ctx, dsize); ug_ctx_set_drawableregion(ctx, dsize);
// atexit(cleanup);
SDL_Event event; SDL_Event event;
char button_map[] = { char button_map[] = {
@ -175,11 +168,10 @@ int main(void)
ug_frame_begin(ctx); ug_frame_begin(ctx);
ug_ctx_set_unit(ctx, UG_UNIT_MM);
ug_container_floating(ctx, "stupid name", ug_container_floating(ctx, "stupid name",
(ug_rect_t){.fx = 0, .fy = 0, .fw = 50, .fh = 50}); (ug_rect_t){.x = 0, .y = 0, .w = 100, .h = 300});
ug_container_floating(ctx, "better name", ug_container_floating(ctx, "better name",
(ug_rect_t){.fx = -20, .fy = -10, .fw = 100, .fh = 30}); (ug_rect_t){.x = -20, .y = -10, .w = 100, .h = 200});
ug_frame_end(ctx); ug_frame_end(ctx);
@ -195,8 +187,8 @@ int main(void)
.w = cmd.rect.w, .w = cmd.rect.w,
.h = cmd.rect.h, .h = cmd.rect.h,
}; };
//printf("DRAWING: x=%d, y=%d, w=%d, h=%d\n", sr.x, sr.y, sr.w, sr.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)); printf("COLOR: #%.8X\n", *((unsigned int *)&col));
SDL_SetRenderDrawColor(r, col.r, col.g, col.b, col.a); SDL_SetRenderDrawColor(r, col.r, col.g, col.b, col.a);
SDL_RenderFillRect(r, &sr); SDL_RenderFillRect(r, &sr);
} }
@ -206,15 +198,11 @@ int main(void)
} while (event.type != SDL_QUIT); } while (event.type != SDL_QUIT);
cleanup();
return 0;
}
void cleanup(void)
{
ug_ctx_free(ctx); ug_ctx_free(ctx);
SDL_DestroyRenderer(r); SDL_DestroyRenderer(r);
SDL_DestroyWindow(w); SDL_DestroyWindow(w);
SDL_Quit(); SDL_Quit();
} return 0;
}

275
ugui.c
View File

@ -3,7 +3,6 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <err.h> #include <err.h>
#include <math.h>
#include "ugui.h" #include "ugui.h"
@ -18,8 +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)) #define INTERSECTS(v, r) (BETWEEN(v.x, r.x, r.x+r.w) && BETWEEN(v.y, r.y, r.y+r.h))
#define CAP(x, s) { if (x < s) x = s; }
// default style // default style
@ -113,6 +111,30 @@ static void update_style_cache(ug_ctx_t *ctx)
} }
ug_rect_t rect_to_px(ug_ctx_t *ctx, ug_rect_t rect)
{
float scale = 1.0;
switch (ctx->unit) {
case UG_UNIT_PX:
return rect;
case UG_UNIT_MM:
scale = ctx->ppm;
break;
case UG_UNIT_PT:
scale = ctx->ppd;
break;
}
rect.x *= scale;
rect.y *= scale;
rect.w *= scale;
rect.h *= scale;
return rect;
}
void push_rect_command(ug_ctx_t *ctx, const ug_rect_t *rect, ug_color_t color) void push_rect_command(ug_ctx_t *ctx, const ug_rect_t *rect, ug_color_t color)
{ {
ug_cmd_t *c; ug_cmd_t *c;
@ -139,10 +161,14 @@ ug_ctx_t *ug_ctx_new(void)
err(errno, "__FUNCTION__:" "Could not allocate context: %s", strerror(errno)); err(errno, "__FUNCTION__:" "Could not allocate context: %s", strerror(errno));
memset(ctx, 0, sizeof(ug_ctx_t)); memset(ctx, 0, sizeof(ug_ctx_t));
ctx->scale = DEF_SCALE;
ctx->ppi = DEF_PPI;
ctx->ppm = PPI_PPM(DEF_SCALE, DEF_PPI);
ctx->ppd = PPI_PPD(DEF_SCALE, DEF_PPI);
ctx->unit = UG_UNIT_PX; ctx->unit = UG_UNIT_PX;
ctx->style = &default_style; ctx->style = &default_style;
ctx->style_px = &style_cache; ctx->style_px = &style_cache;
ug_ctx_set_displayinfo(ctx, DEF_SCALE, DEF_PPI);
// TODO: allocate stacks // TODO: allocate stacks
return ctx; return ctx;
@ -174,12 +200,9 @@ int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi)
if (scale <= 0 || ppi < 20.0) if (scale <= 0 || ppi < 20.0)
return -1; return -1;
ctx->last_ppi = ctx->ppi;
ctx->last_ppm = ctx->ppd;
ctx->last_ppd = ctx->ppm;
ctx->ppm = PPI_PPM(scale, ppi); ctx->ppm = PPI_PPM(scale, ppi);
ctx->ppd = PPI_PPM(scale, ppi); ctx->ppd = PPI_PPM(scale, ppi);
ctx->scale = scale;
ctx->ppi = ppi; ctx->ppi = ppi;
update_style_cache(ctx); update_style_cache(ctx);
@ -257,37 +280,26 @@ static ug_container_t *get_container(ug_ctx_t *ctx, ug_id_t id)
// also handle resizing, moving, ect. if allowed by the container // also handle resizing, moving, ect. if allowed by the container
static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) static void update_container(ug_ctx_t *ctx, ug_container_t *cnt)
{ {
// if the container is new it has never been converted to pixels // if the container was just initialized the unit might not be pixels, this
// is a problem since all mouse events are in pixels and convering back
// and forth accumulates error and in heavy on the cpu
if (cnt->unit != UG_UNIT_PX) { if (cnt->unit != UG_UNIT_PX) {
float scale = 1.0; // FIXME: this takes the unit from the context but it should be fine
switch (ctx->unit) { cnt->rect = rect_to_px(ctx, cnt->rect);
case UG_UNIT_MM: scale = ctx->ppm; break;
case UG_UNIT_PT: scale = ctx->ppd; break;
default: break;
}
cnt->rect.x = roundf(cnt->rect.fx * scale);
cnt->rect.y = roundf(cnt->rect.fy * scale);
cnt->rect.w = roundf(cnt->rect.fw * scale);
cnt->rect.h = roundf(cnt->rect.fh * scale);
cnt->unit = UG_UNIT_PX; cnt->unit = UG_UNIT_PX;
} else if (ctx->ppi != ctx->last_ppi) {
// if the scale has been updated than we need to scale the container
// as well
float scale = ctx->ppi / ctx->last_ppi;
cnt->rect.x = roundf(cnt->rect.x * scale);
cnt->rect.y = roundf(cnt->rect.y * scale);
cnt->rect.w = roundf(cnt->rect.w * scale);
cnt->rect.h = roundf(cnt->rect.h * scale);
} }
cnt->rca = cnt->rect; // recalculate position
// FIXME: this is the right place to do some optimization, what if the
// context didn't change?
// the absoulute position of the container
cnt->rect_abs = cnt->rect;
/* /*
* Container style: * Container style:
* *
* rca * rect_abs(0,0)
* v * v
* +-----------------------------------------------+ * +-----------------------------------------------+
* | Titlebar | * | Titlebar |
* +-----------------------------------------------+ * +-----------------------------------------------+
@ -313,121 +325,114 @@ 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;
int bl = s->cnt.border.l.size;
int br = s->cnt.border.r.size;
int bt = s->cnt.border.t.size;
int bb = s->cnt.border.b.size;
int hh = s->cnt.titlebar.height.size;
int cw = ctx->size.w;
int ch = ctx->size.h;
// 0 -> take all the space, <0 -> take absolute // 0 -> take all the space, <0 -> take absolute
if (cnt->rect.w < 0) cnt->rca.w = -cnt->rect.w; if (cnt->rect_abs.w < 0) cnt->rect_abs.w = -cnt->rect_abs.w;
if (cnt->rect.h < 0) cnt->rca.h = -cnt->rect.h; if (cnt->rect_abs.h < 0) cnt->rect_abs.h = -cnt->rect_abs.h;
// handle relative position if (cnt->rect_abs.w == 0) cnt->rect_abs.w = ctx->size.w -
// and move to fit borders s->cnt.border.l.size -
if (cnt->rect.w == 0) cnt->rca.w = cw - br - bl; s->cnt.border.r.size ;
else cnt->rca.w += bl + br; if (cnt->rect_abs.h == 0) cnt->rect_abs.h = ctx->size.h -
if (cnt->rect.h == 0) cnt->rca.h = ch - bt - bb; s->cnt.border.t.size -
else if (cnt->flags & UG_CNT_MOVABLE) cnt->rca.h += hh + 2*bt + bb; s->cnt.border.b.size ;
else cnt->rca.h += bt + bb; if (cnt->flags & UG_CNT_MOVABLE)
cnt->rect_abs.h += s->cnt.titlebar.height.size;
// the window may have been resized so cap the position to the window size
// FIXME: is MAX(cw - bl, 0) better?
if (cnt->rect.x > cw) cnt->rca.x = cw;
if (cnt->rect.y > ch) cnt->rca.y = ch;
// <0 -> relative to the right margin // <0 -> relative to the right margin
if (cnt->rect.x < 0) cnt->rca.x = cw - cnt->rca.w + cnt->rca.x; if (cnt->rect_abs.x < 0)
if (cnt->rect.y < 0) cnt->rca.y = ch - cnt->rca.h + cnt->rca.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
if (ctx->hover.cnt_last != cnt->id) // FIXME: if this is a brand new container then do we need to handle user
goto cnt_draw; // inputs, since all inputs lag one frame, then it would make no sense
if (ctx->hover.cnt_last == cnt->id) {
// mouse pressed handle resize, for simplicity containers can only
// be resized from the bottom and right border
// mouse pressed handle resize, for simplicity containers can only #define BIN_PATTERN "%c%c%c%c%c%c%c%c"
// be resized from the bottom and right border #define BYTE_TO_BINARY(byte) \
// TODO: bring selected container to the top of the stack (byte & 0x80 ? '1' : '0'), \
if (!(ctx->mouse.down_mask & UG_BTN_LEFT) || (byte & 0x40 ? '1' : '0'), \
!(cnt->flags & (UG_CNT_RESIZABLE | UG_CNT_MOVABLE))) (byte & 0x20 ? '1' : '0'), \
goto cnt_draw; (byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \
ug_vec2_t mpos = ctx->mouse.pos; (byte & 0x04 ? '1' : '0'), \
int minx, maxx, miny, maxy; (byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0')
// handle movable windows
if (cnt->flags & UG_CNT_MOVABLE) { printf("mousemask = "BIN_PATTERN"\n", BYTE_TO_BINARY(ctx->mouse.down_mask));
minx = cnt->rca.x; if (ctx->mouse.down_mask & UG_BTN_LEFT) {
maxx = cnt->rca.x + cnt->rca.w - br; printf("MOUSEDOWN\n");
miny = cnt->rca.y; ug_vec2_t mpos = ctx->mouse.pos;
maxy = cnt->rca.y + bt + hh; int minx, maxx, miny, maxy;
if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) {
cnt->rect.x += ctx->mouse.delta.x; // handle movable windows
cnt->rect.y += ctx->mouse.delta.y; minx = cnt->rect_abs.x;
cnt->rca.x += ctx->mouse.delta.x; maxx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.r.size;
cnt->rca.y += ctx->mouse.delta.y; 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)) {
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 = 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)) {
cnt->rect_abs.w += ctx->mouse.delta.x;
cnt->rect.w += ctx->mouse.delta.x;
}
// bottom border resize
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)) {
cnt->rect_abs.h += ctx->mouse.delta.y;
cnt->rect.h += ctx->mouse.delta.y;
}
} }
// TODO: what if I want to close a floating container?
// Maybe add a UG_CNT_CLOSABLE flag?
// TODO: what about scrolling? how do we know if we need to draw
// a scroll bar? Maybe add that information inside the
// container structure
} }
if (cnt->flags & UG_CNT_RESIZABLE) {
// right border resize
minx = cnt->rca.x + cnt->rca.w - br;
maxx = cnt->rca.x + cnt->rca.w;
miny = cnt->rca.y;
maxy = cnt->rca.y + cnt->rca.h;
if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) {
cnt->rect.w += ctx->mouse.delta.x;
cnt->rca.w += ctx->mouse.delta.x;
}
// bottom border resize
minx = cnt->rca.x;
maxx = cnt->rca.x + cnt->rca.w;
miny = cnt->rca.y + cnt->rca.h - bb;
maxy = cnt->rca.y + cnt->rca.h;
if (BETWEEN(mpos.x, minx, maxx) && BETWEEN(mpos.y, miny, maxy)) {
cnt->rect.h += ctx->mouse.delta.y;
cnt->rca.h += ctx->mouse.delta.y;
}
}
// TODO: what if I want to close a floating container?
// Maybe add a UG_CNT_CLOSABLE flag?
// TODO: what about scrolling? how do we know if we need to draw
// a scroll bar? Maybe add that information inside the
// container structure
// push the appropriate rectangles to the drawing stack // push the appropriate rectangles to the drawing stack
ug_rect_t draw_rect;
cnt_draw:
// push outline // push outline
draw_rect = cnt->rca; push_rect_command(ctx, &cnt->rect_abs, s->cnt.border.color);
push_rect_command(ctx, &draw_rect, s->cnt.border.color); // push titlebar
ug_rect_t titlebar = {
// titlebar .x = (cnt->rect_abs.x + s->cnt.border.l.size),
if (cnt->flags & UG_CNT_MOVABLE) { .y = (cnt->rect_abs.y + s->cnt.border.t.size),
draw_rect.x += bl; .w = (cnt->rect_abs.w - s->cnt.border.r.size - s->cnt.border.l.size),
draw_rect.y += bt; .h = s->cnt.titlebar.height.size,
draw_rect.w -= bl + br; };
draw_rect.h = hh; push_rect_command(ctx, &titlebar, s->cnt.titlebar.bg_color);
push_rect_command(ctx, &draw_rect, s->cnt.titlebar.bg_color);
}
// push main body // push main body
draw_rect = cnt->rca; ug_rect_t body = {
draw_rect.x += bl; .x = (cnt->rect_abs.x + s->cnt.border.l.size),
draw_rect.y += bt; .y = (cnt->rect_abs.y + s->cnt.border.t.size),
draw_rect.w -= bl + br; .w = (cnt->rect_abs.w - s->cnt.border.l.size - s->cnt.border.r.size),
draw_rect.h -= bt + bb; .h = (cnt->rect_abs.h - s->cnt.border.t.size - s->cnt.border.b.size),
};
if (cnt->flags & UG_CNT_MOVABLE) { if (cnt->flags & UG_CNT_MOVABLE) {
draw_rect.y += bt + hh; body.y += s->cnt.titlebar.height.size + s->cnt.border.t.size;
draw_rect.h -= bt + hh; body.h -= s->cnt.titlebar.height.size + s->cnt.border.t.size;
} }
push_rect_command(ctx, &draw_rect, s->cnt.bg_color); push_rect_command(ctx, &body, s->cnt.bg_color);
// TODO: push other rects // TODO: push other rects
} }
@ -523,7 +528,7 @@ int ug_frame_begin(ug_ctx_t *ctx)
ug_vec2_t v = ctx->mouse.pos; ug_vec2_t v = ctx->mouse.pos;
// printf("mouse: x=%d, y=%d\n", ctx->mouse.pos.x, ctx->mouse.pos.x); // 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++) { for (int i = 0; i < ctx->cnt_stack.idx; i++) {
ug_rect_t r = ctx->cnt_stack.items[i].rca; ug_rect_t r = ctx->cnt_stack.items[i].rect_abs;
if (INTERSECTS(v, r)) { if (INTERSECTS(v, r)) {
ctx->hover.cnt = ctx->cnt_stack.items[i].id; ctx->hover.cnt = ctx->cnt_stack.items[i].id;
// printf("intersects! %.8x\n", ctx->hover.cnt); // printf("intersects! %.8x\n", ctx->hover.cnt);
@ -551,12 +556,6 @@ int ug_frame_end(ug_ctx_t *ctx)
ctx->hover.cnt = 0; ctx->hover.cnt = 0;
ctx->hover.elem = 0; ctx->hover.elem = 0;
ctx->last_ppi = ctx->ppi;
ctx->last_ppm = ctx->ppm;
ctx->last_ppd = ctx->ppd;
ctx->frame++;
return 0; return 0;
} }

17
ugui.h
View File

@ -12,16 +12,10 @@
// basic types // basic types
typedef unsigned int ug_id_t; typedef unsigned int ug_id_t;
typedef struct { union {int x, w;}; union {int y, h;}; } ug_vec2_t; typedef struct { union {int x, w;}; union {int y, h;}; } ug_vec2_t;
typedef struct { int x, y, w, h; } ug_rect_t;
typedef struct { unsigned char a, b, g, r; } ug_color_t; typedef struct { unsigned char a, b, g, r; } ug_color_t;
typedef struct { int size, unit; } ug_size_t; typedef struct { int size, unit; } ug_size_t;
typedef struct {
union { int x; float fx; };
union { int y; float fy; };
union { int w; float fw; };
union { int h; float fh; };
} ug_rect_t;
typedef enum { typedef enum {
UG_UNIT_PX = 0, UG_UNIT_PX = 0,
UG_UNIT_MM, UG_UNIT_MM,
@ -35,9 +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;
// absolute position rect
ug_rect_t rca;
ug_vec2_t max_size; ug_vec2_t max_size;
unsigned int flags; unsigned int flags;
} ug_container_t; } ug_container_t;
@ -134,9 +126,8 @@ typedef struct {
const ug_style_t *style_px; const ug_style_t *style_px;
// ppi: pixels per inch // ppi: pixels per inch
// ppm: pixels per millimeter // ppm: pixels per millimeter
// ppd: pixels per dot // ppd: pixels per dot
float ppi, ppm, ppd; float scale, ppi, ppm, ppd;
float last_ppi, last_ppm, last_ppd;
// containers need to know how big the "main container" is so that all // containers need to know how big the "main container" is so that all
// the relative positioning work // the relative positioning work
ug_vec2_t size; ug_vec2_t size;