summaryrefslogtreecommitdiffstats
path: root/graphics/src/widget/canvas/stroke.rs
blob: 2f02a2f396ccdb79d5fc1a148be2b6b224328d7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Create lines from a [crate::widget::canvas::Path] and assigns them various attributes/styles.

use crate::gradient::Gradient;
use crate::layer::mesh;
use crate::widget::canvas::frame::Transform;
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 [`StrokeStyle::Solid`] `BLACK`.
    pub style: Style<'a>,
    /// 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 style of a [`Stroke`].
#[derive(Debug, Clone, Copy)]
pub enum Style<'a> {
    /// A solid color
    Solid(Color),
    /// A color gradient
    Gradient(&'a Gradient),
}

impl<'a> Style<'a> {
    /// Converts a fill's [Style] to a [mesh::Style] for use in the renderer's shader.
    pub(crate) fn as_mesh_style(&self, transform: &Transform) -> mesh::Style {
        match self {
            Style::Solid(color) => mesh::Style::Solid(*color),
            Style::Gradient(gradient) => mesh::Style::Gradient(
                transform.transform_gradient((*gradient).clone()),
            ),
        }
    }
}

/// 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,
}