1use lazy_static::lazy_static;
14use mat::Mat;
15
16use crate::prelude::*;
17
18pub use self::builder::{PictureBuilder as Builder, FitBuilder, WithFrameBuilder};
19
20pub type Picture <'element> = Widget <'element,
21 controller::component::Scroll,
22 model::component::Pixmap,
23 view::component::Image>;
24
25lazy_static!{
30 pub static ref CONTROLS : Controls = Controls::default();
31 }
44
45pub fn scroll_right (
47 _ : &controls::button::Release,
48 _elements : &Tree <Element>,
49 _node_id : &NodeId,
50 _action_buffer : &mut Vec <(NodeId, Action)>
51) {
52 log::trace!("scroll_right...");
53 unimplemented!("TODO: picture scroll right")
54 }
56
57pub(crate) fn image (
62 canvas : &view::component::Canvas,
63 scroll : &controller::component::Scroll,
64 pixmap : &model::component::Pixmap
65) -> view::component::Image {
66 use model::component::Pixmap;
67 match &pixmap {
68 Pixmap::Pixmap8 (mat) =>
69 view::component::Image::Raw8 (make_image (canvas, scroll, &mat)),
70 Pixmap::Pixmap16 (mat) =>
71 view::component::Image::Raw16 (make_image (canvas, scroll, &mat)),
72 Pixmap::Pixmap32 (mat) =>
73 view::component::Image::Raw32 (make_image (canvas, scroll, &mat)),
74 Pixmap::Pixmap64 (mat) =>
75 view::component::Image::Raw64 (make_image (canvas, scroll, &mat)),
76 Pixmap::Texture { resource_id, index, .. } =>
77 view::component::Image::Texture (view::Texture {
78 resource: *resource_id,
79 index: *index
80 })
81 }
82}
83
84fn make_image <T : Copy> (
89 canvas : &view::component::Canvas,
90 _scroll : &controller::component::Scroll,
91 pixmap : &Mat <T>
92) -> Mat <T> {
93 let (image_width, image_height) = canvas.body_wh();
94 let columns = pixmap.width().min (image_width as usize);
95 let rows = pixmap.height().min (image_height as usize);
96 let v = if rows > 0 {
98 pixmap.rows().take (rows).flat_map (|row| &row[0..columns])
99 .cloned().collect::<Vec <T>>()
100 } else {
101 Vec::new()
102 };
103 Mat::from_vec ((rows, columns).into(), v).unwrap()
104}
105
106mod builder {
111 use derive_builder::Builder;
112 use crate::prelude::*;
113
114 #[derive(Builder)]
115 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
116 pub struct Picture <'a, A : Application> {
117 elements : &'a Tree <Element>,
118 parent_id : &'a NodeId,
119 #[builder(default)]
120 bindings : Option <&'a controller::Bindings <A>>,
121 #[builder(default)]
122 frame_appearances : controller::Appearances,
123 #[builder(default)]
124 frame_border : Option <view::Border>,
125 #[builder(default)]
126 frame_clear_color : Option <canvas::ClearColor>,
127 #[builder(default)]
128 frame_layout : controller::component::Layout,
129 #[builder(default)]
130 pixmap : model::component::Pixmap
131 }
132
133 #[derive(Builder)]
134 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
135 pub struct Fit <'a, A : Application> {
136 elements : &'a Tree <Element>,
137 parent_id : &'a NodeId,
138 #[builder(default)]
139 anchor : controller::Alignment,
140 #[builder(default)]
141 appearances : controller::Appearances,
142 #[builder(default)]
143 bindings : Option <&'a controller::Bindings <A>>,
144 #[builder(default)]
145 border : Option <view::Border>,
146 #[builder(default)]
147 clear_color : Option <view::component::canvas::ClearColor>,
148 #[builder(default)]
149 coord_kind_override : Option <view::coordinates::Kind>,
150 #[builder(default)]
151 offset : controller::Offset,
152 #[builder(default)]
153 pixmap : model::component::Pixmap
154 }
155
156 #[derive(Builder)]
157 #[builder(pattern="owned", build_fn(private), setter(strip_option))]
158 pub struct WithFrame <'a, A : Application> {
159 elements : &'a Tree <Element>,
160 frame_id : &'a NodeId,
161 #[builder(default)]
162 bindings : Option <&'a controller::Bindings <A>>,
163 #[builder(default)]
164 pixmap : model::component::Pixmap,
165 }
166
167 impl <'a, A : Application> PictureBuilder <'a, A> {
168 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
169 PictureBuilder {
170 elements: Some (elements),
171 parent_id: Some (parent_id),
172 bindings: None,
173 frame_appearances: None,
174 frame_border: None,
175 frame_clear_color: None,
176 frame_layout: None,
177 pixmap: None
178 }
179 }
180 }
181
182 impl <'a, A : Application> BuildActions for PictureBuilder <'a, A> {
183 fn build_actions (self) -> Vec<(NodeId, Action)> {
186 use std::convert::TryInto;
187 use crate::tree::InsertBehavior;
188 log::trace!("build actions...");
189 let Picture {
190 elements, parent_id, bindings, frame_appearances, frame_border,
191 frame_clear_color, frame_layout, pixmap
192 } = self.build()
193 .map_err(|err| log::error!("frame builder error: {:?}", err))
194 .unwrap();
195 let bindings_empty = Bindings::empty();
196 let bindings = bindings.unwrap_or (&bindings_empty);
197 { let Widget (_, _, canvas) = Frame::try_get (elements, parent_id)
199 .unwrap();
200 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
201 }
202 let mut out = vec![];
203 let (mut subtree, order) = {
204 let mut actions = {
205 let mut frame = frame::Builder::new (elements, parent_id)
206 .appearances (frame_appearances)
207 .bindings (bindings)
208 .layout (frame_layout);
209 set_option!(frame, border, frame_border);
210 set_option!(frame, clear_color, frame_clear_color);
211 frame.build_actions()
212 };
213 out.extend (actions.drain (1..));
214 debug_assert_eq!(actions.len(), 1);
215 actions.pop().unwrap().1.try_into().unwrap()
216 };
217 let frame_id = subtree.root_node_id().unwrap().clone();
218 let picture = {
219 let Widget (_, _, canvas) = Frame::try_get (&subtree, &frame_id)
220 .unwrap();
221 let scroll = Scroll::default_pixel_absolute().into();
222 let image = super::image (canvas, &scroll, &pixmap);
223 let controller = {
224 let mut controller = Controller::with_bindings (
225 &bindings.get_bindings (&super::CONTROLS));
226 controller.component = scroll.into();
227 controller
228 };
229 let model = Model { component: pixmap.into(), .. Model::default() };
230 let view = view::Component::from (image).into();
231 Element::new ("Picture".to_string(), controller, model, view)
232 };
233 let _ = subtree
234 .insert (Node::new (picture), InsertBehavior::UnderNode (&frame_id))
235 .unwrap();
236 out.push ((parent_id.clone(), Action::Create (subtree, order)));
237 log::trace!("...build actions");
238 out
239 }
240 }
241
242 impl <'a, A : Application> FitBuilder <'a, A> {
243 pub fn new (elements : &'a Tree <Element>, parent_id : &'a NodeId) -> Self {
244 FitBuilder {
245 elements: Some (elements),
246 parent_id: Some (parent_id),
247 anchor: None,
248 appearances: None,
249 bindings: None,
250 border: None,
251 clear_color: None,
252 coord_kind_override: None,
253 offset: None,
254 pixmap: None
255 }
256 }
257 }
258
259 impl <'a, A : Application> BuildActions for FitBuilder <'a, A> {
260 fn build_actions (self) -> Vec<(NodeId, Action)> {
263 use crate::tree::InsertBehavior;
264 log::trace!("fit build actions...");
265 let Fit {
266 elements, parent_id, anchor, appearances, bindings, border, clear_color,
267 coord_kind_override, offset, pixmap
268 } = self.build()
269 .map_err(|err| log::error!("frame builder error: {:?}", err))
270 .unwrap();
271 let bindings_empty = Bindings::empty();
272 let bindings = bindings.unwrap_or (&bindings_empty);
273 let (body_width, body_height) = {
274 let Widget (_, _, canvas) = Frame::try_get (elements, parent_id)
275 .unwrap();
276 if let Some (coord_kind) = coord_kind_override.clone() {
277 if canvas.coordinates.kind() == coord_kind {
278 (pixmap.width() as u32, pixmap.height() as u32)
279 } else {
280 match canvas.coordinates.kind() {
281 coordinates::Kind::Tile => {
282 let round_up = |dimension, tile|
284 dimension as u32 / tile +
285 if dimension as u32 % tile != 0 { 1 } else { 0 };
286 let [tile_w, tile_h] = *coordinates::TILE_WH;
287 ( round_up (pixmap.width(), tile_w),
288 round_up (pixmap.height(), tile_h)
289 )
290 }
291 coordinates::Kind::Pixel =>
292 unimplemented!("TODO: pixel frame with tile image")
294 }
295 }
296 } else {
297 (pixmap.width() as u32, pixmap.height() as u32)
298 }
299 };
300 let mut out = vec![];
301 let frame = {
302 let size = {
303 let (border_w, border_h) = border.as_ref().map (Border::total_wh)
304 .unwrap_or ((0,0));
305 let width = (body_width + border_w as u32).into();
306 let height = (body_height + border_h as u32).into();
307 controller::Size { width, height }
308 };
309 let layout = layout::Free { anchor, offset, size };
310 let mut free = frame::free::Builder::new (elements, parent_id)
311 .appearances (appearances)
312 .bindings (bindings)
313 .layout (layout);
314 set_option!(free, border, border);
315 set_option!(free, clear_color, clear_color);
316 free.build_element()
317 };
318 let mut subtree = TreeBuilder::new().with_root (Node::new (frame))
319 .build();
320 let frame_id = subtree.root_node_id().unwrap().clone();
321 let picture = {
322 let Widget (_, _, canvas) = Frame::try_get (&subtree, &frame_id)
323 .unwrap();
324 let scroll = Scroll::default_pixel_absolute().into();
325 let image = super::image (canvas, &scroll, &pixmap);
326 let controller = {
327 let mut controller = Controller::with_bindings (
328 &bindings.get_bindings (&super::CONTROLS));
329 controller.component = scroll.into();
330 controller
331 };
332 let model = Model {
333 component: pixmap.clone().into(), .. Model::default()
334 };
335 let view = view::Component::from (image).into();
336 Element::new ("Picture".to_string(), controller, model, view)
337 };
338 let _ = subtree
339 .insert (Node::new (picture), InsertBehavior::UnderNode (&frame_id))
340 .unwrap();
341 out.push ((
342 parent_id.clone(), Action::Create (subtree, CreateOrder::Append)
343 ));
344 log::trace!("...fit build actions");
345 out
346 }
347 }
348
349 impl <'a, A : Application> WithFrameBuilder <'a, A> {
350 pub fn new (elements : &'a Tree <Element>, frame_id : &'a NodeId) -> Self {
351 WithFrameBuilder {
352 elements: Some (elements),
353 frame_id: Some (frame_id),
354 bindings: None,
355 pixmap: None
356 }
357 }
358 }
359
360 impl <'a, A : Application> BuildElement for WithFrameBuilder <'a, A> {
361 fn build_element (self) -> Element {
363 log::trace!("with frame build actions...");
364 let WithFrame { elements, frame_id, bindings, pixmap } = self.build()
365 .map_err(|err| log::error!("with frame builder error: {:?}", err))
366 .unwrap();
367 let bindings_empty = Bindings::empty();
368 let bindings = bindings.unwrap_or (&bindings_empty)
369 .get_bindings (&super::CONTROLS);
370 let Widget (_, _, canvas) = Frame::try_get (elements, &frame_id).unwrap();
371 assert!(canvas.coordinates.kind() == coordinates::Kind::Tile);
372 let scroll = Scroll::default_pixel_absolute().into();
373 let image = super::image (canvas, &scroll, &pixmap);
374 let controller = {
375 let mut controller = Controller::with_bindings (
376 &bindings.get_bindings (&super::CONTROLS));
377 controller.component = scroll.into();
378 controller
379 };
380 let model = Model { component: pixmap.into(), .. Model::default() };
381 let view = view::Component::from (image).into();
382 log::trace!("...with_frame");
383 Element::new ("Picture".to_string(), controller, model, view)
384 }
385 }
386}