mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 02:08:12 +08:00
Migrate remaining node graph data types from Vec to Table (#4067)
* Move Vec<String> to Table<String> * Remove old VecDVec2 * Move Vec<u8> to Table<u8> * Move Vec<f64> to Table<f64> * Move [f64; 4] to Table<f64> * Move Vec<NodeId> to Table<NodeId> * Tidy up the TaggedValue variants * Move Vec<BrushStroke> to Table<BrushStroke> * Add missing type implementations * Fix tests ---------
This commit is contained in:
@@ -169,12 +169,15 @@ fn generate_layout(introspected_data: &Arc<dyn std::any::Any + Send + Sync + 'st
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
Table<String>,
|
||||
Table<NodeId>,
|
||||
Table<f64>,
|
||||
Table<u8>,
|
||||
GradientStops,
|
||||
f64,
|
||||
u32,
|
||||
u64,
|
||||
bool,
|
||||
Vec<String>,
|
||||
String,
|
||||
Option<f64>,
|
||||
DVec2,
|
||||
@@ -214,46 +217,6 @@ trait TableRowLayout {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TableRowLayout> TableRowLayout for Vec<T> {
|
||||
fn type_name() -> &'static str {
|
||||
"Vec"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Vec<{}> ({} element{})", T::type_name(), self.len(), if self.len() == 1 { "" } else { "s" })
|
||||
}
|
||||
fn element_page(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
if let Some(step) = data.desired_path.get(data.current_depth).cloned() {
|
||||
match step {
|
||||
PathStep::Element(index) => {
|
||||
if let Some(row) = self.get(index) {
|
||||
data.current_depth += 1;
|
||||
let result = row.layout_with_breadcrumb(data);
|
||||
data.current_depth -= 1;
|
||||
return result;
|
||||
} else {
|
||||
warn!("Desired path truncated");
|
||||
data.desired_path.truncate(data.current_depth);
|
||||
}
|
||||
}
|
||||
PathStep::Attribute { .. } => {
|
||||
warn!("Attribute path step inside a Vec is unsupported");
|
||||
data.desired_path.truncate(data.current_depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut rows = self
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, row)| vec![TextLabel::new(format!("{index}")).narrow(true).widget_instance(), row.cell_widget(PathStep::Element(index))])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
rows.insert(0, column_headings(&["", "element"]));
|
||||
|
||||
vec![LayoutGroup::table(rows, false)]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
||||
fn type_name() -> &'static str {
|
||||
"Table"
|
||||
@@ -616,6 +579,21 @@ impl TableRowLayout for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for u8 {
|
||||
fn type_name() -> &'static str {
|
||||
"Byte"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("{self:02X}")
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep) -> WidgetInstance {
|
||||
TextLabel::new(self.identifier()).narrow(true).widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0))])]
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for u32 {
|
||||
fn type_name() -> &'static str {
|
||||
"Number (u32)"
|
||||
@@ -774,6 +752,26 @@ impl TableRowLayout for AlphaBlending {
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for NodeId {
|
||||
fn type_name() -> &'static str {
|
||||
"NodeId"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Node {self}")
|
||||
}
|
||||
fn cell_widget(&self, _target: PathStep) -> WidgetInstance {
|
||||
let node_id = *self;
|
||||
TextButton::new("Go to Node")
|
||||
.tooltip_description("Click to select the node with this ID in the graph.")
|
||||
.on_update(move |_| NodeGraphMessage::SelectedNodesSet { nodes: vec![node_id] }.into())
|
||||
.narrow(true)
|
||||
.widget_instance()
|
||||
}
|
||||
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
vec![LayoutGroup::row(vec![self.cell_widget(PathStep::Element(0))])]
|
||||
}
|
||||
}
|
||||
|
||||
impl TableRowLayout for Option<NodeId> {
|
||||
fn type_name() -> &'static str {
|
||||
"NodeId"
|
||||
@@ -812,8 +810,13 @@ macro_rules! known_table_row_types {
|
||||
Table<Raster<GPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
Table<String>,
|
||||
Table<NodeId>,
|
||||
Table<f64>,
|
||||
Table<u8>,
|
||||
GradientStops,
|
||||
Color,
|
||||
NodeId,
|
||||
Option<NodeId>,
|
||||
AlphaBlending,
|
||||
DAffine2,
|
||||
@@ -822,11 +825,11 @@ macro_rules! known_table_row_types {
|
||||
Vec2,
|
||||
Option<f64>,
|
||||
f64,
|
||||
u8,
|
||||
u32,
|
||||
u64,
|
||||
bool,
|
||||
String,
|
||||
Vec<String>,
|
||||
Vector,
|
||||
Raster<CPU>,
|
||||
Raster<GPU>,
|
||||
|
||||
@@ -491,8 +491,9 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.join_miter_limit), false), false);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<Vec<f64>>::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::VecF64(stroke.dash_lengths), false), true);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashLengthsInput::<graphene_std::table::Table<f64>>::INDEX);
|
||||
let dash_lengths_table = stroke.dash_lengths.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64Table(dash_lengths_table), false), true);
|
||||
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput::INDEX);
|
||||
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.dash_offset), false), true);
|
||||
}
|
||||
@@ -579,7 +580,8 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let Some(brush_node_id) = self.existing_network_node_id("Brush", true) else {
|
||||
return;
|
||||
};
|
||||
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokes(strokes), false), false);
|
||||
let strokes_table = strokes.into_iter().map(graphene_std::table::TableRow::new_from_element).collect();
|
||||
self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokeTable(strokes_table), false), false);
|
||||
}
|
||||
|
||||
pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) {
|
||||
|
||||
@@ -1391,7 +1391,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Raster(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
|
||||
NodeInput::value(TaggedValue::BrushStrokeTable(Default::default()), false),
|
||||
NodeInput::value(TaggedValue::BrushCache(BrushCache::default()), false),
|
||||
],
|
||||
..Default::default()
|
||||
|
||||
@@ -210,14 +210,10 @@ pub(crate) fn property_from_type(
|
||||
Some(x) if x == TypeId::of::<String>() => text_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<DVec2>() => vec2_widget(default_info, "X", "Y", "", None, false),
|
||||
Some(x) if x == TypeId::of::<DAffine2>() => transform_widget(default_info, &mut extra_widgets),
|
||||
// ==========================
|
||||
// PRIMITIVE COLLECTION TYPES
|
||||
// ==========================
|
||||
Some(x) if x == TypeId::of::<Vec<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<Vec<DVec2>>() => array_of_vec2_widget(default_info, TextInput::default()).into(),
|
||||
// ===========
|
||||
// TABLE TYPES
|
||||
// ===========
|
||||
Some(x) if x == TypeId::of::<Table<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<Table<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
|
||||
Some(x) if x == TypeId::of::<Table<GradientStops>>() => color_widget(default_info, ColorInput::default().allow_none(false)),
|
||||
// ============
|
||||
@@ -776,7 +772,7 @@ pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.ok()
|
||||
.map(TaggedValue::VecF64)
|
||||
.map(|values| TaggedValue::F64Table(values.into_iter().map(graphene_std::table::TableRow::new_from_element).collect()))
|
||||
};
|
||||
|
||||
let Some(document_node) = document_node else { return Vec::new() };
|
||||
@@ -784,43 +780,11 @@ pub fn array_of_number_widget(parameter_widgets_info: ParameterWidgetsInfo, text
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return vec![];
|
||||
};
|
||||
if let Some(TaggedValue::VecF64(x)) = &input.as_non_exposed_value() {
|
||||
if let Some(TaggedValue::F64Table(table)) = &input.as_non_exposed_value() {
|
||||
widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
text_input
|
||||
.value(x.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index))
|
||||
.widget_instance(),
|
||||
])
|
||||
}
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn array_of_vec2_widget(parameter_widgets_info: ParameterWidgetsInfo, text_props: TextInput) -> Vec<WidgetInstance> {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
let from_string = |string: &str| {
|
||||
string
|
||||
.split(|c: char| !c.is_alphanumeric() && !matches!(c, '.' | '+' | '-'))
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.parse::<f64>().ok())
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.map(|numbers| numbers.chunks_exact(2).map(|values| DVec2::new(values[0], values[1])).collect())
|
||||
.map(TaggedValue::VecDVec2)
|
||||
};
|
||||
|
||||
let Some(document_node) = document_node else { return Vec::new() };
|
||||
let Some(input) = document_node.inputs.get(index) else {
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return vec![];
|
||||
};
|
||||
if let Some(TaggedValue::VecDVec2(x)) = &input.as_non_exposed_value() {
|
||||
widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
text_props
|
||||
.value(x.iter().map(|v| format!("({}, {})", v.x, v.y)).collect::<Vec<_>>().join(", "))
|
||||
.value(table.iter_element_values().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index))
|
||||
.widget_instance(),
|
||||
])
|
||||
@@ -1839,13 +1803,13 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
};
|
||||
let uniform_val = match input.as_non_exposed_value() {
|
||||
Some(TaggedValue::F64(x)) => *x,
|
||||
Some(TaggedValue::F64Array4(x)) => x[0],
|
||||
Some(TaggedValue::F64Table(table)) => table.iter_element_values().copied().next().unwrap_or(0.),
|
||||
_ => 0.,
|
||||
};
|
||||
let individual_val = match input.as_non_exposed_value() {
|
||||
Some(&TaggedValue::F64Array4(x)) => x,
|
||||
Some(&TaggedValue::F64(x)) => [x; 4],
|
||||
_ => [0.; 4],
|
||||
Some(&TaggedValue::F64(x)) => vec![x; 4],
|
||||
Some(TaggedValue::F64Table(table)) => table.iter_element_values().copied().collect(),
|
||||
_ => vec![0.; 4],
|
||||
};
|
||||
|
||||
// Uniform/individual radio input widget
|
||||
@@ -1868,6 +1832,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
]),
|
||||
})
|
||||
.on_commit(commit_value);
|
||||
let individual_val_for_switch = individual_val.clone();
|
||||
let individual = RadioEntryData::new("Individual")
|
||||
.label("Individual")
|
||||
.on_update(move |_| Message::Batched {
|
||||
@@ -1881,7 +1846,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
NodeGraphMessage::SetInputValue {
|
||||
node_id,
|
||||
input_index: CornerRadiusInput::<f64>::INDEX,
|
||||
value: TaggedValue::F64Array4(individual_val),
|
||||
value: TaggedValue::F64Table(individual_val_for_switch.iter().copied().map(graphene_std::table::TableRow::new_from_element).collect()),
|
||||
}
|
||||
.into(),
|
||||
]),
|
||||
@@ -1899,11 +1864,7 @@ pub(crate) fn rectangle_properties(node_id: NodeId, context: &mut NodeProperties
|
||||
.map(str::parse::<f64>)
|
||||
.collect::<Result<Vec<f64>, _>>()
|
||||
.ok()
|
||||
.map(|v| {
|
||||
let arr: Box<[f64; 4]> = v.into_boxed_slice().try_into().unwrap_or_default();
|
||||
*arr
|
||||
})
|
||||
.map(TaggedValue::F64Array4)
|
||||
.map(|values| TaggedValue::F64Table(values.into_iter().take(4).map(graphene_std::table::TableRow::new_from_element).collect()))
|
||||
};
|
||||
TextInput::default()
|
||||
.value(individual_val.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
|
||||
@@ -2296,11 +2257,10 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
|
||||
_ => &StrokeJoin::Miter,
|
||||
};
|
||||
|
||||
let dash_lengths_val = match &document_node.inputs[DashLengthsInput::<Vec<f64>>::INDEX].as_value() {
|
||||
Some(TaggedValue::VecF64(x)) => x,
|
||||
_ => &vec![],
|
||||
let has_dash_lengths = match &document_node.inputs[DashLengthsInput::<Table<f64>>::INDEX].as_value() {
|
||||
Some(TaggedValue::F64Table(table)) => table.is_empty(),
|
||||
_ => true,
|
||||
};
|
||||
let has_dash_lengths = dash_lengths_val.is_empty();
|
||||
let miter_limit_disabled = join_value != &StrokeJoin::Miter;
|
||||
|
||||
let color = color_widget(
|
||||
@@ -2325,7 +2285,7 @@ pub fn stroke_properties(node_id: NodeId, context: &mut NodePropertiesContext) -
|
||||
.property_row();
|
||||
let disabled_number_input = NumberInput::default().unit(" px").disabled(has_dash_lengths);
|
||||
let dash_lengths = array_of_number_widget(
|
||||
ParameterWidgetsInfo::new(node_id, DashLengthsInput::<Vec<f64>>::INDEX, true, context),
|
||||
ParameterWidgetsInfo::new(node_id, DashLengthsInput::<Table<f64>>::INDEX, true, context),
|
||||
TextInput::default().centered(true),
|
||||
);
|
||||
let number_input = disabled_number_input;
|
||||
|
||||
@@ -21,22 +21,14 @@ pub enum FrontendGraphDataType {
|
||||
impl FrontendGraphDataType {
|
||||
pub fn from_type(input: &Type) -> Self {
|
||||
match TaggedValue::from_type_or_none(input) {
|
||||
TaggedValue::U32(_)
|
||||
| TaggedValue::U64(_)
|
||||
| TaggedValue::F32(_)
|
||||
| TaggedValue::F64(_)
|
||||
| TaggedValue::DVec2(_)
|
||||
| TaggedValue::F64Array4(_)
|
||||
| TaggedValue::VecF64(_)
|
||||
| TaggedValue::VecDVec2(_)
|
||||
| TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Table(_) | TaggedValue::DAffine2(_) => Self::Number,
|
||||
TaggedValue::Artboard(_) => Self::Artboard,
|
||||
TaggedValue::Graphic(_) => Self::Graphic,
|
||||
TaggedValue::Raster(_) => Self::Raster,
|
||||
TaggedValue::Vector(_) => Self::Vector,
|
||||
TaggedValue::Color(_) => Self::Color,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientTable(_) => Self::Gradient,
|
||||
TaggedValue::String(_) | TaggedValue::VecString(_) => Self::Typography,
|
||||
TaggedValue::String(_) | TaggedValue::StringTable(_) => Self::Typography,
|
||||
_ => Self::General,
|
||||
}
|
||||
}
|
||||
|
||||
+3
-9
@@ -53,15 +53,9 @@ impl TypeSource {
|
||||
};
|
||||
match self.compiled_nested_type() {
|
||||
Some(nested_type) => match TaggedValue::from_type_or_none(nested_type) {
|
||||
TaggedValue::U32(_)
|
||||
| TaggedValue::U64(_)
|
||||
| TaggedValue::F32(_)
|
||||
| TaggedValue::F64(_)
|
||||
| TaggedValue::DVec2(_)
|
||||
| TaggedValue::F64Array4(_)
|
||||
| TaggedValue::VecF64(_)
|
||||
| TaggedValue::VecDVec2(_)
|
||||
| TaggedValue::DAffine2(_) => FrontendGraphDataType::Number,
|
||||
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Table(_) | TaggedValue::DAffine2(_) => {
|
||||
FrontendGraphDataType::Number
|
||||
}
|
||||
TaggedValue::Artboard(_) => FrontendGraphDataType::Artboard,
|
||||
TaggedValue::Graphic(_) => FrontendGraphDataType::Graphic,
|
||||
TaggedValue::Raster(_) => FrontendGraphDataType::Raster,
|
||||
|
||||
@@ -9,11 +9,9 @@ use glam::{DVec2, IVec2};
|
||||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
|
||||
use graphene_std::ProtoNodeIdentifier;
|
||||
use graphene_std::subpath::Subpath;
|
||||
use graphene_std::text::{TextAlign, TypesettingConfig};
|
||||
use graphene_std::transform::ScaleType;
|
||||
use graphene_std::uuid::NodeId;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::{PaintOrder, StrokeAlign};
|
||||
use std::collections::HashMap;
|
||||
use std::f64::consts::PI;
|
||||
@@ -1112,80 +1110,6 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path);
|
||||
}
|
||||
|
||||
// Upgrade the old "Spline" node to the new "Spline" node
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER)
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::SplineNode"))
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SplineNode"))
|
||||
|| reference == DefinitionIdentifier::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SplinesFromPointsNode"))
|
||||
{
|
||||
// Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node
|
||||
let identifier = document
|
||||
.network_interface
|
||||
.implementation(node_id, network_path)
|
||||
.and_then(|implementation| implementation.get_proto_node());
|
||||
if identifier.map(|identifier| identifier.as_str()) != Some("graphene_core::vector::generator_nodes::SplineNode") {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Obtain the document node for the given node ID, extract the vector points, and create a Vector path from the list of points
|
||||
let node = document.network_interface.document_node(node_id, network_path)?;
|
||||
let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else {
|
||||
log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2");
|
||||
return None;
|
||||
};
|
||||
let vector = Vector::from_subpath(Subpath::from_anchors(points.to_vec(), false));
|
||||
|
||||
// Retrieve the output connectors linked to the "Spline" node's output connector
|
||||
let Some(spline_outputs) = document.network_interface.outward_wires(network_path)?.get(&OutputConnector::node(*node_id, 0)).cloned() else {
|
||||
log::error!("Vec of InputConnector Spline node is connected to its output connector 0.");
|
||||
return None;
|
||||
};
|
||||
|
||||
// Get the node's current position in the graph
|
||||
let Some(node_position) = document.network_interface.position(node_id, network_path) else {
|
||||
log::error!("Could not get position of spline node.");
|
||||
return None;
|
||||
};
|
||||
|
||||
// Get the "Path" node definition and fill it in with the Vector path and default vector modification
|
||||
let Some(path_node_type) = resolve_network_node_type("Path") else {
|
||||
log::error!("Path node does not exist.");
|
||||
return None;
|
||||
};
|
||||
let modification = Box::new(graphene_std::vector::VectorModification::create_from_vector(&vector));
|
||||
let path_node = path_node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::VectorModification(modification), false))]);
|
||||
|
||||
// Get the "Spline" node definition and wire it up with the "Path" node as input
|
||||
let Some(spline_node_type) = resolve_proto_node_type(graphene_std::vector::spline::IDENTIFIER) else {
|
||||
log::error!("Spline node does not exist.");
|
||||
return None;
|
||||
};
|
||||
let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]);
|
||||
|
||||
// Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them
|
||||
let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)];
|
||||
let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::<HashMap<_, _>>();
|
||||
let new_spline_id = *new_ids.get(&NodeId(0))?;
|
||||
let new_path_id = *new_ids.get(&NodeId(1))?;
|
||||
|
||||
// Remove the old "Spline" node from the document
|
||||
document.network_interface.delete_nodes(vec![*node_id], false, network_path);
|
||||
|
||||
// Insert the new "Path" and "Spline" nodes into the network interface with generated IDs
|
||||
document.network_interface.insert_node_group(nodes.clone(), new_ids, network_path);
|
||||
|
||||
// Reposition the new "Spline" node to match the original "Spline" node's position
|
||||
document.network_interface.shift_node(&new_spline_id, node_position, network_path);
|
||||
|
||||
// Reposition the new "Path" node with an offset relative to the original "Spline" node's position
|
||||
document.network_interface.shift_node(&new_path_id, node_position + IVec2::new(-7, 0), network_path);
|
||||
|
||||
// Redirect each output connection from the old node to the new "Spline" node's output connector
|
||||
for input_connector in spline_outputs {
|
||||
document.network_interface.set_input(&input_connector, NodeInput::node(new_spline_id, 0), network_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
|
||||
if reference == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER) && inputs_count == 8 {
|
||||
let mut template: NodeTemplate = resolve_document_node_type(&reference)?.default_node_template();
|
||||
|
||||
@@ -321,8 +321,8 @@ impl BrushToolData {
|
||||
|
||||
if reference == DefinitionIdentifier::Network("Brush".into()) && node_id != layer.to_node() {
|
||||
let points_input = node.inputs.get(1)?;
|
||||
let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue };
|
||||
self.strokes.clone_from(strokes);
|
||||
let Some(TaggedValue::BrushStrokeTable(strokes)) = points_input.as_value() else { continue };
|
||||
self.strokes = strokes.iter_element_values().cloned().collect();
|
||||
|
||||
return Some(layer);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user