1use std::{
34 cell::RefCell,
35 collections::hash_map::DefaultHasher,
36 hash::{Hash, Hasher},
37 rc::Rc,
38};
39
40use rs_math3d::Dimensioni;
41
42use crate::{
43 input::{ContainerOption, WidgetBehaviourOption},
44 layout::{SizePolicy, StackDirection},
45 widget::Widget,
46 ContainerHandle, Custom, CustomRenderArgs, Node, TextBlock, TextWrap,
47};
48
49use super::{erased_widget_state, widget_handle, NodeId, Policy, TreeCustomRender, WidgetHandle, WidgetTree, WidgetTreeNode, WidgetTreeNodeKind};
50
51struct BuilderFrame {
52 scope_seed: u64,
53 next_auto: u64,
54 nodes: Vec<WidgetTreeNode>,
55}
56
57impl BuilderFrame {
58 fn root(seed: u64) -> Self {
59 Self {
60 scope_seed: seed,
61 next_auto: 0,
62 nodes: Vec::new(),
63 }
64 }
65
66 fn child(seed: u64) -> Self {
67 Self {
68 scope_seed: seed,
69 next_auto: 0,
70 nodes: Vec::new(),
71 }
72 }
73}
74
75#[derive(Copy, Clone, Debug, PartialEq)]
76pub struct NodeOptions {
81 policy: Policy,
82 key: Option<u64>,
83}
84
85impl Default for NodeOptions {
86 fn default() -> Self {
87 Self::new()
88 }
89}
90
91impl NodeOptions {
92 pub const fn new() -> Self {
94 Self { policy: Policy::auto(), key: None }
95 }
96
97 pub const fn with_policy(policy: Policy) -> Self {
99 Self { policy, key: None }
100 }
101
102 pub fn keyed<K: Hash>(key: K) -> Self {
104 Self::new().key(key)
105 }
106
107 pub const fn policy(mut self, policy: Policy) -> Self {
109 self.policy = policy;
110 self
111 }
112
113 pub fn key<K: Hash>(mut self, key: K) -> Self {
115 self.key = Some(hash_builder_key(key));
116 self
117 }
118}
119
120fn hash_builder_key<K: Hash>(key: K) -> u64 {
121 let mut hasher = DefaultHasher::new();
122 key.hash(&mut hasher);
123 hasher.finish()
124}
125
126pub struct WidgetTreeBuilder {
132 frames: Vec<BuilderFrame>,
133}
134
135impl Default for WidgetTreeBuilder {
136 fn default() -> Self {
137 Self::new()
138 }
139}
140
141impl WidgetTreeBuilder {
142 pub const DEFAULT_ROOT_SEED: u64 = 0x9e37_79b9_7f4a_7c15;
144
145 pub fn new() -> Self {
147 Self::with_seed(Self::DEFAULT_ROOT_SEED)
148 }
149
150 pub fn with_seed(seed: u64) -> Self {
152 Self { frames: vec![BuilderFrame::root(seed)] }
153 }
154
155 pub fn build(f: impl FnOnce(&mut Self)) -> WidgetTree {
157 let mut builder = Self::new();
158 f(&mut builder);
159 builder.finish()
160 }
161
162 pub fn build_with_seed(seed: u64, f: impl FnOnce(&mut Self)) -> WidgetTree {
164 let mut builder = Self::with_seed(seed);
165 f(&mut builder);
166 builder.finish()
167 }
168
169 pub fn finish(mut self) -> WidgetTree {
171 debug_assert_eq!(self.frames.len(), 1, "widget tree builder scopes must be balanced");
172 let frame = self.frames.pop().expect("root frame missing");
173 WidgetTree { roots: frame.nodes }
174 }
175
176 pub fn widget<W: Widget + 'static>(&mut self, widget: WidgetHandle<W>) -> NodeId {
178 self.widget_with(NodeOptions::new(), widget)
179 }
180
181 pub fn widget_with<W: Widget + 'static>(&mut self, options: NodeOptions, widget: WidgetHandle<W>) -> NodeId {
183 self.push_leaf(options, WidgetTreeNodeKind::Widget { widget: erased_widget_state(widget) })
184 }
185
186 pub fn text(&mut self, text: impl Into<String>) -> NodeId {
188 let text = text.into();
189 self.widget(widget_handle(TextBlock::new(text)))
190 }
191
192 pub fn text_with_wrap(&mut self, text: impl Into<String>, wrap: TextWrap) -> NodeId {
194 let text = text.into();
195 self.widget(widget_handle(TextBlock::with_wrap(text, wrap)))
196 }
197
198 pub fn custom_render<F>(&mut self, state: WidgetHandle<Custom>, f: F) -> NodeId
200 where
201 F: FnMut(Dimensioni, &CustomRenderArgs) + 'static,
202 {
203 self.custom_render_with(NodeOptions::new(), state, f)
204 }
205
206 pub fn custom_render_with<F>(&mut self, options: NodeOptions, state: WidgetHandle<Custom>, f: F) -> NodeId
208 where
209 F: FnMut(Dimensioni, &CustomRenderArgs) + 'static,
210 {
211 let render: TreeCustomRender = Rc::new(RefCell::new(Box::new(f)));
212 self.push_leaf(options, WidgetTreeNodeKind::CustomRender { state, render })
213 }
214
215 pub fn container(&mut self, handle: ContainerHandle, opt: ContainerOption, behaviour: WidgetBehaviourOption, f: impl FnOnce(&mut Self)) -> NodeId {
217 self.container_with(NodeOptions::new(), handle, opt, behaviour, f)
218 }
219
220 pub fn container_with(
222 &mut self,
223 options: NodeOptions,
224 handle: ContainerHandle,
225 opt: ContainerOption,
226 behaviour: WidgetBehaviourOption,
227 f: impl FnOnce(&mut Self),
228 ) -> NodeId {
229 self.push_group(options, WidgetTreeNodeKind::Container { handle, opt, behaviour }, f)
230 }
231
232 pub fn header(&mut self, state: WidgetHandle<Node>, f: impl FnOnce(&mut Self)) -> NodeId {
234 self.header_with(NodeOptions::new(), state, f)
235 }
236
237 pub fn header_with(&mut self, options: NodeOptions, state: WidgetHandle<Node>, f: impl FnOnce(&mut Self)) -> NodeId {
239 self.push_group(options, WidgetTreeNodeKind::Header { state }, f)
240 }
241
242 pub fn tree_node(&mut self, state: WidgetHandle<Node>, f: impl FnOnce(&mut Self)) -> NodeId {
244 self.tree_node_with(NodeOptions::new(), state, f)
245 }
246
247 pub fn tree_node_with(&mut self, options: NodeOptions, state: WidgetHandle<Node>, f: impl FnOnce(&mut Self)) -> NodeId {
249 self.push_group(options, WidgetTreeNodeKind::Tree { state }, f)
250 }
251
252 pub fn row(&mut self, widths: &[SizePolicy], height: SizePolicy, f: impl FnOnce(&mut Self)) -> NodeId {
254 self.row_with(NodeOptions::new(), widths, height, f)
255 }
256
257 pub fn row_with(&mut self, options: NodeOptions, widths: &[SizePolicy], height: SizePolicy, f: impl FnOnce(&mut Self)) -> NodeId {
259 self.push_group(options, WidgetTreeNodeKind::Row { widths: widths.to_vec(), height }, f)
260 }
261
262 pub fn grid(&mut self, widths: &[SizePolicy], heights: &[SizePolicy], f: impl FnOnce(&mut Self)) -> NodeId {
264 self.grid_with(NodeOptions::new(), widths, heights, f)
265 }
266
267 pub fn grid_with(&mut self, options: NodeOptions, widths: &[SizePolicy], heights: &[SizePolicy], f: impl FnOnce(&mut Self)) -> NodeId {
269 self.push_group(
270 options,
271 WidgetTreeNodeKind::Grid {
272 widths: widths.to_vec(),
273 heights: heights.to_vec(),
274 },
275 f,
276 )
277 }
278
279 pub fn column(&mut self, f: impl FnOnce(&mut Self)) -> NodeId {
281 self.column_with(NodeOptions::new(), f)
282 }
283
284 pub fn column_with(&mut self, options: NodeOptions, f: impl FnOnce(&mut Self)) -> NodeId {
286 self.push_group(options, WidgetTreeNodeKind::Column, f)
287 }
288
289 pub fn stack(&mut self, width: SizePolicy, height: SizePolicy, direction: StackDirection, f: impl FnOnce(&mut Self)) -> NodeId {
291 self.stack_with(NodeOptions::new(), width, height, direction, f)
292 }
293
294 pub fn stack_with(&mut self, options: NodeOptions, width: SizePolicy, height: SizePolicy, direction: StackDirection, f: impl FnOnce(&mut Self)) -> NodeId {
296 self.push_group(options, WidgetTreeNodeKind::Stack { width, height, direction }, f)
297 }
298
299 fn push_leaf(&mut self, options: NodeOptions, kind: WidgetTreeNodeKind) -> NodeId {
300 let id = self.alloc_id(kind.tag(), options.key);
301 self.current_frame_mut().nodes.push(WidgetTreeNode {
302 id,
303 policy: options.policy,
304 kind,
305 children: Vec::new(),
306 });
307 id
308 }
309
310 fn push_group(&mut self, options: NodeOptions, kind: WidgetTreeNodeKind, f: impl FnOnce(&mut Self)) -> NodeId {
311 let id = self.alloc_id(kind.tag(), options.key);
312 self.frames.push(BuilderFrame::child(id.raw() as u64));
313 f(self);
314 let frame = self.frames.pop().expect("child frame missing");
315 self.current_frame_mut().nodes.push(WidgetTreeNode {
316 id,
317 policy: options.policy,
318 kind,
319 children: frame.nodes,
320 });
321 id
322 }
323
324 fn alloc_id(&mut self, tag: u8, key: Option<u64>) -> NodeId {
325 let frame = self.current_frame_mut();
326 let ordinal = frame.next_auto;
327 frame.next_auto += 1;
328
329 let mut hasher = DefaultHasher::new();
330 frame.scope_seed.hash(&mut hasher);
331 tag.hash(&mut hasher);
332 match key {
333 Some(key) => {
334 1u8.hash(&mut hasher);
335 key.hash(&mut hasher);
336 }
337 None => {
338 0u8.hash(&mut hasher);
339 ordinal.hash(&mut hasher);
340 }
341 }
342 NodeId::new(hasher.finish())
343 }
344
345 fn current_frame_mut(&mut self) -> &mut BuilderFrame {
346 self.frames.last_mut().expect("widget tree builder frame missing")
347 }
348}