1use std::collections::HashMap;
17use std::sync::atomic::AtomicU16;
18
19use crate::background::{background, Background};
20use crate::blend::BlendMode;
21use crate::font::{FontStretch, FontStyle, FontWeight, TextDecoration};
22use crate::frame_extras::FrameExtras;
23use crate::geometry::{Rectangle, Size};
24use crate::layout_style::LayoutStyle;
25use crate::node_style::{Display, NodeStyle};
26use crate::path::line_height::Line_height_type;
27use crate::path::{LineHeight, Stroke};
28use crate::pointer::PointerEvents;
29use crate::positioning::{FlexWrap, LayoutSizing, Overflow, OverflowDirection, ScrollInfo};
30use crate::reaction::Reaction;
31use crate::text::{TextAlign, TextAlignVertical, TextOverflow};
32use crate::text_style::StyledTextRun;
33use crate::variable::NumOrVar;
34use crate::view::view::RenderMethod;
35use crate::view::view_data::{Container, StyledTextRuns, Text, View_data_type};
36use crate::view::{ComponentInfo, View, ViewData};
37use crate::view_shape::ViewShape;
38use crate::view_style::ViewStyle;
39
40impl NodeStyle {
41 pub(crate) fn new_default() -> NodeStyle {
42 NodeStyle {
43 font_color: Some(Background::new_with_background(background::Background_type::None(
44 ().into(),
45 )))
46 .into(),
47 font_size: Some(NumOrVar::from_num(18.0)).into(),
48 font_family: None,
49 font_weight: Some(FontWeight::normal()).into(),
50 font_style: FontStyle::FONT_STYLE_NORMAL.into(),
51 text_decoration: TextDecoration::TEXT_DECORATION_NONE.into(),
52 letter_spacing: None,
53 font_stretch: Some(FontStretch::normal()).into(),
54 backgrounds: Vec::new(),
55 box_shadows: Vec::new(),
56 stroke: Some(Stroke::default()).into(),
57 opacity: None,
58 transform: None.into(),
59 relative_transform: None.into(),
60 text_align: TextAlign::TEXT_ALIGN_LEFT.into(),
61 text_align_vertical: TextAlignVertical::TEXT_ALIGN_VERTICAL_TOP.into(),
62 text_overflow: TextOverflow::TEXT_OVERFLOW_CLIP.into(),
63 text_shadow: None.into(),
64 node_size: Some(Size { width: 0.0, height: 0.0, ..Default::default() }).into(),
65 line_height: Some(LineHeight {
66 line_height_type: Some(Line_height_type::Percent(1.0)),
67 ..Default::default()
68 })
69 .into(),
70 line_count: None,
71 font_features: Vec::new(),
72 filters: Vec::new(),
73 backdrop_filters: Vec::new(),
74 blend_mode: BlendMode::BLEND_MODE_PASS_THROUGH.into(),
75 display_type: Display::DISPLAY_FLEX.into(),
76 flex_wrap: FlexWrap::FLEX_WRAP_NO_WRAP.into(),
77 grid_layout_type: None,
78 grid_columns_rows: 0,
79 grid_adaptive_min_size: 1,
80 grid_span_contents: vec![],
81 overflow: Overflow::OVERFLOW_VISIBLE.into(),
82 max_children: None,
83 overflow_node_id: None,
84 overflow_node_name: None,
85 cross_axis_item_spacing: 0.0,
86 horizontal_sizing: LayoutSizing::LAYOUT_SIZING_FIXED.into(),
87 vertical_sizing: LayoutSizing::LAYOUT_SIZING_FIXED.into(),
88 aspect_ratio: None,
89 pointer_events: PointerEvents::POINTER_EVENTS_INHERIT.into(),
90 meter_data: None.into(),
91 hyperlink: None.into(),
92 shader_data: None.into(),
93 scalable_data: None.into(),
94 animation_override: None.into(),
95 ..Default::default()
96 }
97 }
98}
99
100impl ViewStyle {
101 pub fn new_default() -> Self {
102 Self {
103 layout_style: Some(LayoutStyle::new_default()).into(),
104 node_style: Some(NodeStyle::new_default()).into(),
105 ..Default::default()
106 }
107 }
108 pub fn node_style(&self) -> &NodeStyle {
109 self.node_style.as_ref().expect("NodeStyle is required.")
110 }
111 pub fn node_style_mut(&mut self) -> &mut NodeStyle {
112 self.node_style.as_mut().expect("NodeStyle is required.")
113 }
114 pub fn layout_style(&self) -> &LayoutStyle {
115 self.layout_style.as_ref().expect("LayoutStyle is required.")
116 }
117 pub fn layout_style_mut(&mut self) -> &mut LayoutStyle {
118 self.layout_style.as_mut().expect("LayoutStyle is required.")
119 }
120}
121
122impl ViewStyle {
123 pub fn difference(&self, other: &ViewStyle) -> ViewStyle {
126 let mut delta = ViewStyle::new_default();
127 if self.node_style().font_color != other.node_style().font_color {
128 delta.node_style_mut().font_color = other.node_style().font_color.clone();
129 }
130 if self.node_style().font_size != other.node_style().font_size {
131 delta.node_style_mut().font_size = other.node_style().font_size.clone();
132 }
133 if self.node_style().font_family != other.node_style().font_family {
134 delta.node_style_mut().font_family = other.node_style().font_family.clone();
135 }
136 if self.node_style().font_weight != other.node_style().font_weight {
137 delta.node_style_mut().font_weight = other.node_style().font_weight.clone();
138 }
139 if self.node_style().font_style != other.node_style().font_style {
140 delta.node_style_mut().font_style = other.node_style().font_style;
141 }
142 if self.node_style().text_decoration != other.node_style().text_decoration {
143 delta.node_style_mut().text_decoration = other.node_style().text_decoration;
144 }
145 if self.node_style().letter_spacing != other.node_style().letter_spacing {
146 delta.node_style_mut().letter_spacing = other.node_style().letter_spacing;
147 }
148 if self.node_style().font_stretch != other.node_style().font_stretch {
149 delta.node_style_mut().font_stretch = other.node_style().font_stretch.clone();
150 }
151 if self.node_style().backgrounds != other.node_style().backgrounds {
152 delta.node_style_mut().backgrounds = other.node_style().backgrounds.clone();
153 }
154 if self.node_style().box_shadows != other.node_style().box_shadows {
155 delta.node_style_mut().box_shadows = other.node_style().box_shadows.clone();
156 }
157 if self.node_style().stroke != other.node_style().stroke {
158 delta.node_style_mut().stroke = other.node_style().stroke.clone();
159 }
160 if self.node_style().opacity != other.node_style().opacity {
161 delta.node_style_mut().opacity = other.node_style().opacity;
162 }
163 if self.node_style().transform != other.node_style().transform {
164 delta.node_style_mut().transform = other.node_style().transform.clone();
165 }
166 if self.node_style().relative_transform != other.node_style().relative_transform {
167 delta.node_style_mut().relative_transform =
168 other.node_style().relative_transform.clone();
169 }
170 if self.node_style().text_align != other.node_style().text_align {
171 delta.node_style_mut().text_align = other.node_style().text_align;
172 }
173 if self.node_style().text_align_vertical != other.node_style().text_align_vertical {
174 delta.node_style_mut().text_align_vertical = other.node_style().text_align_vertical;
175 }
176 if self.node_style().text_overflow != other.node_style().text_overflow {
177 delta.node_style_mut().text_overflow = other.node_style().text_overflow;
178 }
179 if self.node_style().text_shadow != other.node_style().text_shadow {
180 delta.node_style_mut().text_shadow = other.node_style().text_shadow.clone();
181 }
182 if self.node_style().node_size != other.node_style().node_size {
183 delta.node_style_mut().node_size = other.node_style().node_size.clone();
184 }
185 if self.node_style().line_height != other.node_style().line_height {
186 delta.node_style_mut().line_height = other.node_style().line_height.clone();
187 }
188 if self.node_style().line_count != other.node_style().line_count {
189 delta.node_style_mut().line_count = other.node_style().line_count;
190 }
191 if self.node_style().font_features != other.node_style().font_features {
192 delta.node_style_mut().font_features = other.node_style().font_features.clone();
193 }
194 if self.node_style().filters != other.node_style().filters {
195 delta.node_style_mut().filters = other.node_style().filters.clone();
196 }
197 if self.node_style().backdrop_filters != other.node_style().backdrop_filters {
198 delta.node_style_mut().backdrop_filters = other.node_style().backdrop_filters.clone();
199 }
200 if self.node_style().blend_mode != other.node_style().blend_mode {
201 delta.node_style_mut().blend_mode = other.node_style().blend_mode;
202 }
203 if self.node_style().hyperlink != other.node_style().hyperlink {
204 delta.node_style_mut().hyperlink = other.node_style().hyperlink.clone();
205 }
206 if self.node_style().display_type != other.node_style().display_type {
207 delta.node_style_mut().display_type = other.node_style().display_type;
208 }
209 if self.layout_style().position_type != other.layout_style().position_type {
210 delta.layout_style_mut().position_type = other.layout_style().position_type;
211 }
212 if self.layout_style().flex_direction != other.layout_style().flex_direction {
213 delta.layout_style_mut().flex_direction = other.layout_style().flex_direction;
214 }
215 if self.node_style().flex_wrap != other.node_style().flex_wrap {
216 delta.node_style_mut().flex_wrap = other.node_style().flex_wrap;
217 }
218 if self.node_style().grid_layout_type != other.node_style().grid_layout_type {
219 delta.node_style_mut().grid_layout_type = other.node_style().grid_layout_type;
220 }
221 if self.node_style().grid_columns_rows != other.node_style().grid_columns_rows {
222 delta.node_style_mut().grid_columns_rows = other.node_style().grid_columns_rows;
223 }
224 if self.node_style().grid_adaptive_min_size != other.node_style().grid_adaptive_min_size {
225 delta.node_style_mut().grid_adaptive_min_size =
226 other.node_style().grid_adaptive_min_size;
227 }
228 if self.node_style().grid_span_contents != other.node_style().grid_span_contents {
229 delta.node_style_mut().grid_span_contents =
230 other.node_style().grid_span_contents.clone();
231 }
232 if self.node_style().overflow != other.node_style().overflow {
233 delta.node_style_mut().overflow = other.node_style().overflow;
234 }
235 if self.node_style().max_children != other.node_style().max_children {
236 delta.node_style_mut().max_children = other.node_style().max_children;
237 }
238 if self.node_style().overflow_node_id != other.node_style().overflow_node_id {
239 delta.node_style_mut().overflow_node_id = other.node_style().overflow_node_id.clone();
240 }
241 if self.node_style().overflow_node_name != other.node_style().overflow_node_name {
242 delta.node_style_mut().overflow_node_name =
243 other.node_style().overflow_node_name.clone();
244 }
245 if self.node_style().shader_data != other.node_style().shader_data {
246 delta.node_style_mut().shader_data = other.node_style().shader_data.clone();
247 }
248 if self.layout_style().align_items != other.layout_style().align_items {
249 delta.layout_style_mut().align_items = other.layout_style().align_items;
250 }
251 if self.layout_style().align_content != other.layout_style().align_content {
252 delta.layout_style_mut().align_content = other.layout_style().align_content;
253 }
254 if self.layout_style().justify_content != other.layout_style().justify_content {
255 delta.layout_style_mut().justify_content = other.layout_style().justify_content;
256 }
257 if self.layout_style().top != other.layout_style().top {
258 delta.layout_style_mut().top = other.layout_style().top.clone();
259 }
260 if self.layout_style().left != other.layout_style().left {
261 delta.layout_style_mut().left = other.layout_style().left.clone();
262 }
263 if self.layout_style().bottom != other.layout_style().bottom {
264 delta.layout_style_mut().bottom = other.layout_style().bottom.clone();
265 }
266 if self.layout_style().right != other.layout_style().right {
267 delta.layout_style_mut().right = other.layout_style().right.clone();
268 }
269 if self.layout_style().margin != other.layout_style().margin {
270 delta.layout_style_mut().margin = other.layout_style().margin.clone();
271 }
272 if self.layout_style().padding != other.layout_style().padding {
273 delta.layout_style_mut().padding = other.layout_style().padding.clone();
274 }
275 if self.layout_style().item_spacing != other.layout_style().item_spacing {
276 delta.layout_style_mut().item_spacing = other.layout_style().item_spacing.clone();
277 }
278 if self.node_style().cross_axis_item_spacing != other.node_style().cross_axis_item_spacing {
279 delta.node_style_mut().cross_axis_item_spacing =
280 other.node_style().cross_axis_item_spacing;
281 }
282 if self.layout_style().flex_grow != other.layout_style().flex_grow {
283 delta.layout_style_mut().flex_grow = other.layout_style().flex_grow;
284 }
285 if self.layout_style().flex_shrink != other.layout_style().flex_shrink {
286 delta.layout_style_mut().flex_shrink = other.layout_style().flex_shrink;
287 }
288 if self.layout_style().flex_basis != other.layout_style().flex_basis {
289 delta.layout_style_mut().flex_basis = other.layout_style().flex_basis.clone();
290 }
291 if self.layout_style().width != other.layout_style().width {
292 delta.layout_style_mut().width = other.layout_style().width.clone();
293 }
294 if self.layout_style().height != other.layout_style().height {
295 delta.layout_style_mut().height = other.layout_style().height.clone();
296 }
297 if self.layout_style().max_width != other.layout_style().max_width {
298 delta.layout_style_mut().max_width = other.layout_style().max_width.clone();
299 }
300 if self.layout_style().max_height != other.layout_style().max_height {
301 delta.layout_style_mut().max_height = other.layout_style().max_height.clone();
302 }
303 if self.layout_style().min_width != other.layout_style().min_width {
304 delta.layout_style_mut().min_width = other.layout_style().min_width.clone();
305 }
306 if self.layout_style().min_height != other.layout_style().min_height {
307 delta.layout_style_mut().min_height = other.layout_style().min_height.clone();
308 }
309 if self.layout_style().bounding_box != other.layout_style().bounding_box {
310 delta.layout_style_mut().bounding_box = other.layout_style().bounding_box.clone();
311 }
312 if self.node_style().aspect_ratio != other.node_style().aspect_ratio {
313 delta.node_style_mut().aspect_ratio = other.node_style().aspect_ratio;
314 }
315 if self.node_style().pointer_events != other.node_style().pointer_events {
316 delta.node_style_mut().pointer_events = other.node_style().pointer_events;
317 }
318 if self.node_style().meter_data != other.node_style().meter_data {
319 delta.node_style_mut().meter_data = other.node_style().meter_data.clone();
320 }
321 if self.node_style().horizontal_sizing != other.node_style().horizontal_sizing {
322 delta.node_style_mut().horizontal_sizing = other.node_style().horizontal_sizing;
323 }
324 if self.node_style().vertical_sizing != other.node_style().vertical_sizing {
325 delta.node_style_mut().vertical_sizing = other.node_style().vertical_sizing;
326 }
327 if self.node_style().scalable_data != other.node_style().scalable_data {
328 delta.node_style_mut().scalable_data = other.node_style().scalable_data.clone();
329 }
330 if self.node_style().animation_override != other.node_style().animation_override {
331 delta.node_style_mut().animation_override =
332 other.node_style().animation_override.clone();
333 }
334 delta
335 }
336}
337
338impl ViewData {
339 pub fn difference(&self, other: &ViewData) -> Option<ViewData> {
342 if let Some(View_data_type::Text { .. }) = self.view_data_type {
343 if self != other {
344 return Some(other.clone());
345 }
346 }
347 if let Some(View_data_type::StyledText { .. }) = self.view_data_type {
348 if self != other {
349 return Some(other.clone());
350 }
351 }
352 None
353 }
354}
355
356impl ScrollInfo {
357 pub fn new_default() -> Self {
358 ScrollInfo {
359 overflow: OverflowDirection::OVERFLOW_DIRECTION_NONE.into(),
360 paged_scrolling: false,
361 ..Default::default()
362 }
363 }
364}
365
366impl View {
367 fn next_unique_id() -> u16 {
368 static COUNTER: AtomicU16 = AtomicU16::new(0);
369 COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
370 }
371 #[allow(clippy::too_many_arguments)]
372 pub fn new_rect(
373 id: &str,
374 name: &str,
375 shape: ViewShape,
376 style: ViewStyle,
377 component_info: Option<ComponentInfo>,
378 reactions: Option<Vec<Reaction>>,
379 scroll_info: ScrollInfo,
380 frame_extras: Option<FrameExtras>,
381 design_absolute_bounding_box: Option<Rectangle>,
382 render_method: RenderMethod,
383 explicit_variable_modes: HashMap<String, String>,
384 ) -> View {
385 View {
386 unique_id: View::next_unique_id() as u32,
387 id: id.to_owned(),
388 name: name.to_owned(),
389 component_info: component_info.into(),
390 reactions: reactions.unwrap_or_default(),
391 style: Some(style).into(),
392 frame_extras: frame_extras.into(),
393 scroll_info: Some(scroll_info).into(),
394 data: Some(ViewData {
395 view_data_type: Some(View_data_type::Container(Container {
396 shape: Some(shape).into(),
397 children: vec![],
398 ..Default::default()
399 })),
400 ..Default::default()
401 })
402 .into(),
403 design_absolute_bounding_box: design_absolute_bounding_box.into(),
404 render_method: render_method.into(),
405 explicit_variable_modes,
406 ..Default::default()
407 }
408 }
409 #[allow(clippy::too_many_arguments)]
410 pub fn new_text(
411 id: &str,
412 name: &str,
413 style: ViewStyle,
414 component_info: Option<ComponentInfo>,
415 reactions: Option<Vec<Reaction>>,
416 text: &str,
417 text_res_name: Option<String>,
418 design_absolute_bounding_box: Option<Rectangle>,
419 render_method: RenderMethod,
420 explicit_variable_modes: HashMap<String, String>,
421 ) -> View {
422 View {
423 unique_id: View::next_unique_id() as u32,
424 id: id.to_owned(),
425 name: name.to_owned(),
426 component_info: component_info.into(),
427 reactions: reactions.unwrap_or_default(),
428 style: Some(style).into(),
429 frame_extras: None.into(),
430 scroll_info: Some(ScrollInfo::new_default()).into(),
431 data: Some(ViewData {
432 view_data_type: Some(View_data_type::Text(Text {
433 content: text.into(),
434 res_name: text_res_name,
435 ..Default::default()
436 })),
437 ..Default::default()
438 })
439 .into(),
440 design_absolute_bounding_box: design_absolute_bounding_box.into(),
441 render_method: render_method.into(),
442 explicit_variable_modes,
443 ..Default::default()
444 }
445 }
446 #[allow(clippy::too_many_arguments)]
447 pub fn new_styled_text(
448 id: &str,
449 name: &str,
450 style: ViewStyle,
451 component_info: Option<ComponentInfo>,
452 reactions: Option<Vec<Reaction>>,
453 text: Vec<StyledTextRun>,
454 text_res_name: Option<String>,
455 design_absolute_bounding_box: Option<Rectangle>,
456 render_method: RenderMethod,
457 ) -> View {
458 View {
459 unique_id: View::next_unique_id() as u32,
460 id: id.to_owned(),
461 name: name.to_owned(),
462 style: Some(style).into(),
463 component_info: component_info.into(),
464 reactions: reactions.unwrap_or_default(),
465 frame_extras: None.into(),
466 scroll_info: Some(ScrollInfo::new_default()).into(),
467 data: Some(ViewData {
468 view_data_type: Some(View_data_type::StyledText(StyledTextRuns {
469 styled_texts: text,
470 res_name: text_res_name,
471 ..Default::default()
472 })),
473 ..Default::default()
474 })
475 .into(),
476 design_absolute_bounding_box: design_absolute_bounding_box.into(),
477 render_method: render_method.into(),
478 explicit_variable_modes: HashMap::new(),
479 ..Default::default()
480 }
481 }
482 pub fn add_child(&mut self, child: View) {
483 if let Some(data) = self.data.as_mut() {
484 if let Some(View_data_type::Container { 0: Container { children, .. } }) =
485 data.view_data_type.as_mut()
486 {
487 children.push(child);
488 }
489 }
490 }
491
492 pub fn style(&self) -> &ViewStyle {
493 self.style.as_ref().expect("ViewStyle is required.")
494 }
495 pub fn style_mut(&mut self) -> &mut ViewStyle {
496 self.style.as_mut().expect("ViewStyle is required.")
497 }
498
499 pub fn find_view_by_id(&self, view_id: &str) -> Option<&View> {
501 if view_id == self.id {
502 return Some(self);
503 } else if let Some(id) = view_id.split(';').next_back() {
504 if self.id == id {
507 return Some(self);
508 }
509 }
510 if let Some(data) = &self.data.as_ref() {
511 if let Some(View_data_type::Container { 0: Container { children, .. } }) =
512 &data.view_data_type
513 {
514 for child in children {
515 let result = child.find_view_by_id(view_id);
516 if result.is_some() {
517 return result;
518 }
519 }
520 }
521 }
522 None
523 }
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529 use crate::path::stroke_weight;
530 use crate::path::StrokeWeight;
531 use crate::variable::num_or_var::NumOrVarType;
532
533 #[test]
534 fn test_node_style_new_default() {
535 let style = NodeStyle::new_default();
536 assert!(style.font_color.is_some());
537 assert_eq!(style.font_size.unwrap().NumOrVarType, Some(NumOrVarType::Num(18.0)));
538 assert_eq!(style.font_weight.unwrap(), FontWeight::normal());
539 assert_eq!(style.font_style.enum_value().unwrap(), FontStyle::FONT_STYLE_NORMAL);
540 }
541
542 #[test]
543 fn test_view_style_new_default() {
544 let style = ViewStyle::new_default();
545 assert!(style.layout_style.is_some());
546 assert!(style.node_style.is_some());
547 }
548
549 #[test]
550 fn test_view_style_difference() {
551 let mut style1 = ViewStyle::new_default();
552 let mut style2 = ViewStyle::new_default();
553
554 style2.node_style_mut().opacity = Some(0.5);
556 style2.node_style_mut().letter_spacing = Some(1.2);
557 style2.layout_style_mut().flex_grow = 1.0;
558 style2.node_style_mut().meter_data = Some(Default::default()).into();
559
560 let diff = style1.difference(&style2);
561 assert_eq!(diff.node_style().opacity, Some(0.5));
562 assert_eq!(diff.node_style().letter_spacing, Some(1.2));
563 assert_eq!(diff.layout_style().flex_grow, 1.0);
564 assert_eq!(diff.node_style().meter_data, Some(Default::default()).into());
565
566 style1.node_style_mut().opacity = Some(0.5);
568 style1.node_style_mut().letter_spacing = Some(1.2);
569 style1.layout_style_mut().flex_grow = 1.0;
570 let diff2 = style1.difference(&style2);
571 assert_eq!(diff2.node_style().opacity, None);
572 assert_eq!(diff2.node_style().letter_spacing, None);
573 assert_eq!(diff2.layout_style().flex_grow, 0.0);
574
575 let mut style3 = ViewStyle::new_default();
577 let mut style4 = ViewStyle::new_default();
578 style4.node_style_mut().font_color =
579 Some(Background::new_with_background(background::Background_type::Solid(
580 crate::variable::ColorOrVar::new_color(crate::color::Color::red()),
581 )))
582 .into();
583 style4.node_style_mut().font_size = Some(NumOrVar::from_num(24.0)).into();
584 style4.node_style_mut().font_family = Some("Roboto".to_string());
585 style4.node_style_mut().font_weight = Some(FontWeight::bold()).into();
586 style4.node_style_mut().font_style = FontStyle::FONT_STYLE_ITALIC.into();
587 style4.node_style_mut().text_decoration = TextDecoration::TEXT_DECORATION_UNDERLINE.into();
588 style4.node_style_mut().letter_spacing = Some(2.0);
589 style4.node_style_mut().font_stretch = Some(FontStretch::expanded()).into();
590 style4.node_style_mut().backgrounds.push(Background::new_with_background(
591 background::Background_type::Solid(crate::variable::ColorOrVar::new_color(
592 crate::color::Color::blue(),
593 )),
594 ));
595 style4.node_style_mut().stroke = Some(Stroke {
596 stroke_weight: Some(StrokeWeight {
597 stroke_weight_type: Some(stroke_weight::Stroke_weight_type::Uniform(1.0)),
598 ..Default::default()
599 })
600 .into(),
601 ..Default::default()
602 })
603 .into();
604 style4.layout_style_mut().flex_direction =
605 crate::positioning::FlexDirection::FLEX_DIRECTION_COLUMN.into();
606 style4.layout_style_mut().align_items =
607 crate::positioning::AlignItems::ALIGN_ITEMS_CENTER.into();
608 style4.layout_style_mut().margin = Some(crate::geometry::DimensionRect {
609 start: crate::geometry::DimensionProto::new_points(10.0),
610 ..Default::default()
611 })
612 .into();
613
614 let diff3 = style3.difference(&style4);
615 assert_eq!(diff3.node_style().font_color, style4.node_style().font_color.clone());
616 assert_eq!(diff3.node_style().font_size, style4.node_style().font_size.clone());
617 assert_eq!(diff3.node_style().font_family, style4.node_style().font_family.clone());
618 assert_eq!(diff3.node_style().font_weight, style4.node_style().font_weight.clone());
619 assert_eq!(diff3.node_style().font_style, style4.node_style().font_style);
620 assert_eq!(diff3.node_style().text_decoration, style4.node_style().text_decoration);
621 assert_eq!(diff3.node_style().letter_spacing, style4.node_style().letter_spacing);
622 assert_eq!(diff3.node_style().font_stretch, style4.node_style().font_stretch.clone());
623 assert_eq!(diff3.node_style().backgrounds, style4.node_style().backgrounds.clone());
624 assert_eq!(diff3.node_style().stroke, style4.node_style().stroke.clone());
625 assert_eq!(diff3.layout_style().flex_direction, style4.layout_style().flex_direction);
626 assert_eq!(diff3.layout_style().align_items, style4.layout_style().align_items);
627 assert_eq!(diff3.layout_style().margin, style4.layout_style().margin.clone());
628 assert_eq!(
629 diff3.node_style().animation_override,
630 style4.node_style().animation_override.clone()
631 );
632 assert_eq!(diff3.node_style().horizontal_sizing, style4.node_style().horizontal_sizing);
633
634 style3 = style4.clone();
636 let diff4 = style3.difference(&style4);
637 assert_eq!(diff4.node_style().font_color, ViewStyle::new_default().node_style().font_color);
638 assert_eq!(diff4.node_style().font_size, ViewStyle::new_default().node_style().font_size);
639 assert!(diff4.node_style().font_family.is_none());
640 assert_eq!(
641 diff4.node_style().font_weight,
642 ViewStyle::new_default().node_style().font_weight
643 );
644 assert_eq!(
645 diff4.node_style().font_style.enum_value().unwrap(),
646 FontStyle::FONT_STYLE_NORMAL
647 );
648 assert_eq!(
649 diff4.node_style().text_decoration.enum_value().unwrap(),
650 TextDecoration::TEXT_DECORATION_NONE
651 );
652 assert!(diff4.node_style().letter_spacing.is_none());
653 assert_eq!(
654 diff4.node_style().font_stretch,
655 ViewStyle::new_default().node_style().font_stretch
656 );
657 assert!(diff4.node_style().backgrounds.is_empty());
658 assert_eq!(diff4.node_style().stroke, ViewStyle::new_default().node_style().stroke);
659 assert_eq!(
660 diff4.layout_style().flex_direction.enum_value().unwrap(),
661 crate::positioning::FlexDirection::FLEX_DIRECTION_ROW
662 );
663 assert_eq!(
664 diff4.layout_style().align_items.enum_value().unwrap(),
665 crate::positioning::AlignItems::ALIGN_ITEMS_STRETCH
666 );
667 assert_eq!(diff4.layout_style().margin, ViewStyle::new_default().layout_style().margin);
668 assert_eq!(
669 diff4.node_style().animation_override,
670 ViewStyle::new_default().node_style().animation_override
671 );
672 }
673
674 #[test]
675 fn test_view_new_rect() {
676 let view = View::new_rect(
677 &"rect1".to_string(),
678 &"Rect View".to_string(),
679 ViewShape::default(),
680 ViewStyle::new_default(),
681 None,
682 None,
683 ScrollInfo::new_default(),
684 None,
685 None,
686 RenderMethod::RENDER_METHOD_NONE,
687 HashMap::new(),
688 );
689 assert_eq!(view.id, "rect1");
690 assert_eq!(view.name, "Rect View");
691 assert!(matches!(
692 view.data.unwrap().view_data_type,
693 Some(View_data_type::Container { .. })
694 ));
695 }
696
697 #[test]
698 fn test_view_new_text() {
699 let view = View::new_text(
700 &"text1".to_string(),
701 &"Text View".to_string(),
702 ViewStyle::new_default(),
703 None,
704 None,
705 "Hello",
706 None,
707 None,
708 RenderMethod::RENDER_METHOD_NONE,
709 HashMap::new(),
710 );
711 assert_eq!(view.id, "text1");
712 assert_eq!(view.name, "Text View");
713 assert!(matches!(view.data.unwrap().view_data_type, Some(View_data_type::Text { .. })));
714 }
715
716 #[test]
717 fn test_view_add_child() {
718 let mut parent = View::new_rect(
719 &"parent".to_string(),
720 &"Parent".to_string(),
721 ViewShape::default(),
722 ViewStyle::new_default(),
723 None,
724 None,
725 ScrollInfo::new_default(),
726 None,
727 None,
728 RenderMethod::RENDER_METHOD_NONE,
729 HashMap::new(),
730 );
731 let child = View::new_rect(
732 &"child".to_string(),
733 &"Child".to_string(),
734 ViewShape::default(),
735 ViewStyle::new_default(),
736 None,
737 None,
738 ScrollInfo::new_default(),
739 None,
740 None,
741 RenderMethod::RENDER_METHOD_NONE,
742 HashMap::new(),
743 );
744 parent.add_child(child);
745 if let Some(View_data_type::Container { 0: Container { children, .. } }) =
746 parent.data.unwrap().view_data_type
747 {
748 assert_eq!(children.len(), 1);
749 assert_eq!(children[0].id, "child");
750 } else {
751 panic!("Wrong data type");
752 }
753 }
754
755 #[test]
756 fn test_find_view_by_id() {
757 let child = View::new_rect(
758 &"child".to_string(),
759 &"Child".to_string(),
760 ViewShape::default(),
761 ViewStyle::new_default(),
762 None,
763 None,
764 ScrollInfo::new_default(),
765 None,
766 None,
767 RenderMethod::RENDER_METHOD_NONE,
768 HashMap::new(),
769 );
770 let mut parent = View::new_rect(
771 &"parent".to_string(),
772 &"Parent".to_string(),
773 ViewShape::default(),
774 ViewStyle::new_default(),
775 None,
776 None,
777 ScrollInfo::new_default(),
778 None,
779 None,
780 RenderMethod::RENDER_METHOD_NONE,
781 HashMap::new(),
782 );
783 parent.add_child(child);
784 assert!(parent.find_view_by_id(&"child".to_string()).is_some());
785 assert!(parent.find_view_by_id(&"parent".to_string()).is_some());
786 assert!(parent.find_view_by_id(&"I1;child".to_string()).is_some());
787 assert!(parent.find_view_by_id(&"nonexistent".to_string()).is_none());
788 }
789
790 #[test]
791 fn test_view_data_difference() {
792 let view_data1 = ViewData {
794 view_data_type: Some(View_data_type::Text(Text {
795 content: "hello".to_string(),
796 ..Default::default()
797 })),
798 ..Default::default()
799 };
800 let view_data2 = ViewData {
801 view_data_type: Some(View_data_type::Text(Text {
802 content: "world".to_string(),
803 ..Default::default()
804 })),
805 ..Default::default()
806 };
807 assert_eq!(view_data1.difference(&view_data2), Some(view_data2.clone()));
808
809 let view_data3 = ViewData {
811 view_data_type: Some(View_data_type::Text(Text {
812 content: "hello".to_string(),
813 ..Default::default()
814 })),
815 ..Default::default()
816 };
817 assert_eq!(view_data1.difference(&view_data3), None);
818
819 let view_data4 = ViewData {
821 view_data_type: Some(View_data_type::StyledText(StyledTextRuns {
822 styled_texts: vec![],
823 ..Default::default()
824 })),
825 ..Default::default()
826 };
827 let view_data5 = ViewData {
828 view_data_type: Some(View_data_type::StyledText(StyledTextRuns {
829 styled_texts: vec![StyledTextRun::default()],
830 ..Default::default()
831 })),
832 ..Default::default()
833 };
834 assert_eq!(view_data4.difference(&view_data5), Some(view_data5.clone()));
835
836 let view_data6 = ViewData {
838 view_data_type: Some(View_data_type::StyledText(StyledTextRuns {
839 styled_texts: vec![],
840 ..Default::default()
841 })),
842 ..Default::default()
843 };
844 assert_eq!(view_data4.difference(&view_data6), None);
845
846 let view_data7 = ViewData {
848 view_data_type: Some(View_data_type::Container(Container::default())),
849 ..Default::default()
850 };
851 let view_data8 = ViewData {
852 view_data_type: Some(View_data_type::Container(Container {
853 children: vec![View::default()],
854 ..Default::default()
855 })),
856 ..Default::default()
857 };
858 assert_eq!(view_data7.difference(&view_data8), None);
859 }
860}