1use super::*;
5
6impl Ui {
7 pub fn find(&self, root: NodeId, name: &str) -> Option<NodeId> {
9 if self.nodes[root].name == name {
10 return Some(root);
11 }
12 self.child_ids(root)
13 .into_iter()
14 .find_map(|c| self.find(c, name))
15 }
16
17 pub(super) fn child_ids(&self, id: NodeId) -> Vec<NodeId> {
18 let n = &self.nodes[id];
19 let mut out = n.children.clone();
20 out.extend(n.border);
21 if let Kind::Control(c) = &n.kind {
22 out.extend(c.children());
23 }
24 if let Kind::Button {
25 states, content, ..
26 } = &n.kind
27 {
28 out.extend(states.iter().flatten());
29 out.extend(content.iter());
30 }
31 out
32 }
33
34 pub fn children(&self, id: NodeId) -> Vec<NodeId> {
37 self.child_ids(id)
38 }
39
40 pub fn set_text(&mut self, id: NodeId, text: &str) {
42 let target = match &self.nodes[id].kind {
43 Kind::Button {
44 content: Some(c), ..
45 } => *c,
46 _ => id,
47 };
48 match &mut self.nodes[target].kind {
49 Kind::Text(t) | Kind::Label { text: t, .. } => t.text = text.to_string(),
50 Kind::Control(Control::Edit(e)) => {
51 e.text.text = text.to_string();
52 e.cursor = if e.max_length > 0 {
54 text.chars().count()
55 } else {
56 0
57 };
58 }
59 Kind::Control(Control::Document(d)) => d.text = text.to_string(),
60 Kind::Control(Control::Combo { button, .. } | Control::Check { button, .. }) => {
61 let b = *button;
62 self.set_text(b, text);
63 }
64 _ => log::warn!("set_text on non-text node {}", self.nodes[target].name),
65 }
66 }
67
68 pub fn set_icon(&mut self, id: NodeId, sprite: SpriteRef) {
71 let target = match &self.nodes[id].kind {
72 Kind::Control(Control::Combo { button, .. }) => *button,
73 _ => id,
74 };
75 let mut stack = vec![target];
76 while let Some(n) = stack.pop() {
77 if let Kind::Label { icon, .. } = &mut self.nodes[n].kind {
78 *icon = Some(sprite);
79 return;
80 }
81 stack.extend(self.nodes[n].children.iter().rev());
82 }
83 }
84
85 pub fn select_combo_item(&mut self, combo: NodeId, index: usize) {
87 let Kind::Control(Control::Combo { list, .. }) = self.nodes[combo].kind else {
88 return;
89 };
90 let (text, icon) = match &self.nodes[list].kind {
91 Kind::List(l) => (
92 l.items.get(index).cloned(),
93 l.icons.get(index).copied().flatten(),
94 ),
95 _ => (None, None),
96 };
97 let Some(text) = text else { return };
98 self.list_select(list, Some(index));
99 self.set_text(combo, &text);
100 if let Some(icon) = icon {
101 self.set_icon(combo, icon);
102 }
103 }
104
105 pub fn set_visible(&mut self, id: NodeId, visible: bool) {
107 let f = &mut self.nodes[id].flags;
108 *f = if visible {
109 *f & !flags::HIDDEN
110 } else {
111 *f | flags::HIDDEN
112 };
113 }
114
115 pub fn group(&mut self) -> NodeId {
117 self.add(Node::new(Kind::Group))
118 }
119
120 pub fn ribbon(&mut self, vertical: bool, spacing: i32) -> NodeId {
122 self.add(Node::new(Kind::Ribbon {
123 vertical,
124 uniform: false,
125 spacing,
126 cells: Vec::new(),
127 }))
128 }
129
130 pub fn text(&mut self, font: &str, text: &str) -> NodeId {
132 let font = self.res.font(font);
133 let data = TextData {
134 font,
135 text: text.to_string(),
136 max_width: 0,
137 justify: 0,
138 wrap: false,
139 shadow: false,
140 ellipsis_width: 0,
141 layout: TextLayout::default(),
142 };
143 self.add(Node::new(Kind::Text(data)))
144 }
145
146 pub fn viewport(&mut self) -> NodeId {
148 self.add(Node::new(Kind::Viewport))
149 }
150
151 pub fn picture(&mut self) -> NodeId {
153 self.add(Node::new(Kind::Picture {
154 texture: 0,
155 size: [0, 0],
156 }))
157 }
158
159 pub fn list(&mut self, font: &str) -> NodeId {
161 let font_id = self.res.font(font);
162 let row_height = font_id.map_or(16, |f| self.res.fonts[f].font.size + 4);
163 let highlight = self
164 .res
165 .sprite(Some(r"Dialog\SpriteSheet.rsc:resource"), "White");
166 self.add(Node::new(Kind::List(ListData {
167 items: Vec::new(),
168 icons: Vec::new(),
169 selected: None,
170 hovered: None,
171 scroll: 0,
172 font: font_id,
173 row_height,
174 highlight,
175 rows: Vec::new(),
176 reveal: false,
177 })))
178 }
179
180 pub fn slider(&mut self, range: [f32; 2]) -> NodeId {
182 self.add(Node::new(Kind::Control(Control::Slider(SliderData {
183 sprites: vec![None; 5],
184 range,
185 value: range[0],
186 steps: 0,
187 inset: 8,
188 track_y: 0,
189 number: None,
190 over_knob: false,
191 drag: None,
192 }))))
193 }
194
195 pub fn set_list_items(&mut self, id: NodeId, items: Vec<String>) {
197 self.set_list_icons(id, items, Vec::new());
198 }
199
200 pub fn set_list_icons(
202 &mut self,
203 id: NodeId,
204 items: Vec<String>,
205 icons: Vec<Option<SpriteRef>>,
206 ) {
207 if let Kind::List(l) = &mut self.nodes[id].kind {
208 l.icons = icons;
209 l.items = items;
210 l.selected = None;
211 l.hovered = None;
212 l.scroll = 0;
213 l.rows.clear();
214 }
215 }
216
217 pub fn list_select(&mut self, id: NodeId, index: Option<usize>) {
219 if let Kind::List(l) = &mut self.nodes[id].kind {
220 l.selected = index.filter(|&i| i < l.items.len());
221 l.reveal = true;
222 }
223 }
224
225 pub(super) fn reveal_selection(&mut self, id: NodeId) {
226 let h = self.nodes[id].rect[3] - self.nodes[id].rect[1];
227 if let Kind::List(l) = &mut self.nodes[id].kind {
228 if let (true, Some(i)) = (l.reveal && h > 0, l.selected) {
229 let top = i as i32 * l.row_height;
230 if top < l.scroll {
231 l.scroll = top;
232 } else if top + l.row_height > l.scroll + h {
233 l.scroll = top + l.row_height - h;
234 }
235 l.reveal = false;
236 }
237 }
238 }
239}