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 {
87 fn orphans(&self) -> Vec<Widget>;
91 fn children(&self) -> Vec<InkWrapper<Widget>>;
94}
95
96pub trait InkLeafWidget: InkWidget + Debug {}
97
98pub trait InkCompoundWidget: InkWidget + InkChildren + Debug {}
99
100impl<T> InkCompoundWidget for T where T: InkWidget + InkChildren + Debug {}
101
102impl InkChildren for inkMultiChildren {
103 fn orphans(&self) -> Vec<Widget> {
104 self.children.iter().map(|x| x.data.clone()).collect()
105 }
106
107 fn children(&self) -> Vec<InkWrapper<Widget>> {
108 self.children.to_vec()
109 }
110}
111
112impl_ink_children!(inkCanvasWidget);
113impl_ink_children!(inkHorizontalPanelWidget);
114impl_ink_children!(inkVerticalPanelWidget);
115impl_ink_children!(inkScrollAreaWidget);
116impl_ink_children!(inkUniformGridWidget);
117impl_ink_children!(inkVirtualCompoundWidget);
118impl_ink_children!(inkFlexWidget);
119impl_ink_children!(inkCacheWidget);
120
121impl_ink_widget!(inkCanvasWidget);
122impl_ink_widget!(inkHorizontalPanelWidget);
123impl_ink_widget!(inkVerticalPanelWidget);
124impl_ink_widget!(inkScrollAreaWidget);
125impl_ink_widget!(inkUniformGridWidget);
126impl_ink_widget!(inkVirtualCompoundWidget);
127impl_ink_widget!(inkFlexWidget);
128impl_ink_widget!(inkCacheWidget);
129
130impl_ink_widget!(inkTextWidget);
131impl_ink_widget!(inkImageWidget);
132impl_ink_widget!(inkVideoWidget);
133impl_ink_widget!(inkMaskWidget);
134impl_ink_widget!(inkBorderWidget);
135impl_ink_widget!(inkShapeWidget);
136impl_ink_widget!(inkCircleWidget);
137impl_ink_widget!(inkRectangleWidget);
138impl_ink_widget!(inkVectorGraphicWidget);
139
140impl_leaf_widget!(inkTextWidget);
141impl_leaf_widget!(inkImageWidget);
142impl_leaf_widget!(inkVideoWidget);
143impl_leaf_widget!(inkMaskWidget);
144impl_leaf_widget!(inkBorderWidget);
145impl_leaf_widget!(inkShapeWidget);
146impl_leaf_widget!(inkCircleWidget);
147impl_leaf_widget!(inkRectangleWidget);
148impl_leaf_widget!(inkVectorGraphicWidget);
149
150impl_classname!(inkMultiChildren);
151
152impl_classname!(inkCanvasWidget);
153impl_classname!(inkHorizontalPanelWidget);
154impl_classname!(inkVerticalPanelWidget);
155impl_classname!(inkScrollAreaWidget);
156impl_classname!(inkUniformGridWidget);
157impl_classname!(inkVirtualCompoundWidget);
158impl_classname!(inkFlexWidget);
159impl_classname!(inkCacheWidget);
160
161impl_classname!(inkTextWidget);
162impl_classname!(inkImageWidget);
163impl_classname!(inkVideoWidget);
164impl_classname!(inkMaskWidget);
165impl_classname!(inkBorderWidget);
166impl_classname!(inkShapeWidget);
167impl_classname!(inkCircleWidget);
168impl_classname!(inkRectangleWidget);
169impl_classname!(inkVectorGraphicWidget);
170impl Widget {
171 pub fn name(&self) -> Option<&str> {
172 match self {
173 Self::inkMultiChildren(_) => None,
174 Self::inkCanvasWidget(node) => Some(node.name()),
175 Self::inkHorizontalPanelWidget(node) => Some(node.name()),
176 Self::inkVerticalPanelWidget(node) => Some(node.name()),
177 Self::inkScrollAreaWidget(node) => Some(node.name()),
178 Self::inkUniformGridWidget(node) => Some(node.name()),
179 Self::inkVirtualCompoundWidget(node) => Some(node.name()),
180 Self::inkFlexWidget(node) => Some(node.name()),
181 Self::inkCacheWidget(node) => Some(node.name()),
182 Self::inkTextWidget(node) => Some(node.name()),
183 Self::inkImageWidget(node) => Some(node.name()),
184 Self::inkVideoWidget(node) => Some(node.name()),
185 Self::inkMaskWidget(node) => Some(node.name()),
186 Self::inkBorderWidget(node) => Some(node.name()),
187 Self::inkShapeWidget(node) => Some(node.name()),
188 Self::inkCircleWidget(node) => Some(node.name()),
189 Self::inkRectangleWidget(node) => Some(node.name()),
190 Self::inkVectorGraphicWidget(node) => Some(node.name()),
191 }
192 }
193 pub fn as_compound(&self) -> Option<&dyn InkCompoundWidget> {
194 match self {
195 Self::inkCanvasWidget(node) => Some(node),
196 Self::inkHorizontalPanelWidget(node) => Some(node),
197 Self::inkVerticalPanelWidget(node) => Some(node),
198 Self::inkScrollAreaWidget(node) => Some(node),
199 Self::inkUniformGridWidget(node) => Some(node),
200 Self::inkVirtualCompoundWidget(node) => Some(node),
201 Self::inkFlexWidget(node) => Some(node),
202 Self::inkCacheWidget(node) => Some(node),
203 _ => None,
204 }
205 }
206 pub fn as_widget(&self) -> Option<&dyn InkWidget> {
207 match self {
208 Self::inkMultiChildren(_) => None,
209 Self::inkCanvasWidget(widget) => Some(widget),
210 Self::inkHorizontalPanelWidget(widget) => Some(widget),
211 Self::inkVerticalPanelWidget(widget) => Some(widget),
212 Self::inkScrollAreaWidget(widget) => Some(widget),
213 Self::inkUniformGridWidget(widget) => Some(widget),
214 Self::inkVirtualCompoundWidget(widget) => Some(widget),
215 Self::inkFlexWidget(widget) => Some(widget),
216 Self::inkCacheWidget(widget) => Some(widget),
217 Self::inkTextWidget(widget) => Some(widget),
218 Self::inkImageWidget(widget) => Some(widget),
219 Self::inkVideoWidget(widget) => Some(widget),
220 Self::inkMaskWidget(widget) => Some(widget),
221 Self::inkBorderWidget(widget) => Some(widget),
222 Self::inkShapeWidget(widget) => Some(widget),
223 Self::inkCircleWidget(widget) => Some(widget),
224 Self::inkRectangleWidget(widget) => Some(widget),
225 Self::inkVectorGraphicWidget(widget) => Some(widget),
226 }
227 }
228 pub fn as_leaf(&self) -> Option<&dyn InkLeafWidget> {
229 match self {
230 Self::inkTextWidget(widget) => Some(widget),
231 Self::inkImageWidget(widget) => Some(widget),
232 Self::inkVideoWidget(widget) => Some(widget),
233 Self::inkMaskWidget(widget) => Some(widget),
234 Self::inkBorderWidget(widget) => Some(widget),
235 Self::inkShapeWidget(widget) => Some(widget),
236 Self::inkCircleWidget(widget) => Some(widget),
237 Self::inkRectangleWidget(widget) => Some(widget),
238 Self::inkVectorGraphicWidget(widget) => Some(widget),
239 _ => None,
240 }
241 }
242 pub fn is_leaf(&self) -> bool {
243 self.as_leaf().is_some()
244 }
245 pub fn is_compound(&self) -> bool {
246 self.as_compound().is_some()
247 }
248}
249
250pub trait WidgetTree {
251 fn get_widget_classname(&self, path: &[usize]) -> Option<String>;
253 fn get_path_names(&self, path: &[usize]) -> Option<Vec<String>>;
255 fn get_path_indexes(&self, path: &[&str]) -> Option<Vec<usize>>;
257 fn get_partial_path_indexes(&self, path: &[&str]) -> (Vec<usize>, String);
261}
262
263pub trait ByIndex {
264 fn by_index(&self, idx: usize) -> Option<Widget>;
266}
267
268pub trait ByName {
269 fn by_name(&self, name: &str) -> Option<(usize, Widget)>;
271}
272
273pub trait Leaves {
274 fn leaves(&self) -> Vec<WidgetSummary>;
276}
277
278impl<T> InkChildren for InkWrapper<T>
279where
280 T: InkChildren,
281{
282 fn orphans(&self) -> Vec<Widget> {
283 self.data.orphans()
284 }
285
286 fn children(&self) -> Vec<InkWrapper<Widget>> {
287 self.data.children()
288 }
289}
290
291impl InkChildren for inkWidgetLibraryItem {
292 fn orphans(&self) -> Vec<Widget> {
293 self.package.data.file.root_chunk.root_widget.orphans()
294 }
295
296 fn children(&self) -> Vec<InkWrapper<Widget>> {
297 self.package.data.file.root_chunk.root_widget.children()
298 }
299}
300
301impl<T> ByIndex for T
302where
303 T: InkChildren,
304{
305 fn by_index(&self, idx: usize) -> Option<Widget> {
306 self.orphans().get(idx).cloned()
307 }
308}
309
310impl<T> ByName for T
311where
312 T: InkChildren,
313{
314 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
315 for (idx, child) in self.orphans().iter().enumerate() {
316 if let Widget::inkMultiChildren(_) = &child {
317 panic!("unexpected inkMultiChildren with name {name}");
318 }
319 if let Some(compound) = child.as_compound()
320 && compound.name() == name
321 {
322 return Some((idx, child.clone()));
323 }
324 continue;
325 }
326 None
327 }
328}
329
330impl<T> Leaves for T
331where
332 T: InkCompoundWidget,
333{
334 fn leaves(&self) -> Vec<WidgetSummary> {
335 let mut out = vec![];
336 for child in self.children().iter() {
337 if let Some(name) = child.data.name() {
338 out.push(WidgetSummary {
339 HandleId: child.handle_id,
340 Name: Name {
341 r#type: String::from("CName"),
342 storage: String::from("string"),
343 value: name.to_string(),
344 },
345 });
346 }
347 }
348 out
349 }
350}
351
352impl ByName for Vec<InkWrapper<Widget>> {
353 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
354 for (idx, widget) in self.iter().enumerate() {
355 if let Some(compound) = widget.data.as_compound()
356 && compound.name() == name
357 {
358 return Some((idx, widget.data.clone()));
359 }
360 if let Some(leaf) = widget.data.as_leaf()
361 && leaf.name() == name
362 {
363 return Some((idx, widget.data.clone()));
364 }
365 }
366 None
367 }
368}
369
370impl ByIndex for Vec<InkWrapper<Widget>> {
371 fn by_index(&self, idx: usize) -> Option<Widget> {
372 self.get(idx).map(|x| x.data.clone())
373 }
374}
375
376impl ByName for &dyn InkCompoundWidget {
377 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
378 self.children().by_name(name)
379 }
380}
381
382impl ByIndex for &dyn InkCompoundWidget {
383 fn by_index(&self, idx: usize) -> Option<Widget> {
384 self.children().by_index(idx)
385 }
386}
387
388impl ByName for Widget {
389 fn by_name(&self, name: &str) -> Option<(usize, Widget)> {
390 self.as_compound().and_then(|x| x.by_name(name))
391 }
392}
393
394impl ByIndex for Widget {
395 fn by_index(&self, idx: usize) -> Option<Widget> {
396 if let Widget::inkMultiChildren(node) = self {
397 return node.by_index(idx);
398 }
399 if let Some(compound) = self.as_compound() {
400 return compound.children().by_index(idx);
401 }
402 Some(self.clone())
403 }
404}
405
406impl WidgetTree for inkWidgetLibraryItemInstance {
407 fn get_widget_classname(&self, path: &[usize]) -> Option<String> {
408 let mut parent: Option<Widget> = Some(Widget::inkMultiChildren(
409 self.root_widget.data.children.data.clone(),
410 ));
411 let last = path.len() - 1;
412 for (i, idx) in path.iter().enumerate() {
413 if parent.is_none() {
414 break;
415 }
416 if let Some(ref child) = parent.as_ref().unwrap().by_index(*idx) {
417 if let Widget::inkMultiChildren(_) = child {
418 panic!("encountered unexpected inkMultiChildren at index {idx}");
419 }
420 if child.as_compound().is_some() {
421 if i == last {
422 return Some(child.classname());
423 }
424 parent = Some(child.clone());
425 continue;
426 }
427 if child.as_leaf().is_some() {
428 return Some(child.classname());
429 }
430 }
431 }
432 None
433 }
434
435 fn get_path_names(&self, path: &[usize]) -> Option<Vec<String>> {
436 let mut names: Vec<String> = vec![];
437 let mut parent: Option<Widget> = Some(Widget::inkMultiChildren(
438 self.root_widget.data.children.data.clone(),
439 ));
440
441 let depth = path.len() - 1;
442 for (i, idx) in path.iter().enumerate() {
443 if parent.is_none() {
444 break;
445 }
446 if let Some(ref child) = parent.unwrap().by_index(*idx) {
447 if let Some(name) = child.name() {
448 if child.as_compound().is_some() {
449 names.push(name.to_string());
450 parent = Some(child.clone());
451 continue;
452 }
453 if child.as_leaf().is_some() {
454 names.push(name.to_string());
455 if i < depth {
456 return None;
457 }
458 break;
459 }
460 } else {
461 panic!("encountered unexpected inkMultiChildren at index {idx}");
462 }
463 }
464 return None;
465 }
466 Some(names)
467 }
468
469 fn get_path_indexes(&self, path: &[&str]) -> Option<Vec<usize>> {
470 let (found, _) = self.get_partial_path_indexes(path);
471 if path.len() != found.len() {
472 return None;
473 }
474 Some(found)
475 }
476
477 fn get_partial_path_indexes(&self, path: &[&str]) -> (Vec<usize>, String) {
478 if path.is_empty() {
479 return (Vec::with_capacity(0), "".to_string());
480 }
481 let mut indexes: Vec<usize> = vec![];
482 let depth = path.len() - 1;
483 let mut parent: Option<Widget> =
484 Some(Widget::inkCanvasWidget(self.root_widget.data.clone()));
485 for (i, name) in path.iter().enumerate() {
486 if parent.is_none() || (parent.as_ref().unwrap().is_leaf() && i < depth) {
487 return (indexes, name.to_string());
488 }
489
490 if let Some(compound) = parent.as_ref().unwrap().as_compound()
491 && let Some((idx, widget)) = compound.by_name(name)
492 {
493 indexes.push(idx);
494 parent = Some(widget);
495 continue;
496 }
497 }
498 (indexes, path.last().unwrap().to_string())
499 }
500}
501
502impl inkWidgetLibraryResource {
503 pub fn root(&self) -> &inkWidgetLibraryItem {
504 self.library_items.first().expect("Root")
505 }
506 pub fn root_chunk(&self) -> &inkWidgetLibraryItemInstance {
507 &self.root().package.data.file.root_chunk
508 }
509}
510
511impl WidgetTree for inkWidgetLibraryResource {
512 fn get_widget_classname(&self, indexes: &[usize]) -> Option<String> {
513 self.root_chunk().get_widget_classname(indexes)
514 }
515
516 fn get_path_names(&self, indexes: &[usize]) -> Option<Vec<String>> {
517 self.root_chunk().get_path_names(indexes)
518 }
519
520 fn get_path_indexes(&self, names: &[&str]) -> Option<Vec<usize>> {
521 self.root_chunk().get_path_indexes(names)
522 }
523
524 fn get_partial_path_indexes(&self, names: &[&str]) -> (Vec<usize>, String) {
525 self.root_chunk().get_partial_path_indexes(names)
526 }
527}