1use alloc::string::{String, ToString};
4use crate::corety::AzString;
5
6use crate::props::{
7 basic::{
8 color::{parse_css_color, ColorU, CssColorParseError, CssColorParseErrorOwned},
9 },
10 formatter::PrintAsCssValue,
11 layout::{
12 dimensions::LayoutWidth,
13 spacing::{LayoutPaddingLeft, LayoutPaddingRight},
14 },
15 style::background::StyleBackgroundContent,
16};
17
18#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
25#[repr(C)]
26pub enum ScrollBehavior {
27 #[default]
29 Auto,
30 Smooth,
32}
33
34impl PrintAsCssValue for ScrollBehavior {
35 fn print_as_css_value(&self) -> String {
36 match self {
37 Self::Auto => "auto".to_string(),
38 Self::Smooth => "smooth".to_string(),
39 }
40 }
41}
42
43#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
46#[repr(C)]
47pub enum OverscrollBehavior {
48 #[default]
50 Auto,
51 Contain,
53 None,
55}
56
57impl PrintAsCssValue for OverscrollBehavior {
58 fn print_as_css_value(&self) -> String {
59 match self {
60 Self::Auto => "auto".to_string(),
61 Self::Contain => "contain".to_string(),
62 Self::None => "none".to_string(),
63 }
64 }
65}
66
67#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
76#[repr(C)]
77pub struct ScrollPhysics {
78 pub smooth_scroll_duration_ms: u32,
81
82 pub deceleration_rate: f32,
86
87 pub min_velocity_threshold: f32,
90
91 pub max_velocity: f32,
93
94 pub wheel_multiplier: f32,
97
98 pub invert_direction: bool,
100
101 pub overscroll_elasticity: f32,
104
105 pub max_overscroll_distance: f32,
108
109 pub bounce_back_duration_ms: u32,
112
113 pub timer_interval_ms: u32,
117}
118
119impl Default for ScrollPhysics {
120 fn default() -> Self {
121 Self {
122 smooth_scroll_duration_ms: 300,
123 deceleration_rate: 0.95,
124 min_velocity_threshold: 50.0,
125 max_velocity: 8000.0,
126 wheel_multiplier: 1.0,
127 invert_direction: false,
128 overscroll_elasticity: 0.0, max_overscroll_distance: 100.0,
130 bounce_back_duration_ms: 400,
131 timer_interval_ms: 16,
132 }
133 }
134}
135
136impl ScrollPhysics {
137 #[must_use] pub const fn ios() -> Self {
139 Self {
140 smooth_scroll_duration_ms: 300,
141 deceleration_rate: 0.998,
142 min_velocity_threshold: 20.0,
143 max_velocity: 8000.0,
144 wheel_multiplier: 1.0,
145 invert_direction: true, overscroll_elasticity: 0.5,
147 max_overscroll_distance: 120.0,
148 bounce_back_duration_ms: 500,
149 timer_interval_ms: 16,
150 }
151 }
152
153 #[must_use] pub const fn macos() -> Self {
155 Self {
156 smooth_scroll_duration_ms: 250,
157 deceleration_rate: 0.997,
158 min_velocity_threshold: 30.0,
159 max_velocity: 6000.0,
160 wheel_multiplier: 1.0,
161 invert_direction: true, overscroll_elasticity: 0.3,
163 max_overscroll_distance: 80.0,
164 bounce_back_duration_ms: 400,
165 timer_interval_ms: 16,
166 }
167 }
168
169 #[must_use] pub const fn windows() -> Self {
171 Self {
172 smooth_scroll_duration_ms: 200,
173 deceleration_rate: 0.9,
174 min_velocity_threshold: 100.0,
175 max_velocity: 4000.0,
176 wheel_multiplier: 1.0,
177 invert_direction: false,
178 overscroll_elasticity: 0.0,
179 max_overscroll_distance: 0.0,
180 bounce_back_duration_ms: 200,
181 timer_interval_ms: 16,
182 }
183 }
184
185 #[must_use] pub const fn android() -> Self {
187 Self {
188 smooth_scroll_duration_ms: 250,
189 deceleration_rate: 0.996,
190 min_velocity_threshold: 40.0,
191 max_velocity: 8000.0,
192 wheel_multiplier: 1.0,
193 invert_direction: false,
194 overscroll_elasticity: 0.2, max_overscroll_distance: 60.0,
196 bounce_back_duration_ms: 300,
197 timer_interval_ms: 16,
198 }
199 }
200}
201
202#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
220#[repr(C)]
221pub enum ScrollbarVisibilityMode {
222 #[default]
225 Always,
226 WhenScrolling,
229 Auto,
231}
232
233impl PrintAsCssValue for ScrollbarVisibilityMode {
234 fn print_as_css_value(&self) -> String {
235 match self {
236 Self::Always => "always".to_string(),
237 Self::WhenScrolling => "when-scrolling".to_string(),
238 Self::Auto => "auto".to_string(),
239 }
240 }
241}
242
243#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
254#[repr(C)]
255pub struct ScrollbarFadeDelay {
256 pub ms: u32,
258}
259
260impl ScrollbarFadeDelay {
261 #[must_use] pub const fn new(ms: u32) -> Self { Self { ms } }
262 pub const ZERO: Self = Self { ms: 0 };
263}
264
265impl PrintAsCssValue for ScrollbarFadeDelay {
266 fn print_as_css_value(&self) -> String {
267 if self.ms == 0 { "0".to_string() } else { format!("{}ms", self.ms) }
268 }
269}
270
271#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
282#[repr(C)]
283pub struct ScrollbarFadeDuration {
284 pub ms: u32,
286}
287
288impl ScrollbarFadeDuration {
289 #[must_use] pub const fn new(ms: u32) -> Self { Self { ms } }
290 pub const ZERO: Self = Self { ms: 0 };
291}
292
293impl PrintAsCssValue for ScrollbarFadeDuration {
294 fn print_as_css_value(&self) -> String {
295 if self.ms == 0 { "0".to_string() } else { format!("{}ms", self.ms) }
296 }
297}
298
299#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
313#[repr(C)]
314pub enum OverflowScrolling {
315 #[default]
317 Auto,
318 Touch,
320}
321
322impl PrintAsCssValue for OverflowScrolling {
323 fn print_as_css_value(&self) -> String {
324 match self {
325 Self::Auto => "auto".to_string(),
326 Self::Touch => "touch".to_string(),
327 }
328 }
329}
330
331#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
337#[repr(C)]
338#[derive(Default)]
339pub enum LayoutScrollbarWidth {
340 #[default]
341 Auto,
342 Thin,
343 None,
344}
345
346
347impl PrintAsCssValue for LayoutScrollbarWidth {
348 fn print_as_css_value(&self) -> String {
349 match self {
350 Self::Auto => "auto".to_string(),
351 Self::Thin => "thin".to_string(),
352 Self::None => "none".to_string(),
353 }
354 }
355}
356
357#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
359#[repr(C)]
360pub struct ScrollbarColorCustom {
361 pub thumb: ColorU,
362 pub track: ColorU,
363}
364
365#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
367#[repr(C, u8)]
368#[derive(Default)]
369pub enum StyleScrollbarColor {
370 #[default]
371 Auto,
372 Custom(ScrollbarColorCustom),
373}
374
375
376impl PrintAsCssValue for StyleScrollbarColor {
377 fn print_as_css_value(&self) -> String {
378 match self {
379 Self::Auto => "auto".to_string(),
380 Self::Custom(c) => format!("{} {}", c.thumb.to_hash(), c.track.to_hash()),
381 }
382 }
383}
384
385#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
389#[repr(C)]
390pub struct ScrollbarInfo {
391 pub width: LayoutWidth,
393 pub padding_left: LayoutPaddingLeft,
396 pub padding_right: LayoutPaddingRight,
398 pub track: StyleBackgroundContent,
402 pub thumb: StyleBackgroundContent,
404 pub button: StyleBackgroundContent,
406 pub corner: StyleBackgroundContent,
409 pub resizer: StyleBackgroundContent,
412 pub clip_to_container_border: bool,
417 pub scroll_behavior: ScrollBehavior,
419 pub overscroll_behavior_x: OverscrollBehavior,
421 pub overscroll_behavior_y: OverscrollBehavior,
423 pub overflow_scrolling: OverflowScrolling,
426}
427
428impl Default for ScrollbarInfo {
429 fn default() -> Self {
430 SCROLLBAR_CLASSIC_LIGHT
431 }
432}
433
434impl PrintAsCssValue for ScrollbarInfo {
435 fn print_as_css_value(&self) -> String {
436 format!(
438 "width: {}; padding-left: {}; padding-right: {}; track: {}; thumb: {}; button: {}; \
439 corner: {}; resizer: {}",
440 self.width.print_as_css_value(),
441 self.padding_left.print_as_css_value(),
442 self.padding_right.print_as_css_value(),
443 self.track.print_as_css_value(),
444 self.thumb.print_as_css_value(),
445 self.button.print_as_css_value(),
446 self.corner.print_as_css_value(),
447 self.resizer.print_as_css_value(),
448 )
449 }
450}
451
452#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
454#[repr(C)]
455pub struct ScrollbarStyle {
456 pub horizontal: ScrollbarInfo,
458 pub vertical: ScrollbarInfo,
460}
461
462impl PrintAsCssValue for ScrollbarStyle {
463 fn print_as_css_value(&self) -> String {
464 format!(
466 "horz({}), vert({})",
467 self.horizontal.print_as_css_value(),
468 self.vertical.print_as_css_value()
469 )
470 }
471}
472
473impl crate::codegen::format::FormatAsRustCode for ScrollbarStyle {
475 fn format_as_rust_code(&self, tabs: usize) -> String {
476 let t = String::from(" ").repeat(tabs);
477 let t1 = String::from(" ").repeat(tabs + 1);
478 format!(
479 "ScrollbarStyle {{\r\n{}horizontal: {},\r\n{}vertical: {},\r\n{}}}",
480 t1,
481 crate::codegen::format::format_scrollbar_info(&self.horizontal, tabs + 1),
482 t1,
483 crate::codegen::format::format_scrollbar_info(&self.vertical, tabs + 1),
484 t,
485 )
486 }
487}
488
489impl crate::codegen::format::FormatAsRustCode for LayoutScrollbarWidth {
490 fn format_as_rust_code(&self, _tabs: usize) -> String {
491 match self {
492 Self::Auto => String::from("LayoutScrollbarWidth::Auto"),
493 Self::Thin => String::from("LayoutScrollbarWidth::Thin"),
494 Self::None => String::from("LayoutScrollbarWidth::None"),
495 }
496 }
497}
498
499impl crate::codegen::format::FormatAsRustCode for StyleScrollbarColor {
500 fn format_as_rust_code(&self, _tabs: usize) -> String {
501 match self {
502 Self::Auto => String::from("StyleScrollbarColor::Auto"),
503 Self::Custom(c) => format!(
504 "StyleScrollbarColor::Custom(ScrollbarColorCustom {{ thumb: {}, track: {} }})",
505 crate::codegen::format::format_color_value(&c.thumb),
506 crate::codegen::format::format_color_value(&c.track)
507 ),
508 }
509 }
510}
511
512impl crate::codegen::format::FormatAsRustCode for ScrollbarVisibilityMode {
513 fn format_as_rust_code(&self, _tabs: usize) -> String {
514 match self {
515 Self::Always => String::from("ScrollbarVisibilityMode::Always"),
516 Self::WhenScrolling => String::from("ScrollbarVisibilityMode::WhenScrolling"),
517 Self::Auto => String::from("ScrollbarVisibilityMode::Auto"),
518 }
519 }
520}
521
522impl crate::codegen::format::FormatAsRustCode for ScrollbarFadeDelay {
523 fn format_as_rust_code(&self, _tabs: usize) -> String {
524 format!("ScrollbarFadeDelay::new({})", self.ms)
525 }
526}
527
528impl crate::codegen::format::FormatAsRustCode for ScrollbarFadeDuration {
529 fn format_as_rust_code(&self, _tabs: usize) -> String {
530 format!("ScrollbarFadeDuration::new({})", self.ms)
531 }
532}
533
534#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct ComputedScrollbarStyle {
540 pub width: Option<LayoutWidth>,
542 pub thumb_color: Option<ColorU>,
544 pub track_color: Option<ColorU>,
546}
547
548impl Default for ComputedScrollbarStyle {
549 fn default() -> Self {
550 let default_info = ScrollbarInfo::default();
551 Self {
552 width: Some(default_info.width), thumb_color: match default_info.thumb {
554 StyleBackgroundContent::Color(c) => Some(c),
555 _ => None,
556 },
557 track_color: match default_info.track {
558 StyleBackgroundContent::Color(c) => Some(c),
559 _ => None,
560 },
561 }
562 }
563}
564
565pub const SCROLLBAR_CLASSIC_LIGHT: ScrollbarInfo = ScrollbarInfo {
569 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(17)),
570 padding_left: LayoutPaddingLeft {
571 inner: crate::props::basic::pixel::PixelValue::const_px(2),
572 },
573 padding_right: LayoutPaddingRight {
574 inner: crate::props::basic::pixel::PixelValue::const_px(2),
575 },
576 track: StyleBackgroundContent::Color(ColorU {
577 r: 241,
578 g: 241,
579 b: 241,
580 a: 255,
581 }),
582 thumb: StyleBackgroundContent::Color(ColorU {
583 r: 193,
584 g: 193,
585 b: 193,
586 a: 255,
587 }),
588 button: StyleBackgroundContent::Color(ColorU {
589 r: 163,
590 g: 163,
591 b: 163,
592 a: 255,
593 }),
594 corner: StyleBackgroundContent::Color(ColorU {
595 r: 241,
596 g: 241,
597 b: 241,
598 a: 255,
599 }),
600 resizer: StyleBackgroundContent::Color(ColorU {
601 r: 241,
602 g: 241,
603 b: 241,
604 a: 255,
605 }),
606 clip_to_container_border: false,
607 scroll_behavior: ScrollBehavior::Auto,
608 overscroll_behavior_x: OverscrollBehavior::Auto,
609 overscroll_behavior_y: OverscrollBehavior::Auto,
610 overflow_scrolling: OverflowScrolling::Auto,
611};
612
613pub const SCROLLBAR_CLASSIC_DARK: ScrollbarInfo = ScrollbarInfo {
615 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(17)),
616 padding_left: LayoutPaddingLeft {
617 inner: crate::props::basic::pixel::PixelValue::const_px(2),
618 },
619 padding_right: LayoutPaddingRight {
620 inner: crate::props::basic::pixel::PixelValue::const_px(2),
621 },
622 track: StyleBackgroundContent::Color(ColorU {
623 r: 45,
624 g: 45,
625 b: 45,
626 a: 255,
627 }),
628 thumb: StyleBackgroundContent::Color(ColorU {
629 r: 100,
630 g: 100,
631 b: 100,
632 a: 255,
633 }),
634 button: StyleBackgroundContent::Color(ColorU {
635 r: 120,
636 g: 120,
637 b: 120,
638 a: 255,
639 }),
640 corner: StyleBackgroundContent::Color(ColorU {
641 r: 45,
642 g: 45,
643 b: 45,
644 a: 255,
645 }),
646 resizer: StyleBackgroundContent::Color(ColorU {
647 r: 45,
648 g: 45,
649 b: 45,
650 a: 255,
651 }),
652 clip_to_container_border: false,
653 scroll_behavior: ScrollBehavior::Auto,
654 overscroll_behavior_x: OverscrollBehavior::Auto,
655 overscroll_behavior_y: OverscrollBehavior::Auto,
656 overflow_scrolling: OverflowScrolling::Auto,
657};
658
659pub const SCROLLBAR_MACOS_LIGHT: ScrollbarInfo = ScrollbarInfo {
661 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(8)),
662 padding_left: LayoutPaddingLeft {
663 inner: crate::props::basic::pixel::PixelValue::const_px(0),
664 },
665 padding_right: LayoutPaddingRight {
666 inner: crate::props::basic::pixel::PixelValue::const_px(0),
667 },
668 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
669 thumb: StyleBackgroundContent::Color(ColorU {
670 r: 0,
671 g: 0,
672 b: 0,
673 a: 100,
674 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
676 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
677 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
678 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
680 overscroll_behavior_x: OverscrollBehavior::Auto,
681 overscroll_behavior_y: OverscrollBehavior::Auto,
682 overflow_scrolling: OverflowScrolling::Auto,
683};
684
685pub const SCROLLBAR_MACOS_DARK: ScrollbarInfo = ScrollbarInfo {
687 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(8)),
688 padding_left: LayoutPaddingLeft {
689 inner: crate::props::basic::pixel::PixelValue::const_px(0),
690 },
691 padding_right: LayoutPaddingRight {
692 inner: crate::props::basic::pixel::PixelValue::const_px(0),
693 },
694 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
695 thumb: StyleBackgroundContent::Color(ColorU {
696 r: 255,
697 g: 255,
698 b: 255,
699 a: 100,
700 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
702 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
703 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
704 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
706 overscroll_behavior_x: OverscrollBehavior::Auto,
707 overscroll_behavior_y: OverscrollBehavior::Auto,
708 overflow_scrolling: OverflowScrolling::Auto,
709};
710
711pub const SCROLLBAR_WINDOWS_LIGHT: ScrollbarInfo = ScrollbarInfo {
713 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(12)),
714 padding_left: LayoutPaddingLeft {
715 inner: crate::props::basic::pixel::PixelValue::const_px(0),
716 },
717 padding_right: LayoutPaddingRight {
718 inner: crate::props::basic::pixel::PixelValue::const_px(0),
719 },
720 track: StyleBackgroundContent::Color(ColorU {
721 r: 241,
722 g: 241,
723 b: 241,
724 a: 255,
725 }),
726 thumb: StyleBackgroundContent::Color(ColorU {
727 r: 130,
728 g: 130,
729 b: 130,
730 a: 255,
731 }),
732 button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
733 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
734 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
735 clip_to_container_border: false,
736 scroll_behavior: ScrollBehavior::Auto,
737 overscroll_behavior_x: OverscrollBehavior::None,
738 overscroll_behavior_y: OverscrollBehavior::None,
739 overflow_scrolling: OverflowScrolling::Auto,
740};
741
742pub const SCROLLBAR_WINDOWS_DARK: ScrollbarInfo = ScrollbarInfo {
744 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(12)),
745 padding_left: LayoutPaddingLeft {
746 inner: crate::props::basic::pixel::PixelValue::const_px(0),
747 },
748 padding_right: LayoutPaddingRight {
749 inner: crate::props::basic::pixel::PixelValue::const_px(0),
750 },
751 track: StyleBackgroundContent::Color(ColorU {
752 r: 32,
753 g: 32,
754 b: 32,
755 a: 255,
756 }),
757 thumb: StyleBackgroundContent::Color(ColorU {
758 r: 110,
759 g: 110,
760 b: 110,
761 a: 255,
762 }),
763 button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
764 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
765 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
766 clip_to_container_border: false,
767 scroll_behavior: ScrollBehavior::Auto,
768 overscroll_behavior_x: OverscrollBehavior::None,
769 overscroll_behavior_y: OverscrollBehavior::None,
770 overflow_scrolling: OverflowScrolling::Auto,
771};
772
773pub const SCROLLBAR_IOS_LIGHT: ScrollbarInfo = ScrollbarInfo {
775 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(7)),
776 padding_left: LayoutPaddingLeft {
777 inner: crate::props::basic::pixel::PixelValue::const_px(0),
778 },
779 padding_right: LayoutPaddingRight {
780 inner: crate::props::basic::pixel::PixelValue::const_px(0),
781 },
782 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
783 thumb: StyleBackgroundContent::Color(ColorU {
784 r: 0,
785 g: 0,
786 b: 0,
787 a: 102,
788 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
790 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
791 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
792 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
794 overscroll_behavior_x: OverscrollBehavior::Auto,
795 overscroll_behavior_y: OverscrollBehavior::Auto,
796 overflow_scrolling: OverflowScrolling::Auto,
797};
798
799pub const SCROLLBAR_IOS_DARK: ScrollbarInfo = ScrollbarInfo {
801 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(7)),
802 padding_left: LayoutPaddingLeft {
803 inner: crate::props::basic::pixel::PixelValue::const_px(0),
804 },
805 padding_right: LayoutPaddingRight {
806 inner: crate::props::basic::pixel::PixelValue::const_px(0),
807 },
808 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
809 thumb: StyleBackgroundContent::Color(ColorU {
810 r: 255,
811 g: 255,
812 b: 255,
813 a: 102,
814 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
816 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
817 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
818 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
820 overscroll_behavior_x: OverscrollBehavior::Auto,
821 overscroll_behavior_y: OverscrollBehavior::Auto,
822 overflow_scrolling: OverflowScrolling::Auto,
823};
824
825pub const SCROLLBAR_ANDROID_LIGHT: ScrollbarInfo = ScrollbarInfo {
827 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(6)),
828 padding_left: LayoutPaddingLeft {
829 inner: crate::props::basic::pixel::PixelValue::const_px(0),
830 },
831 padding_right: LayoutPaddingRight {
832 inner: crate::props::basic::pixel::PixelValue::const_px(0),
833 },
834 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
835 thumb: StyleBackgroundContent::Color(ColorU {
836 r: 0,
837 g: 0,
838 b: 0,
839 a: 102,
840 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
842 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
843 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
844 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
846 overscroll_behavior_x: OverscrollBehavior::Contain,
847 overscroll_behavior_y: OverscrollBehavior::Auto,
848 overflow_scrolling: OverflowScrolling::Auto,
849};
850
851pub const SCROLLBAR_ANDROID_DARK: ScrollbarInfo = ScrollbarInfo {
853 width: LayoutWidth::Px(crate::props::basic::pixel::PixelValue::const_px(6)),
854 padding_left: LayoutPaddingLeft {
855 inner: crate::props::basic::pixel::PixelValue::const_px(0),
856 },
857 padding_right: LayoutPaddingRight {
858 inner: crate::props::basic::pixel::PixelValue::const_px(0),
859 },
860 track: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
861 thumb: StyleBackgroundContent::Color(ColorU {
862 r: 255,
863 g: 255,
864 b: 255,
865 a: 102,
866 }), button: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
868 corner: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
869 resizer: StyleBackgroundContent::Color(ColorU::TRANSPARENT),
870 clip_to_container_border: true, scroll_behavior: ScrollBehavior::Smooth,
872 overscroll_behavior_x: OverscrollBehavior::Contain,
873 overscroll_behavior_y: OverscrollBehavior::Auto,
874 overflow_scrolling: OverflowScrolling::Auto,
875};
876
877#[derive(Clone, PartialEq, Eq)]
880pub enum LayoutScrollbarWidthParseError<'a> {
881 InvalidValue(&'a str),
882}
883impl_debug_as_display!(LayoutScrollbarWidthParseError<'a>);
884impl_display! { LayoutScrollbarWidthParseError<'a>, {
885 InvalidValue(v) => format!("Invalid scrollbar-width value: \"{}\"", v),
886}}
887
888#[derive(Debug, Clone, PartialEq, Eq)]
889#[repr(C, u8)]
890pub enum LayoutScrollbarWidthParseErrorOwned {
891 InvalidValue(AzString),
892}
893impl LayoutScrollbarWidthParseError<'_> {
894 #[must_use] pub fn to_contained(&self) -> LayoutScrollbarWidthParseErrorOwned {
895 match self {
896 Self::InvalidValue(s) => {
897 LayoutScrollbarWidthParseErrorOwned::InvalidValue((*s).to_string().into())
898 }
899 }
900 }
901}
902impl LayoutScrollbarWidthParseErrorOwned {
903 #[must_use] pub fn to_shared(&self) -> LayoutScrollbarWidthParseError<'_> {
904 match self {
905 Self::InvalidValue(s) => LayoutScrollbarWidthParseError::InvalidValue(s.as_str()),
906 }
907 }
908}
909
910#[cfg(feature = "parser")]
911pub fn parse_layout_scrollbar_width(
915 input: &str,
916) -> Result<LayoutScrollbarWidth, LayoutScrollbarWidthParseError<'_>> {
917 match input.trim() {
918 "auto" => Ok(LayoutScrollbarWidth::Auto),
919 "thin" => Ok(LayoutScrollbarWidth::Thin),
920 "none" => Ok(LayoutScrollbarWidth::None),
921 _ => Err(LayoutScrollbarWidthParseError::InvalidValue(input)),
922 }
923}
924
925#[derive(Clone, PartialEq)]
926pub enum StyleScrollbarColorParseError<'a> {
927 InvalidValue(&'a str),
928 Color(CssColorParseError<'a>),
929}
930impl_debug_as_display!(StyleScrollbarColorParseError<'a>);
931impl_display! { StyleScrollbarColorParseError<'a>, {
932 InvalidValue(v) => format!("Invalid scrollbar-color value: \"{}\"", v),
933 Color(e) => format!("Invalid color in scrollbar-color: {}", e),
934}}
935impl_from!(CssColorParseError<'a>, StyleScrollbarColorParseError::Color);
936
937#[derive(Debug, Clone, PartialEq)]
938#[repr(C, u8)]
939pub enum StyleScrollbarColorParseErrorOwned {
940 InvalidValue(AzString),
941 Color(CssColorParseErrorOwned),
942}
943impl StyleScrollbarColorParseError<'_> {
944 #[must_use] pub fn to_contained(&self) -> StyleScrollbarColorParseErrorOwned {
945 match self {
946 Self::InvalidValue(s) => {
947 StyleScrollbarColorParseErrorOwned::InvalidValue((*s).to_string().into())
948 }
949 Self::Color(e) => StyleScrollbarColorParseErrorOwned::Color(e.to_contained()),
950 }
951 }
952}
953impl StyleScrollbarColorParseErrorOwned {
954 #[must_use] pub fn to_shared(&self) -> StyleScrollbarColorParseError<'_> {
955 match self {
956 Self::InvalidValue(s) => StyleScrollbarColorParseError::InvalidValue(s.as_str()),
957 Self::Color(e) => StyleScrollbarColorParseError::Color(e.to_shared()),
958 }
959 }
960}
961
962#[cfg(feature = "parser")]
963pub fn parse_style_scrollbar_color(
967 input: &str,
968) -> Result<StyleScrollbarColor, StyleScrollbarColorParseError<'_>> {
969 let input = input.trim();
970 if input == "auto" {
971 return Ok(StyleScrollbarColor::Auto);
972 }
973
974 let mut parts = input.split_whitespace();
975 let thumb_str = parts
976 .next()
977 .ok_or(StyleScrollbarColorParseError::InvalidValue(input))?;
978 let track_str = parts
979 .next()
980 .ok_or(StyleScrollbarColorParseError::InvalidValue(input))?;
981
982 if parts.next().is_some() {
983 return Err(StyleScrollbarColorParseError::InvalidValue(input));
984 }
985
986 let thumb = parse_css_color(thumb_str)?;
987 let track = parse_css_color(track_str)?;
988
989 Ok(StyleScrollbarColor::Custom(ScrollbarColorCustom {
990 thumb,
991 track,
992 }))
993}
994
995#[derive(Clone, PartialEq, Eq)]
998pub enum ScrollbarVisibilityModeParseError<'a> {
999 InvalidValue(&'a str),
1000}
1001impl_debug_as_display!(ScrollbarVisibilityModeParseError<'a>);
1002impl_display! { ScrollbarVisibilityModeParseError<'a>, {
1003 InvalidValue(v) => format!("Invalid scrollbar-visibility value: \"{}\"", v),
1004}}
1005
1006#[derive(Debug, Clone, PartialEq, Eq)]
1007#[repr(C, u8)]
1008pub enum ScrollbarVisibilityModeParseErrorOwned {
1009 InvalidValue(AzString),
1010}
1011impl ScrollbarVisibilityModeParseError<'_> {
1012 #[must_use] pub fn to_contained(&self) -> ScrollbarVisibilityModeParseErrorOwned {
1013 match self {
1014 Self::InvalidValue(s) => ScrollbarVisibilityModeParseErrorOwned::InvalidValue((*s).to_string().into()),
1015 }
1016 }
1017}
1018impl ScrollbarVisibilityModeParseErrorOwned {
1019 #[must_use] pub fn to_shared(&self) -> ScrollbarVisibilityModeParseError<'_> {
1020 match self {
1021 Self::InvalidValue(s) => ScrollbarVisibilityModeParseError::InvalidValue(s.as_str()),
1022 }
1023 }
1024}
1025
1026#[cfg(feature = "parser")]
1027pub fn parse_scrollbar_visibility_mode(
1031 input: &str,
1032) -> Result<ScrollbarVisibilityMode, ScrollbarVisibilityModeParseError<'_>> {
1033 match input.trim() {
1034 "always" => Ok(ScrollbarVisibilityMode::Always),
1035 "when-scrolling" => Ok(ScrollbarVisibilityMode::WhenScrolling),
1036 "auto" => Ok(ScrollbarVisibilityMode::Auto),
1037 _ => Err(ScrollbarVisibilityModeParseError::InvalidValue(input)),
1038 }
1039}
1040
1041#[derive(Clone, PartialEq, Eq)]
1044pub enum ScrollbarFadeDelayParseError<'a> {
1045 InvalidValue(&'a str),
1046}
1047impl_debug_as_display!(ScrollbarFadeDelayParseError<'a>);
1048impl_display! { ScrollbarFadeDelayParseError<'a>, {
1049 InvalidValue(v) => format!("Invalid scrollbar-fade-delay value: \"{}\"", v),
1050}}
1051
1052#[derive(Debug, Clone, PartialEq, Eq)]
1053#[repr(C, u8)]
1054pub enum ScrollbarFadeDelayParseErrorOwned {
1055 InvalidValue(AzString),
1056}
1057impl ScrollbarFadeDelayParseError<'_> {
1058 #[must_use] pub fn to_contained(&self) -> ScrollbarFadeDelayParseErrorOwned {
1059 match self {
1060 Self::InvalidValue(s) => ScrollbarFadeDelayParseErrorOwned::InvalidValue((*s).to_string().into()),
1061 }
1062 }
1063}
1064impl ScrollbarFadeDelayParseErrorOwned {
1065 #[must_use] pub fn to_shared(&self) -> ScrollbarFadeDelayParseError<'_> {
1066 match self {
1067 Self::InvalidValue(s) => ScrollbarFadeDelayParseError::InvalidValue(s.as_str()),
1068 }
1069 }
1070}
1071
1072#[cfg(feature = "parser")]
1073fn parse_time_ms(input: &str) -> Option<u32> {
1074 crate::props::basic::time::parse_duration(input).ok().map(|d| d.inner)
1075}
1076
1077#[cfg(feature = "parser")]
1078pub fn parse_scrollbar_fade_delay(
1082 input: &str,
1083) -> Result<ScrollbarFadeDelay, ScrollbarFadeDelayParseError<'_>> {
1084 parse_time_ms(input)
1085 .map(ScrollbarFadeDelay::new)
1086 .ok_or(ScrollbarFadeDelayParseError::InvalidValue(input))
1087}
1088
1089#[derive(Clone, PartialEq, Eq)]
1092pub enum ScrollbarFadeDurationParseError<'a> {
1093 InvalidValue(&'a str),
1094}
1095impl_debug_as_display!(ScrollbarFadeDurationParseError<'a>);
1096impl_display! { ScrollbarFadeDurationParseError<'a>, {
1097 InvalidValue(v) => format!("Invalid scrollbar-fade-duration value: \"{}\"", v),
1098}}
1099
1100#[derive(Debug, Clone, PartialEq, Eq)]
1101#[repr(C, u8)]
1102pub enum ScrollbarFadeDurationParseErrorOwned {
1103 InvalidValue(AzString),
1104}
1105impl ScrollbarFadeDurationParseError<'_> {
1106 #[must_use] pub fn to_contained(&self) -> ScrollbarFadeDurationParseErrorOwned {
1107 match self {
1108 Self::InvalidValue(s) => ScrollbarFadeDurationParseErrorOwned::InvalidValue((*s).to_string().into()),
1109 }
1110 }
1111}
1112impl ScrollbarFadeDurationParseErrorOwned {
1113 #[must_use] pub fn to_shared(&self) -> ScrollbarFadeDurationParseError<'_> {
1114 match self {
1115 Self::InvalidValue(s) => ScrollbarFadeDurationParseError::InvalidValue(s.as_str()),
1116 }
1117 }
1118}
1119
1120#[cfg(feature = "parser")]
1121pub fn parse_scrollbar_fade_duration(
1125 input: &str,
1126) -> Result<ScrollbarFadeDuration, ScrollbarFadeDurationParseError<'_>> {
1127 parse_time_ms(input)
1128 .map(ScrollbarFadeDuration::new)
1129 .ok_or(ScrollbarFadeDurationParseError::InvalidValue(input))
1130}
1131
1132#[cfg(all(test, feature = "parser"))]
1133mod tests {
1134 use super::*;
1135 use crate::props::basic::color::ColorU;
1136
1137 #[test]
1138 fn test_parse_scrollbar_width() {
1139 assert_eq!(
1140 parse_layout_scrollbar_width("auto").unwrap(),
1141 LayoutScrollbarWidth::Auto
1142 );
1143 assert_eq!(
1144 parse_layout_scrollbar_width("thin").unwrap(),
1145 LayoutScrollbarWidth::Thin
1146 );
1147 assert_eq!(
1148 parse_layout_scrollbar_width("none").unwrap(),
1149 LayoutScrollbarWidth::None
1150 );
1151 assert!(parse_layout_scrollbar_width("thick").is_err());
1152 }
1153
1154 #[test]
1155 fn test_parse_scrollbar_color() {
1156 assert_eq!(
1157 parse_style_scrollbar_color("auto").unwrap(),
1158 StyleScrollbarColor::Auto
1159 );
1160
1161 let custom = parse_style_scrollbar_color("red blue").unwrap();
1162 assert_eq!(
1163 custom,
1164 StyleScrollbarColor::Custom(ScrollbarColorCustom {
1165 thumb: ColorU::RED,
1166 track: ColorU::BLUE
1167 })
1168 );
1169
1170 let custom_hex = parse_style_scrollbar_color("#ff0000 #0000ff").unwrap();
1171 assert_eq!(
1172 custom_hex,
1173 StyleScrollbarColor::Custom(ScrollbarColorCustom {
1174 thumb: ColorU::RED,
1175 track: ColorU::BLUE
1176 })
1177 );
1178
1179 assert!(parse_style_scrollbar_color("red").is_err());
1180 assert!(parse_style_scrollbar_color("red blue green").is_err());
1181 }
1182}