@@ -2502,4 +2502,98 @@ mod test_gradient {
25022502 assert_eq ! ( SRGBA8 :: from( updated. stops. color[ 1 ] ) , SRGBA8 :: from( Color :: GREEN ) , "Middle stop color should be preserved" ) ;
25032503 assert_eq ! ( SRGBA8 :: from( updated. stops. color[ 2 ] ) , SRGBA8 :: from( Color :: BLUE ) , "Last stop color should be preserved" ) ;
25042504 }
2505+
2506+ // When the gradient chain feeds a 'Fill' node's secondary input it's an unencapsulated side-branch (no layer
2507+ // background to lay it out), so a node inserted there must be placed onto the displaced feeder's spot in absolute
2508+ // graph space rather than stranded at the origin.
2509+ #[ tokio:: test]
2510+ async fn gradient_chain_node_on_fill_secondary_input_takes_feeder_slot ( ) {
2511+ use graphene_std:: vector:: style:: GradientSpreadMethod ;
2512+
2513+ let mut editor = EditorTestUtils :: create ( ) ;
2514+ editor. new_document ( ) . await ;
2515+ editor. drag_tool ( ToolType :: Ellipse , 0. , 0. , 100. , 100. , ModifierKeys :: empty ( ) ) . await ;
2516+ let layer = editor. active_document ( ) . metadata ( ) . all_layers ( ) . next ( ) . unwrap ( ) ;
2517+
2518+ // Find the 'Fill' node in the layer's primary chain.
2519+ let fill_reference = DefinitionIdentifier :: ProtoNode ( graphene_std:: vector:: fill:: IDENTIFIER ) ;
2520+ let fill_node_id = {
2521+ let network_interface = & editor. active_document ( ) . network_interface ;
2522+ network_interface
2523+ . document_network ( )
2524+ . nodes
2525+ . keys ( )
2526+ . copied ( )
2527+ . find ( |node_id| network_interface. reference ( node_id, & [ ] ) . as_ref ( ) == Some ( & fill_reference) )
2528+ . expect ( "Fill node should exist" )
2529+ } ;
2530+
2531+ // Feed a 'Gradient Value' node into the Fill node's secondary (fill) input.
2532+ let gradient_value_id = editor. create_node_by_name ( DefinitionIdentifier :: ProtoNode ( graphene_std:: math_nodes:: gradient_value:: IDENTIFIER ) ) . await ;
2533+ editor
2534+ . handle_message ( NodeGraphMessage :: CreateWire {
2535+ output_connector : OutputConnector :: node ( gradient_value_id, 0 ) ,
2536+ input_connector : InputConnector :: node ( fill_node_id, 1 ) ,
2537+ } )
2538+ . await ;
2539+ editor
2540+ . handle_message ( NodeGraphMessage :: SetInputValue {
2541+ node_id : gradient_value_id,
2542+ input_index : 1 ,
2543+ value : TaggedValue :: Gradient ( GradientStops :: new ( [
2544+ GradientStop {
2545+ position : 0. ,
2546+ midpoint : 0.5 ,
2547+ color : Color :: RED ,
2548+ } ,
2549+ GradientStop {
2550+ position : 1. ,
2551+ midpoint : 0.5 ,
2552+ color : Color :: BLUE ,
2553+ } ,
2554+ ] ) ) ,
2555+ } )
2556+ . await ;
2557+
2558+ // Move the feeder off the origin so its slot is unambiguous, then record where it sits.
2559+ editor
2560+ . handle_message ( NodeGraphMessage :: ShiftNodePosition {
2561+ node_id : gradient_value_id,
2562+ x : 4 ,
2563+ y : 6 ,
2564+ } )
2565+ . await ;
2566+ let feeder_position = editor. active_document_mut ( ) . network_interface . position ( & gradient_value_id, & [ ] ) . expect ( "Gradient Value position" ) ;
2567+
2568+ // Set the spread method through the tool, which splices a 'Spread Method' node onto the Fill's fill input wire.
2569+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ layer. to_node( ) ] } ) . await ;
2570+ editor. select_tool ( ToolType :: Gradient ) . await ;
2571+ editor
2572+ . handle_message ( GradientToolMessage :: UpdateOptions {
2573+ options : GradientOptionsUpdate :: SetSpreadMethod ( GradientSpreadMethod :: Reflect ) ,
2574+ } )
2575+ . await ;
2576+
2577+ let spread_reference = DefinitionIdentifier :: ProtoNode ( graphene_std:: math_nodes:: spread_method:: IDENTIFIER ) ;
2578+ let spread_node_id = {
2579+ let network_interface = & editor. active_document ( ) . network_interface ;
2580+ network_interface
2581+ . document_network ( )
2582+ . nodes
2583+ . keys ( )
2584+ . copied ( )
2585+ . find ( |node_id| network_interface. reference ( node_id, & [ ] ) . as_ref ( ) == Some ( & spread_reference) )
2586+ . expect ( "Spread Method node should have been inserted" )
2587+ } ;
2588+
2589+ let spread_position = editor. active_document_mut ( ) . network_interface . position ( & spread_node_id, & [ ] ) . expect ( "Spread Method position" ) ;
2590+ let feeder_position_after = editor. active_document_mut ( ) . network_interface . position ( & gradient_value_id, & [ ] ) . expect ( "Gradient Value position after" ) ;
2591+
2592+ assert_eq ! ( spread_position, feeder_position, "the inserted node should occupy the feeder's former slot, not the graph origin" ) ;
2593+ assert_eq ! (
2594+ feeder_position_after,
2595+ feeder_position - glam:: IVec2 :: new( crate :: consts:: NODE_CHAIN_WIDTH , 0 ) ,
2596+ "the feeder's branch should shift one chain-width left to make room"
2597+ ) ;
2598+ }
25052599}
0 commit comments