1pub mod font;
5pub mod image;
6pub(crate) mod implementation;
7pub mod layout;
8pub mod properties;
9
10use enum_dispatch::enum_dispatch;
11pub use implementation::*;
12
13use serde::{Deserialize, Serialize, ser::SerializeSeq};
14use serde_aux::prelude::deserialize_bool_from_anything;
15
16use crate::{DepotPath, Name, Vector2, is_any_default_localization_string};
17
18use self::{
19 font::{
20 fontStyle, inkFontFamilyResource, textHorizontalAlignment, textLetterCase,
21 textOverflowPolicy, textVerticalAlignment,
22 },
23 image::{inkBrushMirrorType, inkBrushTileType, inkTextureAtlas},
24 layout::{inkEHorizontalAlign, inkEVerticalAlign, inkMargin, textJustificationType},
25};
26
27use super::{HandleId, InkWrapper, LocalizationString};
28
29pub trait SiblingOrNested {
31 fn sibling_or_nested(&self, searched: &[usize]) -> bool;
32}
33
34#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
35#[non_exhaustive]
36pub enum Flags {
37 #[default]
38 Default,
39 Soft,
40 Hard,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct Pivot(Vector2);
45
46impl Default for Pivot {
47 fn default() -> Self {
48 Self(Vector2 { x: 0.5, y: 0.5 })
49 }
50}
51
52fn is_default<T: Default + PartialEq>(value: &T) -> bool {
53 *value == T::default()
54}
55
56macro_rules! native_compound_widget {
57 ($ty:ident) => {
58 #[doc=concat!("see [NativeDB](https://nativedb.red4ext.com/", stringify!($ty), ")")]
59 #[allow(non_camel_case_types)]
60 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
61 #[serde(rename_all = "camelCase")]
62 pub struct $ty {
63 #[serde(default, skip_serializing_if = "is_default")]
64 pub children: InkWrapper<inkMultiChildren>,
65 #[serde(default, skip_serializing_if = "is_default")]
66 pub name: $crate::Name,
67 #[serde(default, skip_serializing_if = "is_default")]
68 pub child_order: self::layout::inkEChildOrder,
69 #[serde(default, skip_serializing_if = "is_default")]
70 pub child_margin: self::layout::inkMargin,
71 }
72 };
73}
74
75macro_rules! native_leaf_widget {
76 ($ty:ident { $($tt:tt)* }) => {
77 #[doc=concat!("🌿 see [NativeDB](https://nativedb.red4ext.com/", stringify!($ty), ")")]
78 #[allow(non_camel_case_types)]
79 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
80 #[serde(rename_all = "camelCase")]
81 pub struct $ty {
82 #[serde(default, skip_serializing_if = "is_default")]
83 pub name: $crate::Name,
84 #[serde(default, skip_serializing_if = "is_default")]
85 pub layout: self::layout::inkWidgetLayout,
86 #[serde(default, skip_serializing_if = "is_default")]
87 pub property_manager: Option<self::properties::PropertyManager>,
88 #[serde(default, skip_serializing_if = "is_default")]
89 pub render_transform_pivot: self::Pivot,
90 #[serde(default, skip_serializing_if = "is_default")]
91 pub render_transform: self::layout::inkUITransform,
92 #[serde(default, skip_serializing_if = "is_default")]
93 pub size: crate::Vector2,
94 $($tt)*
95 }
96 };
97 ($ty:ident) => {
98 native_leaf_widget!($ty {});
99 };
100}
101
102native_compound_widget!(inkCanvasWidget);
103native_compound_widget!(inkHorizontalPanelWidget);
104native_compound_widget!(inkVerticalPanelWidget);
105native_compound_widget!(inkScrollAreaWidget);
106native_compound_widget!(inkUniformGridWidget);
107native_compound_widget!(inkVirtualCompoundWidget);
108native_compound_widget!(inkFlexWidget);
109native_compound_widget!(inkCacheWidget);
110
111#[allow(non_camel_case_types)]
113#[derive(Debug, Default, Clone, Deserialize, PartialEq)]
114pub struct inkMultiChildren {
115 pub children: Vec<InkWrapper<Widget>>,
116}
117
118impl Serialize for inkMultiChildren {
119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120 where
121 S: serde::Serializer,
122 {
123 let mut seq = serializer.serialize_seq(Some(self.children.len()))?;
124 for elem in self.children.iter() {
125 seq.serialize_element(elem)?;
126 }
127 seq.end()
128 }
129}
130
131#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
132#[serde(transparent)]
133pub struct ScrollDelay(u16);
134
135impl Default for ScrollDelay {
136 fn default() -> Self {
137 Self(30)
138 }
139}
140
141#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
142#[serde(transparent)]
143pub struct ScrollTextSpeed(f32);
144
145impl Default for ScrollTextSpeed {
146 fn default() -> Self {
147 Self(0.2)
148 }
149}
150
151native_leaf_widget!(inkTextWidget {
152 #[serde(default, skip_serializing_if = "is_any_default_localization_string",)]
153 pub localization_string: LocalizationString,
154 #[serde(default, skip_serializing_if = "is_default")]
155 pub text: String,
156 #[serde(default, skip_serializing_if = "is_default")]
157 pub font_family: inkFontFamilyResource,
158 #[serde(default, skip_serializing_if = "is_default")]
159 pub font_style: fontStyle,
160 #[serde(default, skip_serializing_if = "is_default")]
161 pub justification: textJustificationType,
162 #[serde(default, skip_serializing_if = "is_default")]
163 pub text_letter_case: Option<textLetterCase>,
164 #[serde(default, skip_serializing_if = "is_default")]
165 pub line_height_percentage: f32,
166 #[serde(default, skip_serializing_if = "is_default")]
167 pub text_horizontal_alignment: textHorizontalAlignment,
168 #[serde(default, skip_serializing_if = "is_default")]
169 pub text_vertical_alignment: textVerticalAlignment,
170 #[serde(default, skip_serializing_if = "is_default")]
171 pub text_overflow_policy: textOverflowPolicy,
172 #[serde(default, skip_serializing_if = "is_default")]
173 pub content_h_align: inkEHorizontalAlign,
174 #[serde(default, skip_serializing_if = "is_default")]
175 pub content_v_align: inkEVerticalAlign,
176 #[serde(default, skip_serializing_if = "is_default")]
177 pub scroll_delay: self::ScrollDelay,
178 #[serde(default, skip_serializing_if = "is_default")]
179 pub scroll_text_speed: self::ScrollTextSpeed,
180});
181native_leaf_widget!(inkImageWidget {
182 #[serde(deserialize_with = "deserialize_bool_from_anything")]
183 pub use_external_dynamic_texture: bool,
184 pub external_dynamic_texture: Name,
185 #[serde(deserialize_with = "deserialize_bool_from_anything")]
186 pub use_nine_slice_scale: bool,
187 pub nine_slice_scale: inkMargin,
188 pub mirror_type: inkBrushMirrorType,
189 pub tile_type: inkBrushTileType,
190 pub horizontal_tile_crop: f32,
191 pub vertical_tile_crop: f32,
192 pub texture_atlas: inkTextureAtlas,
193 pub texture_part: Name,
194 pub content_h_align: inkEHorizontalAlign,
195 pub content_v_align: inkEVerticalAlign,
196 pub tile_h_align: inkEHorizontalAlign,
197 pub tile_v_align: inkEVerticalAlign,
198});
199native_leaf_widget!(inkVideoWidget);
200native_leaf_widget!(inkMaskWidget);
201native_leaf_widget!(inkBorderWidget);
202native_leaf_widget!(inkShapeWidget);
203native_leaf_widget!(inkCircleWidget);
204native_leaf_widget!(inkRectangleWidget);
205native_leaf_widget!(inkVectorGraphicWidget);
206
207#[allow(clippy::enum_variant_names)]
209#[allow(non_camel_case_types)]
210#[non_exhaustive]
211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
212#[enum_dispatch(Classname)]
213#[serde(tag = "$type")]
214pub enum Widget {
215 inkMultiChildren(inkMultiChildren),
216
217 inkCanvasWidget(inkCanvasWidget),
218 inkHorizontalPanelWidget(inkHorizontalPanelWidget),
219 inkVerticalPanelWidget(inkVerticalPanelWidget),
220 inkScrollAreaWidget(inkScrollAreaWidget),
221 inkUniformGridWidget(inkUniformGridWidget),
222 inkVirtualCompoundWidget(inkVirtualCompoundWidget),
223 inkFlexWidget(inkFlexWidget),
224 inkCacheWidget(inkCacheWidget),
225
226 inkTextWidget(inkTextWidget),
227 inkImageWidget(inkImageWidget),
228 inkVideoWidget(inkVideoWidget),
229 inkMaskWidget(inkMaskWidget),
230 inkBorderWidget(inkBorderWidget),
231 inkShapeWidget(inkShapeWidget),
232 inkCircleWidget(inkCircleWidget),
233 inkRectangleWidget(inkRectangleWidget),
234 inkVectorGraphicWidget(inkVectorGraphicWidget),
235}
236
237#[allow(non_camel_case_types)]
239#[derive(Debug, Clone, Serialize, Deserialize)]
240#[serde(rename_all = "camelCase")]
241pub struct inkWidgetLibraryItemInstance {
242 pub root_widget: InkWrapper<inkCanvasWidget>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(rename_all = "PascalCase")]
247pub struct Data {
248 pub file: crate::Data<inkWidgetLibraryItemInstance>,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
252#[serde(rename_all = "PascalCase")]
253pub struct Package {
254 pub data: self::Data,
255}
256
257#[allow(non_camel_case_types)]
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct inkWidgetLibraryItem {
261 pub name: Name,
262 pub package: Package,
263}
264
265#[allow(non_camel_case_types)]
267#[derive(Debug, Clone, Serialize, Deserialize)]
268#[serde(rename_all = "PascalCase")]
269pub struct inkanimAnimationLibraryResource {
270 depot_path: DepotPath,
271 flags: Flags,
272}
273
274#[allow(non_camel_case_types)]
276#[derive(Debug, Clone, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct inkWidgetLibraryResource {
279 pub animation_library_res_ref: inkanimAnimationLibraryResource,
280 pub library_items: Vec<inkWidgetLibraryItem>,
281}
282
283#[allow(non_snake_case)]
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct WidgetSummary {
287 pub HandleId: HandleId,
289 pub Name: Name,
291}