1use std::convert::TryInto;
2use derive_builder::Builder;
3use log;
4
5use crate::prelude::*;
6use super::{Frame, set_layout};
7
8pub fn resize (
16 system : &input::System,
17 elements : &Tree <Element>,
18 node_id : &NodeId,
19 action_buffer : &mut Vec <(NodeId, Action)>
20) {
21 log::trace!("resize...");
22 match system {
23 &input::System::Resized { width, height } => {
24 *coordinates::SCREEN_WH.write().unwrap() = [width, height];
25 let Widget (layout, _, canvas) = Frame::try_get (elements, node_id)
26 .unwrap();
27 let coordinate_kind = Some (canvas.coordinates.kind());
28 let layout = {
29 use controller::component::Layout;
30 let (mut free, area) = layout.variant.clone().try_into().unwrap();
31 free.size = {
32 let width = width.into();
33 let height = height.into();
34 controller::Size { width, height }
35 };
36 free.offset = if canvas.coordinates.kind() == coordinates::Kind::Tile {
37 tile_offset (free.size, free.anchor)
38 } else {
39 pixel_offset (free.size, free.anchor)
40 };
41 Layout { variant: (free, area).into(), .. layout.clone() }
42 };
43 set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
45 }
46 _ => {}
47 }
48 log::trace!("...resize");
49}
50
51#[derive(Builder)]
56#[builder(pattern="owned", build_fn(private), setter(strip_option))]
57#[builder(public)]
58struct Pixel <'a, A : Application> {
59 #[builder(default)]
60 anchor : Option <controller::Alignment>,
61 #[builder(default)]
62 appearances : Option <controller::Appearances>,
63 #[builder(default)]
64 bindings : Option <&'a controller::Bindings <A>>,
65 #[builder(default)]
66 border : Option <view::Border>,
67 #[builder(default)]
68 clear_color : canvas::ClearColor,
69 #[builder(default)]
70 dimensions : Option <view::dimensions::Pixel>,
71 #[builder(default)]
72 orientation : (controller::Orientation, controller::Area),
73 #[builder(default)]
74 system_control : Option <controls::System>
75}
76
77#[derive(Builder)]
78#[builder(pattern="owned", build_fn(private), setter(strip_option))]
79#[builder(public)]
80struct Tile <'a, A : Application> {
81 #[builder(default)]
82 anchor : Option <controller::Alignment>,
83 #[builder(default)]
84 appearances : Option <controller::Appearances>,
85 #[builder(default)]
86 bindings : Option <&'a controller::Bindings <A>>,
87 #[builder(default)]
88 border : Option <view::Border>,
89 #[builder(default)]
90 clear_color : canvas::ClearColor,
91 #[builder(default)]
92 dimensions : Option <view::dimensions::Tile>,
93 #[builder(default)]
94 orientation : (controller::Orientation, controller::Area),
95 #[builder(default)]
96 system_control : Option <controls::System>
97}
98
99impl <'a, A : Application> PixelBuilder <'a, A> {
100 pub fn new() -> Self {
101 PixelBuilder {
102 anchor: None,
103 appearances: None,
104 bindings: None,
105 border: None,
106 clear_color: None,
107 dimensions: None,
108 orientation: None,
109 system_control: None
110 }
111 }
112}
113
114impl <'a, A : Application> BuildElement for PixelBuilder <'a, A> {
115 fn build_element (self) -> Element {
121 log::trace!("pixel build element...");
122 let Pixel {
123 anchor, appearances, bindings, border, clear_color, dimensions,
124 orientation, system_control
125 } = self.build()
126 .map_err(|err| log::error!("frame screen tile builder error: {:?}", err))
127 .unwrap();
128 let controller = {
129 let layout = {
130 use controller::{Alignment, Area, Size};
131 use controller::component::{layout, Layout};
132 let size = dimensions.map_or (
133 Size::default_absolute(),
134 |dimensions| Size {
135 width: dimensions.width().into(),
136 height: dimensions.height().into()
137 }
138 );
139 let anchor = anchor.unwrap_or (Alignment::pixel());
140 let offset = pixel_offset (size, anchor);
141 let free = layout::Free { size, offset, anchor };
142 Layout { orientation, .. layout::Variant::from ((free, Area::default())).into() }
143 };
144 let bindings_empty = controller::Bindings::empty();
145 let bindings = {
146 let mut bindings =
147 bindings.unwrap_or (&bindings_empty).get_bindings (&super::CONTROLS);
148 bindings.system = system_control.map (Into::into)
149 .or (Some (controls::system::Builtin::FrameScreenResize.into()));
150 bindings
151 };
152 let mut controller = Controller::with_bindings (&bindings);
153 controller.component = layout.into();
154 controller.appearances = appearances.unwrap_or_default();
155 controller
156 };
157 let view = {
158 let coordinates = view::Coordinates::Pixel (
159 view::position::Pixel::origin(),
160 dimensions.unwrap_or (view::dimensions::Pixel::default()));
161 let width = coordinates.dimensions_horizontal();
162 let height = coordinates.dimensions_vertical();
163 *coordinates::SCREEN_WH.write().unwrap() = [width, height];
164 let canvas = view::component::Canvas { coordinates, clear_color, border };
165 let appearance = controller.get_appearance().clone();
166 View { appearance, .. view::Component::from (canvas).into() }
167 };
168 log::trace!("...pixel build element");
169 Element::new ("Frame".to_string(), controller, Model::default(), view)
170 }
171}
172
173impl <'a, A : Application> TileBuilder <'a, A> {
174 pub fn new() -> Self {
175 TileBuilder {
176 anchor: None,
177 appearances: None,
178 bindings: None,
179 border: None,
180 clear_color: None,
181 dimensions: None,
182 orientation: None,
183 system_control: None
184 }
185 }
186}
187
188impl <'a, A : Application> BuildElement for TileBuilder <'a, A> {
189 fn build_element (self) -> Element {
191 log::trace!("tile build element...");
192 let Tile {
193 anchor, appearances, bindings, border, clear_color, dimensions,
194 orientation, system_control
195 } = self.build()
196 .map_err(|err| log::error!("frame screen tile builder error: {:?}", err))
197 .unwrap();
198 let controller = {
199 let layout = {
200 use controller::{Alignment, Area, Size};
201 use controller::component::{layout, Layout};
202 let size = dimensions.map_or (Size::default_absolute(),
203 |dimensions| Size {
204 width: dimensions.columns().into(),
205 height: dimensions.rows().into()
206 }
207 );
208 let anchor = anchor.unwrap_or (Alignment::tile());
209 let offset = tile_offset (size, anchor);
210 let free = layout::Free { size, offset, anchor };
211 let area = Area::default();
212 Layout { orientation, .. layout::Variant::from ((free, area)).into() }
213 };
214 let bindings_empty = controller::Bindings::empty();
215 let bindings = {
216 let mut bindings =
217 bindings.unwrap_or (&bindings_empty).get_bindings (&super::CONTROLS);
218 bindings.system = system_control.map (Into::into)
219 .or (Some (controls::system::Builtin::FrameScreenResize.into()));
220 bindings
221 };
222 let mut controller = Controller::with_bindings (&bindings);
223 controller.component = layout.into();
224 controller.appearances = appearances.unwrap_or_default();
225 controller
226 };
227 let view = {
228 let coordinates = view::Coordinates::Tile (
229 view::position::Tile::origin(),
230 dimensions.unwrap_or (view::dimensions::Tile::default()));
231 let width = coordinates.dimensions_horizontal();
232 let height = coordinates.dimensions_vertical();
233 *coordinates::SCREEN_WH.write().unwrap() = [width, height];
234 let canvas = view::component::Canvas { coordinates, clear_color, border };
235 let appearance = controller.get_appearance().clone();
236 View { appearance, .. view::Component::from (canvas).into() }
237 };
238 log::trace!("...tile build element");
239 Element::new ("Frame".to_string(), controller, Model::default(), view)
240 }
241}
242
243pub fn pixel_offset (size : controller::Size, anchor : controller::Alignment)
253 -> controller::Offset
254{
255 use controller::{alignment, offset, Offset};
256 let horizontal = match anchor.horizontal {
257 alignment::Horizontal::Left => 0.into(),
258 alignment::Horizontal::Center => -offset::Signed::from (size.width).half(),
259 alignment::Horizontal::Right => -offset::Signed::from (size.width)
260 };
261 let vertical = match anchor.vertical {
262 alignment::Vertical::Bottom => 0.into(),
263 alignment::Vertical::Middle => -offset::Signed::from (size.height).half(),
264 alignment::Vertical::Top => -offset::Signed::from (size.height)
265 };
266 Offset { horizontal, vertical }
267}
268
269pub fn tile_offset (size : controller::Size, anchor : controller::Alignment)
276 -> controller::Offset
277{
278 use controller::{alignment, offset, Offset};
279 let horizontal = match anchor.horizontal {
280 alignment::Horizontal::Left => 0.into(),
281 alignment::Horizontal::Center => -offset::Signed::from (size.width).half(),
282 alignment::Horizontal::Right => -offset::Signed::from (size.width)
283 };
284 let vertical = match anchor.vertical {
285 alignment::Vertical::Top => 0.into(),
286 alignment::Vertical::Middle => -offset::Signed::from (size.height).half(),
287 alignment::Vertical::Bottom => -offset::Signed::from (size.height)
288 };
289 Offset { horizontal, vertical }
290}