conrod_core/widget/primitive/shape/
polygon.rs1use super::Style;
4use graph;
5use utils::{bounding_box_for_points, vec2_add, vec2_sub};
6use widget;
7use widget::triangles::Triangle;
8use {Color, Colorable, Point, Positionable, Sizeable, Theme, Widget};
9
10#[derive(Copy, Clone, Debug, WidgetCommon_)]
17pub struct Polygon<I> {
18 #[conrod(common_builder)]
20 pub common: widget::CommonBuilder,
21 pub points: I,
23 pub style: Style,
25 pub maybe_shift_to_centre_from: Option<Point>,
27}
28
29#[derive(Clone, Debug, PartialEq)]
31pub struct State {
32 kind: Kind,
34 pub points: Vec<Point>,
36}
37
38#[derive(Copy, Clone, Debug, PartialEq)]
40pub enum Kind {
41 Outline,
43 Fill,
45}
46
47#[derive(Clone)]
50pub struct Triangles<I> {
51 first: Point,
52 prev: Point,
53 points: I,
54}
55
56impl<I> Polygon<I> {
57 pub fn styled(points: I, style: Style) -> Self {
59 Polygon {
60 points: points,
61 common: widget::CommonBuilder::default(),
62 style: style,
63 maybe_shift_to_centre_from: None,
64 }
65 }
66
67 pub fn fill(points: I) -> Self {
69 Polygon::styled(points, Style::fill())
70 }
71
72 pub fn fill_with(points: I, color: Color) -> Self {
74 Polygon::styled(points, Style::fill_with(color))
75 }
76
77 pub fn outline(points: I) -> Self {
79 Polygon::styled(points, Style::outline())
80 }
81
82 pub fn outline_styled(points: I, style: widget::line::Style) -> Self {
84 Polygon::styled(points, Style::outline_styled(style))
85 }
86
87 pub fn abs_styled(points: I, style: Style) -> Self
96 where
97 I: IntoIterator<Item = Point> + Clone,
98 {
99 let points_clone = points.clone().into_iter();
100 let (xy, dim) = bounding_box_for_points(points_clone).xy_dim();
101 Polygon::styled(points, style).wh(dim).xy(xy)
102 }
103
104 pub fn abs_fill(points: I) -> Self
107 where
108 I: IntoIterator<Item = Point> + Clone,
109 {
110 Polygon::abs_styled(points, Style::fill())
111 }
112
113 pub fn abs_fill_with(points: I, color: Color) -> Self
116 where
117 I: IntoIterator<Item = Point> + Clone,
118 {
119 Polygon::abs_styled(points, Style::fill_with(color))
120 }
121
122 pub fn abs_outline(points: I) -> Self
125 where
126 I: IntoIterator<Item = Point> + Clone,
127 {
128 Polygon::abs_styled(points, Style::outline())
129 }
130
131 pub fn abs_outline_styled(points: I, style: widget::line::Style) -> Self
134 where
135 I: IntoIterator<Item = Point> + Clone,
136 {
137 Polygon::abs_styled(points, Style::outline_styled(style))
138 }
139
140 pub fn centred_styled(points: I, style: Style) -> Self
149 where
150 I: IntoIterator<Item = Point> + Clone,
151 {
152 let points_clone = points.clone().into_iter();
153 let (xy, dim) = bounding_box_for_points(points_clone).xy_dim();
154 let mut polygon = Polygon::styled(points, style).wh(dim);
155 polygon.maybe_shift_to_centre_from = Some(xy);
156 polygon
157 }
158
159 pub fn centred_fill(points: I) -> Self
162 where
163 I: IntoIterator<Item = Point> + Clone,
164 {
165 Polygon::centred_styled(points, Style::fill())
166 }
167
168 pub fn centred_fill_with(points: I, color: Color) -> Self
171 where
172 I: IntoIterator<Item = Point> + Clone,
173 {
174 Polygon::centred_styled(points, Style::fill_with(color))
175 }
176
177 pub fn centred_outline(points: I) -> Self
180 where
181 I: IntoIterator<Item = Point> + Clone,
182 {
183 Polygon::centred_styled(points, Style::outline())
184 }
185
186 pub fn centred_outline_styled(points: I, style: widget::line::Style) -> Self
189 where
190 I: IntoIterator<Item = Point> + Clone,
191 {
192 Polygon::centred_styled(points, Style::outline_styled(style))
193 }
194}
195
196impl<I> Widget for Polygon<I>
197where
198 I: IntoIterator<Item = Point>,
199{
200 type State = State;
201 type Style = Style;
202 type Event = ();
203
204 fn init_state(&self, _: widget::id::Generator) -> Self::State {
205 State {
206 kind: Kind::Fill,
207 points: Vec::new(),
208 }
209 }
210
211 fn style(&self) -> Self::Style {
212 self.style.clone()
213 }
214
215 fn is_over(&self) -> widget::IsOverFn {
216 is_over_widget
217 }
218
219 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
221 use utils::{iter_diff, IterDiff};
222 let widget::UpdateArgs {
223 rect, state, style, ..
224 } = args;
225 let Polygon {
226 points,
227 maybe_shift_to_centre_from,
228 ..
229 } = self;
230
231 fn update_points<I>(state: &mut widget::State<State>, points: I)
234 where
235 I: IntoIterator<Item = Point>,
236 {
237 match iter_diff(&state.points, points) {
238 Some(IterDiff::FirstMismatch(i, mismatch)) => state.update(|state| {
239 state.points.truncate(i);
240 state.points.extend(mismatch);
241 }),
242 Some(IterDiff::Longer(remaining)) => {
243 state.update(|state| state.points.extend(remaining))
244 }
245 Some(IterDiff::Shorter(total)) => {
246 state.update(|state| state.points.truncate(total))
247 }
248 None => (),
249 }
250 }
251
252 match maybe_shift_to_centre_from {
254 Some(original) => {
255 let xy = rect.xy();
256 let difference = vec2_sub(xy, original);
257 update_points(
258 state,
259 points.into_iter().map(|point| vec2_add(point, difference)),
260 )
261 }
262 None => update_points(state, points),
263 }
264
265 let kind = match *style {
266 Style::Fill(_) => Kind::Fill,
267 Style::Outline(_) => Kind::Outline,
268 };
269
270 if state.kind != kind {
271 state.update(|state| state.kind = kind);
272 }
273 }
274}
275
276impl<I> Colorable for Polygon<I> {
277 fn color(mut self, color: Color) -> Self {
278 self.style.set_color(color);
279 self
280 }
281}
282
283pub fn triangles<I>(points: I) -> Option<Triangles<I::IntoIter>>
287where
288 I: IntoIterator<Item = Point>,
289{
290 let mut points = points.into_iter();
291 let first = match points.next() {
292 Some(p) => p,
293 None => return None,
294 };
295 let prev = match points.next() {
296 Some(p) => p,
297 None => return None,
298 };
299 Some(Triangles {
300 first: first,
301 prev: prev,
302 points: points,
303 })
304}
305
306impl<I> Iterator for Triangles<I>
307where
308 I: Iterator<Item = Point>,
309{
310 type Item = Triangle<Point>;
311 fn next(&mut self) -> Option<Self::Item> {
312 self.points.next().map(|point| {
313 let t = Triangle([self.first, self.prev, point]);
314 self.prev = point;
315 t
316 })
317 }
318}
319
320pub fn is_over<I>(points: I, point: Point) -> bool
323where
324 I: IntoIterator<Item = Point>,
325{
326 triangles(points)
327 .map(|ts| widget::triangles::is_over(ts, point))
328 .unwrap_or(false)
329}
330
331pub fn is_over_widget(widget: &graph::Container, point: Point, _: &Theme) -> widget::IsOver {
333 widget
334 .state_and_style::<State, Style>()
335 .map(|widget| is_over(widget.state.points.iter().cloned(), point))
336 .unwrap_or_else(|| widget.rect.is_over(point))
337 .into()
338}