The turtle layout system contains the following core concepts:
1pub struct Turtle {
2 // Current turtle position
3 walk: Walk, // Layout behavior
4 layout: Layout, // Layout rules
5 wrap_spacing: f64, // Wrapping spacing
6 align_start: usize, // Alignment start position
7 defer_count: usize, // Defer count
8 shift: DVec2, // Offset amount
9 pos: DVec2, // Current position
10 origin: DVec2, // Starting position
11 width: f64, // Width
12 height: f64, // Height
13 width_used: f64, // Width consumed
14 height_used: f64, // Height consumed
15}
1// Start a turtle layout
2cx.begin_turtle(walk, layout);
3
4// Drawing process example
5turtle.move_to(10.0, 10.0); // Move to specified position
6turtle.line_to(100.0, 100.0); // Draw line to specified position
7turtle.rect(0.0, 0.0, 50.0, 30.0); // Draw rectangle
8
9// End layout
10cx.end_turtle();
1impl Turtle {
2 // Calculate next position
3 pub fn next_pos(&mut self, size: DVec2) -> DVec2 {
4 match self.layout.flow {
5 Flow::Right => {
6 let pos = self.pos;
7 self.pos.x += size.x + self.layout.spacing;
8 self.width_used = self.width_used.max(self.pos.x);
9 pos
10 }
11 Flow::Down => {
12 let pos = self.pos;
13 self.pos.y += size.y + self.layout.spacing;
14 self.height_used = self.height_used.max(self.pos.y);
15 pos
16 }
17 // ... Handle other flow directions
18 }
19 }
20}
1MyView = <View> {
2 // Outer turtle
3 walk: {width: Fill, height: Fit},
4 layout: {flow: Down, spacing: 10},
5
6 // Inner turtle
7 <View> {
8 walk: {width: Fill, height: Fit},
9 layout: {
10 flow: Right,
11 spacing: 5,
12 padding: {left: 10, right: 10}
13 },
14
15 // Content components
16 <Button> {}
17 <Button> {}
18 }
19}
When layout needs to wait for certain conditions to be met, it can use deferred layout:
1impl Turtle {
2 pub fn defer_walk(&mut self, walk: Walk) -> Option<DeferWalk> {
3 if walk.abs_pos.is_some() {
4 return None;
5 }
6
7 // Handle deferred layout logic
8 match self.layout.flow {
9 Flow::Right if walk.width.is_fill() => {
10 // Handle deferral in right-flowing layout
11 let spacing = self.child_spacing();
12 self.pos.x += spacing.x;
13 Some(DeferWalk::Unresolved{...})
14 }
15 // ... Handle other cases
16 }
17 }
18}
1pub struct AlignEntry {
2 align_range: TurtleAlignRange,
3 size: DVec2,
4 shift: f64,
5 index: usize
6}
7
8impl Cx2d {
9 pub fn align_items(&mut self) {
10 // Iterate through all items needing alignment
11 for item in &self.draw_align_list {
12 // Calculate alignment position
13 let shift = match self.layout.align {
14 Align::Center => {
15 (self.width - item.size.x) * 0.5
16 },
17 // ... Handle other alignment types
18 };
19
20 // Apply alignment
21 self.shift_align_range(&item.align_range, shift);
22 }
23 }
24}
1CenteredContent = <View> {
2 layout: {
3 flow: Down,
4 align: {x: 0.5, y: 0.0} // Horizontal center, top align
5 },
6
7 <Text> {
8 walk: {
9 width: Fit,
10 height: Fit
11 },
12 text: "Centered Text"
13 }
14}
Caching Mechanism
1pub struct DrawStateWrap<T: Clone> {
2 state: Option<T>,
3 redraw_id: u64,
4}
5
6impl<T: Clone> DrawStateWrap<T> {
7 pub fn begin(&mut self, cx: &mut Cx2d, init: T) -> bool {
8 if self.redraw_id != cx.redraw_id() {
9 // Only update state when necessary
10 self.redraw_id = cx.redraw_id();
11 self.state = Some(init);
12 true
13 } else {
14 false
15 }
16 }
17}