|
| 1 | +# For Loop Widget |
| 2 | + |
| 3 | +This example demonstrates how to generate components from iterable data in Makepad. |
| 4 | + |
| 5 | +## Writing Live Design |
| 6 | + |
| 7 | +Note that we use `btn: <Button>` instead of `btn = <Button>`. This implies that the button is treated as a prop here. |
| 8 | + |
| 9 | +```rust |
| 10 | +use makepad_widgets::*; |
| 11 | + |
| 12 | +live_design!{ |
| 13 | + // Import the essential base and theme components from makepad_widgets |
| 14 | + import makepad_widgets::base::*; |
| 15 | + import makepad_widgets::theme_desktop_dark::*; |
| 16 | + |
| 17 | + // Define a new component named Footer |
| 18 | + Footer = {{Footer}}{ |
| 19 | + // Set the height and width to fill their container |
| 20 | + height: Fill, |
| 21 | + width: Fill, |
| 22 | + // Define a button with a text prop |
| 23 | + btn: <Button>{ |
| 24 | + text: "Click me", |
| 25 | + } |
| 26 | + } |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +## Writing the Widget |
| 31 | + |
| 32 | +Next, we implement a widget that conforms to the Widget trait. Here, we use `Area + LivePtr + ComponentMap`. You can roughly consider these as a standard combination (though that's not entirely accurate). |
| 33 | + |
| 34 | +- `Area`: Provides a renderable area. |
| 35 | +- `LivePtr`: A special pointer type used to reference `#[live]` data or resources. |
| 36 | +- `ComponentMap`: A container for managing widgets. |
| 37 | + |
| 38 | +```rust |
| 39 | +#[derive(Live, LiveHook, Widget)] |
| 40 | +pub struct Footer { |
| 41 | + // The area property provides a specific region for rendering |
| 42 | + #[rust] |
| 43 | + #[redraw] |
| 44 | + area: Area, |
| 45 | + // Layout for arranging child widgets or components |
| 46 | + #[layout] |
| 47 | + layout: Layout, |
| 48 | + // Walk specifies how child components are positioned and sized |
| 49 | + #[walk] |
| 50 | + walk: Walk, |
| 51 | + // Optional property to hold a reference to the button's live data |
| 52 | + #[live] |
| 53 | + btn: Option<LivePtr>, |
| 54 | + // Maps button identifiers to their corresponding ButtonRef objects |
| 55 | + #[rust] |
| 56 | + btns: ComponentMap<LiveId, ButtonRef> |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +## Drawing the Widget |
| 61 | + |
| 62 | +Implement the `draw_walk` method to render the widget. |
| 63 | + |
| 64 | +```rust |
| 65 | +impl Widget for Footer { |
| 66 | + fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { |
| 67 | + // Start drawing the widget using the specified layout |
| 68 | + cx.begin_turtle(walk, self.layout); |
| 69 | + // Example data to iterate over |
| 70 | + let data = vec!["1","2","3"]; |
| 71 | + for (d_id, name) in data.iter().enumerate() { |
| 72 | + let id = LiveId(d_id as u64); |
| 73 | + // Retrieve or insert a new button based on the id |
| 74 | + let c_btn = self.btns.get_or_insert(cx, id, |cx|{ |
| 75 | + // Create a new button from the live pointer |
| 76 | + WidgetRef::new_from_ptr(cx, self.btn).as_button() |
| 77 | + }); |
| 78 | + // Set the button's text |
| 79 | + c_btn.set_text(name); |
| 80 | + // Draw the button |
| 81 | + c_btn.draw_all(cx, scope); |
| 82 | + } |
| 83 | + |
| 84 | + // End the drawing process for the current widget |
| 85 | + cx.end_turtle(); |
| 86 | + // Retain only the buttons that are visible |
| 87 | + self.btns.retain_visible(); |
| 88 | + // Indicate that the drawing step is complete |
| 89 | + DrawStep::done() |
| 90 | + } |
| 91 | +} |
| 92 | +``` |
0 commit comments