- remove containers from stack when there is no space
- handle containers now returns nonzero when the conatiner is in focus
- container names are now required
master
Alessandro Mauri 2 years ago
parent 46c5de8dcb
commit 7fb9d225a0
  1. 9
      test/main.c
  2. 150
      ugui.c
  3. 14
      ugui.h

@ -180,16 +180,17 @@ int main(void)
ug_container_floating(ctx, "stupid name", 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_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_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_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, "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, "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, "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_sidebar(ctx, "Top Sidebar", (ug_size_t)SIZE_MM(40), UG_SIDE_TOP);
ug_container_floating(ctx, "stupid er", //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_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"); ug_container_body(ctx, "Main Body");
if (ug_container_body(ctx, "Other Body")) if (ug_container_body(ctx, "Other Body"))

150
ugui.c

@ -60,7 +60,7 @@ static const ug_style_t default_style = {
.bg_color = RGB_FORMAT(0x0000ff), .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(10), .border.l = SIZE_PX(3),
.border.r = SIZE_PX(3), .border.r = SIZE_PX(3),
.border.color = RGB_FORMAT(0x00ff00), .border.color = RGB_FORMAT(0x00ff00),
.titlebar.height = SIZE_PX(20), .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) \ #define RESET_STACK(S) \
{ \ { \
memset(S.items, 0, S.idx*sizeof(*(S.items))); \ 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 div_to_rect(ug_ctx_t *ctx, ug_div_t *div)
{ {
ug_rect_t r; ug_rect_t r;
@ -211,12 +221,15 @@ void ug_ctx_free(ug_ctx_t *ctx)
free(ctx); free(ctx);
// NOTE: do not free style since the default is statically allocated, let // NOTE: do not free style since the default style is statically allocated,
// the user take care of it instead // let the user take care of it instead
} }
// TODO: add error codes
#define TEST_CTX(ctx) { if (!ctx) return -1; } #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) 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 // update the container position in the context area
static int position_container(ug_ctx_t *ctx, ug_container_t *cnt) 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; ug_rect_t *rect, *rca;
rect = &cnt->rect; rect = &cnt->rect;
rca = &cnt->rca; 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; if (rect->w == 0) rca->w = cw;
else rca->w += bl + br; else rca->w += bl + br;
if (rect->h == 0) rca->h = ch; 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; else rca->h += bt + bb;
// if the container is not fixed than it can have positions outside of the // if the container is not fixed than it can have positions outside of the
// main window, thus negative // main window, thus negative
if (!TEST(cnt->flags, UG_CNT_FLOATING)) { 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 // <0 -> relative to the right margin
if (rect->x < 0) rca->x = cx + cw - rca->w + rca->x + 1; if (rect->x < 0) rca->x = cx + cw - rca->w + rca->x + 1;
else rca->x = cx; 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 // if we are not the currently active container than definately we are not
// being moved or resized // being moved or resized
if (ctx->active.cnt != cnt->id) { if (ctx->active.cnt != cnt->id) {
cnt->flags &= ~CNT_STATE_ALL; cnt->flags &= ~CNT_STATE_ALL;
return; return 0;
} }
// 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
// TODO: bring selected container to the top of the stack // TODO: change return value to indicate this case
if (!HELD(ctx, UG_BTN_LEFT) || if (!HELD(ctx, UG_BTN_LEFT) ||
!TEST(cnt->flags, (RESIZEALL | UG_CNT_FLOATING))) !TEST(cnt->flags, (RESIZEALL | UG_CNT_MOVABLE)))
return; return 1;
ug_rect_t *rect, *rca; ug_rect_t *rect, *rca;
rect = &cnt->rect; rect = &cnt->rect;
@ -451,7 +469,7 @@ void handle_container(ug_ctx_t *ctx, ug_container_t *cnt)
int minx, maxx, miny, maxy; int minx, maxx, miny, maxy;
// handle movable windows // handle movable windows
if (TEST(cnt->flags, UG_CNT_FLOATING)) { if (TEST(cnt->flags, UG_CNT_MOVABLE)) {
minx = rca->x + bl; minx = rca->x + bl;
maxx = rca->x + rca->w - br; maxx = rca->x + rca->w - br;
miny = rca->y + bt; 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) { if (rect->w - ctx->mouse.delta.x >= 10) {
rect->w -= ctx->mouse.delta.x; 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; rect->x += ctx->mouse.delta.x;
} }
if (rca->w - ctx->mouse.delta.x >= 10) { 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) { if (rect->h - ctx->mouse.delta.y >= 10) {
rect->h -= ctx->mouse.delta.y; 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; rect->y += ctx->mouse.delta.y;
} }
if (rca->h - ctx->mouse.delta.y >= 10) { 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 // TODO: what about scrolling? how do we know if we need to draw
// a scroll bar? Maybe add that information inside the // a scroll bar? Maybe add that information inside the
// container structure // container structure
return 1;
// push the appropriate rectangles to the drawing stack
} }
@ -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); push_rect_command(ctx, &draw_rect, s->cnt.border.color);
// titlebar // titlebar
if (cnt->flags & UG_CNT_FLOATING) { if (TEST(cnt->flags, UG_CNT_MOVABLE)) {
draw_rect.x += bl; draw_rect.x += bl;
draw_rect.y += bt; draw_rect.y += bt;
draw_rect.w -= bl + br; 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.y += bt;
draw_rect.w -= bl + br; draw_rect.w -= bl + br;
draw_rect.h -= bt + bb; 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.y += bt + hh;
draw_rect.h -= 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) int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div)
{ {
TEST_CTX(ctx); TEST_CTX(ctx);
TEST_STR(name);
// TODO: verify div // 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); ug_container_t *cnt = get_container(ctx, id);
if (cnt->id) { if (cnt->id) {
@ -618,33 +636,55 @@ int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div)
cnt->id = id; cnt->id = id;
cnt->max_size = max_size; cnt->max_size = max_size;
cnt->rect = div_to_rect(ctx, &div); cnt->rect = div_to_rect(ctx, &div);
cnt->flags = UG_CNT_FLOATING | RESIZEALL | cnt->flags = UG_CNT_FLOATING | RESIZEALL | UG_CNT_MOVABLE |
UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y ; UG_CNT_SCROLL_X | UG_CNT_SCROLL_Y;
} }
// TODO: what about error codes and meaning? // 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; return -1;
handle_container(ctx, cnt); }
return handle_container(ctx, cnt);
return 0;
} }
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_CTX(ctx);
TEST_STR(name);
// TODO: verify div
ug_id_t id = 0; ug_id_t id = hash(name, strlen(name));
if (name) { ug_container_t *cnt = get_container(ctx, id);
id = hash(name, strlen(name));
if (cnt->id) {
// nothing? maybe we can skip updating all dimensions and stuff
} else { } else {
int blob[3] = { size.size.i, size.unit, side}; cnt->id = id;
id = hash(blob, sizeof(blob)); 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); ug_container_t *cnt = get_container(ctx, id);
if (cnt->id) { if (cnt->id) {
// nothing? maybe we can skip updating all dimensions and stuff // nothing? maybe we can skip updating all dimensions and stuff
} else { } else {
@ -677,25 +717,19 @@ int ug_container_sidebar(ug_ctx_t *ctx, const char *name, ug_size_t size, int si
cnt->rect = rect; cnt->rect = rect;
} }
if (position_container(ctx, cnt)) if (position_container(ctx, cnt)) {
DELETE_FROM_STACK(ctx->cnt_stack, cnt);
return -1; return -1;
handle_container(ctx, cnt); }
return handle_container(ctx, cnt);
return 0;
} }
int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height) int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height)
{ {
TEST_CTX(ctx); TEST_CTX(ctx);
TEST_STR(name);
ug_id_t id = 0; ug_id_t id = hash(name, strlen(name));
if (name) {
id = hash(name, strlen(name));
} else {
int blob[2] = { height.size.i, height.unit};
id = hash(blob, sizeof(blob));
}
ug_container_t *cnt = get_container(ctx, id); ug_container_t *cnt = get_container(ctx, id);
if (cnt->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; cnt->rect = rect;
} }
if (position_container(ctx, cnt)) if (position_container(ctx, cnt)) {
DELETE_FROM_STACK(ctx->cnt_stack, cnt);
return -1; return -1;
handle_container(ctx, cnt); }
return handle_container(ctx, cnt);
return 0;
} }
int ug_container_body(ug_ctx_t *ctx, const char *name) int ug_container_body(ug_ctx_t *ctx, const char *name)
{ {
TEST_CTX(ctx); TEST_CTX(ctx);
TEST_STR(name);
ug_id_t id = 0; ug_id_t id = hash(name, strlen(name));
if (name) {
id = hash(name, strlen(name));
} else {
// sorry but body must have a name
return -1;
}
ug_container_t *cnt = get_container(ctx, id); ug_container_t *cnt = get_container(ctx, id);
if (cnt->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}; 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; return -1;
handle_container(ctx, cnt); }
return handle_container(ctx, cnt);
return 0;
} }

@ -39,13 +39,14 @@ typedef struct {
// the container flags // the container flags
enum { enum {
UG_CNT_FLOATING = BIT(0), // can be moved UG_CNT_FLOATING = BIT(0), // is on top of everything else
UG_CNT_RESIZE_RIGHT = BIT(1), // can be resized UG_CNT_RESIZE_RIGHT = BIT(1), // can be resized from the right border
UG_CNT_RESIZE_BOTTOM = BIT(2), // can be resized UG_CNT_RESIZE_BOTTOM = BIT(2), // can be resized from the bottom border
UG_CNT_RESIZE_LEFT = BIT(3), // can be resized UG_CNT_RESIZE_LEFT = BIT(3), // can be resized from the left border
UG_CNT_RESIZE_TOP = BIT(4), // can be resized 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_X = BIT(5), // can have horizontal scrolling
UG_CNT_SCROLL_Y = BIT(6), // can have vertical scrolling UG_CNT_SCROLL_Y = BIT(6), // can have vertical scrolling
UG_CNT_MOVABLE = BIT(7), // can be moved around
// container state // container state
CNT_STATE_NONE = BIT(30), CNT_STATE_NONE = BIT(30),
CNT_STATE_MOVING = BIT(29), CNT_STATE_MOVING = BIT(29),
@ -53,6 +54,7 @@ enum {
CNT_STATE_RESIZE_B = BIT(27), CNT_STATE_RESIZE_B = BIT(27),
CNT_STATE_RESIZE_L = BIT(26), CNT_STATE_RESIZE_L = BIT(26),
CNT_STATE_RESIZE_R = BIT(25), 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 // 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 // window inside another window
int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div); int ug_container_floating(ug_ctx_t *ctx, const char *name, ug_div_t div);
// like a floating container but cannot be resized // 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 // a menu bar is a container of fixed height, cannot be resized and sits at the
// top of the window // top of the window
int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height); int ug_container_menu_bar(ug_ctx_t *ctx, const char *name, ug_size_t height);

Loading…
Cancel
Save