From 30432cbade3d9b25c4df62656a7494db3f4ea82a Mon Sep 17 00:00:00 2001 From: shan Date: Wed, 5 Oct 2022 10:49:58 -0700 Subject: Readjusted namespaces, removed Geometry example as it's no longer relevant. --- graphics/src/gradient/linear.rs | 71 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 graphics/src/gradient/linear.rs (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs new file mode 100644 index 00000000..00f94adc --- /dev/null +++ b/graphics/src/gradient/linear.rs @@ -0,0 +1,71 @@ +//! Linear gradient builder & definition. + +use crate::gradient::{ColorStop, Gradient}; +use crate::{Color, Point}; + +/// A linear gradient that can be used in the style of [`super::Fill`] or [`super::Stroke`]. +#[derive(Debug, Clone, PartialEq)] +pub struct Linear { + /// The point where the linear gradient begins. + pub start: Point, + /// The point where the linear gradient ends. + pub end: Point, + /// [`ColorStop`]s along the linear gradient path. + pub color_stops: Vec, +} + +/// A [`Linear`] builder. +#[derive(Debug)] +pub struct Builder { + start: Point, + end: Point, + stops: Vec<(f32, Color)>, + valid: bool, +} + +impl Builder { + /// Creates a new [`Builder`]. + pub fn new(start: Point, end: Point) -> Self { + Self { + start, + end, + stops: vec![], + valid: true, + } + } + + /// Adds a new stop, defined by an offset and a color, to the gradient. + /// + /// `offset` must be between `0.0` and `1.0`. + pub fn add_stop(mut self, offset: f32, color: Color) -> Self { + if !(0.0..=1.0).contains(&offset) { + self.valid = false; + } + + self.stops.push((offset, color)); + self + } + + /// Builds the linear [`Gradient`] of this [`Builder`]. + /// + /// Returns `None` if no stops were added to the builder or + /// if stops not between 0.0 and 1.0 were added. + pub fn build(self) -> Option { + if self.stops.is_empty() || !self.valid { + return None; + } + + let mut stops: Vec = self.stops.clone().into_iter().map(|f| ColorStop { + offset: f.0, + color: f.1 + }).collect(); + + stops.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap()); + + Some(Gradient::Linear(Linear { + start: self.start, + end: self.end, + color_stops: stops + })) + } +} \ No newline at end of file -- cgit From cb7c4676543cd508dfae8d4dcbd9cc8b61b1a94e Mon Sep 17 00:00:00 2001 From: shan Date: Thu, 6 Oct 2022 07:28:05 -0700 Subject: Fixed lint issues & cleaned up some documentation. --- graphics/src/gradient/linear.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 00f94adc..1ffe7cf9 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -68,4 +68,4 @@ impl Builder { color_stops: stops })) } -} \ No newline at end of file +} -- cgit From 72feba51bed41db0bc04b43167d5d3b43007fd44 Mon Sep 17 00:00:00 2001 From: shan Date: Thu, 6 Oct 2022 19:13:40 -0700 Subject: Fixed some imports/documentation. --- graphics/src/gradient/linear.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 1ffe7cf9..6bf69b43 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -42,6 +42,7 @@ impl Builder { self.valid = false; } + //TODO: can sort on insert here self.stops.push((offset, color)); self } -- cgit From 12a87c54eb68b992676060c80e518ffb29445cfc Mon Sep 17 00:00:00 2001 From: shan Date: Fri, 7 Oct 2022 11:41:50 -0700 Subject: Added support for relative positioning of gradient fills. Addressed some PR feedback. --- graphics/src/gradient/linear.rs | 148 ++++++++++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 21 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 6bf69b43..a9cfd55d 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -1,7 +1,6 @@ //! Linear gradient builder & definition. - use crate::gradient::{ColorStop, Gradient}; -use crate::{Color, Point}; +use crate::{Color, Point, Size}; /// A linear gradient that can be used in the style of [`super::Fill`] or [`super::Stroke`]. #[derive(Debug, Clone, PartialEq)] @@ -14,18 +13,115 @@ pub struct Linear { pub color_stops: Vec, } +#[derive(Debug)] +/// The position of the gradient within its bounds. +pub enum Position { + /// The gradient will be positioned with respect to two points. + Absolute { + /// The starting point of the gradient. + start: Point, + /// The ending point of the gradient. + end: Point, + }, + /// The gradient will be positioned relative to the provided bounds. + Relative { + /// The top left position of the bounds. + top_left: Point, + /// The width & height of the bounds. + size: Size, + /// The start [Location] of the gradient. + start: Location, + /// The end [Location] of the gradient. + end: Location, + }, +} + +impl Into for (Point, Point) { + fn into(self) -> Position { + Position::Absolute { + start: self.0, + end: self.1, + } + } +} + +#[derive(Debug)] +/// The location of a relatively-positioned gradient. +pub enum Location { + /// Top left. + TopLeft, + /// Top. + Top, + /// Top right. + TopRight, + /// Right. + Right, + /// Bottom right. + BottomRight, + /// Bottom. + Bottom, + /// Bottom left. + BottomLeft, + /// Left. + Left, +} + +impl Location { + fn to_absolute(&self, top_left: Point, size: Size) -> Point { + match self { + Location::TopLeft => top_left, + Location::Top => { + Point::new(top_left.x + size.width / 2.0, top_left.y) + } + Location::TopRight => { + Point::new(top_left.x + size.width, top_left.y) + } + Location::Right => Point::new( + top_left.x + size.width, + top_left.y + size.height / 2.0, + ), + Location::BottomRight => { + Point::new(top_left.x + size.width, top_left.y + size.height) + } + Location::Bottom => Point::new( + top_left.x + size.width / 2.0, + top_left.y + size.height, + ), + Location::BottomLeft => { + Point::new(top_left.x, top_left.y + size.height) + } + Location::Left => { + Point::new(top_left.x, top_left.y + size.height / 2.0) + } + } + } +} + /// A [`Linear`] builder. #[derive(Debug)] pub struct Builder { start: Point, end: Point, - stops: Vec<(f32, Color)>, + stops: Vec, valid: bool, } impl Builder { /// Creates a new [`Builder`]. - pub fn new(start: Point, end: Point) -> Self { + pub fn new(position: Position) -> Self { + let (start, end) = match position { + Position::Absolute { start, end } => (start, end), + Position::Relative { + top_left, + size, + start, + end, + } => ( + start.to_absolute(top_left, size), + end.to_absolute(top_left, size), + ), + }; + Self { start, end, @@ -36,37 +132,47 @@ impl Builder { /// Adds a new stop, defined by an offset and a color, to the gradient. /// - /// `offset` must be between `0.0` and `1.0`. + /// `offset` must be between `0.0` and `1.0` or the gradient cannot be built. + /// + /// Note: when using the [Glow] backend, any color stop added after the 16th + /// will not be displayed. + /// + /// On [backend::Wgpu] backend this limitation does not exist (technical limit is 524,288 stops). pub fn add_stop(mut self, offset: f32, color: Color) -> Self { - if !(0.0..=1.0).contains(&offset) { + if offset.is_finite() && (0.0..=1.0).contains(&offset) { + match self.stops.binary_search_by(|stop| { + stop.offset.partial_cmp(&offset).unwrap() + }) { + Ok(_) => { + //the offset already exists in the gradient + self.valid = false; + } + Err(index) => { + self.stops.insert(index, ColorStop { offset, color }) + } + } + } else { self.valid = false; } - - //TODO: can sort on insert here - self.stops.push((offset, color)); self } /// Builds the linear [`Gradient`] of this [`Builder`]. /// - /// Returns `None` if no stops were added to the builder or + /// Returns `Err` if no stops were added to the builder or /// if stops not between 0.0 and 1.0 were added. - pub fn build(self) -> Option { + pub fn build(self) -> Result { if self.stops.is_empty() || !self.valid { - return None; + return Err("Valid gradient conditions: \ + 1) Must contain at least one color stop. \ + 2) Every color stop offset must be unique. \ + 3) Every color stop must be within the range of 0.0..=1.0"); } - let mut stops: Vec = self.stops.clone().into_iter().map(|f| ColorStop { - offset: f.0, - color: f.1 - }).collect(); - - stops.sort_by(|a, b| a.offset.partial_cmp(&b.offset).unwrap()); - - Some(Gradient::Linear(Linear { + Ok(Gradient::Linear(Linear { start: self.start, end: self.end, - color_stops: stops + color_stops: self.stops, })) } } -- cgit From c4565759e4294540f54a81e4d91ddea7a769d3d4 Mon Sep 17 00:00:00 2001 From: bungoboingo Date: Tue, 18 Oct 2022 15:18:37 -0700 Subject: Cleaned up namespaces re: PR comments. --- graphics/src/gradient/linear.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index a9cfd55d..020c65db 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -134,10 +134,13 @@ impl Builder { /// /// `offset` must be between `0.0` and `1.0` or the gradient cannot be built. /// - /// Note: when using the [Glow] backend, any color stop added after the 16th + /// Note: when using the [`glow`] backend, any color stop added after the 16th /// will not be displayed. /// - /// On [backend::Wgpu] backend this limitation does not exist (technical limit is 524,288 stops). + /// On the [`wgpu`] backend this limitation does not exist (technical limit is 524,288 stops). + /// + /// [`glow`]: https://docs.rs/iced_glow + /// [`wgpu`]: https://docs.rs/iced_wgpu pub fn add_stop(mut self, offset: f32, color: Color) -> Self { if offset.is_finite() && (0.0..=1.0).contains(&offset) { match self.stops.binary_search_by(|stop| { -- cgit From ab311c9375999d568a599b31424a12beb3f02ad2 Mon Sep 17 00:00:00 2001 From: bungoboingo Date: Tue, 18 Oct 2022 17:45:47 -0700 Subject: Changed gradient builder to be more clear about what caused certain errors. --- graphics/src/gradient/linear.rs | 52 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 020c65db..03dd04a2 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -103,7 +103,7 @@ pub struct Builder { start: Point, end: Point, stops: Vec, - valid: bool, + error: Option } impl Builder { @@ -126,7 +126,7 @@ impl Builder { start, end, stops: vec![], - valid: true, + error: None } } @@ -147,35 +147,43 @@ impl Builder { stop.offset.partial_cmp(&offset).unwrap() }) { Ok(_) => { - //the offset already exists in the gradient - self.valid = false; - } + self.error = Some(BuilderError::DuplicateOffset(offset)) + }, Err(index) => { - self.stops.insert(index, ColorStop { offset, color }) + self.stops.insert(index, ColorStop { offset, color }); } } } else { - self.valid = false; - } + self.error = Some(BuilderError::InvalidOffset(offset)) + }; + self } /// Builds the linear [`Gradient`] of this [`Builder`]. /// - /// Returns `Err` if no stops were added to the builder or - /// if stops not between 0.0 and 1.0 were added. - pub fn build(self) -> Result { - if self.stops.is_empty() || !self.valid { - return Err("Valid gradient conditions: \ - 1) Must contain at least one color stop. \ - 2) Every color stop offset must be unique. \ - 3) Every color stop must be within the range of 0.0..=1.0"); + /// Returns `BuilderError` if gradient in invalid. + pub fn build(self) -> Result { + if self.stops.is_empty() { + Err(BuilderError::MissingColorStop) + } else if let Some(error) = self.error { + Err(error) + } else { + Ok(Gradient::Linear(Linear { + start: self.start, + end: self.end, + color_stops: self.stops, + })) } - - Ok(Gradient::Linear(Linear { - start: self.start, - end: self.end, - color_stops: self.stops, - })) } } + +#[derive(Debug, thiserror::Error)] +pub enum BuilderError { + #[error("Gradients must contain at least one color stop.")] + MissingColorStop, + #[error("Offset {0} must be a unique, finite number.")] + DuplicateOffset(f32), + #[error("Offset {0} must be within 0.0..=1.0.")] + InvalidOffset(f32), +} -- cgit From d53e2624255680448282fb6f767c7eb732a74a9f Mon Sep 17 00:00:00 2001 From: bungoboingo Date: Wed, 19 Oct 2022 10:13:07 -0700 Subject: Documentation changes --- graphics/src/gradient/linear.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 03dd04a2..31dcbe00 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -181,9 +181,12 @@ impl Builder { #[derive(Debug, thiserror::Error)] pub enum BuilderError { #[error("Gradients must contain at least one color stop.")] + /// Gradients must contain at least one color stop. MissingColorStop, #[error("Offset {0} must be a unique, finite number.")] + /// Offsets in a gradient must all be unique & finite. DuplicateOffset(f32), - #[error("Offset {0} must be within 0.0..=1.0.")] + #[error("Offset {0} must be between 0.0..=1.0.")] + /// Offsets in a gradient must be between 0.0..=1.0. InvalidOffset(f32), } -- cgit From b95745340441835bd25b5cadc2342254631f8c05 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Nov 2022 04:35:16 +0100 Subject: Run `cargo fmt` --- graphics/src/gradient/linear.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 31dcbe00..aaa9e234 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -103,7 +103,7 @@ pub struct Builder { start: Point, end: Point, stops: Vec, - error: Option + error: Option, } impl Builder { @@ -126,7 +126,7 @@ impl Builder { start, end, stops: vec![], - error: None + error: None, } } @@ -148,7 +148,7 @@ impl Builder { }) { Ok(_) => { self.error = Some(BuilderError::DuplicateOffset(offset)) - }, + } Err(index) => { self.stops.insert(index, ColorStop { offset, color }); } -- cgit From 7e22e2d45293c5916812be03dc7367134b69b3ad Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Nov 2022 04:53:27 +0100 Subject: Fix lints by `clippy` --- graphics/src/gradient/linear.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index aaa9e234..439e848e 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -36,12 +36,9 @@ pub enum Position { }, } -impl Into for (Point, Point) { - fn into(self) -> Position { - Position::Absolute { - start: self.0, - end: self.1, - } +impl From<(Point, Point)> for Position { + fn from((start, end): (Point, Point)) -> Self { + Self::Absolute { start, end } } } -- cgit From d8045e2dc30633553e087ad6f7748235223017d7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Nov 2022 05:15:32 +0100 Subject: Move `Position` and `Location` to `gradient` module --- graphics/src/gradient/linear.rs | 86 ++--------------------------------------- 1 file changed, 3 insertions(+), 83 deletions(-) (limited to 'graphics/src/gradient/linear.rs') diff --git a/graphics/src/gradient/linear.rs b/graphics/src/gradient/linear.rs index 439e848e..9928c1eb 100644 --- a/graphics/src/gradient/linear.rs +++ b/graphics/src/gradient/linear.rs @@ -1,6 +1,6 @@ //! Linear gradient builder & definition. -use crate::gradient::{ColorStop, Gradient}; -use crate::{Color, Point, Size}; +use crate::gradient::{ColorStop, Gradient, Position}; +use crate::{Color, Point}; /// A linear gradient that can be used in the style of [`super::Fill`] or [`super::Stroke`]. #[derive(Debug, Clone, PartialEq)] @@ -13,87 +13,6 @@ pub struct Linear { pub color_stops: Vec, } -#[derive(Debug)] -/// The position of the gradient within its bounds. -pub enum Position { - /// The gradient will be positioned with respect to two points. - Absolute { - /// The starting point of the gradient. - start: Point, - /// The ending point of the gradient. - end: Point, - }, - /// The gradient will be positioned relative to the provided bounds. - Relative { - /// The top left position of the bounds. - top_left: Point, - /// The width & height of the bounds. - size: Size, - /// The start [Location] of the gradient. - start: Location, - /// The end [Location] of the gradient. - end: Location, - }, -} - -impl From<(Point, Point)> for Position { - fn from((start, end): (Point, Point)) -> Self { - Self::Absolute { start, end } - } -} - -#[derive(Debug)] -/// The location of a relatively-positioned gradient. -pub enum Location { - /// Top left. - TopLeft, - /// Top. - Top, - /// Top right. - TopRight, - /// Right. - Right, - /// Bottom right. - BottomRight, - /// Bottom. - Bottom, - /// Bottom left. - BottomLeft, - /// Left. - Left, -} - -impl Location { - fn to_absolute(&self, top_left: Point, size: Size) -> Point { - match self { - Location::TopLeft => top_left, - Location::Top => { - Point::new(top_left.x + size.width / 2.0, top_left.y) - } - Location::TopRight => { - Point::new(top_left.x + size.width, top_left.y) - } - Location::Right => Point::new( - top_left.x + size.width, - top_left.y + size.height / 2.0, - ), - Location::BottomRight => { - Point::new(top_left.x + size.width, top_left.y + size.height) - } - Location::Bottom => Point::new( - top_left.x + size.width / 2.0, - top_left.y + size.height, - ), - Location::BottomLeft => { - Point::new(top_left.x, top_left.y + size.height) - } - Location::Left => { - Point::new(top_left.x, top_left.y + size.height / 2.0) - } - } - } -} - /// A [`Linear`] builder. #[derive(Debug)] pub struct Builder { @@ -175,6 +94,7 @@ impl Builder { } } +/// An error that happened when building a [`Linear`] gradient. #[derive(Debug, thiserror::Error)] pub enum BuilderError { #[error("Gradients must contain at least one color stop.")] -- cgit