From fb292d8b5b6848cc47cb01a4e49c0efedfc8f8fa Mon Sep 17 00:00:00 2001
From: Aaron Fenyes <aaron.fenyes@fareycircles.ooo>
Date: Fri, 1 Nov 2024 04:25:03 -0700
Subject: [PATCH] Render constraint lists dynamically

---
 app-proto/src/add_remove.rs | 28 ++++++++++++++--------------
 app-proto/src/assembly.rs   | 13 +++++++------
 app-proto/src/outline.rs    | 12 +++++++-----
 3 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/app-proto/src/add_remove.rs b/app-proto/src/add_remove.rs
index 15d30f2..e9a3515 100644
--- a/app-proto/src/add_remove.rs
+++ b/app-proto/src/add_remove.rs
@@ -12,7 +12,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Castor"),
             color: [1.00_f32, 0.25_f32, 0.00_f32],
             rep: engine::sphere(0.5, 0.5, 0.0, 1.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -22,7 +22,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Pollux"),
             color: [0.00_f32, 0.25_f32, 1.00_f32],
             rep: engine::sphere(-0.5, -0.5, 0.0, 1.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -32,7 +32,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Ursa major"),
             color: [0.25_f32, 0.00_f32, 1.00_f32],
             rep: engine::sphere(-0.5, 0.5, 0.0, 0.75),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -42,7 +42,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Ursa minor"),
             color: [0.25_f32, 1.00_f32, 0.00_f32],
             rep: engine::sphere(0.5, -0.5, 0.0, 0.5),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -52,7 +52,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Deimos"),
             color: [0.75_f32, 0.75_f32, 0.00_f32],
             rep: engine::sphere(0.0, 0.15, 1.0, 0.25),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -62,7 +62,7 @@ fn load_gen_assemb(assembly: &Assembly) {
             label: String::from("Phobos"),
             color: [0.00_f32, 0.75_f32, 0.50_f32],
             rep: engine::sphere(0.0, -0.15, -1.0, 0.25),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -77,7 +77,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Central".to_string(),
             color: [0.75_f32, 0.75_f32, 0.75_f32],
             rep: engine::sphere(0.0, 0.0, 0.0, 1.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -87,7 +87,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Assembly plane".to_string(),
             color: [0.75_f32, 0.75_f32, 0.75_f32],
             rep: engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -97,7 +97,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Side 1".to_string(),
             color: [1.00_f32, 0.00_f32, 0.25_f32],
             rep: engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -107,7 +107,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Side 2".to_string(),
             color: [0.25_f32, 1.00_f32, 0.00_f32],
             rep: engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -117,7 +117,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Side 3".to_string(),
             color: [0.00_f32, 0.25_f32, 1.00_f32],
             rep: engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -127,7 +127,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Corner 1".to_string(),
             color: [0.75_f32, 0.75_f32, 0.75_f32],
             rep: engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -137,7 +137,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: "Corner 2".to_string(),
             color: [0.75_f32, 0.75_f32, 0.75_f32],
             rep: engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
@@ -147,7 +147,7 @@ fn load_low_curv_assemb(assembly: &Assembly) {
             label: String::from("Corner 3"),
             color: [0.75_f32, 0.75_f32, 0.75_f32],
             rep: engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0),
-            constraints: BTreeSet::default(),
+            constraints: create_signal(BTreeSet::default()),
             index: 0
         }
     );
diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs
index 0970932..64f1b04 100644
--- a/app-proto/src/assembly.rs
+++ b/app-proto/src/assembly.rs
@@ -13,7 +13,7 @@ pub struct Element {
     pub label: String,
     pub color: [f32; 3],
     pub rep: DVector<f64>,
-    pub constraints: BTreeSet<usize>,
+    pub constraints: Signal<BTreeSet<usize>>,
     
     // internal properties, not reflected in any view
     pub index: usize
@@ -87,7 +87,7 @@ impl Assembly {
                 label: format!("Sphere {}", id_num),
                 color: [0.75_f32, 0.75_f32, 0.75_f32],
                 rep: DVector::<f64>::from_column_slice(&[0.0, 0.0, 0.0, 0.5, -0.5]),
-                constraints: BTreeSet::default(),
+                constraints: create_signal(BTreeSet::default()),
                 index: 0
             }
         );
@@ -96,10 +96,11 @@ impl Assembly {
     pub fn insert_constraint(&self, constraint: Constraint) {
         let args = constraint.args;
         let key = self.constraints.update(|csts| csts.insert(constraint));
-        self.elements.update(|elts| {
-            elts[args.0].constraints.insert(key);
-            elts[args.1].constraints.insert(key);
-        });
+        let arg_constraints = self.elements.with(
+            |elts| (elts[args.0].constraints, elts[args.1].constraints)
+        );
+        arg_constraints.0.update(|csts| csts.insert(key));
+        arg_constraints.1.update(|csts| csts.insert(key));
     }
     
     // --- realization ---
diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs
index 66b50f4..e29781b 100644
--- a/app-proto/src/outline.rs
+++ b/app-proto/src/outline.rs
@@ -76,7 +76,10 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
         let u_coord = format!("{:.3}", u).replace("-", "\u{2212}");
         View::from(div().children(u_coord))
     }).collect::<Vec<_>>();
-    let constrained = element.constraints.len() > 0;
+    let constrained = element.constraints.map(|csts| csts.len() > 0);
+    let constraint_list = element.constraints.map(
+        |csts| csts.clone().into_iter().collect()
+    );
     let details_node = create_node_ref();
     view! {
         li {
@@ -101,7 +104,7 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
                                     }
                                     event.prevent_default();
                                 },
-                                "ArrowRight" if constrained => {
+                                "ArrowRight" if constrained.get() => {
                                     let _ = details_node
                                         .get()
                                         .unchecked_into::<web_sys::Element>()
@@ -150,7 +153,7 @@ fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
                 }
                 ul(class="constraints") {
                     Keyed(
-                        list=element.constraints.into_iter().collect::<Vec<_>>(),
+                        list=constraint_list,
                         view=move |cst_key| view! {
                             ConstraintOutlineItem(
                                 constraint_key=cst_key,
@@ -200,8 +203,7 @@ pub fn Outline() -> View {
                     key.clone(),
                     elt.id.clone(),
                     elt.label.clone(),
-                    elt.rep.into_iter().map(|u| u.to_bits()).collect::<Vec<_>>(),
-                    elt.constraints.clone()
+                    elt.rep.into_iter().map(|u| u.to_bits()).collect::<Vec<_>>()
                 )
             )
         }