From ba54900852f1f1283a2e110c38e72c8ad3bc7e30 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Wed, 7 Dec 2022 18:35:59 +0100 Subject: [PATCH] working mm units --- test/Makefile | 2 +- test/main.c | 32 ++++++--- ugui.c | 194 +++++++++++++++++++++++--------------------------- ugui.h | 12 +++- 4 files changed, 121 insertions(+), 119 deletions(-) diff --git a/test/Makefile b/test/Makefile index 7df0c19..577a91f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,5 +1,5 @@ CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g -LDFLAGS = -lSDL2 +LDFLAGS = -lSDL2 -lm test: main.c ../ugui.c ../ugui.h gcc ${CFLAGS} -c ../ugui.c -o ugui.o diff --git a/test/main.c b/test/main.c index 058f932..f1a74ca 100644 --- a/test/main.c +++ b/test/main.c @@ -3,6 +3,13 @@ #include "../ugui.h" + +SDL_Window *w; +SDL_Renderer *r; +ug_ctx_t *ctx; + +void cleanup(void); + int main(void) { SDL_DisplayMode dm; @@ -22,7 +29,6 @@ int main(void) 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, @@ -31,7 +37,6 @@ int main(void) //SDL_Surface *s; //s = SDL_GetWindowSurface(w); - SDL_Renderer *r; r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED); @@ -47,11 +52,13 @@ int main(void) SDL_GetDisplayDPI(idx, &dpi, NULL, NULL); - ug_ctx_t *ctx = ug_ctx_new(); + ctx = ug_ctx_new(); ug_ctx_set_displayinfo(ctx, scale, dpi); ug_ctx_set_drawableregion(ctx, dsize); +// atexit(cleanup); + SDL_Event event; char button_map[] = { @@ -168,10 +175,11 @@ int main(void) ug_frame_begin(ctx); + ug_ctx_set_unit(ctx, UG_UNIT_MM); ug_container_floating(ctx, "stupid name", - (ug_rect_t){.x = 0, .y = 0, .w = 100, .h = 300}); + (ug_rect_t){.fx = 0, .fy = 0, .fw = 50, .fh = 50}); ug_container_floating(ctx, "better name", - (ug_rect_t){.x = -20, .y = -10, .w = 100, .h = 200}); + (ug_rect_t){.fx = -20, .fy = -10, .fw = 100, .fh = 30}); ug_frame_end(ctx); @@ -187,8 +195,8 @@ int main(void) .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)); + //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); } @@ -198,11 +206,15 @@ int main(void) } while (event.type != SDL_QUIT); + cleanup(); - ug_ctx_free(ctx); + return 0; +} +void cleanup(void) +{ + 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 affe126..d35268e 100644 --- a/ugui.c +++ b/ugui.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "ugui.h" @@ -112,30 +113,6 @@ 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) { ug_cmd_t *c; @@ -162,14 +139,10 @@ ug_ctx_t *ug_ctx_new(void) err(errno, "__FUNCTION__:" "Could not allocate context: %s", strerror(errno)); 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->style = &default_style; ctx->style_px = &style_cache; + ug_ctx_set_displayinfo(ctx, DEF_SCALE, DEF_PPI); // TODO: allocate stacks return ctx; @@ -203,7 +176,6 @@ int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi) ctx->ppm = PPI_PPM(scale, ppi); ctx->ppd = PPI_PPM(scale, ppi); - ctx->scale = scale; ctx->ppi = ppi; update_style_cache(ctx); @@ -281,20 +253,21 @@ static ug_container_t *get_container(ug_ctx_t *ctx, ug_id_t id) // also handle resizing, moving, ect. if allowed by the container static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) { - // 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) { - // FIXME: this takes the unit from the context but it should be fine - cnt->rect = rect_to_px(ctx, cnt->rect); - cnt->unit = UG_UNIT_PX; + // use millimeters as common screen-relative units + if (cnt->unit == UG_UNIT_PT) { + cnt->rect.fx *= ctx->ppd; + cnt->rect.fy *= ctx->ppd; + cnt->rect.fw *= ctx->ppd; + cnt->rect.fh *= ctx->ppd; } // 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; + if (cnt->unit != UG_UNIT_PX) { + cnt->rect_abs.x = roundf(cnt->rect.fx * ctx->ppm); + cnt->rect_abs.y = roundf(cnt->rect.fy * ctx->ppm); + cnt->rect_abs.w = roundf(cnt->rect.fw * ctx->ppm); + cnt->rect_abs.h = roundf(cnt->rect.fh * ctx->ppm); + } /* * Container style: @@ -349,7 +322,6 @@ static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) // the window may have been resized so cap the position to the window size - printf("window size: w=%d, h=%d\n", ctx->size.x, ctx->size.y); if (cnt->rect_abs.x > ctx->size.w) cnt->rect_abs.x = ctx->size.x - cnt->rect_abs.w; if (cnt->rect_abs.y > ctx->size.h) @@ -364,73 +336,85 @@ static void update_container(ug_ctx_t *ctx, ug_container_t *cnt) // 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_last == cnt->id) { - // mouse pressed handle resize, for simplicity containers can only - // be resized from the bottom and right border - -//#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 = cnt->rect_abs.x; - maxx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.l.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)) { - 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; - CAP(cnt->rect_abs.w, 0); - CAP(cnt->rect.w, 0); - } - - // 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; - CAP(cnt->rect_abs.h, s->text.size.size); - CAP(cnt->rect.h, s->text.size.size); - } + if (ctx->hover.cnt_last != cnt->id) + goto cnt_draw; + + // mouse pressed handle resize, for simplicity containers can only + // be resized from the bottom and right border + if (!(ctx->mouse.down_mask & UG_BTN_LEFT) || + !(cnt->flags & (UG_CNT_RESIZABLE | UG_CNT_MOVABLE))) + goto cnt_draw; + + ug_vec2_t mpos = ctx->mouse.pos; + int minx, maxx, miny, maxy; + int delta_x = 0, delta_y = 0, delta_w = 0, delta_h = 0; + + // handle movable windows + if (cnt->flags & UG_CNT_MOVABLE) { + minx = cnt->rect_abs.x; + maxx = cnt->rect_abs.x + cnt->rect_abs.w - s->cnt.border.l.size; + miny = cnt->rect_abs.y; + maxy = cnt->rect_abs.y + s->cnt.titlebar.height.size; + if (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; + + delta_x = ctx->mouse.delta.x; + delta_y = 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->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; + CAP(cnt->rect_abs.w, 0); + + delta_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; + CAP(cnt->rect_abs.h, s->text.size.size); + + delta_h = ctx->mouse.delta.y; + } } + if (delta_x || delta_y || delta_w || delta_h) { + if (cnt->unit == UG_UNIT_PX) { + cnt->rect = cnt->rect_abs; + } else { + if (cnt->rect.fx < 0) + cnt->rect.fx = cnt->rect_abs.x / ctx->ppm; + if (cnt->rect.fy < 0) + cnt->rect.fy = cnt->rect_abs.y / ctx->ppm; + cnt->rect.fx += delta_x / ctx->ppm; + cnt->rect.fy += delta_y / ctx->ppm; + cnt->rect.fw += delta_w / ctx->ppm; + cnt->rect.fh += delta_h / ctx->ppm; + } + } + + // 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 + + cnt_draw: // push the appropriate rectangles to the drawing stack // push outline push_rect_command(ctx, &cnt->rect_abs, s->cnt.border.color); diff --git a/ugui.h b/ugui.h index 7a86d34..1ba2eab 100644 --- a/ugui.h +++ b/ugui.h @@ -12,10 +12,16 @@ // basic types typedef unsigned int ug_id_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 { 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 { UG_UNIT_PX = 0, UG_UNIT_MM, @@ -126,8 +132,8 @@ typedef struct { const ug_style_t *style_px; // ppi: pixels per inch // ppm: pixels per millimeter - // ppd: pixels per dot - float scale, ppi, ppm, ppd; + // ppd: pixels per dot + float ppi, ppm, ppd; // containers need to know how big the "main container" is so that all // the relative positioning work ug_vec2_t size;