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}