freya_core/
node.rs

1use freya_engine::prelude::*;
2use freya_native_core::real_dom::NodeImmutable;
3use torin::{
4    alignment::Alignment,
5    direction::Direction,
6    gaps::Gaps,
7    prelude::{
8        Content,
9        Position,
10        VisibleSize,
11    },
12    size::Size,
13};
14
15use crate::{
16    dom::DioxusNode,
17    states::{
18        AccessibilityNodeState,
19        CursorState,
20        FontStyleState,
21        LayoutState,
22        StyleState,
23        SvgState,
24        TransformState,
25    },
26    values::{
27        Border,
28        CornerRadius,
29        Fill,
30        Shadow,
31        SvgPaint,
32        TextOverflow,
33    },
34};
35
36#[derive(Clone, PartialEq)]
37pub struct NodeState {
38    pub cursor: CursorState,
39    pub font_style: FontStyleState,
40    pub size: LayoutState,
41    pub style: StyleState,
42    pub transform: TransformState,
43    pub accessibility: AccessibilityNodeState,
44    pub svg: SvgState,
45}
46
47pub fn get_node_state(node: &DioxusNode) -> NodeState {
48    let cursor = node
49        .get::<CursorState>()
50        .as_deref()
51        .cloned()
52        .unwrap_or_default();
53    let font_style = node
54        .get::<FontStyleState>()
55        .as_deref()
56        .cloned()
57        .unwrap_or_default();
58    let size = node
59        .get::<LayoutState>()
60        .as_deref()
61        .cloned()
62        .unwrap_or_default();
63    let style = node
64        .get::<StyleState>()
65        .as_deref()
66        .cloned()
67        .unwrap_or_default();
68    let transform = node
69        .get::<TransformState>()
70        .as_deref()
71        .cloned()
72        .unwrap_or_default();
73    let accessibility = node
74        .get::<AccessibilityNodeState>()
75        .as_deref()
76        .cloned()
77        .unwrap_or_default();
78    let svg = node
79        .get::<SvgState>()
80        .as_deref()
81        .cloned()
82        .unwrap_or_default();
83
84    NodeState {
85        cursor,
86        font_style,
87        size,
88        style,
89        transform,
90        accessibility,
91        svg,
92    }
93}
94
95impl NodeState {
96    pub fn attributes(&self) -> Vec<(&str, AttributeType)> {
97        let mut attributes = vec![
98            ("width", AttributeType::Size(&self.size.width)),
99            ("height", AttributeType::Size(&self.size.height)),
100            ("min_width", AttributeType::Size(&self.size.minimum_width)),
101            ("min_height", AttributeType::Size(&self.size.minimum_height)),
102            ("max_width", AttributeType::Size(&self.size.maximum_width)),
103            ("max_height", AttributeType::Size(&self.size.maximum_height)),
104            (
105                "visible_width",
106                AttributeType::VisibleSize(&self.size.visible_width),
107            ),
108            (
109                "visible_height",
110                AttributeType::VisibleSize(&self.size.visible_height),
111            ),
112            ("direction", AttributeType::Direction(&self.size.direction)),
113            ("padding", AttributeType::Measures(self.size.padding)),
114            ("margin", AttributeType::Measures(self.size.margin)),
115            ("position", AttributeType::Position(&self.size.position)),
116            (
117                "main_alignment",
118                AttributeType::Alignment(&self.size.main_alignment),
119            ),
120            (
121                "cross_alignment",
122                AttributeType::Alignment(&self.size.cross_alignment),
123            ),
124            {
125                let background = &self.style.background;
126                let fill = match *background {
127                    Fill::Color(_) => AttributeType::Color(background.clone()),
128                    Fill::LinearGradient(_) => AttributeType::Gradient(background.clone()),
129                    Fill::RadialGradient(_) => AttributeType::Gradient(background.clone()),
130                    Fill::ConicGradient(_) => AttributeType::Gradient(background.clone()),
131                };
132                ("background", fill)
133            },
134            (
135                "corner_radius",
136                AttributeType::CornerRadius(self.style.corner_radius),
137            ),
138            ("color", AttributeType::Color(self.font_style.color.into())),
139            (
140                "font_family",
141                AttributeType::Text(self.font_style.font_family.join(",")),
142            ),
143            (
144                "font_size",
145                AttributeType::Measure(self.font_style.font_size),
146            ),
147            (
148                "line_height",
149                AttributeType::OptionalMeasure(self.font_style.line_height),
150            ),
151            (
152                "text_align",
153                AttributeType::TextAlignment(&self.font_style.text_align),
154            ),
155            (
156                "text_overflow",
157                AttributeType::TextOverflow(&self.font_style.text_overflow),
158            ),
159            ("offset_x", AttributeType::Measure(self.size.offset_x.get())),
160            ("offset_y", AttributeType::Measure(self.size.offset_y.get())),
161            ("content", AttributeType::Content(&self.size.content)),
162            (
163                "svg_fill",
164                AttributeType::OptionalColor(self.svg.svg_fill.and_then(|fill| match fill {
165                    SvgPaint::None => None,
166                    SvgPaint::CurrentColor => Some(Fill::Color(self.font_style.color)),
167                    SvgPaint::Color(color) => Some(Fill::Color(color)),
168                })),
169            ),
170            (
171                "svg_stroke",
172                AttributeType::OptionalColor(self.svg.svg_stroke.and_then(|stroke| match stroke {
173                    SvgPaint::None => None,
174                    SvgPaint::CurrentColor => Some(Fill::Color(self.font_style.color)),
175                    SvgPaint::Color(color) => Some(Fill::Color(color)),
176                })),
177            ),
178        ];
179
180        let shadows = &self.style.shadows;
181        for shadow in shadows.iter() {
182            attributes.push(("shadow", AttributeType::Shadow(shadow)));
183        }
184
185        let borders = &self.style.borders;
186        for border in borders.iter() {
187            attributes.push(("border", AttributeType::Border(border)));
188        }
189
190        let text_shadows = &self.font_style.text_shadows;
191
192        for text_shadow in text_shadows.iter() {
193            attributes.push(("text_shadow", AttributeType::TextShadow(text_shadow)));
194        }
195
196        attributes
197    }
198}
199
200pub enum AttributeType<'a> {
201    Color(Fill),
202    OptionalColor(Option<Fill>),
203    Gradient(Fill),
204    Size(&'a Size),
205    VisibleSize(&'a VisibleSize),
206    Measure(f32),
207    OptionalMeasure(Option<f32>),
208    Measures(Gaps),
209    CornerRadius(CornerRadius),
210    Direction(&'a Direction),
211    Position(&'a Position),
212    Content(&'a Content),
213    Alignment(&'a Alignment),
214    Shadow(&'a Shadow),
215    TextShadow(&'a TextShadow),
216    Text(String),
217    Border(&'a Border),
218    TextAlignment(&'a TextAlign),
219    TextOverflow(&'a TextOverflow),
220}
221
222pub trait ExternalPretty {
223    fn pretty(&self) -> String;
224}
225
226impl ExternalPretty for TextAlign {
227    fn pretty(&self) -> String {
228        match self {
229            TextAlign::Left => "left".to_string(),
230            TextAlign::Right => "right".to_string(),
231            TextAlign::Center => "center".to_string(),
232            TextAlign::Justify => "justify".to_string(),
233            TextAlign::Start => "start".to_string(),
234            TextAlign::End => "end".to_string(),
235        }
236    }
237}