Add Gradient tool test for select and delete removes a stop (#2571)
* Add Gradient tool test for select and delete removes a stop * refactor fills and double click into functions * refactor
This commit is contained in:
parent
b45f7ef0c7
commit
6196dbff95
|
|
@ -539,6 +539,7 @@ mod test_gradient {
|
||||||
pub use crate::test_utils::test_prelude::*;
|
pub use crate::test_utils::test_prelude::*;
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use graphene_core::vector::fill;
|
use graphene_core::vector::fill;
|
||||||
|
use graphene_core::vector::style::Gradient;
|
||||||
use graphene_std::vector::style::Fill;
|
use graphene_std::vector::style::Fill;
|
||||||
|
|
||||||
use super::gradient_space_transform;
|
use super::gradient_space_transform;
|
||||||
|
|
@ -557,6 +558,30 @@ mod test_gradient {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_gradient(editor: &mut EditorTestUtils) -> (Gradient, DAffine2) {
|
||||||
|
let fills = get_fills(editor).await;
|
||||||
|
assert_eq!(fills.len(), 1, "Expected 1 gradient fill, found {}", fills.len());
|
||||||
|
|
||||||
|
let (fill, transform) = fills.first().unwrap();
|
||||||
|
let gradient = fill.as_gradient().expect("Expected gradient fill type");
|
||||||
|
|
||||||
|
(gradient.clone(), transform.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_stops_at_positions(actual_positions: &[f64], expected_positions: &[f64], tolerance: f64) {
|
||||||
|
assert_eq!(
|
||||||
|
actual_positions.len(),
|
||||||
|
expected_positions.len(),
|
||||||
|
"Expected {} stops, found {}",
|
||||||
|
expected_positions.len(),
|
||||||
|
actual_positions.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, (actual, expected)) in actual_positions.iter().zip(expected_positions.iter()).enumerate() {
|
||||||
|
assert!((actual - expected).abs() < tolerance, "Stop {}: Expected position near {}, got {}", i, expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_artboard() {
|
async fn ignore_artboard() {
|
||||||
let mut editor = EditorTestUtils::create();
|
let mut editor = EditorTestUtils::create();
|
||||||
|
|
@ -583,10 +608,9 @@ mod test_gradient {
|
||||||
editor.select_primary_color(Color::GREEN).await;
|
editor.select_primary_color(Color::GREEN).await;
|
||||||
editor.select_secondary_color(Color::BLUE).await;
|
editor.select_secondary_color(Color::BLUE).await;
|
||||||
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
|
||||||
let fills = get_fills(&mut editor).await;
|
|
||||||
assert_eq!(fills.len(), 1);
|
let (gradient, transform) = get_gradient(&mut editor).await;
|
||||||
let (fill, transform) = fills.first().unwrap();
|
|
||||||
let gradient = fill.as_gradient().unwrap();
|
|
||||||
// Gradient goes from secondary colour to primary colour
|
// Gradient goes from secondary colour to primary colour
|
||||||
let stops = gradient.stops.iter().map(|stop| (stop.0, stop.1.to_rgba8_srgb())).collect::<Vec<_>>();
|
let stops = gradient.stops.iter().map(|stop| (stop.0, stop.1.to_rgba8_srgb())).collect::<Vec<_>>();
|
||||||
assert_eq!(stops, vec![(0., Color::BLUE.to_rgba8_srgb()), (1., Color::GREEN.to_rgba8_srgb())]);
|
assert_eq!(stops, vec![(0., Color::BLUE.to_rgba8_srgb()), (1., Color::GREEN.to_rgba8_srgb())]);
|
||||||
|
|
@ -607,9 +631,9 @@ mod test_gradient {
|
||||||
let end = DVec2::new(24., 4.);
|
let end = DVec2::new(24., 4.);
|
||||||
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
||||||
editor.drag_tool(ToolType::Gradient, start.x, start.y, end.x, end.y, ModifierKeys::SHIFT).await;
|
editor.drag_tool(ToolType::Gradient, start.x, start.y, end.x, end.y, ModifierKeys::SHIFT).await;
|
||||||
let fills = get_fills(&mut editor).await;
|
|
||||||
let (fill, transform) = fills.first().unwrap();
|
let (gradient, transform) = get_gradient(&mut editor).await;
|
||||||
let gradient = fill.as_gradient().unwrap();
|
|
||||||
assert!(transform.transform_point2(gradient.start).abs_diff_eq(start, 1e-10));
|
assert!(transform.transform_point2(gradient.start).abs_diff_eq(start, 1e-10));
|
||||||
|
|
||||||
// 15 degrees from horizontal
|
// 15 degrees from horizontal
|
||||||
|
|
@ -649,10 +673,9 @@ mod test_gradient {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
|
||||||
let fills = get_fills(&mut editor).await;
|
|
||||||
assert_eq!(fills.len(), 1);
|
let (gradient, transform) = get_gradient(&mut editor).await;
|
||||||
let (fill, transform) = fills.first().unwrap();
|
|
||||||
let gradient = fill.as_gradient().unwrap();
|
|
||||||
assert!(transform.transform_point2(gradient.start).abs_diff_eq(DVec2::new(2., 3.), 1e-10));
|
assert!(transform.transform_point2(gradient.start).abs_diff_eq(DVec2::new(2., 3.), 1e-10));
|
||||||
assert!(transform.transform_point2(gradient.end).abs_diff_eq(DVec2::new(24., 4.), 1e-10));
|
assert!(transform.transform_point2(gradient.end).abs_diff_eq(DVec2::new(24., 4.), 1e-10));
|
||||||
}
|
}
|
||||||
|
|
@ -663,44 +686,20 @@ mod test_gradient {
|
||||||
editor.new_document().await;
|
editor.new_document().await;
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
editor.select_primary_color(Color::GREEN).await;
|
editor.select_primary_color(Color::GREEN).await;
|
||||||
editor.select_secondary_color(Color::BLUE).await;
|
editor.select_secondary_color(Color::BLUE).await;
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
// Get initial gradient state (should have 2 stops)
|
// Get initial gradient state (should have 2 stops)
|
||||||
let initial_fills = get_fills(&mut editor).await;
|
let (initial_gradient, _) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(initial_fills.len(), 1);
|
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
|
||||||
let (initial_fill, _) = initial_fills.first().unwrap();
|
|
||||||
let initial_gradient = initial_fill.as_gradient().unwrap();
|
|
||||||
assert_eq!(initial_gradient.stops.len(), 2);
|
|
||||||
|
|
||||||
editor.select_tool(ToolType::Gradient).await;
|
editor.select_tool(ToolType::Gradient).await;
|
||||||
|
editor.double_click(DVec2::new(50., 0.)).await;
|
||||||
// Simulate a double click
|
|
||||||
let click_position = DVec2::new(50., 0.);
|
|
||||||
let modifier_keys = ModifierKeys::empty();
|
|
||||||
|
|
||||||
// Send the DoubleClick event
|
|
||||||
editor
|
|
||||||
.handle_message(InputPreprocessorMessage::DoubleClick {
|
|
||||||
editor_mouse_state: EditorMouseState {
|
|
||||||
editor_position: click_position,
|
|
||||||
mouse_keys: MouseKeys::LEFT,
|
|
||||||
scroll_delta: ScrollDelta::default(),
|
|
||||||
},
|
|
||||||
modifier_keys,
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// Check that a new stop has been added
|
// Check that a new stop has been added
|
||||||
let updated_fills = get_fills(&mut editor).await;
|
let (updated_gradient, _) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(updated_fills.len(), 1);
|
assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops, found {}", updated_gradient.stops.len());
|
||||||
let (updated_fill, _) = updated_fills.first().unwrap();
|
|
||||||
let updated_gradient = updated_fill.as_gradient().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(updated_gradient.stops.len(), 3);
|
|
||||||
|
|
||||||
let positions: Vec<f64> = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect();
|
let positions: Vec<f64> = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect();
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -735,11 +734,9 @@ mod test_gradient {
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
// Get the initial gradient state (should have 2 stops)
|
// Get the initial gradient state
|
||||||
let initial_fills = get_fills(&mut editor).await;
|
let (initial_gradient, transform) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(initial_fills.len(), 1);
|
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
|
||||||
let (initial_fill, transform) = initial_fills.first().unwrap();
|
|
||||||
let initial_gradient = initial_fill.as_gradient().unwrap();
|
|
||||||
|
|
||||||
// Verify initial gradient endpoints in viewport space
|
// Verify initial gradient endpoints in viewport space
|
||||||
let initial_start = transform.transform_point2(initial_gradient.start);
|
let initial_start = transform.transform_point2(initial_gradient.start);
|
||||||
|
|
@ -755,9 +752,7 @@ mod test_gradient {
|
||||||
|
|
||||||
editor.move_mouse(start_pos.x, start_pos.y, ModifierKeys::empty(), MouseKeys::empty()).await;
|
editor.move_mouse(start_pos.x, start_pos.y, ModifierKeys::empty(), MouseKeys::empty()).await;
|
||||||
editor.left_mousedown(start_pos.x, start_pos.y, ModifierKeys::empty()).await;
|
editor.left_mousedown(start_pos.x, start_pos.y, ModifierKeys::empty()).await;
|
||||||
|
|
||||||
editor.move_mouse(end_pos.x, end_pos.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
|
editor.move_mouse(end_pos.x, end_pos.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.mouseup(
|
.mouseup(
|
||||||
EditorMouseState {
|
EditorMouseState {
|
||||||
|
|
@ -770,10 +765,7 @@ mod test_gradient {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Check the updated gradient
|
// Check the updated gradient
|
||||||
let updated_fills = get_fills(&mut editor).await;
|
let (updated_gradient, transform) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(updated_fills.len(), 1);
|
|
||||||
let (updated_fill, transform) = updated_fills.first().unwrap();
|
|
||||||
let updated_gradient = updated_fill.as_gradient().unwrap();
|
|
||||||
|
|
||||||
// Verify the start point hasn't changed
|
// Verify the start point hasn't changed
|
||||||
let updated_start = transform.transform_point2(updated_gradient.start);
|
let updated_start = transform.transform_point2(updated_gradient.start);
|
||||||
|
|
@ -790,46 +782,29 @@ mod test_gradient {
|
||||||
editor.new_document().await;
|
editor.new_document().await;
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
editor.select_primary_color(Color::GREEN).await;
|
editor.select_primary_color(Color::GREEN).await;
|
||||||
editor.select_secondary_color(Color::BLUE).await;
|
editor.select_secondary_color(Color::BLUE).await;
|
||||||
|
|
||||||
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
editor.select_tool(ToolType::Gradient).await;
|
editor.select_tool(ToolType::Gradient).await;
|
||||||
let click_position = DVec2::new(50., 0.);
|
|
||||||
let modifier_keys = ModifierKeys::empty();
|
|
||||||
|
|
||||||
editor
|
// Add a middle stop at 50%
|
||||||
.handle_message(InputPreprocessorMessage::DoubleClick {
|
editor.double_click(DVec2::new(50., 0.)).await;
|
||||||
editor_mouse_state: EditorMouseState {
|
|
||||||
editor_position: click_position,
|
|
||||||
mouse_keys: MouseKeys::LEFT,
|
|
||||||
scroll_delta: ScrollDelta::default(),
|
|
||||||
},
|
|
||||||
modifier_keys,
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let fills = get_fills(&mut editor).await;
|
let (initial_gradient, _) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(fills.len(), 1);
|
assert_eq!(initial_gradient.stops.len(), 3, "Expected 3 stops, found {}", initial_gradient.stops.len());
|
||||||
let (initial_fill, _) = fills.first().unwrap();
|
|
||||||
let initial_gradient = initial_fill.as_gradient().unwrap();
|
|
||||||
assert_eq!(initial_gradient.stops.len(), 3);
|
|
||||||
|
|
||||||
// Verify initial stop positions and colors
|
// Verify initial stop positions and colors
|
||||||
let mut stops = initial_gradient.stops.clone();
|
let mut stops = initial_gradient.stops.clone();
|
||||||
stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
||||||
|
|
||||||
assert!((stops[0].0 - 0.0).abs() < 0.001);
|
let positions: Vec<f64> = stops.iter().map(|(pos, _)| *pos).collect();
|
||||||
assert!((stops[1].0 - 0.5).abs() < 0.1);
|
assert_stops_at_positions(&positions, &[0.0, 0.5, 1.0], 0.1);
|
||||||
assert!((stops[2].0 - 1.0).abs() < 0.001);
|
|
||||||
|
|
||||||
let middle_color = stops[1].1.to_rgba8_srgb();
|
let middle_color = stops[1].1.to_rgba8_srgb();
|
||||||
|
|
||||||
// Simulate dragging the middle stop to position 0.8
|
// Simulate dragging the middle stop to position 0.8
|
||||||
editor.select_tool(ToolType::Gradient).await;
|
let click_position = DVec2::new(50., 0.);
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.mousedown(
|
.mousedown(
|
||||||
EditorMouseState {
|
EditorMouseState {
|
||||||
|
|
@ -855,24 +830,78 @@ mod test_gradient {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let fills_after_drag = get_fills(&mut editor).await;
|
let (updated_gradient, _) = get_gradient(&mut editor).await;
|
||||||
assert_eq!(fills_after_drag.len(), 1);
|
assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops after dragging, found {}", updated_gradient.stops.len());
|
||||||
let (updated_fill, _) = fills_after_drag.first().unwrap();
|
|
||||||
let updated_gradient = updated_fill.as_gradient().unwrap();
|
|
||||||
assert_eq!(updated_gradient.stops.len(), 3);
|
|
||||||
|
|
||||||
// Verify updated stop positions and colors
|
// Verify updated stop positions and colors
|
||||||
let mut updated_stops = updated_gradient.stops.clone();
|
let mut updated_stops = updated_gradient.stops.clone();
|
||||||
updated_stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
updated_stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
||||||
|
|
||||||
// Check positions are now correctly ordered
|
// Check positions are now correctly ordered
|
||||||
assert!((updated_stops[0].0 - 0.0).abs() < 0.001);
|
let updated_positions: Vec<f64> = updated_stops.iter().map(|(pos, _)| *pos).collect();
|
||||||
assert!((updated_stops[1].0 - 0.8).abs() < 0.1);
|
assert_stops_at_positions(&updated_positions, &[0.0, 0.8, 1.0], 0.1);
|
||||||
assert!((updated_stops[2].0 - 1.0).abs() < 0.001);
|
|
||||||
|
|
||||||
// Colors should maintain their associations with the stop points
|
// Colors should maintain their associations with the stop points
|
||||||
assert_eq!(updated_stops[0].1.to_rgba8_srgb(), Color::BLUE.to_rgba8_srgb());
|
assert_eq!(updated_stops[0].1.to_rgba8_srgb(), Color::BLUE.to_rgba8_srgb());
|
||||||
assert_eq!(updated_stops[1].1.to_rgba8_srgb(), middle_color);
|
assert_eq!(updated_stops[1].1.to_rgba8_srgb(), middle_color);
|
||||||
assert_eq!(updated_stops[2].1.to_rgba8_srgb(), Color::GREEN.to_rgba8_srgb());
|
assert_eq!(updated_stops[2].1.to_rgba8_srgb(), Color::GREEN.to_rgba8_srgb());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn select_and_delete_removes_stop() {
|
||||||
|
let mut editor = EditorTestUtils::create();
|
||||||
|
editor.new_document().await;
|
||||||
|
|
||||||
|
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
|
||||||
|
editor.select_primary_color(Color::GREEN).await;
|
||||||
|
editor.select_secondary_color(Color::BLUE).await;
|
||||||
|
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
|
||||||
|
|
||||||
|
// Get initial gradient state (should have 2 stops)
|
||||||
|
let (initial_gradient, _) = get_gradient(&mut editor).await;
|
||||||
|
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
|
||||||
|
|
||||||
|
editor.select_tool(ToolType::Gradient).await;
|
||||||
|
|
||||||
|
// Add two middle stops
|
||||||
|
editor.double_click(DVec2::new(25., 0.)).await;
|
||||||
|
editor.double_click(DVec2::new(75., 0.)).await;
|
||||||
|
|
||||||
|
let (updated_gradient, _) = get_gradient(&mut editor).await;
|
||||||
|
assert_eq!(updated_gradient.stops.len(), 4, "Expected 4 stops, found {}", updated_gradient.stops.len());
|
||||||
|
|
||||||
|
let positions: Vec<f64> = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect();
|
||||||
|
|
||||||
|
// Use helper function to verify positions
|
||||||
|
assert_stops_at_positions(&positions, &[0.0, 0.25, 0.75, 1.0], 0.05);
|
||||||
|
|
||||||
|
// Select the stop at position 0.75 and delete it
|
||||||
|
let position2 = DVec2::new(75., 0.);
|
||||||
|
editor.move_mouse(position2.x, position2.y, ModifierKeys::empty(), MouseKeys::empty()).await;
|
||||||
|
editor.left_mousedown(position2.x, position2.y, ModifierKeys::empty()).await;
|
||||||
|
editor
|
||||||
|
.mouseup(
|
||||||
|
EditorMouseState {
|
||||||
|
editor_position: position2,
|
||||||
|
mouse_keys: MouseKeys::empty(),
|
||||||
|
scroll_delta: ScrollDelta::default(),
|
||||||
|
},
|
||||||
|
ModifierKeys::empty(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
editor.press(Key::Delete, ModifierKeys::empty()).await;
|
||||||
|
|
||||||
|
// Verify we now have 3 stops
|
||||||
|
let (final_gradient, _) = get_gradient(&mut editor).await;
|
||||||
|
assert_eq!(final_gradient.stops.len(), 3, "Expected 3 stops after deletion, found {}", final_gradient.stops.len());
|
||||||
|
|
||||||
|
let final_positions: Vec<f64> = final_gradient.stops.iter().map(|(pos, _)| *pos).collect();
|
||||||
|
|
||||||
|
// Verify final positions with helper function
|
||||||
|
assert_stops_at_positions(&final_positions, &[0.0, 0.25, 1.0], 0.05);
|
||||||
|
|
||||||
|
// Additional verification that 0.75 stop is gone
|
||||||
|
assert!(!final_positions.iter().any(|pos| (pos - 0.75).abs() < 0.05), "Stop at position 0.75 should have been deleted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,18 @@ impl EditorTestUtils {
|
||||||
pub async fn get_selected_layer(&mut self) -> Option<LayerNodeIdentifier> {
|
pub async fn get_selected_layer(&mut self) -> Option<LayerNodeIdentifier> {
|
||||||
self.active_document().network_interface.selected_nodes().selected_layers(self.active_document().metadata()).next()
|
self.active_document().network_interface.selected_nodes().selected_layers(self.active_document().metadata()).next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn double_click(&mut self, position: DVec2) {
|
||||||
|
self.handle_message(InputPreprocessorMessage::DoubleClick {
|
||||||
|
editor_mouse_state: EditorMouseState {
|
||||||
|
editor_position: position,
|
||||||
|
mouse_keys: MouseKeys::LEFT,
|
||||||
|
scroll_delta: ScrollDelta::default(),
|
||||||
|
},
|
||||||
|
modifier_keys: ModifierKeys::empty(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FrontendMessageTestUtils {
|
pub trait FrontendMessageTestUtils {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue