Skip to main content

banished_ui/controls/
values.rs

1//! Reading and setting the controls' values: sliders, check boxes, spinners, combos, tables, graphs
2//! and images.
3
4use super::*;
5
6impl Ui {
7    /// Set the value of a slider, scroll bar or progress bar.
8    pub fn set_value(&mut self, id: NodeId, value: f32) {
9        if !value.is_finite() {
10            return;
11        }
12        let mut label = None;
13        match &mut self.nodes[id].kind {
14            Kind::Control(Control::Slider(s)) => {
15                s.value = value.clamp(s.range[0].min(s.range[1]), s.range[0].max(s.range[1]));
16                label = s.number.map(|n| (n, format_number(s.value)));
17            }
18            Kind::Control(
19                Control::Progress { value: v, .. } | Control::Scroll { value: v, .. },
20            ) => *v = value.clamp(0.0, 1.0),
21            Kind::Control(Control::Edit(e)) => {
22                let value = if let Some(range) = e.range {
23                    value
24                        .clamp(range[0].min(range[1]), range[0].max(range[1]))
25                        .trunc()
26                } else {
27                    value
28                };
29                e.text.text = format_number(value);
30                e.cursor = e.text.text.chars().count();
31            }
32            _ => {}
33        }
34        if let Some((n, text)) = label {
35            self.set_text(n, &text);
36        }
37    }
38
39    /// The value of a slider, scroll bar or progress bar.
40    pub fn value(&self, id: NodeId) -> Option<f32> {
41        match &self.nodes[id].kind {
42            Kind::Control(Control::Slider(s)) => Some(s.value),
43            Kind::Control(Control::Progress { value, .. } | Control::Scroll { value, .. }) => {
44                Some(*value)
45            }
46            Kind::Control(Control::Edit(e)) => e.text.text.parse().ok(),
47            _ => None,
48        }
49    }
50
51    /// Set the smallest and the largest value of a slider.
52    pub fn set_slider_range(&mut self, id: NodeId, range: [f32; 2]) {
53        if let Kind::Control(Control::Slider(slider)) = &mut self.nodes[id].kind {
54            slider.range = range;
55            slider.value = slider
56                .value
57                .clamp(range[0].min(range[1]), range[0].max(range[1]));
58        }
59    }
60
61    /// `UI::TableElement::SetChild(child, index)`: put `child` in cell `index` (row-major).
62    pub fn set_table_child(&mut self, table: NodeId, index: usize, child: NodeId) {
63        if let Kind::Control(Control::Table {
64            cells,
65            columns,
66            rows,
67            ..
68        }) = &mut self.nodes[table].kind
69        {
70            let cols = columns.len().max(1);
71            let (x, y) = (index % cols, index / cols);
72            if y >= rows.len() {
73                rows.resize(y + 1, 0);
74            }
75            cells.retain(|c| (c.0, c.1) != (x, y));
76            cells.push((x, y, child));
77        }
78    }
79
80    /// `UI::ImageElement::SetSprite` on every image inside `id`.
81    pub fn set_images(&mut self, id: NodeId, sprite: SpriteRef) {
82        let mut stack = vec![id];
83        while let Some(n) = stack.pop() {
84            if let Kind::Image { sprite: s, .. } = &mut self.nodes[n].kind {
85                *s = Some(sprite);
86            }
87            stack.extend(self.child_ids(n));
88        }
89    }
90
91    /// The range of the spinner's number edit, its current value clamped to it.
92    ///
93    /// Original: `SpinnerElement::SetMinMax`, Runtime `0x1800da5b0`.
94    pub fn set_spinner_range(&mut self, id: NodeId, min: i32, max: i32) {
95        let edit = match &self.nodes[id].kind {
96            Kind::Control(Control::Spinner { parts, .. }) => parts[0],
97            _ => None,
98        };
99        let Some(edit) = edit else { return };
100        if let Kind::Control(Control::Edit(e)) = &mut self.nodes[edit].kind {
101            e.range = Some([min as f32, max as f32]);
102        }
103        let value = match &self.nodes[id].kind {
104            Kind::Control(Control::Spinner { value, .. }) => *value,
105            _ => return,
106        };
107        let clamped = value.clamp(min.min(max), min.max(max));
108        if clamped != value {
109            if let Kind::Control(Control::Spinner { value, .. }) = &mut self.nodes[id].kind {
110                *value = clamped;
111            }
112            self.set_text(edit, &clamped.to_string());
113        }
114    }
115
116    // +0xf8; +0xfc
117    /// The range of a spinner's number edit.
118    pub fn spinner_range(&self, id: NodeId) -> Option<(i32, i32)> {
119        let Kind::Control(Control::Spinner { parts, .. }) = &self.nodes[id].kind else {
120            return None;
121        };
122        match &self.nodes[parts[0]?].kind {
123            Kind::Control(Control::Edit(e)) => e
124                .range
125                .map(|r| (r[0].min(r[1]) as i32, r[0].max(r[1]) as i32)),
126            _ => None,
127        }
128    }
129
130    /// Whether a check control is checked.
131    pub fn checked(&self, id: NodeId) -> bool {
132        matches!(
133            self.nodes[id].kind,
134            Kind::Control(Control::Check { checked: true, .. })
135        )
136    }
137
138    /// Check or clear a check box.
139    pub fn set_checked(&mut self, id: NodeId, value: bool) {
140        if let Kind::Control(Control::Check { checked, .. }) = &mut self.nodes[id].kind {
141            *checked = value;
142        }
143    }
144
145    /// Set the choices of a combo box.
146    pub fn set_choices(&mut self, id: NodeId, choices: Vec<String>) {
147        self.set_choices_with_icons(id, choices, Vec::new());
148    }
149
150    /// `ComboElement::AddItem` for each item, its text and sprite.
151    pub fn set_choices_with_icons(
152        &mut self,
153        id: NodeId,
154        choices: Vec<String>,
155        icons: Vec<Option<SpriteRef>>,
156    ) {
157        if let Kind::Control(Control::Combo { list, .. }) = self.nodes[id].kind {
158            self.set_list_icons(list, choices, icons);
159        }
160    }
161
162    /// `GraphElement::SetYRange`, `SetXDivisions`, `RemoveGraphs` then `AddGraph` and
163    /// `AddGraphPoint` for each (colour, points).
164    pub fn set_graph(
165        &mut self,
166        id: NodeId,
167        y_range: f32,
168        x_divisions: i32,
169        series: Vec<(u32, Vec<i32>)>,
170    ) {
171        if let Kind::Control(Control::Graph {
172            series: s,
173            y_range: y,
174            x_divisions: x,
175            ..
176        }) = &mut self.nodes[id].kind
177        {
178            *s = series;
179            *y = y_range;
180            *x = x_divisions;
181        }
182    }
183
184    /// `LabelElement::SetSpriteColor`.
185    pub fn set_label_sprite_color(&mut self, id: NodeId, color: u32) {
186        if let Kind::Label { icon_color, .. } = &mut self.nodes[id].kind {
187            *icon_color = color;
188        }
189    }
190}