Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Designer Performance #306

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export class OcclusionLayerManager {
throw new Error(`tried to remove container width id ${id} while children still present`);
}
parent!.removeChild(elem);
this.objectManager.returnToPool(DIV, elem);
})
let var_name = containerCssClipPathVar(id);
document.documentElement.style.removeProperty(var_name);
Expand Down
23 changes: 12 additions & 11 deletions pax-designer/src/glass/control_point.pax
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
@mouse_down=self.mouse_down
@double_click=self.double_click
>
if !self.data.styling.round {
if !self.style.round {
<Rectangle class=control_point/>
}
if self.data.styling.round {
if self.style.round {
<Ellipse class=control_point/>
}
<Rectangle fill=TRANSPARENT/>
// for debugging:
// <Rectangle fill=rgba(255, 0, 0, 30)/>
</Group>

@settings {
Expand All @@ -20,21 +22,20 @@
anchor_y: {(self.data.anchor_y*100.0)%},
x: {(self.data.point.x)px},
y: {(self.data.point.y)px},
width: {(self.data.styling.width + self.data.styling.hit_padding)px}
height: {(self.data.styling.height + self.data.styling.hit_padding)px}
rotate: {self.applied_rotation}

width: {(self.style.width + self.style.hit_padding)px}
height: {(self.style.height + self.style.hit_padding)px}
}
.control_point {
stroke: {
color: {self.data.styling.stroke_color}
width: {(self.data.styling.stroke_width_pixels)px}
color: {self.style.stroke_color}
width: {(self.style.stroke_width_pixels)px}
}
x: 50%,
y: 50%,
fill: { self.data.styling.fill_color }
width: {(self.data.styling.width)px}
height: {(self.data.styling.height)px}
anchor_x: {(100.0 - self.data.anchor_x*100.0)%},
anchor_y: {(100.0 - self.data.anchor_y*100.0)%},
fill: {self.style.fill_color}
width: {(self.style.width)px}
height: {(self.style.height)px}
}
}
44 changes: 31 additions & 13 deletions pax-designer/src/glass/control_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@ use crate::model::input::Dir;
pub struct ControlPoint {
pub data: Property<ControlPointDef>,
pub ind: Property<Numeric>,
pub styles: Property<Vec<ControlPointStyling>>,
// the transform of the currently selected object
pub object_rotation: Property<Rotation>,

// private
// the transform to be applied to this control point
pub applied_rotation: Property<Rotation>,
// derived from styling lookup ind in controlpointdef on mount.
pub style: Property<ControlPointStyling>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -153,13 +156,23 @@ impl ToolBehavior for ControlPointTool {

impl ControlPoint {
pub fn on_mount(&mut self, _ctx: &NodeContext) {
let data = self.data.clone();
// NOTE: styling only applied once at mount, not reactive
let style = self
.styles
.read(|styles| styles[self.data.read(|data| data.styling_lookup_ind)].clone());
let affected_by_transform = style.affected_by_transform.clone();
self.style.replace_with(Property::new(style));

let object_transform = self.object_rotation.clone();
let data = self.data.clone();
let deps = [data.untyped(), object_transform.untyped()];
self.applied_rotation.replace_with(Property::computed(
move || {
if data.get().styling.affected_by_transform {
object_transform.get()
if affected_by_transform {
Rotation::Degrees(
(object_transform.get().get_as_degrees() + data.read(|data| data.rotation))
.into(),
)
} else {
Default::default()
}
Expand Down Expand Up @@ -204,14 +217,16 @@ impl ControlPoint {
}

pub fn mouse_over(&mut self, ctx: &NodeContext, _event: Event<MouseOver>) {
self.data.read(|data| {
model::perform_action(
&SetCursor(DesignerCursor {
cursor_type: data.styling.cursor_type,
rotation_degrees: data.node_local_rotation_degrees,
}),
ctx,
);
self.style.read(|style| {
self.data.read(|data| {
model::perform_action(
&SetCursor(DesignerCursor {
cursor_type: style.cursor_type,
rotation_degrees: data.cursor_rotation,
}),
ctx,
);
})
})
}
pub fn mouse_out(&mut self, ctx: &NodeContext, _event: Event<MouseOut>) {
Expand All @@ -227,8 +242,11 @@ pub struct ControlPointDef {
pub anchor_x: f64,
/// 0.0-1.0
pub anchor_y: f64,
pub node_local_rotation_degrees: f64,
pub styling: ControlPointStyling,
/// Node-local rotation in degrees
pub rotation: f64,
// Node-local rotation in degrees
pub cursor_rotation: f64,
pub styling_lookup_ind: usize,
}

#[pax]
Expand Down
1 change: 1 addition & 0 deletions pax-designer/src/glass/wireframe_editor.pax
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
for (data, i) in self.control_points {
<ControlPoint
data=data
styles=styles
ind=i
object_rotation={self.object_rotation}
/>
Expand Down
75 changes: 43 additions & 32 deletions pax-designer/src/glass/wireframe_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use self::editor_generation::Editor;
pub struct WireframeEditor {
pub control_points: Property<Vec<ControlPointDef>>,
pub bounding_segments: Property<Vec<BoundingSegment>>,
pub styles: Property<Vec<ControlPointStyling>>,
pub on_selection_changed: Property<bool>,
pub object_rotation: Property<Rotation>,
}
Expand All @@ -52,6 +53,7 @@ impl WireframeEditor {

let control_points = self.control_points.clone();
let bounding_segments = self.bounding_segments.clone();
let styles = self.styles.clone();
// This is doing _hierarchical_ binding:
// whenever the selection ID changes, the transform and bounds of
// the editor (among other things) are re-bound to the engine node
Expand All @@ -64,7 +66,12 @@ impl WireframeEditor {
if selected.items.len() > 0 {
Self::bind_object_transform(object_rotation.clone(), &selected);
let editor = Editor::new(ctx.clone(), selected);
Self::bind_editor(control_points.clone(), bounding_segments.clone(), editor);
Self::bind_editor(
control_points.clone(),
bounding_segments.clone(),
styles.clone(),
editor,
);
} else {
control_points.replace_with(Property::new(vec![]));
bounding_segments.replace_with(Property::new(vec![]));
Expand All @@ -84,39 +91,41 @@ impl WireframeEditor {
fn bind_editor(
control_points: Property<Vec<ControlPointDef>>,
bounding_segments: Property<Vec<BoundingSegment>>,
editor: Property<Editor>,
styles: Property<Vec<ControlPointStyling>>,
editor: Editor,
) {
let editorcp = editor.clone();
let deps = [editor.untyped()];

let deps: Vec<_> = editor
.controls
.iter()
.map(|set| set.points.untyped())
.collect();
let controls: Vec<_> = editor
.controls
.iter()
.map(|set| set.points.clone())
.enumerate()
.collect();
let new_styles: Vec<_> = editor.controls.into_iter().map(|set| set.styling).collect();
styles.set(new_styles);
control_points.replace_with(Property::computed(
move || {
let mut control_points = vec![];
let mut behaviors = vec![];
for control_set in editorcp.get().controls {
let (control_points_set, behavior_set): (Vec<_>, Vec<_>) = control_set
.points
.into_iter()
.map(|c_point| {
(
(c_point.point, c_point.rotation, c_point.anchor),
c_point.behavior,
)
})
.unzip();
let control_points_from_set: Vec<ControlPointDef> = control_points_set
.into_iter()
.map(|(p, rot, anchor)| ControlPointDef {
point: p.into(),
node_local_rotation_degrees: rot,
anchor_x: anchor.x,
anchor_y: anchor.y,
styling: control_set.styling.clone(),
})
.collect();
control_points.extend(control_points_from_set);
behaviors.extend(behavior_set);
}
let (control_points, behaviors) = controls
.iter()
.flat_map(|(style_index, c)| c.get().into_iter().map(|p| (*style_index, p)))
.map(|(style_index, p)| {
(
ControlPointDef {
point: p.point.into(),
anchor_x: p.anchor.x,
anchor_y: p.anchor.y,
rotation: p.rotation,
cursor_rotation: p.cursor_rotation,
styling_lookup_ind: style_index,
},
p.behavior,
)
})
.unzip();

CONTROL_POINT_FUNCS.with_borrow_mut(|funcs| {
*funcs = Some(behaviors);
Expand All @@ -126,8 +135,10 @@ impl WireframeEditor {
&deps,
));

let segments = editor.segments.clone();
let deps = [segments.untyped()];
bounding_segments.replace_with(Property::computed(
move || editor.get().segments.into_iter().map(Into::into).collect(),
move || segments.get().into_iter().map(Into::into).collect(),
&deps,
));
}
Expand Down
30 changes: 15 additions & 15 deletions pax-designer/src/glass/wireframe_editor/editor_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ pub mod stacker_control;
#[derive(Clone, Default)]
pub struct Editor {
pub controls: Vec<ControlPointSet>,
pub segments: Vec<(Point2<Glass>, Point2<Glass>)>,
pub segments: Property<Vec<(Point2<Glass>, Point2<Glass>)>>,
}

impl Editor {
pub fn new(ctx: NodeContext, selection: SelectionState) -> Property<Self> {
pub fn new(ctx: NodeContext, selection: SelectionState) -> Self {
let total_bounds = selection.total_bounds.clone();
let deps = [total_bounds.untyped()];
let total_bounds_cp = total_bounds.clone();
Expand All @@ -60,21 +60,16 @@ impl Editor {
&deps,
);

let mut deps: Vec<_> = control_point_sets.iter().map(|p| p.untyped()).collect();
deps.push(bounding_segments.untyped());
Property::computed(
move || Self {
controls: control_point_sets.iter().map(|set| set.get()).collect(),
segments: bounding_segments.get(),
},
&deps,
)
Self {
controls: control_point_sets,
segments: bounding_segments,
}
}

fn object_specific_control_point_sets(
ctx: NodeContext,
selection: SelectionState,
) -> Vec<Property<ControlPointSet>> {
) -> Vec<ControlPointSet> {
if selection.items.len() != 1 {
return Vec::default();
}
Expand All @@ -90,9 +85,9 @@ impl Editor {
match import_path.as_ref().map(|v| v.as_str()) {
Some("pax_std::layout::stacker::Stacker") => {
vec![
stacker_control::stacker_divider_control_set(ctx.clone(), item.clone()),
// add slot control generally for all slot components?
slot_control::slot_dot_control_set(ctx.clone(), item.clone()),
stacker_control::stacker_divider_control_set(ctx.clone(), item.clone()),
]
}
_ => return Vec::default(),
Expand All @@ -108,8 +103,10 @@ pub struct CPoint {
pub point: Point2<Glass>,
/// Node-local rotation in degrees
pub rotation: f64,
/// Node-local cursor rotation in degrees
pub cursor_rotation: f64,
/// Anchor of control point (x/y 0.0-1.0, 0.5 is center)
pub anchor: Point2<Generic>,
pub anchor: Point2<NodeLocal>,
/// behavior on click/double click
pub behavior: ControlPointToolFactory,
}
Expand All @@ -119,7 +116,10 @@ impl Default for CPoint {
Self {
point: Default::default(),
rotation: 0.0,
cursor_rotation: 0.0,
anchor: Point2::new(0.5, 0.5),
// TODO we want this to be required most likely,
// make builder instead of derive of Default?
behavior: ControlPointToolFactory {
tool_factory: Rc::new(|_, _| {
Rc::new(RefCell::new({
Expand Down Expand Up @@ -179,6 +179,6 @@ impl Interpolatable for ControlPointSet {}

#[derive(Clone, Default)]
pub struct ControlPointSet {
pub points: Vec<CPoint>,
pub points: Property<Vec<CPoint>>,
pub styling: ControlPointStyling,
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{

use super::ControlPointSet;

pub fn anchor_control_point_set(anchor: Property<Point2<Glass>>) -> Property<ControlPointSet> {
pub fn anchor_control_point_set(anchor: Property<Point2<Glass>>) -> ControlPointSet {
let anchor_control_point_styling = ControlPointStyling {
round: true,
stroke_color: Color::BLUE,
Expand All @@ -36,22 +36,22 @@ pub fn anchor_control_point_set(anchor: Property<Point2<Glass>>) -> Property<Con
};

let deps = [anchor.untyped()];
Property::computed(
let anchor_control_point = Property::computed(
move || {
let anchor = anchor.get();
let anchor_control_point = vec![CPoint {
vec![CPoint {
point: anchor,
behavior: anchor_factory(),
..Default::default()
}];

ControlPointSet {
points: anchor_control_point,
styling: anchor_control_point_styling.clone(),
}
}]
},
&deps,
)
);

ControlPointSet {
points: anchor_control_point,
styling: anchor_control_point_styling.clone(),
}
}

fn anchor_factory() -> ControlPointToolFactory {
Expand Down
Loading
Loading