inkanim_types/ink/widget/
implementation.rs1use std::fmt::Debug;
2
3use enum_dispatch::enum_dispatch;
4
5use crate::{Name, ink::InkWrapper};
6
7use super::{
8 SiblingOrNested, Widget, WidgetSummary, inkBorderWidget, inkCacheWidget, inkCanvasWidget,
9 inkCircleWidget, inkFlexWidget, inkHorizontalPanelWidget, inkImageWidget, inkMaskWidget,
10 inkMultiChildren, inkRectangleWidget, inkScrollAreaWidget, inkShapeWidget, inkTextWidget,
11 inkUniformGridWidget, inkVectorGraphicWidget, inkVerticalPanelWidget, inkVideoWidget,
12 inkVirtualCompoundWidget, inkWidgetLibraryItem, inkWidgetLibraryItemInstance,
13 inkWidgetLibraryResource,
14};
15
16impl SiblingOrNested for Vec<usize> {
17 fn sibling_or_nested(&self, searched: &[usize]) -> bool {
18 let count_own = self.len();
19 let count_searched = searched.len();
20 if count_searched == 0 {
21 return true;
22 }
23 let last_searched = count_searched - 1;
24 for (i, path_index) in self.iter().enumerate() {
25 if *path_index != searched[i] {
26 return false;
27 }
28 if i == last_searched && count_own >= count_searched {
29 return true;
30 }
31 }
32 false
33 }
34}
35
36macro_rules! impl_ink_children {
37 ($ty:ident) => {
38 impl InkChildren for $ty {
39 fn orphans(&self) -> Vec<Widget> {
40 self.children.data.orphans()
41 }
42
43 fn children(&self) -> Vec<InkWrapper<Widget>> {
44 self.children.data.children()
45 }
46 }
47 };
48}
49
50macro_rules! impl_ink_widget {
51 ($ty:ident) => {
52 impl InkWidget for $ty {
53 fn name(&self) -> &str {
54 self.name.as_str()
55 }
56 }
57 };
58}
59
60macro_rules! impl_leaf_widget {
61 ($ty:ident) => {
62 impl InkLeafWidget for $ty {}
63 };
64}
65
66macro_rules! impl_classname {
67 ($ty:ident) => {
68 impl Classname for $ty {
69 fn classname(&self) -> String {
70 stringify!($ty).to_string()
71 }
72 }
73 };
74}
75
76#[enum_dispatch]
77pub trait Classname {
78 fn classname(&self) -> String;
79}
80
81pub trait InkWidget: Debug {
82 fn name(&self) -> &str;
83}
84
85pub trait InkChildren {
86 fn orphans(&self) -> Vec<Widget>;
87 fn children(&self) -> Vec<InkWrapper<Widget>>;
88}
89
90pub trait InkLeafWidget: InkWidget + Debug {}
91
92pub trait InkCompoundWidget: InkWidget + InkChildren + Debug {}
93
94impl<T> InkCompoundWidget for T where T: InkWidget + InkChildren + Debug {}
95
96impl InkChildren for inkMultiChildren {
97 fn orphans(&self) -> Vec<Widget> {
98 self.children.iter().map(|x| x.data.clone()).collect()
99 }
100
101 fn children(&self) -> Vec<InkWrapper<Widget>> {
102 self.children.to_vec()
103 }
104}
105
106impl_ink_children!(inkCanvasWidget);
107impl_ink_children!(inkHorizontalPanelWidget);
108impl_ink_children!(inkVerticalPanelWidget);
109impl_ink_children!(inkScrollAreaWidget);
110impl_ink_children!(inkUniformGridWidget);
111impl_ink_children!(inkVirtualCompoundWidget);
112impl_ink_children!(inkFlexWidget);
113impl_ink_children!(inkCacheWidget);
114
115impl_ink_widget!(inkCanvasWidget);
116impl_ink_widget!(inkHorizontalPanelWidget);
117impl_ink_widget!(inkVerticalPanelWidget);
118impl_ink_widget!(inkScrollAreaWidget);
119impl_ink_widget!(inkUniformGridWidget);
120impl_ink_widget!(inkVirtualCompoundWidget);
121impl_ink_widget!(inkFlexWidget);
122impl_ink_widget!(inkCacheWidget);
123
124impl_ink_widget!(inkTextWidget);
125impl_ink_widget!(inkImageWidget);
126impl_ink_widget!(inkVideoWidget);
127impl_ink_widget!(inkMaskWidget);
128impl_ink_widget!(inkBorderWidget);
129impl_ink_widget!(inkShapeWidget);
130impl_ink_widget!(inkCircleWidget);
131impl_ink_widget!(inkRectangleWidget);
132impl_ink_widget!(inkVectorGraphicWidget);
133
134impl_leaf_widget!(inkTextWidget);
135impl_leaf_widget!(inkImageWidget);
136impl_leaf_widget!(inkVideoWidget);
137impl_leaf_widget!(inkMaskWidget);
138impl_leaf_widget!(inkBorderWidget);
139impl_leaf_widget!(inkShapeWidget);
140impl_leaf_widget!(inkCircleWidget);
141impl_leaf_widget!(inkRectangleWidget);
142impl_leaf_widget!(inkVectorGraphicWidget);
143
144impl_classname!(inkMultiChildren);
145
146impl_classname!(inkCanvasWidget);
147impl_classname!(inkHorizontalPanelWidget);
148impl_classname!(inkVerticalPanelWidget);
149impl_classname!(inkScrollAreaWidget);
150impl_classname!(inkUniformGridWidget);
151impl_classname!(inkVirtualCompoundWidget);
152impl_classname!(inkFlexWidget);
153impl_classname!(inkCacheWidget);
154
155impl_classname!(inkTextWidget);
156impl_classname!(inkImageWidget);
157impl_classname!(inkVideoWidget);
158impl_classname!(inkMaskWidget);
159impl_classname!(inkBorderWidget);
160impl_classname!(inkShapeWidget);
161impl_classname!(inkCircleWidget);
162impl_classname!(inkRectangleWidget);
163impl_classname!(inkVectorGraphicWidget);
164impl Widget {
165 pub fn name(&self) -> Option<&str> {
166 match self {
167 Self::inkMultiChildren(_) => None,
168 Self::inkCanvasWidget(node) => Some(node.name()),
169 Self::inkHorizontalPanelWidget(node) => Some(node.name()),
170 Self::inkVerticalPanelWidget(node) => Some(node.name()),
171 Self::inkScrollAreaWidget(node) => Some(node.name()),
172 Self::inkUniformGridWidget(node) => Some(node.name()),
173 Self::inkVirtualCompoundWidget(node) => Some(node.name()),
174 Self::inkFlexWidget(node) => Some(node.name()),
175 Self::inkCacheWidget(node) => Some(node.name()),
176 Self::inkTextWidget(node) => Some(node.name()),
177 Self::inkImageWidget(node) => Some(node.name()),
178 Self::inkVideoWidget(node) => Some(node.name()),
179 Self::inkMaskWidget(node) => Some(node.name()),
180 Self::inkBorderWidget(node) => Some(node.name()),
181 Self::inkShapeWidget(node) => Some(node.name()),
182 Self::inkCircleWidget(node) => Some(node.name()),
183 Self::inkRectangleWidget(node) => Some(node.name()),
184 Self::inkVectorGraphicWidget(node) => Some(node.name()),
185 }
186 }
187 pub fn as_compound(&self) -> Option<&dyn InkCompoundWidget> {
188 match self {
189 Self::inkCanvasWidget(node) => Some(node),
190 Self::inkHorizontalPanelWidget(node) => Some(node),
191 Self::inkVerticalPanelWidget(node) => Some(node),
192 Self::inkScrollAreaWidget(node) => Some(node),
193 Self::inkUniformGridWidget(node) => Some(node),
194 Self::inkVirtualCompoundWidget(node) => Some(node),
195 Self::inkFlexWidget(node) => Some(node),
196 Self::inkCacheWidget(node) => Some(node),
197 _ => None,
198 }
199 }
200 pub fn as_widget(&self) -> Option<&dyn InkWidget> {
201 match self {
202 Self::inkMultiChildren(_) => None,
203 Self::inkCanvasWidget(widget) => Some(widget),
204 Self::inkHorizontalPanelWidget(widget) => Some(widget),
205 Self::inkVerticalPanelWidget(widget) => Some(widget),
206 Self::inkScrollAreaWidget(widget) => Some(widget),
207 Self::inkUniformGridWidget(widget) => Some(widget),
208 Self::inkVirtualCompoundWidget(widget) => Some(widget),
209 Self::inkFlexWidget(widget) => Some(widget),
210 Self::inkCacheWidget(widget) => Some(widget),
211 Self::inkTextWidget(widget) => Some(widget),
212 Self::inkImageWidget(widget) => Some(widget),
213 Self::inkVideoWidget(widget) => Some(widget),
214 Self::inkMaskWidget(widget) => Some(widget),
215 Self::inkBorderWidget(widget) => Some(widget),
216 Self::inkShapeWidget(widget) => Some(widget),
217 Self::inkCircleWidget(widget) => Some(widget),
218 Self::inkRectangleWidget(widget) => Some(widget),
219 Self::inkVectorGraphicWidget(widget) => Some(widget),
220 }
221 }
222 pub fn as_leaf(&self) -> Option<&dyn InkLeafWidget> {
223 match self {
224 Self::inkTextWidget(widget) => Some(widget),
225 Self::inkImageWidget(widget) => Some(widget),
226 Self::inkVideoWidget(widget) => Some(widget),
227 Self::inkMaskWidget(widget) => Some(widget),
228 Self::inkBorderWidget(widget) => Some(widget),
229 Self::inkShapeWidget(widget) => Some(widget),
230 Self::inkCircleWidget(widget) => Some(widget),
231 Self::inkRectangleWidget(widget) => Some(widget),
232 Self::inkVectorGraphicWidget(widget) => Some(widget),
233 _ => None,
234 }
235 }
236 pub fn is_leaf(&self) -> bool {
237 self.as_leaf().is_some()
238 }
239 pub fn is_compound(&self) -> bool {
240 self.as_compound().is_some()
241 }
242}
243
244pub trait WidgetTree {
245 fn get_widget_classname(&self, path: &[usize]) -> Option<String>;
247 fn get_path_names(&self, path: &[usize]) -> Option<Vec<String>>;
249 fn get_path_indexes(&self, path: &[&str]) -> Option<Vec<usize>>;
251}
252
253pub trait ByIndex {
254 fn by_index(&self, idx: usize) -> Option<Widget>;
256}
257
258pub trait ByName {
259 fn by_name(&self, name: &str) -> Option<(usize, Widget)>;
261}
262
263pub trait Leaves {
264 fn leaves(&self) -> Vec<WidgetSummary>;
266}
267
268impl<T> InkChildren for InkWrapper<T>
269where
270 T: InkChildren,
271{
272 fn orphans(&self) -> Vec<Widget> {
273 self.data.orphans()
274 }
275
276 fn children(&self) -> Vec<InkWrapper<Widget>> {
277 self.data.children()
278 }
279}
280
281impl<T> ByIndex for T
282where
283 T: InkChildren,
284{
285 fn by_index(&self, idx: usize) -> Option<Widget> {
286 self.orphans().get(idx).cloned()
287 }
288}
289
290impl<T> ByName for T
291where
292 T: InkChildren,
293{
294 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
295 for (idx, child) in self.orphans().iter().enumerate() {
296 if let Widget::inkMultiChildren(_) = &child {
297 panic!("unexpected inkMultiChildren with name {name}");
298 }
299 if let Some(compound) = child.as_compound() {
300 if compound.name() == name {
301 return Some((idx, child.clone()));
302 }
303 }
304 continue;
305 }
306 None
307 }
308}
309
310impl<T> Leaves for T
311where
312 T: InkCompoundWidget,
313{
314 fn leaves(&self) -> Vec<WidgetSummary> {
315 let mut out = vec![];
316 for child in self.children().iter() {
317 if let Some(name) = child.data.name() {
318 out.push(WidgetSummary {
319 HandleId: child.handle_id,
320 Name: Name {
321 r#type: String::from("CName"),
322 storage: String::from("string"),
323 value: name.to_string(),
324 },
325 });
326 }
327 }
328 out
329 }
330}
331
332impl ByName for Vec<InkWrapper<Widget>> {
333 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
334 for (idx, widget) in self.iter().enumerate() {
335 if let Some(compound) = widget.data.as_compound() {
336 if compound.name() == name {
337 return Some((idx, widget.data.clone()));
338 }
339 }
340 if let Some(leaf) = widget.data.as_leaf() {
341 if leaf.name() == name {
342 return Some((idx, widget.data.clone()));
343 }
344 }
345 }
346 None
347 }
348}
349
350impl ByIndex for Vec<InkWrapper<Widget>> {
351 fn by_index(&self, idx: usize) -> Option<Widget> {
352 self.get(idx).map(|x| x.data.clone())
353 }
354}
355
356impl ByName for &dyn InkCompoundWidget {
357 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
358 self.children().by_name(name)
359 }
360}
361
362impl ByIndex for &dyn InkCompoundWidget {
363 fn by_index(&self, idx: usize) -> Option<Widget> {
364 self.children().by_index(idx)
365 }
366}
367
368impl ByIndex for Widget {
369 fn by_index(&self, idx: usize) -> Option<Widget> {
370 if let Widget::inkMultiChildren(node) = self {
371 return node.by_index(idx);
372 }
373 if let Some(compound) = self.as_compound() {
374 return compound.children().by_index(idx);
375 }
376 Some(self.clone())
377 }
378}
379
380impl WidgetTree for inkWidgetLibraryItemInstance {
381 fn get_widget_classname(&self, path: &[usize]) -> Option<String> {
382 let mut parent: Option<Widget> = Some(Widget::inkMultiChildren(
383 self.root_widget.data.children.data.clone(),
384 ));
385 let last = path.len() - 1;
386 for (i, idx) in path.iter().enumerate() {
387 if parent.is_none() {
388 break;
389 }
390 if let Some(ref child) = parent.as_ref().unwrap().by_index(*idx) {
391 if let Widget::inkMultiChildren(_) = child {
392 panic!("encountered unexpected inkMultiChildren at index {idx}");
393 }
394 if child.as_compound().is_some() {
395 if i == last {
396 return Some(child.classname());
397 }
398 parent = Some(child.clone());
399 continue;
400 }
401 if child.as_leaf().is_some() {
402 return Some(child.classname());
403 }
404 }
405 }
406 None
407 }
408
409 fn get_path_names(&self, path: &[usize]) -> Option<Vec<String>> {
410 let mut names: Vec<String> = vec![];
411 let mut parent: Option<Widget> = Some(Widget::inkMultiChildren(
412 self.root_widget.data.children.data.clone(),
413 ));
414
415 let depth = path.len() - 1;
416 for (i, idx) in path.iter().enumerate() {
417 if parent.is_none() {
418 break;
419 }
420 if let Some(ref child) = parent.unwrap().by_index(*idx) {
421 if let Some(name) = child.name() {
422 if child.as_compound().is_some() {
423 names.push(name.to_string());
424 parent = Some(child.clone());
425 continue;
426 }
427 if child.as_leaf().is_some() {
428 names.push(name.to_string());
429 if i < depth {
430 return None;
431 }
432 break;
433 }
434 } else {
435 panic!("encountered unexpected inkMultiChildren at index {idx}");
436 }
437 }
438 return None;
439 }
440 Some(names)
441 }
442
443 fn get_path_indexes(&self, path: &[&str]) -> Option<Vec<usize>> {
444 let mut indexes: Vec<usize> = vec![];
445 let depth = path.len() - 1;
446 let mut parent: Option<Widget> =
447 Some(Widget::inkCanvasWidget(self.root_widget.data.clone()));
448 for (i, name) in path.iter().enumerate() {
449 if parent.is_none() {
450 break;
451 }
452
453 if parent.as_ref().unwrap().is_leaf() {
454 if i < depth {
455 return None;
456 }
457 break;
458 }
459
460 if let Some(compound) = parent.as_ref().unwrap().as_compound() {
461 if let Some((idx, widget)) = compound.by_name(name) {
462 indexes.push(idx);
463 parent = Some(widget);
464 continue;
465 }
466 }
467 return None;
468 }
469 Some(indexes)
470 }
471}
472
473impl inkWidgetLibraryResource {
474 pub fn root(&self) -> &inkWidgetLibraryItem {
475 self.library_items.first().expect("Root")
476 }
477 pub fn root_chunk(&self) -> &inkWidgetLibraryItemInstance {
478 &self.root().package.data.file.root_chunk
479 }
480}
481
482impl WidgetTree for inkWidgetLibraryResource {
483 fn get_widget_classname(&self, indexes: &[usize]) -> Option<String> {
484 self.root_chunk().get_widget_classname(indexes)
485 }
486
487 fn get_path_names(&self, indexes: &[usize]) -> Option<Vec<String>> {
488 self.root_chunk().get_path_names(indexes)
489 }
490
491 fn get_path_indexes(&self, names: &[&str]) -> Option<Vec<usize>> {
492 self.root_chunk().get_path_indexes(names)
493 }
494}