1use color;
4use graph;
5use std;
6use utils::{vec2_add, vec2_sub};
7use widget;
8use {Point, Positionable, Rect, Scalar, Sizeable, Theme, Widget};
9
10#[derive(Copy, Clone, Debug, WidgetCommon_)]
12pub struct Triangles<S, I> {
13 #[conrod(common_builder)]
15 pub common: widget::CommonBuilder,
16 pub style: S,
18 pub triangles: I,
20 pub maybe_shift_to_centre_from: Option<Point>,
22}
23
24pub trait Vertex: Clone + Copy + PartialEq {
26 fn point(&self) -> Point;
28 fn add(self, p: Point) -> Self;
30}
31
32pub trait Style: widget::Style + Clone + Send {
34 type Vertex: Vertex + Send;
36}
37
38#[derive(Copy, Clone, Debug, PartialEq)]
40pub struct SingleColor(pub color::Rgba);
41
42#[derive(Copy, Clone, Debug, PartialEq)]
44pub struct MultiColor;
45
46#[derive(Copy, Clone, Debug, PartialEq)]
48pub struct Triangle<V>(pub [V; 3])
49where
50 V: Vertex;
51
52pub type ColoredPoint = (Point, color::Rgba);
54
55#[derive(Clone, Debug, PartialEq)]
57pub struct State<T> {
58 pub triangles: T,
60}
61
62impl Vertex for Point {
63 fn point(&self) -> Point {
64 *self
65 }
66 fn add(self, add: Point) -> Self {
67 vec2_add(self, add)
68 }
69}
70
71impl Vertex for ColoredPoint {
72 fn point(&self) -> Point {
73 self.0
74 }
75 fn add(self, add: Point) -> Self {
76 let (p, c) = self;
77 (vec2_add(p, add), c)
78 }
79}
80
81impl Style for SingleColor {
82 type Vertex = Point;
83}
84
85impl Style for MultiColor {
86 type Vertex = ColoredPoint;
87}
88
89#[derive(Copy, Clone, Debug)]
94pub struct TrianglesUnpositioned<S, I> {
95 triangles: Triangles<S, I>,
96}
97
98impl<V> Triangle<V>
99where
100 V: Vertex,
101{
102 pub fn add(self, amount: Point) -> Self {
104 let a = self[0].add(amount);
105 let b = self[1].add(amount);
106 let c = self[2].add(amount);
107 Triangle([a, b, c])
108 }
109
110 pub fn points(self) -> [Point; 3] {
112 [self[0].point(), self[1].point(), self[2].point()]
113 }
114}
115
116impl Triangle<Point> {
117 pub fn color(self, a: color::Rgba, b: color::Rgba, c: color::Rgba) -> Triangle<ColoredPoint> {
119 Triangle([(self[0], a), (self[1], b), (self[2], c)])
120 }
121
122 pub fn color_all(self, color: color::Rgba) -> Triangle<ColoredPoint> {
124 Triangle([(self[0], color), (self[1], color), (self[2], color)])
125 }
126}
127
128impl<V> std::ops::Deref for Triangle<V>
129where
130 V: Vertex,
131{
132 type Target = [V; 3];
133 fn deref(&self) -> &Self::Target {
134 &self.0
135 }
136}
137
138impl<V> From<[V; 3]> for Triangle<V>
139where
140 V: Vertex,
141{
142 fn from(points: [V; 3]) -> Self {
143 Triangle(points)
144 }
145}
146
147impl<V> From<(V, V, V)> for Triangle<V>
148where
149 V: Vertex,
150{
151 fn from((a, b, c): (V, V, V)) -> Self {
152 Triangle([a, b, c])
153 }
154}
155
156impl<V> Into<[V; 3]> for Triangle<V>
157where
158 V: Vertex,
159{
160 fn into(self) -> [V; 3] {
161 self.0
162 }
163}
164
165impl<V> Into<(V, V, V)> for Triangle<V>
166where
167 V: Vertex,
168{
169 fn into(self) -> (V, V, V) {
170 (self[0], self[1], self[2])
171 }
172}
173
174impl<S, I> Triangles<S, I> {
175 fn new(style: S, triangles: I) -> Self {
176 Triangles {
177 common: widget::CommonBuilder::default(),
178 style: style,
179 triangles: triangles,
180 maybe_shift_to_centre_from: None,
181 }
182 }
183}
184
185impl<I> Triangles<SingleColor, I>
186where
187 I: IntoIterator<Item = Triangle<<SingleColor as Style>::Vertex>>,
188{
189 pub fn single_color<C>(color: C, points: I) -> TrianglesUnpositioned<SingleColor, I>
193 where
194 C: Into<color::Rgba>,
195 {
196 let style = SingleColor(color.into());
197 TrianglesUnpositioned::new(Triangles::new(style, points))
198 }
199}
200
201impl<I> Triangles<MultiColor, I>
202where
203 I: IntoIterator<Item = Triangle<<MultiColor as Style>::Vertex>>,
204{
205 pub fn multi_color(points: I) -> TrianglesUnpositioned<MultiColor, I> {
209 TrianglesUnpositioned::new(Triangles::new(MultiColor, points))
210 }
211}
212
213fn bounding_rect_for_triangles<I, V>(triangles: I) -> Rect
214where
215 I: IntoIterator<Item = Triangle<V>>,
216 V: Vertex,
217{
218 struct TriangleVertices<V>
219 where
220 V: Vertex,
221 {
222 index: usize,
223 triangle: Triangle<V>,
224 }
225
226 impl<V> Iterator for TriangleVertices<V>
227 where
228 V: Vertex,
229 {
230 type Item = V;
231 fn next(&mut self) -> Option<Self::Item> {
232 let v = self.triangle.get(self.index).map(|&v| v);
233 self.index += 1;
234 v
235 }
236 }
237
238 let points = triangles.into_iter().flat_map(|t| {
239 let vs = TriangleVertices {
240 index: 0,
241 triangle: t,
242 };
243 vs.map(|v| v.point())
244 });
245 super::super::bounding_box_for_points(points)
246}
247
248impl<S, I> TrianglesUnpositioned<S, I>
249where
250 S: Style,
251 I: IntoIterator<Item = Triangle<S::Vertex>>,
252 Triangles<S, I>: Widget,
253{
254 fn new(triangles: Triangles<S, I>) -> Self {
255 TrianglesUnpositioned {
256 triangles: triangles,
257 }
258 }
259
260 pub fn with_bounding_rect(self, rect: Rect) -> Triangles<S, I> {
269 let TrianglesUnpositioned { triangles } = self;
270 let (xy, dim) = rect.xy_dim();
271 triangles.wh(dim).xy(xy)
272 }
273
274 pub fn calc_bounding_rect(self) -> Triangles<S, I>
289 where
290 I: Clone,
291 {
292 let TrianglesUnpositioned { triangles } = self;
293 let (xy, dim) = bounding_rect_for_triangles(triangles.triangles.clone()).xy_dim();
294 triangles.wh(dim).xy(xy)
295 }
296
297 pub fn centre_points_to_bounding_rect(self) -> Triangles<S, I>
312 where
313 I: Clone,
314 {
315 let TrianglesUnpositioned { mut triangles } = self;
316 let (xy, dim) = bounding_rect_for_triangles(triangles.triangles.clone()).xy_dim();
317 triangles.maybe_shift_to_centre_from = Some(xy);
318 triangles.wh(dim)
319 }
320}
321
322impl<S, I> Widget for Triangles<S, I>
323where
324 S: Style,
325 I: IntoIterator<Item = Triangle<S::Vertex>>,
326{
327 type State = State<Vec<Triangle<S::Vertex>>>;
328 type Style = S;
329 type Event = ();
330
331 fn init_state(&self, _: widget::id::Generator) -> Self::State {
332 State {
333 triangles: Vec::new(),
334 }
335 }
336
337 fn style(&self) -> Self::Style {
338 self.style.clone()
339 }
340
341 fn is_over(&self) -> widget::IsOverFn {
342 is_over_widget::<S>
343 }
344
345 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
346 use utils::{iter_diff, IterDiff};
347 let widget::UpdateArgs { rect, state, .. } = args;
348 let Triangles {
349 triangles,
350 maybe_shift_to_centre_from,
351 ..
352 } = self;
353
354 fn update_triangles<I>(state: &mut widget::State<State<Vec<I::Item>>>, triangles: I)
357 where
358 I: IntoIterator,
359 I::Item: PartialEq,
360 {
361 match iter_diff(&state.triangles, triangles) {
362 Some(IterDiff::FirstMismatch(i, mismatch)) => state.update(|state| {
363 state.triangles.truncate(i);
364 state.triangles.extend(mismatch);
365 }),
366 Some(IterDiff::Longer(remaining)) => {
367 state.update(|state| state.triangles.extend(remaining))
368 }
369 Some(IterDiff::Shorter(total)) => {
370 state.update(|state| state.triangles.truncate(total))
371 }
372 None => (),
373 }
374 }
375
376 match maybe_shift_to_centre_from {
377 Some(original) => {
378 let xy = rect.xy();
379 let difference = vec2_sub(xy, original);
380 let triangles = triangles.into_iter().map(|tri| tri.add(difference));
381 update_triangles(state, triangles)
382 }
383 None => update_triangles(state, triangles),
384 }
385 }
386}
387
388#[inline]
437pub fn from_quad(points: [Point; 4]) -> (Triangle<Point>, Triangle<Point>) {
438 let (a, b, c, d) = (points[0], points[1], points[2], points[3]);
439 (Triangle([a, b, c]), Triangle([a, c, d]))
440}
441
442impl<V> AsRef<Triangle<V>> for Triangle<V>
443where
444 V: Vertex,
445{
446 fn as_ref(&self) -> &Triangle<V> {
447 self
448 }
449}
450
451pub fn is_over_triangle<V>(t: &Triangle<V>, p: Point) -> bool
453where
454 V: Vertex,
455{
456 let ps = t.points();
457 let (a, b, c) = (ps[0], ps[1], ps[2]);
458
459 fn sign(a: Point, b: Point, c: Point) -> Scalar {
460 (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
461 }
462
463 let b1 = sign(p, a, b) < 0.0;
464 let b2 = sign(p, b, c) < 0.0;
465 let b3 = sign(p, c, a) < 0.0;
466
467 (b1 == b2) && (b2 == b3)
468}
469
470pub fn is_over<V, I, T>(ts: I, p: Point) -> bool
472where
473 V: Vertex,
474 T: AsRef<Triangle<V>>,
475 I: IntoIterator<Item = T>,
476{
477 ts.into_iter().any(|t| is_over_triangle(t.as_ref(), p))
478}
479
480pub fn is_over_widget<S>(widget: &graph::Container, point: Point, _: &Theme) -> widget::IsOver
482where
483 S: Style,
484{
485 widget
486 .state_and_style::<State<Vec<Triangle<S::Vertex>>>, S>()
487 .map(|widget| is_over(widget.state.triangles.iter().cloned(), point))
488 .unwrap_or_else(|| widget.rect.is_over(point))
489 .into()
490}