1use graph;
4use utils;
5use widget;
6use {Scalar, Ui, UiCell, Widget};
7
8pub type WidgetNum = usize;
10pub type ColNum = usize;
12pub type RowNum = usize;
14pub type Width = Scalar;
16pub type Height = Scalar;
18pub type PosX = Scalar;
20pub type PosY = Scalar;
22
23#[derive(Clone, WidgetCommon_)]
27#[allow(missing_copy_implementations)]
28pub struct Matrix {
29 #[conrod(common_builder)]
30 common: widget::CommonBuilder,
31 style: Style,
32 cols: usize,
33 rows: usize,
34}
35
36pub struct State {
38 indices: Vec<Vec<widget::Id>>,
42}
43
44#[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle_)]
46pub struct Style {
47 #[conrod(default = "0.0")]
49 pub cell_pad_w: Option<Scalar>,
50 #[conrod(default = "0.0")]
52 pub cell_pad_h: Option<Scalar>,
53}
54
55#[derive(Debug)]
59#[allow(missing_copy_implementations)]
60pub struct Elements {
61 num_rows: usize,
62 num_cols: usize,
63 row: usize,
64 col: usize,
65 matrix_id: widget::Id,
66 elem_w: Scalar,
67 elem_h: Scalar,
68 x_min: Scalar,
69 x_max: Scalar,
70 y_min: Scalar,
71 y_max: Scalar,
72}
73
74#[derive(Copy, Clone, Debug)]
76pub struct Element {
77 pub widget_id: widget::Id,
79 pub row: usize,
81 pub col: usize,
83 pub w: Scalar,
85 pub h: Scalar,
87 pub rel_x: Scalar,
89 pub rel_y: Scalar,
91 matrix_id: widget::Id,
93}
94
95impl Matrix {
96 pub fn new(cols: usize, rows: usize) -> Self {
98 Matrix {
99 common: widget::CommonBuilder::default(),
100 style: Style::default(),
101 cols: cols,
102 rows: rows,
103 }
104 }
105
106 pub fn cell_padding(mut self, w: Scalar, h: Scalar) -> Self {
108 self.style.cell_pad_w = Some(w);
109 self.style.cell_pad_h = Some(h);
110 self
111 }
112}
113
114impl Widget for Matrix {
115 type State = State;
116 type Style = Style;
117 type Event = Elements;
118
119 fn init_state(&self, _: widget::id::Generator) -> Self::State {
120 State {
121 indices: Vec::new(),
122 }
123 }
124
125 fn style(&self) -> Self::Style {
126 self.style.clone()
127 }
128
129 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
131 let widget::UpdateArgs {
132 id,
133 state,
134 rect,
135 style,
136 ui,
137 ..
138 } = args;
139 let Matrix { cols, rows, .. } = self;
140
141 let num_cols = state.indices.len();
143 if num_cols < cols {
144 state.update(|state| {
145 state
146 .indices
147 .extend((num_cols..cols).map(|_| Vec::with_capacity(rows)));
148 });
149 }
150
151 for col in 0..cols {
153 let num_rows = state.indices[col].len();
154 if num_rows < rows {
155 let mut id_gen = ui.widget_id_generator();
156 state.update(|state| {
157 let extension = (num_rows..rows).map(|_| id_gen.next());
158 state.indices[col].extend(extension);
159 });
160 }
161 }
162
163 let cell_pad_w = style.cell_pad_w(&ui.theme);
164 let cell_pad_h = style.cell_pad_h(&ui.theme);
165 let (w, h) = rect.w_h();
166 let elem_w = w / cols as Scalar;
167 let elem_h = h / rows as Scalar;
168 let (half_w, half_h) = (w / 2.0, h / 2.0);
169 let x_min = -half_w + elem_w / 2.0;
170 let x_max = half_w + elem_w / 2.0;
171 let y_min = -half_h - elem_h / 2.0;
172 let y_max = half_h - elem_h / 2.0;
173
174 let elements = Elements {
175 num_rows: rows,
176 num_cols: cols,
177 row: 0,
178 col: 0,
179 matrix_id: id,
180 elem_w: elem_w - cell_pad_w * 2.0,
181 elem_h: elem_h - cell_pad_h * 2.0,
182 x_min: x_min,
183 x_max: x_max,
184 y_min: y_min,
185 y_max: y_max,
186 };
187
188 elements
189 }
190}
191
192impl Elements {
193 pub fn next(&mut self, ui: &Ui) -> Option<Element> {
195 let Elements {
196 ref mut row,
197 ref mut col,
198 num_rows,
199 num_cols,
200 matrix_id,
201 elem_w,
202 elem_h,
203 x_min,
204 x_max,
205 y_min,
206 y_max,
207 } = *self;
208
209 let (r, c) = (*row, *col);
210
211 let widget_id = match ui
213 .widget_graph()
214 .widget(matrix_id)
215 .and_then(|container| container.unique_widget_state::<Matrix>())
216 .and_then(|&graph::UniqueWidgetState { ref state, .. }| {
217 state
218 .indices
219 .get(c)
220 .and_then(|col| col.get(r).map(|&id| id))
221 }) {
222 Some(id) => id,
223 None => return None,
224 };
225
226 *row += 1;
228 if *row >= num_rows {
229 *row = 0;
230 *col += 1;
231 }
232
233 let rel_x = utils::map_range(c as Scalar, 0.0, num_cols as Scalar, x_min, x_max);
234 let rel_y = utils::map_range(r as Scalar, 0.0, num_rows as Scalar, y_max, y_min);
235
236 Some(Element {
237 widget_id: widget_id,
238 matrix_id: matrix_id,
239 col: c,
240 row: r,
241 w: elem_w,
242 h: elem_h,
243 rel_x: rel_x,
244 rel_y: rel_y,
245 })
246 }
247}
248
249impl Element {
250 pub fn set<W>(self, widget: W, ui: &mut UiCell) -> W::Event
258 where
259 W: Widget,
260 {
261 use {Positionable, Sizeable};
262 let Element {
263 widget_id,
264 matrix_id,
265 w,
266 h,
267 rel_x,
268 rel_y,
269 ..
270 } = self;
271 widget
272 .w_h(w, h)
273 .x_y_relative_to(matrix_id, rel_x, rel_y)
274 .set(widget_id, ui)
275 }
276}