diff --git a/test/main.c b/test/main.c index 4897a21..aa0e7fb 100644 --- a/test/main.c +++ b/test/main.c @@ -180,17 +180,18 @@ int main(void) ug_container_floating(ctx, "stupid name", (ug_div_t){.x=SIZE_PX(0), .y=SIZE_PX(0), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); - ug_container_floating(ctx, "floating windoooooooow", - (ug_div_t){.x=SIZE_PX(100), .y=SIZE_PX(0), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); + //ug_container_floating(ctx, "floating windoooooooow", + // (ug_div_t){.x=SIZE_PX(100), .y=SIZE_PX(0), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); ug_container_sidebar(ctx, "Right Sidebar", (ug_size_t)SIZE_PX(300), UG_SIDE_RIGHT); ug_container_sidebar(ctx, "Left Sidebar", (ug_size_t)SIZE_PX(200), UG_SIDE_LEFT); ug_container_sidebar(ctx, "Bottom Sidebar", (ug_size_t)SIZE_MM(10), UG_SIDE_BOTTOM); ug_container_sidebar(ctx, "Top Sidebar", (ug_size_t)SIZE_MM(40), UG_SIDE_TOP); - ug_container_floating(ctx, "stupid er", - (ug_div_t){.x=SIZE_PX(150), .y=SIZE_PX(-100), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); - + //ug_container_floating(ctx, "stupid er", + // (ug_div_t){.x=SIZE_PX(150), .y=SIZE_PX(-100), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); + ug_container_popup(ctx, "Annoying popup", (ug_div_t){.x=SIZE_MM(150), .y=SIZE_MM(150), .w=SIZE_PX(100), .h=SIZE_MM(75.0)}); + ug_container_body(ctx, "Main Body"); if (ug_container_body(ctx, "Other Body")) printf("No space!\n"); diff --git a/ugui.c b/ugui.c index 0956c72..3f3bbe3 100644 --- a/ugui.c +++ b/ugui.c @@ -60,7 +60,7 @@ static const ug_style_t default_style = { .bg_color = RGB_FORMAT(0x0000ff), .border.t = SIZE_PX(3), .border.b = SIZE_PX(3), - .border.l = SIZE_PX(10), + .border.l = SIZE_PX(3), .border.r = SIZE_PX(3), .border.color = RGB_FORMAT(0x00ff00), .titlebar.height = SIZE_PX(20), @@ -97,6 +97,17 @@ static ug_style_t style_cache = {0}; } +#define DELETE_FROM_STACK(S, c) \ +{ \ + for (int i = 0; i < S.idx; i++) { \ + if (c->id != S.items[i].id) \ + continue; \ + memmove(&S.items[i], &S.items[i+1], (S.idx-i)*sizeof(S.items[0])); \ + memset(&S.items[S.idx--], 0, sizeof(S.items[0])); \ + } \ +} + + #define RESET_STACK(S) \ { \ memset(S.items, 0, S.idx*sizeof(*(S.items))); \ @@ -140,7 +151,6 @@ int size_to_px(ug_ctx_t *ctx, ug_size_t s) } } - ug_rect_t div_to_rect(ug_ctx_t *ctx, ug_div_t *div) { ug_rect_t r; @@ -211,12 +221,15 @@ void ug_ctx_free(ug_ctx_t *ctx) free(ctx); - // NOTE: do not free style since the default is statically allocated, let - // the user take care of it instead + // NOTE: do not free style since the default style is statically allocated, + // let the user take care of it instead } +// TODO: add error codes #define TEST_CTX(ctx) { if (!ctx) return -1; } +#define TEST_STR(s) { if (!s || !s[0]) return -1; } + int ug_ctx_set_displayinfo(ug_ctx_t *ctx, float scale, float ppi) { @@ -327,6 +340,11 @@ static void sort_containers(ug_ctx_t *ctx) // update the container position in the context area static int position_container(ug_ctx_t *ctx, ug_container_t *cnt) { + if (!TEST(cnt->flags, UG_CNT_FLOATING)) + // if there is no space left propagate the error + if (ctx->origin.w <= 0 || ctx->origin.h <= 0) + return -1; + ug_rect_t *rect, *rca; rect = &cnt->rect; rca = &cnt->rca; @@ -387,16 +405,13 @@ static int position_container(ug_ctx_t *ctx, ug_container_t *cnt) if (rect->w == 0) rca->w = cw; else rca->w += bl + br; if (rect->h == 0) rca->h = ch; - else if (TEST(cnt->flags, UG_CNT_FLOATING)) rca->h += hh + 2*bt + bb; + else if (TEST(cnt->flags, UG_CNT_MOVABLE)) rca->h += hh + 2*bt + bb; else rca->h += bt + bb; // if the container is not fixed than it can have positions outside of the // main window, thus negative if (!TEST(cnt->flags, UG_CNT_FLOATING)) { - // if there is no space left propagate the error - if (!ctx->origin.w || !ctx->origin.h) - return -1; // <0 -> relative to the right margin if (rect->x < 0) rca->x = cx + cw - rca->w + rca->x + 1; else rca->x = cx; @@ -420,21 +435,24 @@ static int position_container(ug_ctx_t *ctx, ug_container_t *cnt) } -void handle_container(ug_ctx_t *ctx, ug_container_t *cnt) +// TODO: make a set of fixed return values for the different states +// handle moving and resizing, return 1 if it had focus, 0 otherwise, negative +// return values represent errors +static int handle_container(ug_ctx_t *ctx, ug_container_t *cnt) { // if we are not the currently active container than definately we are not // being moved or resized if (ctx->active.cnt != cnt->id) { cnt->flags &= ~CNT_STATE_ALL; - return; + return 0; } // mouse pressed handle resize, for simplicity containers can only // be resized from the bottom and right border - // TODO: bring selected container to the top of the stack + // TODO: change return value to indicate this case if (!HELD(ctx, UG_BTN_LEFT) || - !TEST(cnt->flags, (RESIZEALL | UG_CNT_FLOATING))) - return; + !TEST(cnt->flags, (RESIZEALL | UG_CNT_MOVABLE))) + return 1; ug_rect_t *rect, *rca; rect = &cnt->rect; @@ -451,7 +469,7 @@ void handle_container(ug_ctx_t *ctx, ug_container_t *cnt) int minx, maxx, miny, maxy; // handle movable windows - if (TEST(cnt->flags, UG_CNT_FLOATING)) { + if (TEST(cnt->flags, UG_CNT_MOVABLE)) { minx = rca->x + bl; maxx = rca->x + rca->w - br; miny = rca->y + bt; @@ -498,7 +516,7 @@ void handle_container(ug_ctx_t *ctx, ug_container_t *cnt) if (rect->w - ctx->mouse.delta.x >= 10) { rect->w -= ctx->mouse.delta.x; - if (TEST(cnt->flags, UG_CNT_FLOATING)) + if (TEST(cnt->flags, UG_CNT_MOVABLE)) rect->x += ctx->mouse.delta.x; } if (rca->w - ctx->mouse.delta.x >= 10) { @@ -538,7 +556,7 @@ void handle_container(ug_ctx_t *ctx, ug_container_t *cnt) if (rect->h - ctx->mouse.delta.y >= 10) { rect->h -= ctx->mouse.delta.y; - if (TEST(cnt->flags, UG_CNT_FLOATING)) + if (TEST(cnt->flags, UG_CNT_MOVABLE)) rect->y += ctx->mouse.delta.y; } if (rca->h - ctx->mouse.delta.y >= 10) { @@ -559,8 +577,7 @@ void handle_container(ug_ctx_t *ctx, ug_container_t *cnt) // 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 + return 1; } @@ -579,7 +596,7 @@ void draw_container(ug_ctx_t *ctx, ug_container_t *cnt) push_rect_command(ctx, &draw_rect, s->cnt.border.color); // titlebar - if (cnt->flags & UG_CNT_FLOATING) { + if (TEST(cnt->flags, UG_CNT_MOVABLE)) { draw_rect.x += bl; draw_rect.y += bt; draw_rect.w -= bl + br; @@ -593,7 +610,7 @@ void draw_container(ug_ctx_t *ctx, ug_container_t *cnt) draw_rect.y += bt; draw_rect.w -= bl + br; draw_rect.h -= bt + bb; - if (cnt->flags & UG_CNT_FLOATING) { + if (TEST(cnt->flags, UG_CNT_MOVABLE)) { draw_rect.y += bt + hh; draw_rect.h -= bt + hh; } @@ -607,9 +624,10 @@ void draw_container(ug_ctx_t *ctx, ug_container_t *cnt) int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div) { TEST_CTX(ctx); + TEST_STR(name); // TODO: verify div - ug_id_t id = name ? hash(name, strlen(name)) : hash(&div, sizeof(ug_div_t)); + ug_id_t id = hash(name, strlen(name)); ug_container_t *cnt = get_container(ctx, id); if (cnt->id) { @@ -618,32 +636,54 @@ int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div) cnt->id = id; cnt->max_size = max_size; cnt->rect = div_to_rect(ctx, &div); - cnt->flags = UG_CNT_FLOATING | RESIZEALL | - UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y ; + cnt->flags = UG_CNT_FLOATING | RESIZEALL | UG_CNT_MOVABLE | + UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y; } // TODO: what about error codes and meaning? - if (position_container(ctx, cnt)) + if (position_container(ctx, cnt)) { + DELETE_FROM_STACK(ctx->cnt_stack, cnt); return -1; - handle_container(ctx, cnt); - - return 0; + } + return handle_container(ctx, cnt); } -int ug_container_sidebar(ug_ctx_t *ctx, const char *name, ug_size_t size, int side) +int ug_container_popup(ug_ctx_t *ctx, const char *name, ug_div_t div) { TEST_CTX(ctx); + TEST_STR(name); + // TODO: verify div - ug_id_t id = 0; - if (name) { - id = hash(name, strlen(name)); + ug_id_t id = hash(name, strlen(name)); + ug_container_t *cnt = get_container(ctx, id); + + if (cnt->id) { + // nothing? maybe we can skip updating all dimensions and stuff } else { - int blob[3] = { size.size.i, size.unit, side}; - id = hash(blob, sizeof(blob)); + cnt->id = id; + cnt->max_size = max_size; + cnt->rect = div_to_rect(ctx, &div); + cnt->flags = UG_CNT_FLOATING; } + // TODO: what about error codes and meaning? + if (position_container(ctx, cnt)) { + DELETE_FROM_STACK(ctx->cnt_stack, cnt); + return -1; + } + return handle_container(ctx, cnt); +} + + +int ug_container_sidebar(ug_ctx_t *ctx, const char *name, ug_size_t size, int side) +{ + TEST_CTX(ctx); + TEST_STR(name); + + ug_id_t id = hash(name, strlen(name)); ug_container_t *cnt = get_container(ctx, id); + if (cnt->id) { // nothing? maybe we can skip updating all dimensions and stuff @@ -677,25 +717,19 @@ int ug_container_sidebar(ug_ctx_t *ctx, const char *name, ug_size_t size, int si cnt->rect = rect; } - if (position_container(ctx, cnt)) + if (position_container(ctx, cnt)) { + DELETE_FROM_STACK(ctx->cnt_stack, cnt); return -1; - handle_container(ctx, cnt); - - return 0; + } + return handle_container(ctx, cnt); } int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height) { TEST_CTX(ctx); + TEST_STR(name); - ug_id_t id = 0; - if (name) { - id = hash(name, strlen(name)); - } else { - int blob[2] = { height.size.i, height.unit}; - id = hash(blob, sizeof(blob)); - } - + ug_id_t id = hash(name, strlen(name)); ug_container_t *cnt = get_container(ctx, id); if (cnt->id) { @@ -711,26 +745,20 @@ int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height) cnt->rect = rect; } - if (position_container(ctx, cnt)) + if (position_container(ctx, cnt)) { + DELETE_FROM_STACK(ctx->cnt_stack, cnt); return -1; - handle_container(ctx, cnt); - - return 0; + } + return handle_container(ctx, cnt); } int ug_container_body(ug_ctx_t *ctx, const char *name) { TEST_CTX(ctx); + TEST_STR(name); - ug_id_t id = 0; - if (name) { - id = hash(name, strlen(name)); - } else { - // sorry but body must have a name - return -1; - } - + ug_id_t id = hash(name, strlen(name)); ug_container_t *cnt = get_container(ctx, id); if (cnt->id) { @@ -742,11 +770,11 @@ int ug_container_body(ug_ctx_t *ctx, const char *name) cnt->rect = (ug_rect_t){0}; } - if (position_container(ctx, cnt)) + if (position_container(ctx, cnt)) { + DELETE_FROM_STACK(ctx->cnt_stack, cnt); return -1; - handle_container(ctx, cnt); - - return 0; + } + return handle_container(ctx, cnt); } diff --git a/ugui.h b/ugui.h index 8347539..a4fd317 100644 --- a/ugui.h +++ b/ugui.h @@ -39,13 +39,14 @@ typedef struct { // the container flags enum { - UG_CNT_FLOATING = BIT(0), // can be moved - UG_CNT_RESIZE_RIGHT = BIT(1), // can be resized - UG_CNT_RESIZE_BOTTOM = BIT(2), // can be resized - UG_CNT_RESIZE_LEFT = BIT(3), // can be resized - UG_CNT_RESIZE_TOP = BIT(4), // can be resized + UG_CNT_FLOATING = BIT(0), // is on top of everything else + UG_CNT_RESIZE_RIGHT = BIT(1), // can be resized from the right border + UG_CNT_RESIZE_BOTTOM = BIT(2), // can be resized from the bottom border + UG_CNT_RESIZE_LEFT = BIT(3), // can be resized from the left border + UG_CNT_RESIZE_TOP = BIT(4), // can be resized from the top border UG_CNT_SCROLL_X = BIT(5), // can have horizontal scrolling UG_CNT_SCROLL_Y = BIT(6), // can have vertical scrolling + UG_CNT_MOVABLE = BIT(7), // can be moved around // container state CNT_STATE_NONE = BIT(30), CNT_STATE_MOVING = BIT(29), @@ -53,6 +54,7 @@ enum { CNT_STATE_RESIZE_B = BIT(27), CNT_STATE_RESIZE_L = BIT(26), CNT_STATE_RESIZE_R = BIT(25), + CNT_STATE_DELETE = BIT(24), // The container is marked for removal }; // style, defines default height, width, color, margins, borders, etc @@ -210,7 +212,7 @@ int ug_ctx_set_style(ug_ctx_t *ctx, const ug_style_t *style); // window inside another window int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div); // like a floating container but cannot be resized -int ug_container_popup(ug_ctx_t *ctx, const char *name, ug_rect_t rect); +int ug_container_popup(ug_ctx_t *ctx, const char *name, ug_div_t div); // a menu bar is a container of fixed height, cannot be resized and sits at the // top of the window int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height);