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 }
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 }
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 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 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 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 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 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 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 let (x0, x1) = if layout.clip_x {
288 (o.x, if w.is_nan() {
289 f64::NAN
290 } else {
292 o.x + w})
294 } else {
295 (f64::NAN, f64::NAN)};
297
298 let (y0, y1) = if layout.clip_y {
299 (o.y, if h.is_nan() {
300 f64::NAN
301 } else {
302 o.y + h})
304 }else {(f64::NAN,f64::NAN)};(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 let w = if turtle.width.is_nan() {
367 let w = turtle.width_used + turtle.layout.padding.right - turtle.layout.scroll.x;
368 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 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 }
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 => { 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;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 => { 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 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 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 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 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}