Introduce ghost mode for elements #85
4 changed files with 40 additions and 7 deletions
|
@ -90,6 +90,10 @@ summary > div, .regulator {
|
|||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.element > input {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.element-switch {
|
||||
width: 18px;
|
||||
padding-left: 2px;
|
||||
|
|
|
@ -101,6 +101,7 @@ pub trait Element: Serial + ProblemPoser + DisplayItem {
|
|||
fn id(&self) -> &String;
|
||||
fn label(&self) -> &String;
|
||||
fn representation(&self) -> Signal<DVector<f64>>;
|
||||
fn ghost(&self) -> Signal<bool>;
|
||||
|
||||
// the regulators the element is subject to. the assembly that owns the
|
||||
// element is responsible for keeping this set up to date
|
||||
|
@ -154,6 +155,7 @@ pub struct Sphere {
|
|||
pub label: String,
|
||||
pub color: ElementColor,
|
||||
pub representation: Signal<DVector<f64>>,
|
||||
pub ghost: Signal<bool>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
serial: u64,
|
||||
column_index: Cell<Option<usize>>
|
||||
|
@ -173,6 +175,7 @@ impl Sphere {
|
|||
label: label,
|
||||
color: color,
|
||||
representation: create_signal(representation),
|
||||
ghost: create_signal(false),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
serial: Self::next_serial(),
|
||||
column_index: None.into()
|
||||
|
@ -210,6 +213,10 @@ impl Element for Sphere {
|
|||
self.representation
|
||||
}
|
||||
|
||||
fn ghost(&self) -> Signal<bool> {
|
||||
self.ghost
|
||||
}
|
||||
|
||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||
self.regulators
|
||||
}
|
||||
|
@ -244,6 +251,7 @@ pub struct Point {
|
|||
pub label: String,
|
||||
pub color: ElementColor,
|
||||
pub representation: Signal<DVector<f64>>,
|
||||
pub ghost: Signal<bool>,
|
||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||
serial: u64,
|
||||
column_index: Cell<Option<usize>>
|
||||
|
@ -263,6 +271,7 @@ impl Point {
|
|||
label,
|
||||
color,
|
||||
representation: create_signal(representation),
|
||||
ghost: create_signal(false),
|
||||
regulators: create_signal(BTreeSet::new()),
|
||||
serial: Self::next_serial(),
|
||||
column_index: None.into()
|
||||
|
@ -296,6 +305,10 @@ impl Element for Point {
|
|||
self.representation
|
||||
}
|
||||
|
||||
fn ghost(&self) -> Signal<bool> {
|
||||
self.ghost
|
||||
}
|
||||
|
||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||
self.regulators
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ use crate::{
|
|||
struct SceneSpheres {
|
||||
representations: Vec<DVector<f64>>,
|
||||
colors: Vec<ElementColor>,
|
||||
opacities: Vec<f32>,
|
||||
highlights: Vec<f32>
|
||||
}
|
||||
|
||||
|
@ -33,6 +34,7 @@ impl SceneSpheres {
|
|||
SceneSpheres {
|
||||
representations: Vec::new(),
|
||||
colors: Vec::new(),
|
||||
opacities: Vec::new(),
|
||||
highlights: Vec::new()
|
||||
}
|
||||
}
|
||||
|
@ -41,9 +43,10 @@ impl SceneSpheres {
|
|||
self.representations.len().try_into().expect("Number of spheres must fit in a 32-bit integer")
|
||||
}
|
||||
|
||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, highlight: f32) {
|
||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, opacity: f32, highlight: f32) {
|
||||
self.representations.push(representation);
|
||||
self.colors.push(color);
|
||||
self.opacities.push(opacity);
|
||||
self.highlights.push(highlight);
|
||||
}
|
||||
}
|
||||
|
@ -98,11 +101,16 @@ pub trait DisplayItem {
|
|||
|
||||
impl DisplayItem for Sphere {
|
||||
fn show(&self, scene: &mut Scene, selected: bool) {
|
||||
const HIGHLIGHT: f32 = 0.2; /* SCAFFOLDING */
|
||||
/* SCAFFOLDING */
|
||||
const DEFAULT_OPACITY: f32 = 0.5;
|
||||
const GHOST_OPACITY: f32 = 0.2;
|
||||
const HIGHLIGHT: f32 = 0.2;
|
||||
|
||||
let representation = self.representation.get_clone_untracked();
|
||||
let color = if selected { self.color.map(|channel| 0.2 + 0.8*channel) } else { self.color };
|
||||
let opacity = if self.ghost.get() { GHOST_OPACITY } else { DEFAULT_OPACITY };
|
||||
let highlight = if selected { 1.0 } else { HIGHLIGHT };
|
||||
scene.spheres.push(representation, color, highlight);
|
||||
scene.spheres.push(representation, color, opacity, highlight);
|
||||
}
|
||||
|
||||
// this method should be kept synchronized with `sphere_cast` in
|
||||
|
@ -365,6 +373,7 @@ pub fn Display() -> View {
|
|||
state.assembly.elements.with(|elts| {
|
||||
for elt in elts {
|
||||
elt.representation().track();
|
||||
elt.ghost().track();
|
||||
}
|
||||
});
|
||||
state.selection.track();
|
||||
|
@ -395,7 +404,6 @@ pub fn Display() -> View {
|
|||
const SHRINKING_SPEED: f64 = 0.15; // in length units per second
|
||||
|
||||
// display parameters
|
||||
const OPACITY: f32 = 0.5; /* SCAFFOLDING */
|
||||
const LAYER_THRESHOLD: i32 = 0; /* DEBUG */
|
||||
const DEBUG_MODE: i32 = 0; /* DEBUG */
|
||||
|
||||
|
@ -648,7 +656,7 @@ pub fn Display() -> View {
|
|||
|
||||
let sphere_color = &mut [0.0; 4];
|
||||
sphere_color[..3].copy_from_slice(&scene.spheres.colors[n]);
|
||||
sphere_color[3] = OPACITY;
|
||||
sphere_color[3] = scene.spheres.opacities[n];
|
||||
|
||||
ctx.uniform3fv_with_f32_array(
|
||||
sphere_sp_locs[n].as_ref(),
|
||||
|
@ -854,7 +862,11 @@ pub fn Display() -> View {
|
|||
let (dir, pixel_size) = event_dir(&event);
|
||||
console::log_1(&JsValue::from(dir.to_string()));
|
||||
let mut clicked: Option<(Rc<dyn Element>, f64)> = None;
|
||||
for elt in state.assembly.elements.get_clone_untracked() {
|
||||
let tangible_elts = state.assembly.elements
|
||||
.get_clone_untracked()
|
||||
.into_iter()
|
||||
.filter(|elt| !elt.ghost().get());
|
||||
for elt in tangible_elts {
|
||||
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)) {
|
||||
Some(depth) => match clicked {
|
||||
Some((_, best_depth)) => {
|
||||
|
|
|
@ -202,7 +202,11 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
|
|||
) {
|
||||
div(class="element-label") { (label) }
|
||||
div(class="element-representation") { (rep_components) }
|
||||
div(class="status")
|
||||
|
||||
input(
|
||||
r#type="checkbox",
|
||||
bind:checked=element.ghost(),
|
||||
on:click=|event: MouseEvent| event.stop_propagation()
|
||||
)
|
||||
}
|
||||
}
|
||||
ul(class="regulators") {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue
Did we intentionally remove this indicator, which flags an element with an invalidly specified regulator when the regulator list is closed? The removal looks like a regression—especially because we didn't remove the associated CSS—but I wanted to check in case we decided on it in a meeting and I forgot to write it down.
I think I never responded to this. If you think there should be some indication of a regulator with bad input (or something like that) and there currently is no such indication, absolutely feel free to file an issue. I don't recall any discussion that we should not have such an indication. (And hopefully filing issues/recording notes in some permanent online fashion immediately after our meetings will help with confidence on such matters!)