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