makepad_draw/
turtle.rs

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