Circular Dependencies in Makepad Live DSL Layout System

Understanding Layout Circular Dependencies

Layout circular dependencies occur when components' size calculations create mutual dependencies, preventing the layout engine from determining final dimensions. This typically happens in these scenarios:

  1. Parent-child component size interdependencies
  2. Sibling component size interdependencies
  3. Complex Fit layout nesting

Let's understand these situations through specific examples:

Parent-Child Circular Dependency

1// Incorrect example: Parent-child circular dependency
2ParentView = <View> {
3    walk: {
4        width: Fill,
5        height: Fit  // Parent height depends on child
6    },
7    layout: {
8        flow: Down
9    },
10
11    <ChildView> {
12        walk: {
13            width: Fill,
14            height: Percentage(0.5)  // Child height depends on parent
15        }
16    }
17}

In this example:

  1. Parent component's height is set to Fit, waiting for child component height calculation
  2. Child component's height is set to 50% of parent height, waiting for parent height calculation
  3. Creates a cycle: parent waiting for child, child waiting for parent

Parent-child circular dependency diagram

1┌─ Parent (height: Fit) ─┐
2│     ?                  │
3│  ┌─ Child ─┐           │
4│  │  height:│           │
5│  │  50%    │   ?       │
6│  │  of ?   │           │
7│  └─────────┘           │
8└────────────────────────┘

Sibling Component Circular Dependency

1// Incorrect example: Sibling component circular dependency
2Container = <View> {
3    layout: {
4        flow: Right
5    },
6
7    <LeftView> {
8        walk: {
9            width: Fill,  // Left component fills remaining space
10            height: Fit
11        }
12    }
13
14    <RightView> {
15        walk: {
16            width: Fit,   // Right component width adapts to content
17            height: Fit
18        },
19        layout: {
20            flow: Down
21        }
22    }
23}

In this example:

  1. Left component wants to fill space excluding right component
  2. Right component's width depends on its content
  3. Layout engine cannot determine which component to calculate first

How to Avoid Circular Dependencies

1. Explicit Size Constraints

The safest approach is to provide explicit constraints for critical dimensions:

1// Correct example: Explicit size constraints
2ParentView = <View> {
3    walk: {
4        width: Fill,
5        height: Fixed(500)  // Explicit parent height
6    },
7
8    <ChildView> {
9        walk: {
10            width: Fill,
11            height: Percentage(0.5)  // Now calculatable
12        }
13    }
14}

2. Using Fixed or Max/Min Constraints

1Container = <View> {
2    layout: {
3        flow: Right
4    },
5
6    <LeftView> {
7        walk: {
8            width: Percentage(0.7),  // Fixed ratio
9            height: Fit
10        }
11    }
12
13    <RightView> {
14        walk: {
15            width: Fixed(200),  // Fixed width
16            height: Fit
17        }
18    }
19}

3. Layout Directional Principles

Establishing correct layout direction can avoid many circular dependencies:

1// Recommended layout direction
2GoodLayout = <View> {
3    layout: {
4        flow: Down  // Vertical layout makes size calculation more straightforward
5    },
6
7    <Header> {
8        walk: {
9            width: Fill,
10            height: Fixed(60)  // Fixed height header
11        }
12    }
13
14    <Content> {
15        walk: {
16            width: Fill,
17            height: Fill  // Fill remaining space
18        }
19    }
20
21    <Footer> {
22        walk: {
23            width: Fill,
24            height: Fit  // Footer height adapts to content
25        }
26    }
27}

Layout Engine's Resolution Strategy

When encountering potential circular dependencies, the Makepad layout engine employs these strategies:

1. Priority Order

  • Fixed sizes calculate first
  • Fill calculations second
  • Fit calculations last

2. Breaking Cycles

  • Uses default or minimum values for unresolvable cycles
  • Issues warnings in development mode

3. Caching Mechanism

  • Caches calculated layout results
  • Avoids recalculating identical layouts