Skip to main content

bevy_hui/
data.rs

1use crate::adaptor::AssetLoadAdaptor;
2use crate::animation::{AnimationDirection, Atlas};
3use crate::prelude::*;
4use crate::util::{SlotId, SlotMap};
5use bevy::ecs::system::EntityCommands;
6use bevy::platform::collections::HashMap;
7use bevy::prelude::*;
8use bevy::ui::widget::NodeImageMode;
9
10#[derive(Debug, Default, Reflect)]
11#[reflect]
12pub enum NodeType {
13    #[default]
14    Node,
15    Image,
16    Text,
17    Button,
18    Slot,
19    Template,
20    Property,
21    Custom(String),
22}
23
24/// a single nodes data
25#[derive(Debug, Default, Reflect)]
26#[reflect]
27pub struct XNode {
28    pub uuid: u64,
29    pub src: Option<String>,
30    pub styles: Vec<StyleAttr>,
31    pub target: Option<String>,
32    pub watch: Option<String>,
33    pub id: Option<String>,
34    pub name: Option<String>,
35    pub uncompiled: Vec<AttrTokens>,
36    pub tags: HashMap<String, String>,
37    pub defs: HashMap<String, String>,
38    pub event_listener: Vec<Action>,
39    pub content_id: SlotId,
40    pub node_type: NodeType,
41    #[reflect(ignore)]
42    pub children: Vec<XNode>,
43}
44
45/// holds a parsed template
46/// can be build as UI.
47#[derive(Debug, Asset, Reflect)]
48#[reflect]
49pub struct HtmlTemplate {
50    pub name: Option<String>,
51    pub properties: HashMap<String, String>,
52    pub root: Vec<XNode>,
53    pub content: SlotMap<String>,
54}
55
56/// any valid attribute that can be found
57/// on nodes.
58#[derive(Debug, Clone, Reflect)]
59#[reflect]
60pub enum Attribute {
61    Style(StyleAttr),
62    PropertyDefinition(String, String),
63    Name(String),
64    Uncompiled(AttrTokens),
65    Action(Action),
66    Path(String),
67    Target(String),
68    Id(String),
69    Watch(String),
70    Tag(String, String),
71}
72
73/// raw attribute
74#[derive(Debug, Reflect, PartialEq, Clone)]
75#[reflect]
76pub struct AttrTokens {
77    pub prefix: Option<String>,
78    pub ident: String,
79    pub key: String,
80}
81
82impl AttrTokens {
83    pub fn compile(&self, props: &TemplateProperties, loader: &mut impl AssetLoadAdaptor) -> Option<Attribute> {
84        let Some(prop_val) = props.get(&self.key) else {
85            return None;
86        };
87
88        let (_, attr) = match crate::parse::attribute_from_parts::<nom::error::Error<&[u8]>>(
89            self.prefix.as_ref().map(|s| s.as_bytes()),
90            self.ident.as_bytes(),
91            prop_val.as_bytes(),
92            loader
93        ) {
94            Ok(val) => val,
95            Err(_) => (
96                "".as_bytes(),
97                Attribute::PropertyDefinition(self.ident.to_owned(), prop_val.to_owned()),
98            ),
99        };
100
101        // recursive compile, what could go wrong
102        if let Attribute::Uncompiled(attr) = attr {
103            return attr.compile(props, loader);
104        };
105
106        Some(attr)
107    }
108}
109
110#[derive(Debug, Reflect, PartialEq, Clone)]
111#[reflect]
112pub enum Action {
113    OnPress(Vec<String>),
114    OnEnter(Vec<String>),
115    OnExit(Vec<String>),
116    OnSpawn(Vec<String>),
117    OnChange(Vec<String>),
118}
119
120impl Action {
121    pub fn self_insert(self, mut cmd: EntityCommands) {
122        match self {
123            Action::OnPress(fn_id) => {
124                cmd.insert(crate::prelude::OnUiPress(fn_id));
125            }
126            Action::OnEnter(fn_id) => {
127                cmd.insert(crate::prelude::OnUiEnter(fn_id));
128            }
129            Action::OnExit(fn_id) => {
130                cmd.insert(crate::prelude::OnUiExit(fn_id));
131            }
132            Action::OnSpawn(fn_id) => {
133                cmd.insert(crate::prelude::OnUiSpawn(fn_id));
134            }
135            Action::OnChange(fn_id) => {
136                cmd.insert(crate::prelude::OnUiChange(fn_id));
137            }
138        }
139    }
140}
141
142#[derive(Debug, Clone, Reflect)]
143#[reflect]
144pub enum FontReference {
145    Handle(Handle<Font>),
146    Path(String),
147}
148
149#[derive(Debug, Clone, Reflect)]
150#[reflect]
151pub enum StyleAttr {
152    Display(Display),
153    Position(PositionType),
154    Overflow(Overflow),
155    OverflowClipMargin(OverflowClipMargin),
156    FrameTime(Val),
157    Left(Val),
158    Right(Val),
159    Top(Val),
160    Bottom(Val),
161    Width(Val),
162    Height(Val),
163    MinWidth(Val),
164    MinHeight(Val),
165    MaxWidth(Val),
166    MaxHeight(Val),
167    AspectRatio(f32),
168    AlignItems(AlignItems),
169    JustifyItems(JustifyItems),
170    AlignSelf(AlignSelf),
171    JustifySelf(JustifySelf),
172    AlignContent(AlignContent),
173    JustifyContent(JustifyContent),
174    Margin(UiRect),
175    Padding(UiRect),
176    Zindex(ZIndex),
177    GlobalZIndex(GlobalZIndex),
178
179    // ------------
180    // border
181    Border(UiRect),
182    BorderColor(Color),
183    BorderRadius(UiRect),
184    Outline(Outline),
185
186    // ------------
187    // flex
188    FlexDirection(FlexDirection),
189    FlexWrap(FlexWrap),
190    FlexGrow(f32),
191    FlexShrink(f32),
192    FlexBasis(Val),
193    RowGap(Val),
194    ColumnGap(Val),
195
196    // -----------
197    // grid
198    GridAutoFlow(GridAutoFlow),
199    GridTemplateRows(Vec<RepeatedGridTrack>),
200    GridTemplateColumns(Vec<RepeatedGridTrack>),
201    GridAutoRows(Vec<GridTrack>),
202    GridAutoColumns(Vec<GridTrack>),
203    GridRow(GridPlacement),
204    GridColumn(GridPlacement),
205
206    // -----
207    // font
208    FontSize(f32),
209    Font(FontReference),
210    FontColor(Color),
211    TextLayout(TextLayout),
212
213    // -----
214    // color
215    Background(Color),
216    ShadowColor(Color),
217    ShadowOffset(Val, Val),
218    ShadowSpread(Val),
219    ShadowBlur(Val),
220    TextShadow(TextShadow),
221
222    // -----
223    Hover(#[reflect(ignore)] Box<StyleAttr>),
224    Pressed(#[reflect(ignore)] Box<StyleAttr>),
225    Active(#[reflect(ignore)] Box<StyleAttr>),
226
227    // -----
228    // animations
229    Delay(f32),
230    Easing(EaseFunction),
231    Atlas(Option<Atlas>),
232    Duration(f32),
233    Iterations(i64),
234    Direction(AnimationDirection),
235    FPS(i64),
236    Frames(Vec<i64>),
237
238    // -----
239    // image
240    ImageColor(Color),
241    ImageScaleMode(NodeImageMode),
242    ImageRegion(Rect),
243
244    // -----
245    // picking
246    #[cfg(feature = "picking")]
247    Pickable((bool, bool)),
248}
249
250impl Default for StyleAttr {
251    fn default() -> Self {
252        StyleAttr::Display(Display::None)
253    }
254}