mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 18:08:12 +08:00
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:
co-authored by
Keavon Chambers
parent
e4d3faa52a
commit
6d74abb4de
@@ -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(), ©_ids).collect();
|
||||
let nodes: HashMap<NodeId, DocumentNode> =
|
||||
NodeGraphMessageHandler::copy_nodes(document.network(), &document.node_graph_handler.network, &document.node_graph_handler.resolved_types, ©_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),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user