diff --git a/app-proto/sketch-outline/main.css b/app-proto/sketch-outline/main.css index cd7bc44..fbccab7 100644 --- a/app-proto/sketch-outline/main.css +++ b/app-proto/sketch-outline/main.css @@ -7,7 +7,7 @@ body { /* outline */ -ul { +#outline { float: left; width: 450px; height: 750px; @@ -19,32 +19,35 @@ ul { } li { - display: flex; - padding: 3px; list-style-type: none; - background-color: #444; - border-radius: 8px; -} - -li.selected { - color: #fff; - background-color: #666; } li:not(:last-child) { margin-bottom: 8px; } -li > .elt-label { +.elt { + display: flex; + padding: 3px; + background-color: #444; + border-radius: 8px; +} + +.elt.selected { + color: #fff; + background-color: #666; +} + +.elt > .elt-label { flex-grow: 1; padding: 2px 0px 2px 4px; } -li > .elt-rep { +.elt > .elt-rep { display: flex; } -li > .elt-rep > div { +.elt > .elt-rep > div { padding: 2px; margin-left: 3px; text-align: center; @@ -52,18 +55,26 @@ li > .elt-rep > div { background-color: #333; } -li.selected > .elt-rep > div { +.elt.selected > .elt-rep > div { background-color: #555; } -li > .elt-rep > div:first-child { +.elt-rep > div:first-child { border-radius: 6px 0px 0px 6px; } -li > .elt-rep > div:last-child { +.elt-rep > div:last-child { border-radius: 0px 6px 6px 0px; } +.constraints > li { + margin-top: 4px; + margin-bottom: 4px; + padding: 5px; + background-color: #444; + border-radius: 8px; +} + /* display */ canvas { diff --git a/app-proto/sketch-outline/src/assembly.rs b/app-proto/sketch-outline/src/assembly.rs index 79912b9..4cd769c 100644 --- a/app-proto/sketch-outline/src/assembly.rs +++ b/app-proto/sketch-outline/src/assembly.rs @@ -1,4 +1,5 @@ use nalgebra::DVector; +use rustc_hash::FxHashSet; use slab::Slab; use sycamore::reactive::Signal; @@ -7,11 +8,18 @@ pub struct Element { pub id: String, pub label: String, pub color: [f32; 3], - pub rep: DVector + pub rep: DVector, + pub constraints: FxHashSet +} + +pub struct Constraint { + pub args: (usize, usize), + pub rep: f64 } // a complete, view-independent description of an assembly #[derive(Clone)] pub struct Assembly { - pub elements: Signal> + pub elements: Signal>, + pub constraints: Signal> } \ No newline at end of file diff --git a/app-proto/sketch-outline/src/main.rs b/app-proto/sketch-outline/src/main.rs index a43b020..20ae651 100644 --- a/app-proto/sketch-outline/src/main.rs +++ b/app-proto/sketch-outline/src/main.rs @@ -21,7 +21,8 @@ fn main() { sycamore::render(|| { let state = AppState { assembly: Assembly { - elements: create_signal(Slab::new()) + elements: create_signal(Slab::new()), + constraints: create_signal(Slab::new()) }, selection: create_signal(FxHashSet::default()) }; @@ -31,7 +32,13 @@ fn main() { id: String::from("wing_a"), label: String::from("Wing A"), color: [1.00_f32, 0.25_f32, 0.00_f32], - rep: DVector::::from_column_slice(&[0.5, 0.5, 0.0, 0.5, -0.25]) + rep: DVector::::from_column_slice(&[0.5, 0.5, 0.0, 0.5, -0.25]), + constraints: { + let mut set = FxHashSet::default(); + set.insert(1); + set.insert(2); + set + } } ) ); @@ -41,7 +48,8 @@ fn main() { id: String::from("wing_b"), label: String::from("Wing B"), color: [0.00_f32, 0.25_f32, 1.00_f32], - rep: DVector::::from_column_slice(&[-0.5, -0.5, 0.0, 0.5, -0.25]) + rep: DVector::::from_column_slice(&[-0.5, -0.5, 0.0, 0.5, -0.25]), + constraints: FxHashSet::default() }, ) ); @@ -51,7 +59,8 @@ fn main() { id: String::from("central"), label: String::from("Central"), color: [0.75_f32, 0.75_f32, 0.75_f32], - rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.4, -0.625]) + rep: DVector::::from_column_slice(&[0.0, 0.0, 0.0, 0.4, -0.625]), + constraints: FxHashSet::default() } ) ); diff --git a/app-proto/sketch-outline/src/outline.rs b/app-proto/sketch-outline/src/outline.rs index 031f9bc..4cb3901 100644 --- a/app-proto/sketch-outline/src/outline.rs +++ b/app-proto/sketch-outline/src/outline.rs @@ -18,6 +18,7 @@ pub fn Outline() -> View { view! { ul( + id="outline", on:click={ let state = use_context::(); move |_| state.selection.update(|sel| sel.clear()) @@ -30,9 +31,9 @@ pub fn Outline() -> View { let class = create_memo({ move || { if state.selection.with(|sel| sel.contains(&key)) { - "selected" + "elt selected" } else { - "" + "elt" } } }); @@ -44,29 +45,12 @@ pub fn Outline() -> View { view! { /* [TO DO] switch to integer-valued parameters whenever that becomes possible again */ - li( - class=class.get(), - tabindex="0", - on:click={ - move |event: MouseEvent| { - if event.shift_key() { - state.selection.update(|sel| { - if !sel.remove(&key) { - sel.insert(key); - } - }); - } else { - state.selection.update(|sel| { - sel.clear(); - sel.insert(key); - }); - } - event.stop_propagation(); - } - }, - on:keydown={ - move |event: KeyboardEvent| { - if event.key() == "Enter" { + li { + div( + class=class.get(), + tabindex="0", + on:click={ + move |event: MouseEvent| { if event.shift_key() { state.selection.update(|sel| { if !sel.remove(&key) { @@ -79,13 +63,39 @@ pub fn Outline() -> View { sel.insert(key); }); } - event.prevent_default(); + event.stop_propagation(); + } + }, + on:keydown={ + move |event: KeyboardEvent| { + if event.key() == "Enter" { + if event.shift_key() { + state.selection.update(|sel| { + if !sel.remove(&key) { + sel.insert(key); + } + }); + } else { + state.selection.update(|sel| { + sel.clear(); + sel.insert(key); + }); + } + event.prevent_default(); + } } } + ) { + div(class="elt-label") { (label) } + div(class="elt-rep") { (rep_components) } + } + ul(class="constraints") { + Keyed( + list=elt.constraints.into_iter().collect::>(), + view=|c_key: usize| view! { li { (c_key.to_string()) } }, + key=|c_key| c_key.clone() + ) } - ) { - div(class="elt-label") { (label) } - div(class="elt-rep") { (rep_components) } } } },