1use gpui::ClickEvent;
2
3use crate::{prelude::*, IconButtonShape};
4
5#[derive(IntoElement)]
6pub struct NumericStepper {
7 value: SharedString,
8 on_decrement: Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>,
9 on_increment: Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>,
10 on_reset: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
11}
12
13impl NumericStepper {
14 pub fn new(
15 value: impl Into<SharedString>,
16 on_decrement: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
17 on_increment: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
18 ) -> Self {
19 Self {
20 value: value.into(),
21 on_decrement: Box::new(on_decrement),
22 on_increment: Box::new(on_increment),
23 on_reset: None,
24 }
25 }
26
27 pub fn on_reset(
28 mut self,
29 on_reset: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
30 ) -> Self {
31 self.on_reset = Some(Box::new(on_reset));
32 self
33 }
34}
35
36impl RenderOnce for NumericStepper {
37 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
38 let shape = IconButtonShape::Square;
39 let icon_size = IconSize::Small;
40
41 h_flex()
42 .gap_1()
43 .map(|element| {
44 if let Some(on_reset) = self.on_reset {
45 element.child(
46 IconButton::new("reset", IconName::RotateCcw)
47 .shape(shape)
48 .icon_size(icon_size)
49 .on_click(on_reset),
50 )
51 } else {
52 element.child(
53 h_flex()
54 .size(icon_size.square(cx))
55 .flex_none()
56 .into_any_element(),
57 )
58 }
59 })
60 .child(
61 h_flex()
62 .gap_1()
63 .px_1()
64 .rounded_sm()
65 .bg(cx.theme().colors().editor_background)
66 .child(
67 IconButton::new("decrement", IconName::Dash)
68 .shape(shape)
69 .icon_size(icon_size)
70 .on_click(self.on_decrement),
71 )
72 .child(Label::new(self.value))
73 .child(
74 IconButton::new("increment", IconName::Plus)
75 .shape(shape)
76 .icon_size(icon_size)
77 .on_click(self.on_increment),
78 ),
79 )
80 }
81}