Support connecting noodle to another node and ensure it
stays connected when parent node moves
This commit is contained in:
parent
050bb355d0
commit
8501eb787e
@ -38,10 +38,16 @@ struct ui_elem_colours {
|
|||||||
colour border;
|
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;
|
typedef struct ui_node_elem ui_node_elem;
|
||||||
struct ui_node_elem {
|
struct ui_node_elem {
|
||||||
rect rec;
|
rect rec;
|
||||||
line *noodles;
|
ui_noodle_elem *noodles;
|
||||||
u64 inputs;
|
u64 inputs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -181,7 +181,8 @@ void add_node(compositor *comp, node_type type, node_data data, u64 inputs,
|
|||||||
return;
|
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) {
|
if (!noodles) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
147
src/ui.c
147
src/ui.c
@ -10,8 +10,10 @@
|
|||||||
#define NOODLE_HALF_WIDTH 2
|
#define NOODLE_HALF_WIDTH 2
|
||||||
#define DEFAULT_NOODLE_LENGTH 60
|
#define DEFAULT_NOODLE_LENGTH 60
|
||||||
|
|
||||||
internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln,
|
internal u64 get_id(ui_ctx *ctx);
|
||||||
ui_elem_colours colours, rect node);
|
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 bool aabb(rect rec, i32 x, i32 y);
|
||||||
internal line line_from_origin(point origin, f64 angle, i32 line_length);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 id = (ctx->count)++;
|
u64 id = get_id(ctx);
|
||||||
ctx->elements[id] = (ui_elem){
|
ctx->elements[id] = (ui_elem){
|
||||||
.id = id,
|
.id = id,
|
||||||
.rect = rec,
|
.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};
|
return (ui_node_elem){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 id = (ctx->count)++;
|
u64 id = get_id(ctx);
|
||||||
ctx->elements[id] = (ui_elem){
|
ctx->elements[id] = (ui_elem){
|
||||||
.id = id,
|
.id = id,
|
||||||
.rect = node.rec,
|
.rect = node.rec,
|
||||||
.type = UI_ELEM_NODE,
|
.type = UI_ELEM_NODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
line ln = {0};
|
|
||||||
f64 angle = 90.0;
|
f64 angle = 90.0;
|
||||||
f64 angle_delta = 25.0;
|
f64 angle_delta = 25.0;
|
||||||
i64 delta_multiplier = node.inputs % 2 == 0 ? -1 : 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) {
|
for (u64 i = 0; i < node.inputs; ++i) {
|
||||||
f64 new_angle = angle + angle_delta * delta_multiplier;
|
f64 new_angle = angle + angle_delta * delta_multiplier;
|
||||||
|
|
||||||
if (node.noodles[i].p0.x == node.noodles[i].p1.x &&
|
if (node.noodles[i].noodle.p0.x == node.noodles[i].noodle.p1.x &&
|
||||||
node.noodles[i].p0.y == node.noodles[i].p1.y) {
|
node.noodles[i].noodle.p0.y == node.noodles[i].noodle.p1.y) {
|
||||||
point origin = {node.rec.topleft.x + node.rec.w / 2,
|
point origin = {node.rec.topleft.x + node.rec.w / 2,
|
||||||
node.rec.topleft.y + node.rec.h / 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 {
|
} 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) {
|
if (delta_multiplier > 0) {
|
||||||
angle = new_angle;
|
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) {
|
if (ctx->mouse_up) {
|
||||||
|
if (ctx->hovered == ctx->active && ctx->hovered == id) {
|
||||||
ctx->hovered = ctx->active = -1;
|
ctx->hovered = ctx->active = -1;
|
||||||
ctx->rel_x = ctx->rel_y = 0;
|
}
|
||||||
|
|
||||||
return node;
|
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;
|
node.rec.topleft.y += ctx->rel_y;
|
||||||
|
|
||||||
for (u64 i = 0; i < node.inputs; ++i) {
|
for (u64 i = 0; i < node.inputs; ++i) {
|
||||||
node.noodles[i].p0.x += ctx->rel_x;
|
if (node.noodles[i].connected_node == 0) {
|
||||||
node.noodles[i].p0.y += ctx->rel_y;
|
node.noodles[i].noodle.p0.x += ctx->rel_x;
|
||||||
node.noodles[i].p1.x += ctx->rel_x;
|
node.noodles[i].noodle.p0.y += ctx->rel_y;
|
||||||
node.noodles[i].p1.y += ctx->rel_y;
|
}
|
||||||
|
|
||||||
|
node.noodles[i].noodle.p1.x += ctx->rel_x;
|
||||||
|
node.noodles[i].noodle.p1.y += ctx->rel_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -184,42 +191,52 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node,
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln,
|
internal u64 get_id(ui_ctx *ctx) {
|
||||||
ui_elem_colours colours, rect node) {
|
// 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) {
|
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){
|
ctx->elements[id] = (ui_elem){
|
||||||
.id = id,
|
.id = id,
|
||||||
.rect = (rect){0},
|
.rect = (rect){0},
|
||||||
.type = UI_ELEM_NOODLE,
|
.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};
|
rect bounding_box = (rect){0};
|
||||||
|
|
||||||
if (horizontal) {
|
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.topleft = (point){x, noodle.noodle.p0.y - NOODLE_HALF_WIDTH};
|
||||||
bounding_box.w = abs(ln.p1.x - ln.p0.x);
|
bounding_box.w = abs(noodle.noodle.p1.x - noodle.noodle.p0.x);
|
||||||
bounding_box.h = NOODLE_HALF_WIDTH * 2;
|
bounding_box.h = NOODLE_HALF_WIDTH * 2;
|
||||||
|
|
||||||
fill_rect(wnd, bounding_box, colours.fill);
|
fill_rect(wnd, bounding_box, colours.fill);
|
||||||
} else {
|
} else {
|
||||||
vec2 direction = line_direction(&ln);
|
vec2 direction = line_direction(&noodle.noodle);
|
||||||
|
|
||||||
quad qd = (quad){0};
|
quad qd = (quad){0};
|
||||||
|
|
||||||
if (direction.x == 0) {
|
if (direction.x == 0) {
|
||||||
qd = (quad){
|
qd = (quad){
|
||||||
.p0 = (point){ln.p0.x - NOODLE_HALF_WIDTH, ln.p0.y},
|
.p0 = (point){noodle.noodle.p0.x - NOODLE_HALF_WIDTH,
|
||||||
.p1 = (point){ln.p0.x + NOODLE_HALF_WIDTH, ln.p0.y},
|
noodle.noodle.p0.y},
|
||||||
.p2 = (point){ln.p1.x - NOODLE_HALF_WIDTH, ln.p1.y},
|
.p1 = (point){noodle.noodle.p0.x + NOODLE_HALF_WIDTH,
|
||||||
.p3 = (point){ln.p1.x + NOODLE_HALF_WIDTH, ln.p1.y},
|
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 {
|
} else {
|
||||||
f32 slope = (f32)(direction.y) / direction.x;
|
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;
|
f32 perpendicular_dx = -1.0f * slope * perpendicular_dy;
|
||||||
|
|
||||||
qd = (quad){
|
qd = (quad){
|
||||||
.p0 = (point){ln.p0.x - perpendicular_dx, ln.p0.y - perpendicular_dy},
|
.p0 = (point){noodle.noodle.p0.x - perpendicular_dx,
|
||||||
.p1 = (point){ln.p0.x + perpendicular_dx, ln.p0.y + perpendicular_dy},
|
noodle.noodle.p0.y - perpendicular_dy},
|
||||||
.p2 = (point){ln.p1.x - perpendicular_dx, ln.p1.y - perpendicular_dy},
|
.p1 = (point){noodle.noodle.p0.x + perpendicular_dx,
|
||||||
.p3 = (point){ln.p1.x + perpendicular_dx, ln.p1.y + perpendicular_dy},
|
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)) {
|
if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) {
|
||||||
return ln;
|
return noodle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->mouse_up) {
|
if (ctx->mouse_up) {
|
||||||
|
if (ctx->hovered == ctx->active && ctx->hovered == id) {
|
||||||
ctx->hovered = ctx->active = -1;
|
ctx->hovered = ctx->active = -1;
|
||||||
ctx->rel_x = ctx->rel_y = 0;
|
|
||||||
return (line){
|
for (u64 i = 0; i < ctx->count; ++i) {
|
||||||
.p0 = ln.p0,
|
const ui_elem *elem = &(ctx->elements[i]);
|
||||||
.p1 = ln.p0,
|
|
||||||
|
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) {
|
if (ctx->hovered == id && ctx->active == id) {
|
||||||
ln.p0.x += ctx->rel_x;
|
noodle.noodle.p0.x += ctx->rel_x;
|
||||||
ln.p0.y += ctx->rel_y;
|
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) ||
|
if (!aabb(bounding_box, ctx->mouse_x, ctx->mouse_y) ||
|
||||||
aabb(node, ctx->mouse_x, ctx->mouse_y)) {
|
aabb(*node, ctx->mouse_x, ctx->mouse_y)) {
|
||||||
return ln;
|
return noodle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->hovered = id;
|
ctx->hovered = id;
|
||||||
@ -294,7 +353,7 @@ internal line ui_noodle(const window *wnd, ui_ctx *ctx, line ln,
|
|||||||
ctx->active = id;
|
ctx->active = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ln;
|
return noodle;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool aabb(rect rec, i32 x, i32 y) {
|
internal bool aabb(rect rec, i32 x, i32 y) {
|
||||||
|
Loading…
Reference in New Issue
Block a user