1use crate::cx::*;
2use makepad_tinyserde::*;
3
4impl Cx {
5 pub fn set_count_of_aligned_instance(&mut self, instance_count: usize) -> Area {
10 let mut area = self.align_list.last_mut().unwrap();
11 if let Area::Instance(inst) = &mut area {
12 inst.instance_count = instance_count;
13 }
14 area.clone()
15 }
16
17 pub fn begin_turtle(&mut self, layout: Layout, guard_area: Area) {
19
20 if !self.is_in_redraw_cycle {
21 panic!("calling begin_turtle outside of redraw cycle is not possible!");
22 }
23
24 let (mut origin, mut abs_size) = if let Some(parent) = self.turtles.last() {
26 (Vec2 {x: layout.walk.margin.l + parent.pos.x, y: layout.walk.margin.t + parent.pos.y}, parent.abs_size)
27 }
28 else {
29 (Vec2 {x: layout.walk.margin.l, y: layout.walk.margin.t}, Vec2::default())
30 };
31
32 if let Some(layout_abs_size) = layout.abs_size {
34 abs_size = layout_abs_size;
35 }
36
37 let is_abs_origin;
39 if let Some(abs_origin) = layout.abs_origin {
40 origin = abs_origin;
41 is_abs_origin = true;
42 }
43 else {
44 is_abs_origin = false;
45 }
46
47 let (width, min_width) = layout.walk.width.eval_width(self, layout.walk.margin, is_abs_origin, abs_size.x);
49 let (height, min_height) = layout.walk.height.eval_height(self, layout.walk.margin, is_abs_origin, abs_size.y);
50
51 let turtle = Turtle {
52 align_list_x: self.align_list.len(),
53 align_list_y: self.align_list.len(),
54 origin: origin,
55 pos: Vec2 {x: origin.x + layout.padding.l, y: origin.y + layout.padding.t},
56 layout: layout,
57 biggest: 0.0,
58 bound_left_top: Vec2 {x: std::f32::INFINITY, y: std::f32::INFINITY},
59 bound_right_bottom: Vec2 {x: std::f32::NEG_INFINITY, y: std::f32::NEG_INFINITY},
60 width: width,
61 height: height,
62 min_width: min_width,
63 min_height: min_height,
64 width_used: 0.,
65 height_used: 0.,
66 abs_size: abs_size,
67 guard_area: guard_area,
68 };
70
71 self.turtles.push(turtle);
72 }
73
74 pub fn end_turtle(&mut self, guard_area: Area) -> Rect {
75 let old = self.turtles.pop().unwrap();
76 if guard_area != old.guard_area {
77 panic!("End turtle guard area misaligned!, begin/end pair not matched begin {:?} end {:?}", old.guard_area, guard_area)
78 }
79
80 let w = if old.width.is_nan() {
81 if old.bound_right_bottom.x == std::f32::NEG_INFINITY { Width::Fix(old.layout.padding.l + old.layout.padding.r)
83 }
84 else { Width::Fix(max_zero_keep_nan(old.bound_right_bottom.x - old.origin.x + old.layout.padding.r).max(old.min_width))
86 }
87 }
88 else {
89 Width::Fix(old.width)
90 };
91
92 let h = if old.height.is_nan() {
93 if old.bound_right_bottom.y == std::f32::NEG_INFINITY { Height::Fix(old.layout.padding.t + old.layout.padding.b)
95 }
96 else { Height::Fix(max_zero_keep_nan(old.bound_right_bottom.y - old.origin.y + old.layout.padding.b).max(old.min_height))
98 }
99 }
100 else {
101 Height::Fix(old.height)
102 };
103
104 let margin = old.layout.walk.margin.clone();
105 let dx = Self::compute_align_turtle_x(&old);
107 if dx > 0.0 {
108 self.do_align_x(dx, old.align_list_x);
109 }
110 let dy = Self::compute_align_turtle_y(&old);
111 if dy > 0.0 {
112 self.do_align_y(dy, old.align_list_y);
113 }
114
115 if !old.layout.abs_origin.is_none() {
117 let abs_origin = if let Some(abs_origin) = old.layout.abs_origin {abs_origin} else {Vec2::default()};
118 let w = if let Width::Fix(vw) = w {vw} else {0.};
119 let h = if let Height::Fix(vh) = h {vh} else {0.};
120 return Rect {x: abs_origin.x, y: abs_origin.y, w: w, h: h};
121 }
122
123 return self.walk_turtle_with_old(Walk {width: w, height: h, margin}, Some(&old))
124 }
125
126 pub fn walk_turtle(&mut self, walk: Walk) -> Rect {
127 self.walk_turtle_with_old(walk, None)
128 }
129
130 pub fn walk_turtle_with_old(&mut self, walk: Walk, old_turtle: Option<&Turtle>) -> Rect {
132 let mut align_dx = 0.0;
133 let mut align_dy = 0.0;
134 let (w,_mw) = walk.width.eval_width(self, walk.margin, false, 0.0);
135 let (h,_mh) = walk.height.eval_height(self, walk.margin, false, 0.0);
136
137 let ret = if let Some(turtle) = self.turtles.last_mut() {
138 let (x, y) = match turtle.layout.direction {
139 Direction::Right => {
140 match turtle.layout.line_wrap {
141 LineWrap::NewLine => {
142 if (turtle.pos.x + walk.margin.l + w) >
143 (turtle.origin.x + turtle.width - turtle.layout.padding.r) {
144 let old_x = turtle.pos.x;
146 let old_y = turtle.pos.y;
147 turtle.pos.x = turtle.origin.x + turtle.layout.padding.l;
148 turtle.pos.y += turtle.biggest;
149 turtle.biggest = 0.0;
150 align_dx = turtle.pos.x - old_x;
151 align_dy = turtle.pos.y - old_y;
152 }
153 },
154 LineWrap::MaxSize(max_size) => {
155 let new_size = turtle.pos.x + walk.margin.l + w;
156 if new_size > (turtle.origin.x + turtle.width - turtle.layout.padding.r)
157 || new_size > (turtle.origin.x + max_size - turtle.layout.padding.r) {
158 let old_x = turtle.pos.x;
160 let old_y = turtle.pos.y;
161 turtle.pos.x = turtle.origin.x + turtle.layout.padding.l;
162 turtle.pos.y += turtle.biggest;
163 turtle.biggest = 0.0;
164 align_dx = turtle.pos.x - old_x;
165 align_dy = turtle.pos.y - old_y;
166 }
167 },
168 LineWrap::None => {
169 }
170 }
171
172 let x = turtle.pos.x + walk.margin.l;
173 let y = turtle.pos.y + walk.margin.t;
174 turtle.pos.x += w + walk.margin.l + walk.margin.r;
176
177 let biggest = h + walk.margin.t + walk.margin.b;
179 if biggest > turtle.biggest {
180 turtle.biggest = biggest;
181 }
182 (x, y)
183 },
184 Direction::Down => {
185 match turtle.layout.line_wrap {
186 LineWrap::NewLine => {
187 if (turtle.pos.y + walk.margin.t + h) >
188 (turtle.origin.y + turtle.height - turtle.layout.padding.b) {
189 let old_x = turtle.pos.x;
191 let old_y = turtle.pos.y;
192 turtle.pos.y = turtle.origin.y + turtle.layout.padding.t;
193 turtle.pos.x += turtle.biggest;
194 turtle.biggest = 0.0;
195 align_dx = turtle.pos.x - old_x;
196 align_dy = turtle.pos.y - old_y;
197 }
198 },
199 LineWrap::MaxSize(max_size) => {
200 let new_size = turtle.pos.y + walk.margin.t + h;
201 if new_size > (turtle.origin.y + turtle.height - turtle.layout.padding.b)
202 || new_size > (turtle.origin.y + max_size - turtle.layout.padding.b) {
203 let old_x = turtle.pos.x;
205 let old_y = turtle.pos.y;
206 turtle.pos.y = turtle.origin.y + turtle.layout.padding.t;
207 turtle.pos.x += turtle.biggest;
208 turtle.biggest = 0.0;
209 align_dx = turtle.pos.x - old_x;
210 align_dy = turtle.pos.y - old_y;
211 }
212 },
213 LineWrap::None => {
214 }
215 }
216
217 let x = turtle.pos.x + walk.margin.l;
218 let y = turtle.pos.y + walk.margin.t;
219 turtle.pos.y += h + walk.margin.t + walk.margin.b;
221
222 let biggest = w + walk.margin.r + walk.margin.l;
224 if biggest > turtle.biggest {
225 turtle.biggest = biggest;
226 }
227 (x, y)
228 },
229 _ => {
230 (turtle.pos.x + walk.margin.l, turtle.pos.y + walk.margin.t)
231 }
232 };
233
234 let bound_x2 = x + w + if walk.margin.r < 0. {walk.margin.r} else {0.};
235 if bound_x2 > turtle.bound_right_bottom.x {
236 turtle.bound_right_bottom.x = bound_x2;
237 }
238 let bound_y2 = y + h + walk.margin.t + if walk.margin.b < 0. {walk.margin.b} else {0.};
240 if bound_y2 > turtle.bound_right_bottom.y {
241 turtle.bound_right_bottom.y = bound_y2;
242 }
243
244 if x < turtle.bound_left_top.x {
245 turtle.bound_left_top.x = x;
246 }
247 if y < turtle.bound_left_top.y {
248 turtle.bound_left_top.y = y;
249 }
250 Rect {
253 x: x,
254 y: y,
255 w: w,
256 h: h
257 }
258 }
259 else {
260 Rect {
261 x: 0.0,
262 y: 0.0,
263 w: w,
264 h: h
265 }
266 };
267
268 if align_dx != 0.0 {
269 if let Some(old_turtle) = old_turtle {
270 self.do_align_x(align_dx, old_turtle.align_list_x);
271 }
272 };
273 if align_dy != 0.0 {
274 if let Some(old_turtle) = old_turtle {
275 self.do_align_y(align_dy, old_turtle.align_list_y);
276 }
277 };
278
279 ret
280 }
281
282 pub fn walk_turtle_right_no_wrap(&mut self, w: f32, h: f32, scroll: Vec2) -> Option<Rect> {
284 if let Some(turtle) = self.turtles.last_mut() {
285 let x = turtle.pos.x;
286 let y = turtle.pos.y;
287 turtle.pos.x += w;
289
290 let biggest = h;
292 if biggest > turtle.biggest {
293 turtle.biggest = biggest;
294 }
295 let bound_x2 = x + w;
297 if bound_x2 > turtle.bound_right_bottom.x {
298 turtle.bound_right_bottom.x = bound_x2;
299 }
300 let bound_y2 = turtle.pos.y + h;
302 if bound_y2 > turtle.bound_right_bottom.y {
303 turtle.bound_right_bottom.y = bound_y2;
304 }
305
306 let vx = turtle.origin.x + scroll.x;
307 let vy = turtle.origin.y + scroll.y;
308 let vw = turtle.width;
309 let vh = turtle.height;
310
311 if x > vx + vw || x + w < vx || y > vy + vh || y + h < vy {
312 None
313 }
314 else {
315 Some(Rect {
316 x: x,
317 y: y,
318 w: w,
319 h: h
320 })
321 }
322 }
323 else {
324 None
325 }
326 }
327
328 pub fn turtle_new_line(&mut self) {
329 if let Some(turtle) = self.turtles.last_mut() {
330 match turtle.layout.direction {
331 Direction::Right => {
332 turtle.pos.x = turtle.origin.x + turtle.layout.padding.l;
333 turtle.pos.y += turtle.biggest + turtle.layout.new_line_padding;
334 turtle.biggest = 0.0;
335 },
336 Direction::Down => {
337 turtle.pos.y = turtle.origin.y + turtle.layout.padding.t;
338 turtle.pos.x += turtle.biggest + turtle.layout.new_line_padding;
339 turtle.biggest = 0.0;
340 },
341 _ => ()
342 }
343 }
344 }
345
346 pub fn turtle_line_is_visible(&mut self, min_height: f32, scroll: Vec2) -> bool {
347 if let Some(turtle) = self.turtles.last_mut() {
348 let y = turtle.pos.y;
349 let h = turtle.biggest.max(min_height);
350 let vy = turtle.origin.y + scroll.y;
351 let vh = turtle.height;
352
353 if y > vy + vh || y + h < vy {
354 return false
355 }
356 else {
357 return true
358 }
359 }
360 false
361 }
362
363 pub fn turtle_new_line_min_height(&mut self, min_height: f32) {
364 if let Some(turtle) = self.turtles.last_mut() {
365 turtle.pos.x = turtle.origin.x + turtle.layout.padding.l;
366 turtle.pos.y += turtle.biggest.max(min_height);
367 turtle.biggest = 0.0;
368 }
369 }
370
371 fn do_align_x(&mut self, dx: f32, align_start: usize) {
372 let dx = (dx * self.current_dpi_factor).floor() / self.current_dpi_factor;
373 for i in align_start..self.align_list.len() {
374 let align_item = &self.align_list[i];
375 match align_item {
376 Area::Instance(inst) => {
377 let cxview = &mut self.views[inst.view_id];
378 let draw_call = &mut cxview.draw_calls[inst.draw_call_id];
379 let sh = &self.shaders[draw_call.shader_id];
380 for i in 0..inst.instance_count {
381 if let Some(x) = sh.mapping.rect_instance_props.x {
382 draw_call.instance[inst.instance_offset + x + i * sh.mapping.instance_slots] += dx;
383 }
384 }
385 },
386 _ => (),
387 }
388 }
389 }
390
391 fn do_align_y(&mut self, dy: f32, align_start: usize) {
392 let dy = (dy * self.current_dpi_factor).floor() / self.current_dpi_factor;
393 for i in align_start..self.align_list.len() {
394 let align_item = &self.align_list[i];
395 match align_item {
396 Area::Instance(inst) => {
397 let cxview = &mut self.views[inst.view_id];
398 let draw_call = &mut cxview.draw_calls[inst.draw_call_id];
399 let sh = &self.shaders[draw_call.shader_id];
400 for i in 0..inst.instance_count {
401 if let Some(y) = sh.mapping.rect_instance_props.y {
402 draw_call.instance[inst.instance_offset + y + i * sh.mapping.instance_slots] += dy;
403 }
404 }
405 },
406 _ => (),
407 }
408 }
409 }
410
411 pub fn get_turtle_rect(&self) -> Rect {
412 if let Some(turtle) = self.turtles.last() {
413 return Rect {
414 x: turtle.origin.x,
415 y: turtle.origin.y,
416 w: turtle.width,
417 h: turtle.height
418 }
419 };
420 return Rect::default();
421 }
422
423 pub fn get_turtle_biggest(&self) -> f32 {
424 if let Some(turtle) = self.turtles.last() {
425 turtle.biggest
426 }
427 else {
428 0.
429 }
430 }
431
432 pub fn get_turtle_bounds(&self) -> Vec2 {
433 if let Some(turtle) = self.turtles.last() {
434
435 return Vec2 {
436 x: if turtle.bound_right_bottom.x<0. {0.}else {turtle.bound_right_bottom.x} + turtle.layout.padding.r - turtle.origin.x,
437 y: if turtle.bound_right_bottom.y<0. {0.}else {turtle.bound_right_bottom.y} + turtle.layout.padding.b - turtle.origin.y
438 };
439 }
440 return Vec2::default()
441 }
442
443 pub fn set_turtle_bounds(&mut self, bound: Vec2) {
444 if let Some(turtle) = self.turtles.last_mut() {
445 turtle.bound_right_bottom = Vec2 {
446 x: bound.x - turtle.layout.padding.r + turtle.origin.x,
447 y: bound.y - turtle.layout.padding.b + turtle.origin.y
448 }
449 }
450 }
451
452 pub fn get_turtle_origin(&self) -> Vec2 {
453 if let Some(turtle) = self.turtles.last() {
454 return turtle.origin;
455 }
456 return Vec2::default()
457 }
458
459 pub fn move_turtle(&mut self, dx: f32, dy: f32) {
460 if let Some(turtle) = self.turtles.last_mut() {
461 turtle.pos.x += dx;
462 turtle.pos.y += dy;
463 }
464 }
465
466 pub fn get_turtle_pos(&self) -> Vec2 {
467 if let Some(turtle) = self.turtles.last() {
468 turtle.pos
469 }
470 else {
471 Vec2::default()
472 }
473 }
474
475 pub fn set_turtle_pos(&mut self, pos: Vec2) {
476 if let Some(turtle) = self.turtles.last_mut() {
477 turtle.pos = pos
478 }
479 }
480
481 pub fn get_rel_turtle_pos(&self) -> Vec2 {
482 if let Some(turtle) = self.turtles.last() {
483 Vec2 {x: turtle.pos.x - turtle.origin.x, y: turtle.pos.y - turtle.origin.y}
484 }
485 else {
486 Vec2::default()
487 }
488 }
489
490 pub fn set_turtle_padding(&mut self, padding: Padding) {
491 if let Some(turtle) = self.turtles.last_mut() {
492 turtle.layout.padding = padding
493 }
494 }
495
496 pub fn visible_in_turtle(&self, geom: Rect, scroll: Vec2) -> bool {
497 if let Some(turtle) = self.turtles.last() {
498 let view = Rect {
499 x: scroll.x, y: scroll.y, w: turtle.width, h: turtle.height, };
504
505 return view.intersects(geom)
506 }
507 else {
508 false
509 }
510 }
511
512 fn compute_align_turtle_x(turtle: &Turtle) -> f32 {
513 if turtle.layout.align.fx > 0.0 {
514 let dx = turtle.layout.align.fx *
515 ((turtle.width - turtle.width_used - (turtle.layout.padding.l + turtle.layout.padding.r)) - (turtle.bound_right_bottom.x - (turtle.origin.x + turtle.layout.padding.l)));
516 if dx.is_nan() {return 0.0}
517 dx
518 }
519 else {
520 0.
521 }
522 }
523
524 fn compute_align_turtle_y(turtle: &Turtle) -> f32 {
525 if turtle.layout.align.fy > 0.0 {
526 let dy = turtle.layout.align.fy *
527 ((turtle.height - turtle.height_used - (turtle.layout.padding.t + turtle.layout.padding.b)) - (turtle.bound_right_bottom.y - (turtle.origin.y + turtle.layout.padding.t)));
528 if dy.is_nan() {return 0.0}
529 dy
530 }
531 else {
532 0.
533 }
534 }
535
536 pub fn compute_turtle_width(&mut self) {
537 if let Some(turtle) = self.turtles.last_mut() {
538 if turtle.width.is_nan() {
539 if turtle.bound_right_bottom.x != std::f32::NEG_INFINITY { turtle.width = max_zero_keep_nan(turtle.bound_right_bottom.x - turtle.origin.x + turtle.layout.padding.r);
541 turtle.width_used = 0.;
542 turtle.bound_right_bottom.x = 0.;
543 }
544 }
545 }
546 }
547
548 pub fn compute_turtle_height(&mut self) {
549 if let Some(turtle) = self.turtles.last_mut() {
550 if turtle.height.is_nan() {
551 if turtle.bound_right_bottom.y != std::f32::NEG_INFINITY { turtle.height = max_zero_keep_nan(turtle.bound_right_bottom.y - turtle.origin.y + turtle.layout.padding.b);
553 turtle.height_used = 0.;
554 turtle.bound_right_bottom.y = 0.;
555 }
556 }
557 }
558 }
559
560 pub fn change_turtle_align_x(&mut self, fx: f32) {
562 let (dx, align_origin_x) = if let Some(turtle) = self.turtles.last_mut() {
563 (Self::compute_align_turtle_x(&turtle), turtle.align_list_x)
564 }
565 else {
566 (0., 0)
567 };
568 if dx > 0.0 {
569 self.do_align_x(dx, align_origin_x);
570 }
571 if let Some(turtle) = self.turtles.last_mut() {
573 turtle.align_list_x = self.align_list.len();
574 turtle.layout.align.fx = fx;
575 turtle.width_used = turtle.bound_right_bottom.x - turtle.origin.x;
576 turtle.bound_right_bottom.x = std::f32::NEG_INFINITY;
577 }
578 }
579
580 pub fn change_turtle_align_y(&mut self, fy: f32) {
582 let (dy, align_origin_y) = if let Some(turtle) = self.turtles.last_mut() {
583 (Self::compute_align_turtle_y(&turtle), turtle.align_list_y)
584 }
585 else {
586 (0.0, 0)
587 };
588 if dy > 0.0 {
589 self.do_align_y(dy, align_origin_y);
590 }
591 if let Some(turtle) = self.turtles.last_mut() {
593 turtle.align_list_y = self.align_list.len();
594 turtle.layout.align.fy = fy;
595 turtle.height_used = turtle.bound_right_bottom.y - turtle.origin.y;
596 turtle.bound_right_bottom.y = std::f32::NEG_INFINITY;
597 }
598 }
599
600 pub fn turtle_align_y(&mut self) {
602 let fy = if let Some(turtle) = self.turtles.last_mut() {
603 turtle.layout.align.fy
604 }
605 else {
606 return
607 };
608 self.change_turtle_align_y(fy);
609 if let Some(turtle) = self.turtles.last_mut() {
610 turtle.height_used = 0.;
611 }
612 }
613
614 pub fn turtle_align_x(&mut self) {
615 let fx = if let Some(turtle) = self.turtles.last_mut() {
616 turtle.layout.align.fx
617 }
618 else {
619 return
620 };
621 self.change_turtle_align_x(fx);
622 if let Some(turtle) = self.turtles.last_mut() {
623 turtle.width_used = 0.;
624 }
625 }
626
627 pub fn reset_turtle_bounds(&mut self) {
628 if let Some(turtle) = self.turtles.last_mut() {
629 turtle.bound_left_top = Vec2 {x: std::f32::INFINITY, y: std::f32::INFINITY};
630 turtle.bound_right_bottom = Vec2 {x: std::f32::NEG_INFINITY, y: std::f32::NEG_INFINITY};
631 }
632 }
633
634 pub fn reset_turtle_pos(&mut self) {
635 if let Some(turtle) = self.turtles.last_mut() {
636 turtle.pos = Vec2 {
638 x: turtle.origin.x + turtle.layout.padding.l,
639 y: turtle.origin.y + turtle.layout.padding.t
640 };
641 }
642 }
643
644
645 fn _get_width_left(&self, abs: bool, abs_size: f32) -> f32 {
646 if !abs {
647 self.get_width_left()
648 }
649 else {
650 abs_size
651 }
652 }
653
654 pub fn get_width_left(&self) -> f32 {
655 if let Some(turtle) = self.turtles.last() {
656 let nan_val = max_zero_keep_nan(turtle.width - turtle.width_used - (turtle.pos.x - turtle.origin.x));
657 if nan_val.is_nan() { if turtle.bound_right_bottom.x != std::f32::NEG_INFINITY {
659 return turtle.bound_right_bottom.x - turtle.origin.x
660 }
661 }
662 return nan_val
663 }
664 0.
665 }
666
667 fn _get_width_total(&self, abs: bool, abs_size: f32) -> f32 {
668 if !abs {
669 self.get_width_total()
670 }
671 else {
672 abs_size
673 }
674 }
675
676 pub fn get_width_total(&self) -> f32 {
677 if let Some(turtle) = self.turtles.last() {
678 let nan_val = max_zero_keep_nan(turtle.width);
679 if nan_val.is_nan() { if turtle.bound_right_bottom.x != std::f32::NEG_INFINITY {
681 return turtle.bound_right_bottom.x - turtle.origin.x + turtle.layout.padding.r
682 }
683 }
684 return nan_val
685 }
686 0.
687 }
688
689 fn _get_height_left(&self, abs: bool, abs_size: f32) -> f32 {
690 if !abs {
691 self.get_height_left()
692 }
693 else {
694 abs_size
695 }
696 }
697
698 pub fn get_height_left(&self) -> f32 {
699 if let Some(turtle) = self.turtles.last() {
700 let nan_val = max_zero_keep_nan(turtle.height - turtle.height_used - (turtle.pos.y - turtle.origin.y));
701 if nan_val.is_nan() { if turtle.bound_right_bottom.y != std::f32::NEG_INFINITY {
703 return turtle.bound_right_bottom.y - turtle.origin.y
704 }
705 }
706 return nan_val
707 }
708 0.
709 }
710
711 fn _get_height_total(&self, abs: bool, abs_size: f32) -> f32 {
712 if !abs {
713 self.get_height_total()
714 }
715 else {
716 abs_size
717 }
718 }
719
720 pub fn get_height_total(&self) -> f32 {
721 if let Some(turtle) = self.turtles.last() {
722 let nan_val = max_zero_keep_nan(turtle.height );
723 if nan_val.is_nan() { if turtle.bound_right_bottom.y != std::f32::NEG_INFINITY {
725 return turtle.bound_right_bottom.y - turtle.origin.y + turtle.layout.padding.b
726 }
727 }
728 return nan_val
729 }
730 0.
731 }
732
733 pub fn is_height_computed(&self) -> bool {
734 if let Some(turtle) = self.turtles.last() {
735 if let Height::Compute = turtle.layout.walk.height {
736 return true
737 }
738 }
739 false
740 }
741
742 pub fn is_width_computed(&self) -> bool {
743 if let Some(turtle) = self.turtles.last() {
744 if let Width::Compute = turtle.layout.walk.width {
745 return true
746 }
747 }
748 false
749 }
750
751}
752#[derive(Copy, Clone, Debug)]
781pub enum Width {
782 Fill,
783 Fix(f32),
784 Compute,
785 ComputeFill,
786 FillPad(f32),
787 FillScale(f32),
788 FillScalePad(f32, f32),
789 Scale(f32),
790 ScalePad(f32, f32),
791}
792
793#[derive(Copy, Clone, Debug)]
794pub enum Height {
795 Fill,
796 Fix(f32),
797 Compute,
798 ComputeFill,
799 FillPad(f32),
800 FillScale(f32),
801 FillScalePad(f32, f32),
802 Scale(f32),
803 ScalePad(f32, f32),
804}
805
806impl Default for Width {
807 fn default() -> Self {
808 Width::Fill
809 }
810}
811
812
813impl Default for Height {
814 fn default() -> Self {
815 Height::Fill
816 }
817}
818
819
820impl Width {
821 pub fn fixed(&self) -> f32 {
822 match self {
823 Width::Fix(v) => *v,
824 _ => 0.
825 }
826 }
827
828 pub fn eval_width(&self, cx: &Cx, margin: Margin, abs: bool, abs_pos: f32) -> (f32,f32) {
829 match self {
830 Width::Compute => (std::f32::NAN,0.),
831 Width::ComputeFill => (std::f32::NAN,cx._get_width_left(abs, abs_pos) - (margin.l + margin.r)),
832 Width::Fix(v) => (max_zero_keep_nan(*v),0.),
833 Width::Fill => (max_zero_keep_nan(cx._get_width_left(abs, abs_pos) - (margin.l + margin.r)),0.),
834 Width::FillPad(p) => (max_zero_keep_nan(cx._get_width_left(abs, abs_pos) - p - (margin.l + margin.r)),0.),
835 Width::FillScale(s) => (max_zero_keep_nan(cx._get_width_left(abs, abs_pos) * s - (margin.l + margin.r)),0.),
836 Width::FillScalePad(s, p) => (max_zero_keep_nan(cx._get_width_left(abs, abs_pos) * s - p - (margin.l + margin.r)),0.),
837 Width::Scale(s) => (max_zero_keep_nan(cx._get_width_total(abs, abs_pos) * s - (margin.l + margin.r)),0.),
838 Width::ScalePad(s, p) => (max_zero_keep_nan(cx._get_width_total(abs, abs_pos) * s - p - (margin.l + margin.r)),0.),
839 }
840 }
841}
842
843impl Height {
844 pub fn fixed(&self) -> f32 {
845 match self {
846 Height::Fix(v) => *v,
847 _ => 0.
848 }
849 }
850 pub fn eval_height(&self, cx: &Cx, margin: Margin, abs: bool, abs_pos: f32) -> (f32,f32) {
851 match self {
852 Height::Compute => (std::f32::NAN,0.),
853 Height::ComputeFill => (std::f32::NAN,cx._get_height_left(abs, abs_pos) - (margin.t + margin.b)),
854 Height::Fix(v) => (max_zero_keep_nan(*v),0.),
855 Height::Fill => (max_zero_keep_nan(cx._get_height_left(abs, abs_pos) - (margin.t + margin.b)),0.),
856 Height::FillPad(p) => (max_zero_keep_nan(cx._get_height_left(abs, abs_pos) - p - (margin.t + margin.b)),0.),
857 Height::FillScale(s) => (max_zero_keep_nan(cx._get_height_left(abs, abs_pos) * s - (margin.t + margin.b)),0.),
858 Height::FillScalePad(s, p) => (max_zero_keep_nan(cx._get_height_left(abs, abs_pos) * s - p - (margin.t + margin.b)),0.),
859 Height::Scale(s) => (max_zero_keep_nan(cx._get_height_total(abs, abs_pos) * s - (margin.t + margin.b)),0.),
860 Height::ScalePad(s, p) => (max_zero_keep_nan(cx._get_height_total(abs, abs_pos) * s - p - (margin.t + margin.b)),0.),
861 }
862 }
863}
864
865#[derive(Clone, Copy, Default, Debug)]
866pub struct Align {
867 pub fx: f32,
868 pub fy: f32
869}
870
871impl Align {
872 pub fn left_top() -> Align {Align {fx: 0., fy: 0.}}
873 pub fn center_top() -> Align {Align {fx: 0.5, fy: 0.0}}
874 pub fn right_top() -> Align {Align {fx: 1.0, fy: 0.0}}
875 pub fn left_center() -> Align {Align {fx: 0.0, fy: 0.5}}
876 pub fn center() -> Align {Align {fx: 0.5, fy: 0.5}}
877 pub fn right_center() -> Align {Align {fx: 1.0, fy: 0.5}}
878 pub fn left_bottom() -> Align {Align {fx: 0., fy: 1.0}}
879 pub fn center_bottom() -> Align {Align {fx: 0.5, fy: 1.0}}
880 pub fn right_bottom() -> Align {Align {fx: 1.0, fy: 1.0}}
881}
882
883#[derive(Clone, Copy, Default, Debug)]
884pub struct Margin {
885 pub l: f32,
886 pub t: f32,
887 pub r: f32,
888 pub b: f32
889}
890
891impl Margin {
892 pub fn zero() -> Margin {
893 Margin {l: 0.0, t: 0.0, r: 0.0, b: 0.0}
894 }
895
896 pub fn all(v: f32) -> Margin {
897 Margin {l: v, t: v, r: v, b: v}
898 }
899}
900
901impl Rect {
902 pub fn contains_with_margin(&self, x: f32, y: f32, margin: &Option<Margin>) -> bool {
903 if let Some(margin) = margin {
904 return x >= self.x - margin.l && x <= self.x + self.w + margin.r &&
905 y >= self.y - margin.t && y <= self.y + self.h + margin.b;
906 }
907 else {
908 return self.contains(x, y);
909 }
910
911 }
912}
913
914#[derive(Clone, Copy, Default, Debug)]
915pub struct Padding {
916 pub l: f32,
917 pub t: f32,
918 pub r: f32,
919 pub b: f32
920}
921
922impl Padding {
923 pub fn zero() -> Padding {
924 Padding {l: 0.0, t: 0.0, r: 0.0, b: 0.0}
925 }
926 pub fn all(v: f32) -> Padding {
927 Padding {l: v, t: v, r: v, b: v}
928 }
929}
930
931
932#[derive(Copy, Clone, Debug)]
933pub enum Direction {
934 Left,
935 Right,
936 Up,
937 Down
938}
939
940impl Default for Direction {
941 fn default() -> Self {
942 Direction::Right
943 }
944}
945
946#[derive(Copy, Clone, SerRon, DeRon)]
947pub enum Axis {
948 Horizontal,
949 Vertical
950}
951
952impl Default for Axis {
953 fn default() -> Self {
954 Axis::Horizontal
955 }
956}
957
958#[derive(Copy, Clone, Debug)]
959pub enum LineWrap {
960 None,
961 NewLine,
962 MaxSize(f32)
963}
964impl Default for LineWrap {
965 fn default() -> Self {
966 LineWrap::None
967 }
968}
969
970#[derive(Copy, Clone, Default, Debug)]
971pub struct Layout {
972 pub padding: Padding,
973 pub align: Align,
974 pub direction: Direction,
975 pub line_wrap: LineWrap,
976 pub new_line_padding: f32,
977 pub abs_origin: Option<Vec2>,
978 pub abs_size: Option<Vec2>,
979 pub walk: Walk,
980}
981
982#[derive(Copy, Clone, Default, Debug)]
983pub struct Walk {
984 pub margin: Margin,
985 pub width: Width,
986 pub height: Height,
987}
988
989impl Walk {
990 pub fn wh(w: Width, h: Height) -> Self {
991 Self {
992 width: w,
993 height: h,
994 margin: Margin::zero(),
995 }
996 }
997}
998
999impl Layout {
1000 pub fn abs_origin_zero() -> Self {
1001 Layout {
1002 abs_origin: Some(Vec2::default()),
1003 ..Default::default()
1004 }
1005 }
1006}
1007
1008#[derive(Clone, Default, Debug)]
1009pub struct Turtle {
1010 pub align_list_x: usize,
1011 pub align_list_y: usize,
1012 pub pos: Vec2,
1013 pub origin: Vec2,
1014 pub bound_left_top: Vec2,
1015 pub bound_right_bottom: Vec2,
1016 pub width: f32,
1017 pub height: f32,
1018 pub min_width: f32,
1019 pub min_height: f32,
1020 pub abs_size: Vec2,
1021 pub width_used: f32,
1022 pub height_used: f32,
1023 pub biggest: f32,
1024 pub layout: Layout,
1025 pub guard_area: Area
1026}
1027
1028pub fn max_zero_keep_nan(v: f32) -> f32 {
1029 if v.is_nan() {
1030 v
1031 }
1032 else {
1033 f32::max(v, 0.0)
1034 }
1035}