bevy_ui_builders/number_input/
builder.rs

1//! NumberInputBuilder for creating validated number input fields
2
3use bevy::prelude::*;
4use super::types::*;
5use crate::text_input::{TextInputBuilder, InputFilter};
6
7/// Builder for creating number input fields with validation
8///
9/// # Examples
10///
11/// ```ignore
12/// use bevy_ui_builders::prelude::*;
13///
14/// fn build_number_input(parent: &mut ChildSpawnerCommands) {
15///     NumberInputBuilder::new()
16///         .min(8.0)
17///         .max(24.0)
18///         .default_value(16.0)
19///         .build(parent);
20/// }
21/// ```
22pub struct NumberInputBuilder {
23    min: Option<f32>,
24    max: Option<f32>,
25    step: f32,
26    default_value: Option<f32>,
27    width: Val,
28    placeholder: Option<String>,
29}
30
31impl NumberInputBuilder {
32    /// Create a new number input builder
33    pub fn new() -> Self {
34        Self {
35            min: None,
36            max: None,
37            step: 1.0,
38            default_value: None,
39            width: Val::Px(crate::styles::dimensions::INPUT_WIDTH_DEFAULT),
40            placeholder: None,
41        }
42    }
43
44    /// Set the minimum allowed value
45    pub fn min(mut self, min: f32) -> Self {
46        self.min = Some(min);
47        self
48    }
49
50    /// Set the maximum allowed value
51    pub fn max(mut self, max: f32) -> Self {
52        self.max = Some(max);
53        self
54    }
55
56    /// Set the step size for increment/decrement
57    pub fn step(mut self, step: f32) -> Self {
58        self.step = step;
59        self
60    }
61
62    /// Set the default value
63    pub fn default_value(mut self, value: f32) -> Self {
64        self.default_value = Some(value);
65        self
66    }
67
68    /// Set the width of the input field
69    pub fn width(mut self, width: Val) -> Self {
70        self.width = width;
71        self
72    }
73
74    /// Set placeholder text
75    pub fn with_placeholder(mut self, placeholder: impl Into<String>) -> Self {
76        self.placeholder = Some(placeholder.into());
77        self
78    }
79
80    /// Build the number input and spawn it
81    pub fn build(self, parent: &mut ChildSpawnerCommands) -> Entity {
82        let config = NumberInputConfig {
83            min: self.min,
84            max: self.max,
85            step: self.step,
86        };
87
88        // Clamp default value to range if provided
89        let initial_value = if let Some(value) = self.default_value {
90            Some(config.clamp_value(value).to_string())
91        } else {
92            None
93        };
94
95        // Build hint text for min/max if provided
96        let hint = match (self.min, self.max) {
97            (Some(min), Some(max)) => Some(format!("Range: {}-{}", min, max)),
98            (Some(min), None) => Some(format!("Min: {}", min)),
99            (None, Some(max)) => Some(format!("Max: {}", max)),
100            (None, None) => None,
101        };
102
103        // Create the text input with decimal filter
104        let mut text_input = TextInputBuilder::new()
105            .with_width(self.width)
106            .with_filter(InputFilter::Decimal);
107
108        // Set placeholder or hint
109        if let Some(placeholder) = self.placeholder {
110            text_input = text_input.with_placeholder(&placeholder);
111        } else if let Some(hint_text) = hint {
112            text_input = text_input.with_placeholder(&hint_text);
113        }
114
115        // Set initial value if provided
116        if let Some(value_str) = initial_value {
117            text_input = text_input.with_value(&value_str);
118        }
119
120        // Add automatic validation for range if min or max is specified
121        if self.min.is_some() || self.max.is_some() {
122            let min = self.min.unwrap_or(f32::MIN);
123            let max = self.max.unwrap_or(f32::MAX);
124            text_input = text_input.with_validation(vec![
125                crate::ValidationRule::Range { min, max }
126            ]);
127        }
128
129        // Build and add marker components
130        let entity = text_input.build(parent);
131
132        parent.commands().entity(entity).insert((
133            NumberInput,
134            config,
135        ));
136
137        entity
138    }
139}
140
141impl Default for NumberInputBuilder {
142    fn default() -> Self {
143        Self::new()
144    }
145}