From c0eb2ee4ff3209a14bbbe1c6c446a66b2e9bd35f Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 23 Aug 2026 19:05:26 +0000 Subject: [PATCH] Remove the runtime-named attribute family and its type-erased bridges --- .../messages/portfolio/document_migration.rs | 6 +- .../interpreted-executor/src/node_registry.rs | 84 +---- node-graph/nodes/graphic/src/graphic.rs | 318 ++---------------- node-graph/nodes/graphic/src/record.rs | 74 +++- node-graph/nodes/vector/src/vector_nodes.rs | 11 +- 5 files changed, 107 insertions(+), 386 deletions(-) diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index aed1c3c1dd..226027e4fd 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -2602,8 +2602,10 @@ mod tests { use super::*; #[test] - fn the_flip_reset_markers_track_the_live_merge_internals() { - assert_eq!(FLIP_RESET_NODE_MARKERS, &[graphene_std::graphic::write_attribute::IDENTIFIER.as_str()]); + fn the_flip_reset_markers_keep_the_historical_merge_internals_spelling() { + // The node itself is removed; the marker matches its spelling in + // documents saved before the flip, which must stay stable. + assert_eq!(FLIP_RESET_NODE_MARKERS, &["graphic_nodes::graphic::WriteAttributeNode"]); } #[test] diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 3297b6baa2..5b15c01225 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -1,19 +1,18 @@ use glam::{DAffine2, DVec2, IVec2}; -use graphene_std::gradient::GradientStops; -use graphene_std::list::{AttributeDyn, AttributeValueDyn, List, ListDyn}; + +use graphene_std::list::List; #[cfg(feature = "gpu")] use graphene_std::raster::GPU; -use graphene_std::raster::color::Color; -use graphene_std::raster::*; + +#[cfg(feature = "gpu")] +use graphene_std::SourceId; use graphene_std::raster::{CPU, Raster}; use graphene_std::registry::{ConstructionError, EdgeHandle, NodeIOTypes, RegistryEntry}; #[cfg(feature = "gpu")] -use graphene_std::SourceId; -#[cfg(feature = "gpu")] use graphene_std::runtime::RuntimeHandle; -use graphene_std::uuid::NodeId; + use graphene_std::vector::Vector; -use graphene_std::{Artboard, Context, Graphic, ProtoNodeIdentifier, concrete}; +use graphene_std::{Context, Graphic, ProtoNodeIdentifier, concrete}; use node_registry_macros::{convert_node, into_node}; use std::collections::HashMap; #[cfg(feature = "gpu")] @@ -32,57 +31,6 @@ fn node_registry() -> HashMap> { convert_node!(from: List>, to: List), #[cfg(feature = "gpu")] convert_node!(from: List>, to: List), - // Type-erased attribute conversions for the `Attach Attribute` node, so it monomorphizes only over the destination `List` type. - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List>, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: AttributeDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List>, to: ListDyn), - #[cfg(feature = "gpu")] - convert_node!(from: List>, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - convert_node!(from: List, to: ListDyn), - // Type-erased attribute value conversions for the `Write Attribute` node, so it monomorphizes only over the destination `List` type. - convert_node!(from: f64, to: AttributeValueDyn), - convert_node!(from: u32, to: AttributeValueDyn), - convert_node!(from: u64, to: AttributeValueDyn), - convert_node!(from: bool, to: AttributeValueDyn), - convert_node!(from: String, to: AttributeValueDyn), - convert_node!(from: DVec2, to: AttributeValueDyn), - convert_node!(from: DAffine2, to: AttributeValueDyn), - convert_node!(from: Color, to: AttributeValueDyn), - convert_node!(from: BlendMode, to: AttributeValueDyn), - convert_node!(from: graphene_std::vector::style::GradientType, to: AttributeValueDyn), - convert_node!(from: graphene_std::vector::style::GradientSpreadMethod, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), - convert_node!(from: List>, to: AttributeValueDyn), - convert_node!(from: List>, to: AttributeValueDyn), - convert_node!(from: List, to: AttributeValueDyn), // into_node!(from: List>, to: List>), convert_node!(from: DVec2, to: DVec2), convert_node!(from: List, to: List), @@ -174,15 +122,17 @@ fn node_registry() -> HashMap> { node_types.extend( graphene_std::graphic::level_to_list_entries() .into_iter() - .zip(["List", "List", "List>", "List>", "List", "List", "List"]) + .zip([ + "List", + "List", + "List>", + "List>", + "List", + "List", + "List", + ]) .map(|(entry, target)| (ProtoNodeIdentifier::with_owned_string(format!("graphene_core::ops::ConvertNode<{target}>")), entry)), ); - // The same bridge into the attribute family's type-erased list. - node_types.extend( - graphene_std::graphic::level_to_list_dyn_entries() - .into_iter() - .map(|entry| (ProtoNodeIdentifier::new("graphene_core::ops::ConvertNode"), entry)), - ); // ============= // CONVERT NODES // ============= @@ -209,7 +159,6 @@ fn node_registry() -> HashMap> { .flatten(), ); - let mut map: HashMap> = HashMap::new(); let insert = |map: &mut HashMap>, id: ProtoNodeIdentifier, entry: RegistryEntry| { let rows = map.entry(id).or_default(); @@ -390,7 +339,6 @@ mod node_registry_macros { }; } - pub(crate) use convert_node; pub(crate) use into_node; } diff --git a/node-graph/nodes/graphic/src/graphic.rs b/node-graph/nodes/graphic/src/graphic.rs index 8bdaf5367b..07f3f224f3 100644 --- a/node-graph/nodes/graphic/src/graphic.rs +++ b/node-graph/nodes/graphic/src/graphic.rs @@ -2,15 +2,15 @@ use core_types::attribute::{Attr, EditorLayerPath, Transform as TransformAttr}; use core_types::bounds::{BoundingBox, RenderBoundingBox}; use core_types::extent::{ExtentIn, LevelIn, ListIn, ValueIn}; use core_types::gpoll::{Extent, GPoll, GraphError, Interrupt, Level}; -use core_types::list::{AttributeDyn, AttributeValueDyn, Item, List, ListDyn}; +use core_types::list::List; use core_types::registry::types::{Angle, SignedInteger}; use core_types::uuid::NodeId; -use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, AnyHash, BlendMode, CacheHash, Color, Context, Ctx, DeriveCtx, ExtractIndex, InjectIndex}; +use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, CacheHash, Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex}; use glam::{DAffine2, DVec2}; use graphic_types::graphic::{Graphic, IntoGraphicList}; use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, Artboard, Vector}; use raster_types::{CPU, GPU, Raster}; -use vector_types::gradient::{GradientSpreadMethod, GradientType}; + use vector_types::{GradientStop, GradientStops, ReferencePoint}; /// Resolves a signed index over `total` lanes: negatives count from the end, @@ -98,7 +98,8 @@ fn omit_element_extent(list: ExtentIn<'_>, index: ValueIn<'_, f64>, level: Level pub fn extract_element( _: impl Ctx + ExtractIndex + InjectIndex + Copy, /// The `List` of data to extract from. - #[implementations(String, f64, NodeId, Color, GradientStops, Vector, Raster, Graphic, Artboard)] list: IList, + #[implementations(String, f64, NodeId, Color, GradientStops, Vector, Raster, Graphic, Artboard)] + list: IList, /// The index of the item to retrieve, starting from 0 for the first item. Negative indices count backwards from the end of the list, starting from -1 for the last item. index: SignedInteger, ) -> T { @@ -274,7 +275,15 @@ fn mirror<'e>( )>, Interrupt, > { - mirror_lane(ctx.arena(), legacy_render_list_of(content), ctx.innermost_index() as usize, relative_to_bounds, offset, angle, keep_original) + mirror_lane( + ctx.arena(), + legacy_render_list_of(content), + ctx.innermost_index() as usize, + relative_to_bounds, + offset, + angle, + keep_original, + ) } /// The kept originals double the level, counted from the subject's extent @@ -324,7 +333,15 @@ fn mirror_vector<'e>( )>, Interrupt, > { - mirror_lane(ctx.arena(), legacy_render_list_of(content), ctx.innermost_index() as usize, relative_to_bounds, offset, angle, keep_original) + mirror_lane( + ctx.arena(), + legacy_render_list_of(content), + ctx.innermost_index() as usize, + relative_to_bounds, + offset, + angle, + keep_original, + ) } fn mirror_vector_extent( @@ -371,281 +388,6 @@ pub fn stamp_layer_path<'e, T>(ctx: impl Ctx + ExtractArena<'e>, element: T, pat Ok((element, Attr(parked.as_slice()))) } -/// Sets a named attribute on the input `List`, computing one value per item via the value-producing input. That input -/// is evaluated once per item, with the item's index and the item itself (as a `List` containing only that item, -/// passed as a vararg) provided via context, so the upstream pipeline can return a different value per item that may -/// be derived from the item's own data. If the attribute already exists, its values are replaced; if not, it's added. -/// The value is type-erased into an `AttributeValueDyn` by an auto-inserted convert node, so this node only -/// monomorphizes over `T` instead of the cartesian product `(T, U)`. -#[node_macro::node(category("Attributes: Write"))] -fn write_attribute( - ctx: impl Ctx + DeriveCtx, - /// The `List` to set the named attribute on (one value per item). - #[implementations( - List, - List, - List, - List>, - List, - List, - List, - List, - List, - List, - List, - List, - List, - )] - mut content: List, - /// The attribute name (key) to write or replace. - name: String, - /// The node that produces the attribute value for each item. Called once per item with the item's index in context. - #[implementations(Context -> AttributeValueDyn)] - value: impl Node, Output = AttributeValueDyn>, -) -> Result, Interrupt> { - let spilled = ctx.index_head(); - for index in 0..content.len() { - let row = content.clone_item(index).expect("index is within bounds"); - let item = List::new_from_item(row); - let scoped = ctx.push_vararg(&item); - let v = value.eval(&scoped.ctx().promoted(&spilled, index as u64))?; - content.set_attribute_value_dyn(&name, index, v); - } - Ok(content) -} - -/// Sets a named attribute on the primary list, with each value taken from the corresponding item's element in the source list (paired by index, wrapping if the source has fewer items). -/// The source is type-erased into an `AttributeDyn` by an auto-inserted convert node, so this node only monomorphizes over `T` instead of the cartesian product `(T, U)`. -#[node_macro::node(category("Attributes: Write"))] -fn attach_attribute( - _: impl Ctx, - /// The `List` to attach the new attribute to. - #[implementations( - List, - List, - List, - List>, - List, - List, - List, - List, - List, - List, - List, - List, - List, - )] - mut content: List, - /// The source values to attach. - #[expose] - source: AttributeDyn, - /// The name to assign to the new destination attribute. - name: String, -) -> List { - if source.is_empty() { - return content; - } - content.set_attribute_dyn(name, source); - content -} - -/// Reads a named `Vector` attribute from the input list, outputting each value as an element of a new `Vector[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_vector( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(value.clone())); - } - result -} - -/// Reads a named numeric attribute (`f64`, `u64`, or `u32`) from the input list, outputting each value as an element of a new `f64[]`. Integer values are converted to `f64`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_number( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let value = content - .attribute::(&name, index) - .copied() - .or_else(|| content.attribute::(&name, index).map(|v| *v as f64)) - .or_else(|| content.attribute::(&name, index).map(|v| *v as f64)); - let Some(value) = value else { continue }; - result.push(Item::new_from_element(value)); - } - result -} - -/// Reads a named `bool` attribute from the input list, outputting each value as an element of a new `bool[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_bool( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `String` attribute from the input list, outputting each value as an element of a new `String[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_string( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(value.clone())); - } - result -} - -/// Reads a named `DAffine2` transform attribute from the input list, outputting each value as an element of a new `DAffine2[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_transform( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `Color` attribute from the input list, outputting each value as an element of a new `Color[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_color( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `BlendMode` attribute from the input list, outputting each value as an element of a new `BlendMode[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_blend_mode( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `GradientType` attribute from the input list, outputting each value as an element of a new `GradientType[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_gradient_type( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `GradientSpreadMethod` attribute from the input list, outputting each value as an element of a new `GradientSpreadMethod[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_spread_method( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(*value)); - } - result -} - -/// Reads a named `GradientStops` attribute from the input list, outputting each value as an element of a new `GradientStops[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_gradient_stops( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(value.clone())); - } - result -} - -/// Reads a named `Artboard` attribute from the input list, outputting each value as an element of a new `Artboard[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_artboard( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::(&name, index) else { continue }; - result.push(Item::new_from_element(value.clone())); - } - result -} - -/// Reads a named `Raster` attribute from the input list, outputting each value as an element of a new `Raster[]`. -#[node_macro::node(category("Attributes: Read"))] -fn read_attribute_raster( - _: impl Ctx, - content: ListDyn, - /// The attribute name (key) to read. - name: String, -) -> List> { - let mut result = List::with_capacity(content.len()); - for index in 0..content.len() { - let Some(value) = content.attribute::>(&name, index) else { continue }; - result.push(Item::new_from_element(value.clone())); - } - result -} - /// Joins two levels of the same type, the base's lanes followed by the new's. #[node_macro::node(category("General"), extent(extend_extent))] pub fn extend( @@ -783,20 +525,6 @@ pub fn level_to_list( graphic_types::graphic::run_to_render_list::(&item).expect("the run holds the row's element type") } -/// The transitional level bridge into the type-erased list the attribute -/// family consumes, as [`level_to_list`]. -#[node_macro::node(category(""))] -pub fn level_to_list_dyn( - _: impl Ctx + ExtractIndex + InjectIndex + Copy, - #[implementations(Graphic, Vector, Raster, Raster, Color, GradientStops, String)] value: IList, - _converter: (), -) -> ListDyn { - // SAFETY: a materialized input's frames are arena-resident. - let item = unsafe { core_types::record::GroupItem::from_resident(value.batch()) }; - graphic_types::graphic::run_to_render_list::(&item).expect("the run holds the row's element type").into() -} - -pub use _level_to_list_dyn_mod::level_to_list_dyn_entries; pub use _level_to_list_mod::level_to_list_entries; pub use _to_graphic_mod::to_graphic_entries; diff --git a/node-graph/nodes/graphic/src/record.rs b/node-graph/nodes/graphic/src/record.rs index 26aead193a..0b70291dba 100644 --- a/node-graph/nodes/graphic/src/record.rs +++ b/node-graph/nodes/graphic/src/record.rs @@ -8,8 +8,8 @@ use core_types::extent::{ExtentIn, LevelIn, ListIn, ValueIn}; use core_types::gpoll::{Extent, GPoll, GraphError, Interrupt}; use core_types::{ATTR_TRANSFORM, Color, Ctx}; use glam::DAffine2; -use graphic_types::graphic::Graphic; use graphic_types::Vector; +use graphic_types::graphic::Graphic; use raster_types::{CPU, Raster}; use vector_types::{GradientStop, GradientStops}; @@ -335,14 +335,27 @@ mod tests { fn fixture_rows() -> Vec<(Graphic, DAffine2)> { vec![ (text("a"), translation(1.)), - (group(vec![(text("b"), translation(20.)), (group(vec![(text("c"), translation(300.))]), translation(4000.))]), translation(0.5)), + ( + group(vec![(text("b"), translation(20.)), (group(vec![(text("c"), translation(300.))]), translation(4000.))]), + translation(0.5), + ), ] } macro_rules! build { ($layout:ident, $rows:expr, $fully:expr) => { install( - FlattenNode::new(RecordSource::new(GraphicSource { layout: $layout.clone(), rows: $rows }, &$layout, &$layout), ValueNode($fully)), + FlattenNode::new( + RecordSource::new( + GraphicSource { + layout: $layout.clone(), + rows: $rows, + }, + &$layout, + &$layout, + ), + ValueNode($fully), + ), flatten_layout_meta(), &[Some(&$layout)], ) @@ -425,7 +438,14 @@ mod tests { let layout = graphic_layout(); let node = install( MapNode::<_, _, Graphic>::new( - RecordSource::new(GraphicSource { layout: layout.clone(), rows: ragged_rows() }, &layout, &layout), + RecordSource::new( + GraphicSource { + layout: layout.clone(), + rows: ragged_rows(), + }, + &layout, + &layout, + ), PerRowSource { layout: layout.clone() }, &layout, ), @@ -464,7 +484,14 @@ mod tests { let layout = graphic_layout(); let flat = install( FlatMapNode::<_, _, Graphic>::new( - RecordSource::new(GraphicSource { layout: layout.clone(), rows: ragged_rows() }, &layout, &layout), + RecordSource::new( + GraphicSource { + layout: layout.clone(), + rows: ragged_rows(), + }, + &layout, + &layout, + ), PerRowSource { layout: layout.clone() }, &layout, ), @@ -473,7 +500,14 @@ mod tests { ); let mapped = install( MapNode::<_, _, Graphic>::new( - RecordSource::new(GraphicSource { layout: layout.clone(), rows: ragged_rows() }, &layout, &layout), + RecordSource::new( + GraphicSource { + layout: layout.clone(), + rows: ragged_rows(), + }, + &layout, + &layout, + ), PerRowSource { layout: layout.clone() }, &layout, ), @@ -536,7 +570,14 @@ mod tests { let layout = graphic_layout(); let node = install( FlatMapNode::<_, _, Graphic>::new( - RecordSource::new(GraphicSource { layout: layout.clone(), rows: ragged_rows() }, &layout, &layout), + RecordSource::new( + GraphicSource { + layout: layout.clone(), + rows: ragged_rows(), + }, + &layout, + &layout, + ), PerRowSource { layout: layout.clone() }, &layout, ), @@ -608,7 +649,11 @@ mod tests { }; assert_eq!(children.len(), 1); assert_eq!(text_of(children.element(0).unwrap()), "c"); - assert_eq!(children.attribute_cloned_or_default::(ATTR_TRANSFORM, 0).translation.x, 300., "embedded transforms ride untouched"); + assert_eq!( + children.attribute_cloned_or_default::(ATTR_TRANSFORM, 0).translation.x, + 300., + "embedded transforms ride untouched" + ); let transform: DAffine2 = unsafe { rec.read(offset) }; assert_eq!(transform.translation.x, 4000.5); unsafe { stack::rewind(mark) }; @@ -661,7 +706,7 @@ mod tests { let layout = graphic_layout(); let rows = vec![(text("a"), translation(1.)), (text("b"), translation(2.))]; let node = install( - WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows, }, &layout, &layout), &layout), + WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows }, &layout, &layout), &layout), wrap_layout_meta(), &[Some(&layout)], ); @@ -753,12 +798,7 @@ mod tests { let layout = Layout::default().with_writes(1, record::element_write_hashed::(), &[]); let out = Layout::default().with_writes(0, record::element_write_hashed::(), &[]); - let build = |colors: Vec| { - install_flip( - ToGradientNode::new(RecordSource::new(ColorSource { layout: layout.clone(), colors }, &layout, &layout), &layout), - &out, - ) - }; + let build = |colors: Vec| install_flip(ToGradientNode::new(RecordSource::new(ColorSource { layout: layout.clone(), colors }, &layout, &layout), &layout), &out); let stops_of = |colors: Vec| { let node = build(colors); let GPoll::Final(value) = node.eval(&ctx) else { @@ -788,7 +828,7 @@ mod tests { let layout = graphic_layout(); let rows = vec![(text("a"), translation(1.)), (text("b"), translation(2.))]; let node = install( - WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows, }, &layout, &layout), &layout), + WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows }, &layout, &layout), &layout), wrap_layout_meta(), &[Some(&layout)], ); @@ -819,7 +859,7 @@ mod tests { let layout = graphic_layout(); let rows = vec![(text("a"), translation(1.)), (text("b"), translation(2.))]; let wrapped = install( - WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows, }, &layout, &layout), &layout), + WrapNode::new(RecordSource::new(GraphicSource { layout: layout.clone(), rows }, &layout, &layout), &layout), wrap_layout_meta(), &[Some(&layout)], ); diff --git a/node-graph/nodes/vector/src/vector_nodes.rs b/node-graph/nodes/vector/src/vector_nodes.rs index 6445b3dcab..d4548bdd56 100644 --- a/node-graph/nodes/vector/src/vector_nodes.rs +++ b/node-graph/nodes/vector/src/vector_nodes.rs @@ -10,17 +10,17 @@ use core_types::extent::{ExtentIn, LevelIn, ListIn, ValueIn}; use core_types::gpoll::GraphError; use core_types::gpoll::Interrupt; use core_types::gpoll::{Extent, GPoll}; -use core_types::list::{Item, ItemAttributeValues, List, ListDyn}; +use core_types::list::{Item, ItemAttributeValues, List}; use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue}; use core_types::transform::Transform; use core_types::uuid::NodeId; -use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex}; +use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, CacheHash, Color, Ctx, DeriveCtx, ExtractIndex, InjectIndex}; use glam::{DAffine2, DMat2, DVec2}; -use graphic_types::Vector; use graphic_types::graphic::{bake_paint_transforms, graphic_list_at, has_paint_at, is_paint_present, set_paint_attribute_at}; use graphic_types::markers::{EditorMergedLayers, Fill, Stroke as StrokeAttr}; use graphic_types::raster_types::{CPU, GPU, Raster}; use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_FILL, ATTR_STROKE, Graphic, IntoGraphicList}; +use graphic_types::{Artboard, Vector}; use kurbo::simplify::{SimplifyOptions, simplify_bezpath}; use kurbo::{Affine, BezPath, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveArclen, PathEl, PathSeg, Shape}; use rand::{Rng, SeedableRng}; @@ -3540,7 +3540,10 @@ fn point_inside(_: impl Ctx + ExtractIndex + InjectIndex + Copy, source: IList f64 { +fn count_elements( + _: impl Ctx + ExtractIndex + InjectIndex + Copy, + #[implementations(Graphic, Artboard, Vector, Raster, Color, GradientStops, String)] content: IList, +) -> f64 { content.len() as f64 }