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);
565
566impl FormatAsRustCode for StyleObjectPosition {
567 fn format_as_rust_code(&self, _tabs: usize) -> String {
568 format!("StyleObjectPosition {{ horizontal: {}, vertical: {} }}",
569 format_background_position_horizontal(&self.horizontal),
570 format_background_position_vertical(&self.vertical))
571 }
572}
573
574impl FormatAsRustCode for StyleAspectRatio {
575 fn format_as_rust_code(&self, _tabs: usize) -> String {
576 match self {
577 Self::Auto => "StyleAspectRatio::Auto".to_string(),
578 Self::Ratio(r) => format!("StyleAspectRatio::Ratio(AspectRatioValue {{ width: {}, height: {} }})", r.width, r.height),
579 }
580 }
581}
582
583impl_enum_fmt!(StyleTextOrientation, Mixed, Upright, Sideways);
584impl_enum_fmt!(StyleTextAlignLast, Auto, Start, End, Left, Right, Center, Justify);
585
586impl_enum_fmt!(StyleTextTransform, None, Capitalize, Uppercase, Lowercase, FullWidth);
587
588impl_enum_fmt!(StyleDirection, Ltr, Rtl);
589
590impl_enum_fmt!(StyleWhiteSpace, Normal, Pre, Nowrap, PreWrap, PreLine, BreakSpaces);
591
592impl_enum_fmt!(StyleVisibility, Visible, Hidden, Collapse);
593
594impl_enum_fmt!(LayoutWritingMode, HorizontalTb, VerticalRl, VerticalLr);
595
596impl_enum_fmt!(LayoutClear, None, Left, Right, Both);
597
598impl_enum_fmt!(
599 StyleCursor,
600 Alias,
601 AllScroll,
602 Cell,
603 ColResize,
604 ContextMenu,
605 Copy,
606 Crosshair,
607 Default,
608 EResize,
609 EwResize,
610 Grab,
611 Grabbing,
612 Help,
613 Move,
614 NResize,
615 NsResize,
616 NeswResize,
617 NwseResize,
618 Pointer,
619 Progress,
620 RowResize,
621 SResize,
622 SeResize,
623 Text,
624 Unset,
625 VerticalText,
626 WResize,
627 Wait,
628 ZoomIn,
629 ZoomOut
630);
631
632impl_enum_fmt!(
633 BorderStyle,
634 None,
635 Solid,
636 Double,
637 Dotted,
638 Dashed,
639 Hidden,
640 Groove,
641 Ridge,
642 Inset,
643 Outset
644);
645
646impl_enum_fmt!(
647 StyleBackgroundRepeat,
648 NoRepeat,
649 PatternRepeat,
650 RepeatX,
651 RepeatY
652);
653
654impl_enum_fmt!(
655 LayoutDisplay,
656 None,
657 Block,
658 Inline,
659 InlineBlock,
660 Flex,
661 InlineFlex,
662 Table,
663 InlineTable,
664 TableRowGroup,
665 TableHeaderGroup,
666 TableFooterGroup,
667 TableRow,
668 TableColumnGroup,
669 TableColumn,
670 TableCell,
671 TableCaption,
672 ListItem,
673 RunIn,
674 Marker,
675 Grid,
676 InlineGrid,
677 FlowRoot,
678 Contents
679);
680
681impl_enum_fmt!(LayoutFloat, Left, Right, None);
682
683impl_enum_fmt!(LayoutBoxSizing, ContentBox, BorderBox);
684
685impl_enum_fmt!(LayoutFlexDirection, Row, RowReverse, Column, ColumnReverse);
686
687impl_enum_fmt!(LayoutFlexWrap, Wrap, NoWrap, WrapReverse);
688
689impl_enum_fmt!(
690 LayoutJustifyContent,
691 Start,
692 End,
693 FlexStart,
694 FlexEnd,
695 Center,
696 SpaceBetween,
697 SpaceAround,
698 SpaceEvenly
699);
700
701impl_enum_fmt!(LayoutAlignItems, Stretch, Center, Start, End, Baseline);
702
703impl_enum_fmt!(
704 LayoutAlignContent,
705 Start,
706 End,
707 Stretch,
708 Center,
709 SpaceBetween,
710 SpaceAround
711);
712
713impl_enum_fmt!(Shape, Circle, Ellipse);
714
715impl_enum_fmt!(LayoutOverflow, Auto, Scroll, Visible, Hidden, Clip);
716
717impl_enum_fmt!(StyleTextAlign, Center, Left, Right, Justify, Start, End);
718
719impl_enum_fmt!(StyleUserSelect, Auto, Text, None, All);
720
721impl_enum_fmt!(StyleTextDecoration, None, Underline, Overline, LineThrough);
722
723impl_enum_fmt!(
724 DirectionCorner,
725 Right,
726 Left,
727 Top,
728 Bottom,
729 TopRight,
730 TopLeft,
731 BottomRight,
732 BottomLeft
733);
734
735impl_enum_fmt!(ExtendMode, Clamp, Repeat);
736
737impl_enum_fmt!(StyleBackfaceVisibility, Visible, Hidden);
738
739impl_enum_fmt!(StyleUnicodeBidi, Normal, Embed, Isolate, BidiOverride, IsolateOverride, Plaintext);
740impl_enum_fmt!(StyleTextBoxTrim, None, TrimStart, TrimEnd, TrimBoth);
741impl_enum_fmt!(StyleTextBoxEdge, Auto, TextEdge, CapHeight, ExHeight);
742impl_enum_fmt!(StyleDominantBaseline, Auto, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, Hanging, TextTop);
743impl_enum_fmt!(StyleAlignmentBaseline, Baseline, TextBottom, Alphabetic, Ideographic, Middle, Central, Mathematical, TextTop);
744impl_enum_fmt!(StyleInitialLetterAlign, Auto, Alphabetic, Hanging, Ideographic);
745impl_enum_fmt!(StyleInitialLetterWrap, None, First, All, Grid);
746impl_enum_fmt!(StyleScrollbarGutter, Auto, Stable, StableBothEdges);
747
748impl FormatAsRustCode for StyleOverflowClipMargin {
749 fn format_as_rust_code(&self, tabs: usize) -> String {
750 format!("StyleOverflowClipMargin {{ inner: {} }}", self.inner.format_as_rust_code(tabs))
751 }
752}
753
754impl FormatAsRustCode for StyleClipRect {
755 fn format_as_rust_code(&self, _tabs: usize) -> String {
756 fn fmt_edge(o: OptionF32) -> String {
757 match o {
758 OptionF32::None => String::from("OptionF32::None"),
759 OptionF32::Some(v) => format!("OptionF32::Some({v:?})"),
760 }
761 }
762 format!(
763 "StyleClipRect {{ top: {}, right: {}, bottom: {}, left: {} }}",
764 fmt_edge(self.top),
765 fmt_edge(self.right),
766 fmt_edge(self.bottom),
767 fmt_edge(self.left),
768 )
769 }
770}
771
772fn format_style_background_size(c: &StyleBackgroundSize) -> String {
775 match c {
776 StyleBackgroundSize::Contain => String::from("StyleBackgroundSize::Contain"),
777 StyleBackgroundSize::Cover => String::from("StyleBackgroundSize::Cover"),
778 StyleBackgroundSize::ExactSize(size) => format!(
779 "StyleBackgroundSize::ExactSize(PixelValueSize {{ width: {}, height: {} }})",
780 format_pixel_value(&size.width),
781 format_pixel_value(&size.height)
782 ),
783 }
784}
785
786#[must_use] pub fn format_scrollbar_info(s: &ScrollbarInfo, tabs: usize) -> String {
790 let t = String::from(" ").repeat(tabs);
791 let t1 = String::from(" ").repeat(tabs + 1);
792 format!(
793 "ScrollbarInfo {{\r\n{}width: {},\r\n{}padding_left: {},\r\n{}padding_right: \
794 {},\r\n{}track: {},\r\n{}thumb: {},\r\n{}button: {},\r\n{}button: {},\r\n{}resizer: \
795 {},\r\n{}}}",
796 t1,
797 s.width.format_as_rust_code(tabs + 1),
798 t1,
799 s.padding_left.format_as_rust_code(tabs + 1),
800 t1,
801 s.padding_right.format_as_rust_code(tabs + 1),
802 t1,
803 format_style_background_content(&s.track, tabs + 1),
804 t1,
805 format_style_background_content(&s.thumb, tabs + 1),
806 t1,
807 format_style_background_content(&s.button, tabs + 1),
808 t1,
809 format_style_background_content(&s.corner, tabs + 1),
810 t1,
811 format_style_background_content(&s.resizer, tabs + 1),
812 t
813 )
814}
815
816fn format_style_background_content(content: &StyleBackgroundContent, tabs: usize) -> String {
819 match content {
820 StyleBackgroundContent::LinearGradient(l) => format!(
821 "StyleBackgroundContent::LinearGradient({})",
822 format_linear_gradient(l, tabs)
823 ),
824 StyleBackgroundContent::RadialGradient(r) => format!(
825 "StyleBackgroundContent::RadialGradient({})",
826 format_radial_gradient(r, tabs)
827 ),
828 StyleBackgroundContent::ConicGradient(r) => format!(
829 "StyleBackgroundContent::ConicGradient({})",
830 format_conic_gradient(r, tabs)
831 ),
832 StyleBackgroundContent::Image(id) => format!("StyleBackgroundContent::Image({id:?})"),
833 StyleBackgroundContent::Color(c) => {
834 format!("StyleBackgroundContent::Color({})", format_color_value(c))
835 }
836 StyleBackgroundContent::SystemColor(s) => {
837 use crate::props::basic::color::SystemColorRef;
838 let variant = match s {
839 SystemColorRef::Text => "Text",
840 SystemColorRef::Background => "Background",
841 SystemColorRef::Accent => "Accent",
842 SystemColorRef::AccentText => "AccentText",
843 SystemColorRef::ButtonFace => "ButtonFace",
844 SystemColorRef::ButtonText => "ButtonText",
845 SystemColorRef::WindowBackground => "WindowBackground",
846 SystemColorRef::SelectionBackground => "SelectionBackground",
847 SystemColorRef::SelectionText => "SelectionText",
848 };
849 format!("StyleBackgroundContent::SystemColor(SystemColorRef::{variant})")
850 }
851 }
852}
853
854fn format_direction(d: &Direction, tabs: usize) -> String {
855 match d {
856 Direction::Angle(fv) => format!("Direction::Angle({})", format_angle_value(fv)),
857 Direction::FromTo(DirectionCorners { dir_from, dir_to }) => format!(
858 "Direction::FromTo(DirectionCorners {{ dir_from: {}, dir_to: {} }})",
859 dir_from.format_as_rust_code(tabs + 1),
860 dir_to.format_as_rust_code(tabs + 1)
861 ),
862 }
863}
864
865fn format_linear_gradient(l: &LinearGradient, tabs: usize) -> String {
866 let t = String::from(" ").repeat(tabs);
867 let t1 = String::from(" ").repeat(tabs + 1);
868 format!(
869 "LinearGradient {{\r\n{}direction: {},\r\n{}extend_mode: {},\r\n{}stops: \
870 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
871 t1,
872 format_direction(&l.direction, tabs + 1),
873 t1,
874 l.extend_mode.format_as_rust_code(tabs + 1),
875 t1,
876 l.stops.get_hash(),
877 t,
878 )
879}
880
881fn format_conic_gradient(r: &ConicGradient, tabs: usize) -> String {
882 let t = String::from(" ").repeat(tabs);
883 let t1 = String::from(" ").repeat(tabs + 1);
884
885 format!(
886 "ConicGradient {{\r\n{}extend_mode: {},\r\n{}center: {},\r\n{}angle: {},\r\n{}stops: \
887 NormalizedRadialColorStopVec::from_const_slice(RADIAL_COLOR_STOP_{}_ITEMS),\r\n{}}}",
888 t1,
889 r.extend_mode.format_as_rust_code(tabs + 1),
890 t1,
891 format_style_background_position(&r.center, tabs + 1),
892 t1,
893 format_angle_value(&r.angle),
894 t1,
895 r.stops.get_hash(),
896 t,
897 )
898}
899
900fn format_radial_gradient(r: &RadialGradient, tabs: usize) -> String {
901 let t = String::from(" ").repeat(tabs);
902 let t1 = String::from(" ").repeat(tabs + 1);
903 format!(
904 "RadialGradient {{\r\n{}shape: {},\r\n{}extend_mode: {},\r\n{}position: {},\r\n{}size: \
905 RadialGradientSize::{:?},\r\n{}stops: \
906 NormalizedLinearColorStopVec::from_const_slice(LINEAR_COLOR_STOP_{}_ITEMS),\r\n{}}}",
907 t1,
908 r.shape.format_as_rust_code(tabs + 1),
909 t1,
910 r.extend_mode.format_as_rust_code(tabs + 1),
911 t1,
912 format_style_background_position(&r.position, tabs + 1),
913 t1,
914 r.size,
915 t1,
916 r.stops.get_hash(),
917 t,
918 )
919}
920
921fn format_linear_color_stops(stops: &[NormalizedLinearColorStop], tabs: usize) -> String {
922 let t = String::from(" ").repeat(tabs);
923 stops
924 .iter()
925 .map(format_linear_color_stop)
926 .collect::<Vec<_>>()
927 .join(&format!(",\r\n{t}"))
928}
929
930fn format_linear_color_stop(g: &NormalizedLinearColorStop) -> String {
931 format!(
932 "NormalizedLinearColorStop {{ offset: {}, color: {} }}",
933 format_percentage_value(&g.offset),
934 format_color_or_system(g.color),
935 )
936}
937
938fn format_radial_color_stops(stops: &[NormalizedRadialColorStop], tabs: usize) -> String {
939 let t = String::from(" ").repeat(tabs);
940 stops
941 .iter()
942 .map(format_radial_color_stop)
943 .collect::<Vec<_>>()
944 .join(&format!(",\r\n{t}"))
945}
946
947fn format_radial_color_stop(g: &NormalizedRadialColorStop) -> String {
948 format!(
949 "RadialColorStop {{ angle: {}, color: {} }}",
950 format_angle_value(&g.angle),
951 format_color_or_system(g.color),
952 )
953}
954
955fn format_style_filter(st: &StyleFilter, tabs: usize) -> String {
956 match st {
957 StyleFilter::Blend(mb) => format!("StyleFilter::Blend({})", mb.format_as_rust_code(tabs)),
958 StyleFilter::Flood(c) => format!("StyleFilter::Flood({})", format_color_value(c)),
959 StyleFilter::Blur(m) => format!(
960 "StyleFilter::Blur(StyleBlur {{ width: {}, height: {} }})",
961 format_pixel_value(&m.width),
962 format_pixel_value(&m.height)
963 ),
964 StyleFilter::Opacity(pct) => {
965 format!("StyleFilter::Opacity({})", format_percentage_value(pct))
966 }
967 StyleFilter::ColorMatrix(cm) => format!(
968 "StyleFilter::ColorMatrix(StyleColorMatrix {{ m0: {}, m1: {}, m2: {}, m3: {}, m4: {}, \
969 m5: {}, m6: {}, m7: {}, m8: {}, m9: {}, m10: {}, m11: {}, m12: {}, m13: {}, m14: {}, \
970 m15: {}, m16: {}, m17: {}, m18: {}, m19: {} }})",
971 format_float_value(&cm.m0),
972 format_float_value(&cm.m1),
973 format_float_value(&cm.m2),
974 format_float_value(&cm.m3),
975 format_float_value(&cm.m4),
976 format_float_value(&cm.m5),
977 format_float_value(&cm.m6),
978 format_float_value(&cm.m7),
979 format_float_value(&cm.m8),
980 format_float_value(&cm.m9),
981 format_float_value(&cm.m10),
982 format_float_value(&cm.m11),
983 format_float_value(&cm.m12),
984 format_float_value(&cm.m13),
985 format_float_value(&cm.m14),
986 format_float_value(&cm.m15),
987 format_float_value(&cm.m16),
988 format_float_value(&cm.m17),
989 format_float_value(&cm.m18),
990 format_float_value(&cm.m19)
991 ),
992 StyleFilter::DropShadow(m) => {
993 format!("StyleFilter::DropShadow({})", m.format_as_rust_code(tabs))
994 }
995 StyleFilter::ComponentTransfer => "StyleFilter::ComponentTransfer".to_string(),
996 StyleFilter::Offset(o) => format!(
997 "StyleFilter::Offset(StyleFilterOffset {{ x: {}, y: {} }})",
998 format_pixel_value(&o.x),
999 format_pixel_value(&o.y)
1000 ),
1001 StyleFilter::Composite(StyleCompositeFilter::Over) => {
1002 "StyleFilter::Composite(StyleCompositeFilter::Over)".to_string()
1003 }
1004 StyleFilter::Composite(StyleCompositeFilter::In) => {
1005 "StyleFilter::Composite(StyleCompositeFilter::In)".to_string()
1006 }
1007 StyleFilter::Composite(StyleCompositeFilter::Atop) => {
1008 "StyleFilter::Composite(StyleCompositeFilter::Atop)".to_string()
1009 }
1010 StyleFilter::Composite(StyleCompositeFilter::Out) => {
1011 "StyleFilter::Composite(StyleCompositeFilter::Out)".to_string()
1012 }
1013 StyleFilter::Composite(StyleCompositeFilter::Xor) => {
1014 "StyleFilter::Composite(StyleCompositeFilter::Xor)".to_string()
1015 }
1016 StyleFilter::Composite(StyleCompositeFilter::Lighter) => {
1017 "StyleFilter::Composite(StyleCompositeFilter::Lighter)".to_string()
1018 }
1019 StyleFilter::Composite(StyleCompositeFilter::Arithmetic(fv)) => format!(
1020 "StyleFilter::Composite(StyleCompositeFilter::Arithmetic(ArithmeticCoefficients {{ \
1021 k1: {}, k2: {}, k3: {}, k4: {} }}))",
1022 format_float_value(&fv.k1),
1023 format_float_value(&fv.k2),
1024 format_float_value(&fv.k3),
1025 format_float_value(&fv.k4)
1026 ),
1027 StyleFilter::Brightness(v) => format!("StyleFilter::Brightness({})", format_percentage_value(v)),
1028 StyleFilter::Contrast(v) => format!("StyleFilter::Contrast({})", format_percentage_value(v)),
1029 StyleFilter::Grayscale(v) => format!("StyleFilter::Grayscale({})", format_percentage_value(v)),
1030 StyleFilter::HueRotate(a) => format!("StyleFilter::HueRotate({})", format_angle_value(a)),
1031 StyleFilter::Invert(v) => format!("StyleFilter::Invert({})", format_percentage_value(v)),
1032 StyleFilter::Saturate(v) => format!("StyleFilter::Saturate({})", format_percentage_value(v)),
1033 StyleFilter::Sepia(v) => format!("StyleFilter::Sepia({})", format_percentage_value(v)),
1034 }
1035}
1036
1037fn format_style_transforms(stops: &[StyleTransform], tabs: usize) -> String {
1038 let t = String::from(" ").repeat(tabs);
1039 stops
1040 .iter()
1041 .map(|s| format_style_transform(s, tabs))
1042 .collect::<Vec<_>>()
1043 .join(&format!(",\r\n{t}"))
1044}
1045
1046#[allow(clippy::too_many_lines)] fn format_style_transform(st: &StyleTransform, tabs: usize) -> String {
1048 let tabs_minus_one = String::from(" ").repeat(tabs);
1049 let tabs = String::from(" ").repeat(tabs + 1);
1050 match st {
1051 StyleTransform::Matrix(m) => format!(
1052 "StyleTransform::Matrix(StyleTransformMatrix2D {{ a: {}, b: {}, c: {}, d: {}, tx: {}, \
1053 ty: {} }})",
1054 format_float_value(&m.a),
1055 format_float_value(&m.b),
1056 format_float_value(&m.c),
1057 format_float_value(&m.d),
1058 format_float_value(&m.tx),
1059 format_float_value(&m.ty)
1060 ),
1061 StyleTransform::Matrix3D(m) => format!(
1062 "StyleTransform::Matrix3D(StyleTransformMatrix3D {{\r\n{tabs}m11: {},\r\n{tabs}m12: \
1063 {},\r\n{tabs}m13: {},\r\n{tabs}m14: {},\r\n{tabs}m21: {},\r\n{tabs}m22: \
1064 {},\r\n{tabs}m23: {},\r\n{tabs}m24: {},\r\n{tabs}m31: {},\r\n{tabs}m32: \
1065 {},\r\n{tabs}m33: {},\r\n{tabs}m34: {},\r\n{tabs}m41: {},\r\n{tabs}m42: \
1066 {},\r\n{tabs}m43: {},\r\n{tabs}m44: {}\r\n{tabs_minus_one}}})",
1067 format_float_value(&m.m11),
1068 format_float_value(&m.m12),
1069 format_float_value(&m.m13),
1070 format_float_value(&m.m14),
1071 format_float_value(&m.m21),
1072 format_float_value(&m.m22),
1073 format_float_value(&m.m23),
1074 format_float_value(&m.m24),
1075 format_float_value(&m.m31),
1076 format_float_value(&m.m32),
1077 format_float_value(&m.m33),
1078 format_float_value(&m.m34),
1079 format_float_value(&m.m41),
1080 format_float_value(&m.m42),
1081 format_float_value(&m.m43),
1082 format_float_value(&m.m44),
1083 tabs = tabs,
1084 tabs_minus_one = tabs_minus_one,
1085 ),
1086 StyleTransform::Translate(t) => format!(
1087 "StyleTransform::Translate(StyleTransformTranslate2D {{ x: {}, y: {} }})",
1088 format_pixel_value(&t.x),
1089 format_pixel_value(&t.y)
1090 ),
1091 StyleTransform::Translate3D(t) => format!(
1092 "StyleTransform::Translate3D(StyleTransformTranslate3D {{ x: {}, y: {}, z: {} }})",
1093 format_pixel_value(&t.x),
1094 format_pixel_value(&t.y),
1095 format_pixel_value(&t.z)
1096 ),
1097 StyleTransform::TranslateX(x) => {
1098 format!("StyleTransform::TranslateX({})", format_pixel_value(x))
1099 }
1100 StyleTransform::TranslateY(y) => {
1101 format!("StyleTransform::TranslateY({})", format_pixel_value(y))
1102 }
1103 StyleTransform::TranslateZ(z) => {
1104 format!("StyleTransform::TranslateZ({})", format_pixel_value(z))
1105 }
1106 StyleTransform::Rotate(r) => format!("StyleTransform::Rotate({})", format_angle_value(r)),
1107 StyleTransform::Rotate3D(r) => format!(
1108 "StyleTransform::Rotate3D(StyleTransformRotate3D {{ {}, {}, {}, {} }})",
1109 format_float_value(&r.x),
1110 format_float_value(&r.y),
1111 format_float_value(&r.z),
1112 format_angle_value(&r.angle)
1113 ),
1114 StyleTransform::RotateX(x) => {
1115 format!("StyleTransform::RotateX({})", format_angle_value(x))
1116 }
1117 StyleTransform::RotateY(y) => {
1118 format!("StyleTransform::RotateY({})", format_angle_value(y))
1119 }
1120 StyleTransform::RotateZ(z) => {
1121 format!("StyleTransform::RotateZ({})", format_angle_value(z))
1122 }
1123 StyleTransform::Scale(s) => format!(
1124 "StyleTransform::Scale(StyleTransformScale2D {{ x: {}, y: {} }})",
1125 format_float_value(&s.x),
1126 format_float_value(&s.y)
1127 ),
1128 StyleTransform::Scale3D(s) => format!(
1129 "StyleTransform::Scale3D(StyleTransformScale3D {{ x: {}, y: {}, z: {} }})",
1130 format_float_value(&s.x),
1131 format_float_value(&s.y),
1132 format_float_value(&s.z)
1133 ),
1134 StyleTransform::ScaleX(x) => {
1135 format!("StyleTransform::ScaleX({})", format_percentage_value(x))
1136 }
1137 StyleTransform::ScaleY(y) => {
1138 format!("StyleTransform::ScaleY({})", format_percentage_value(y))
1139 }
1140 StyleTransform::ScaleZ(z) => {
1141 format!("StyleTransform::ScaleZ({})", format_percentage_value(z))
1142 }
1143 StyleTransform::Skew(sk) => format!(
1144 "StyleTransform::Skew(StyleTransformSkew2D {{ x: {}, y: {} }})",
1145 format_angle_value(&sk.x),
1146 format_angle_value(&sk.y)
1147 ),
1148 StyleTransform::SkewX(x) => {
1149 format!("StyleTransform::SkewX({})", format_angle_value(x))
1150 }
1151 StyleTransform::SkewY(y) => {
1152 format!("StyleTransform::SkewY({})", format_angle_value(y))
1153 }
1154 StyleTransform::Perspective(dist) => {
1155 format!("StyleTransform::Perspective({})", format_pixel_value(dist))
1156 }
1157 }
1158}
1159
1160fn format_font_ids(font_ids: &[StyleFontFamily], tabs: usize) -> String {
1161 let t = String::from(" ").repeat(tabs);
1162 font_ids
1163 .iter()
1164 .map(|s| s.format_as_rust_code(tabs + 1))
1165 .collect::<Vec<_>>()
1166 .join(&format!(",\r\n{t}"))
1167}
1168
1169fn format_style_background_position(b: &StyleBackgroundPosition, tabs: usize) -> String {
1170 let t = String::from(" ").repeat(tabs);
1171 let t1 = String::from(" ").repeat(tabs + 1);
1172 format!(
1173 "StyleBackgroundPosition {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
1174 t1,
1175 format_background_position_horizontal(&b.horizontal),
1176 t1,
1177 format_background_position_vertical(&b.vertical),
1178 t
1179 )
1180}
1181
1182fn format_background_position_horizontal(b: &BackgroundPositionHorizontal) -> String {
1183 match b {
1184 BackgroundPositionHorizontal::Left => "BackgroundPositionHorizontal::Left".to_string(),
1185 BackgroundPositionHorizontal::Center => "BackgroundPositionHorizontal::Center".to_string(),
1186 BackgroundPositionHorizontal::Right => "BackgroundPositionHorizontal::Right".to_string(),
1187 BackgroundPositionHorizontal::Exact(p) => format!(
1188 "BackgroundPositionHorizontal::Exact({})",
1189 format_pixel_value(p)
1190 ),
1191 }
1192}
1193
1194fn format_background_position_vertical(b: &BackgroundPositionVertical) -> String {
1195 match b {
1196 BackgroundPositionVertical::Top => "BackgroundPositionVertical::Top".to_string(),
1197 BackgroundPositionVertical::Center => "BackgroundPositionVertical::Center".to_string(),
1198 BackgroundPositionVertical::Bottom => "BackgroundPositionVertical::Bottom".to_string(),
1199 BackgroundPositionVertical::Exact(p) => format!(
1200 "BackgroundPositionVertical::Exact({})",
1201 format_pixel_value(p)
1202 ),
1203 }
1204}
1205
1206