mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 15:28:04 +08:00
Read the layer path in its owned form and retarget the introspection tests
This commit is contained in:
@@ -7,8 +7,8 @@ use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graphene_std::Color;
|
||||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::list::List;
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::{CPU, GPU, Image, Raster};
|
||||
use graphene_std::subpath::Subpath;
|
||||
@@ -16,7 +16,6 @@ use graphene_std::text::{Font, TypesettingConfig};
|
||||
use graphene_std::vector::misc::ManipulatorPointId;
|
||||
use graphene_std::vector::style::{FillChoice, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin, initial_gradient_transform_for_bounding_box};
|
||||
use graphene_std::vector::{GradientSpreadMethod, GradientStops, GradientType, PointId, SegmentId, VectorModificationType};
|
||||
use graphene_std::Color;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// Returns the ID of the first Spline node in the horizontal flow which is not followed by a `Path` node, or `None` if none exists.
|
||||
@@ -977,6 +976,8 @@ impl<'a> NodeGraphLayer<'a> {
|
||||
pub fn is_raster_layer(layer: LayerNodeIdentifier, network_interface: &mut NodeNetworkInterface) -> bool {
|
||||
let layer_input_type = network_interface.input_type(&InputConnector::node(layer.to_node(), 1), &[]);
|
||||
|
||||
layer_input_type.compiled_nested_type() == Some(&concrete!(List<Raster<CPU>>)) || layer_input_type.compiled_nested_type() == Some(&concrete!(List<Raster<GPU>>))
|
||||
// A leveled wire is typed by its element; depth rides the layout.
|
||||
let compiled = layer_input_type.compiled_nested_type();
|
||||
compiled == Some(&concrete!(Raster<CPU>)) || compiled == Some(&concrete!(Raster<GPU>))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,15 +574,22 @@ mod test_artboard {
|
||||
use graphene_std::Artboard;
|
||||
use graphene_std::list::List;
|
||||
|
||||
/// A leveled wire introspects as its whole legacy list, so each `extend`
|
||||
/// occurrence yields one list rather than one element.
|
||||
async fn get_artboards(editor: &mut EditorTestUtils) -> List<Artboard> {
|
||||
let instrumented = match editor.eval_graph().await {
|
||||
Ok(instrumented) => instrumented,
|
||||
Err(e) => panic!("Failed to evaluate graph: {e}"),
|
||||
};
|
||||
instrumented
|
||||
.grab_all_input::<graphene_std::graphic::extend::NewInput<Artboard>>(&editor.runtime)
|
||||
.map(graphene_std::list::Item::new_from_element)
|
||||
.collect()
|
||||
let mut artboards = List::new();
|
||||
for list in instrumented.grab_all_input_level::<graphene_std::graphic::extend::NewInput<Artboard>, Artboard>(&editor.runtime) {
|
||||
for index in 0..list.len() {
|
||||
if let Some(item) = list.clone_item(index) {
|
||||
artboards.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
artboards
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
||||
@@ -205,17 +205,22 @@ impl Fsm for FillToolFsmState {
|
||||
#[cfg(test)]
|
||||
mod test_fill {
|
||||
pub use crate::test_utils::test_prelude::*;
|
||||
use graphene_std::Graphic;
|
||||
use graphene_std::color::SRGBA8;
|
||||
use graphene_std::vector::fill;
|
||||
use graphene_std::Graphic;
|
||||
|
||||
async fn get_fills(editor: &mut EditorTestUtils) -> Vec<Graphic> {
|
||||
/// Paint inputs are single-typed now, so the monitored wire carries the
|
||||
/// colors themselves and the `Graphic` conversion sits downstream of it.
|
||||
async fn get_fills(editor: &mut EditorTestUtils) -> Vec<Color> {
|
||||
let instrumented = match editor.eval_graph().await {
|
||||
Ok(instrumented) => instrumented,
|
||||
Err(e) => panic!("Failed to evaluate graph: {e}"),
|
||||
};
|
||||
|
||||
instrumented.grab_all_input::<fill::FillInput>(&editor.runtime).collect()
|
||||
instrumented
|
||||
.grab_all_input_level::<fill::FillInput, Color>(&editor.runtime)
|
||||
.flat_map(|list| list.iter_element_values().cloned().collect::<Vec<_>>())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -245,9 +250,7 @@ mod test_fill {
|
||||
editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::empty()).await;
|
||||
let fills = get_fills(&mut editor).await;
|
||||
assert_eq!(fills.len(), 1);
|
||||
let Some(Graphic::Color(color_list)) = fills.first() else { panic!("the fill paint holds a color") };
|
||||
let color = color_list.element(0).expect("Color is stored in the list");
|
||||
assert_eq!(SRGBA8::from(*color), SRGBA8::from(Color::GREEN));
|
||||
assert_eq!(SRGBA8::from(fills[0]), SRGBA8::from(Color::GREEN));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -259,8 +262,6 @@ mod test_fill {
|
||||
editor.click_tool(ToolType::Fill, MouseKeys::LEFT, DVec2::new(2., 2.), ModifierKeys::SHIFT).await;
|
||||
let fills = get_fills(&mut editor).await;
|
||||
assert_eq!(fills.len(), 1);
|
||||
let Some(Graphic::Color(color_list)) = fills.first() else { panic!("the fill paint holds a color") };
|
||||
let color = color_list.element(0).expect("Color is stored in the list");
|
||||
assert_eq!(SRGBA8::from(*color), SRGBA8::from(Color::YELLOW));
|
||||
assert_eq!(SRGBA8::from(fills[0]), SRGBA8::from(Color::YELLOW));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,6 +999,20 @@ mod test {
|
||||
.filter_map(Instrumented::downcast::<Input>) // Some might not resolve (e.g. generics that don't work properly)
|
||||
}
|
||||
|
||||
/// Grab all of the values of a LEVELED input, which introspects as its
|
||||
/// whole legacy list rather than as one element. `T` is the introspected
|
||||
/// element type, which differs from the declared one where a conversion
|
||||
/// sits downstream of the monitor.
|
||||
pub fn grab_all_input_level<'a, Input: NodeInputDecleration + 'a, T: Send + Sync + Clone + 'static>(&'a self, runtime: &'a NodeRuntime) -> impl Iterator<Item = List<T>> + 'a {
|
||||
self.protonodes_by_name
|
||||
.get(&Input::identifier())
|
||||
.map_or([].as_slice(), |x| x.as_slice())
|
||||
.iter()
|
||||
.filter_map(|inputs| inputs.get(Input::INDEX))
|
||||
.filter_map(|input_monitor_node| runtime.executor.introspect(input_monitor_node).ok())
|
||||
.filter_map(|dynamic| dynamic.downcast_ref::<List<T>>().cloned())
|
||||
}
|
||||
|
||||
pub fn grab_protonode_input<Input: NodeInputDecleration>(&self, path: &Vec<NodeId>, runtime: &NodeRuntime) -> Option<Input::Result>
|
||||
where
|
||||
Input::Result: Send + Sync + Clone + 'static,
|
||||
|
||||
@@ -128,9 +128,9 @@ fn flatten_graphic_list<T>(content: List<Graphic>, extract_variant: fn(Graphic)
|
||||
let parent_has_transform = current_graphic_item.attribute::<DAffine2>(ATTR_TRANSFORM).is_some();
|
||||
let parent_has_opacity = current_graphic_item.attribute::<f64>(ATTR_OPACITY).is_some();
|
||||
let parent_has_fill = current_graphic_item.attribute::<f64>(ATTR_OPACITY_FILL).is_some();
|
||||
let parent_has_layer_path = current_graphic_item.attribute::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH).is_some();
|
||||
let parent_has_layer_path = current_graphic_item.attribute::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH).is_some();
|
||||
|
||||
let layer_path: List<NodeId> = current_graphic_item.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH);
|
||||
let layer_path: Vec<NodeId> = current_graphic_item.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH);
|
||||
let current_transform: DAffine2 = current_graphic_item.attribute_cloned_or_default(ATTR_TRANSFORM);
|
||||
let current_opacity: f64 = current_graphic_item.attribute_cloned_or(ATTR_OPACITY, 1.);
|
||||
let current_fill: f64 = current_graphic_item.attribute_cloned_or(ATTR_OPACITY_FILL, 1.);
|
||||
@@ -323,7 +323,7 @@ impl IntoGraphicList for List<Vector> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
// Propagate `editor:layer_path` from item 0 onto the wrapper Graphic item so a subsequent
|
||||
// `flatten_graphic_list` doesn't overwrite the inner Vector's stamp with an empty value
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let mut graphic_list = List::new_from_element(Graphic::Vector(self));
|
||||
if !layer_path.is_empty() {
|
||||
graphic_list.set_attribute(ATTR_EDITOR_LAYER_PATH, 0, layer_path);
|
||||
@@ -358,7 +358,7 @@ impl IntoGraphicList for List<GradientStops> {
|
||||
|
||||
impl IntoGraphicList for List<String> {
|
||||
fn into_graphic_list(self) -> List<Graphic> {
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let mut graphic_list = List::new_from_element(Graphic::Text(self));
|
||||
if !layer_path.is_empty() {
|
||||
graphic_list.set_attribute(ATTR_EDITOR_LAYER_PATH, 0, layer_path);
|
||||
|
||||
@@ -584,8 +584,8 @@ impl Render for Graphic {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than the first item
|
||||
if !list.is_empty() {
|
||||
let layer_path: List<NodeId> = list.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let layer_path: Vec<NodeId> = list.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
||||
let layer = layer_path.last().copied();
|
||||
let transform: DAffine2 = list.attribute_cloned_or_default(ATTR_TRANSFORM, 0);
|
||||
|
||||
metadata.first_element_source_id.insert(element_id, layer);
|
||||
@@ -803,8 +803,8 @@ impl Render for List<Artboard> {
|
||||
let Some(content) = self.element(index).map(Artboard::as_graphic_list) else { continue };
|
||||
let (location, dimensions, _background, clip) = read_artboard_attributes(self, index);
|
||||
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let element_id = layer_path.iter_element_values().next_back().copied();
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let element_id = layer_path.last().copied();
|
||||
|
||||
if let Some(element_id) = element_id {
|
||||
let subpath = Subpath::new_rectangle(DVec2::ZERO, dimensions);
|
||||
@@ -975,8 +975,8 @@ impl Render for List<Graphic> {
|
||||
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
|
||||
for index in 0..self.len() {
|
||||
let item_transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.last().copied();
|
||||
let element = self.element(index).unwrap();
|
||||
|
||||
let mut footprint = footprint;
|
||||
@@ -1057,9 +1057,9 @@ impl Render for List<Graphic> {
|
||||
}
|
||||
|
||||
fn new_ids_from_hash(&mut self, _reference: Option<NodeId>) {
|
||||
let (elements, layers) = self.element_and_attribute_slices_mut::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH);
|
||||
let (elements, layers) = self.element_and_attribute_slices_mut::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH);
|
||||
for (element, layer) in elements.iter_mut().zip(layers.iter()) {
|
||||
element.new_ids_from_hash(layer.iter_element_values().next_back().copied());
|
||||
element.new_ids_from_hash(layer.last().copied());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1576,8 +1576,8 @@ impl Render for List<Vector> {
|
||||
for index in 0..self.len() {
|
||||
let Some(source) = self.element(index) else { continue };
|
||||
let transform: DAffine2 = self.attribute_cloned_or_default(ATTR_TRANSFORM, index);
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.last().copied();
|
||||
|
||||
if let Some(element_id) = caller_element_id.or(layer) {
|
||||
// When recovering element_id from the item's editor:layer_path tag (because the caller
|
||||
@@ -2573,8 +2573,8 @@ impl Render for List<String> {
|
||||
let mut accumulated_click_targets: HashMap<NodeId, Vec<Arc<ClickTarget>>> = HashMap::new();
|
||||
|
||||
for index in 0..self.len() {
|
||||
let layer_path: List<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.iter_element_values().next_back().copied();
|
||||
let layer_path: Vec<NodeId> = self.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer = layer_path.last().copied();
|
||||
let Some(element_id) = caller_element_id.or(layer) else { continue };
|
||||
|
||||
// When recovering element_id from the item's tag (caller passed None), also store the transform metadata.
|
||||
|
||||
@@ -225,10 +225,7 @@ where
|
||||
}
|
||||
let fill = park_paint(legacy.attribute::<List<Graphic>>(graphic_types::ATTR_FILL, source).cloned())?;
|
||||
let stroke = park_paint(legacy.attribute::<List<Graphic>>(graphic_types::ATTR_STROKE, source).cloned())?;
|
||||
let layer_path: Vec<NodeId> = legacy
|
||||
.attribute::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH, source)
|
||||
.map(|path| path.iter_element_values().copied().collect())
|
||||
.unwrap_or_default();
|
||||
let layer_path: Vec<NodeId> = legacy.attribute::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, source).map(|path| path.clone()).unwrap_or_default();
|
||||
let layer_path = arena.alloc(layer_path).ok_or_else(exhausted)?.0;
|
||||
|
||||
Ok((
|
||||
|
||||
@@ -74,10 +74,7 @@ fn boolean_core<'e>(
|
||||
let element = result_vector_list.element(0).cloned().unwrap_or_default();
|
||||
let fill = park_paint(graphic_types::graphic::graphic_list_at(&result_vector_list, 0, graphic_types::ATTR_FILL).map(|paint| paint.into_owned()))?;
|
||||
let stroke = park_paint(graphic_types::graphic::graphic_list_at(&result_vector_list, 0, graphic_types::ATTR_STROKE).map(|paint| paint.into_owned()))?;
|
||||
let layer_path: Vec<NodeId> = result_vector_list
|
||||
.attribute::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH, 0)
|
||||
.map(|path| path.iter_element_values().copied().collect())
|
||||
.unwrap_or_default();
|
||||
let layer_path: Vec<NodeId> = result_vector_list.attribute::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, 0).map(|path| path.clone()).unwrap_or_default();
|
||||
let layer_path = arena.alloc(layer_path).ok_or_else(exhausted)?.0;
|
||||
// Snapshot the input layers so the renderer can recurse into them for
|
||||
// editor click-target preservation.
|
||||
@@ -321,7 +318,7 @@ fn flatten_vector(graphic_list: &List<Graphic>) -> List<Vector> {
|
||||
(0..image.len())
|
||||
.map(|i| {
|
||||
let row_transform: DAffine2 = image.attribute_cloned_or_default(ATTR_TRANSFORM, i);
|
||||
let layer: List<NodeId> = image.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, i);
|
||||
let layer: Vec<NodeId> = image.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, i);
|
||||
let blend_mode: BlendMode = image.attribute_cloned_or_default(ATTR_BLEND_MODE, i);
|
||||
let opacity: f64 = image.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
||||
let fill: f64 = image.attribute_cloned_or(ATTR_OPACITY_FILL, i, 1.);
|
||||
@@ -354,7 +351,7 @@ fn flatten_vector(graphic_list: &List<Graphic>) -> List<Vector> {
|
||||
(0..image.len())
|
||||
.map(|i| {
|
||||
let row_transform: DAffine2 = image.attribute_cloned_or_default(ATTR_TRANSFORM, i);
|
||||
let layer: List<NodeId> = image.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, i);
|
||||
let layer: Vec<NodeId> = image.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, i);
|
||||
let blend_mode: BlendMode = image.attribute_cloned_or_default(ATTR_BLEND_MODE, i);
|
||||
let opacity: f64 = image.attribute_cloned_or(ATTR_OPACITY, i, 1.);
|
||||
let fill: f64 = image.attribute_cloned_or(ATTR_OPACITY_FILL, i, 1.);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::TypesettingConfig;
|
||||
use super::text_context::TextContext;
|
||||
use crate::markers::{ATTR_FONT, ATTR_TEXT_ALIGN};
|
||||
use core_types::blending::BlendMode;
|
||||
use core_types::list::List;
|
||||
use core_types::uuid::NodeId;
|
||||
use crate::markers::{ATTR_FONT, ATTR_TEXT_ALIGN};
|
||||
use core_types::{
|
||||
ATTR_BLEND_MODE, ATTR_EDITOR_LAYER_PATH, ATTR_FONT_SIZE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM,
|
||||
};
|
||||
@@ -54,7 +54,7 @@ pub fn shape_text_list(strings: &List<String>, separate_glyphs: bool) -> List<Ve
|
||||
|
||||
let vectors = to_path(text, &font, typesetting, separate_glyphs);
|
||||
let transform = strings.attribute_cloned_or_default::<DAffine2>(ATTR_TRANSFORM, index);
|
||||
let layer_path = strings.attribute_cloned_or_default::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let layer_path = strings.attribute_cloned_or_default::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let blend_mode = strings.attribute::<BlendMode>(ATTR_BLEND_MODE, index).copied();
|
||||
let opacity = strings.attribute::<f64>(ATTR_OPACITY, index).copied();
|
||||
let opacity_fill = strings.attribute::<f64>(ATTR_OPACITY_FILL, index).copied();
|
||||
|
||||
@@ -1492,10 +1492,7 @@ fn emit_legacy_lane<'e>(
|
||||
let element = output.element(lane).cloned().unwrap_or_default();
|
||||
let fill = output.attribute::<List<Graphic>>(ATTR_FILL, lane).map(|paint| park_paint(arena, paint.clone())).transpose()?;
|
||||
let stroke = output.attribute::<List<Graphic>>(ATTR_STROKE, lane).map(|paint| park_paint(arena, paint.clone())).transpose()?;
|
||||
let layer_path: Vec<NodeId> = output
|
||||
.attribute::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH, lane)
|
||||
.map(|path| path.iter_element_values().copied().collect())
|
||||
.unwrap_or_default();
|
||||
let layer_path: Vec<NodeId> = output.attribute::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, lane).map(|path| path.clone()).unwrap_or_default();
|
||||
let layer_path = arena.alloc(layer_path).ok_or_else(exhausted)?.0;
|
||||
let merged_layers = output
|
||||
.attribute::<List<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, lane)
|
||||
@@ -1753,8 +1750,8 @@ fn flatten_path_core<'e>(
|
||||
// Concatenate every vector element's subpaths into the single output compound path
|
||||
for index in 0..flattened.len() {
|
||||
let Some(element) = flattened.element(index) else { continue };
|
||||
let layer_path: List<NodeId> = flattened.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let node_id = layer_path.iter_element_values().next_back().map(|node_id| node_id.0).unwrap_or_default();
|
||||
let layer_path: Vec<NodeId> = flattened.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, index);
|
||||
let node_id = layer_path.last().map(|node_id| node_id.0).unwrap_or_default();
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(index, node_id).hash(&mut hasher);
|
||||
@@ -1786,11 +1783,7 @@ fn flatten_path_core<'e>(
|
||||
stroke = carrier.attribute::<List<Graphic>>(ATTR_STROKE, 0).map(|paint| park_paint(arena, paint.clone())).transpose()?;
|
||||
|
||||
// Adopt the last input item's layer so the editor can also bucket clicks under a contributing child layer
|
||||
layer_path = flattened
|
||||
.attribute_cloned_or_default::<List<NodeId>>(ATTR_EDITOR_LAYER_PATH, primary)
|
||||
.iter_element_values()
|
||||
.copied()
|
||||
.collect();
|
||||
layer_path = flattened.attribute_cloned_or_default::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, primary);
|
||||
}
|
||||
let exhausted = || {
|
||||
Interrupt::from(GraphError {
|
||||
@@ -3150,7 +3143,7 @@ fn morph_core(content: List<Graphic>, progression: f64, reverse: bool, distribut
|
||||
// The result is a synthesis of source and target, so adopt whichever endpoint the result is closer to as
|
||||
// the click-target identity (so the editor can route clicks back to one of the contributing layers)
|
||||
let primary_index = if time < 0.5 { source_index } else { target_index };
|
||||
let layer_path: List<NodeId> = content.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, primary_index);
|
||||
let layer_path: Vec<NodeId> = content.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, primary_index);
|
||||
|
||||
let mut item = Item::new_from_element(vector)
|
||||
.with_attribute(ATTR_TRANSFORM, lerped_transform)
|
||||
|
||||
Reference in New Issue
Block a user