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 self.align_list.push(AlignEntry::EndTurtle);
220 self.perform_nested_clipping_on_align_list_and_shift(turtle.align_start, self.align_list.len());
221 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 self.align_list.push(AlignEntry::EndTurtle);
230 self.perform_nested_clipping_on_align_list_and_shift(turtle.align_start, self.align_list.len());
231 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 let (x0, x1) = if layout.clip_x {
252 (o.x, if w.is_nan() {
253 f64::NAN
254 } else {
256 o.x + w})
258 } else {
259 (f64::NAN, f64::NAN)};
261
262 let (y0, y1) = if layout.clip_y {
263 (o.y, if h.is_nan() {
264 f64::NAN
265 } else {
266 o.y + h})
268 }else {(f64::NAN,f64::NAN)};(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 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 => { 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 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 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 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 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