mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 10:38:11 +08:00
Gradient tool improvements (#927)
* Reuse existing gradient * Double click to insert gradient stop * Add history states to the gradient tool * Do trig in viewport space so it is actually perpendicular * Sync tool options with active gradient * Deleting points with delete key * More tolerance on inserting points
This commit is contained in:
committed by
Keavon Chambers
parent
69293964c4
commit
0d703e857b
@@ -205,4 +205,17 @@ impl Color {
|
||||
|
||||
Some(Color::from_rgb8(r, g, b))
|
||||
}
|
||||
|
||||
/// Linearly interpolates between two colors based on t.
|
||||
///
|
||||
/// T must be between 0 and 1.
|
||||
pub fn lerp(self, other: Color, t: f32) -> Option<Self> {
|
||||
assert!((0. ..=1.).contains(&t));
|
||||
Color::from_rgbaf32(
|
||||
self.red + ((other.red - self.red) * t),
|
||||
self.green + ((other.green - self.green) * t),
|
||||
self.blue + ((other.blue - self.blue) * t),
|
||||
self.alpha + ((other.alpha - self.alpha) * t),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,12 @@ pub struct Document {
|
||||
pub state_identifier: DefaultHasher,
|
||||
}
|
||||
|
||||
impl PartialEq for Document {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.state_identifier.finish() == other.state_identifier.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Document {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
@@ -138,6 +138,45 @@ impl Gradient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a stop into the gradient, the index if successful
|
||||
pub fn insert_stop(&mut self, mouse: DVec2, transform: DAffine2) -> Option<usize> {
|
||||
// Transform the start and end positions to the same coordinate space as the mouse.
|
||||
let (start, end) = (transform.transform_point2(self.start), transform.transform_point2(self.end));
|
||||
|
||||
// Calculate the new position by finding the closest point on the line
|
||||
let new_position = ((end - start).angle_between(mouse - start)).cos() * start.distance(mouse) / start.distance(end);
|
||||
|
||||
// Don't insert point past end of line
|
||||
if !(0. ..=1.).contains(&new_position) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Compute the color of the inserted stop
|
||||
let get_color = |index: usize, time: f64| match (self.positions[index].1, self.positions.get(index + 1).and_then(|x| x.1)) {
|
||||
// Lerp between the nearest colours if applicable
|
||||
(Some(a), Some(b)) => a.lerp(
|
||||
b,
|
||||
((time - self.positions[index].0) / self.positions.get(index + 1).map(|end| end.0 - self.positions[index].0).unwrap_or_default()) as f32,
|
||||
),
|
||||
// Use the start or the end colour if applicable
|
||||
(Some(v), _) | (_, Some(v)) => Some(v),
|
||||
_ => Some(Color::WHITE),
|
||||
};
|
||||
|
||||
// Compute the correct index to keep the positions in order
|
||||
let mut index = 0;
|
||||
while self.positions.len() > index && self.positions[index].0 <= new_position {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
let new_color = get_color(index - 1, new_position);
|
||||
|
||||
// Insert the new stop
|
||||
self.positions.insert(index, (new_position, new_color));
|
||||
|
||||
Some(index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the fill of a layer.
|
||||
@@ -189,6 +228,15 @@ impl Fill {
|
||||
pub fn is_some(&self) -> bool {
|
||||
*self != Self::None
|
||||
}
|
||||
|
||||
/// Extract a gradient from the fill
|
||||
pub fn as_gradient(&self) -> Option<&Gradient> {
|
||||
if let Self::Gradient(gradient) = self {
|
||||
Some(gradient)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The stroke (outline) style of an SVG element.
|
||||
|
||||
Reference in New Issue
Block a user