1use std::convert::TryFrom;
2use log;
3use lazy_static::lazy_static;
4
5use crate::prelude::*;
6
7use super::set_layout;
8
9pub use self::builder::TiledBuilder as Builder;
10
11lazy_static!{
16 pub static ref CONTROLS : Controls = controls::Builder::new()
17 .buttons ({
18 let mut v : Vec <controls::Button> = vec![
19 controls::button::Builtin::FrameTiledIncreaseSize,
20 controls::button::Builtin::FrameTiledDecreaseSize
21 ].into_iter().map (Into::into).collect();
22 v.extend (super::CONTROLS.buttons.iter().cloned());
23 v.into()
24 })
25 .build();
26}
27
28pub fn increase_size (
32 _ : &controls::button::Release,
33 elements : &Tree <Element>,
34 node_id : &NodeId,
35 action_buffer : &mut Vec <(NodeId, Action)>
36) {
37 log::trace!("increase_size...");
38 let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
39 let coordinate_kind = Some (canvas.coordinates.kind());
40 let layout = {
41 use controller::component::{layout, Layout};
42 let mut tiled = layout::Tiled::try_from (layout.variant.clone()).unwrap();
43 tiled.modify_size (1);
44 Layout { variant: tiled.into(), .. layout.clone() }
45 };
46 set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
47 log::trace!("...increase_size");
48}
49
50pub fn decrease_size (
54 _ : &controls::button::Release,
55 elements : &Tree <Element>,
56 node_id : &NodeId,
57 action_buffer : &mut Vec <(NodeId, Action)>
58) {
59 log::trace!("decrease_size...");
60 let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
61 let coordinate_kind = Some (canvas.coordinates.kind());
62 let layout = {
63 use controller::component::{layout, Layout};
64 let mut tiled = layout::Tiled::try_from (layout.variant.clone()).unwrap();
65 tiled.modify_size (-1);
66 Layout { variant: tiled.into(), .. layout.clone() }
67 };
68 set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
69 log::trace!("...decrease_size");
70}
71
72pub (crate) fn new_coordinates (
79 elements : &Tree <Element>,
80 frame_id : &NodeId,
81 layout : &controller::component::layout::Tiled
82) -> Vec <(NodeId, view::Coordinates)> {
83 use controller::component::layout;
84 log::trace!("coordinates...");
85 let parent_id = elements.get_parent_id (frame_id);
86 let Widget (parent_layout, _, parent_canvas) =
87 Frame::try_get (elements, parent_id).unwrap();
88 let parent_node = elements.get (parent_id).unwrap();
89 let mut total_weights = 0;
90 let mut total_absolute = 0;
91 let mut add_layout = |layout : &layout::Tiled| match layout {
92 layout::Tiled::Weighted (weight) => total_weights += weight.get(),
93 layout::Tiled::Absolute (size) => total_absolute += size.get()
94 };
95 let tiled_children = parent_node.children().iter().filter_map (|child_id| {
96 let Widget (child_layout, _, _) = Frame::try_get (elements, child_id).ok()?;
97 if child_id == frame_id {
98 add_layout (layout);
100 Some ((child_id.clone(), layout))
101 } else {
102 if let controller::component::layout::Variant::Tiled (ref tiled) =
103 child_layout.variant
104 {
105 add_layout (tiled);
106 Some ((child_id.clone(), tiled))
107 } else {
108 None
109 }
110 }
111 }).collect::<Vec<_>>();
112 let mut out = vec![];
113 let mut start_weight = 0;
114 let mut start_absolute = 0;
115 for (id, layout) in tiled_children.into_iter() {
116 let coordinates = coordinates (
117 &parent_layout.orientation, &parent_canvas, layout, &mut start_weight,
118 &mut start_absolute, total_weights, total_absolute);
119 out.push ((id, coordinates));
120 }
121 log::trace!("...coordinates");
122 out
123}
124
125pub (crate) fn destroy_coordinates (
128 elements : &Tree <Element>,
129 frame_id : &NodeId
130) -> Vec <(NodeId, view::Coordinates)> {
131 use controller::component::layout;
132 log::trace!("destroy_coordinates...");
133 let parent_id = elements.get_parent_id (frame_id);
134 let Widget (parent_layout, _, parent_canvas) =
135 Frame::try_get (elements, parent_id).unwrap();
136 let parent_node = elements.get (parent_id).unwrap();
137 let mut total_weights = 0;
138 let mut total_absolute = 0;
139 let mut add_layout = |layout : &layout::Tiled| match layout {
140 layout::Tiled::Weighted (weight) => total_weights += weight.get(),
141 layout::Tiled::Absolute (size) => total_absolute += size.get()
142 };
143 let tiled_children = parent_node.children().iter().filter_map (|child_id| {
144 if child_id == frame_id {
145 None
146 } else {
147 let Widget (child_layout, _, _) = Frame::try_get (elements, child_id)
148 .ok()?;
149 if let controller::component::layout::Variant::Tiled (ref tiled) =
150 child_layout.variant
151 {
152 add_layout (tiled);
153 Some ((child_id.clone(), tiled))
154 } else {
155 None
156 }
157 }
158 }).collect::<Vec <_>>();
159 let mut out = vec![];
160 let mut start_weight = 0;
161 let mut start_absolute = 0;
162 for (id, layout) in tiled_children.into_iter() {
163 let coordinates = coordinates (
164 &parent_layout.orientation, &parent_canvas, layout, &mut start_weight,
165 &mut start_absolute, total_weights, total_absolute);
166 out.push ((id, coordinates));
167 }
168 log::trace!("...destroy_coordinates");
169 out
170}
171
172pub (crate) fn child_coordinates (
175 orientation : &(controller::Orientation, controller::Area),
176 canvas : &view::component::Canvas,
177 layouts : Vec <controller::component::layout::Tiled>
178) -> Vec <view::Coordinates> {
179 use controller::component::layout;
180 let mut child_coordinates = vec![];
181 let mut total_weights = 0;
182 let mut total_absolute = 0;
183 let add_layout = |layout : &layout::Tiled| match layout {
184 layout::Tiled::Weighted (weight) => total_weights += weight.get(),
185 layout::Tiled::Absolute (size) => total_absolute += size.get()
186 };
187 layouts.iter().for_each (add_layout);
188 let mut start_weight = 0;
189 let mut start_absolute = 0;
190 for layout in layouts {
191 child_coordinates.push (
192 coordinates (&orientation, &canvas, &layout, &mut start_weight,
193 &mut start_absolute, total_weights, total_absolute));
194 }
195 child_coordinates
196}
197
198fn coordinates (
203 (parent_orientation, parent_area) :
204 &(controller::Orientation, controller::Area),
205 parent_canvas : &view::component::Canvas,
206 child_layout : &controller::component::layout::Tiled,
207 start_weight : &mut u32,
208 start_absolute : &mut u32,
209 total_weights : u32,
210 total_absolute : u32
211) -> view::Coordinates {
212 use controller::component::layout;
213 use view::{coordinates, dimensions, position};
214 log::trace!("coordinates...");
215 let parent_coordinates = match parent_area {
216 controller::Area::Exterior => parent_canvas.coordinates,
217 controller::Area::Interior => parent_canvas.body_coordinates()
218 };
219 let (position_horizontal, position_vertical, width, height) =
220 match parent_orientation {
221 controller::Orientation::Horizontal => {
222 let height = parent_coordinates.dimensions_vertical();
223 let parent_width = parent_coordinates.dimensions_horizontal();
224 let position_vertical = parent_coordinates.position_vertical();
225 let parent_position_horizontal = parent_coordinates.position_horizontal();
226 let position_horizontal = parent_position_horizontal +
227 *start_absolute as i32 +
228 ((*start_weight as f64 / total_weights as f64) *
229 parent_width.saturating_sub (total_absolute) as f64)
230 as i32;
231 let width = match child_layout {
232 layout::Tiled::Weighted (weight) => {
233 let weight = weight.get();
234 *start_weight += weight;
235 let next_position = parent_position_horizontal +
236 *start_absolute as i32 +
237 ((*start_weight as f64 / total_weights as f64) *
238 parent_width.saturating_sub (total_absolute) as f64)
239 as i32;
240 (next_position - position_horizontal) as u32
241 }
242 layout::Tiled::Absolute (size) => {
243 let size = size.get();
244 *start_absolute += size;
245 size
246 }
247 };
248 (position_horizontal, position_vertical, width, height)
249 }
250 controller::Orientation::Vertical => {
251 let width = parent_coordinates.dimensions_horizontal();
252 let parent_height = parent_coordinates.dimensions_vertical();
253 let position_horizontal = parent_coordinates.position_horizontal();
254 let parent_position_vertical = parent_coordinates.position_vertical();
255 let position_vertical = parent_position_vertical +
256 *start_absolute as i32 +
257 ((*start_weight as f64 / total_weights as f64) *
258 parent_height.saturating_sub (total_absolute) as f64)
259 as i32;
260 let height = match child_layout {
261 layout::Tiled::Weighted (weight) => {
262 let weight = weight.get();
263 *start_weight += weight;
264 let next_position = parent_position_vertical +
265 *start_absolute as i32 +
266 ((*start_weight as f64 / total_weights as f64) *
267 parent_height.saturating_sub (total_absolute) as f64)
268 as i32;
269 (next_position - position_vertical) as u32
270 }
271 layout::Tiled::Absolute (size) => {
272 let size = size.get();
273 *start_absolute += size;
274 size
275 }
276 };
277 (position_horizontal, position_vertical, width, height)
278 }
279 };
280 let out = if parent_coordinates.kind() == coordinates::Kind::Tile {
281 ( position::Tile::new_rc (position_vertical, position_horizontal),
282 dimensions::Tile::new_rc (height, width)
283 ).into()
284 } else {
285 debug_assert!(parent_coordinates.kind() == coordinates::Kind::Pixel);
286 ( position::Pixel::new_xy (position_horizontal, position_vertical),
287 dimensions::Pixel::new_wh (width, height)
288 ).into()
289 };
290 log::trace!("...coordinates");
291 out
292}
293
294mod builder {
299 use derive_builder::Builder;
300 use crate::prelude::*;
301 use frame::set_coordinates;
302
303 #[derive(Builder)]
304 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
305 pub struct Tiled <'a, A : Application> {
306 elements : &'a Tree <Element>,
307 parent_id : &'a NodeId,
308 #[builder(default)]
309 appearances : controller::Appearances,
310 #[builder(default)]
311 bindings : Option <&'a controller::Bindings <A>>,
312 #[builder(default)]
313 border : Option <view::Border>,
314 #[builder(default)]
315 clear_color : canvas::ClearColor,
316 #[builder(default)]
317 create_order : CreateOrder,
318 #[builder(default)]
319 disabled : bool,
320 #[builder(default)]
321 layout : controller::component::layout::Tiled,
322 #[builder(default)]
323 orientation : (controller::Orientation, controller::Area),
324 }
325
326 impl <'a, A : Application> TiledBuilder <'a, A> {
327 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
328 TiledBuilder {
329 elements: Some (elements),
330 parent_id: Some (parent_id),
331 appearances: None,
332 bindings: None,
333 border: None,
334 clear_color: None,
335 create_order: None,
336 disabled: None,
337 layout: None,
338 orientation: None
339 }
340 }
341 }
342
343 impl <'a, A : Application> BuildActions for TiledBuilder <'a, A> {
344 fn build_actions (self) -> Vec <(NodeId, Action)> {
349 use view::component::Canvas;
350 log::trace!("build actions...");
351 let Tiled {
352 elements, parent_id, appearances, bindings, border, clear_color,
353 create_order, disabled, layout, orientation
354 } = self.build()
355 .map_err(|err| log::error!("frame free builder error: {:?}", err))
356 .unwrap();
357 let bindings_empty = controller::Bindings::empty();
358 let bindings = bindings.unwrap_or (&bindings_empty)
359 .get_bindings (&super::CONTROLS);
360 let (new_coordinates, sibling_coordinates) =
361 create_coordinates (elements, parent_id, &layout, create_order);
362 let frame = {
363 use controller::component::Layout;
364 let controller = {
365 let mut controller = Controller::with_bindings (&bindings);
366 controller.component = Layout {
367 orientation, variant: layout.clone().into()
368 }.into();
369 controller.appearances = appearances;
370 controller
371 };
372 let view = {
373 let coordinates = new_coordinates;
374 let appearance = controller.get_appearance().clone();
375 let component = Canvas { coordinates, clear_color, border }.into();
376 View { component, appearance, .. View::default() }
377 };
378 let mut frame =
379 Element::new ("Frame".to_string(), controller, Model::default(), view);
380 let parent_node = elements.get (parent_id).unwrap();
381 if parent_node.data().controller.state == controller::State::Disabled ||
382 disabled
383 {
384 frame.disable()
385 }
386 frame
387 };
388 let mut out = vec![(
389 parent_id.clone(), Action::create_singleton (frame, create_order)
390 )];
391 for (id, coordinates) in sibling_coordinates.into_iter() {
392 set_coordinates (elements, &id, &coordinates, None, &mut out);
393 }
394 log::trace!("...build actions");
395 out
396 }
397 }
398
399 fn create_coordinates (
403 elements : &Tree <Element>,
404 parent_frame_id : &NodeId,
405 layout : &controller::component::layout::Tiled,
406 order : CreateOrder
407 ) -> (view::Coordinates, Vec <(NodeId, view::Coordinates)>) {
408 use controller::component::layout;
409 log::trace!("create_coordinates...");
410 let Widget (parent_layout, _, parent_canvas) =
411 Frame::try_get (elements, parent_frame_id).unwrap();
412 let parent_node = elements.get (parent_frame_id).unwrap();
413 let mut total_weights = 0;
414 let mut total_absolute = 0;
415 let mut add_layout = |layout : &layout::Tiled| match layout {
416 layout::Tiled::Weighted (weight) => total_weights += weight.get(),
417 layout::Tiled::Absolute (size) => total_absolute += size.get()
418 };
419 add_layout (layout);
420 let sibling_layouts = parent_node.children().iter().map (|child_id| {
421 let Widget (child_layout, _, _) = Frame::try_get (elements, child_id)
422 .ok()?;
423 if let layout::Variant::Tiled (ref tiled) = child_layout.variant {
424 add_layout (tiled);
425 Some ((child_id, tiled))
426 } else {
427 None
428 }
429 }).collect::<Vec <_>>();
430 let order_index = match order {
431 CreateOrder::Prepend => Some (0),
432 CreateOrder::NthSibling (n) => Some (n),
433 CreateOrder::Append => None
434 };
435 let mut sibling_coordinates = vec![];
436 let mut start_weight = 0;
437 let mut start_absolute = 0;
438 let mut new_coordinates = None;
439 let mut index = 0;
440 for (i, maybe_tiled) in sibling_layouts.into_iter().enumerate() {
442 if order_index == Some (i as u32) {
443 new_coordinates = Some (super::coordinates (
444 &parent_layout.orientation, &parent_canvas, layout, &mut start_weight,
445 &mut start_absolute, total_weights, total_absolute
446 ));
447 }
448 if let Some ((id, tiled)) = maybe_tiled {
449 let coordinates = super::coordinates (
450 &parent_layout.orientation, &parent_canvas, tiled, &mut start_weight,
451 &mut start_absolute, total_weights, total_absolute);
452 sibling_coordinates.push ((id.clone(), coordinates));
453 }
454 index = i + 1;
455 }
456 if new_coordinates.is_none() {
457 if cfg!(debug_assertions) {
458 if let Some (n) = order_index {
459 debug_assert_eq!(n, index as u32);
460 }
461 }
462 new_coordinates = Some (super::coordinates (
463 &parent_layout.orientation, &parent_canvas, layout,
464 &mut start_weight, &mut start_absolute, total_weights, total_absolute
465 ));
466 }
467 log::trace!("...create_coordinates");
468 (new_coordinates.unwrap(), sibling_coordinates)
469 }
470}