Inheritance

Inherited component instances can:

  1. Override parent component properties
  2. Add new properties
  3. Extend with new child component instances
1// Base card component
2Card = {{MyView}} {
3    // Base properties
4    background_color: #fff,
5    corner_radius: 4.0,
6    shadow_color: #0007,
7
8    // Base layout
9    flow: Down,
10    spacing: 10
11}
12
13// Product card extension
14ProductCard = <Card> {
15    // 1. Override parent component properties
16    background_color: #f5f5f5,  // Override background color
17    corner_radius: 8.0,         // Override corner radius
18
19    // 2. Add new properties
20    width: 200,
21    height: 300,
22    border_width: 1.0,         // Add border
23
24    // 3. Add child components
25    image_container = <View> {
26        height: 160
27    }
28
29    title = <Label> {
30        text_wrap: Word,
31        color: #333
32    }
33
34    price = <Label> {
35        color: #f00,
36        font_size: 18
37    }
38
39    buy_button = <Button> {
40        width: Fill,
41        label: "Buy Now"
42    }
43}
44
45// Can be further inherited and extended
46FeaturedProductCard = <ProductCard> {
47    // Override properties
48    height: 350,
49    background_color: #fff0f0,
50
51    // Add new components
52    badge = <Label> {
53        text: "Featured",
54        background_color: #f00,
55        color: #fff
56    }
57}

In Live DSL, ProductCard = <Card> typically represents "referencing" a component.

Live inheritance system characteristics:

Inheritance method

1. Property Inheritance

1ParentView = {{View}} {
2    color: #f00,
3    spacing: 10
4}
5
6ChildView = <ParentView> {
7    // Inherits color and spacing
8    // Overrides color
9    color: #00f,
10    // Adds new property
11    margin: 20
12}

2. Layout Inheritance

1CardBase = {{View}} {
2    flow: Down,
3    spacing: 10,
4
5    header = <View> {
6        height: 50
7    }
8}
9
10CustomCard = <CardBase> {
11    // Inherits layout properties
12    // Modifies child component
13    header = <View> {
14        height: 60,
15        background_color: #f00
16    }
17}

3. Animation Inheritance

1ButtonBase = {{Button}} {
2    animator: {
3        hover = {
4            default: off
5            on = {
6                apply: {color: #f00}
7            }
8        }
9    }
10}
11
12CustomButton = <ButtonBase> {
13    // Inherits animation
14    animator: {
15        // Adds new animation state
16        pressed = {
17            default: off
18            on = {
19                apply: {scale: 0.9}
20            }
21        }
22    }
23}

4. Event Handling Inheritance

1ClickableView = {{View}} {
2    cursor: Pointer,
3    grab_key_focus: true
4}
5
6InteractiveCard = <ClickableView> {
7    // Inherits interaction behavior
8    // Adds visual feedback
9    animator: {
10        pressed = {
11            default: off
12            on = {
13                apply: {
14                    background_color: #eee
15                }
16            }
17        }
18    }
19}

Creating New Components Through Inheritance

1live_design!{
2    // Define a common button style
3    // Inherit from Button
4    MyButton = {{MyButton}} <Button> {
5        width: 200,
6        height: 50,
7        margin: {left: 20, right: 20},
8
9        text: "My Button",
10        draw_text: {
11            color: #ffffff
12        },
13    }
14}
15
16#[derive(Live,Widget)]
17pub struct MyButton {
18    // Inherit all Button functionality
19    #[deref]
20    button: Button,
21    #[rust]
22    initialized: bool,
23}

Note this syntax: MyButton = {{MyButton}} <Button>, which creates your own MyButton component by inheriting from the existing Button Widget.

This approach is suitable when extending existing components.

Inheritance Usage Guidelines

  1. Keep inheritance hierarchy shallow. Avoid deep inheritance chains for easier understanding of component relationships.
  2. Use clear naming conventions. Base components use Base/Common prefix, variants use functionality-related names.
  3. Use inheritance judiciously. Not all components need inheritance; sometimes direct creation is more appropriate.

Rust Struct Inheritance

The #[deref] attribute macro in Rust structs:

1struct DrawWave {
2    #[deref] draw_super: DrawQuad,  // Inherit DrawQuad's fields and methods
3    #[live] gain: f32,
4    #[live] vu_left: f32,
5}

This is a compile-time Rust trait implementation mechanism:

  • Uses makepad_derive_widget macro to generate Deref/DerefMut trait implementation for DrawQuad
  • Allows DrawWave to directly access DrawQuad's fields and methods
  • Represents a Rust language-level "delegation/inheritance" pattern (using Deref to simulate inheritance is an anti-pattern, but works well in the Makepad framework)

Using both together:

1// Rust-level base component implementation
2struct Button {
3    #[deref] draw_super: DrawQuad, // Inherit drawing capabilities
4    #[live] color: Vec4
5}
6
7// Live DSL-level component customization
8DefaultButton = <Button> {  // Reference and override properties
9    color: #f00
10}

Key differences between #[deref] and referencing component instances in Live DSL:

  1. #[deref] is a Rust compile-time type system feature used to implement basic component functionality inheritance and method delegation.
  2. Live DSL component referencing is primarily used for creating component structures.