1extern crate azul_core;
24extern crate azul_css;
25#[cfg(feature = "text_layout")]
26pub extern crate azul_text_layout as text_layout;
27
28use std::collections::BTreeMap;
29use azul_css::LayoutRect;
30use azul_core::{
31 ui_solver::PositionedRectangle,
32 id_tree::{NodeHierarchy, NodeDepths, NodeDataContainer},
33 dom::NodeId,
34 display_list::DisplayRectangle,
35 traits::GetTextLayout,
36};
37
38mod anon;
39mod block;
40mod number;
42mod geometry;
43
44pub mod style;
45#[cfg(feature = "text_layout")]
46pub mod ui_solver;
47pub use crate::geometry::{Size, Offsets};
48pub use crate::number::Number;
49pub use crate::style::Style;
50
51pub trait GetStyle {
52 fn get_style(&self) -> Style;
53}
54
55#[derive(Debug, Clone, PartialEq, PartialOrd)]
56pub struct SolvedUi {
57 pub solved_rects: NodeDataContainer<PositionedRectangle>,
58}
59
60#[derive(Debug, Clone, PartialEq)]
61pub enum RectContent<T: GetTextLayout> {
62 Image(usize, usize),
64 Text(T),
67}
68
69impl<T: GetTextLayout> RectContent<T> {
70
71 pub fn is_text(&self) -> bool {
72 use self::RectContent::*;
73 match self {
74 Image(_, _) => false,
75 Text(_) => true,
76 }
77 }
78
79 pub fn is_image(&self) -> bool {
80 use self::RectContent::*;
81 match self {
82 Image(_, _) => true,
83 Text(_) => false,
84 }
85 }
86}
87
88impl SolvedUi {
89 pub fn new<T: GetStyle, U: GetTextLayout>(
90 bounds: LayoutRect,
91 node_hierarchy: &NodeHierarchy,
92 display_rects: &NodeDataContainer<T>,
93 rect_contents: &mut BTreeMap<NodeId, RectContent<U>>,
94 node_depths: &NodeDepths,
95 ) -> Self {
96
97 use crate::anon::AnonDom;
98
99 let styles = display_rects.transform(|node, node_id| Style {
100 aspect_ratio: match rect_contents.get(&node_id) {
101 Some(RectContent::Image(w, h)) => Number::Defined(*w as f32 / *h as f32),
102 _ => Number::Undefined,
103 },
104 .. node.get_style()
105 });
106
107 let anon_dom = AnonDom::new(
108 node_hierarchy,
109 &styles,
110 node_depths,
111 rect_contents,
112 );
113
114 let solved_rects = block::compute(
116 bounds.size,
117 &anon_dom,
118 rect_contents,
119 );
120
121 SolvedUi { solved_rects }
122 }
123}
124
125impl GetStyle for DisplayRectangle {
126
127 fn get_style(&self) -> Style {
128
129 use crate::style::*;
130 use azul_css::{
131 PixelValue, LayoutDisplay, LayoutDirection, LayoutWrap, LayoutPosition,
132 LayoutAlignItems, LayoutAlignContent, LayoutJustifyContent,
133 LayoutBoxSizing, Overflow as LayoutOverflow, CssPropertyValue,
134 };
135 use azul_core::ui_solver::DEFAULT_FONT_SIZE;
136
137 let rect_layout = &self.layout;
138 let rect_style = &self.style;
139
140 #[inline]
141 fn translate_dimension(input: Option<CssPropertyValue<PixelValue>>) -> Dimension {
142 use azul_css::{SizeMetric, EM_HEIGHT, PT_TO_PX};
143 match input {
144 None => Dimension::Undefined,
145 Some(CssPropertyValue::Auto) => Dimension::Auto,
146 Some(CssPropertyValue::None) => Dimension::Pixels(0.0),
147 Some(CssPropertyValue::Initial) => Dimension::Undefined,
148 Some(CssPropertyValue::Inherit) => Dimension::Undefined,
149 Some(CssPropertyValue::Exact(pixel_value)) => match pixel_value.metric {
150 SizeMetric::Px => Dimension::Pixels(pixel_value.number.get()),
151 SizeMetric::Percent => Dimension::Percent(pixel_value.number.get()),
152 SizeMetric::Pt => Dimension::Pixels(pixel_value.number.get() * PT_TO_PX),
153 SizeMetric::Em => Dimension::Pixels(pixel_value.number.get() * EM_HEIGHT),
154 }
155 }
156 }
157
158 Style {
159 display: match rect_layout.display {
160 None => Display::Block,
161 Some(CssPropertyValue::None) => Display::None,
162 Some(CssPropertyValue::Auto) => Display::Block,
163 Some(CssPropertyValue::Initial) => Display::Block,
164 Some(CssPropertyValue::Inherit) => Display::Block,
165 Some(CssPropertyValue::Exact(LayoutDisplay::Block)) => Display::Block,
166 Some(CssPropertyValue::Exact(LayoutDisplay::Flex)) => Display::Flex,
167 Some(CssPropertyValue::Exact(LayoutDisplay::InlineBlock)) => Display::InlineBlock,
168 },
169 box_sizing: match rect_layout.box_sizing.unwrap_or_default().get_property_or_default() {
170 None => BoxSizing::ContentBox,
171 Some(LayoutBoxSizing::ContentBox) => BoxSizing::ContentBox,
172 Some(LayoutBoxSizing::BorderBox) => BoxSizing::BorderBox,
173 },
174 position_type: match rect_layout.position.unwrap_or_default().get_property_or_default() {
175 Some(LayoutPosition::Static) => PositionType::Static,
176 Some(LayoutPosition::Relative) => PositionType::Relative,
177 Some(LayoutPosition::Absolute) => PositionType::Absolute,
178 Some(LayoutPosition::Fixed) => PositionType::Fixed,
179 None => PositionType::Static,
180 },
181 direction: Direction::LTR,
182 flex_direction: match rect_layout.direction.unwrap_or_default().get_property_or_default() {
183 Some(LayoutDirection::Row) => FlexDirection::Row,
184 Some(LayoutDirection::RowReverse) => FlexDirection::RowReverse,
185 Some(LayoutDirection::Column) => FlexDirection::Column,
186 Some(LayoutDirection::ColumnReverse) => FlexDirection::ColumnReverse,
187 None => FlexDirection::Row,
188 },
189 flex_wrap: match rect_layout.wrap.unwrap_or_default().get_property_or_default() {
190 Some(LayoutWrap::Wrap) => FlexWrap::Wrap,
191 Some(LayoutWrap::NoWrap) => FlexWrap::NoWrap,
192 None => FlexWrap::Wrap,
193 },
194 overflow: match rect_layout.overflow_x.unwrap_or_default().get_property_or_default() {
195 Some(LayoutOverflow::Scroll) => Overflow::Scroll,
196 Some(LayoutOverflow::Auto) => Overflow::Scroll,
197 Some(LayoutOverflow::Hidden) => Overflow::Hidden,
198 Some(LayoutOverflow::Visible) => Overflow::Visible,
199 None => Overflow::Scroll,
200 },
201 align_items: match rect_layout.align_items.unwrap_or_default().get_property_or_default() {
202 Some(LayoutAlignItems::Stretch) => AlignItems::Stretch,
203 Some(LayoutAlignItems::Center) => AlignItems::Center,
204 Some(LayoutAlignItems::Start) => AlignItems::FlexStart,
205 Some(LayoutAlignItems::End) => AlignItems::FlexEnd,
206 None => AlignItems::FlexStart,
207 },
208 align_content: match rect_layout.align_content.unwrap_or_default().get_property_or_default() {
209 Some(LayoutAlignContent::Stretch) => AlignContent::Stretch,
210 Some(LayoutAlignContent::Center) => AlignContent::Center,
211 Some(LayoutAlignContent::Start) => AlignContent::FlexStart,
212 Some(LayoutAlignContent::End) => AlignContent::FlexEnd,
213 Some(LayoutAlignContent::SpaceBetween) => AlignContent::SpaceBetween,
214 Some(LayoutAlignContent::SpaceAround) => AlignContent::SpaceAround,
215 None => AlignContent::Stretch,
216 },
217 justify_content: match rect_layout.justify_content.unwrap_or_default().get_property_or_default() {
218 Some(LayoutJustifyContent::Center) => JustifyContent::Center,
219 Some(LayoutJustifyContent::Start) => JustifyContent::FlexStart,
220 Some(LayoutJustifyContent::End) => JustifyContent::FlexEnd,
221 Some(LayoutJustifyContent::SpaceBetween) => JustifyContent::SpaceBetween,
222 Some(LayoutJustifyContent::SpaceAround) => JustifyContent::SpaceAround,
223 Some(LayoutJustifyContent::SpaceEvenly) => JustifyContent::SpaceEvenly,
224 None => JustifyContent::FlexStart,
225 },
226 position: Offsets {
227 left: translate_dimension(rect_layout.left.map(|prop| prop.map_property(|l| l.0))),
228 right: translate_dimension(rect_layout.right.map(|prop| prop.map_property(|r| r.0))),
229 top: translate_dimension(rect_layout.top.map(|prop| prop.map_property(|t| t.0))),
230 bottom: translate_dimension(rect_layout.bottom.map(|prop| prop.map_property(|b| b.0))),
231 },
232 margin: Offsets {
233 left: translate_dimension(rect_layout.margin_left.map(|prop| prop.map_property(|l| l.0))),
234 right: translate_dimension(rect_layout.margin_right.map(|prop| prop.map_property(|r| r.0))),
235 top: translate_dimension(rect_layout.margin_top.map(|prop| prop.map_property(|t| t.0))),
236 bottom: translate_dimension(rect_layout.margin_bottom.map(|prop| prop.map_property(|b| b.0))),
237 },
238 padding: Offsets {
239 left: translate_dimension(rect_layout.padding_left.map(|prop| prop.map_property(|l| l.0))),
240 right: translate_dimension(rect_layout.padding_right.map(|prop| prop.map_property(|r| r.0))),
241 top: translate_dimension(rect_layout.padding_top.map(|prop| prop.map_property(|t| t.0))),
242 bottom: translate_dimension(rect_layout.padding_bottom.map(|prop| prop.map_property(|b| b.0))),
243 },
244 border: Offsets {
245 left: translate_dimension(rect_layout.border_left_width.map(|prop| prop.map_property(|l| l.0))),
246 right: translate_dimension(rect_layout.border_right_width.map(|prop| prop.map_property(|r| r.0))),
247 top: translate_dimension(rect_layout.border_top_width.map(|prop| prop.map_property(|t| t.0))),
248 bottom: translate_dimension(rect_layout.border_bottom_width.map(|prop| prop.map_property(|b| b.0))),
249 },
250 flex_grow: rect_layout.flex_grow.unwrap_or_default().get_property_or_default().unwrap_or_default().0.get(),
251 flex_shrink: rect_layout.flex_shrink.unwrap_or_default().get_property_or_default().unwrap_or_default().0.get(),
252 size: Size {
253 width: translate_dimension(rect_layout.width.map(|prop| prop.map_property(|l| l.0))),
254 height: translate_dimension(rect_layout.height.map(|prop| prop.map_property(|l| l.0))),
255 },
256 min_size: Size {
257 width: translate_dimension(rect_layout.min_width.map(|prop| prop.map_property(|l| l.0))),
258 height: translate_dimension(rect_layout.min_height.map(|prop| prop.map_property(|l| l.0))),
259 },
260 max_size: Size {
261 width: translate_dimension(rect_layout.max_width.map(|prop| prop.map_property(|l| l.0))),
262 height: translate_dimension(rect_layout.max_height.map(|prop| prop.map_property(|l| l.0))),
263 },
264 align_self: AlignSelf::default(), flex_basis: Dimension::default(), aspect_ratio: Number::Undefined,
267 font_size_px: rect_style.font_size.and_then(|fs| fs.get_property_owned()).unwrap_or(DEFAULT_FONT_SIZE).0,
268 line_height: rect_style.line_height.and_then(|lh| lh.map_property(|lh| lh.0).get_property_owned()).map(|lh| lh.get()),
269 letter_spacing: rect_style.letter_spacing.and_then(|ls| ls.map_property(|ls| ls.0).get_property_owned()),
270 word_spacing: rect_style.word_spacing.and_then(|ws| ws.map_property(|ws| ws.0).get_property_owned()),
271 tab_width: rect_style.tab_width.and_then(|tw| tw.map_property(|tw| tw.0).get_property_owned()).map(|tw| tw.get()),
272 }
273 }
274}