Read the layer path in its owned form and retarget the introspection tests

This commit is contained in:
Dennis Kobert
2026-08-24 10:26:24 +00:00
parent abb099a1c3
commit ed6922d7eb
10 changed files with 66 additions and 56 deletions

View File

@@ -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>))
}
}

View File

@@ -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)]

View File

@@ -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));
}
}

View File

@@ -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,