diff --git a/include/ui.h b/include/ui.h index b537e0d..75a3a1f 100644 --- a/include/ui.h +++ b/include/ui.h @@ -38,10 +38,16 @@ struct ui_elem_colours { colour border; }; +typedef struct ui_noodle_elem ui_noodle_elem; +struct ui_noodle_elem { + line noodle; + u64 connected_node; +}; + typedef struct ui_node_elem ui_node_elem; struct ui_node_elem { rect rec; - line *noodles; + ui_noodle_elem *noodles; u64 inputs; }; diff --git a/src/compositor.c b/src/compositor.c index 1b68dd7..c2cfa02 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -181,7 +181,8 @@ void add_node(compositor *comp, node_type type, node_data data, u64 inputs, return; } - line *noodles = mem_arena_alloc(comp->arena, inputs * sizeof(line)); + u64 alloc_size = inputs * sizeof(ui_noodle_elem); + ui_noodle_elem *noodles = mem_arena_alloc(comp->arena, alloc_size); if (!noodles) { return; } diff --git a/src/ui.c b/src/ui.c index 9390f65..e44c19d 100644 --- a/src/ui.c +++ b/src/ui.c @@ -10,8 +10,10 @@ #define NOODLE_HALF_WIDTH 2 #define DEFAULT_NOODLE_LENGTH 60 -internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln, - ui_elem_colours colours, rect node); +internal u64 get_id(ui_ctx *ctx); +internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx, + ui_noodle_elem noodle, + ui_elem_colours colours, u64 parent_id); internal bool aabb(rect rec, i32 x, i32 y); internal line line_from_origin(point origin, f64 angle, i32 line_length); @@ -68,7 +70,7 @@ bool ui_button(const window *wnd, ui_ctx *ctx, rect rec, return false; } - u64 id = (ctx->count)++; + u64 id = get_id(ctx); ctx->elements[id] = (ui_elem){ .id = id, .rect = rec, @@ -106,14 +108,13 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, return (ui_node_elem){0}; } - u64 id = (ctx->count)++; + u64 id = get_id(ctx); ctx->elements[id] = (ui_elem){ .id = id, .rect = node.rec, .type = UI_ELEM_NODE, }; - line ln = {0}; f64 angle = 90.0; f64 angle_delta = 25.0; i64 delta_multiplier = node.inputs % 2 == 0 ? -1 : 0; @@ -121,17 +122,18 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, for (u64 i = 0; i < node.inputs; ++i) { f64 new_angle = angle + angle_delta * delta_multiplier; - if (node.noodles[i].p0.x == node.noodles[i].p1.x && - node.noodles[i].p0.y == node.noodles[i].p1.y) { + if (node.noodles[i].noodle.p0.x == node.noodles[i].noodle.p1.x && + node.noodles[i].noodle.p0.y == node.noodles[i].noodle.p1.y) { point origin = {node.rec.topleft.x + node.rec.w / 2, node.rec.topleft.y + node.rec.h / 2}; - ln = line_from_origin(origin, new_angle, DEFAULT_NOODLE_LENGTH); + node.noodles[i].noodle = + line_from_origin(origin, new_angle, DEFAULT_NOODLE_LENGTH); } else { - ln = node.noodles[i]; + node.noodles[i].noodle = node.noodles[i].noodle; } - node.noodles[i] = ui_noodle(wnd, ctx, ln, colours, node.rec); + node.noodles[i] = ui_noodle(wnd, ctx, node.noodles[i], colours, id); if (delta_multiplier > 0) { angle = new_angle; @@ -152,8 +154,10 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, } if (ctx->mouse_up) { - ctx->hovered = ctx->active = -1; - ctx->rel_x = ctx->rel_y = 0; + if (ctx->hovered == ctx->active && ctx->hovered == id) { + ctx->hovered = ctx->active = -1; + } + return node; } @@ -162,10 +166,13 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, node.rec.topleft.y += ctx->rel_y; for (u64 i = 0; i < node.inputs; ++i) { - node.noodles[i].p0.x += ctx->rel_x; - node.noodles[i].p0.y += ctx->rel_y; - node.noodles[i].p1.x += ctx->rel_x; - node.noodles[i].p1.y += ctx->rel_y; + if (node.noodles[i].connected_node == 0) { + node.noodles[i].noodle.p0.x += ctx->rel_x; + node.noodles[i].noodle.p0.y += ctx->rel_y; + } + + node.noodles[i].noodle.p1.x += ctx->rel_x; + node.noodles[i].noodle.p1.y += ctx->rel_y; } return node; @@ -184,42 +191,52 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, return node; } -internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln, - ui_elem_colours colours, rect node) { +internal u64 get_id(ui_ctx *ctx) { + // This will always keep the 0 slot empty + return ++(ctx->count); +} + +internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx, + ui_noodle_elem noodle, + ui_elem_colours colours, u64 parent_id) { if (ctx->count + 1 >= MAX_UI_ELEMENTS) { - return (line){0}; + return (ui_noodle_elem){0}; } - u64 id = (ctx->count)++; + u64 id = get_id(ctx); ctx->elements[id] = (ui_elem){ .id = id, .rect = (rect){0}, .type = UI_ELEM_NOODLE, }; - bool horizontal = ln.p0.y == ln.p1.y; + bool horizontal = noodle.noodle.p0.y == noodle.noodle.p1.y; rect bounding_box = (rect){0}; if (horizontal) { - i32 x = min(ln.p0.x, ln.p1.x); + i32 x = min(noodle.noodle.p0.x, noodle.noodle.p1.x); - bounding_box.topleft = (point){x, ln.p0.y - NOODLE_HALF_WIDTH}; - bounding_box.w = abs(ln.p1.x - ln.p0.x); + bounding_box.topleft = (point){x, noodle.noodle.p0.y - NOODLE_HALF_WIDTH}; + bounding_box.w = abs(noodle.noodle.p1.x - noodle.noodle.p0.x); bounding_box.h = NOODLE_HALF_WIDTH * 2; fill_rect(wnd, bounding_box, colours.fill); } else { - vec2 direction = line_direction(&ln); + vec2 direction = line_direction(&noodle.noodle); quad qd = (quad){0}; if (direction.x == 0) { qd = (quad){ - .p0 = (point){ln.p0.x - NOODLE_HALF_WIDTH, ln.p0.y}, - .p1 = (point){ln.p0.x + NOODLE_HALF_WIDTH, ln.p0.y}, - .p2 = (point){ln.p1.x - NOODLE_HALF_WIDTH, ln.p1.y}, - .p3 = (point){ln.p1.x + NOODLE_HALF_WIDTH, ln.p1.y}, + .p0 = (point){noodle.noodle.p0.x - NOODLE_HALF_WIDTH, + noodle.noodle.p0.y}, + .p1 = (point){noodle.noodle.p0.x + NOODLE_HALF_WIDTH, + noodle.noodle.p0.y}, + .p2 = (point){noodle.noodle.p1.x - NOODLE_HALF_WIDTH, + noodle.noodle.p1.y}, + .p3 = (point){noodle.noodle.p1.x + NOODLE_HALF_WIDTH, + noodle.noodle.p1.y}, }; } else { f32 slope = (f32)(direction.y) / direction.x; @@ -229,10 +246,14 @@ internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln, f32 perpendicular_dx = -1.0f * slope * perpendicular_dy; qd = (quad){ - .p0 = (point){ln.p0.x - perpendicular_dx, ln.p0.y - perpendicular_dy}, - .p1 = (point){ln.p0.x + perpendicular_dx, ln.p0.y + perpendicular_dy}, - .p2 = (point){ln.p1.x - perpendicular_dx, ln.p1.y - perpendicular_dy}, - .p3 = (point){ln.p1.x + perpendicular_dx, ln.p1.y + perpendicular_dy}, + .p0 = (point){noodle.noodle.p0.x - perpendicular_dx, + noodle.noodle.p0.y - perpendicular_dy}, + .p1 = (point){noodle.noodle.p0.x + perpendicular_dx, + noodle.noodle.p0.y + perpendicular_dy}, + .p2 = (point){noodle.noodle.p1.x - perpendicular_dx, + noodle.noodle.p1.y - perpendicular_dy}, + .p3 = (point){noodle.noodle.p1.x + perpendicular_dx, + noodle.noodle.p1.y + perpendicular_dy}, }; } @@ -263,29 +284,67 @@ internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln, } if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) { - return ln; + return noodle; } if (ctx->mouse_up) { - ctx->hovered = ctx->active = -1; - ctx->rel_x = ctx->rel_y = 0; - return (line){ - .p0 = ln.p0, - .p1 = ln.p0, + if (ctx->hovered == ctx->active && ctx->hovered == id) { + ctx->hovered = ctx->active = -1; + + for (u64 i = 0; i < ctx->count; ++i) { + const ui_elem *elem = &(ctx->elements[i]); + + if (elem->type != UI_ELEM_NODE || elem->id == parent_id) { + continue; + } + + if (!aabb(elem->rect, ctx->mouse_x, ctx->mouse_y)) { + continue; + } + + point p0 = (point){ + .x = elem->rect.topleft.x + elem->rect.w / 2, + .y = elem->rect.topleft.y + elem->rect.h / 2, + }; + + line updated_noodle = (line){ + .p0 = p0, + .p1 = noodle.noodle.p1, + }; + return (ui_noodle_elem){ + .noodle = updated_noodle, + .connected_node = i, + }; + } + + noodle.connected_node = 0; + } + + if (noodle.connected_node > 0) { + return noodle; + } + + line updated_noodle = (line){ + .p0 = noodle.noodle.p1, + .p1 = noodle.noodle.p1, + }; + return (ui_noodle_elem){ + .noodle = updated_noodle, + .connected_node = noodle.connected_node, }; - // return ln; } if (ctx->hovered == id && ctx->active == id) { - ln.p0.x += ctx->rel_x; - ln.p0.y += ctx->rel_y; + noodle.noodle.p0.x += ctx->rel_x; + noodle.noodle.p0.y += ctx->rel_y; - return ln; + return noodle; } + const rect *node = &(ctx->elements[parent_id].rect); if (!aabb(bounding_box, ctx->mouse_x, ctx->mouse_y) || - aabb(node, ctx->mouse_x, ctx->mouse_y)) { - return ln; + aabb(*node, ctx->mouse_x, ctx->mouse_y)) { + return noodle; } ctx->hovered = id; @@ -294,7 +353,7 @@ internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln, ctx->active = id; } - return ln; + return noodle; } internal bool aabb(rect rec, i32 x, i32 y) {