diff options
| author | 2023-07-12 12:23:18 -0700 | |
|---|---|---|
| committer | 2023-07-12 12:23:18 -0700 | |
| commit | 633f405f3f78bc7f82d2b2061491b0e011137451 (patch) | |
| tree | 5ebfc1f45d216a5c14a90492563599e6969eab4d /graphics/src/widget/canvas | |
| parent | 41836dd80d0534608e7aedfbf2319c540a23de1a (diff) | |
| parent | 21bd51426d900e271206f314e0c915dd41065521 (diff) | |
| download | iced-633f405f3f78bc7f82d2b2061491b0e011137451.tar.gz iced-633f405f3f78bc7f82d2b2061491b0e011137451.tar.bz2 iced-633f405f3f78bc7f82d2b2061491b0e011137451.zip | |
Merge remote-tracking branch 'origin/master' into feat/multi-window-support
# Conflicts:
#	Cargo.toml
#	core/src/window/icon.rs
#	core/src/window/id.rs
#	core/src/window/position.rs
#	core/src/window/settings.rs
#	examples/integration/src/main.rs
#	examples/integration_opengl/src/main.rs
#	glutin/src/application.rs
#	native/src/subscription.rs
#	native/src/window.rs
#	runtime/src/window/action.rs
#	src/lib.rs
#	src/window.rs
#	winit/Cargo.toml
#	winit/src/application.rs
#	winit/src/icon.rs
#	winit/src/settings.rs
#	winit/src/window.rs
Diffstat (limited to 'graphics/src/widget/canvas')
| -rw-r--r-- | graphics/src/widget/canvas/cache.rs | 100 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/cursor.rs | 64 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/event.rs | 21 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/fill.rs | 72 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/frame.rs | 530 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/geometry.rs | 24 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/path.rs | 109 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/path/arc.rs | 42 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/path/builder.rs | 198 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/program.rs | 102 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/stroke.rs | 126 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/style.rs | 23 | ||||
| -rw-r--r-- | graphics/src/widget/canvas/text.rs | 57 | 
13 files changed, 0 insertions, 1468 deletions
| diff --git a/graphics/src/widget/canvas/cache.rs b/graphics/src/widget/canvas/cache.rs deleted file mode 100644 index 52217bbb..00000000 --- a/graphics/src/widget/canvas/cache.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::widget::canvas::{Frame, Geometry}; -use crate::Primitive; - -use iced_native::Size; -use std::{cell::RefCell, sync::Arc}; - -enum State { -    Empty, -    Filled { -        bounds: Size, -        primitive: Arc<Primitive>, -    }, -} - -impl Default for State { -    fn default() -> Self { -        State::Empty -    } -} -/// A simple cache that stores generated [`Geometry`] to avoid recomputation. -/// -/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer -/// change or it is explicitly cleared. -#[derive(Debug, Default)] -pub struct Cache { -    state: RefCell<State>, -} - -impl Cache { -    /// Creates a new empty [`Cache`]. -    pub fn new() -> Self { -        Cache { -            state: Default::default(), -        } -    } - -    /// Clears the [`Cache`], forcing a redraw the next time it is used. -    pub fn clear(&self) { -        *self.state.borrow_mut() = State::Empty; -    } - -    /// Draws [`Geometry`] using the provided closure and stores it in the -    /// [`Cache`]. -    /// -    /// The closure will only be called when -    /// - the bounds have changed since the previous draw call. -    /// - the [`Cache`] is empty or has been explicitly cleared. -    /// -    /// Otherwise, the previously stored [`Geometry`] will be returned. The -    /// [`Cache`] is not cleared in this case. In other words, it will keep -    /// returning the stored [`Geometry`] if needed. -    pub fn draw( -        &self, -        bounds: Size, -        draw_fn: impl FnOnce(&mut Frame), -    ) -> Geometry { -        use std::ops::Deref; - -        if let State::Filled { -            bounds: cached_bounds, -            primitive, -        } = self.state.borrow().deref() -        { -            if *cached_bounds == bounds { -                return Geometry::from_primitive(Primitive::Cached { -                    cache: primitive.clone(), -                }); -            } -        } - -        let mut frame = Frame::new(bounds); -        draw_fn(&mut frame); - -        let primitive = { -            let geometry = frame.into_geometry(); - -            Arc::new(geometry.into_primitive()) -        }; - -        *self.state.borrow_mut() = State::Filled { -            bounds, -            primitive: primitive.clone(), -        }; - -        Geometry::from_primitive(Primitive::Cached { cache: primitive }) -    } -} - -impl std::fmt::Debug for State { -    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -        match self { -            State::Empty => write!(f, "Empty"), -            State::Filled { primitive, bounds } => f -                .debug_struct("Filled") -                .field("primitive", primitive) -                .field("bounds", bounds) -                .finish(), -        } -    } -} diff --git a/graphics/src/widget/canvas/cursor.rs b/graphics/src/widget/canvas/cursor.rs deleted file mode 100644 index 9588d129..00000000 --- a/graphics/src/widget/canvas/cursor.rs +++ /dev/null @@ -1,64 +0,0 @@ -use iced_native::{Point, Rectangle}; - -/// The mouse cursor state. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Cursor { -    /// The cursor has a defined position. -    Available(Point), - -    /// The cursor is currently unavailable (i.e. out of bounds or busy). -    Unavailable, -} - -impl Cursor { -    // TODO: Remove this once this type is used in `iced_native` to encode -    // proper cursor availability -    pub(crate) fn from_window_position(position: Point) -> Self { -        if position.x < 0.0 || position.y < 0.0 { -            Cursor::Unavailable -        } else { -            Cursor::Available(position) -        } -    } - -    /// Returns the absolute position of the [`Cursor`], if available. -    pub fn position(&self) -> Option<Point> { -        match self { -            Cursor::Available(position) => Some(*position), -            Cursor::Unavailable => None, -        } -    } - -    /// Returns the relative position of the [`Cursor`] inside the given bounds, -    /// if available. -    /// -    /// If the [`Cursor`] is not over the provided bounds, this method will -    /// return `None`. -    pub fn position_in(&self, bounds: &Rectangle) -> Option<Point> { -        if self.is_over(bounds) { -            self.position_from(bounds.position()) -        } else { -            None -        } -    } - -    /// Returns the relative position of the [`Cursor`] from the given origin, -    /// if available. -    pub fn position_from(&self, origin: Point) -> Option<Point> { -        match self { -            Cursor::Available(position) => { -                Some(Point::new(position.x - origin.x, position.y - origin.y)) -            } -            Cursor::Unavailable => None, -        } -    } - -    /// Returns whether the [`Cursor`] is currently over the provided bounds -    /// or not. -    pub fn is_over(&self, bounds: &Rectangle) -> bool { -        match self { -            Cursor::Available(position) => bounds.contains(*position), -            Cursor::Unavailable => false, -        } -    } -} diff --git a/graphics/src/widget/canvas/event.rs b/graphics/src/widget/canvas/event.rs deleted file mode 100644 index 7c733a4d..00000000 --- a/graphics/src/widget/canvas/event.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Handle events of a canvas. -use iced_native::keyboard; -use iced_native::mouse; -use iced_native::touch; - -pub use iced_native::event::Status; - -/// A [`Canvas`] event. -/// -/// [`Canvas`]: crate::widget::Canvas -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Event { -    /// A mouse event. -    Mouse(mouse::Event), - -    /// A touch event. -    Touch(touch::Event), - -    /// A keyboard event. -    Keyboard(keyboard::Event), -} diff --git a/graphics/src/widget/canvas/fill.rs b/graphics/src/widget/canvas/fill.rs deleted file mode 100644 index e954ebb5..00000000 --- a/graphics/src/widget/canvas/fill.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Fill [crate::widget::canvas::Geometry] with a certain style. -use crate::{Color, Gradient}; - -pub use crate::widget::canvas::Style; - -/// The style used to fill geometry. -#[derive(Debug, Clone)] -pub struct Fill { -    /// The color or gradient of the fill. -    /// -    /// By default, it is set to [`Style::Solid`] with [`Color::BLACK`]. -    pub style: Style, - -    /// The fill rule defines how to determine what is inside and what is -    /// outside of a shape. -    /// -    /// See the [SVG specification][1] for more details. -    /// -    /// By default, it is set to `NonZero`. -    /// -    /// [1]: https://www.w3.org/TR/SVG/painting.html#FillRuleProperty -    pub rule: FillRule, -} - -impl Default for Fill { -    fn default() -> Self { -        Self { -            style: Style::Solid(Color::BLACK), -            rule: FillRule::NonZero, -        } -    } -} - -impl From<Color> for Fill { -    fn from(color: Color) -> Fill { -        Fill { -            style: Style::Solid(color), -            ..Fill::default() -        } -    } -} - -impl From<Gradient> for Fill { -    fn from(gradient: Gradient) -> Self { -        Fill { -            style: Style::Gradient(gradient), -            ..Default::default() -        } -    } -} - -/// The fill rule defines how to determine what is inside and what is outside of -/// a shape. -/// -/// See the [SVG specification][1]. -/// -/// [1]: https://www.w3.org/TR/SVG/painting.html#FillRuleProperty -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(missing_docs)] -pub enum FillRule { -    NonZero, -    EvenOdd, -} - -impl From<FillRule> for lyon::tessellation::FillRule { -    fn from(rule: FillRule) -> lyon::tessellation::FillRule { -        match rule { -            FillRule::NonZero => lyon::tessellation::FillRule::NonZero, -            FillRule::EvenOdd => lyon::tessellation::FillRule::EvenOdd, -        } -    } -} diff --git a/graphics/src/widget/canvas/frame.rs b/graphics/src/widget/canvas/frame.rs deleted file mode 100644 index d68548ae..00000000 --- a/graphics/src/widget/canvas/frame.rs +++ /dev/null @@ -1,530 +0,0 @@ -use crate::gradient::Gradient; -use crate::triangle; -use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Style, Text}; -use crate::Primitive; - -use iced_native::{Point, Rectangle, Size, Vector}; - -use lyon::geom::euclid; -use lyon::tessellation; -use std::borrow::Cow; - -/// The frame of a [`Canvas`]. -/// -/// [`Canvas`]: crate::widget::Canvas -#[allow(missing_debug_implementations)] -pub struct Frame { -    size: Size, -    buffers: BufferStack, -    primitives: Vec<Primitive>, -    transforms: Transforms, -    fill_tessellator: tessellation::FillTessellator, -    stroke_tessellator: tessellation::StrokeTessellator, -} - -enum Buffer { -    Solid(tessellation::VertexBuffers<triangle::ColoredVertex2D, u32>), -    Gradient( -        tessellation::VertexBuffers<triangle::Vertex2D, u32>, -        Gradient, -    ), -} - -struct BufferStack { -    stack: Vec<Buffer>, -} - -impl BufferStack { -    fn new() -> Self { -        Self { stack: Vec::new() } -    } - -    fn get_mut(&mut self, style: &Style) -> &mut Buffer { -        match style { -            Style::Solid(_) => match self.stack.last() { -                Some(Buffer::Solid(_)) => {} -                _ => { -                    self.stack.push(Buffer::Solid( -                        tessellation::VertexBuffers::new(), -                    )); -                } -            }, -            Style::Gradient(gradient) => match self.stack.last() { -                Some(Buffer::Gradient(_, last)) if gradient == last => {} -                _ => { -                    self.stack.push(Buffer::Gradient( -                        tessellation::VertexBuffers::new(), -                        gradient.clone(), -                    )); -                } -            }, -        } - -        self.stack.last_mut().unwrap() -    } - -    fn get_fill<'a>( -        &'a mut self, -        style: &Style, -    ) -> Box<dyn tessellation::FillGeometryBuilder + 'a> { -        match (style, self.get_mut(style)) { -            (Style::Solid(color), Buffer::Solid(buffer)) => { -                Box::new(tessellation::BuffersBuilder::new( -                    buffer, -                    TriangleVertex2DBuilder(color.into_linear()), -                )) -            } -            (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new( -                tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder), -            ), -            _ => unreachable!(), -        } -    } - -    fn get_stroke<'a>( -        &'a mut self, -        style: &Style, -    ) -> Box<dyn tessellation::StrokeGeometryBuilder + 'a> { -        match (style, self.get_mut(style)) { -            (Style::Solid(color), Buffer::Solid(buffer)) => { -                Box::new(tessellation::BuffersBuilder::new( -                    buffer, -                    TriangleVertex2DBuilder(color.into_linear()), -                )) -            } -            (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new( -                tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder), -            ), -            _ => unreachable!(), -        } -    } -} - -#[derive(Debug)] -struct Transforms { -    previous: Vec<Transform>, -    current: Transform, -} - -#[derive(Debug, Clone, Copy)] -struct Transform { -    raw: lyon::math::Transform, -    is_identity: bool, -} - -impl Transform { -    /// Transforms the given [Point] by the transformation matrix. -    fn transform_point(&self, point: &mut Point) { -        let transformed = self -            .raw -            .transform_point(euclid::Point2D::new(point.x, point.y)); -        point.x = transformed.x; -        point.y = transformed.y; -    } - -    fn transform_style(&self, style: Style) -> Style { -        match style { -            Style::Solid(color) => Style::Solid(color), -            Style::Gradient(gradient) => { -                Style::Gradient(self.transform_gradient(gradient)) -            } -        } -    } - -    fn transform_gradient(&self, mut gradient: Gradient) -> Gradient { -        let (start, end) = match &mut gradient { -            Gradient::Linear(linear) => (&mut linear.start, &mut linear.end), -        }; -        self.transform_point(start); -        self.transform_point(end); -        gradient -    } -} - -impl Frame { -    /// Creates a new empty [`Frame`] with the given dimensions. -    /// -    /// The default coordinate system of a [`Frame`] has its origin at the -    /// top-left corner of its bounds. -    pub fn new(size: Size) -> Frame { -        Frame { -            size, -            buffers: BufferStack::new(), -            primitives: Vec::new(), -            transforms: Transforms { -                previous: Vec::new(), -                current: Transform { -                    raw: lyon::math::Transform::identity(), -                    is_identity: true, -                }, -            }, -            fill_tessellator: tessellation::FillTessellator::new(), -            stroke_tessellator: tessellation::StrokeTessellator::new(), -        } -    } - -    /// Returns the width of the [`Frame`]. -    #[inline] -    pub fn width(&self) -> f32 { -        self.size.width -    } - -    /// Returns the height of the [`Frame`]. -    #[inline] -    pub fn height(&self) -> f32 { -        self.size.height -    } - -    /// Returns the dimensions of the [`Frame`]. -    #[inline] -    pub fn size(&self) -> Size { -        self.size -    } - -    /// Returns the coordinate of the center of the [`Frame`]. -    #[inline] -    pub fn center(&self) -> Point { -        Point::new(self.size.width / 2.0, self.size.height / 2.0) -    } - -    /// Draws the given [`Path`] on the [`Frame`] by filling it with the -    /// provided style. -    pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) { -        let Fill { style, rule } = fill.into(); - -        let mut buffer = self -            .buffers -            .get_fill(&self.transforms.current.transform_style(style)); - -        let options = -            tessellation::FillOptions::default().with_fill_rule(rule.into()); - -        if self.transforms.current.is_identity { -            self.fill_tessellator.tessellate_path( -                path.raw(), -                &options, -                buffer.as_mut(), -            ) -        } else { -            let path = path.transformed(&self.transforms.current.raw); - -            self.fill_tessellator.tessellate_path( -                path.raw(), -                &options, -                buffer.as_mut(), -            ) -        } -        .expect("Tessellate path."); -    } - -    /// Draws an axis-aligned rectangle given its top-left corner coordinate and -    /// its `Size` on the [`Frame`] by filling it with the provided style. -    pub fn fill_rectangle( -        &mut self, -        top_left: Point, -        size: Size, -        fill: impl Into<Fill>, -    ) { -        let Fill { style, rule } = fill.into(); - -        let mut buffer = self -            .buffers -            .get_fill(&self.transforms.current.transform_style(style)); - -        let top_left = -            self.transforms.current.raw.transform_point( -                lyon::math::Point::new(top_left.x, top_left.y), -            ); - -        let size = -            self.transforms.current.raw.transform_vector( -                lyon::math::Vector::new(size.width, size.height), -            ); - -        let options = -            tessellation::FillOptions::default().with_fill_rule(rule.into()); - -        self.fill_tessellator -            .tessellate_rectangle( -                &lyon::math::Box2D::new(top_left, top_left + size), -                &options, -                buffer.as_mut(), -            ) -            .expect("Fill rectangle"); -    } - -    /// Draws the stroke of the given [`Path`] on the [`Frame`] with the -    /// provided style. -    pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) { -        let stroke = stroke.into(); - -        let mut buffer = self -            .buffers -            .get_stroke(&self.transforms.current.transform_style(stroke.style)); - -        let mut options = tessellation::StrokeOptions::default(); -        options.line_width = stroke.width; -        options.start_cap = stroke.line_cap.into(); -        options.end_cap = stroke.line_cap.into(); -        options.line_join = stroke.line_join.into(); - -        let path = if stroke.line_dash.segments.is_empty() { -            Cow::Borrowed(path) -        } else { -            Cow::Owned(path::dashed(path, stroke.line_dash)) -        }; - -        if self.transforms.current.is_identity { -            self.stroke_tessellator.tessellate_path( -                path.raw(), -                &options, -                buffer.as_mut(), -            ) -        } else { -            let path = path.transformed(&self.transforms.current.raw); - -            self.stroke_tessellator.tessellate_path( -                path.raw(), -                &options, -                buffer.as_mut(), -            ) -        } -        .expect("Stroke path"); -    } - -    /// Draws the characters of the given [`Text`] on the [`Frame`], filling -    /// them with the given color. -    /// -    /// __Warning:__ Text currently does not work well with rotations and scale -    /// transforms! The position will be correctly transformed, but the -    /// resulting glyphs will not be rotated or scaled properly. -    /// -    /// Additionally, all text will be rendered on top of all the layers of -    /// a [`Canvas`]. Therefore, it is currently only meant to be used for -    /// overlays, which is the most common use case. -    /// -    /// Support for vectorial text is planned, and should address all these -    /// limitations. -    /// -    /// [`Canvas`]: crate::widget::Canvas -    pub fn fill_text(&mut self, text: impl Into<Text>) { -        let text = text.into(); - -        let position = if self.transforms.current.is_identity { -            text.position -        } else { -            let transformed = self.transforms.current.raw.transform_point( -                lyon::math::Point::new(text.position.x, text.position.y), -            ); - -            Point::new(transformed.x, transformed.y) -        }; - -        // TODO: Use vectorial text instead of primitive -        self.primitives.push(Primitive::Text { -            content: text.content, -            bounds: Rectangle { -                x: position.x, -                y: position.y, -                width: f32::INFINITY, -                height: f32::INFINITY, -            }, -            color: text.color, -            size: text.size, -            font: text.font, -            horizontal_alignment: text.horizontal_alignment, -            vertical_alignment: text.vertical_alignment, -        }); -    } - -    /// Stores the current transform of the [`Frame`] and executes the given -    /// drawing operations, restoring the transform afterwards. -    /// -    /// This method is useful to compose transforms and perform drawing -    /// operations in different coordinate systems. -    #[inline] -    pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { -        self.transforms.previous.push(self.transforms.current); - -        f(self); - -        self.transforms.current = self.transforms.previous.pop().unwrap(); -    } - -    /// Executes the given drawing operations within a [`Rectangle`] region, -    /// clipping any geometry that overflows its bounds. Any transformations -    /// performed are local to the provided closure. -    /// -    /// This method is useful to perform drawing operations that need to be -    /// clipped. -    #[inline] -    pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) { -        let mut frame = Frame::new(region.size()); - -        f(&mut frame); - -        let primitives = frame.into_primitives(); - -        let (text, meshes) = primitives -            .into_iter() -            .partition(|primitive| matches!(primitive, Primitive::Text { .. })); - -        let translation = Vector::new(region.x, region.y); - -        self.primitives.push(Primitive::Group { -            primitives: vec![ -                Primitive::Translate { -                    translation, -                    content: Box::new(Primitive::Group { primitives: meshes }), -                }, -                Primitive::Translate { -                    translation, -                    content: Box::new(Primitive::Clip { -                        bounds: Rectangle::with_size(region.size()), -                        content: Box::new(Primitive::Group { -                            primitives: text, -                        }), -                    }), -                }, -            ], -        }); -    } - -    /// Applies a translation to the current transform of the [`Frame`]. -    #[inline] -    pub fn translate(&mut self, translation: Vector) { -        self.transforms.current.raw = self -            .transforms -            .current -            .raw -            .pre_translate(lyon::math::Vector::new( -                translation.x, -                translation.y, -            )); -        self.transforms.current.is_identity = false; -    } - -    /// Applies a rotation in radians to the current transform of the [`Frame`]. -    #[inline] -    pub fn rotate(&mut self, angle: f32) { -        self.transforms.current.raw = self -            .transforms -            .current -            .raw -            .pre_rotate(lyon::math::Angle::radians(angle)); -        self.transforms.current.is_identity = false; -    } - -    /// Applies a scaling to the current transform of the [`Frame`]. -    #[inline] -    pub fn scale(&mut self, scale: f32) { -        self.transforms.current.raw = -            self.transforms.current.raw.pre_scale(scale, scale); -        self.transforms.current.is_identity = false; -    } - -    /// Produces the [`Geometry`] representing everything drawn on the [`Frame`]. -    pub fn into_geometry(self) -> Geometry { -        Geometry::from_primitive(Primitive::Group { -            primitives: self.into_primitives(), -        }) -    } - -    fn into_primitives(mut self) -> Vec<Primitive> { -        for buffer in self.buffers.stack { -            match buffer { -                Buffer::Solid(buffer) => { -                    if !buffer.indices.is_empty() { -                        self.primitives.push(Primitive::SolidMesh { -                            buffers: triangle::Mesh2D { -                                vertices: buffer.vertices, -                                indices: buffer.indices, -                            }, -                            size: self.size, -                        }) -                    } -                } -                Buffer::Gradient(buffer, gradient) => { -                    if !buffer.indices.is_empty() { -                        self.primitives.push(Primitive::GradientMesh { -                            buffers: triangle::Mesh2D { -                                vertices: buffer.vertices, -                                indices: buffer.indices, -                            }, -                            size: self.size, -                            gradient, -                        }) -                    } -                } -            } -        } - -        self.primitives -    } -} - -struct Vertex2DBuilder; - -impl tessellation::FillVertexConstructor<triangle::Vertex2D> -    for Vertex2DBuilder -{ -    fn new_vertex( -        &mut self, -        vertex: tessellation::FillVertex<'_>, -    ) -> triangle::Vertex2D { -        let position = vertex.position(); - -        triangle::Vertex2D { -            position: [position.x, position.y], -        } -    } -} - -impl tessellation::StrokeVertexConstructor<triangle::Vertex2D> -    for Vertex2DBuilder -{ -    fn new_vertex( -        &mut self, -        vertex: tessellation::StrokeVertex<'_, '_>, -    ) -> triangle::Vertex2D { -        let position = vertex.position(); - -        triangle::Vertex2D { -            position: [position.x, position.y], -        } -    } -} - -struct TriangleVertex2DBuilder([f32; 4]); - -impl tessellation::FillVertexConstructor<triangle::ColoredVertex2D> -    for TriangleVertex2DBuilder -{ -    fn new_vertex( -        &mut self, -        vertex: tessellation::FillVertex<'_>, -    ) -> triangle::ColoredVertex2D { -        let position = vertex.position(); - -        triangle::ColoredVertex2D { -            position: [position.x, position.y], -            color: self.0, -        } -    } -} - -impl tessellation::StrokeVertexConstructor<triangle::ColoredVertex2D> -    for TriangleVertex2DBuilder -{ -    fn new_vertex( -        &mut self, -        vertex: tessellation::StrokeVertex<'_, '_>, -    ) -> triangle::ColoredVertex2D { -        let position = vertex.position(); - -        triangle::ColoredVertex2D { -            position: [position.x, position.y], -            color: self.0, -        } -    } -} diff --git a/graphics/src/widget/canvas/geometry.rs b/graphics/src/widget/canvas/geometry.rs deleted file mode 100644 index e8ac621d..00000000 --- a/graphics/src/widget/canvas/geometry.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::Primitive; - -/// A bunch of shapes that can be drawn. -/// -/// [`Geometry`] can be easily generated with a [`Frame`] or stored in a -/// [`Cache`]. -/// -/// [`Frame`]: crate::widget::canvas::Frame -/// [`Cache`]: crate::widget::canvas::Cache -#[derive(Debug, Clone)] -pub struct Geometry(Primitive); - -impl Geometry { -    pub(crate) fn from_primitive(primitive: Primitive) -> Self { -        Self(primitive) -    } - -    /// Turns the [`Geometry`] into a [`Primitive`]. -    /// -    /// This can be useful if you are building a custom widget. -    pub fn into_primitive(self) -> Primitive { -        self.0 -    } -} diff --git a/graphics/src/widget/canvas/path.rs b/graphics/src/widget/canvas/path.rs deleted file mode 100644 index aeb2589e..00000000 --- a/graphics/src/widget/canvas/path.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Build different kinds of 2D shapes. -pub mod arc; - -mod builder; - -#[doc(no_inline)] -pub use arc::Arc; -pub use builder::Builder; - -use crate::widget::canvas::LineDash; - -use iced_native::{Point, Size}; -use lyon::algorithms::walk::{walk_along_path, RepeatedPattern, WalkerEvent}; -use lyon::path::iterator::PathIterator; - -/// An immutable set of points that may or may not be connected. -/// -/// A single [`Path`] can represent different kinds of 2D shapes! -#[derive(Debug, Clone)] -pub struct Path { -    raw: lyon::path::Path, -} - -impl Path { -    /// Creates a new [`Path`] with the provided closure. -    /// -    /// Use the [`Builder`] to configure your [`Path`]. -    pub fn new(f: impl FnOnce(&mut Builder)) -> Self { -        let mut builder = Builder::new(); - -        // TODO: Make it pure instead of side-effect-based (?) -        f(&mut builder); - -        builder.build() -    } - -    /// Creates a new [`Path`] representing a line segment given its starting -    /// and end points. -    pub fn line(from: Point, to: Point) -> Self { -        Self::new(|p| { -            p.move_to(from); -            p.line_to(to); -        }) -    } - -    /// Creates a new [`Path`] representing a rectangle given its top-left -    /// corner coordinate and its `Size`. -    pub fn rectangle(top_left: Point, size: Size) -> Self { -        Self::new(|p| p.rectangle(top_left, size)) -    } - -    /// Creates a new [`Path`] representing a circle given its center -    /// coordinate and its radius. -    pub fn circle(center: Point, radius: f32) -> Self { -        Self::new(|p| p.circle(center, radius)) -    } - -    #[inline] -    pub(crate) fn raw(&self) -> &lyon::path::Path { -        &self.raw -    } - -    #[inline] -    pub(crate) fn transformed( -        &self, -        transform: &lyon::math::Transform, -    ) -> Path { -        Path { -            raw: self.raw.clone().transformed(transform), -        } -    } -} - -pub(super) fn dashed(path: &Path, line_dash: LineDash<'_>) -> Path { -    Path::new(|builder| { -        let segments_odd = (line_dash.segments.len() % 2 == 1) -            .then(|| [line_dash.segments, line_dash.segments].concat()); - -        let mut draw_line = false; - -        walk_along_path( -            path.raw().iter().flattened(0.01), -            0.0, -            lyon::tessellation::StrokeOptions::DEFAULT_TOLERANCE, -            &mut RepeatedPattern { -                callback: |event: WalkerEvent<'_>| { -                    let point = Point { -                        x: event.position.x, -                        y: event.position.y, -                    }; - -                    if draw_line { -                        builder.line_to(point); -                    } else { -                        builder.move_to(point); -                    } - -                    draw_line = !draw_line; - -                    true -                }, -                index: line_dash.offset, -                intervals: segments_odd -                    .as_deref() -                    .unwrap_or(line_dash.segments), -            }, -        ); -    }) -} diff --git a/graphics/src/widget/canvas/path/arc.rs b/graphics/src/widget/canvas/path/arc.rs deleted file mode 100644 index b8e72daf..00000000 --- a/graphics/src/widget/canvas/path/arc.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Build and draw curves. -use iced_native::{Point, Vector}; - -/// A segment of a differentiable curve. -#[derive(Debug, Clone, Copy)] -pub struct Arc { -    /// The center of the arc. -    pub center: Point, -    /// The radius of the arc. -    pub radius: f32, -    /// The start of the segment's angle, clockwise rotation. -    pub start_angle: f32, -    /// The end of the segment's angle, clockwise rotation. -    pub end_angle: f32, -} - -/// An elliptical [`Arc`]. -#[derive(Debug, Clone, Copy)] -pub struct Elliptical { -    /// The center of the arc. -    pub center: Point, -    /// The radii of the arc's ellipse, defining its axes. -    pub radii: Vector, -    /// The rotation of the arc's ellipse. -    pub rotation: f32, -    /// The start of the segment's angle, clockwise rotation. -    pub start_angle: f32, -    /// The end of the segment's angle, clockwise rotation. -    pub end_angle: f32, -} - -impl From<Arc> for Elliptical { -    fn from(arc: Arc) -> Elliptical { -        Elliptical { -            center: arc.center, -            radii: Vector::new(arc.radius, arc.radius), -            rotation: 0.0, -            start_angle: arc.start_angle, -            end_angle: arc.end_angle, -        } -    } -} diff --git a/graphics/src/widget/canvas/path/builder.rs b/graphics/src/widget/canvas/path/builder.rs deleted file mode 100644 index 5121aa68..00000000 --- a/graphics/src/widget/canvas/path/builder.rs +++ /dev/null @@ -1,198 +0,0 @@ -use crate::widget::canvas::path::{arc, Arc, Path}; - -use iced_native::{Point, Size}; -use lyon::path::builder::SvgPathBuilder; - -/// A [`Path`] builder. -/// -/// Once a [`Path`] is built, it can no longer be mutated. -#[allow(missing_debug_implementations)] -pub struct Builder { -    raw: lyon::path::builder::WithSvg<lyon::path::path::BuilderImpl>, -} - -impl Builder { -    /// Creates a new [`Builder`]. -    pub fn new() -> Builder { -        Builder { -            raw: lyon::path::Path::builder().with_svg(), -        } -    } - -    /// Moves the starting point of a new sub-path to the given `Point`. -    #[inline] -    pub fn move_to(&mut self, point: Point) { -        let _ = self.raw.move_to(lyon::math::Point::new(point.x, point.y)); -    } - -    /// Connects the last point in the [`Path`] to the given `Point` with a -    /// straight line. -    #[inline] -    pub fn line_to(&mut self, point: Point) { -        let _ = self.raw.line_to(lyon::math::Point::new(point.x, point.y)); -    } - -    /// Adds an [`Arc`] to the [`Path`] from `start_angle` to `end_angle` in -    /// a clockwise direction. -    #[inline] -    pub fn arc(&mut self, arc: Arc) { -        self.ellipse(arc.into()); -    } - -    /// Adds a circular arc to the [`Path`] with the given control points and -    /// radius. -    /// -    /// This essentially draws a straight line segment from the current -    /// position to `a`, but fits a circular arc of `radius` tangent to that -    /// segment and tangent to the line between `a` and `b`. -    /// -    /// With another `.line_to(b)`, the result will be a path connecting the -    /// starting point and `b` with straight line segments towards `a` and a -    /// circular arc smoothing out the corner at `a`. -    /// -    /// See [the HTML5 specification of `arcTo`](https://html.spec.whatwg.org/multipage/canvas.html#building-paths:dom-context-2d-arcto) -    /// for more details and examples. -    pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) { -        use lyon::{math, path}; - -        let start = self.raw.current_position(); -        let mid = math::Point::new(a.x, a.y); -        let end = math::Point::new(b.x, b.y); - -        if start == mid || mid == end || radius == 0.0 { -            let _ = self.raw.line_to(mid); -            return; -        } - -        let double_area = start.x * (mid.y - end.y) -            + mid.x * (end.y - start.y) -            + end.x * (start.y - mid.y); - -        if double_area == 0.0 { -            let _ = self.raw.line_to(mid); -            return; -        } - -        let to_start = (start - mid).normalize(); -        let to_end = (end - mid).normalize(); - -        let inner_angle = to_start.dot(to_end).acos(); - -        let origin_angle = inner_angle / 2.0; - -        let origin_adjacent = radius / origin_angle.tan(); - -        let arc_start = mid + to_start * origin_adjacent; -        let arc_end = mid + to_end * origin_adjacent; - -        let sweep = to_start.cross(to_end) < 0.0; - -        let _ = self.raw.line_to(arc_start); - -        self.raw.arc_to( -            math::Vector::new(radius, radius), -            math::Angle::radians(0.0), -            path::ArcFlags { -                large_arc: false, -                sweep, -            }, -            arc_end, -        ); -    } - -    /// Adds an ellipse to the [`Path`] using a clockwise direction. -    pub fn ellipse(&mut self, arc: arc::Elliptical) { -        use lyon::{geom, math}; - -        let arc = geom::Arc { -            center: math::Point::new(arc.center.x, arc.center.y), -            radii: math::Vector::new(arc.radii.x, arc.radii.y), -            x_rotation: math::Angle::radians(arc.rotation), -            start_angle: math::Angle::radians(arc.start_angle), -            sweep_angle: math::Angle::radians(arc.end_angle - arc.start_angle), -        }; - -        let _ = self.raw.move_to(arc.sample(0.0)); - -        arc.for_each_quadratic_bezier(&mut |curve| { -            let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to); -        }); -    } - -    /// Adds a cubic Bézier curve to the [`Path`] given its two control points -    /// and its end point. -    #[inline] -    pub fn bezier_curve_to( -        &mut self, -        control_a: Point, -        control_b: Point, -        to: Point, -    ) { -        use lyon::math; - -        let _ = self.raw.cubic_bezier_to( -            math::Point::new(control_a.x, control_a.y), -            math::Point::new(control_b.x, control_b.y), -            math::Point::new(to.x, to.y), -        ); -    } - -    /// Adds a quadratic Bézier curve to the [`Path`] given its control point -    /// and its end point. -    #[inline] -    pub fn quadratic_curve_to(&mut self, control: Point, to: Point) { -        use lyon::math; - -        let _ = self.raw.quadratic_bezier_to( -            math::Point::new(control.x, control.y), -            math::Point::new(to.x, to.y), -        ); -    } - -    /// Adds a rectangle to the [`Path`] given its top-left corner coordinate -    /// and its `Size`. -    #[inline] -    pub fn rectangle(&mut self, top_left: Point, size: Size) { -        self.move_to(top_left); -        self.line_to(Point::new(top_left.x + size.width, top_left.y)); -        self.line_to(Point::new( -            top_left.x + size.width, -            top_left.y + size.height, -        )); -        self.line_to(Point::new(top_left.x, top_left.y + size.height)); -        self.close(); -    } - -    /// Adds a circle to the [`Path`] given its center coordinate and its -    /// radius. -    #[inline] -    pub fn circle(&mut self, center: Point, radius: f32) { -        self.arc(Arc { -            center, -            radius, -            start_angle: 0.0, -            end_angle: 2.0 * std::f32::consts::PI, -        }); -    } - -    /// Closes the current sub-path in the [`Path`] with a straight line to -    /// the starting point. -    #[inline] -    pub fn close(&mut self) { -        self.raw.close() -    } - -    /// Builds the [`Path`] of this [`Builder`]. -    #[inline] -    pub fn build(self) -> Path { -        Path { -            raw: self.raw.build(), -        } -    } -} - -impl Default for Builder { -    fn default() -> Self { -        Self::new() -    } -} diff --git a/graphics/src/widget/canvas/program.rs b/graphics/src/widget/canvas/program.rs deleted file mode 100644 index 656dbfa6..00000000 --- a/graphics/src/widget/canvas/program.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::widget::canvas::event::{self, Event}; -use crate::widget::canvas::mouse; -use crate::widget::canvas::{Cursor, Geometry}; -use crate::Rectangle; - -/// The state and logic of a [`Canvas`]. -/// -/// A [`Program`] can mutate internal state and produce messages for an -/// application. -/// -/// [`Canvas`]: crate::widget::Canvas -pub trait Program<Message, Theme = iced_native::Theme> { -    /// The internal state mutated by the [`Program`]. -    type State: Default + 'static; - -    /// Updates the [`State`](Self::State) of the [`Program`]. -    /// -    /// When a [`Program`] is used in a [`Canvas`], the runtime will call this -    /// method for each [`Event`]. -    /// -    /// This method can optionally return a `Message` to notify an application -    /// of any meaningful interactions. -    /// -    /// By default, this method does and returns nothing. -    /// -    /// [`Canvas`]: crate::widget::Canvas -    fn update( -        &self, -        _state: &mut Self::State, -        _event: Event, -        _bounds: Rectangle, -        _cursor: Cursor, -    ) -> (event::Status, Option<Message>) { -        (event::Status::Ignored, None) -    } - -    /// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. -    /// -    /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a -    /// [`Cache`]. -    /// -    /// [`Frame`]: crate::widget::canvas::Frame -    /// [`Cache`]: crate::widget::canvas::Cache -    fn draw( -        &self, -        state: &Self::State, -        theme: &Theme, -        bounds: Rectangle, -        cursor: Cursor, -    ) -> Vec<Geometry>; - -    /// Returns the current mouse interaction of the [`Program`]. -    /// -    /// The interaction returned will be in effect even if the cursor position -    /// is out of bounds of the program's [`Canvas`]. -    /// -    /// [`Canvas`]: crate::widget::Canvas -    fn mouse_interaction( -        &self, -        _state: &Self::State, -        _bounds: Rectangle, -        _cursor: Cursor, -    ) -> mouse::Interaction { -        mouse::Interaction::default() -    } -} - -impl<Message, Theme, T> Program<Message, Theme> for &T -where -    T: Program<Message, Theme>, -{ -    type State = T::State; - -    fn update( -        &self, -        state: &mut Self::State, -        event: Event, -        bounds: Rectangle, -        cursor: Cursor, -    ) -> (event::Status, Option<Message>) { -        T::update(self, state, event, bounds, cursor) -    } - -    fn draw( -        &self, -        state: &Self::State, -        theme: &Theme, -        bounds: Rectangle, -        cursor: Cursor, -    ) -> Vec<Geometry> { -        T::draw(self, state, theme, bounds, cursor) -    } - -    fn mouse_interaction( -        &self, -        state: &Self::State, -        bounds: Rectangle, -        cursor: Cursor, -    ) -> mouse::Interaction { -        T::mouse_interaction(self, state, bounds, cursor) -    } -} diff --git a/graphics/src/widget/canvas/stroke.rs b/graphics/src/widget/canvas/stroke.rs deleted file mode 100644 index 4c19251d..00000000 --- a/graphics/src/widget/canvas/stroke.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! Create lines from a [crate::widget::canvas::Path] and assigns them various attributes/styles. -pub use crate::widget::canvas::Style; - -use iced_native::Color; - -/// The style of a stroke. -#[derive(Debug, Clone)] -pub struct Stroke<'a> { -    /// The color or gradient of the stroke. -    /// -    /// By default, it is set to a [`Style::Solid`] with [`Color::BLACK`]. -    pub style: Style, -    /// The distance between the two edges of the stroke. -    pub width: f32, -    /// The shape to be used at the end of open subpaths when they are stroked. -    pub line_cap: LineCap, -    /// The shape to be used at the corners of paths or basic shapes when they -    /// are stroked. -    pub line_join: LineJoin, -    /// The dash pattern used when stroking the line. -    pub line_dash: LineDash<'a>, -} - -impl<'a> Stroke<'a> { -    /// Sets the color of the [`Stroke`]. -    pub fn with_color(self, color: Color) -> Self { -        Stroke { -            style: Style::Solid(color), -            ..self -        } -    } - -    /// Sets the width of the [`Stroke`]. -    pub fn with_width(self, width: f32) -> Self { -        Stroke { width, ..self } -    } - -    /// Sets the [`LineCap`] of the [`Stroke`]. -    pub fn with_line_cap(self, line_cap: LineCap) -> Self { -        Stroke { line_cap, ..self } -    } - -    /// Sets the [`LineJoin`] of the [`Stroke`]. -    pub fn with_line_join(self, line_join: LineJoin) -> Self { -        Stroke { line_join, ..self } -    } -} - -impl<'a> Default for Stroke<'a> { -    fn default() -> Self { -        Stroke { -            style: Style::Solid(Color::BLACK), -            width: 1.0, -            line_cap: LineCap::default(), -            line_join: LineJoin::default(), -            line_dash: LineDash::default(), -        } -    } -} - -/// The shape used at the end of open subpaths when they are stroked. -#[derive(Debug, Clone, Copy)] -pub enum LineCap { -    /// The stroke for each sub-path does not extend beyond its two endpoints. -    Butt, -    /// At the end of each sub-path, the shape representing the stroke will be -    /// extended by a square. -    Square, -    /// At the end of each sub-path, the shape representing the stroke will be -    /// extended by a semicircle. -    Round, -} - -impl Default for LineCap { -    fn default() -> LineCap { -        LineCap::Butt -    } -} - -impl From<LineCap> for lyon::tessellation::LineCap { -    fn from(line_cap: LineCap) -> lyon::tessellation::LineCap { -        match line_cap { -            LineCap::Butt => lyon::tessellation::LineCap::Butt, -            LineCap::Square => lyon::tessellation::LineCap::Square, -            LineCap::Round => lyon::tessellation::LineCap::Round, -        } -    } -} - -/// The shape used at the corners of paths or basic shapes when they are -/// stroked. -#[derive(Debug, Clone, Copy)] -pub enum LineJoin { -    /// A sharp corner. -    Miter, -    /// A round corner. -    Round, -    /// A bevelled corner. -    Bevel, -} - -impl Default for LineJoin { -    fn default() -> LineJoin { -        LineJoin::Miter -    } -} - -impl From<LineJoin> for lyon::tessellation::LineJoin { -    fn from(line_join: LineJoin) -> lyon::tessellation::LineJoin { -        match line_join { -            LineJoin::Miter => lyon::tessellation::LineJoin::Miter, -            LineJoin::Round => lyon::tessellation::LineJoin::Round, -            LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel, -        } -    } -} - -/// The dash pattern used when stroking the line. -#[derive(Debug, Clone, Copy, Default)] -pub struct LineDash<'a> { -    /// The alternating lengths of lines and gaps which describe the pattern. -    pub segments: &'a [f32], - -    /// The offset of [`LineDash::segments`] to start the pattern. -    pub offset: usize, -} diff --git a/graphics/src/widget/canvas/style.rs b/graphics/src/widget/canvas/style.rs deleted file mode 100644 index 6794f2e7..00000000 --- a/graphics/src/widget/canvas/style.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{Color, Gradient}; - -/// The coloring style of some drawing. -#[derive(Debug, Clone, PartialEq)] -pub enum Style { -    /// A solid [`Color`]. -    Solid(Color), - -    /// A [`Gradient`] color. -    Gradient(Gradient), -} - -impl From<Color> for Style { -    fn from(color: Color) -> Self { -        Self::Solid(color) -    } -} - -impl From<Gradient> for Style { -    fn from(gradient: Gradient) -> Self { -        Self::Gradient(gradient) -    } -} diff --git a/graphics/src/widget/canvas/text.rs b/graphics/src/widget/canvas/text.rs deleted file mode 100644 index 056f8204..00000000 --- a/graphics/src/widget/canvas/text.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::alignment; -use crate::{Color, Font, Point}; - -/// A bunch of text that can be drawn to a canvas -#[derive(Debug, Clone)] -pub struct Text { -    /// The contents of the text -    pub content: String, -    /// The position of the text relative to the alignment properties. -    /// By default, this position will be relative to the top-left corner coordinate meaning that -    /// if the horizontal and vertical alignments are unchanged, this property will tell where the -    /// top-left corner of the text should be placed. -    /// By changing the horizontal_alignment and vertical_alignment properties, you are are able to -    /// change what part of text is placed at this positions. -    /// For example, when the horizontal_alignment and vertical_alignment are set to Center, the -    /// center of the text will be placed at the given position NOT the top-left coordinate. -    pub position: Point, -    /// The color of the text -    pub color: Color, -    /// The size of the text -    pub size: f32, -    /// The font of the text -    pub font: Font, -    /// The horizontal alignment of the text -    pub horizontal_alignment: alignment::Horizontal, -    /// The vertical alignment of the text -    pub vertical_alignment: alignment::Vertical, -} - -impl Default for Text { -    fn default() -> Text { -        Text { -            content: String::new(), -            position: Point::ORIGIN, -            color: Color::BLACK, -            size: 16.0, -            font: Font::Default, -            horizontal_alignment: alignment::Horizontal::Left, -            vertical_alignment: alignment::Vertical::Top, -        } -    } -} - -impl From<String> for Text { -    fn from(content: String) -> Text { -        Text { -            content, -            ..Default::default() -        } -    } -} - -impl From<&str> for Text { -    fn from(content: &str) -> Text { -        String::from(content).into() -    } -} | 
