Inheritance
Inherited component instances can:
- Override parent component properties
- Add new properties
- 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
- Keep inheritance hierarchy shallow. Avoid deep inheritance chains for easier understanding of component relationships.
- Use clear naming conventions. Base components use
Base/Common
prefix, variants use functionality-related names.
- 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:
#[deref]
is a Rust compile-time type system feature used to implement basic component functionality inheritance and method delegation.
- Live DSL component referencing is primarily used for creating component structures.