Migrate the Select tool to the document graph (#1433)

* function for accessing document metadata

* Better select tool

* Fix render

* Fix transforms

* Fix loading saved documents

* Populate graph UI when loading autosave

* Multiple transform nodes

* Fix deep select

* Graph tooltips

* Fix flip axis icon

* Show disabled widgets

* Stop select tool from selecting artboards

* Disable (not hide) the pivot widget; remove Deep/Shallow select for now

* Code review changes

* Fix pivot position with select tool

* Fix incorrectly selected layers when shift clicking

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2023-10-17 11:09:32 -07:00
committed by Keavon Chambers
co-authored by Dennis Kobert Keavon Chambers
parent e1cdb2242d
commit 5827e989dc
46 changed files with 1041 additions and 1215 deletions
@@ -103,14 +103,14 @@ struct ArtboardToolData {
impl ArtboardToolData {
fn refresh_overlays(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
let current_artboard = self.selected_artboard.and_then(|layer| document.document_legacy.metadata.bounding_box_document(layer));
let current_artboard = self.selected_artboard.and_then(|layer| document.metadata().bounding_box_document(layer));
match (current_artboard, self.bounding_box_overlays.take()) {
(None, Some(bounding_box_overlays)) => bounding_box_overlays.delete(responses),
(Some(bounds), paths) => {
let mut bounding_box_overlays = paths.unwrap_or_else(|| BoundingBoxOverlays::new(responses));
bounding_box_overlays.bounds = bounds;
bounding_box_overlays.transform = document.document_legacy.metadata.document_to_viewport;
bounding_box_overlays.transform = document.metadata().document_to_viewport;
bounding_box_overlays.transform(responses);
@@ -265,7 +265,7 @@ impl Fsm for ArtboardToolFsmState {
let mouse_position = input.mouse.position;
let snapped_mouse_position = tool_data.snap_manager.snap_position(responses, document, mouse_position);
let root_transform = document.document_legacy.metadata.document_to_viewport.inverse();
let root_transform = document.metadata().document_to_viewport.inverse();
let mut start = tool_data.drag_start;
let mut size = snapped_mouse_position - start;
@@ -341,7 +341,7 @@ impl Fsm for BrushToolFsmState {
document, global_tool_data, input, ..
} = tool_action_data;
let document_position = document.document_legacy.metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
let document_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
let layer_position = tool_data.transform.inverse().transform_point2(document_position);
let ToolMessage::Brush(event) = event else {
@@ -68,7 +68,7 @@ impl Fsm for FillToolFsmState {
let ToolMessage::Fill(event) = event else {
return self;
};
let Some(layer_identifier) = document.document_legacy.metadata.click(input.mouse.position) else {
let Some(layer_identifier) = document.metadata().click(input.mouse.position, &document.document_legacy.document_network) else {
return self;
};
let layer = layer_identifier.to_path();
@@ -110,7 +110,7 @@ impl Fsm for NodeGraphToolFsmState {
match (self, event) {
(_, FrameToolMessage::DocumentIsDirty | FrameToolMessage::SelectionChanged) => {
tool_data.path_outlines.clear_selected(responses);
tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data);
//tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data);
self
}
@@ -191,7 +191,7 @@ impl Fsm for FreehandToolFsmState {
document, global_tool_data, input, ..
} = tool_action_data;
let transform = document.document_legacy.metadata.document_to_viewport;
let transform = document.metadata().document_to_viewport;
let ToolMessage::Freehand(event) = event else {
return self;
@@ -116,10 +116,10 @@ enum GradientToolFsmState {
/// Computes the transform from gradient space to viewport space (where gradient space is 0..1)
fn gradient_space_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 {
let bounds = document.document_legacy.metadata.bounding_box_with_transform(layer, DAffine2::IDENTITY).unwrap();
let bounds = document.metadata().nonzero_bounding_box(layer);
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
let multiplied = document.document_legacy.metadata.transform_from_viewport(layer);
let multiplied = document.metadata().transform_to_viewport(layer);
multiplied * bound_transform
}
@@ -252,7 +252,7 @@ impl SelectedGradient {
};
// Clear the gradient if layer deleted
if !inner_gradient.layer.exists(&document.document_legacy.metadata) {
if !inner_gradient.layer.exists(&document.metadata()) {
responses.add(ToolMessage::RefreshToolOptions);
*gradient = None;
return;
@@ -391,7 +391,7 @@ impl Fsm for GradientToolFsmState {
SelectedGradient::update(&mut tool_data.selected_gradient, document, responses);
}
for layer in document.document_legacy.metadata.selected_visible_layers() {
for layer in document.metadata().selected_visible_layers() {
if let Some(gradient) = get_gradient(layer, &document.document_legacy) {
let dragging = tool_data
.selected_gradient
@@ -526,7 +526,7 @@ impl Fsm for GradientToolFsmState {
document.backup_nonmut(responses);
GradientToolFsmState::Drawing
} else {
let selected_layer = document.document_legacy.metadata.click(input.mouse.position);
let selected_layer = document.metadata().click(input.mouse.position, &document.document_legacy.document_network);
// Apply the gradient to the selected layer
if let Some(layer) = selected_layer {
@@ -540,7 +540,7 @@ impl Fsm for GradientToolFsmState {
// return self;
// }
if !document.document_legacy.metadata.selected_layers_contains(layer) {
if !document.metadata().selected_layers_contains(layer) {
let replacement_selected_layers = vec![layer.to_path()];
responses.add(DocumentMessage::SetSelectedLayers { replacement_selected_layers });
@@ -118,7 +118,7 @@ impl Fsm for ImaginateToolFsmState {
match (self, event) {
(_, ImaginateToolMessage::DocumentIsDirty | ImaginateToolMessage::SelectionChanged) => {
tool_data.path_outlines.clear_selected(responses);
tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data);
//tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data);
self
}
@@ -181,7 +181,7 @@ impl Fsm for LineToolFsmState {
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
let viewport_start = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
tool_data.drag_start = document.document_legacy.metadata.document_to_viewport.inverse().transform_point2(viewport_start);
tool_data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(viewport_start);
let subpath = bezier_rs::Subpath::new_line(DVec2::ZERO, DVec2::X);
@@ -202,7 +202,7 @@ impl Fsm for LineToolFsmState {
tool_data.drag_current = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
let keyboard = &input.keyboard;
let transform = document.document_legacy.metadata.document_to_viewport;
let transform = document.metadata().document_to_viewport;
responses.add(generate_transform(tool_data, transform, keyboard.key(lock_angle), keyboard.key(snap_angle), keyboard.key(center)));
LineToolFsmState::Drawing
@@ -210,7 +210,7 @@ struct PathToolData {
impl PathToolData {
fn refresh_overlays(&mut self, document: &DocumentMessageHandler, shape_editor: &mut ShapeState, shape_overlay: &mut OverlayRenderer, responses: &mut VecDeque<Message>) {
// Set the previously selected layers to invisible
for layer in document.document_legacy.metadata.all_layers() {
for layer in document.metadata().all_layers() {
shape_overlay.layer_overlay_visibility(&document.document_legacy, layer, false, responses);
}
@@ -242,15 +242,11 @@ impl PathToolData {
PathToolFsmState::Dragging
}
// We didn't find a point nearby, so consider selecting the nearest shape instead
else if let Some(layer) = document.document_legacy.metadata.click(input.mouse.position) {
// TODO: Actual selection
let layer_list = vec![layer.to_path()];
else if let Some(layer) = document.metadata().click(input.mouse.position, &document.document_legacy.document_network) {
if shift {
responses.add(DocumentMessage::AddSelectedLayers { additional_layers: layer_list });
responses.add(NodeGraphMessage::AddSelectNodes { nodes: vec![layer.to_node()] });
} else {
responses.add(DocumentMessage::SetSelectedLayers {
replacement_selected_layers: layer_list,
});
responses.add(NodeGraphMessage::SetSelectNodes { nodes: vec![layer.to_node()] });
}
self.drag_start_pos = input.mouse.position;
self.previous_mouse_position = input.mouse.position;
@@ -342,7 +338,7 @@ impl Fsm for PathToolFsmState {
match (self, event) {
(_, PathToolMessage::SelectionChanged) => {
// Set the newly targeted layers to visible
let target_layers = document.document_legacy.metadata.selected_layers().collect();
let target_layers = document.metadata().selected_layers().collect();
shape_editor.set_selected_layers(target_layers);
tool_data.refresh_overlays(document, shape_editor, shape_overlay, responses);
@@ -354,7 +350,7 @@ impl Fsm for PathToolFsmState {
(_, PathToolMessage::DocumentIsDirty) => {
// When the document has moved / needs to be redraw, re-render the overlays
// TODO the overlay system should probably receive this message instead of the tool
for layer in document.document_legacy.metadata.selected_layers() {
for layer in document.metadata().selected_layers() {
shape_overlay.render_subpath_overlays(&shape_editor.selected_shape_state, &document.document_legacy, layer, responses);
}
@@ -386,7 +382,7 @@ impl Fsm for PathToolFsmState {
let shift_pressed = input.keyboard.get(add_to_selection as usize);
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(DocumentMessage::DeselectAllLayers);
responses.add(NodeGraphMessage::SetSelectNodes { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(&document.document_legacy, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
tool_data.refresh_overlays(document, shape_editor, shape_overlay, responses);
@@ -401,7 +397,7 @@ impl Fsm for PathToolFsmState {
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(DocumentMessage::DeselectAllLayers);
responses.add(NodeGraphMessage::SetSelectNodes { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(&document.document_legacy, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
tool_data.refresh_overlays(document, shape_editor, shape_overlay, responses);
@@ -247,7 +247,7 @@ impl PenToolData {
let layer_path = document.get_path_for_new_layer();
// Get the position and set properties
let transform = document.document_legacy.metadata.document_to_viewport * document.document_legacy.multiply_transforms(&layer_path[..layer_path.len() - 1]).unwrap_or_default();
let transform = document.metadata().document_to_viewport * document.document_legacy.multiply_transforms(&layer_path[..layer_path.len() - 1]).unwrap_or_default();
let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position);
let start_position = transform.inverse().transform_point2(snapped_position);
self.weight = line_weight;
@@ -566,7 +566,7 @@ impl Fsm for PenToolFsmState {
transform = DAffine2::IDENTITY;
}
transform = document.document_legacy.metadata.document_to_viewport * transform;
transform = document.metadata().document_to_viewport * transform;
let ToolMessage::Pen(event) = event else {
return self;
@@ -579,19 +579,19 @@ impl Fsm for PenToolFsmState {
(_, PenToolMessage::DocumentIsDirty) => {
// When the document has moved / needs to be redraw, re-render the overlays
// TODO the overlay system should probably receive this message instead of the tool
for layer in document.document_legacy.metadata.selected_layers() {
for layer in document.metadata().selected_layers() {
shape_overlay.render_subpath_overlays(&shape_editor.selected_shape_state, &document.document_legacy, layer, responses);
}
self
}
(_, PenToolMessage::SelectionChanged) => {
// Set the previously selected layers to invisible
for layer in document.document_legacy.metadata.all_layers() {
for layer in document.metadata().all_layers() {
shape_overlay.layer_overlay_visibility(&document.document_legacy, layer, false, responses);
}
// Redraw the overlays of the newly selected layers
for layer in document.document_legacy.metadata.selected_layers() {
for layer in document.metadata().selected_layers() {
shape_overlay.render_subpath_overlays(&shape_editor.selected_shape_state, &document.document_legacy, layer, responses);
}
self
File diff suppressed because it is too large Load Diff
@@ -202,7 +202,7 @@ impl Fsm for SplineToolFsmState {
..
} = tool_action_data;
let transform = document.document_legacy.metadata.document_to_viewport;
let transform = document.metadata().document_to_viewport;
let ToolMessage::Spline(event) = event else {
return self;