1use alloc::{collections::btree_map::BTreeMap, format, string::String, string::ToString, vec::Vec};
11use core::fmt::Write;
12use core::hash::Hash;
13
14#[allow(clippy::wildcard_imports)]
17use crate::{
18 corety::*,
19 css::*,
20 props::{basic::*, layout::*, property::*, style::*},
21};
22
23pub trait FormatAsRustCode {
25 fn format_as_rust_code(&self, tabs: usize) -> String;
26}
27
28pub trait GetHash {
30 fn get_hash(&self) -> u64;
31}
32
33impl<T: Hash> GetHash for T {
34 fn get_hash(&self) -> u64 {
35 use core::hash::Hasher;
36 let mut hasher = std::hash::DefaultHasher::new();
37 self.hash(&mut hasher);
38 hasher.finish()
39 }
40}
41
42impl<T: FormatAsRustCode + 'static> FormatAsRustCode for BoxOrStatic<T> {
46 fn format_as_rust_code(&self, tabs: usize) -> String {
47 self.as_ref().format_as_rust_code(tabs)
48 }
49}
50
51#[derive(Debug, Default)]
54pub struct VecContents {
55 pub strings: BTreeMap<u64, AzString>,
57 pub style_filters: BTreeMap<u64, StyleFilterVec>,
58 pub style_background_sizes: BTreeMap<u64, StyleBackgroundSizeVec>,
59 pub style_background_repeats: BTreeMap<u64, StyleBackgroundRepeatVec>,
60 pub style_background_contents: BTreeMap<u64, StyleBackgroundContentVec>,
61 pub style_background_positions: BTreeMap<u64, StyleBackgroundPositionVec>,
62 pub style_transforms: BTreeMap<u64, StyleTransformVec>,
63 pub font_families: BTreeMap<u64, StyleFontFamilyVec>,
64 pub linear_color_stops: BTreeMap<u64, NormalizedLinearColorStopVec>,
65 pub radial_color_stops: BTreeMap<u64, NormalizedRadialColorStopVec>,
66}
67
68impl VecContents {
69 pub fn format(&self, tabs: usize) -> String {
70 let mut result = String::new();
71 let t = " ".repeat(tabs);
72 let t2 = " ".repeat(tabs + 1);
73
74 for (key, item) in &self.strings {
75 let _ = write!(result,
76 "\r\n const STRING_{}: AzString = AzString::from_const_str(\"{}\");",
77 key,
78 item.as_str()
79 );
80 }
81
82 for (key, item) in &self.style_filters {
83 let val = item
84 .iter()
85 .map(|filter| format_style_filter(filter, tabs + 1))
86 .collect::<Vec<_>>()
87 .join(&format!(",\r\n{t}"));
88
89 let _ = write!(result,
90 "\r\n const STYLE_FILTER_{key}_ITEMS: &[StyleFilter] = &[\r\n{t2}{val}\r\n{t}];"
91 );
92 }
93
94 for (key, item) in &self.style_background_sizes {
95 let val = item
96 .iter()
97 .map(format_style_background_size)
98 .collect::<Vec<_>>()
99 .join(&format!(",\r\n{t}"));
100
101 let _ = write!(result,
102 "\r\n const STYLE_BACKGROUND_SIZE_{key}_ITEMS: &[StyleBackgroundSize] = \
103 &[\r\n{t2}{val}\r\n{t}];"
104 );
105 }
106
107 for (key, item) in &self.style_background_repeats {
108 let val = item
109 .iter()
110 .map(|bgr| bgr.format_as_rust_code(tabs + 1))
111 .collect::<Vec<_>>()
112 .join(&format!(",\r\n{t}"));
113
114 let _ = write!(result,
115 "\r\n const STYLE_BACKGROUND_REPEAT_{key}_ITEMS: &[StyleBackgroundRepeat] = \
116 &[\r\n{t2}{val}\r\n{t}];"
117 );
118 }
119
120 for (key, item) in &self.style_background_contents {
121 let val = item
122 .iter()
123 .map(|bgc| format_style_background_content(bgc, tabs + 1))
124 .collect::<Vec<_>>()
125 .join(&format!(",\r\n{t}"));
126
127 let _ = write!(result,
128 "\r\n const STYLE_BACKGROUND_CONTENT_{key}_ITEMS: &[StyleBackgroundContent] = \
129 &[\r\n{t2}{val}\r\n{t}];"
130 );
131 }
132
133 for (key, item) in &self.style_background_positions {
134 let val = item
135 .iter()
136 .map(|bgp| format_style_background_position(bgp, tabs))
137 .collect::<Vec<_>>()
138 .join(&format!(",\r\n{t}"));
139
140 let _ = write!(result,
141 "\r\n const STYLE_BACKGROUND_POSITION_{key}_ITEMS: &[StyleBackgroundPosition] = \
142 &[\r\n{t2}{val}\r\n{t}];"
143 );
144 }
145
146 for (key, item) in &self.style_transforms {
147 let val = format_style_transforms(item.as_ref(), tabs + 1);
148
149 let _ = write!(result,
150 "\r\n const STYLE_TRANSFORM_{key}_ITEMS: &[StyleTransform] = &[\r\n{t2}{val}\r\n{t}];"
151 );
152 }
153
154 for (key, item) in &self.font_families {
155 let val = format_font_ids(item.as_ref(), tabs + 1);
156
157 let _ = write!(result,
158 "\r\n const STYLE_FONT_FAMILY_{key}_ITEMS: &[StyleFontFamily] = &[\r\n{t2}{val}\r\n{t}];"
159 );
160 }
161
162 for (key, item) in &self.linear_color_stops {
163 let val = format_linear_color_stops(item.as_ref(), 1);
164
165 let _ = write!(result,
166 "\r\n const LINEAR_COLOR_STOP_{key}_ITEMS: &[NormalizedLinearColorStop] = \
167 &[\r\n{t2}{val}\r\n{t}];"
168 );
169 }
170
171 for (key, item) in &self.radial_color_stops {
172 let val = format_radial_color_stops(item.as_ref(), tabs);
173
174 let _ = write!(result,
175 "\r\n const RADIAL_COLOR_STOP_{key}_ITEMS: &[NormalizedRadialColorStop] = \
176 &[\r\n{t2}{val}\r\n{t}];"
177 );
178 }
179
180 result
181 }
182
183 #[allow(clippy::match_same_arms)]
187 pub fn insert_from_css_property(&mut self, prop: &CssProperty) {
188 match prop {
189 CssProperty::FontFamily(CssPropertyValue::Exact(v)) => {
190 for family in v {
191 match family {
192 StyleFontFamily::System(s) => {
193 let s = s.as_str();
196 let s = s.trim();
197 let s = s.trim_start_matches('\"');
198 let s = s.trim_end_matches('\"');
199 let s = s.trim_start_matches('\'');
200 let s = s.trim_end_matches('\'');
201
202 self.strings.insert(s.get_hash(), s.to_string().into());
203 }
204 StyleFontFamily::File(s) => {
205 let s = s.as_str();
206 let s = s.trim();
207 let s = s.trim_start_matches('\"');
208 let s = s.trim_end_matches('\"');
209 let s = s.trim_start_matches('\'');
210 let s = s.trim_end_matches('\'');
211
212 self.strings.insert(s.get_hash(), s.to_string().into());
213 }
214 _ => {}
215 }
216 }
217 self.font_families.insert(v.get_hash(), v.clone());
218 }
219 CssProperty::Transform(CssPropertyValue::Exact(v)) => {
220 self.style_transforms.insert(v.get_hash(), v.clone());
221 }
222 CssProperty::BackgroundRepeat(CssPropertyValue::Exact(v)) => {
223 self.style_background_repeats
224 .insert(v.get_hash(), v.clone());
225 }
226 CssProperty::BackgroundSize(CssPropertyValue::Exact(v)) => {
227 self.style_background_sizes.insert(v.get_hash(), v.clone());
228 }
229 CssProperty::BackgroundPosition(CssPropertyValue::Exact(v)) => {
230 self.style_background_positions
231 .insert(v.get_hash(), v.clone());
232 }
233 CssProperty::BackgroundContent(CssPropertyValue::Exact(ref v)) => {
234 for background in v {
235 match background {
236 StyleBackgroundContent::Image(id) => {
237 self.strings.insert(id.get_hash(), id.clone());
238 }
239 StyleBackgroundContent::LinearGradient(lg) => {
240 self.linear_color_stops
241 .insert(lg.stops.get_hash(), lg.stops.clone());
242 }
243 StyleBackgroundContent::RadialGradient(rg) => {
244 self.linear_color_stops
245 .insert(rg.stops.get_hash(), rg.stops.clone());
246 }
247 StyleBackgroundContent::ConicGradient(lg) => {
248 self.radial_color_stops
249 .insert(lg.stops.get_hash(), lg.stops.clone());
250 }
251 _ => {}
252 }
253 }
254 self.style_background_contents
255 .insert(v.get_hash(), v.clone());
256 }
257 CssProperty::Filter(CssPropertyValue::Exact(v)) => {
258 self.style_filters.insert(v.get_hash(), v.clone());
259 }
260 CssProperty::BackdropFilter(CssPropertyValue::Exact(v)) => {
261 self.style_filters.insert(v.get_hash(), v.clone());
262 }
263 _ => {}
264 }
265 }
266}
267
268#[must_use] pub fn format_pixel_value(p: &PixelValue) -> String {
272 let value = p.number.get();
273
274 let abs_val = libm::fabsf(value);
278 let sign: isize = if value < 0.0 { -1 } else { 1 };
279 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
280 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
281
282 match p.metric {
283 SizeMetric::Pt => format!(
284 "PixelValue::const_pt_fractional({pre_comma}, {post_comma})"
285 ),
286 SizeMetric::Em => format!(
287 "PixelValue::const_em_fractional({pre_comma}, {post_comma})"
288 ),
289 other => format!(
290 "PixelValue::const_from_metric_fractional(SizeMetric::{other:?}, {pre_comma}, {post_comma})"
291 ),
292 }
293}
294
295#[inline]
300#[allow(clippy::cast_possible_truncation)]
301const fn f32_to_isize(v: f32) -> isize {
302 v as isize
303}
304
305#[must_use] pub fn format_pixel_value_no_percent(p: &PixelValueNoPercent) -> String {
307 format!(
308 "PixelValueNoPercent {{ inner: {} }}",
309 format_pixel_value(&p.inner)
310 )
311}
312
313#[must_use] pub fn format_float_value(f: &FloatValue) -> String {
315 let value = f.get();
316 let abs_val = libm::fabsf(value);
317 let sign: isize = if value < 0.0 { -1 } else { 1 };
318 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
319 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
320 format!(
321 "FloatValue::const_new_fractional({pre_comma}, {post_comma})"
322 )
323}
324
325#[must_use] pub fn format_percentage_value(f: &PercentageValue) -> String {
327 let value = f.normalized() * 100.0;
328 let abs_val = libm::fabsf(value);
329 let sign: isize = if value < 0.0 { -1 } else { 1 };
330 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
331 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
332 format!(
333 "PercentageValue::const_new_fractional({pre_comma}, {post_comma})"
334 )
335}
336
337#[must_use] pub fn format_angle_value(f: &AngleValue) -> String {
339 let value = f.number.get();
340 let abs_val = libm::fabsf(value);
341 let sign: isize = if value < 0.0 { -1 } else { 1 };
342 let pre_comma = f32_to_isize(libm::floorf(abs_val)) * sign;
343 let post_comma = f32_to_isize(libm::roundf((abs_val - libm::floorf(abs_val)) * 100.0));
344 format!(
345 "AngleValue::const_from_metric_fractional(AngleMetric::{:?}, {}, {})",
346 f.metric, pre_comma, post_comma
347 )
348}
349
350#[must_use] pub fn format_color_value(c: &ColorU) -> String {
352 format!(
353 "ColorU {{ r: {}, g: {}, b: {}, a: {} }}",
354 c.r, c.g, c.b, c.a
355 )
356}
357
358fn format_grid_line(line: &GridLine, _tabs: usize) -> String {
359 match line {
360 GridLine::Auto => "GridLine::Auto".to_string(),
361 GridLine::Line(n) => format!("GridLine::Line({n})"),
362 GridLine::Named(named) => format!(
363 "GridLine::Named(NamedGridLine {{ grid_line_name: AzString::from_const_str({:?}), span_count: {} }})",
364 named.grid_line_name.as_ref(),
365 named.span_count,
366 ),
367 GridLine::Span(n) => format!("GridLine::Span({n})"),
368 }
369}
370
371fn format_color_or_system(c: ColorOrSystem) -> String {
372 use crate::props::basic::color::{ColorOrSystem, SystemColorRef};
373 match c {
374 ColorOrSystem::Color(color) => format!("ColorOrSystem::Color({})", format_color_value(&color)),
375 ColorOrSystem::System(system_ref) => {
376 let variant = match system_ref {
377 SystemColorRef::Text => "Text",
378 SystemColorRef::Background => "Background",
379 SystemColorRef::Accent => "Accent",
380 SystemColorRef::AccentText => "AccentText",
381 SystemColorRef::ButtonFace => "ButtonFace",
382 SystemColorRef::ButtonText => "ButtonText",
383 SystemColorRef::WindowBackground => "WindowBackground",
384 SystemColorRef::SelectionBackground => "SelectionBackground",
385 SystemColorRef::SelectionText => "SelectionText",
386 };
387 format!("ColorOrSystem::System(SystemColorRef::{variant})")
388 }
389 }
390}
391
392macro_rules! impl_float_value_fmt {
395 ($struct_name:ident) => {
396 impl FormatAsRustCode for $struct_name {
397 fn format_as_rust_code(&self, _tabs: usize) -> String {
398 format!(
399 "{} {{ inner: {} }}",
400 stringify!($struct_name),
401 format_float_value(&self.inner)
402 )
403 }
404 }
405 };
406}
407
408impl_float_value_fmt!(LayoutFlexGrow);
409impl_float_value_fmt!(LayoutFlexShrink);
410
411macro_rules! impl_percentage_value_fmt {
412 ($struct_name:ident) => {
413 impl FormatAsRustCode for $struct_name {
414 fn format_as_rust_code(&self, _tabs: usize) -> String {
415 format!(
416 "{} {{ inner: {} }}",
417 stringify!($struct_name),
418 format_percentage_value(&self.inner)
419 )
420 }
421 }
422 };
423}
424
425impl_percentage_value_fmt!(StyleLineHeight);
426impl_percentage_value_fmt!(StyleOpacity);
427
428macro_rules! impl_pixel_value_fmt {
429 ($struct_name:ident) => {
430 impl FormatAsRustCode for $struct_name {
431 fn format_as_rust_code(&self, _tabs: usize) -> String {
432 format!(
433 "{} {{ inner: {} }}",
434 stringify!($struct_name),
435 format_pixel_value(&self.inner)
436 )
437 }
438 }
439 };
440}
441
442impl_pixel_value_fmt!(StyleTabSize);
443impl_pixel_value_fmt!(StyleBorderTopLeftRadius);
444impl_pixel_value_fmt!(StyleBorderBottomLeftRadius);
445impl_pixel_value_fmt!(StyleBorderTopRightRadius);
446impl_pixel_value_fmt!(StyleBorderBottomRightRadius);
447
448impl_pixel_value_fmt!(LayoutBorderTopWidth);
449impl_pixel_value_fmt!(LayoutBorderLeftWidth);
450impl_pixel_value_fmt!(LayoutBorderRightWidth);
451impl_pixel_value_fmt!(LayoutBorderBottomWidth);
452impl_pixel_value_fmt!(StyleLetterSpacing);
453impl_pixel_value_fmt!(StyleWordSpacing);
454impl_pixel_value_fmt!(StyleFontSize);
455
456impl_pixel_value_fmt!(LayoutMarginTop);
457impl_pixel_value_fmt!(LayoutMarginBottom);
458impl_pixel_value_fmt!(LayoutMarginRight);
459impl_pixel_value_fmt!(LayoutMarginLeft);
460
461impl_pixel_value_fmt!(LayoutPaddingTop);
462impl_pixel_value_fmt!(LayoutPaddingBottom);
463impl_pixel_value_fmt!(LayoutPaddingRight);
464impl_pixel_value_fmt!(LayoutPaddingLeft);
465impl_pixel_value_fmt!(LayoutPaddingInlineStart);
466impl_pixel_value_fmt!(LayoutPaddingInlineEnd);
467
468impl FormatAsRustCode for LayoutWidth {
469 fn format_as_rust_code(&self, _tabs: usize) -> String {
470 match self {
471 Self::Auto => "LayoutWidth::Auto".to_string(),
472 Self::Px(px) => format!("LayoutWidth::Px({})", format_pixel_value(px)),
473 Self::MinContent => "LayoutWidth::MinContent".to_string(),
474 Self::MaxContent => "LayoutWidth::MaxContent".to_string(),
475 Self::FitContent(px) => format!("LayoutWidth::FitContent({})", format_pixel_value(px)),
476 Self::Calc(items) => format!("LayoutWidth::Calc(/* {} items */)", items.len()),
477 }
478 }
479}
480
481impl FormatAsRustCode for LayoutHeight {
482 fn format_as_rust_code(&self, _tabs: usize) -> String {
483 match self {
484 Self::Auto => "LayoutHeight::Auto".to_string(),
485 Self::Px(px) => format!("LayoutHeight::Px({})", format_pixel_value(px)),
486 Self::MinContent => "LayoutHeight::MinContent".to_string(),
487 Self::MaxContent => "LayoutHeight::MaxContent".to_string(),
488 Self::FitContent(px) => format!("LayoutHeight::FitContent({})", format_pixel_value(px)),
489 Self::Calc(items) => format!("LayoutHeight::Calc(/* {} items */)", items.len()),
490 }
491 }
492}
493
494impl_pixel_value_fmt!(LayoutMinHeight);
495impl_pixel_value_fmt!(LayoutMinWidth);
496impl_pixel_value_fmt!(LayoutMaxWidth);
497impl_pixel_value_fmt!(LayoutMaxHeight);
498impl_pixel_value_fmt!(LayoutTop);
499impl_pixel_value_fmt!(LayoutInsetBottom);
500
501impl_pixel_value_fmt!(LayoutRight);
502impl_pixel_value_fmt!(LayoutLeft);
503
504impl_pixel_value_fmt!(LayoutColumnGap);
507impl_pixel_value_fmt!(LayoutRowGap);
508
509impl FormatAsRustCode for GridTemplate {
510 fn format_as_rust_code(&self, tabs: usize) -> String {
511 let tracks: Vec<String> = self
512 .tracks
513 .as_ref()
514 .iter()
515 .map(|t| t.format_as_rust_code(tabs))
516 .collect();
517 format!(
518 "GridTemplate {{ tracks: GridTrackSizingVec::from_vec(vec![{}]) }}",
519 tracks.join(", ")
520 )
521 }
522}
523
524impl FormatAsRustCode for GridPlacement {
525 fn format_as_rust_code(&self, tabs: usize) -> String {
526 format!(
527 "GridPlacement {{ grid_start: {}, grid_end: {} }}",
528 format_grid_line(&self.grid_start, tabs),
529 format_grid_line(&self.grid_end, tabs),
530 )
531 }
532}
533
534impl_color_value_fmt!(StyleTextColor);
535impl_color_value_fmt!(StyleBorderTopColor);
536impl_color_value_fmt!(StyleBorderLeftColor);
537impl_color_value_fmt!(StyleBorderRightColor);
538impl_color_value_fmt!(StyleBorderBottomColor);
539
540impl_enum_fmt!(
541 StyleMixBlendMode,
542 Normal,
543 Multiply,
544 Screen,
545 Overlay,
546 Darken,
547 Lighten,
548 ColorDodge,
549 ColorBurn,
550 HardLight,
551 SoftLight,
552 Difference,
553 Exclusion,
554 Hue,
555 Saturation,
556 Color,
557 Luminosity
558);
559
560impl_enum_fmt!(StyleHyphens, None, Manual, Auto);
561impl_enum_fmt!(StyleWordBreak, Normal, BreakAll, KeepAll, BreakWord);
562impl_enum_fmt!(StyleOverflowWrap, Normal, Anywhere, BreakWord);
563impl_enum_fmt!(StyleLineBreak, Auto, Loose, Normal, Strict, Anywhere);
564impl_enum_fmt!(StyleObjectFit, Fill, Contain, Cover, None, ScaleDown);
565impl_enum_fmt!(StyleTextOverflow, Clip, Ellipsis);
566
567impl FormatAsRustCode for StyleObjectPosition {
568 fn format_as_rust_code(&self, _tabs: usize) -> String {
569 format!("StyleObjectPosition {{ horizontal: {}, vertical: {} }}",
570 format_background_position_horizontal(&self.horizontal),
571 format_background_position_vertical(&self.vertical))
572 }
573}
574
575impl FormatAsRustCode for StyleAspectRatio {
576 fn format_as_rust_code(&self, _tabs: usize) -> String {
577 match self {
578 Self::Auto => "StyleAspectRatio::Auto".to_string(),
579 Self::Ratio(r) => format!("StyleAspectRatio::Ratio(AspectRatioValue {{ width: {}, height: {} }})", r.width, r.height),
580 }
581 }
582}
583
584impl_enum_fmt!(StyleTextOrientation, Mixed, Upright, Sideways);
585impl_enum_fmt!(StyleTextAlignLast, Auto, Start, End, Left, Right, Center, Justify);
586
587impl_enum_fmt!(StyleTextTransform, None, Capitalize, Uppercase, Lowercase, FullWidth);
588
589impl_enum_fmt!(StyleDirection, Ltr, Rtl);
590
591impl_enum_fmt!(StyleWhiteSpace, Normal, Pre, Nowrap, PreWrap, PreLine, BreakSpaces);
592
593impl_enum_fmt!(StyleVisibility, Visible, Hidden, Collapse);
594
595impl_enum_fmt!(LayoutWritingMode, HorizontalTb, VerticalRl, VerticalLr);
596
597impl_enum_fmt!(LayoutClear, None, Left, Right, Both);
598
599impl_enum_fmt!(
600 StyleCursor,
601 Alias,
602 AllScroll,
603 Cell,
604 ColResize,
605 ContextMenu,
606 Copy,
607 Crosshair,
608 Default,
609 EResize,
610 EwResize,
611 Grab,
612 Grabbing,
613 Help,
614 Move,
615 NResize,
616 NsResize,
617 NeswResize,
618 NwseResize,
619 Pointer,
620 Progress,
621 RowResize,
622 SResize,
623 SeResize,
624 Text,
625 Unset,
626 VerticalText,
627 WResize,
628 Wait,
629 ZoomIn,
630 ZoomOut
631);
632
633impl_enum_fmt!(
634 BorderStyle,
635 None,
636 Solid,
637 Double,
638 Dotted,
639 Dashed,
640 Hidden,
641 Groove,
642 Ridge,
643 Inset,
644 Outset
645);
646
647impl_enum_fmt!(
648 StyleBackgroundRepeat,
649 NoRepeat,
650 PatternRepeat,
651 RepeatX,
652 RepeatY
653);
654
655impl_enum_fmt!(
656 LayoutDisplay,
657 None,
658 Block,
659 Inline,
660 InlineBlock,
661 Flex,
662 InlineFlex,
663 Table,
664 InlineTable,
665 TableRowGroup,
666 TableHeaderGroup,
667 TableFooterGroup,
668 TableRow,
669 TableColumnGroup,
670 TableColumn,
671 TableCell,
672 TableCaption,
673 ListItem,
674 RunIn,
675 Marker,
676 Grid,
677 InlineGrid,
678 FlowRoot,
679 Contents
680);
681
682impl_enum_fmt!(LayoutFloat, Left, Right, None);
683
684impl_enum_fmt!(LayoutBoxSizing, ContentBox, BorderBox);
685
686impl_enum_fmt!(LayoutFlexDirection, Row, RowReverse, Column, ColumnReverse);
687
688impl_enum_fmt!(LayoutFlexWrap, Wrap, NoWrap, WrapReverse);
689
690impl_enum_fmt!(
691 LayoutJustifyContent,
692 Start,
693 End,
694 FlexStart,
695 FlexEnd,
696 Center,
697 SpaceBetween,
698 SpaceAround,
699 SpaceEvenly
700);
701
702impl_enum_fmt!(LayoutAlignItems, Stretch, Center, Start, End, Baseline);
703
704impl_enum_fmt!(
705 LayoutAlignContent,
706 Start,
707 End,
708 Stretch,
709 Center,
710 SpaceBetween,
711 SpaceAround
712);
713
714impl_enum_fmt!(Shape, Circle, Ellipse);
715
716impl_enum_fmt!(LayoutOverflow, Auto, Scroll, Visible, Hidden, Clip);
717
718impl_enum_fmt!(StyleTextAlign, Center, Left, Right, Justify, Start, End);
719
720impl_enum_fmt!(StyleUserSelect, Auto, Text, None, All);
721
722impl_enum_fmt!(StyleTextDecoration, None, Underline, Overline, LineThrough);
723
724impl_enum_fmt!(
725 DirectionCorner,
726 Right,
727 Left,
728 Top,
729 Bottom,
730 TopRight,
731 TopLeft,
732 BottomRight,
733 BottomLeft
734);
735
736impl_enum_fmt!(ExtendMode, Clamp, Repeat);
737
738impl_enum_fmt!(StyleBackfaceVisibility, Visible, Hidden);
739
740impl_enum_fmt!(StyleUnicodeBidi, Normal, Embed, Isolate, BidiOverride, IsolateOverride, Plaintext);
741impl_enum_fmt!(StyleTextBoxTrim, None, TrimStart, TrimEnd, TrimBoth);
742impl_enum_fmt!(TextBoxEdgeOver, Auto, Text, Cap, Ex, Ideographic, IdeographicInk);
743impl_enum_fmt!(TextBoxEdgeUnder, Auto, Text, Alphabetic, Ideographic, IdeographicInk);
744impl FormatAsRustCode for StyleTextBoxEdge {
745 fn format_as_rust_code(&self, tabs: usize) -> String {
746 format!(
747 "StyleTextBoxEdge {{ over: {}, under: {} }}",
748 self.over.format_as_rust_code(tabs),
749 self.under.format_as_rust_code(tabs)
750 )
751 }
752}
753impl_enum_fmt!(StyleDominantBaseline, Auto, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, Hanging, TextTop);
754impl_enum_fmt!(StyleAlignmentBaseline, Baseline, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, TextTop);
755impl_enum_fmt!(StyleBaselineSource, Auto, First, Last);
756impl_enum_fmt!(StyleLineFitEdge, Leading, Text, Cap, Ex, Ideographic, IdeographicInk, Alphabetic);
757impl_enum_fmt!(StyleInitialLetterAlign, Auto, Alphabetic, Hanging, Ideographic);
758impl_enum_fmt!(StyleInitialLetterWrap, None, First, All, Grid);
759impl_enum_fmt!(StyleScrollbarGutter, Auto, Stable, StableBothEdges);
760
761impl FormatAsRustCode for StyleOverflowClipMargin {
762 fn format_as_rust_code(&self, tabs: usize) -> String {
763 format!("StyleOverflowClipMargin {{ inner: {} }}", self.inner.format_as_rust_code(tabs))
764 }
765}
766
767impl FormatAsRustCode for StyleClipRect {
768 fn format_as_rust_code(&self, _tabs: usize) -> String {
769 fn fmt_edge(o: OptionF32) -> String {
770 match o {
771 OptionF32::None => String::from("OptionF32::None"),
772 OptionF32::Some(v) => format!("OptionF32::Some({v:?})"),
773 }
774 }
775 format!(
776 "StyleClipRect {{ top: {}, right: {}, bottom: {}, left: {} }}",
777 fmt_edge(self.top),
778 fmt_edge(self.right),
779 fmt_edge(self.bottom),
780 fmt_edge(self.left),
781 )
782 }
783}
784
785fn format_style_background_size(c: &StyleBackgroundSize) -> String {
788 match c {
789 StyleBackgroundSize::Contain => String::from("StyleBackgroundSize::Contain"),
790 StyleBackgroundSize::Cover => String::from("StyleBackgroundSize::Cover"),
791 StyleBackgroundSize::ExactSize(size) => format!(
792 "StyleBackgroundSize::ExactSize(PixelValueSize {{ width: {}, height: {} }})",
793 format_pixel_value(&size.width),
794 format_pixel_value(&size.height)
795 ),
796 }
797}
798
799#[must_use] pub fn format_scrollbar_info(s: &ScrollbarInfo, tabs: usize) -> String {
803 let t = String::from(" ").repeat(tabs);
804 let t1 = String::from(" ").repeat(tabs + 1);
805 format!(
806 "ScrollbarInfo {{\r\n{}width: {},\r\n{}padding_left: {},\r\n{}padding_right: \
807 {},\r\n{}track: {},\r\n{}thumb: {},\r\n{}button: {},\r\n{}button: {},\r\n{}resizer: \
808 {},\r\n{}}}",
809 t1,
810 s.width.format_as_rust_code(tabs + 1),
811 t1,
812 s.padding_left.format_as_rust_code(tabs + 1),
813 t1,
814 s.padding_right.format_as_rust_code(tabs + 1),
815 t1,
816 format_style_background_content(&s.track, tabs + 1),
817 t1,
818 format_style_background_content(&s.thumb, tabs + 1),
819 t1,
820 format_style_background_content(&s.button, tabs + 1),
821 t1,
822 format_style_background_content(&s.corner, tabs + 1),
823 t1,
824 format_style_background_content(&s.resizer, tabs + 1),
825 t
826 )
827}
828
829fn format_style_background_content(content: &StyleBackgroundContent, tabs: usize) -> String {
832 match content {
833 StyleBackgroundContent::LinearGradient(l) => format!(
834 "StyleBackgroundContent::LinearGradient({})",
835 format_linear_gradient(l, tabs)
836 ),
837 StyleBackgroundContent::RadialGradient(r) => format!(
838 "StyleBackgroundContent::RadialGradient({})",
839 format_radial_gradient(r, tabs)
840 ),
841 StyleBackgroundContent::ConicGradient(r) => format!(
842 "StyleBackgroundContent::ConicGradient({})",
843 format_conic_gradient(r, tabs)
844 ),
845 StyleBackgroundContent::Image(id) => format!("StyleBackgroundContent::Image({id:?})"),
846 StyleBackgroundContent::Color(c) => {
847 format!("StyleBackgroundContent::Color({})", format_color_value(c))
848 }
849 StyleBackgroundContent::SystemColor(s) => {
850 use crate::props::basic::color::SystemColorRef;
851 let variant = match s {
852 SystemColorRef::Text => "Text",
853 SystemColorRef::Background => "Background",
854 SystemColorRef::Accent => "Accent",
855 SystemColorRef::AccentText => "AccentText",
856 SystemColorRef::ButtonFace => "ButtonFace",
857 SystemColorRef::ButtonText => "ButtonText",
858 SystemColorRef::WindowBackground => "WindowBackground",
859 SystemColorRef::SelectionBackground => "SelectionBackground",
860 SystemColorRef::SelectionText => "SelectionText",
861 };
862 format!("StyleBackgroundContent::SystemColor(SystemColorRef::{variant})")
863 }
864 }
865}
866
867fn format_direction(d: &Direction, tabs: usize) -> String {
868 match d {
869 Direction::Angle(fv) => format!("Direction::Angle({})", format_angle_value(fv)),
870 Direction::FromTo(DirectionCorners { dir_from, dir_to }) => format!(
871 "Direction::FromTo(DirectionCorners {{ dir_from: {}, dir_to: {} }})",
872 dir_from.format_as_rust_code(tabs + 1),
873 dir_to.format_as_rust_code(tabs + 1)
874 ),
875 }
876}
877
878fn format_linear_gradient(l: &LinearGradient, tabs: usize) -> String {
879 let t = String::from(" ").repeat(tabs);
880 let t1 = String::from(" ").repeat(tabs + 1);
881 format!(
882 "LinearGradient {{\r\n{}direction: {},\r\n{}extend_mode: {},\r\n{}stops: \
883 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
884 t1,
885 format_direction(&l.direction, tabs + 1),
886 t1,
887 l.extend_mode.format_as_rust_code(tabs + 1),
888 t1,
889 l.stops.get_hash(),
890 t,
891 )
892}
893
894fn format_conic_gradient(r: &ConicGradient, tabs: usize) -> String {
895 let t = String::from(" ").repeat(tabs);
896 let t1 = String::from(" ").repeat(tabs + 1);
897
898 format!(
899 "ConicGradient {{\r\n{}extend_mode: {},\r\n{}center: {},\r\n{}angle: {},\r\n{}stops: \
900 NormalizedRadialColorStopVec::from_const_slice(RADIAL_COLOR_STOP_{}_ITEMS),\r\n{}}}",
901 t1,
902 r.extend_mode.format_as_rust_code(tabs + 1),
903 t1,
904 format_style_background_position(&r.center, tabs + 1),
905 t1,
906 format_angle_value(&r.angle),
907 t1,
908 r.stops.get_hash(),
909 t,
910 )
911}
912
913fn format_radial_gradient(r: &RadialGradient, tabs: usize) -> String {
914 let t = String::from(" ").repeat(tabs);
915 let t1 = String::from(" ").repeat(tabs + 1);
916 format!(
917 "RadialGradient {{\r\n{}shape: {},\r\n{}extend_mode: {},\r\n{}position: {},\r\n{}size: \
918 RadialGradientSize::{:?},\r\n{}stops: \
919 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
920 t1,
921 r.shape.format_as_rust_code(tabs + 1),
922 t1,
923 r.extend_mode.format_as_rust_code(tabs + 1),
924 t1,
925 format_style_background_position(&r.position, tabs + 1),
926 t1,
927 r.size,
928 t1,
929 r.stops.get_hash(),
930 t,
931 )
932}
933
934fn format_linear_color_stops(stops: &[NormalizedLinearColorStop], tabs: usize) -> String {
935 let t = String::from(" ").repeat(tabs);
936 stops
937 .iter()
938 .map(format_linear_color_stop)
939 .collect::<Vec<_>>()
940 .join(&format!(",\r\n{t}"))
941}
942
943fn format_linear_color_stop(g: &NormalizedLinearColorStop) -> String {
944 format!(
945 "NormalizedLinearColorStop {{ offset: {}, color: {} }}",
946 format_percentage_value(&g.offset),
947 format_color_or_system(g.color),
948 )
949}
950
951fn format_radial_color_stops(stops: &[NormalizedRadialColorStop], tabs: usize) -> String {
952 let t = String::from(" ").repeat(tabs);
953 stops
954 .iter()
955 .map(format_radial_color_stop)
956 .collect::<Vec<_>>()
957 .join(&format!(",\r\n{t}"))
958}
959
960fn format_radial_color_stop(g: &NormalizedRadialColorStop) -> String {
961 format!(
962 "RadialColorStop {{ angle: {}, color: {} }}",
963 format_angle_value(&g.angle),
964 format_color_or_system(g.color),
965 )
966}
967
968fn format_style_filter(st: &StyleFilter, tabs: usize) -> String {
969 match st {
970 StyleFilter::Blend(mb) => format!("StyleFilter::Blend({})", mb.format_as_rust_code(tabs)),
971 StyleFilter::Flood(c) => format!("StyleFilter::Flood({})", format_color_value(c)),
972 StyleFilter::Blur(m) => format!(
973 "StyleFilter::Blur(StyleBlur {{ width: {}, height: {} }})",
974 format_pixel_value(&m.width),
975 format_pixel_value(&m.height)
976 ),
977 StyleFilter::Opacity(pct) => {
978 format!("StyleFilter::Opacity({})", format_percentage_value(pct))
979 }
980 StyleFilter::ColorMatrix(cm) => format!(
981 "StyleFilter::ColorMatrix(StyleColorMatrix {{ m0: {}, m1: {}, m2: {}, m3: {}, m4: {}, \
982 m5: {}, m6: {}, m7: {}, m8: {}, m9: {}, m10: {}, m11: {}, m12: {}, m13: {}, m14: {}, \
983 m15: {}, m16: {}, m17: {}, m18: {}, m19: {} }})",
984 format_float_value(&cm.m0),
985 format_float_value(&cm.m1),
986 format_float_value(&cm.m2),
987 format_float_value(&cm.m3),
988 format_float_value(&cm.m4),
989 format_float_value(&cm.m5),
990 format_float_value(&cm.m6),
991 format_float_value(&cm.m7),
992 format_float_value(&cm.m8),
993 format_float_value(&cm.m9),
994 format_float_value(&cm.m10),
995 format_float_value(&cm.m11),
996 format_float_value(&cm.m12),
997 format_float_value(&cm.m13),
998 format_float_value(&cm.m14),
999 format_float_value(&cm.m15),
1000 format_float_value(&cm.m16),
1001 format_float_value(&cm.m17),
1002 format_float_value(&cm.m18),
1003 format_float_value(&cm.m19)
1004 ),
1005 StyleFilter::DropShadow(m) => {
1006 format!("StyleFilter::DropShadow({})", m.format_as_rust_code(tabs))
1007 }
1008 StyleFilter::ComponentTransfer => "StyleFilter::ComponentTransfer".to_string(),
1009 StyleFilter::Offset(o) => format!(
1010 "StyleFilter::Offset(StyleFilterOffset {{ x: {}, y: {} }})",
1011 format_pixel_value(&o.x),
1012 format_pixel_value(&o.y)
1013 ),
1014 StyleFilter::Composite(StyleCompositeFilter::Over) => {
1015 "StyleFilter::Composite(StyleCompositeFilter::Over)".to_string()
1016 }
1017 StyleFilter::Composite(StyleCompositeFilter::In) => {
1018 "StyleFilter::Composite(StyleCompositeFilter::In)".to_string()
1019 }
1020 StyleFilter::Composite(StyleCompositeFilter::Atop) => {
1021 "StyleFilter::Composite(StyleCompositeFilter::Atop)".to_string()
1022 }
1023 StyleFilter::Composite(StyleCompositeFilter::Out) => {
1024 "StyleFilter::Composite(StyleCompositeFilter::Out)".to_string()
1025 }
1026 StyleFilter::Composite(StyleCompositeFilter::Xor) => {
1027 "StyleFilter::Composite(StyleCompositeFilter::Xor)".to_string()
1028 }
1029 StyleFilter::Composite(StyleCompositeFilter::Lighter) => {
1030 "StyleFilter::Composite(StyleCompositeFilter::Lighter)".to_string()
1031 }
1032 StyleFilter::Composite(StyleCompositeFilter::Arithmetic(fv)) => format!(
1033 "StyleFilter::Composite(StyleCompositeFilter::Arithmetic(ArithmeticCoefficients {{ \
1034 k1: {}, k2: {}, k3: {}, k4: {} }}))",
1035 format_float_value(&fv.k1),
1036 format_float_value(&fv.k2),
1037 format_float_value(&fv.k3),
1038 format_float_value(&fv.k4)
1039 ),
1040 StyleFilter::Brightness(v) => format!("StyleFilter::Brightness({})", format_percentage_value(v)),
1041 StyleFilter::Contrast(v) => format!("StyleFilter::Contrast({})", format_percentage_value(v)),
1042 StyleFilter::Grayscale(v) => format!("StyleFilter::Grayscale({})", format_percentage_value(v)),
1043 StyleFilter::HueRotate(a) => format!("StyleFilter::HueRotate({})", format_angle_value(a)),
1044 StyleFilter::Invert(v) => format!("StyleFilter::Invert({})", format_percentage_value(v)),
1045 StyleFilter::Saturate(v) => format!("StyleFilter::Saturate({})", format_percentage_value(v)),
1046 StyleFilter::Sepia(v) => format!("StyleFilter::Sepia({})", format_percentage_value(v)),
1047 }
1048}
1049
1050fn format_style_transforms(stops: &[StyleTransform], tabs: usize) -> String {
1051 let t = String::from(" ").repeat(tabs);
1052 stops
1053 .iter()
1054 .map(|s| format_style_transform(s, tabs))
1055 .collect::<Vec<_>>()
1056 .join(&format!(",\r\n{t}"))
1057}
1058
1059#[allow(clippy::too_many_lines)] fn format_style_transform(st: &StyleTransform, tabs: usize) -> String {
1061 let tabs_minus_one = String::from(" ").repeat(tabs);
1062 let tabs = String::from(" ").repeat(tabs + 1);
1063 match st {
1064 StyleTransform::Matrix(m) => format!(
1065 "StyleTransform::Matrix(StyleTransformMatrix2D {{ a: {}, b: {}, c: {}, d: {}, tx: {}, \
1066 ty: {} }})",
1067 format_float_value(&m.a),
1068 format_float_value(&m.b),
1069 format_float_value(&m.c),
1070 format_float_value(&m.d),
1071 format_float_value(&m.tx),
1072 format_float_value(&m.ty)
1073 ),
1074 StyleTransform::Matrix3D(m) => format!(
1075 "StyleTransform::Matrix3D(StyleTransformMatrix3D {{\r\n{tabs}m11: {},\r\n{tabs}m12: \
1076 {},\r\n{tabs}m13: {},\r\n{tabs}m14: {},\r\n{tabs}m21: {},\r\n{tabs}m22: \
1077 {},\r\n{tabs}m23: {},\r\n{tabs}m24: {},\r\n{tabs}m31: {},\r\n{tabs}m32: \
1078 {},\r\n{tabs}m33: {},\r\n{tabs}m34: {},\r\n{tabs}m41: {},\r\n{tabs}m42: \
1079 {},\r\n{tabs}m43: {},\r\n{tabs}m44: {}\r\n{tabs_minus_one}}})",
1080 format_float_value(&m.m11),
1081 format_float_value(&m.m12),
1082 format_float_value(&m.m13),
1083 format_float_value(&m.m14),
1084 format_float_value(&m.m21),
1085 format_float_value(&m.m22),
1086 format_float_value(&m.m23),
1087 format_float_value(&m.m24),
1088 format_float_value(&m.m31),
1089 format_float_value(&m.m32),
1090 format_float_value(&m.m33),
1091 format_float_value(&m.m34),
1092 format_float_value(&m.m41),
1093 format_float_value(&m.m42),
1094 format_float_value(&m.m43),
1095 format_float_value(&m.m44),
1096 tabs = tabs,
1097 tabs_minus_one = tabs_minus_one,
1098 ),
1099 StyleTransform::Translate(t) => format!(
1100 "StyleTransform::Translate(StyleTransformTranslate2D {{ x: {}, y: {} }})",
1101 format_pixel_value(&t.x),
1102 format_pixel_value(&t.y)
1103 ),
1104 StyleTransform::Translate3D(t) => format!(
1105 "StyleTransform::Translate3D(StyleTransformTranslate3D {{ x: {}, y: {}, z: {} }})",
1106 format_pixel_value(&t.x),
1107 format_pixel_value(&t.y),
1108 format_pixel_value(&t.z)
1109 ),
1110 StyleTransform::TranslateX(x) => {
1111 format!("StyleTransform::TranslateX({})", format_pixel_value(x))
1112 }
1113 StyleTransform::TranslateY(y) => {
1114 format!("StyleTransform::TranslateY({})", format_pixel_value(y))
1115 }
1116 StyleTransform::TranslateZ(z) => {
1117 format!("StyleTransform::TranslateZ({})", format_pixel_value(z))
1118 }
1119 StyleTransform::Rotate(r) => format!("StyleTransform::Rotate({})", format_angle_value(r)),
1120 StyleTransform::Rotate3D(r) => format!(
1121 "StyleTransform::Rotate3D(StyleTransformRotate3D {{ {}, {}, {}, {} }})",
1122 format_float_value(&r.x),
1123 format_float_value(&r.y),
1124 format_float_value(&r.z),
1125 format_angle_value(&r.angle)
1126 ),
1127 StyleTransform::RotateX(x) => {
1128 format!("StyleTransform::RotateX({})", format_angle_value(x))
1129 }
1130 StyleTransform::RotateY(y) => {
1131 format!("StyleTransform::RotateY({})", format_angle_value(y))
1132 }
1133 StyleTransform::RotateZ(z) => {
1134 format!("StyleTransform::RotateZ({})", format_angle_value(z))
1135 }
1136 StyleTransform::Scale(s) => format!(
1137 "StyleTransform::Scale(StyleTransformScale2D {{ x: {}, y: {} }})",
1138 format_float_value(&s.x),
1139 format_float_value(&s.y)
1140 ),
1141 StyleTransform::Scale3D(s) => format!(
1142 "StyleTransform::Scale3D(StyleTransformScale3D {{ x: {}, y: {}, z: {} }})",
1143 format_float_value(&s.x),
1144 format_float_value(&s.y),
1145 format_float_value(&s.z)
1146 ),
1147 StyleTransform::ScaleX(x) => {
1148 format!("StyleTransform::ScaleX({})", format_percentage_value(x))
1149 }
1150 StyleTransform::ScaleY(y) => {
1151 format!("StyleTransform::ScaleY({})", format_percentage_value(y))
1152 }
1153 StyleTransform::ScaleZ(z) => {
1154 format!("StyleTransform::ScaleZ({})", format_percentage_value(z))
1155 }
1156 StyleTransform::Skew(sk) => format!(
1157 "StyleTransform::Skew(StyleTransformSkew2D {{ x: {}, y: {} }})",
1158 format_angle_value(&sk.x),
1159 format_angle_value(&sk.y)
1160 ),
1161 StyleTransform::SkewX(x) => {
1162 format!("StyleTransform::SkewX({})", format_angle_value(x))
1163 }
1164 StyleTransform::SkewY(y) => {
1165 format!("StyleTransform::SkewY({})", format_angle_value(y))
1166 }
1167 StyleTransform::Perspective(dist) => {
1168 format!("StyleTransform::Perspective({})", format_pixel_value(dist))
1169 }
1170 }
1171}
1172
1173fn format_font_ids(font_ids: &[StyleFontFamily], tabs: usize) -> String {
1174 let t = String::from(" ").repeat(tabs);
1175 font_ids
1176 .iter()
1177 .map(|s| s.format_as_rust_code(tabs + 1))
1178 .collect::<Vec<_>>()
1179 .join(&format!(",\r\n{t}"))
1180}
1181
1182fn format_style_background_position(b: &StyleBackgroundPosition, tabs: usize) -> String {
1183 let t = String::from(" ").repeat(tabs);
1184 let t1 = String::from(" ").repeat(tabs + 1);
1185 format!(
1186 "StyleBackgroundPosition {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1187 t1,
1188 format_background_position_horizontal(&b.horizontal),
1189 t1,
1190 format_background_position_vertical(&b.vertical),
1191 t
1192 )
1193}
1194
1195fn format_background_position_horizontal(b: &BackgroundPositionHorizontal) -> String {
1196 match b {
1197 BackgroundPositionHorizontal::Left => "BackgroundPositionHorizontal::Left".to_string(),
1198 BackgroundPositionHorizontal::Center => "BackgroundPositionHorizontal::Center".to_string(),
1199 BackgroundPositionHorizontal::Right => "BackgroundPositionHorizontal::Right".to_string(),
1200 BackgroundPositionHorizontal::Exact(p) => format!(
1201 "BackgroundPositionHorizontal::Exact({})",
1202 format_pixel_value(p)
1203 ),
1204 }
1205}
1206
1207fn format_background_position_vertical(b: &BackgroundPositionVertical) -> String {
1208 match b {
1209 BackgroundPositionVertical::Top => "BackgroundPositionVertical::Top".to_string(),
1210 BackgroundPositionVertical::Center => "BackgroundPositionVertical::Center".to_string(),
1211 BackgroundPositionVertical::Bottom => "BackgroundPositionVertical::Bottom".to_string(),
1212 BackgroundPositionVertical::Exact(p) => format!(
1213 "BackgroundPositionVertical::Exact({})",
1214 format_pixel_value(p)
1215 ),
1216 }
1217}
1218
1219