From 7b7a913c46fff1fe8ee630295536ea3653290f57 Mon Sep 17 00:00:00 2001
From: Abdelrahman <said.abdelrahman89@gmail.com>
Date: Sun, 25 Feb 2024 20:31:11 +0000
Subject: [PATCH] Simplify the immediate mode functions and move node
 connection logic to the application level

---
 include/ui.h     |  21 ++----
 src/compositor.c |  74 +++++++++++++++++-----
 src/ui.c         | 162 ++++++++++-------------------------------------
 3 files changed, 100 insertions(+), 157 deletions(-)

diff --git a/include/ui.h b/include/ui.h
index d36e67e..39b9437 100644
--- a/include/ui.h
+++ b/include/ui.h
@@ -16,6 +16,8 @@
 #define NODE_WIDTH 70
 #define NODE_HEIGHT 20
 
+#define DEFAULT_NOODLE_LENGTH 60
+
 typedef enum ui_elem_type ui_elem_type;
 typedef struct ui_elem ui_elem;
 typedef struct ui_ctx ui_ctx;
@@ -43,19 +45,6 @@ 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;
-  ui_noodle_elem *noodles;
-  u64 inputs;
-};
-
 struct ui_ctx {
   u64 count;
   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);
 bool ui_button(const window *wnd, ui_ctx *ctx, rect rect,
                ui_elem_colours colours);
-ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node,
-                     ui_elem_colours colours);
+bool ui_node(const window *wnd, ui_ctx *ctx, rect rect,
+             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
diff --git a/src/compositor.c b/src/compositor.c
index c2cfa02..19b8338 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -9,6 +9,7 @@
 #include <SDL2/SDL_render.h>
 #include <SDL2/SDL_video.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 #define MAX_WINDOWS 2
@@ -153,8 +154,54 @@ i32 run_main_loop(void) {
     }
 
     for (u64 i = 0; i < comp.count; ++i) {
-      comp.nodes[i].node = ui_node(main_window, &(comp.ctx), comp.nodes[i].node,
-                                   comp.nodes[i].colours);
+      node *node_elem = &(comp.nodes[i]);
+
+      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) {
@@ -181,28 +228,25 @@ void add_node(compositor *comp, node_type type, node_data data, u64 inputs,
     return;
   }
 
-  u64 alloc_size = inputs * sizeof(ui_noodle_elem);
-  ui_noodle_elem *noodles = mem_arena_alloc(comp->arena, alloc_size);
+  u64 alloc_size = inputs * sizeof(line);
+  line *noodles = mem_arena_alloc(comp->arena, alloc_size);
   if (!noodles) {
     return;
   }
 
-  ui_node_elem elem = {
-      .rec =
-          (rect){
-              .topleft.x = x,
-              .topleft.y = y,
-              .w = NODE_WIDTH,
-              .h = NODE_HEIGHT,
-          },
-      .inputs = inputs,
-      .noodles = noodles,
+  rect rec = (rect){
+      .topleft.x = x,
+      .topleft.y = y,
+      .w = NODE_WIDTH,
+      .h = NODE_HEIGHT,
   };
 
   comp->nodes[(comp->count)++] = (node){
-      .node = elem,
+      .rec = rec,
       .colours = colours,
       .type = type,
       .data.path = data.path,
+      .inputs = inputs,
+      .noodles = noodles,
   };
 }
diff --git a/src/ui.c b/src/ui.c
index 1493273..8bd72d2 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -8,14 +8,8 @@
 #include <stdlib.h>
 
 #define NOODLE_HALF_WIDTH 2
-#define DEFAULT_NOODLE_LENGTH 60
 
 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) {
   *ctx = (ui_ctx){0};
@@ -102,55 +96,24 @@ bool ui_button(const window *wnd, ui_ctx *ctx, rect rec,
   return false;
 }
 
-ui_node_elem ui_node(const window *wnd, ui_ctx *ctx, ui_node_elem node,
-                     ui_elem_colours colours) {
+bool ui_node(const window *wnd, ui_ctx *ctx, rect rect,
+             ui_elem_colours colours) {
   if (ctx->count + 1 >= MAX_UI_ELEMENTS) {
-    return (ui_node_elem){0};
+    return false;
   }
 
   u64 id = get_id(ctx);
   ctx->elements[id] = (ui_elem){
       .id = id,
-      .rec = node.rec,
+      .rec = rect,
       .type = UI_ELEM_NODE,
   };
 
-  f64 angle = 90.0;
-  f64 angle_delta = 25.0;
-  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);
+  fill_rect(wnd, rect, colours.fill);
+  draw_rect(wnd, rect, colours.border);
 
   if (wnd != ctx->wnd || (ctx->active >= 0 && ctx->active != id)) {
-    return node;
+    return false;
   }
 
   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;
     }
 
-    return node;
+    return false;
   }
 
   if (ctx->hovered == id && ctx->active == id) {
-    node.rec.topleft.x += ctx->rel_x;
-    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;
-      node.noodles[i].noodle.p1.y += ctx->rel_y;
-    }
-
-    return node;
+    return true;
   }
 
-  if (!aabb(node.rec, ctx->mouse_x, ctx->mouse_y)) {
-    return node;
+  if (!aabb(rect, ctx->mouse_x, ctx->mouse_y)) {
+    return false;
   }
 
   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;
   }
 
-  return node;
+  return false;
 }
 
 internal u64 get_id(ui_ctx *ctx) {
@@ -196,47 +146,42 @@ internal u64 get_id(ui_ctx *ctx) {
   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) {
+bool ui_noodle(const window *wnd, ui_ctx *ctx, line ln, ui_elem_colours colours,
+               rect parent_node) {
   if (ctx->count + 1 >= MAX_UI_ELEMENTS) {
-    return (ui_noodle_elem){0};
+    return false;
   }
 
   u64 id = get_id(ctx);
   ctx->elements[id] = (ui_elem){
       .id = id,
-      .ln = noodle.noodle,
+      .ln = ln,
       .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};
 
   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.w = abs(noodle.noodle.p1.x - noodle.noodle.p0.x);
+    bounding_box.topleft = (point){x, ln.p0.y - NOODLE_HALF_WIDTH};
+    bounding_box.w = abs(ln.p1.x - ln.p0.x);
     bounding_box.h = NOODLE_HALF_WIDTH * 2;
 
     fill_rect(wnd, bounding_box, colours.fill);
   } else {
-    vec2 direction = line_direction(&noodle.noodle);
+    vec2 direction = line_direction(&ln);
 
     quad qd = (quad){0};
 
     if (direction.x == 0) {
       qd = (quad){
-          .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},
+          .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},
       };
     } else {
       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;
 
       qd = (quad){
-          .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},
+          .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},
       };
     }
 
@@ -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)) {
-    return noodle;
+    return false;
   }
 
   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;
     }
 
-    if (noodle.connected_node > RESERVED_UI_SLOT) {
-      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 true;
   }
 
   if (ctx->hovered == id && ctx->active == id) {
-    noodle.noodle.p0.x += ctx->rel_x;
-    noodle.noodle.p0.y += ctx->rel_y;
-
-    return noodle;
+    return true;
   }
 
-  const rect *node = &(ctx->elements[parent_id].rec);
   if (!aabb(bounding_box, ctx->mouse_x, ctx->mouse_y) ||
-      aabb(*node, ctx->mouse_x, ctx->mouse_y)) {
-    return noodle;
+      aabb(parent_node, ctx->mouse_x, ctx->mouse_y)) {
+    return false;
   }
 
   ctx->hovered = id;
@@ -325,23 +251,5 @@ internal ui_noodle_elem ui_noodle(const window *wnd, ui_ctx *ctx,
     ctx->active = id;
   }
 
-  return noodle;
-}
-
-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,
-  };
+  return false;
 }