Simplify the immediate mode functions and move node

connection logic to the application level
This commit is contained in:
Abdelrahman Said 2024-02-25 20:31:11 +00:00
parent bc6bb1afdc
commit 7b7a913c46
3 changed files with 100 additions and 157 deletions

View File

@ -16,6 +16,8 @@
#define NODE_WIDTH 70 #define NODE_WIDTH 70
#define NODE_HEIGHT 20 #define NODE_HEIGHT 20
#define DEFAULT_NOODLE_LENGTH 60
typedef enum ui_elem_type ui_elem_type; typedef enum ui_elem_type ui_elem_type;
typedef struct ui_elem ui_elem; typedef struct ui_elem ui_elem;
typedef struct ui_ctx ui_ctx; typedef struct ui_ctx ui_ctx;
@ -43,19 +45,6 @@ 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;
struct ui_node_elem {
rect rec;
ui_noodle_elem *noodles;
u64 inputs;
};
struct ui_ctx { struct ui_ctx {
u64 count; u64 count;
i64 hovered; i64 hovered;
@ -75,7 +64,9 @@ void reset_ui_ctx(ui_ctx *ctx);
void handle_ui_events(const window *wnd, ui_ctx *ctx, const SDL_Event *event); void handle_ui_events(const window *wnd, ui_ctx *ctx, const SDL_Event *event);
bool ui_button(const window *wnd, ui_ctx *ctx, rect rect, bool ui_button(const window *wnd, ui_ctx *ctx, rect rect,
ui_elem_colours colours); ui_elem_colours colours);
ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, bool ui_node(const window *wnd, ui_ctx *ctx, rect rect,
ui_elem_colours colours); ui_elem_colours colours);
bool ui_noodle(const window *wnd, ui_ctx *ctx, line ln, ui_elem_colours colours,
rect parent_node);
#endif // !UI_H #endif // !UI_H

View File

@ -9,6 +9,7 @@
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define MAX_WINDOWS 2 #define MAX_WINDOWS 2
@ -153,8 +154,54 @@ i32 run_main_loop(void) {
} }
for (u64 i = 0; i < comp.count; ++i) { for (u64 i = 0; i < comp.count; ++i) {
comp.nodes[i].node = ui_node(main_window, &(comp.ctx), comp.nodes[i].node, node *node_elem = &(comp.nodes[i]);
comp.nodes[i].colours);
f64 angle = 90.0;
f64 angle_delta = 25.0;
i64 delta_multiplier = node_elem->inputs % 2 == 0 ? -1 : 0;
for (u64 j = 0; j < comp.nodes[i].inputs; ++j) {
f64 new_angle = angle + angle_delta * delta_multiplier;
line *ln = &(node_elem->noodles[j]);
if (ln->p0.x == ln->p1.x && ln->p0.y == ln->p1.y) {
point origin = {node_elem->rec.topleft.x + node_elem->rec.w / 2,
node_elem->rec.topleft.y + node_elem->rec.h / 2};
*ln = line_from_origin(origin, new_angle, DEFAULT_NOODLE_LENGTH);
}
if (ui_noodle(main_window, &(comp.ctx), *ln, node_elem->colours,
node_elem->rec)) {
ln->p0.x += comp.ctx.rel_x;
ln->p0.y += comp.ctx.rel_y;
}
if (delta_multiplier > 0) {
angle = new_angle;
}
if (delta_multiplier == 0) {
delta_multiplier = -1;
} else {
delta_multiplier *= -1;
}
}
if (ui_node(main_window, &(comp.ctx), node_elem->rec,
node_elem->colours)) {
node_elem->rec.topleft.x += comp.ctx.rel_x;
node_elem->rec.topleft.y += comp.ctx.rel_y;
for (u64 j = 0; j < comp.nodes[i].inputs; ++j) {
line *ln = &(node_elem->noodles[j]);
ln->p0.x += comp.ctx.rel_x;
ln->p0.y += comp.ctx.rel_y;
ln->p1.x += comp.ctx.rel_x;
ln->p1.y += comp.ctx.rel_y;
}
}
} }
for (u64 i = 0; i < MAX_WINDOWS; ++i) { for (u64 i = 0; i < MAX_WINDOWS; ++i) {
@ -181,28 +228,25 @@ void add_node(compositor *comp, node_type type, node_data data, u64 inputs,
return; return;
} }
u64 alloc_size = inputs * sizeof(ui_noodle_elem); u64 alloc_size = inputs * sizeof(line);
ui_noodle_elem *noodles = mem_arena_alloc(comp->arena, alloc_size); line *noodles = mem_arena_alloc(comp->arena, alloc_size);
if (!noodles) { if (!noodles) {
return; return;
} }
ui_node_elem elem = { rect rec = (rect){
.rec =
(rect){
.topleft.x = x, .topleft.x = x,
.topleft.y = y, .topleft.y = y,
.w = NODE_WIDTH, .w = NODE_WIDTH,
.h = NODE_HEIGHT, .h = NODE_HEIGHT,
},
.inputs = inputs,
.noodles = noodles,
}; };
comp->nodes[(comp->count)++] = (node){ comp->nodes[(comp->count)++] = (node){
.node = elem, .rec = rec,
.colours = colours, .colours = colours,
.type = type, .type = type,
.data.path = data.path, .data.path = data.path,
.inputs = inputs,
.noodles = noodles,
}; };
} }

160
src/ui.c
View File

@ -8,14 +8,8 @@
#include <stdlib.h> #include <stdlib.h>
#define NOODLE_HALF_WIDTH 2 #define NOODLE_HALF_WIDTH 2
#define DEFAULT_NOODLE_LENGTH 60
internal u64 get_id(ui_ctx *ctx); 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);
void init_ui_ctx(ui_ctx *ctx) { void init_ui_ctx(ui_ctx *ctx) {
*ctx = (ui_ctx){0}; *ctx = (ui_ctx){0};
@ -102,55 +96,24 @@ bool ui_button(const window *wnd, ui_ctx *ctx, rect rec,
return false; return false;
} }
ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node, bool ui_node(const window *wnd, ui_ctx *ctx, rect rect,
ui_elem_colours colours) { ui_elem_colours colours) {
if (ctx->count + 1 >= MAX_UI_ELEMENTS) { if (ctx->count + 1 >= MAX_UI_ELEMENTS) {
return (ui_node_elem){0}; return false;
} }
u64 id = get_id(ctx); u64 id = get_id(ctx);
ctx->elements[id] = (ui_elem){ ctx->elements[id] = (ui_elem){
.id = id, .id = id,
.rec = node.rec, .rec = rect,
.type = UI_ELEM_NODE, .type = UI_ELEM_NODE,
}; };
f64 angle = 90.0; fill_rect(wnd, rect, colours.fill);
f64 angle_delta = 25.0; draw_rect(wnd, rect, colours.border);
i64 delta_multiplier = node.inputs % 2 == 0 ? -1 : 0;
for (u64 i = 0; i < node.inputs; ++i) {
f64 new_angle = angle + angle_delta * delta_multiplier;
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};
node.noodles[i].noodle =
line_from_origin(origin, new_angle, DEFAULT_NOODLE_LENGTH);
} else {
node.noodles[i].noodle = node.noodles[i].noodle;
}
node.noodles[i] = ui_noodle(wnd, ctx, node.noodles[i], colours, id);
if (delta_multiplier > 0) {
angle = new_angle;
}
if (delta_multiplier == 0) {
delta_multiplier = -1;
} else {
delta_multiplier *= -1;
}
}
fill_rect(wnd, node.rec, colours.fill);
draw_rect(wnd, node.rec, colours.border);
if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) { if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) {
return node; return false;
} }
if (ctx->mouse_up) { if (ctx->mouse_up) {
@ -158,28 +121,15 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node,
ctx->hovered = ctx->active = -1; ctx->hovered = ctx->active = -1;
} }
return node; return false;
} }
if (ctx->hovered == id && ctx->active == id) { if (ctx->hovered == id && ctx->active == id) {
node.rec.topleft.x += ctx->rel_x; return true;
node.rec.topleft.y += ctx->rel_y;
for (u64 i = 0; i < node.inputs; ++i) {
if (node.noodles[i].connected_node == RESERVED_UI_SLOT) {
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; if (!aabb(rect, ctx->mouse_x, ctx->mouse_y)) {
node.noodles[i].noodle.p1.y += ctx->rel_y; return false;
}
return node;
}
if (!aabb(node.rec, ctx->mouse_x, ctx->mouse_y)) {
return node;
} }
ctx->hovered = id; ctx->hovered = id;
@ -188,7 +138,7 @@ ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node,
ctx->active = id; ctx->active = id;
} }
return node; return false;
} }
internal u64 get_id(ui_ctx *ctx) { internal u64 get_id(ui_ctx *ctx) {
@ -196,47 +146,42 @@ internal u64 get_id(ui_ctx *ctx) {
return ++(ctx->count); return ++(ctx->count);
} }
internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx, bool ui_noodle(const window *wnd, ui_ctx *ctx, line ln, ui_elem_colours colours,
ui_noodle_elem noodle, rect parent_node) {
ui_elem_colours colours, u64 parent_id) {
if (ctx->count + 1 >= MAX_UI_ELEMENTS) { if (ctx->count + 1 >= MAX_UI_ELEMENTS) {
return (ui_noodle_elem){0}; return false;
} }
u64 id = get_id(ctx); u64 id = get_id(ctx);
ctx->elements[id] = (ui_elem){ ctx->elements[id] = (ui_elem){
.id = id, .id = id,
.ln = noodle.noodle, .ln = ln,
.type = UI_ELEM_NOODLE, .type = UI_ELEM_NOODLE,
}; };
bool horizontal = noodle.noodle.p0.y == noodle.noodle.p1.y; bool horizontal = ln.p0.y == ln.p1.y;
rect bounding_box = (rect){0}; rect bounding_box = (rect){0};
if (horizontal) { if (horizontal) {
i32 x = min(noodle.noodle.p0.x, noodle.noodle.p1.x); i32 x = min(ln.p0.x, ln.p1.x);
bounding_box.topleft = (point){x, noodle.noodle.p0.y - NOODLE_HALF_WIDTH}; bounding_box.topleft = (point){x, ln.p0.y - NOODLE_HALF_WIDTH};
bounding_box.w = abs(noodle.noodle.p1.x - noodle.noodle.p0.x); bounding_box.w = abs(ln.p1.x - ln.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(&noodle.noodle); vec2 direction = line_direction(&ln);
quad qd = (quad){0}; quad qd = (quad){0};
if (direction.x == 0) { if (direction.x == 0) {
qd = (quad){ qd = (quad){
.p0 = (point){noodle.noodle.p0.x - NOODLE_HALF_WIDTH, .p0 = (point){ln.p0.x - NOODLE_HALF_WIDTH, ln.p0.y},
noodle.noodle.p0.y}, .p1 = (point){ln.p0.x + NOODLE_HALF_WIDTH, ln.p0.y},
.p1 = (point){noodle.noodle.p0.x + NOODLE_HALF_WIDTH, .p2 = (point){ln.p1.x - NOODLE_HALF_WIDTH, ln.p1.y},
noodle.noodle.p0.y}, .p3 = (point){ln.p1.x + NOODLE_HALF_WIDTH, ln.p1.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;
@ -246,14 +191,10 @@ internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx,
f32 perpendicular_dx = -1.0f * slope * perpendicular_dy; f32 perpendicular_dx = -1.0f * slope * perpendicular_dy;
qd = (quad){ qd = (quad){
.p0 = (point){noodle.noodle.p0.x - perpendicular_dx, .p0 = (point){ln.p0.x - perpendicular_dx, ln.p0.y - perpendicular_dy},
noodle.noodle.p0.y - perpendicular_dy}, .p1 = (point){ln.p0.x + perpendicular_dx, ln.p0.y + perpendicular_dy},
.p1 = (point){noodle.noodle.p0.x + perpendicular_dx, .p2 = (point){ln.p1.x - perpendicular_dx, ln.p1.y - perpendicular_dy},
noodle.noodle.p0.y + perpendicular_dy}, .p3 = (point){ln.p1.x + perpendicular_dx, ln.p1.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},
}; };
} }
@ -284,7 +225,7 @@ internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx,
} }
if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) { if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) {
return noodle; return false;
} }
if (ctx->mouse_up) { if (ctx->mouse_up) {
@ -292,31 +233,16 @@ internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx,
ctx->hovered = ctx->active = -1; ctx->hovered = ctx->active = -1;
} }
if (noodle.connected_node > RESERVED_UI_SLOT) { return true;
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,
};
} }
if (ctx->hovered == id && ctx->active == id) { if (ctx->hovered == id && ctx->active == id) {
noodle.noodle.p0.x += ctx->rel_x; return true;
noodle.noodle.p0.y += ctx->rel_y;
return noodle;
} }
const rect *node = &(ctx->elements[parent_id].rec);
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(parent_node, ctx->mouse_x, ctx->mouse_y)) {
return noodle; return false;
} }
ctx->hovered = id; ctx->hovered = id;
@ -325,23 +251,5 @@ internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx,
ctx->active = id; ctx->active = id;
} }
return noodle; return false;
}
internal bool aabb(rect rec, i32 x, i32 y) {
return x > rec.topleft.x && x <= rec.topleft.x + rec.w && y > rec.topleft.y &&
y <= rec.topleft.y + rec.h;
}
internal line line_from_origin(point origin, f64 angle, i32 line_length) {
f64 rad = radians(angle);
f64 direction = angle / absolute(angle) * -1;
i32 adjacent = line_length * cos(rad) * direction; // dx
i32 opposite = line_length * sin(rad) * direction; // dy
return (line){
(point){origin.x + adjacent, origin.y + opposite},
origin,
};
} }