Node network subgraph editing (#1750)

* Breadcrumb visualization, nested network consistency, create definitions for Merge internal nodes

* Add index to network inputs, remove imports usage from flatten network

* Replace NodeOutput with NodeInput::Node

* Fully remove imports field, remove unnecessary identity nodes, move Output node to encapsulating network

* Replace previous_outputs with root_node, fix adding artboard/layer to empty network

* Import/Export UI nodes

* Display input/output types dynamically from compiled network

* Add LayerNodeIdentifer::ROOT_PARENT

* Prevent .to_node() on ROOT_PARENT

* Separate NodeGraphMessage and GraphOperationMessage

* General bug fixes with nested networks

* Change layer color, various bug fixes and improvements

* Fix disconnect and set node input for proto nodes and UI export node

* Dashed line to export for previewed node

* Fix deleting proto nodes and nodes that feed into export

* Allow modifications to nodes outside of nested network

* Get network from Node Id parameter

* Change root_node to previous_root_node

* Get TaggedValue from proto node implementation type when disconnecting

* Improve preview functionality and state

* Artboard position and delete children fix

* Name inputs/outputs based on DocumentNodeDefinition or type, fix new artboard/layer insertion

* replace "Link" with "Wire", adjust previewing

* Various bug fixes and improvements

* Modify Sample and Poisson-Disk points, fix incorrect input index and deleting currently viewed node

* Open demo artwork

* Fix opening already upgraded documents and refactor FrontendGraphDataType usages

* Fix deleting within network and other bugs

* Get default node input from compiled network when copying, fix previews, tests, demo artwork

* Code cleanup

* Hide EditorApi and add a comment describing unresolved Import node input types

* Code review

* Replace placeholder ROOT_PARENT NodeId with std::u64::MAX

* Breadcrumb padding

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
adamgerhant
2024-06-02 08:01:56 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent e4d3faa52a
commit 6d74abb4de
77 changed files with 3921 additions and 2324 deletions
@@ -227,6 +227,7 @@ pub struct NodeGraphLayer<'a> {
impl<'a> NodeGraphLayer<'a> {
/// Get the layer node from the document
pub fn new(layer: LayerNodeIdentifier, network: &'a NodeNetwork) -> Self {
debug_assert!(layer != LayerNodeIdentifier::ROOT_PARENT, "Cannot create new NodeGraphLayer from ROOT_PARENT");
Self {
node_graph: network,
layer_node: layer.to_node(),
@@ -33,6 +33,11 @@ impl Resize {
let Some(layer) = self.layer else {
return None;
};
if layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Resize layer cannot be ROOT_PARENT");
}
if !document.network().nodes.contains_key(&layer.to_node()) {
self.layer.take();
return None;
@@ -276,7 +276,13 @@ impl SnapManager {
candidates.push(layer);
}
}
add_candidates(LayerNodeIdentifier::ROOT, snap_data, quad, &mut candidates);
if let Some(root) = snap_data.document.network.get_root_node() {
if snap_data.document.network.nodes.get(&root.id).expect("Root should always be a node in find_candidates").is_layer {
add_candidates(LayerNodeIdentifier::new(root.id, &snap_data.document.network), snap_data, quad, &mut candidates);
}
}
if candidates.len() > 10 {
warn!("Snap candidate overflow");
}
@@ -203,7 +203,6 @@ impl LayerSnapper {
}
pub fn snap_anchors(&mut self, snap_data: &mut SnapData, point: &SnapCandidatePoint, snap_results: &mut SnapResults, c: SnapConstraint, constrained_point: DVec2) {
self.collect_anchors(snap_data, point.source_index == 0);
//info!("Points to snap {:#?}", self.points_to_snap);
let mut best = None;
for candidate in &self.points_to_snap {
// Candidate is not on constraint
@@ -155,6 +155,10 @@ impl ArtboardToolData {
let Some(movement) = &bounds.selected_edges else {
return;
};
if self.selected_artboard.unwrap() == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Selected artboard cannot be ROOT_PARENT");
return;
}
let center = from_center.then_some(bounds.center_of_transformation);
let (min, size) = movement.new_size(mouse_position, bounds.transform, center, constrain_square, None);
@@ -233,6 +237,10 @@ impl Fsm for ArtboardToolFsmState {
let size = bounds.bounds[1] - bounds.bounds[0];
let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_position - tool_data.drag_current);
if tool_data.selected_artboard.unwrap() == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Selected artboard cannot be ROOT_PARENT");
return ArtboardToolFsmState::Ready;
}
responses.add(GraphOperationMessage::ResizeArtboard {
id: tool_data.selected_artboard.unwrap().to_node(),
location: position.round().as_ivec2(),
@@ -257,7 +265,7 @@ impl Fsm for ArtboardToolFsmState {
}
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
let mouse_position = input.mouse.position;
let snapped_mouse_position = mouse_position; //tool_data.snap_manager.snap_position(responses, document, mouse_position);
let snapped_mouse_position = mouse_position;
let root_transform = document.metadata().document_to_viewport.inverse();
@@ -280,11 +288,15 @@ impl Fsm for ArtboardToolFsmState {
let start = start.min(end);
if let Some(artboard) = tool_data.selected_artboard {
responses.add(GraphOperationMessage::ResizeArtboard {
id: artboard.to_node(),
location: start.round().as_ivec2(),
dimensions: size.round().as_ivec2(),
});
if artboard == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Selected artboard cannot be ROOT_PARENT");
} else {
responses.add(GraphOperationMessage::ResizeArtboard {
id: artboard.to_node(),
location: start.round().as_ivec2(),
dimensions: size.round().as_ivec2(),
});
}
} else {
let id = NodeId(generate_uuid());
@@ -395,11 +407,15 @@ impl Fsm for ArtboardToolFsmState {
}
(_, ArtboardToolMessage::NudgeSelected { delta_x, delta_y }) => {
if let Some(bounds) = &mut tool_data.bounding_box_manager {
responses.add(GraphOperationMessage::ResizeArtboard {
id: tool_data.selected_artboard.unwrap().to_node(),
location: DVec2::new(bounds.bounds[0].x + delta_x, bounds.bounds[0].y + delta_y).round().as_ivec2(),
dimensions: (bounds.bounds[1] - bounds.bounds[0]).round().as_ivec2(),
});
if tool_data.selected_artboard.unwrap() == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Selected artboard cannot be ROOT_PARENT");
} else {
responses.add(GraphOperationMessage::ResizeArtboard {
id: tool_data.selected_artboard.unwrap().to_node(),
location: DVec2::new(bounds.bounds[0].x + delta_x, bounds.bounds[0].y + delta_y).round().as_ivec2(),
dimensions: (bounds.bounds[1] - bounds.bounds[0]).round().as_ivec2(),
});
}
}
ArtboardToolFsmState::Ready
@@ -323,6 +323,7 @@ impl Fsm for BrushToolFsmState {
let layer_position = tool_data.transform.inverse().transform_point2(parent_transform);
let layer_document_scale = document.metadata().transform_to_document(parent) * tool_data.transform;
// TODO: Also scale it based on the input image ('Background' parameter).
// TODO: Resizing the input image results in a different brush size from the chosen diameter.
let layer_scale = 0.0001_f64 // Safety against division by zero
@@ -355,7 +356,7 @@ impl Fsm for BrushToolFsmState {
(BrushToolFsmState::Drawing, BrushToolMessage::PointerMove) => {
if let Some(layer) = tool_data.layer {
if let Some(stroke) = tool_data.strokes.last_mut() {
let parent = layer.parent(document.metadata()).unwrap_or_default();
let parent = layer.parent(document.metadata()).unwrap_or(LayerNodeIdentifier::ROOT_PARENT);
let parent_position = document.metadata().transform_to_viewport(parent).inverse().transform_point2(input.mouse.position);
let layer_position = tool_data.transform.inverse().transform_point2(parent_position);
@@ -128,7 +128,7 @@ pub enum GradientDragTarget {
/// Contains information about the selected gradient handle
#[derive(Clone, Debug, Default)]
struct SelectedGradient {
layer: LayerNodeIdentifier,
layer: Option<LayerNodeIdentifier>,
transform: DAffine2,
gradient: Gradient,
dragging: GradientDragTarget,
@@ -138,7 +138,7 @@ impl SelectedGradient {
pub fn new(gradient: Gradient, layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Self {
let transform = gradient_space_transform(layer, document);
Self {
layer,
layer: Some(layer),
transform,
gradient,
dragging: GradientDragTarget::End,
@@ -198,10 +198,12 @@ impl SelectedGradient {
/// Update the layer fill to the current gradient
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
self.gradient.transform = self.transform;
responses.add(GraphOperationMessage::FillSet {
layer: self.layer,
fill: Fill::Gradient(self.gradient.clone()),
});
if let Some(layer) = self.layer {
responses.add(GraphOperationMessage::FillSet {
layer,
fill: Fill::Gradient(self.gradient.clone()),
});
}
}
}
@@ -250,7 +252,9 @@ impl Fsm for GradientToolFsmState {
for layer in document.selected_nodes.selected_visible_layers(document.metadata()) {
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document);
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
let dragging = selected
.filter(|selected| selected.layer.map_or(false, |selected_layer| selected_layer == layer))
.map(|selected| selected.dragging);
let Gradient { start, end, positions, .. } = gradient;
let (start, end) = (transform.transform_point2(start), transform.transform_point2(end));
@@ -289,10 +293,13 @@ impl Fsm for GradientToolFsmState {
// The gradient has only one point and so should become a fill
if selected_gradient.gradient.positions.len() == 1 {
responses.add(GraphOperationMessage::FillSet {
layer: selected_gradient.layer,
fill: Fill::Solid(selected_gradient.gradient.positions[0].1),
});
if let Some(layer) = selected_gradient.layer {
responses.add(GraphOperationMessage::FillSet {
layer,
fill: Fill::Solid(selected_gradient.gradient.positions[0].1),
});
}
return self;
}
@@ -367,7 +374,7 @@ impl Fsm for GradientToolFsmState {
if pos.distance_squared(mouse) < tolerance {
dragging = true;
tool_data.selected_gradient = Some(SelectedGradient {
layer,
layer: Some(layer),
transform,
gradient: gradient.clone(),
dragging: GradientDragTarget::Step(index),
@@ -381,7 +388,7 @@ impl Fsm for GradientToolFsmState {
if pos.distance_squared(mouse) < tolerance {
dragging = true;
tool_data.selected_gradient = Some(SelectedGradient {
layer,
layer: Some(layer),
transform,
gradient: gradient.clone(),
dragging: dragging_target,
@@ -362,9 +362,9 @@ impl PathToolData {
// TODO: enable snapping
//self
// .snap_manager
// .start_snap(document, input, document.bounding_boxes(Some(&selected_layers), None, font_cache), true, true);
// self
// .snap_manager
// .start_snap(document, input, document.bounding_boxes(Some(&selected_layers), None, font_cache), true, true);
// Do not snap against handles when anchor is selected
let mut additional_selected_points = Vec::new();
@@ -147,12 +147,21 @@ impl SelectTool {
})
}
fn boolean_widgets(&self) -> impl Iterator<Item = WidgetHolder> {
fn boolean_widgets(&self, selected_count: usize) -> impl Iterator<Item = WidgetHolder> {
let enabled = move |operation| {
if operation == BooleanOperation::Union {
(1..=2).contains(&selected_count)
} else {
selected_count == 2
}
};
let operations = BooleanOperation::list();
let icons = BooleanOperation::icons();
operations.into_iter().zip(icons.into_iter()).map(|(operation, icon)| {
operations.into_iter().zip(icons.into_iter()).map(move |(operation, icon)| {
IconButton::new(icon, 24)
.tooltip(operation.to_string())
.disabled(!enabled(operation))
.on_update(move |_| GraphOperationMessage::InsertBooleanOperation { operation }.into())
.widget_holder()
})
@@ -194,10 +203,8 @@ impl LayoutHolder for SelectTool {
widgets.extend(self.flip_widgets(disabled));
// Boolean
if self.tool_data.selected_layers_count == 2 {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
widgets.extend(self.boolean_widgets());
}
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
widgets.extend(self.boolean_widgets(self.tool_data.selected_layers_count));
Layout::WidgetLayout(WidgetLayout::new(vec![LayoutGroup::Row { widgets }]))
}
@@ -316,6 +323,14 @@ impl SelectToolData {
let mut new_dragging = Vec::new();
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied().rev()) {
let Some(layer) = layer_ancestors.last().copied() else { continue };
// `layer` cannot be `ROOT_PARENT`, since `ROOT_PARENT` cannot be part of `layers_dragging`
if layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("ROOT_PARENT cannot be in layers_dragging");
continue;
}
// `parent` can be `ROOT_PARENT`
let Some(parent) = layer.parent(&document.metadata) else { continue };
// Moves the layer back to its starting position.
@@ -345,7 +360,8 @@ impl SelectToolData {
copy_ids.insert(node_id, NodeId((index + 1) as u64));
});
};
let nodes: HashMap<NodeId, DocumentNode> = NodeGraphMessageHandler::copy_nodes(document.network(), &copy_ids).collect();
let nodes: HashMap<NodeId, DocumentNode> =
NodeGraphMessageHandler::copy_nodes(document.network(), &document.node_graph_handler.network, &document.node_graph_handler.resolved_types, &copy_ids).collect();
let insert_index = DocumentMessageHandler::get_calculated_insert_index(&document.metadata, &document.selected_nodes, parent);
@@ -368,8 +384,13 @@ impl SelectToolData {
// Delete the duplicated layers
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied()) {
let layer = layer_ancestors.last().unwrap();
if *layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("ROOT_PARENT cannot be in layers_dragging");
continue;
}
responses.add(NodeGraphMessage::DeleteNodes {
node_ids: vec![layer_ancestors.last().unwrap().to_node()],
node_ids: vec![layer.to_node()],
reconnect: true,
});
}
@@ -382,7 +403,17 @@ impl SelectToolData {
skip_rerender: true,
});
}
let nodes = original.iter().map(|layer| layer.to_node()).collect();
let nodes = original
.iter()
.filter_map(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
Some(layer.to_node())
} else {
log::error!("ROOT_PARENT cannot be part of non_duplicated_layers");
None
}
})
.collect();
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });
self.layers_dragging = original;
}
@@ -512,8 +543,8 @@ impl Fsm for SelectToolFsmState {
if tool_data.pivot.is_over(input.mouse.position) {
responses.add(DocumentMessage::StartTransaction);
//tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
//tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
// tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
// tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
SelectToolFsmState::DraggingPivot
}
@@ -526,7 +557,15 @@ impl Fsm for SelectToolFsmState {
if let Some(bounds) = &mut tool_data.bounding_box_manager {
bounds.original_bound_transform = bounds.transform;
tool_data.layers_dragging.retain(|layer| document.network.nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
document.network.nodes.contains_key(&layer.to_node())
} else {
log::error!("ROOT_PARENT should not be part of layers_dragging");
false
}
});
let mut selected = Selected::new(
&mut bounds.original_transforms,
&mut bounds.center_of_transformation,
@@ -548,7 +587,14 @@ impl Fsm for SelectToolFsmState {
responses.add(DocumentMessage::StartTransaction);
if let Some(bounds) = &mut tool_data.bounding_box_manager {
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
document.network.nodes.contains_key(&layer.to_node())
} else {
log::error!("ROOT_PARENT should not be part of layers_dragging");
false
}
});
let mut selected = Selected::new(
&mut bounds.original_transforms,
&mut bounds.center_of_transformation,
@@ -705,7 +751,14 @@ impl Fsm for SelectToolFsmState {
let pivot_transform = DAffine2::from_translation(pivot);
let transformation = pivot_transform * delta * pivot_transform.inverse();
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
document.network.nodes.contains_key(&layer.to_node())
} else {
log::error!("ROOT_PARENT should not be part of layers_dragging");
false
}
});
let selected = &tool_data.layers_dragging;
let mut selected = Selected::new(
&mut bounds.original_transforms,
@@ -748,7 +801,14 @@ impl Fsm for SelectToolFsmState {
let delta = DAffine2::from_angle(snapped_angle);
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
document.network().nodes.contains_key(&layer.to_node())
} else {
log::error!("ROOT_PARENT should not be part of replacement_selected_layers");
false
}
});
let mut selected = Selected::new(
&mut bounds.original_transforms,
&mut bounds.center_of_transformation,
@@ -767,7 +827,7 @@ impl Fsm for SelectToolFsmState {
}
(SelectToolFsmState::DraggingPivot, SelectToolMessage::PointerMove(modifier_keys)) => {
let mouse_position = input.mouse.position;
let snapped_mouse_position = mouse_position; //tool_data.snap_manager.snap_position(responses, document, mouse_position);
let snapped_mouse_position = mouse_position;
tool_data.pivot.set_viewport_position(snapped_mouse_position, document, responses);
// AutoPanning
@@ -884,14 +944,28 @@ impl Fsm for SelectToolFsmState {
tool_data.layers_dragging.extend(replacement_selected_layers.iter());
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: replacement_selected_layers.iter().map(|layer| layer.to_node()).collect(),
nodes: replacement_selected_layers
.iter()
.filter_map(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
Some(layer.to_node())
} else {
log::error!("ROOT_PARENT cannot be part of replacement_selected_layers");
None
}
})
.collect(),
});
}
} else if let Some(selecting_layer) = tool_data.select_single_layer.take() {
if !tool_data.has_dragged {
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: vec![selecting_layer.to_node()],
});
if selecting_layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("selecting_layer should not be ROOT_PARENT");
} else {
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: vec![selecting_layer.to_node()],
});
}
}
}
@@ -955,7 +1029,18 @@ impl Fsm for SelectToolFsmState {
tool_data.layers_dragging = new_selected.into_iter().collect();
responses.add(DocumentMessage::StartTransaction);
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: tool_data.layers_dragging.iter().map(|layer| layer.to_node()).collect(),
nodes: tool_data
.layers_dragging
.iter()
.filter_map(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
Some(layer.to_node())
} else {
log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging");
None
}
})
.collect(),
});
}
responses.add(OverlaysMessage::Draw);
@@ -986,7 +1071,13 @@ impl Fsm for SelectToolFsmState {
SelectToolFsmState::Ready { selection }
}
(_, SelectToolMessage::Abort) => {
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
document.network().nodes.contains_key(&layer.to_node())
} else {
false
}
});
if let Some(mut bounding_box_overlays) = tool_data.bounding_box_manager.take() {
let mut selected = Selected::new(
&mut bounding_box_overlays.original_transforms,
@@ -1103,27 +1194,47 @@ fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec
.filter(not_artboard(document))
.find(|&ancestor| document.selected_nodes.selected_layers_contains(ancestor, document.metadata()));
let new_selected = ancestor.unwrap_or_else(|| {
layer
.ancestors(document.metadata())
.take_while(|&layer| layer != LayerNodeIdentifier::ROOT)
.filter(not_artboard(document))
.last()
.unwrap_or(layer)
});
let new_selected = ancestor.unwrap_or_else(|| layer.ancestors(document.metadata()).filter(not_artboard(document)).last().unwrap_or(layer));
tool_data.layers_dragging.retain(|layer| !layer.ancestors(document.metadata()).any(|ancestor| ancestor == new_selected));
tool_data.layers_dragging.push(new_selected);
}
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: tool_data.layers_dragging.iter().map(|layer| layer.to_node()).collect(),
nodes: tool_data
.layers_dragging
.iter()
.filter_map(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
Some(layer.to_node())
} else {
log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging");
None
}
})
.collect(),
});
}
fn drag_deepest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<LayerNodeIdentifier>, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) {
tool_data.layers_dragging.append(&mut vec![document.find_deepest(&selected, &document.network).unwrap_or_default()]);
tool_data
.layers_dragging
.append(&mut vec![document.find_deepest(&selected, &document.network).unwrap_or(LayerNodeIdentifier::new(
document.network.get_root_node().expect("Root node should exist when dragging layers").id,
&document.network,
))]);
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: tool_data.layers_dragging.iter().map(|layer| layer.to_node()).collect(),
nodes: tool_data
.layers_dragging
.iter()
.filter_map(|layer| {
if *layer != LayerNodeIdentifier::ROOT_PARENT {
Some(layer.to_node())
} else {
log::error!("ROOT_PARENT cannot be part of tool_data.layers_dragging");
None
}
})
.collect(),
});
}
@@ -1141,6 +1252,11 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
return;
};
if new_selected == LayerNodeIdentifier::ROOT_PARENT {
log::error!("new_selected cannot be ROOT_PARENT");
return;
}
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] });
}
@@ -200,10 +200,7 @@ impl Fsm for SplineToolFsmState {
return self;
};
match (self, event) {
(_, SplineToolMessage::CanvasTransformed) => {
// tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
self
}
(_, SplineToolMessage::CanvasTransformed) => self,
(SplineToolFsmState::Ready, SplineToolMessage::DragStart) => {
responses.add(DocumentMessage::StartTransaction);
responses.add(DocumentMessage::DeselectAllLayers);
@@ -211,9 +208,7 @@ impl Fsm for SplineToolFsmState {
let parent = document.new_layer_parent(true);
let transform = document.metadata().transform_to_viewport(parent);
//tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
//tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
let snapped_position = input.mouse.position; //tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
let snapped_position = input.mouse.position;
let pos = transform.inverse().transform_point2(snapped_position);
@@ -241,7 +236,7 @@ impl Fsm for SplineToolFsmState {
let Some(layer) = tool_data.layer else {
return SplineToolFsmState::Ready;
};
let snapped_position = input.mouse.position; //tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
let snapped_position = input.mouse.position;
let transform = document.metadata().transform_to_viewport(layer);
let pos = transform.inverse().transform_point2(snapped_position);
@@ -2,7 +2,6 @@
use super::tool_prelude::*;
use crate::application::generate_uuid;
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
@@ -34,8 +33,8 @@ impl Default for TextOptions {
fn default() -> Self {
Self {
font_size: 24,
font_name: DEFAULT_FONT_FAMILY.into(),
font_style: DEFAULT_FONT_STYLE.into(),
font_name: graphene_core::consts::DEFAULT_FONT_FAMILY.into(),
font_style: graphene_core::consts::DEFAULT_FONT_STYLE.into(),
fill: ToolColorOptions::new_primary(),
}
}
@@ -214,8 +213,9 @@ struct TextToolData {
impl TextToolData {
/// Set the editing state of the currently modifying layer
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
// TODO: Should always set visibility for document network, but `node_id` is not a layer so it crashes
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network) {
responses.add(NodeGraphMessage::SetVisibility { node_id, visible: !editable });
responses.add(GraphOperationMessage::SetVisibility { node_id, visible: !editable });
}
if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) {
@@ -248,6 +248,10 @@ impl TextToolData {
}
fn start_editing_layer(&mut self, layer: LayerNodeIdentifier, tool_state: TextToolFsmState, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
if layer == LayerNodeIdentifier::ROOT_PARENT {
log::error!("Cannot edit ROOT_PARENT in TextTooLData")
}
if tool_state == TextToolFsmState::Editing {
self.set_editing(false, font_cache, document, responses);
}
@@ -427,7 +431,7 @@ impl Fsm for TextToolFsmState {
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => {
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
responses.add(NodeGraphMessage::SetQualifiedInputValue {
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap()],
node_id: graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap(),
input_index: 1,
value: TaggedValue::String(new_text),
});