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!(StyleTextBoxEdge, Auto, TextEdge, CapHeight, ExHeight);
743impl_enum_fmt!(StyleDominantBaseline, Auto, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, Hanging, TextTop);
744impl_enum_fmt!(StyleAlignmentBaseline, Baseline, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, TextTop);
745impl_enum_fmt!(StyleBaselineSource, Auto, First, Last);
746impl_enum_fmt!(StyleLineFitEdge, Leading, Text, Cap, Ex, Ideographic, IdeographicInk, Alphabetic);
747impl_enum_fmt!(StyleInitialLetterAlign, Auto, Alphabetic, Hanging, Ideographic);
748impl_enum_fmt!(StyleInitialLetterWrap, None, First, All, Grid);
749impl_enum_fmt!(StyleScrollbarGutter, Auto, Stable, StableBothEdges);
750
751impl FormatAsRustCode for StyleOverflowClipMargin {
752 fn format_as_rust_code(&self, tabs: usize) -> String {
753 format!("StyleOverflowClipMargin {{ inner: {} }}", self.inner.format_as_rust_code(tabs))
754 }
755}
756
757impl FormatAsRustCode for StyleClipRect {
758 fn format_as_rust_code(&self, _tabs: usize) -> String {
759 fn fmt_edge(o: OptionF32) -> String {
760 match o {
761 OptionF32::None => String::from("OptionF32::None"),
762 OptionF32::Some(v) => format!("OptionF32::Some({v:?})"),
763 }
764 }
765 format!(
766 "StyleClipRect {{ top: {}, right: {}, bottom: {}, left: {} }}",
767 fmt_edge(self.top),
768 fmt_edge(self.right),
769 fmt_edge(self.bottom),
770 fmt_edge(self.left),
771 )
772 }
773}
774
775fn format_style_background_size(c: &StyleBackgroundSize) -> String {
778 match c {
779 StyleBackgroundSize::Contain => String::from("StyleBackgroundSize::Contain"),
780 StyleBackgroundSize::Cover => String::from("StyleBackgroundSize::Cover"),
781 StyleBackgroundSize::ExactSize(size) => format!(
782 "StyleBackgroundSize::ExactSize(PixelValueSize {{ width: {}, height: {} }})",
783 format_pixel_value(&size.width),
784 format_pixel_value(&size.height)
785 ),
786 }
787}
788
789#[must_use] pub fn format_scrollbar_info(s: &ScrollbarInfo, tabs: usize) -> String {
793 let t = String::from(" ").repeat(tabs);
794 let t1 = String::from(" ").repeat(tabs + 1);
795 format!(
796 "ScrollbarInfo {{\r\n{}width: {},\r\n{}padding_left: {},\r\n{}padding_right: \
797 {},\r\n{}track: {},\r\n{}thumb: {},\r\n{}button: {},\r\n{}button: {},\r\n{}resizer: \
798 {},\r\n{}}}",
799 t1,
800 s.width.format_as_rust_code(tabs + 1),
801 t1,
802 s.padding_left.format_as_rust_code(tabs + 1),
803 t1,
804 s.padding_right.format_as_rust_code(tabs + 1),
805 t1,
806 format_style_background_content(&s.track, tabs + 1),
807 t1,
808 format_style_background_content(&s.thumb, tabs + 1),
809 t1,
810 format_style_background_content(&s.button, tabs + 1),
811 t1,
812 format_style_background_content(&s.corner, tabs + 1),
813 t1,
814 format_style_background_content(&s.resizer, tabs + 1),
815 t
816 )
817}
818
819fn format_style_background_content(content: &StyleBackgroundContent, tabs: usize) -> String {
822 match content {
823 StyleBackgroundContent::LinearGradient(l) => format!(
824 "StyleBackgroundContent::LinearGradient({})",
825 format_linear_gradient(l, tabs)
826 ),
827 StyleBackgroundContent::RadialGradient(r) => format!(
828 "StyleBackgroundContent::RadialGradient({})",
829 format_radial_gradient(r, tabs)
830 ),
831 StyleBackgroundContent::ConicGradient(r) => format!(
832 "StyleBackgroundContent::ConicGradient({})",
833 format_conic_gradient(r, tabs)
834 ),
835 StyleBackgroundContent::Image(id) => format!("StyleBackgroundContent::Image({id:?})"),
836 StyleBackgroundContent::Color(c) => {
837 format!("StyleBackgroundContent::Color({})", format_color_value(c))
838 }
839 StyleBackgroundContent::SystemColor(s) => {
840 use crate::props::basic::color::SystemColorRef;
841 let variant = match s {
842 SystemColorRef::Text => "Text",
843 SystemColorRef::Background => "Background",
844 SystemColorRef::Accent => "Accent",
845 SystemColorRef::AccentText => "AccentText",
846 SystemColorRef::ButtonFace => "ButtonFace",
847 SystemColorRef::ButtonText => "ButtonText",
848 SystemColorRef::WindowBackground => "WindowBackground",
849 SystemColorRef::SelectionBackground => "SelectionBackground",
850 SystemColorRef::SelectionText => "SelectionText",
851 };
852 format!("StyleBackgroundContent::SystemColor(SystemColorRef::{variant})")
853 }
854 }
855}
856
857fn format_direction(d: &Direction, tabs: usize) -> String {
858 match d {
859 Direction::Angle(fv) => format!("Direction::Angle({})", format_angle_value(fv)),
860 Direction::FromTo(DirectionCorners { dir_from, dir_to }) => format!(
861 "Direction::FromTo(DirectionCorners {{ dir_from: {}, dir_to: {} }})",
862 dir_from.format_as_rust_code(tabs + 1),
863 dir_to.format_as_rust_code(tabs + 1)
864 ),
865 }
866}
867
868fn format_linear_gradient(l: &LinearGradient, tabs: usize) -> String {
869 let t = String::from(" ").repeat(tabs);
870 let t1 = String::from(" ").repeat(tabs + 1);
871 format!(
872 "LinearGradient {{\r\n{}direction: {},\r\n{}extend_mode: {},\r\n{}stops: \
873 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
874 t1,
875 format_direction(&l.direction, tabs + 1),
876 t1,
877 l.extend_mode.format_as_rust_code(tabs + 1),
878 t1,
879 l.stops.get_hash(),
880 t,
881 )
882}
883
884fn format_conic_gradient(r: &ConicGradient, tabs: usize) -> String {
885 let t = String::from(" ").repeat(tabs);
886 let t1 = String::from(" ").repeat(tabs + 1);
887
888 format!(
889 "ConicGradient {{\r\n{}extend_mode: {},\r\n{}center: {},\r\n{}angle: {},\r\n{}stops: \
890 NormalizedRadialColorStopVec::from_const_slice(RADIAL_COLOR_STOP_{}_ITEMS),\r\n{}}}",
891 t1,
892 r.extend_mode.format_as_rust_code(tabs + 1),
893 t1,
894 format_style_background_position(&r.center, tabs + 1),
895 t1,
896 format_angle_value(&r.angle),
897 t1,
898 r.stops.get_hash(),
899 t,
900 )
901}
902
903fn format_radial_gradient(r: &RadialGradient, tabs: usize) -> String {
904 let t = String::from(" ").repeat(tabs);
905 let t1 = String::from(" ").repeat(tabs + 1);
906 format!(
907 "RadialGradient {{\r\n{}shape: {},\r\n{}extend_mode: {},\r\n{}position: {},\r\n{}size: \
908 RadialGradientSize::{:?},\r\n{}stops: \
909 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
910 t1,
911 r.shape.format_as_rust_code(tabs + 1),
912 t1,
913 r.extend_mode.format_as_rust_code(tabs + 1),
914 t1,
915 format_style_background_position(&r.position, tabs + 1),
916 t1,
917 r.size,
918 t1,
919 r.stops.get_hash(),
920 t,
921 )
922}
923
924fn format_linear_color_stops(stops: &[NormalizedLinearColorStop], tabs: usize) -> String {
925 let t = String::from(" ").repeat(tabs);
926 stops
927 .iter()
928 .map(format_linear_color_stop)
929 .collect::<Vec<_>>()
930 .join(&format!(",\r\n{t}"))
931}
932
933fn format_linear_color_stop(g: &NormalizedLinearColorStop) -> String {
934 format!(
935 "NormalizedLinearColorStop {{ offset: {}, color: {} }}",
936 format_percentage_value(&g.offset),
937 format_color_or_system(g.color),
938 )
939}
940
941fn format_radial_color_stops(stops: &[NormalizedRadialColorStop], tabs: usize) -> String {
942 let t = String::from(" ").repeat(tabs);
943 stops
944 .iter()
945 .map(format_radial_color_stop)
946 .collect::<Vec<_>>()
947 .join(&format!(",\r\n{t}"))
948}
949
950fn format_radial_color_stop(g: &NormalizedRadialColorStop) -> String {
951 format!(
952 "RadialColorStop {{ angle: {}, color: {} }}",
953 format_angle_value(&g.angle),
954 format_color_or_system(g.color),
955 )
956}
957
958fn format_style_filter(st: &StyleFilter, tabs: usize) -> String {
959 match st {
960 StyleFilter::Blend(mb) => format!("StyleFilter::Blend({})", mb.format_as_rust_code(tabs)),
961 StyleFilter::Flood(c) => format!("StyleFilter::Flood({})", format_color_value(c)),
962 StyleFilter::Blur(m) => format!(
963 "StyleFilter::Blur(StyleBlur {{ width: {}, height: {} }})",
964 format_pixel_value(&m.width),
965 format_pixel_value(&m.height)
966 ),
967 StyleFilter::Opacity(pct) => {
968 format!("StyleFilter::Opacity({})", format_percentage_value(pct))
969 }
970 StyleFilter::ColorMatrix(cm) => format!(
971 "StyleFilter::ColorMatrix(StyleColorMatrix {{ m0: {}, m1: {}, m2: {}, m3: {}, m4: {}, \
972 m5: {}, m6: {}, m7: {}, m8: {}, m9: {}, m10: {}, m11: {}, m12: {}, m13: {}, m14: {}, \
973 m15: {}, m16: {}, m17: {}, m18: {}, m19: {} }})",
974 format_float_value(&cm.m0),
975 format_float_value(&cm.m1),
976 format_float_value(&cm.m2),
977 format_float_value(&cm.m3),
978 format_float_value(&cm.m4),
979 format_float_value(&cm.m5),
980 format_float_value(&cm.m6),
981 format_float_value(&cm.m7),
982 format_float_value(&cm.m8),
983 format_float_value(&cm.m9),
984 format_float_value(&cm.m10),
985 format_float_value(&cm.m11),
986 format_float_value(&cm.m12),
987 format_float_value(&cm.m13),
988 format_float_value(&cm.m14),
989 format_float_value(&cm.m15),
990 format_float_value(&cm.m16),
991 format_float_value(&cm.m17),
992 format_float_value(&cm.m18),
993 format_float_value(&cm.m19)
994 ),
995 StyleFilter::DropShadow(m) => {
996 format!("StyleFilter::DropShadow({})", m.format_as_rust_code(tabs))
997 }
998 StyleFilter::ComponentTransfer => "StyleFilter::ComponentTransfer".to_string(),
999 StyleFilter::Offset(o) => format!(
1000 "StyleFilter::Offset(StyleFilterOffset {{ x: {}, y: {} }})",
1001 format_pixel_value(&o.x),
1002 format_pixel_value(&o.y)
1003 ),
1004 StyleFilter::Composite(StyleCompositeFilter::Over) => {
1005 "StyleFilter::Composite(StyleCompositeFilter::Over)".to_string()
1006 }
1007 StyleFilter::Composite(StyleCompositeFilter::In) => {
1008 "StyleFilter::Composite(StyleCompositeFilter::In)".to_string()
1009 }
1010 StyleFilter::Composite(StyleCompositeFilter::Atop) => {
1011 "StyleFilter::Composite(StyleCompositeFilter::Atop)".to_string()
1012 }
1013 StyleFilter::Composite(StyleCompositeFilter::Out) => {
1014 "StyleFilter::Composite(StyleCompositeFilter::Out)".to_string()
1015 }
1016 StyleFilter::Composite(StyleCompositeFilter::Xor) => {
1017 "StyleFilter::Composite(StyleCompositeFilter::Xor)".to_string()
1018 }
1019 StyleFilter::Composite(StyleCompositeFilter::Lighter) => {
1020 "StyleFilter::Composite(StyleCompositeFilter::Lighter)".to_string()
1021 }
1022 StyleFilter::Composite(StyleCompositeFilter::Arithmetic(fv)) => format!(
1023 "StyleFilter::Composite(StyleCompositeFilter::Arithmetic(ArithmeticCoefficients {{ \
1024 k1: {}, k2: {}, k3: {}, k4: {} }}))",
1025 format_float_value(&fv.k1),
1026 format_float_value(&fv.k2),
1027 format_float_value(&fv.k3),
1028 format_float_value(&fv.k4)
1029 ),
1030 StyleFilter::Brightness(v) => format!("StyleFilter::Brightness({})", format_percentage_value(v)),
1031 StyleFilter::Contrast(v) => format!("StyleFilter::Contrast({})", format_percentage_value(v)),
1032 StyleFilter::Grayscale(v) => format!("StyleFilter::Grayscale({})", format_percentage_value(v)),
1033 StyleFilter::HueRotate(a) => format!("StyleFilter::HueRotate({})", format_angle_value(a)),
1034 StyleFilter::Invert(v) => format!("StyleFilter::Invert({})", format_percentage_value(v)),
1035 StyleFilter::Saturate(v) => format!("StyleFilter::Saturate({})", format_percentage_value(v)),
1036 StyleFilter::Sepia(v) => format!("StyleFilter::Sepia({})", format_percentage_value(v)),
1037 }
1038}
1039
1040fn format_style_transforms(stops: &[StyleTransform], tabs: usize) -> String {
1041 let t = String::from(" ").repeat(tabs);
1042 stops
1043 .iter()
1044 .map(|s| format_style_transform(s, tabs))
1045 .collect::<Vec<_>>()
1046 .join(&format!(",\r\n{t}"))
1047}
1048
1049#[allow(clippy::too_many_lines)] fn format_style_transform(st: &StyleTransform, tabs: usize) -> String {
1051 let tabs_minus_one = String::from(" ").repeat(tabs);
1052 let tabs = String::from(" ").repeat(tabs + 1);
1053 match st {
1054 StyleTransform::Matrix(m) => format!(
1055 "StyleTransform::Matrix(StyleTransformMatrix2D {{ a: {}, b: {}, c: {}, d: {}, tx: {}, \
1056 ty: {} }})",
1057 format_float_value(&m.a),
1058 format_float_value(&m.b),
1059 format_float_value(&m.c),
1060 format_float_value(&m.d),
1061 format_float_value(&m.tx),
1062 format_float_value(&m.ty)
1063 ),
1064 StyleTransform::Matrix3D(m) => format!(
1065 "StyleTransform::Matrix3D(StyleTransformMatrix3D {{\r\n{tabs}m11: {},\r\n{tabs}m12: \
1066 {},\r\n{tabs}m13: {},\r\n{tabs}m14: {},\r\n{tabs}m21: {},\r\n{tabs}m22: \
1067 {},\r\n{tabs}m23: {},\r\n{tabs}m24: {},\r\n{tabs}m31: {},\r\n{tabs}m32: \
1068 {},\r\n{tabs}m33: {},\r\n{tabs}m34: {},\r\n{tabs}m41: {},\r\n{tabs}m42: \
1069 {},\r\n{tabs}m43: {},\r\n{tabs}m44: {}\r\n{tabs_minus_one}}})",
1070 format_float_value(&m.m11),
1071 format_float_value(&m.m12),
1072 format_float_value(&m.m13),
1073 format_float_value(&m.m14),
1074 format_float_value(&m.m21),
1075 format_float_value(&m.m22),
1076 format_float_value(&m.m23),
1077 format_float_value(&m.m24),
1078 format_float_value(&m.m31),
1079 format_float_value(&m.m32),
1080 format_float_value(&m.m33),
1081 format_float_value(&m.m34),
1082 format_float_value(&m.m41),
1083 format_float_value(&m.m42),
1084 format_float_value(&m.m43),
1085 format_float_value(&m.m44),
1086 tabs = tabs,
1087 tabs_minus_one = tabs_minus_one,
1088 ),
1089 StyleTransform::Translate(t) => format!(
1090 "StyleTransform::Translate(StyleTransformTranslate2D {{ x: {}, y: {} }})",
1091 format_pixel_value(&t.x),
1092 format_pixel_value(&t.y)
1093 ),
1094 StyleTransform::Translate3D(t) => format!(
1095 "StyleTransform::Translate3D(StyleTransformTranslate3D {{ x: {}, y: {}, z: {} }})",
1096 format_pixel_value(&t.x),
1097 format_pixel_value(&t.y),
1098 format_pixel_value(&t.z)
1099 ),
1100 StyleTransform::TranslateX(x) => {
1101 format!("StyleTransform::TranslateX({})", format_pixel_value(x))
1102 }
1103 StyleTransform::TranslateY(y) => {
1104 format!("StyleTransform::TranslateY({})", format_pixel_value(y))
1105 }
1106 StyleTransform::TranslateZ(z) => {
1107 format!("StyleTransform::TranslateZ({})", format_pixel_value(z))
1108 }
1109 StyleTransform::Rotate(r) => format!("StyleTransform::Rotate({})", format_angle_value(r)),
1110 StyleTransform::Rotate3D(r) => format!(
1111 "StyleTransform::Rotate3D(StyleTransformRotate3D {{ {}, {}, {}, {} }})",
1112 format_float_value(&r.x),
1113 format_float_value(&r.y),
1114 format_float_value(&r.z),
1115 format_angle_value(&r.angle)
1116 ),
1117 StyleTransform::RotateX(x) => {
1118 format!("StyleTransform::RotateX({})", format_angle_value(x))
1119 }
1120 StyleTransform::RotateY(y) => {
1121 format!("StyleTransform::RotateY({})", format_angle_value(y))
1122 }
1123 StyleTransform::RotateZ(z) => {
1124 format!("StyleTransform::RotateZ({})", format_angle_value(z))
1125 }
1126 StyleTransform::Scale(s) => format!(
1127 "StyleTransform::Scale(StyleTransformScale2D {{ x: {}, y: {} }})",
1128 format_float_value(&s.x),
1129 format_float_value(&s.y)
1130 ),
1131 StyleTransform::Scale3D(s) => format!(
1132 "StyleTransform::Scale3D(StyleTransformScale3D {{ x: {}, y: {}, z: {} }})",
1133 format_float_value(&s.x),
1134 format_float_value(&s.y),
1135 format_float_value(&s.z)
1136 ),
1137 StyleTransform::ScaleX(x) => {
1138 format!("StyleTransform::ScaleX({})", format_percentage_value(x))
1139 }
1140 StyleTransform::ScaleY(y) => {
1141 format!("StyleTransform::ScaleY({})", format_percentage_value(y))
1142 }
1143 StyleTransform::ScaleZ(z) => {
1144 format!("StyleTransform::ScaleZ({})", format_percentage_value(z))
1145 }
1146 StyleTransform::Skew(sk) => format!(
1147 "StyleTransform::Skew(StyleTransformSkew2D {{ x: {}, y: {} }})",
1148 format_angle_value(&sk.x),
1149 format_angle_value(&sk.y)
1150 ),
1151 StyleTransform::SkewX(x) => {
1152 format!("StyleTransform::SkewX({})", format_angle_value(x))
1153 }
1154 StyleTransform::SkewY(y) => {
1155 format!("StyleTransform::SkewY({})", format_angle_value(y))
1156 }
1157 StyleTransform::Perspective(dist) => {
1158 format!("StyleTransform::Perspective({})", format_pixel_value(dist))
1159 }
1160 }
1161}
1162
1163fn format_font_ids(font_ids: &[StyleFontFamily], tabs: usize) -> String {
1164 let t = String::from(" ").repeat(tabs);
1165 font_ids
1166 .iter()
1167 .map(|s| s.format_as_rust_code(tabs + 1))
1168 .collect::<Vec<_>>()
1169 .join(&format!(",\r\n{t}"))
1170}
1171
1172fn format_style_background_position(b: &StyleBackgroundPosition, tabs: usize) -> String {
1173 let t = String::from(" ").repeat(tabs);
1174 let t1 = String::from(" ").repeat(tabs + 1);
1175 format!(
1176 "StyleBackgroundPosition {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1177 t1,
1178 format_background_position_horizontal(&b.horizontal),
1179 t1,
1180 format_background_position_vertical(&b.vertical),
1181 t
1182 )
1183}
1184
1185fn format_background_position_horizontal(b: &BackgroundPositionHorizontal) -> String {
1186 match b {
1187 BackgroundPositionHorizontal::Left => "BackgroundPositionHorizontal::Left".to_string(),
1188 BackgroundPositionHorizontal::Center => "BackgroundPositionHorizontal::Center".to_string(),
1189 BackgroundPositionHorizontal::Right => "BackgroundPositionHorizontal::Right".to_string(),
1190 BackgroundPositionHorizontal::Exact(p) => format!(
1191 "BackgroundPositionHorizontal::Exact({})",
1192 format_pixel_value(p)
1193 ),
1194 }
1195}
1196
1197fn format_background_position_vertical(b: &BackgroundPositionVertical) -> String {
1198 match b {
1199 BackgroundPositionVertical::Top => "BackgroundPositionVertical::Top".to_string(),
1200 BackgroundPositionVertical::Center => "BackgroundPositionVertical::Center".to_string(),
1201 BackgroundPositionVertical::Bottom => "BackgroundPositionVertical::Bottom".to_string(),
1202 BackgroundPositionVertical::Exact(p) => format!(
1203 "BackgroundPositionVertical::Exact({})",
1204 format_pixel_value(p)
1205 ),
1206 }
1207}
1208
1209