banished_ui/
instantiate.rs1use super::*;
5
6impl Ui {
7 pub fn instantiate(&mut self, reference: &str) -> Option<NodeId> {
9 let name = reference
10 .rsplit_once(':')
11 .map_or(reference, |(_, name)| name);
12 let reference = self
13 .overrides
14 .last()
15 .and_then(|o| o.get(name))
16 .cloned()
17 .unwrap_or_else(|| Some(reference.to_string()))?;
18 if self.stack.len() >= 128 || self.stack.contains(&reference) {
19 log::warn!("recursive UI reference: {reference}");
20 return None;
21 }
22 self.stack.push(reference.clone());
23 let result = self.instantiate_reference(&reference);
24 self.stack.pop();
25 result
26 }
27
28 pub(super) fn instantiate_reference(&mut self, reference: &str) -> Option<NodeId> {
29 let element = self.res.element(reference)?;
30 let name = reference
31 .rsplit_once(':')
32 .map_or(reference, |(_, n)| n)
33 .to_string();
34 let id = self.instantiate_element(&element, name);
35 self.nodes[id].reference = reference.to_string();
36 Some(id)
37 }
38
39 pub(super) fn text_data(&mut self, t: &banished_formats::ui::Text) -> TextData {
40 let font = t.font.as_deref().and_then(|f| self.res.font(f));
41 let text = self.res.string(t.string_table.as_deref(), &t.text);
42 TextData {
43 font,
44 text,
45 max_width: t.max_width,
46 justify: t.justify,
47 wrap: t.wrap,
48 shadow: t.shadow,
49 ellipsis_width: t.ellipsis_width,
50 layout: TextLayout::default(),
51 }
52 }
53
54 pub(super) fn instantiate_element(&mut self, e: &Element, name: String) -> NodeId {
55 let child = |ui: &mut Ui, r: &Option<String>| r.as_deref().and_then(|r| ui.instantiate(r));
56 let mut children = Vec::new();
57 let kind = match &e.kind {
58 ElementKind::Group { children: c } => {
59 children = c.iter().filter_map(|r| child(self, r)).collect();
60 Kind::Group
61 }
62 ElementKind::Ribbon {
63 vertical,
64 uniform,
65 spacing,
66 children: c,
67 } => {
68 children = c.iter().filter_map(|r| child(self, r)).collect();
69 Kind::Ribbon {
70 vertical: *vertical,
71 uniform: *uniform,
72 spacing: *spacing,
73 cells: Vec::new(),
74 }
75 }
76 ElementKind::Border {
77 sprite_sheet,
78 sprites,
79 } => {
80 let mut out = [None; 9];
81 for (o, s) in out.iter_mut().zip(sprites) {
82 *o = self.res.sprite(sprite_sheet.as_deref(), s);
83 }
84 Kind::Border { sprites: out }
85 }
86 ElementKind::Image {
87 sprite_sheet,
88 sprite,
89 size,
90 } => Kind::Image {
91 sprite: self.res.sprite(sprite_sheet.as_deref(), sprite),
92 size: *size,
93 },
94 ElementKind::FrustumOutline {
95 sprite_sheet,
96 sprite,
97 size,
98 } => Kind::Lines {
99 sprite: self.res.sprite(sprite_sheet.as_deref(), sprite),
100 size: *size,
101 lines: Vec::new(),
102 },
103 ElementKind::AnimatedImage {
104 sprite_sheet,
105 sprite,
106 size,
107 frames,
108 rate,
109 } => {
110 let mut sprites = if frames.is_empty() {
111 vec![self.res.sprite(sprite_sheet.as_deref(), sprite)]
112 } else {
113 frames
114 .iter()
115 .map(|frame| self.res.sprite(sprite_sheet.as_deref(), frame))
116 .collect()
117 };
118 if sprites.is_empty() {
119 sprites.push(self.res.sprite(sprite_sheet.as_deref(), sprite));
120 }
121 Kind::AnimatedImage {
122 sprites,
123 size: *size,
124 frames_per_second: *rate,
125 frame: 0,
126 clock: 0.0,
127 }
128 }
129 ElementKind::Button(b) => {
130 let mut states = [None; 4];
131 for (s, r) in states.iter_mut().zip(&b.states) {
132 *s = child(self, r);
133 }
134 let content = child(self, &b.content);
135 Kind::Button {
136 states,
137 content,
138 colors: b.colors,
139 state: 0,
140 }
141 }
142 ElementKind::Text(t) => Kind::Text(self.text_data(t)),
143 ElementKind::Label(l) => Kind::Label {
144 text: self.text_data(&l.text),
145 icon: self.res.sprite(l.sprite_sheet.as_deref(), &l.sprite),
146 icon_size: l.icon_size,
147 text_alignment: l.text_alignment,
148 orientation: l.orientation,
149 min_text_width: l.min_text_width,
150 gap: l.gap,
151 icon_color: 0xFFFF_FFFF,
152 },
153 _ => Kind::Control(self.instantiate_control(&e.kind)),
154 };
155 let b = &e.base;
156 let mut node = Node::new(kind);
157 node.name = name;
158 node.margins = b.margins;
159 node.min_size = b.min_size;
160 node.alignment = b.alignment;
161 node.flags = b.flags;
162 node.color = b.color;
163 node.cursor = b.cursor;
164 node.children = children;
165 node.tooltip = self.res.string(b.string_table.as_deref(), &b.tooltip);
166 node.tooltip_dialog = b.tooltip_dialog.clone();
167 node.string_table = b.string_table.clone();
168 node.border = child(self, &b.border);
169
170 self.add(node)
171 }
172}