makepad_draw/
turtle.rs

1use {
2    crate::{
3        makepad_platform::*,
4        cx_2d::{Cx2d},
5    }
6};
7
8#[derive(Copy, Clone, Debug, Live, LiveHook, LiveRegister)]
9#[live_ignore]
10pub struct Layout {
11    #[live] pub scroll: DVec2,
12    #[live(true)] pub clip_x: bool,
13    #[live(true)] pub clip_y: bool,
14    #[live] pub padding: Padding,
15    #[live] pub align: Align,
16    #[live] pub flow: Flow,
17    #[live] pub spacing: f64,
18    //#[live] pub line_spacing: f64
19}
20
21impl Default for Layout{
22    fn default()->Self{
23        Self{
24            scroll: dvec2(0.0,0.0),
25            clip_x: true,
26            clip_y: true,
27            padding: Padding::default(),
28            align: Align{x:0.0,y:0.0},
29            flow: Flow::Right,
30            spacing: 0.0,
31            //line_spacing: 0.0
32        }
33    }
34}
35
36#[derive(Copy, Clone, Default, Debug, Live, LiveHook, LiveRegister)]
37#[live_ignore]
38pub struct Walk {
39    #[live] pub abs_pos: Option<DVec2>,
40    #[live] pub margin: Margin,
41    #[live] pub width: Size,
42    #[live] pub height: Size,
43}
44
45#[derive(Clone, Copy, Default, Debug, Live, LiveHook, LiveRegister)]
46#[live_ignore]
47pub struct Align {
48    #[live] pub x: f64,
49    #[live] pub y: f64
50}
51
52#[derive(Clone, Copy, Default, Debug, Live, LiveRegister)]
53#[live_ignore]
54pub struct Padding {
55    #[live] pub left: f64,
56    #[live] pub top: f64,
57    #[live] pub right: f64,
58    #[live] pub bottom: f64
59}
60
61#[derive(Copy, Clone, Debug, Live, LiveHook)]
62#[live_ignore]
63pub enum Axis2 {
64    #[pick] Horizontal,
65    Vertical
66}
67
68impl Default for Axis2 {
69    fn default() -> Self {
70        Axis2::Horizontal
71    }
72}
73
74#[derive(Copy, Clone, Debug, Live, LiveHook, PartialEq)]
75#[live_ignore]
76pub enum Flow {
77    #[pick] Right,
78    Down,
79    //Left,
80    //Up,
81    Overlay, 
82    RightWrap
83}
84
85#[derive(Copy, Clone, Debug, Live)]
86#[live_ignore]
87pub enum Size {
88    #[pick] Fill,
89    #[live(200.0)] Fixed(f64),
90    Fit,
91    All
92}
93
94#[derive(Clone, Debug)]
95pub enum DeferWalk{
96    Unresolved{
97        defer_index: usize,
98        margin: Margin,
99        other_axis: Size,
100        pos: DVec2
101    },
102    Resolved(Walk)
103}
104
105#[derive(Debug)]
106pub enum AlignEntry{
107    Unset,
108    Area(Area),
109    ShiftTurtle{area:Area, shift:DVec2, skip:usize},
110    SkipTurtle{skip:usize},
111    BeginTurtle(DVec2,DVec2),
112    EndTurtle
113}
114
115#[derive(Clone, Default, Debug)]
116pub struct TurtleWalk {
117    align_start: usize,
118    defer_index: usize,
119    rect: Rect,
120}
121
122#[derive(Clone, Default, Debug)]
123pub struct Turtle {
124    walk: Walk,
125    layout: Layout,
126    wrap_spacing: f64,
127    align_start: usize,
128    turtle_walks_start: usize,
129    defer_count: usize,
130    shift: DVec2,
131    pos: DVec2,
132    origin: DVec2,
133    width: f64,
134    height: f64,
135    width_used: f64,
136    height_used: f64,
137    guard_area: Area
138}
139
140impl<'a,'b> Cx2d<'a,'b> {
141    pub fn turtle(&self) -> &Turtle {
142        self.turtles.last().unwrap()
143    }
144    
145    pub fn turtle_mut(&mut self) -> &mut Turtle {
146        self.turtles.last_mut().unwrap()
147    }
148    
149    pub fn begin_turtle(&mut self, walk: Walk, layout: Layout) {
150        self.begin_turtle_with_guard(walk, layout, Area::Empty)
151    }
152    
153    pub fn defer_walk(&mut self, walk: Walk) -> Option<DeferWalk> {
154        if walk.abs_pos.is_some(){
155            return None
156        }
157        let turtle = self.turtles.last_mut().unwrap();
158        let defer_index = turtle.defer_count;
159        let pos = turtle.pos;
160        let size = dvec2(
161            turtle.eval_width(walk.width, walk.margin, turtle.layout.flow),
162            turtle.eval_height(walk.height, walk.margin, turtle.layout.flow)
163        );
164        let margin_size = walk.margin.size();
165        match turtle.layout.flow {
166            Flow::Right if walk.width.is_fill() => {
167                let spacing = turtle.child_spacing(self.turtle_walks.len());
168                turtle.pos.x += margin_size.x + spacing.x;
169                turtle.update_width_max(turtle.pos.x, 0.0);
170                turtle.update_height_max(turtle.pos.y, size.y + margin_size.y);
171                turtle.defer_count += 1;
172                Some(DeferWalk::Unresolved{
173                    defer_index,
174                    margin: walk.margin,
175                    other_axis: walk.height,
176                    pos: pos + spacing
177                })
178            },
179            Flow::Down if walk.height.is_fill() => {
180                let spacing = turtle.child_spacing(self.turtle_walks.len());
181                turtle.pos.y += margin_size.y + spacing.y;
182                turtle.update_width_max(turtle.pos.x, size.x + margin_size.x);
183                turtle.update_height_max(turtle.pos.y, 0.0);
184                turtle.defer_count += 1;
185                Some(DeferWalk::Unresolved {
186                    defer_index,
187                    margin: walk.margin,
188                    other_axis: walk.width,
189                    pos: pos + spacing
190                })
191            },
192            Flow::RightWrap if walk.width.is_fill() => {
193                error!("flow RightWrap does not support fill childnodes");
194                None
195            },
196            _ => {
197                None
198            }
199        }
200    }
201    
202    pub fn begin_pass_sized_turtle_no_clip(&mut self, layout: Layout) {
203        let size = self.current_pass_size();
204        self.begin_sized_turtle_no_clip(size, layout)
205    }
206    
207    pub fn begin_pass_sized_turtle(&mut self, layout: Layout) {
208        let size = self.current_pass_size();
209        self.begin_sized_turtle(size, layout)
210    }
211    
212    pub fn begin_sized_turtle_no_clip(&mut self, size:DVec2,layout: Layout) {
213        self.begin_sized_turtle(size, layout);
214        *self.align_list.last_mut().unwrap() = AlignEntry::Unset;
215    }
216                    
217    pub fn begin_sized_turtle(&mut self, size:DVec2, layout: Layout) {
218        self.align_list.push(AlignEntry::BeginTurtle(dvec2(0.0,0.0),size));
219        let turtle = Turtle {
220            walk: Walk::fill(),
221            layout,
222            align_start: self.align_list.len() - 1,
223            turtle_walks_start: self.turtle_walks.len(),
224            defer_count: 0,
225            pos: DVec2 {
226                x: layout.padding.left,
227                y: layout.padding.top
228            },
229            wrap_spacing: 0.0,
230            origin: dvec2(0.0, 0.0),
231            width: size.x,
232            height: size.y,
233            shift: dvec2(0.0, 0.0),
234            width_used: layout.padding.left,
235            height_used: layout.padding.top,
236            guard_area: Area::Empty,
237        };
238        self.turtles.push(turtle);
239    }
240    
241    pub fn end_pass_sized_turtle_no_clip(&mut self) {
242        let turtle = self.turtles.pop().unwrap();
243                
244        self.perform_nested_clipping_on_align_list_and_shift(turtle.align_start, self.align_list.len());
245        //log!("{:?}", self.align_list[turtle.align_start]);
246        self.align_list[turtle.align_start] = AlignEntry::SkipTurtle{skip:self.align_list.len()};
247        self.turtle_walks.truncate(turtle.turtle_walks_start);
248    }
249    
250    pub fn end_pass_sized_turtle(&mut self){
251        let turtle = self.turtles.pop().unwrap();
252        // lets perform clipping on our alignlist.
253        self.align_list.push(AlignEntry::EndTurtle);
254        
255        self.perform_nested_clipping_on_align_list_and_shift(turtle.align_start, self.align_list.len());
256        //log!("{:?}", self.align_list[turtle.align_start]);
257        self.align_list[turtle.align_start] = AlignEntry::SkipTurtle{skip:self.align_list.len()};
258        self.turtle_walks.truncate(turtle.turtle_walks_start);
259    }
260    
261    pub fn end_pass_sized_turtle_with_shift(&mut self, area:Area, shift:DVec2){
262        let turtle = self.turtles.pop().unwrap();
263        // lets perform clipping on our alignlist.
264        self.align_list.push(AlignEntry::EndTurtle);
265        
266        self.perform_nested_clipping_on_align_list_and_shift(turtle.align_start, self.align_list.len());
267        //log!("{:?}", self.align_list[turtle.align_start]);
268        self.align_list[turtle.align_start] = AlignEntry::ShiftTurtle{
269            area,
270            shift, 
271            skip: self.align_list.len()
272        };
273        self.turtle_walks.truncate(turtle.turtle_walks_start);
274    }
275    
276    pub fn begin_turtle_with_guard(&mut self, walk: Walk, layout: Layout, guard_area: Area) {
277        let (origin, width, height, draw_clip) = if let Some(parent) = self.turtles.last() {
278            
279            let o = walk.margin.left_top() + if let Some(pos) = walk.abs_pos {pos} else {
280                parent.pos + parent.child_spacing(self.turtle_walks.len())
281            };
282            
283            let w = parent.eval_width(walk.width, walk.margin, parent.layout.flow);
284            let h = parent.eval_height(walk.height, walk.margin, parent.layout.flow);
285            
286            // figure out new clipping rect
287            let (x0, x1) = if layout.clip_x {
288                (/*parent.draw_clip.0.x.max(*/o.x/*)*/, if w.is_nan() {
289                    f64::NAN
290                    //parent.draw_clip.1.x
291                } else {
292                    /*parent.draw_clip.1.x.min*/o.x + w/*)*/
293                })
294            } else {
295                (f64::NAN, f64::NAN)//parent.draw_clip.0.x, parent.draw_clip.1.x)
296            };
297            
298            let (y0, y1) = if layout.clip_y {
299                (/*parent.draw_clip.0.y.max(*/o.y/*)*/, if h.is_nan() {
300                    f64::NAN
301                } else {
302                    /*parent.draw_clip.1.y.min(*/o.y + h/*)*/
303                })
304            }else {(f64::NAN,f64::NAN)};//parent.draw_clip.0.y, parent.draw_clip.1.y)};
305            
306            (o - layout.scroll, w, h, (dvec2(x0, y0), (dvec2(x1, y1))))
307        }
308        else {
309            let o = DVec2 {x: walk.margin.left, y: walk.margin.top};
310            let w = walk.width.fixed_or_nan();
311            let h = walk.height.fixed_or_nan();
312            
313            (o, w, h, (dvec2(o.x, o.y), dvec2(o.x + w, o.y + h)))
314        };
315        self.align_list.push(AlignEntry::BeginTurtle(draw_clip.0,draw_clip.1));
316        let turtle = Turtle {
317            walk,
318            layout,
319            align_start: self.align_list.len()-1,
320            turtle_walks_start: self.turtle_walks.len(),
321            defer_count: 0,
322            wrap_spacing: 0.0,
323            pos: DVec2 {
324                x: origin.x + layout.padding.left,
325                y: origin.y + layout.padding.top
326            },
327            origin,
328            width,
329            height,
330            shift: dvec2(0.0,0.0),
331            width_used: layout.padding.left,
332            height_used: layout.padding.top,
333            guard_area,
334        };
335        
336        self.turtles.push(turtle);
337    }
338    
339    pub fn turtle_has_align_items(&mut self)->bool{
340        self.align_list.len() != self.turtle().align_start + 1
341    }
342    
343    pub fn end_turtle(&mut self) -> Rect {
344        self.end_turtle_with_guard(Area::Empty)
345    }
346    
347    pub fn end_turtle_with_area(&mut self, area: &mut Area)->Rect {
348        let rect = self.end_turtle_with_guard(Area::Empty);
349        self.add_aligned_rect_area(area, rect);
350        rect
351    }
352    
353    pub fn end_turtle_with_guard(&mut self, guard_area: Area) -> Rect {
354        let turtle = self.turtles.last().unwrap();
355        if guard_area != turtle.guard_area {
356            panic!("End turtle guard area misaligned!, begin/end pair not matched begin {:?} end {:?}", turtle.guard_area, guard_area)
357        }
358        
359        let turtle_align_start = turtle.align_start;
360        let turtle_abs_pos = turtle.walk.abs_pos;
361        let turtle_margin = turtle.walk.margin;
362        let turtle_walks_start = turtle.turtle_walks_start;
363        let turtle_shift = turtle.shift;
364                
365        // computed width / height
366        let w = if turtle.width.is_nan() {
367            let w = turtle.width_used + turtle.layout.padding.right - turtle.layout.scroll.x;
368            // we should update the clip pos
369            if let AlignEntry::BeginTurtle(p1,p2) = &mut self.align_list[turtle_align_start]{
370                p2.x = p1.x + w;
371            }
372            Size::Fixed(w)
373        }
374        else {
375            Size::Fixed(turtle.width)
376        };
377        
378        let h = if turtle.height.is_nan() {
379            let h =  turtle.height_used + turtle.layout.padding.bottom - turtle.layout.scroll.y;
380            // we should update the clip pos
381            if let AlignEntry::BeginTurtle(p1,p2) = &mut self.align_list[turtle_align_start]{
382                p2.y = p1.y + h;
383            }
384            Size::Fixed(h)
385        }
386        else {
387            Size::Fixed(turtle.height)
388        };
389                
390        match turtle.layout.flow {
391            Flow::Right => {
392                if turtle.defer_count > 0 {
393                    let left = turtle.width_left();
394                    let part = left / turtle.defer_count as f64;
395                    let align_y = turtle.layout.align.y;
396                    let padded_height_or_used = turtle.padded_height_or_used();
397                    for i in turtle_walks_start..self.turtle_walks.len() {
398                        let walk = &self.turtle_walks[i];
399                        let shift_x = walk.defer_index as f64 * part;
400                        let shift_y = align_y * (padded_height_or_used - walk.rect.size.y);
401                        let align_start = walk.align_start;
402                        let align_end = self.get_turtle_walk_align_end(i);
403                        self.move_align_list(shift_x, shift_y, align_start, align_end, false, turtle_shift);
404                    }
405                }
406                else {
407                    let align_x = turtle.layout.align.x;
408                    let align_y = turtle.layout.align.y;
409                    let width_left = turtle.width_left();
410                    let padded_height_or_used = turtle.padded_height_or_used();
411                    if align_x != 0.0 || align_y != 0.0{
412                        for i in turtle_walks_start..self.turtle_walks.len() {
413                            let walk = &self.turtle_walks[i];
414                            let shift_x = align_x * width_left;
415                            let shift_y = align_y * (padded_height_or_used - walk.rect.size.y);
416                            let align_start = walk.align_start;
417                            let align_end = self.get_turtle_walk_align_end(i);
418                            self.move_align_list(shift_x, shift_y, align_start, align_end, false, turtle_shift);
419                        }
420                    }
421                }
422            },
423            Flow::RightWrap=>{
424                if turtle.defer_count > 0{panic!()}
425                // for now we only support align:0,0
426            }
427            Flow::Down => {
428                if turtle.defer_count > 0 {
429                    let left = turtle.height_left();
430                    let part = left / turtle.defer_count as f64;
431                    let padded_width_or_used = turtle.padded_width_or_used();
432                    let align_x = turtle.layout.align.x;
433                    for i in turtle_walks_start..self.turtle_walks.len() {
434                        let walk = &self.turtle_walks[i];
435                        let shift_x = align_x * (padded_width_or_used- walk.rect.size.x);
436                        let shift_y = walk.defer_index as f64 * part;
437                        let align_start = walk.align_start;
438                        let align_end = self.get_turtle_walk_align_end(i);
439                        self.move_align_list(shift_x, shift_y, align_start, align_end, false, turtle_shift);
440                    }
441                }
442                else {
443                    let align_x = turtle.layout.align.x;
444                    let align_y = turtle.layout.align.y;
445                    let padded_width_or_used = turtle.padded_width_or_used();
446                    let height_left = turtle.height_left();
447                    if align_x != 0.0 || align_y != 0.0{
448                        for i in turtle_walks_start..self.turtle_walks.len() {
449                            let walk = &self.turtle_walks[i];
450                            let shift_x = align_x * (padded_width_or_used - walk.rect.size.x);
451                            let shift_y = align_y * height_left;
452                            let align_start = walk.align_start;
453                            let align_end = self.get_turtle_walk_align_end(i);
454                            self.move_align_list(shift_x, shift_y, align_start, align_end, false, turtle_shift);
455                        }
456                    }
457                }
458            },
459            Flow::Overlay => {
460                let align_x = turtle.layout.align.x;
461                let align_y = turtle.layout.align.y;
462                if align_x != 0.0 || align_y != 0.0{
463                    let padded_width_or_used = turtle.padded_width_or_used();
464                    let padded_height_or_used = turtle.padded_height_or_used();
465                    for i in turtle_walks_start..self.turtle_walks.len() {
466                        let walk = &self.turtle_walks[i];
467                        let shift_x = align_x * (padded_width_or_used - walk.rect.size.x);
468                        let shift_y = align_y * (padded_height_or_used - walk.rect.size.y);
469                        let align_start = walk.align_start;
470                        let align_end = self.get_turtle_walk_align_end(i);
471                        self.move_align_list(shift_x, shift_y, align_start, align_end, false, turtle_shift);
472                    }
473                }
474            }
475        }
476        self.turtles.pop();
477        self.turtle_walks.truncate(turtle_walks_start);
478        self.align_list.push(AlignEntry::EndTurtle);
479        if self.turtles.len() == 0 {
480            return Rect {
481                pos: dvec2(0.0, 0.0),
482                size: dvec2(w.fixed_or_zero(), h.fixed_or_zero())
483            }
484        }
485        let rect = self.walk_turtle_move(Walk {width: w, height: h, abs_pos:turtle_abs_pos, margin:turtle_margin}, turtle_align_start);
486        rect
487    }
488    
489    pub fn walk_turtle(&mut self, walk: Walk) -> Rect {
490        self.walk_turtle_move(walk, self.align_list.len())
491    }
492    
493    pub fn set_turtle_wrap_spacing(&mut self, spacing: f64){
494        self.turtle_mut().wrap_spacing = spacing;
495    }
496
497    pub fn walk_turtle_with_area(&mut self, area: &mut Area, walk: Walk) -> Rect {
498        let rect = self.walk_turtle_move(walk, self.align_list.len());
499        self.add_aligned_rect_area(area, rect);
500        rect
501    }
502    
503    pub fn walk_turtle_with_align(&mut self, walk: Walk, align_start: usize) -> Rect {
504        self.walk_turtle_move(walk, align_start)
505    }
506    
507    pub fn peek_walk_turtle(&self, walk: Walk) -> Rect {
508        self.walk_turtle_peek(walk)
509    }
510    
511    pub fn walk_turtle_would_be_visible(&mut self, walk: Walk) -> bool {
512        let rect = self.walk_turtle_peek(walk);
513        self.turtle().rect_is_visible(rect)
514    }
515       
516    pub fn peek_walk_pos(&self, walk: Walk) -> DVec2 {
517        if let Some(pos) = walk.abs_pos {
518            pos + walk.margin.left_top()
519        }
520        else {
521            let turtle = self.turtles.last().unwrap();
522            turtle.pos + walk.margin.left_top()
523        }
524    }
525    
526    fn walk_turtle_move(&mut self, walk: Walk, align_start: usize) -> Rect {
527        
528        let turtle = self.turtles.last_mut().unwrap();
529        let size = dvec2(
530            turtle.eval_width(walk.width, walk.margin, turtle.layout.flow),
531            turtle.eval_height(walk.height, walk.margin, turtle.layout.flow)
532        );
533        
534        if let Some(pos) = walk.abs_pos {
535            self.turtle_walks.push(TurtleWalk {
536                align_start,
537                defer_index: 0,
538                rect: Rect {pos, size: size + walk.margin.size()}
539            });
540            
541            match turtle.layout.flow {
542                Flow::Right=>turtle.update_height_max(pos.y, size.y + walk.margin.size().y),
543                Flow::Down=>turtle.update_width_max(pos.x, size.x + walk.margin.size().x),
544                Flow::Overlay => { // do not walk
545                    turtle.update_width_max(pos.x, size.x);
546                    turtle.update_height_max(pos.y,size.y);
547                }
548                Flow::RightWrap=>{
549                    turtle.update_height_max(pos.y, size.y + walk.margin.size().y);
550                }
551            }
552            Rect {pos: pos + walk.margin.left_top(), size}
553        }
554        else {
555            let spacing = turtle.child_spacing(self.turtle_walks.len());
556            let mut pos = turtle.pos;
557            let margin_size = walk.margin.size();
558            let defer_index = turtle.defer_count;
559            match turtle.layout.flow {
560                Flow::Right => {
561                    turtle.pos.x = pos.x + size.x + margin_size.x + spacing.x;
562                    if size.x < 0.0 {
563                        turtle.update_width_min(turtle.pos.x, 0.0);
564                        turtle.update_height_max(turtle.pos.y,size.y + margin_size.y);
565                    }
566                    else {
567                        turtle.update_width_max(turtle.pos.x, 0.0);
568                        turtle.update_height_max(turtle.pos.y,size.y + margin_size.y);
569                    }
570                },
571                Flow::RightWrap => {
572                    if turtle.pos.x - turtle.origin.x + size.x > turtle.width - turtle.layout.padding.right{
573                        
574                        pos.x =  turtle.origin.x + turtle.layout.padding.left - spacing.x;
575                        let dx = pos.x - turtle.pos.x;
576                        turtle.pos.x = pos.x + size.x + margin_size.x + spacing.x;
577                        
578                        pos.y = turtle.height_used + turtle.origin.y + turtle.wrap_spacing + spacing.x;//turtle.layout.line_spacing;
579                        let dy = pos.y - turtle.pos.y;
580                        turtle.pos.y = pos.y;
581                        
582                        turtle.update_height_max(turtle.pos.y,size.y + margin_size.y);
583                                                
584                        if align_start != self.align_list.len(){
585                            self.move_align_list(dx, dy, align_start, self.align_list.len(), false, dvec2(0.0,0.0));
586                        }
587                    }
588                    else{
589                        turtle.pos.x = pos.x + size.x + margin_size.x + spacing.x;
590                        if size.x < 0.0 {
591                            turtle.update_width_min(turtle.pos.x, 0.0);
592                            turtle.update_height_max(turtle.pos.y,size.y + margin_size.y); 
593                        }
594                        else {
595                            turtle.update_width_max(turtle.pos.x, 0.0);
596                            turtle.update_height_max(turtle.pos.y,size.y + margin_size.y);
597                        }
598                    }
599                },
600                Flow::Down => {
601                    turtle.pos.y = pos.y + size.y + margin_size.y + spacing.y;
602                    if size.y < 0.0 {
603                        turtle.update_width_max(turtle.pos.x, size.x + margin_size.x);
604                        turtle.update_height_min(turtle.pos.y,0.0);
605                    }
606                    else {
607                        turtle.update_width_max(turtle.pos.x, size.x + margin_size.x);
608                        turtle.update_height_max(turtle.pos.y,0.0);
609                    }
610                },
611                Flow::Overlay => { // do not walk
612                    turtle.update_width_max(turtle.pos.x, size.x);
613                    turtle.update_height_max(turtle.pos.y,size.y);
614                }
615            };
616            
617            self.turtle_walks.push(TurtleWalk {
618                align_start,
619                defer_index,
620                rect: Rect {pos, size: size + margin_size}
621            });
622            Rect {pos: pos + walk.margin.left_top() + spacing, size}
623        }
624    }
625    
626    pub fn emit_turtle_walk(&mut self, rect:Rect){
627        let turtle = self.turtles.last().unwrap();
628        self.turtle_walks.push(TurtleWalk {
629            align_start: self.align_list.len(),
630            defer_index: turtle.defer_count,
631            rect
632        });
633    }
634    
635    fn walk_turtle_peek(&self, walk: Walk) -> Rect {
636        if self.turtles.len() == 0{
637            return Rect::default()
638        }
639        let turtle = self.turtles.last().unwrap();
640        let size = dvec2(
641            turtle.eval_width(walk.width, walk.margin, turtle.layout.flow),
642            turtle.eval_height(walk.height, walk.margin, turtle.layout.flow)
643        );
644        
645        if let Some(pos) = walk.abs_pos {
646            Rect {pos: pos + walk.margin.left_top(), size}
647        }
648        else {
649            let spacing = turtle.child_spacing(self.turtle_walks.len());
650            let pos = turtle.pos;
651            Rect {pos: pos + walk.margin.left_top() + spacing, size}
652        }
653    }
654    
655    
656    pub fn turtle_new_line(&mut self){
657        let turtle = self.turtles.last_mut().unwrap();
658        turtle.pos.x = turtle.origin.x + turtle.layout.padding.left;
659        let next_y = turtle.height_used + turtle.origin.y + turtle.wrap_spacing;
660        turtle.pos.y = turtle.pos.y.max(next_y);
661        turtle.height_used = turtle.pos.y - turtle.origin.y;
662        turtle.wrap_spacing = 0.0;
663    }
664
665    pub fn turtle_new_line_with_spacing(&mut self, spacing: f64){
666        let turtle = self.turtles.last_mut().unwrap();
667        turtle.pos.x = turtle.origin.x + turtle.layout.padding.left;
668        let next_y = turtle.height_used + turtle.origin.y + turtle.wrap_spacing + spacing;
669        turtle.pos.y = turtle.pos.y.max(next_y);
670        turtle.height_used = turtle.pos.y - turtle.origin.y;
671        turtle.wrap_spacing = 0.0;
672    }
673    
674    fn move_align_list(&mut self, dx: f64, dy: f64, align_start: usize, align_end: usize, shift_clip: bool, turtle_shift:DVec2) {
675        //let current_dpi_factor = self.current_dpi_factor();
676        let dx = if dx.is_nan() {0.0}else {dx} + turtle_shift.x;
677        let dy = if dy.is_nan() {0.0}else {dy} + turtle_shift.y;
678        if dx.abs() <  0.000000001 && dy.abs() <  0.000000001{
679            return 
680        }
681        //let dx = (dx * current_dpi_factor).floor() / current_dpi_factor;
682        //let dy = (dy * current_dpi_factor).floor() / current_dpi_factor;
683        let d = dvec2(dx, dy);
684        let mut c = align_start;
685        while c < align_end {
686            let align_item = &mut self.align_list[c];
687            match align_item {
688                AlignEntry::Area(Area::Instance(inst)) => {
689                    let draw_list = &mut self.cx.cx.draw_lists[inst.draw_list_id];
690                    let draw_item = &mut draw_list.draw_items[inst.draw_item_id];
691                    let draw_call = draw_item.draw_call().unwrap();
692                    let sh = &self.cx.cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
693                    let inst_buf = draw_item.instances.as_mut().unwrap();
694                    for i in 0..inst.instance_count {
695                        if let Some(rect_pos) = sh.mapping.rect_pos {
696                            inst_buf[inst.instance_offset + rect_pos + 0 + i * sh.mapping.instances.total_slots] += dx as f32;
697                            inst_buf[inst.instance_offset + rect_pos + 1 + i * sh.mapping.instances.total_slots] += dy as f32;
698                            if shift_clip{
699                                if let Some(draw_clip) = sh.mapping.draw_clip {
700                                    inst_buf[inst.instance_offset + draw_clip + 0 + i * sh.mapping.instances.total_slots] += dx as f32;
701                                    inst_buf[inst.instance_offset + draw_clip + 1 + i * sh.mapping.instances.total_slots] += dy as f32;
702                                    inst_buf[inst.instance_offset + draw_clip + 2 + i * sh.mapping.instances.total_slots] += dx as f32;
703                                    inst_buf[inst.instance_offset + draw_clip + 3 + i * sh.mapping.instances.total_slots] += dy as f32;
704                                }
705                            }
706                        }
707                    }
708                },
709                AlignEntry::Area(Area::Rect(ra)) => {
710                    let draw_list = &mut self.cx.draw_lists[ra.draw_list_id];
711                    let rect_area = &mut draw_list.rect_areas[ra.rect_id];
712                    rect_area.rect.pos += d;
713                    if shift_clip{
714                        rect_area.draw_clip.0 += d;
715                        rect_area.draw_clip.1 += d;
716                    }
717                }
718                AlignEntry::BeginTurtle(clip0, clip1)=>{
719                    *clip0 += d;
720                    *clip1 += d;
721                }
722                AlignEntry::SkipTurtle{skip} | AlignEntry::ShiftTurtle{skip,..} =>{
723                    c = *skip;
724                    continue;
725                }
726                _ => (),
727            }
728            c += 1;
729        }
730    }
731    
732    fn perform_nested_clipping_on_align_list_and_shift(&mut self, align_start:usize, align_end:usize){
733        self.turtle_clips.clear();
734        let mut i = align_start;
735        while i < align_end{
736            let align_item = &self.align_list[i];
737            match align_item {
738                AlignEntry::SkipTurtle{skip} =>{
739                    i = *skip;
740                    continue;
741                }
742                AlignEntry::ShiftTurtle{area, shift, skip} =>{
743                    let rect = area.rect(self);
744                    let skip = *skip;
745                    self.move_align_list(rect.pos.x+shift.x, rect.pos.y+shift.y, i + 1, skip, true, dvec2(0.0,0.0));
746                    i = skip;
747                    continue;
748                }
749                AlignEntry::BeginTurtle(clip0, clip1)=>{
750                    if let Some((tclip0, tclip1)) = self.turtle_clips.last(){
751                        self.turtle_clips.push((
752                            dvec2(clip0.x.max(tclip0.x),clip0.y.max(tclip0.y)),
753                            dvec2(clip1.x.min(tclip1.x),clip1.y.min(tclip1.y)),
754                        ));
755                    }
756                    else{
757                        self.turtle_clips.push((*clip0, *clip1));
758                    }
759                }
760                AlignEntry::EndTurtle=>{
761                    self.turtle_clips.pop().unwrap();
762                }
763                AlignEntry::Area(Area::Instance(inst)) => if let Some((clip0, clip1)) = self.turtle_clips.last(){
764                    let draw_list = &mut self.cx.cx.draw_lists[inst.draw_list_id];
765                    let draw_item = &mut draw_list.draw_items[inst.draw_item_id];
766                    let draw_call = draw_item.draw_call().unwrap();
767                    let sh = &self.cx.cx.draw_shaders[draw_call.draw_shader.draw_shader_id];
768                    let inst_buf = draw_item.instances.as_mut().unwrap();
769                    for i in 0..inst.instance_count {
770                        if let Some(draw_clip) = sh.mapping.draw_clip {
771                            inst_buf[inst.instance_offset + draw_clip + 0 + i * sh.mapping.instances.total_slots] = clip0.x as f32;
772                            inst_buf[inst.instance_offset + draw_clip + 1 + i * sh.mapping.instances.total_slots] = clip0.y as f32;
773                            inst_buf[inst.instance_offset + draw_clip + 2 + i * sh.mapping.instances.total_slots] = clip1.x as f32;
774                            inst_buf[inst.instance_offset + draw_clip + 3 + i * sh.mapping.instances.total_slots] = clip1.y as f32;
775                        }
776                    }
777                },
778                AlignEntry::Area(Area::Rect(ra)) => if let Some((clip0, clip1)) = self.turtle_clips.last(){
779                    let draw_list = &mut self.cx.draw_lists[ra.draw_list_id];
780                    let rect_area = &mut draw_list.rect_areas[ra.rect_id];
781                    rect_area.draw_clip.0 = *clip0;
782                    rect_area.draw_clip.1 = *clip1;
783                }
784                AlignEntry::Unset=>{}
785                AlignEntry::Area(_)=>{}
786            }
787            i += 1;
788        }
789    }
790    
791    fn get_turtle_walk_align_end(&self, i: usize) -> usize {
792        if i < self.turtle_walks.len() - 1 {
793            self.turtle_walks[i + 1].align_start
794        }
795        else {
796            self.align_list.len()
797        }
798    }
799    
800    pub fn get_turtle_align_range(&self) -> TurtleAlignRange {
801        TurtleAlignRange{
802            start:  self.turtles.last().unwrap().align_start,
803            end: self.align_list.len()
804        }
805    }
806    
807    pub fn shift_align_range(&mut self, range: &TurtleAlignRange, shift: DVec2) {
808        self.move_align_list(shift.x, shift.y, range.start, range.end, true, dvec2(0.0,0.0));
809    }
810    
811    pub fn add_rect_area(&mut self, area: &mut Area, rect: Rect) {
812        //let turtle = self.turtle();
813        self.add_aligned_rect_area(area, rect)
814    }
815}
816
817pub struct TurtleAlignRange{
818    start: usize,
819    end: usize
820}
821
822impl Turtle {
823    pub fn row_height(&self)->f64{
824        self.height_used - (self.pos.y - self.origin.y) + self.wrap_spacing
825    }
826    
827    pub fn update_width_max(&mut self, pos:f64, dx: f64) {
828        self.width_used = self.width_used.max((pos + dx) - self.origin.x);
829    }
830    
831    pub fn update_height_max(&mut self, pos:f64, dy: f64) {
832        self.height_used = self.height_used.max((pos + dy) - self.origin.y);
833    }
834    
835    pub fn update_width_min(&mut self, pos:f64, dx: f64) {
836        self.width_used = self.width_used.min((pos + dx) - self.origin.x);
837    }
838    
839    pub fn update_height_min(&mut self, pos:f64, dy: f64) {
840        self.height_used = self.height_used.min((pos + dy) - self.origin.y);
841    }
842    
843    pub fn set_shift(&mut self, shift: DVec2) {
844        self.shift = shift;
845    }
846    
847    pub fn layout(&self)->&Layout{
848        &self.layout
849    }
850
851    pub fn layout_mut(&mut self)-> &mut Layout {
852        &mut self.layout
853    }
854    
855    pub fn used(&self) -> DVec2 {
856        dvec2(self.width_used, self.height_used)
857    }
858    
859    pub fn set_used(&mut self, width_used: f64, height_used: f64) {
860        self.width_used = width_used;
861        self.height_used = height_used;
862    }
863    
864    
865    /*
866    pub fn move_pos(&mut self, dx: f64, dy: f64) {
867        self.pos.x += dx;
868        self.pos.y += dy;
869        self.update_width_max(0.0);
870        self.update_height_max(0.0);
871    }
872    */
873         
874        
875    pub fn set_wrap_spacing(&mut self, value: f64){
876        self.wrap_spacing = self.wrap_spacing.max(value);
877    }
878    
879    pub fn set_pos(&mut self, pos: DVec2) {
880        self.pos = pos
881    }
882    
883    fn child_spacing(&self, walks_len: usize) -> DVec2 {
884        if self.turtle_walks_start < walks_len || self.defer_count > 0 {
885            match self.layout.flow {
886                Flow::Right => {
887                    dvec2(self.layout.spacing, 0.0)
888                }
889                Flow::Down => {
890                    dvec2(0.0, self.layout.spacing)
891                }
892                Flow::Overlay => {
893                    dvec2(0.0, 0.0)
894                }
895                Flow::RightWrap=>{
896                    dvec2(self.layout.spacing, 0.0)
897                }
898            }
899        }
900        else {
901            dvec2(0.0, 0.0)
902        }
903    }
904        
905    pub fn rect_is_visible(&self,  geom: Rect) -> bool {
906        let view = Rect {pos: self.origin + self.layout.scroll, size: dvec2(self.width, self.height)};
907        return view.intersects(geom)
908    }
909    
910    
911    pub fn origin(&self) -> DVec2 {
912        self.origin
913    }
914    
915    pub fn rel_pos(&self) -> DVec2 {
916        DVec2 {
917            x: self.pos.x - self.origin.x,
918            y: self.pos.y - self.origin.y
919        }
920    }
921    
922    pub fn rel_pos_padded(&self) -> DVec2 {
923        DVec2 {
924            x: self.pos.x - self.origin.x - self.layout.padding.left,
925            y: self.pos.y - self.origin.y - self.layout.padding.right
926        }
927    }
928    
929    pub fn pos(&self) -> DVec2 {
930        self.pos
931    }
932
933    pub fn scroll(&self) -> DVec2 {
934        self.layout.scroll
935    }
936
937    pub fn max_width(&self, walk: Walk) -> Option<f64> {
938        if walk.width.is_fit() {
939            return None;
940        }
941        Some(self.eval_width(walk.width, walk.margin, self.layout().flow) as f64)
942    }
943
944    pub fn max_height(&self, walk: Walk) -> Option<f64> {
945        if walk.height.is_fit() {
946            return None
947        }
948        Some(self.eval_width(walk.height, walk.margin, self.layout().flow) as f64)
949    }
950    
951    pub fn eval_width(&self, width: Size, margin: Margin, flow: Flow) -> f64 {
952        return match width {
953            Size::Fit => std::f64::NAN,
954            Size::Fixed(v) => max_zero_keep_nan(v),
955            Size::Fill => {
956                match flow {
957                    Flow::RightWrap=> {
958                        max_zero_keep_nan(self.width - (self.pos.x - self.origin.x) - margin.width() -self.layout.padding.right)
959                    }
960                    Flow::Right => {
961                        max_zero_keep_nan(self.width_left() - margin.width())
962                    },
963                    Flow::Down | Flow::Overlay => {
964                        let r = max_zero_keep_nan(self.width - self.layout.padding.width() - margin.width());
965                        if r.is_nan() {
966                            return self.width_used - margin.width() - self.layout.padding.right
967                        }
968                        return r
969                    }
970                }
971            },
972            Size::All=>self.width
973        }
974    }
975    
976    pub fn eval_height(&self, height: Size, margin: Margin, flow: Flow) -> f64 {
977        return match height {
978            Size::Fit => std::f64::NAN,
979            Size::Fixed(v) => max_zero_keep_nan(v),
980            Size::Fill => {
981                match flow {
982                    Flow::RightWrap | Flow::Right | Flow::Overlay => {
983                        let r = max_zero_keep_nan(self.height - self.layout.padding.height() - margin.height());
984                        if r.is_nan() {
985                            return self.height_used - margin.height() - self.layout.padding.bottom
986                        }
987                        return r
988                    }
989                    Flow::Down => {
990                        max_zero_keep_nan(self.height_left() - margin.height())
991                    }
992                }
993            }
994            Size::All=>self.height
995        }
996    }
997    
998    pub fn rect(&self) -> Rect {
999        Rect {
1000            pos: self.origin,
1001            size: dvec2(self.width, self.height)
1002        }
1003    }
1004    
1005   pub fn unscrolled_rect(&self) -> Rect {
1006        Rect {
1007            pos: self.origin + self.layout.scroll,
1008            size: dvec2(self.width, self.height)
1009        }
1010    }
1011    
1012    pub fn padded_rect_used(&self) -> Rect {
1013        Rect {
1014            pos: self.origin + self.layout.padding.left_top(),
1015            size: self.used() - self.layout.padding.left_top()
1016        }
1017    }
1018    pub fn rect_left(&self) -> Rect {
1019        Rect {
1020            pos: self.pos,
1021            size: dvec2(self.width_left(), self.height_left())
1022        }
1023    }
1024    
1025    pub fn padded_rect(&self) -> Rect {
1026        Rect {
1027            pos: self.origin + self.layout.padding.left_top(),
1028            size: dvec2(self.width, self.height) - self.layout.padding.size()
1029        }
1030    }
1031    
1032    pub fn size(&self) -> DVec2 {
1033        dvec2(self.width, self.height)
1034    }
1035    
1036    pub fn width_left(&self) -> f64 {
1037        return max_zero_keep_nan(self.width - self.width_used - self.layout.padding.right);
1038    }
1039    
1040    pub fn height_left(&self) -> f64 {
1041        return max_zero_keep_nan(self.height - self.height_used - self.layout.padding.bottom);
1042    }
1043    
1044    pub fn padded_height_or_used(&self) -> f64 {
1045        let r = max_zero_keep_nan(self.height - self.layout.padding.height());
1046        if r.is_nan() {
1047            self.height_used - self.layout.padding.bottom
1048        }
1049        else {
1050            r
1051        }
1052    }
1053    
1054    pub fn padded_width_or_used(&self) -> f64 {
1055        let r = max_zero_keep_nan(self.width - self.layout.padding.width());
1056        if r.is_nan() {
1057            self.width_used - self.layout.padding.right
1058        }
1059        else {
1060            r
1061        }
1062    }
1063}
1064
1065impl DeferWalk {
1066    
1067    pub fn resolve(&mut self, cx: &Cx2d) -> Walk {
1068        match self{
1069            Self::Resolved(walk)=>{*walk},
1070            Self::Unresolved{pos, defer_index, margin, other_axis}=>{
1071                let turtle = cx.turtles.last().unwrap();
1072                let walk = match turtle.layout.flow {
1073                    Flow::Right => {
1074                        let left = turtle.width_left();
1075                        let part = left / turtle.defer_count as f64;
1076                        Walk {
1077                            abs_pos: Some(*pos + dvec2(part * *defer_index as f64, 0.)),
1078                            margin: *margin,
1079                            width: Size::Fixed(part),
1080                            height: *other_axis
1081                        }
1082                    },
1083                    Flow::RightWrap => {
1084                        panic!()
1085                    }
1086                    Flow::Down => { 
1087                        let left = turtle.height_left();
1088                        let part = left / turtle.defer_count as f64;
1089                        Walk {
1090                            abs_pos: Some(*pos + dvec2(0., part * *defer_index as f64)),
1091                            margin: *margin,
1092                            height: Size::Fixed(part),
1093                            width: *other_axis
1094                        }
1095                    }
1096                    Flow::Overlay => panic!()
1097                };
1098                *self = DeferWalk::Resolved(walk);
1099                walk
1100            }
1101        }
1102    }
1103    
1104}
1105
1106impl Layout {
1107    pub fn flow_right() -> Self {
1108        Self {
1109            flow: Flow::Right,
1110            ..Self::default()
1111        }
1112    }
1113    
1114    pub fn flow_down() -> Self {
1115        Self {
1116            flow: Flow::Down,
1117            ..Self::default()
1118        }
1119    }
1120    
1121    pub fn flow_overlay() -> Self {
1122        Self {
1123            flow: Flow::Overlay,
1124            ..Self::default()
1125        }
1126    }
1127
1128    pub fn with_scroll(mut self, v: DVec2) -> Self {
1129        self.scroll = v;
1130        self
1131    }
1132    
1133    pub fn with_align_x(mut self, v: f64) -> Self {
1134        self.align.x = v;
1135        self
1136    }
1137    
1138    pub fn with_align_y(mut self, v: f64) -> Self {
1139        self.align.y = v;
1140        self
1141    }
1142    
1143    pub fn with_clip(mut self, clip_x:bool, clip_y:bool) -> Self {
1144        self.clip_x = clip_x;
1145        self.clip_y = clip_y;
1146        self
1147    }
1148    
1149    pub fn with_padding_all(mut self, v: f64) -> Self {
1150        self.padding = Padding {left: v, right: v, top: v, bottom: v};
1151        self
1152    }
1153    
1154    pub fn with_padding_top(mut self, v: f64) -> Self {
1155        self.padding.top = v;
1156        self
1157    }
1158    
1159    pub fn with_padding_right(mut self, v: f64) -> Self {
1160        self.padding.right = v;
1161        self
1162    }
1163    
1164    pub fn with_padding_bottom(mut self, v: f64) -> Self {
1165        self.padding.bottom = v;
1166        self
1167    }
1168    
1169    pub fn with_padding_left(mut self, v: f64) -> Self {
1170        self.padding.left = v;
1171        self
1172    }
1173    
1174    pub fn with_padding(mut self, v: Padding) -> Self {
1175        self.padding = v;
1176        self
1177    }
1178}
1179
1180impl Walk {
1181    pub fn empty() -> Self {
1182        Self {
1183            abs_pos: None,
1184            margin: Margin::default(),
1185            width: Size::Fixed(0.0),
1186            height: Size::Fixed(0.0),
1187        }
1188    }
1189    
1190    pub fn size(w: Size, h: Size) -> Self {
1191        Self {
1192            abs_pos: None,
1193            margin: Margin::default(),
1194            width: w,
1195            height: h,
1196        }
1197    }
1198
1199    pub fn abs_rect(rect:Rect) -> Self {
1200        Self {
1201            abs_pos: Some(rect.pos),
1202            margin: Margin::default(),
1203            width: Size::Fixed(rect.size.x),
1204            height: Size::Fixed(rect.size.y),
1205        }
1206    }
1207    
1208    pub fn fixed(w:f64, h:f64) -> Self {
1209        Self {
1210            abs_pos: None,
1211            margin: Margin::default(),
1212            width: Size::Fixed(w),
1213            height: Size::Fixed(h),
1214        }
1215    }
1216        
1217    pub fn fixed_size(size: DVec2) -> Self {
1218        Self {
1219            abs_pos: None,
1220            margin: Margin::default(),
1221            width: Size::Fixed(size.x),
1222            height: Size::Fixed(size.y),
1223        }
1224    }
1225    
1226    pub fn fit() -> Self {
1227        Self {
1228            abs_pos: None,
1229            margin: Margin::default(),
1230            width: Size::Fit,
1231            height: Size::Fit,
1232        }
1233    }
1234    
1235    pub fn fill() -> Self {
1236        Self {
1237            abs_pos: None,
1238            margin: Margin::default(),
1239            width: Size::Fill,
1240            height: Size::Fill,
1241        }
1242    }
1243    
1244    pub fn fill_fit() -> Self {
1245        Self {
1246            abs_pos: None,
1247            margin: Margin::default(),
1248            width: Size::Fill,
1249            height: Size::Fit,
1250        }
1251    }
1252    
1253    pub fn with_abs_pos(mut self, v: DVec2) -> Self {
1254        self.abs_pos = Some(v);
1255        self
1256    }
1257    pub fn with_margin_all(mut self, v: f64) -> Self {
1258        self.margin = Margin {left: v, right: v, top: v, bottom: v};
1259        self
1260    }
1261    
1262    pub fn with_margin_top(mut self, v: f64) -> Self {
1263        self.margin.top = v;
1264        self
1265    }
1266    
1267    pub fn with_margin_right(mut self, v: f64) -> Self {
1268        self.margin.right = v;
1269        self
1270    }
1271    
1272    pub fn with_margin_bottom(mut self, v: f64) -> Self {
1273        self.margin.bottom = v;
1274        self
1275    }
1276    
1277    pub fn with_margin_left(mut self, v: f64) -> Self {
1278        self.margin.left = v;
1279        self
1280    }
1281    
1282    pub fn with_margin(mut self, v: Margin) -> Self {
1283        self.margin = v;
1284        self
1285    }
1286    
1287    pub fn with_add_padding(mut self, v: Padding) -> Self {
1288        self.margin.top += v.top;
1289        self.margin.left += v.left;
1290        self.margin.right += v.right;
1291        self.margin.bottom += v.bottom;
1292        self
1293    }
1294}
1295
1296impl Padding {
1297    pub fn left_top(&self) -> DVec2 {
1298        dvec2(self.left, self.top)
1299    }
1300    pub fn right_bottom(&self) -> DVec2 {
1301        dvec2(self.right, self.bottom)
1302    }
1303    pub fn size(&self) -> DVec2 {
1304        dvec2(self.left + self.right, self.top + self.bottom)
1305    }
1306    pub fn width(&self) -> f64 {
1307        self.left + self.right
1308    }
1309    pub fn height(&self) -> f64 {
1310        self.top + self.bottom
1311    }
1312}
1313
1314impl LiveHook for Padding {
1315    fn skip_apply(&mut self, _cx: &mut Cx, _apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> Option<usize> {
1316        if let Some(v) = nodes[index].value.as_float(){
1317            *self = Self {left: v, top: v, right: v, bottom: v};
1318            Some(index + 1)
1319        }
1320        else{
1321            None
1322        }
1323    }
1324}
1325
1326impl Default for Flow {
1327    fn default() -> Self {Self::Down}
1328}
1329
1330
1331impl LiveHook for Size {
1332    fn skip_apply(&mut self, cx: &mut Cx, _apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> Option<usize> {
1333        match &nodes[index].value {
1334            LiveValue::Array => {
1335                fn last_keyframe_value_from_array(index: usize, nodes: &[LiveNode]) -> Option<usize> {
1336                    if let Some(index) = nodes.last_child(index) {
1337                        if nodes[index].value.is_object() {
1338                            return nodes.child_by_name(index, live_id!(value).as_field());
1339                        }
1340                        else {
1341                            return Some(index)
1342                        }
1343                    }
1344                    None
1345                }
1346
1347                if let Some(inner_index) = last_keyframe_value_from_array(index, nodes) {
1348                    match &nodes[inner_index].value {
1349                        LiveValue::Float64(val) => {
1350                            *self = Self::Fixed(*val);
1351                        }
1352                        LiveValue::Int64(val) => {
1353                            *self = Self::Fixed(*val as f64);
1354                        }
1355                        _ => {
1356                            cx.apply_error_wrong_value_type_for_primitive(live_error_origin!(), index, nodes, "Animation array");
1357                        }
1358                    }
1359                }
1360                else {
1361                    cx.apply_error_wrong_value_type_for_primitive(live_error_origin!(), index, nodes, "Animation array");
1362                }
1363                Some(nodes.skip_node(index))
1364            }
1365            LiveValue::Expr {..} => {
1366                panic!("Expr node found whilst deserialising DSL")
1367            },
1368            LiveValue::Float32(v) => {
1369                *self = Self::Fixed(*v as f64);
1370                Some(index + 1)
1371            }
1372            LiveValue::Float64(v) => {
1373                *self = Self::Fixed(*v);
1374                Some(index + 1)
1375            }
1376            LiveValue::Int64(v) => {
1377                *self = Self::Fixed(*v as f64);
1378                Some(index + 1)
1379            }
1380            _ => None
1381        }
1382    }
1383}
1384
1385impl Default for Size {
1386    fn default() -> Self {
1387        Size::Fill
1388    }
1389}
1390
1391impl Size {
1392    pub fn fixed_or_zero(&self) -> f64 {
1393        match self {
1394            Self::Fixed(v) => *v,
1395            _ => 0.
1396        }
1397    }
1398    
1399    pub fn fixed_or_nan(&self) -> f64 {
1400        match self {
1401            Self::Fixed(v) => max_zero_keep_nan(*v),
1402            _ => std::f64::NAN,
1403        }
1404    }
1405
1406    pub fn is_fixed(&self) -> bool {
1407        match self {
1408            Self::Fixed(_) => true,
1409            _ => false
1410        }
1411    }
1412
1413    pub fn is_fit(&self) -> bool {
1414        match self {
1415            Self::Fit => true,
1416            _ => false
1417        }
1418    }
1419    
1420    pub fn is_fill(&self) -> bool {
1421        match self {
1422            Self::Fill => true,
1423            _ => false
1424        }
1425    }
1426}
1427
1428fn max_zero_keep_nan(v: f64) -> f64 {
1429    if v.is_nan() {
1430        v
1431    }
1432    else {
1433        f64::max(v, 0.0)
1434    }
1435}