rgpui_component/stepper/
stepper.rs1use std::rc::Rc;
2
3use rgpui::{
4 App, Axis, ElementId, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
5 StyleRefinement, Styled, Window, div, prelude::FluentBuilder as _,
6};
7
8use crate::{AxisExt, Sizable, Size, StyledExt as _, stepper::StepperItem};
9
10#[derive(IntoElement)]
12pub struct Stepper {
13 id: ElementId,
14 style: StyleRefinement,
15 items: Vec<StepperItem>,
16 step: usize,
17 layout: Axis,
18 disabled: bool,
19 size: Size,
20 text_center: bool,
21 on_click: Rc<dyn Fn(&usize, &mut Window, &mut App) + 'static>,
22}
23
24impl Stepper {
25 pub fn new(id: impl Into<ElementId>) -> Self {
29 Self {
30 id: id.into(),
31 style: StyleRefinement::default(),
32 items: Vec::new(),
33 step: 0,
34 layout: Axis::Horizontal,
35 disabled: false,
36 size: Size::default(),
37 text_center: false,
38 on_click: Rc::new(|_, _, _| {}),
39 }
40 }
41
42 pub fn text_center(mut self, center: bool) -> Self {
44 self.text_center = center;
45 self
46 }
47
48 pub fn layout(mut self, layout: Axis) -> Self {
50 self.layout = layout;
51 self
52 }
53
54 pub fn vertical(mut self) -> Self {
56 self.layout = Axis::Vertical;
57 self
58 }
59
60 pub fn selected_index(mut self, index: usize) -> Self {
62 self.step = index;
63 self
64 }
65
66 pub fn item(mut self, item: StepperItem) -> Self {
68 self.items.push(item);
69 self
70 }
71
72 pub fn items(mut self, items: impl IntoIterator<Item = StepperItem>) -> Self {
74 self.items.extend(items);
75 self
76 }
77
78 pub fn disabled(mut self, disabled: bool) -> Self {
80 self.disabled = disabled;
81 self
82 }
83
84 pub fn on_click<F>(mut self, f: F) -> Self
88 where
89 F: Fn(&usize, &mut Window, &mut App) + 'static,
90 {
91 self.on_click = Rc::new(f);
92 self
93 }
94}
95
96impl Sizable for Stepper {
97 fn with_size(mut self, size: impl Into<Size>) -> Self {
98 self.size = size.into();
99 self
100 }
101}
102
103impl Styled for Stepper {
104 fn style(&mut self) -> &mut StyleRefinement {
105 &mut self.style
106 }
107}
108
109impl RenderOnce for Stepper {
110 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
111 let total_items = self.items.len();
112 div()
113 .id(self.id)
114 .w_full()
115 .when(self.layout.is_horizontal(), |this| this.h_flex())
116 .when(self.layout.is_vertical(), |this| this.v_flex())
117 .refine_style(&self.style)
118 .children(self.items.into_iter().enumerate().map(|(step, item)| {
119 let is_last = step + 1 == total_items;
120 item.step(step)
121 .with_size(self.size)
122 .checked_step(self.step)
123 .layout(self.layout)
124 .text_center(self.text_center)
125 .when(self.disabled, |this| this.disabled(true))
126 .is_last(is_last)
127 .on_click({
128 let on_click = self.on_click.clone();
129 move |_, window, cx| {
130 on_click(&step, window, cx);
131 }
132 })
133 }))
134 }
135}