numeric_stepper.rs

  1use gpui::ClickEvent;
  2
  3use crate::{IconButtonShape, prelude::*};
  4
  5#[derive(IntoElement, RegisterComponent)]
  6pub struct NumericStepper {
  7    id: ElementId,
  8    value: SharedString,
  9    on_decrement: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
 10    on_increment: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
 11    /// Whether to reserve space for the reset button.
 12    reserve_space_for_reset: bool,
 13    on_reset: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
 14}
 15
 16impl NumericStepper {
 17    pub fn new(
 18        id: impl Into<ElementId>,
 19        value: impl Into<SharedString>,
 20        on_decrement: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
 21        on_increment: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
 22    ) -> Self {
 23        Self {
 24            id: id.into(),
 25            value: value.into(),
 26            on_decrement: Box::new(on_decrement),
 27            on_increment: Box::new(on_increment),
 28            reserve_space_for_reset: false,
 29            on_reset: None,
 30        }
 31    }
 32
 33    pub fn reserve_space_for_reset(mut self, reserve_space_for_reset: bool) -> Self {
 34        self.reserve_space_for_reset = reserve_space_for_reset;
 35        self
 36    }
 37
 38    pub fn on_reset(
 39        mut self,
 40        on_reset: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
 41    ) -> Self {
 42        self.on_reset = Some(Box::new(on_reset));
 43        self
 44    }
 45}
 46
 47impl RenderOnce for NumericStepper {
 48    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
 49        let shape = IconButtonShape::Square;
 50        let icon_size = IconSize::Small;
 51
 52        h_flex()
 53            .id(self.id)
 54            .gap_1()
 55            .map(|element| {
 56                if let Some(on_reset) = self.on_reset {
 57                    element.child(
 58                        IconButton::new("reset", IconName::RotateCcw)
 59                            .shape(shape)
 60                            .icon_size(icon_size)
 61                            .on_click(on_reset),
 62                    )
 63                } else if self.reserve_space_for_reset {
 64                    element.child(
 65                        h_flex()
 66                            .size(icon_size.square(window, cx))
 67                            .flex_none()
 68                            .into_any_element(),
 69                    )
 70                } else {
 71                    element
 72                }
 73            })
 74            .child(
 75                h_flex()
 76                    .gap_1()
 77                    .px_1()
 78                    .rounded_xs()
 79                    .bg(cx.theme().colors().editor_background)
 80                    .child(
 81                        IconButton::new("decrement", IconName::Dash)
 82                            .shape(shape)
 83                            .icon_size(icon_size)
 84                            .on_click(self.on_decrement),
 85                    )
 86                    .child(Label::new(self.value))
 87                    .child(
 88                        IconButton::new("increment", IconName::Plus)
 89                            .shape(shape)
 90                            .icon_size(icon_size)
 91                            .on_click(self.on_increment),
 92                    ),
 93            )
 94    }
 95}
 96
 97impl Component for NumericStepper {
 98    fn scope() -> ComponentScope {
 99        ComponentScope::Input
100    }
101
102    fn name() -> &'static str {
103        "NumericStepper"
104    }
105
106    fn sort_name() -> &'static str {
107        Self::name()
108    }
109
110    fn description() -> Option<&'static str> {
111        Some("A button used to increment or decrement a numeric value. ")
112    }
113
114    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
115        Some(
116            div()
117                .child(NumericStepper::new(
118                    "numeric-stepper-component-preview",
119                    "10",
120                    move |_, _, _| {},
121                    move |_, _, _| {},
122                ))
123                .into_any_element(),
124        )
125    }
126}