1use floem_renderer::text::FontWeight as FontWeightProp;
131use peniko::color::palette;
132use peniko::kurbo::{self, Affine, RoundedRect, Stroke, Vec2};
133use peniko::{Brush, Color};
134use rustc_hash::FxHashMap;
135use smallvec::SmallVec;
136use std::any::Any;
137use std::collections::HashMap;
138use std::fmt::{self, Debug};
139use std::marker::PhantomData;
140use std::rc::Rc;
141use std::sync::atomic::{AtomicU64, Ordering};
142use taffy::GridTemplateComponent;
143
144pub use taffy::style::{
145 AlignContent, AlignItems, BoxSizing, Dimension, Display, FlexDirection, FlexWrap,
146 JustifyContent, JustifyItems, Position,
147};
148use taffy::{
149 geometry::{MinMax, Size},
150 prelude::{GridPlacement, Line, Rect},
151 style::{
152 LengthPercentage, MaxTrackSizingFunction, MinTrackSizingFunction, Overflow,
153 Style as TaffyStyle,
154 },
155};
156
157use crate::layout::responsive::{GridBreakpoints, ScreenSize, ScreenSizeBp};
158
159use crate::style::components::Focus;
160use crate::text::{OverflowWrap, WordBreakStrength};
161use crate::views::editor::SelectionColor;
162use crate::{prop, prop_extractor};
164
165mod cache;
166mod components;
167mod custom;
168mod cx;
169mod props;
170pub mod recalc;
171mod selectors;
172#[cfg(test)]
173mod tests;
174pub mod theme;
175mod transition;
176pub mod unit;
177mod values;
178
179pub use components::{
180 Border, BorderColor, BorderRadius, BoxShadow, CursorStyle, Margin, NoWrapOverflow, Padding,
181 PointerEvents, TextOverflow,
182};
183pub use custom::{CustomStylable, CustomStyle};
184pub use cx::{InheritedInteractionCx, InteractionState, StyleCx};
185pub use props::{
186 ExtractorField, StyleClass, StyleClassInfo, StyleClassRef, StyleDebugGroup,
187 StyleDebugGroupInfo, StyleDebugGroupRef, StyleKey, StyleKeyInfo, StyleProp, StylePropInfo,
188 StylePropReader, StylePropRef,
189};
190pub use selectors::{NthChild, StructuralSelector, StyleSelector, StyleSelectors};
191pub use theme::{DesignSystem, StyleThemeExt};
192pub use transition::{DirectTransition, Transition, TransitionState};
193pub use unit::{
194 AnchorAbout, Angle, Auto, DurationUnitExt, Em, FontSizeCx, Length, LengthAuto, Lh,
195 LineHeightValue, Pct, Pt, UnitExt,
196};
197pub use values::{
198 ContextValue, ObjectFit, ObjectPosition, StrokeWrap, StyleMapValue, StylePropValue, StyleValue,
199};
200
201pub use cache::{StyleCache, StyleCacheKey};
202
203pub(crate) use props::{RESPONSIVE_SELECTORS_INFO, STRUCTURAL_SELECTORS_INFO, style_key_selector};
204
205static NEXT_STYLE_MERGE_ID: AtomicU64 = AtomicU64::new(1);
206const MERGE_MIX_CONST: u64 = 0x9E3779B97F4A7C15;
207static DEFERRED_EFFECTS_INFO: StyleKeyInfo = StyleKeyInfo::DeferredEffects;
208const DEFERRED_EFFECTS_KEY: StyleKey = StyleKey {
209 info: &DEFERRED_EFFECTS_INFO,
210};
211
212fn next_style_merge_id() -> u64 {
213 NEXT_STYLE_MERGE_ID.fetch_add(1, Ordering::Relaxed)
214}
215
216fn combine_merge_ids(a: u64, b: u64) -> u64 {
217 a.rotate_left(13) ^ b.wrapping_mul(MERGE_MIX_CONST)
218}
219
220type StructuralSelectorRules = SmallVec<[(StructuralSelector, Rc<Style>); 2]>;
221type ResponsiveSelectorRules = SmallVec<[(ResponsiveSelector, Rc<Style>); 2]>;
222
223#[derive(Clone)]
224pub(crate) struct DeferredStyleEffect {
225 run: Rc<dyn Fn(&Style)>,
226}
227
228impl DeferredStyleEffect {
229 fn new(run: impl Fn(&Style) + 'static) -> Self {
230 Self { run: Rc::new(run) }
231 }
232
233 fn run(&self, style: &Style) {
234 (self.run)(style);
235 }
236}
237
238#[derive(Clone, Default, Debug)]
239pub struct ExprStyle {
240 style: Style,
241}
242
243impl From<Style> for ExprStyle {
244 fn from(style: Style) -> Self {
245 Self { style }
246 }
247}
248
249impl From<ExprStyle> for Style {
250 fn from(style: ExprStyle) -> Self {
251 style.style
252 }
253}
254
255#[derive(Debug, Clone, Copy, Default)]
256pub struct ContextRef<P: StyleProp> {
257 _marker: PhantomData<P>,
258}
259
260impl<P: StyleProp> ContextRef<P> {
261 pub fn def<T>(self, f: impl Fn(P::Type) -> T + 'static) -> ContextValue<T>
275 where
276 P::Type: 'static,
277 T: 'static,
278 {
279 ContextValue::new(move |style| {
280 let value = style.get_prop::<P>().unwrap_or_else(P::default_value);
281 f(value)
282 })
283 }
284
285 pub fn map<T>(self, f: impl Fn(P::Type) -> T + 'static) -> ContextValue<T>
286 where
287 P::Type: 'static,
288 T: 'static,
289 {
290 self.def(f)
291 }
292
293 pub(crate) fn into_deferred(self, f: impl Fn(P::Type) + 'static) -> DeferredStyleEffect
294 where
295 P::Type: 'static,
296 {
297 let effect = self.def(move |value| {
298 f(value);
299 });
300 DeferredStyleEffect::new(move |style| {
301 effect.resolve(style);
302 })
303 }
304}
305
306impl ExprStyle {
307 pub fn new() -> Self {
308 Self {
309 style: Style::new(),
310 }
311 }
312
313 pub fn build(self) -> Style {
314 self.style
315 }
316
317 pub fn map(self, over: impl FnOnce(Self) -> Self) -> Self {
318 over(self)
319 }
320
321 fn merge(mut self, over: Style) -> Self {
322 self.style.apply_mut(&over);
323 self
324 }
325
326 pub fn apply_if(self, cond: bool, f: impl FnOnce(Self) -> Self) -> Self {
327 if cond { f(self) } else { self }
328 }
329
330 pub fn set<P: StyleProp>(mut self, prop: P, value: impl Into<StyleValue<P::Type>>) -> Self {
331 self.style = self.style.set_style_value(prop, value.into());
332 self
333 }
334
335 pub fn set_context<P: StyleProp>(mut self, prop: P, value: ContextValue<P::Type>) -> Self {
336 self.style = self.style.set_context(prop, value);
337 self
338 }
339
340 pub fn set_from_context<C: StyleProp, P: StyleProp>(
341 mut self,
342 prop: P,
343 context: ContextRef<C>,
344 f: impl Fn(C::Type) -> P::Type + 'static,
345 ) -> Self
346 where
347 C::Type: 'static,
348 P::Type: 'static,
349 {
350 self.style = self.style.set_from_context(prop, context, f);
351 self
352 }
353
354 pub fn set_context_opt<P: StyleProp<Type = Option<T>>, T: 'static>(
355 mut self,
356 prop: P,
357 value: ContextValue<Option<T>>,
358 ) -> Self {
359 self.style = self.style.set_context_opt(prop, value);
360 self
361 }
362
363 pub fn set_from_context_opt<C: StyleProp, P: StyleProp<Type = Option<T>>, T: 'static>(
364 mut self,
365 prop: P,
366 context: ContextRef<C>,
367 f: impl Fn(C::Type) -> Option<T> + 'static,
368 ) -> Self
369 where
370 C::Type: 'static,
371 {
372 self.style = self.style.set_from_context_opt(prop, context, f);
373 self
374 }
375
376 pub fn with<P: StyleProp>(self, f: impl FnOnce(ExprStyle, ContextRef<P>) -> ExprStyle) -> Self {
377 f(self, ContextRef::default())
378 }
379
380 pub fn hover(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
381 self.merge(Style::default().hover(|s| style(s.into()).into()))
382 }
383
384 pub fn focus(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
385 self.merge(Style::default().focus(|s| style(s.into()).into()))
386 }
387
388 pub fn focus_visible(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
389 self.merge(Style::default().focus_visible(|s| style(s.into()).into()))
390 }
391
392 pub fn focus_within(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
393 self.merge(Style::default().focus_within(|s| style(s.into()).into()))
394 }
395
396 pub fn active(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
397 self.merge(Style::default().active(|s| style(s.into()).into()))
398 }
399
400 pub fn disabled(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
401 self.merge(Style::default().disabled(|s| style(s.into()).into()))
402 }
403
404 pub fn class<C: StyleClass>(
405 self,
406 class: C,
407 style: impl FnOnce(ExprStyle) -> ExprStyle,
408 ) -> Self {
409 self.merge(Style::default().class(class, |s| style(s.into()).into()))
410 }
411
412 pub fn font_size<T>(self, size: ContextValue<T>) -> Self
414 where
415 T: Into<Pt> + 'static,
416 {
417 let px = size.map(|s| s.into().0);
418 self.set_context(FontSize, px)
419 }
420
421 pub fn size<W, H>(self, width: ContextValue<W>, height: ContextValue<H>) -> Self
422 where
423 W: Into<LengthAuto> + 'static,
424 H: Into<LengthAuto> + 'static,
425 {
426 self.width(width).height(height)
427 }
428
429 pub fn absolute(self) -> Self {
430 self.set(PositionProp, Position::Absolute)
431 }
432
433 pub fn flex_row(self) -> Self {
434 self.set(FlexDirectionProp, FlexDirection::Row)
435 }
436
437 pub fn margin<T>(self, margin: ContextValue<T>) -> Self
438 where
439 T: Into<LengthAuto> + 'static,
440 {
441 let margin = margin.map(Into::into);
442 self.set(MarginLeft, margin.clone())
443 .set(MarginTop, margin.clone())
444 .set(MarginRight, margin.clone())
445 .set(MarginBottom, margin)
446 }
447
448 pub fn border_color<T>(self, color: ContextValue<T>) -> Self
449 where
450 T: Into<Brush> + 'static,
451 {
452 let color = color.map(|color| Some(color.into()));
453 self.set(BorderLeftColor, color.clone())
454 .set(BorderTopColor, color.clone())
455 .set(BorderRightColor, color.clone())
456 .set(BorderBottomColor, color)
457 }
458
459 pub fn border_radius<T>(self, radius: ContextValue<T>) -> Self
460 where
461 T: Into<Length> + 'static,
462 {
463 let radius = radius.map(Into::into);
464 self.set(BorderTopLeftRadius, radius.clone())
465 .set(BorderTopRightRadius, radius.clone())
466 .set(BorderBottomLeftRadius, radius.clone())
467 .set(BorderBottomRightRadius, radius)
468 }
469
470 pub fn border<T>(self, width: ContextValue<T>) -> Self
471 where
472 T: Into<Pt> + 'static,
473 {
474 let stroke = width.map(|width| Stroke::new(width.into().0));
475 self.set(BorderLeft, stroke.clone())
476 .set(BorderTop, stroke.clone())
477 .set(BorderRight, stroke.clone())
478 .set(BorderBottom, stroke)
479 }
480
481 pub fn border_top<T>(self, width: ContextValue<T>) -> Self
482 where
483 T: Into<Pt> + 'static,
484 {
485 self.set(BorderTop, width.map(|width| Stroke::new(width.into().0)))
486 }
487
488 pub fn items_center(self) -> Self {
489 self.set(AlignItemsProp, Some(AlignItems::Center))
490 }
491
492 pub fn justify_center(self) -> Self {
493 self.set(
494 JustifyContentProp,
495 Some(taffy::style::JustifyContent::Center),
496 )
497 }
498
499 pub fn selected(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
500 self.merge(Style::default().selected(|s| style(s.into()).into()))
501 }
502
503 pub fn drag(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
504 self.merge(Style::default().drag(|s| style(s.into()).into()))
505 }
506
507 pub fn file_hover(self, style: impl FnOnce(ExprStyle) -> ExprStyle) -> Self {
508 self.merge(Style::default().file_hover(|s| style(s.into()).into()))
509 }
510
511 pub fn padding<T>(self, padding: ContextValue<T>) -> Self
512 where
513 T: Into<Length> + 'static,
514 {
515 let padding = padding.map(Into::into);
516 self.set(PaddingLeft, padding.clone())
517 .set(PaddingTop, padding.clone())
518 .set(PaddingRight, padding.clone())
519 .set(PaddingBottom, padding)
520 }
521
522 pub fn padding_horiz<T>(self, padding: ContextValue<T>) -> Self
523 where
524 T: Into<Length> + 'static,
525 {
526 let padding = padding.map(Into::into);
527 self.set(PaddingLeft, padding.clone())
528 .set(PaddingRight, padding)
529 }
530
531 pub fn padding_vert<T>(self, padding: ContextValue<T>) -> Self
532 where
533 T: Into<Length> + 'static,
534 {
535 let padding = padding.map(Into::into);
536 self.set(PaddingTop, padding.clone())
537 .set(PaddingBottom, padding)
538 }
539
540 pub fn gap<T>(self, gap: ContextValue<T>) -> Self
541 where
542 T: Into<Length> + 'static,
543 {
544 let gap = gap.map(Into::into);
545 self.set(ColGap, gap.clone()).set(RowGap, gap)
546 }
547
548 pub fn custom<CS>(self, custom: impl FnOnce(CS) -> CS) -> Self
549 where
550 CS: Default + Clone + Into<Style> + From<Style>,
551 {
552 self.merge(custom(CS::default()).into())
553 }
554
555 pub fn apply_border_radius(self, border_radius: BorderRadius) -> Self {
556 self.merge(Style::new().apply_border_radius(border_radius))
557 }
558
559 pub fn apply_box_shadows(self, shadow: impl Into<SmallVec<[BoxShadow; 3]>>) -> Self {
560 self.set(BoxShadowProp, shadow.into())
561 }
562
563 pub fn transition_background(self, transition: Transition) -> Self {
564 self.merge(Style::new().transition_background(transition))
565 }
566
567 pub fn border_bottom(self, width: impl Into<Pt>) -> Self {
568 self.set(BorderBottom, Stroke::new(width.into().0))
569 }
570
571 pub fn outline(self, width: impl Into<Pt>) -> Self {
572 self.set(Outline, Stroke::new(width.into().0))
573 }
574}
575
576fn fx_hash_map_with_capacity<K, V>(capacity: usize) -> FxHashMap<K, V> {
577 FxHashMap::with_capacity_and_hasher(capacity, Default::default())
578}
579
580fn take_any<T: Any + Clone>(value: Rc<dyn Any>) -> T {
581 Rc::downcast::<T>(value)
582 .map(|rc| Rc::try_unwrap(rc).unwrap_or_else(|rc| (*rc).clone()))
583 .unwrap_or_else(|_| panic!("unexpected style map payload type"))
584}
585
586#[derive(Clone)]
587struct StructuralSelectors(StructuralSelectorRules);
588
589#[derive(Clone)]
590struct ResponsiveSelectors(ResponsiveSelectorRules);
591
592#[derive(Clone, Copy, Debug, PartialEq)]
593enum ResponsiveSelector {
594 ScreenSize(ScreenSize),
595 MinWidth(Pt),
596 MaxWidth(Pt),
597 WidthRange { min: Pt, max: Pt },
598}
599
600impl ResponsiveSelector {
601 fn matches(&self, width: f64) -> bool {
602 match self {
603 ResponsiveSelector::ScreenSize(size) => {
604 let bp = GridBreakpoints::default().get_width_bp(width);
605 size.breakpoints().contains(&bp)
606 }
607 ResponsiveSelector::MinWidth(min) => width >= min.0,
608 ResponsiveSelector::MaxWidth(max) => width <= max.0,
609 ResponsiveSelector::WidthRange { min, max } => width >= min.0 && width <= max.0,
610 }
611 }
612}
613
614style_key_selector!(selector_xs, StyleSelectors::empty().responsive());
615style_key_selector!(selector_sm, StyleSelectors::empty().responsive());
616style_key_selector!(selector_md, StyleSelectors::empty().responsive());
617style_key_selector!(selector_lg, StyleSelectors::empty().responsive());
618style_key_selector!(selector_xl, StyleSelectors::empty().responsive());
619style_key_selector!(selector_xxl, StyleSelectors::empty().responsive());
620
621pub(crate) fn screen_size_bp_to_key(breakpoint: ScreenSizeBp) -> StyleKey {
622 match breakpoint {
623 ScreenSizeBp::Xs => selector_xs(),
624 ScreenSizeBp::Sm => selector_sm(),
625 ScreenSizeBp::Md => selector_md(),
626 ScreenSizeBp::Lg => selector_lg(),
627 ScreenSizeBp::Xl => selector_xl(),
628 ScreenSizeBp::Xxl => selector_xxl(),
629 }
630}
631
632fn structural_selectors_key() -> StyleKey {
633 StyleKey {
634 info: &STRUCTURAL_SELECTORS_INFO,
635 }
636}
637
638fn responsive_selectors_key() -> StyleKey {
639 StyleKey {
640 info: &RESPONSIVE_SELECTORS_INFO,
641 }
642}
643
644pub fn resolve_nested_maps(
646 style: Style,
647 interact_state: &mut InteractionState,
648 screen_size_bp: ScreenSizeBp,
649 classes: &[StyleClassRef],
650 inherited_context: &Style,
651 class_context: &Style,
652) -> (Style, StyleSelectors) {
653 let mut selectors = StyleSelectors::empty();
656
657 let effect_context = style.effect_context.clone();
658
659 let class_style = resolve_classes(
660 classes,
661 interact_state,
662 screen_size_bp,
663 class_context,
664 &mut selectors,
665 );
666 selectors |= class_style.selectors();
667 let view_style = resolve_style(style, interact_state, screen_size_bp, &mut selectors);
668 let result = class_style
669 .apply(view_style)
670 .with_inherited_context(inherited_context);
671 result.run_deferred_effects();
672 let _ = effect_context;
673 (result, selectors)
674}
675
676fn resolve_classes(
677 classes: &[StyleClassRef],
678 interact_state: &InteractionState,
679 screen_size_bp: ScreenSizeBp,
680 class_context: &Style,
681 selectors: &mut StyleSelectors,
682) -> Style {
683 let mut result = Style::with_capacity(classes.len());
684
685 for class in classes {
686 if let Some(map) = class_context.get_nested_map(class.key) {
687 let resolved = resolve_style(map.clone(), interact_state, screen_size_bp, selectors);
688 result.apply_mut(&resolved);
689 }
690 }
691
692 result
693}
694
695fn resolve_style(
696 style: Style,
697 interact_state: &InteractionState,
698 screen_size_bp: ScreenSizeBp,
699 selectors: &mut StyleSelectors,
700) -> Style {
701 resolve_selectors(style, interact_state, screen_size_bp, selectors)
702}
703
704fn resolve_selectors(
705 mut style: Style,
706 interact_state: &InteractionState,
707 screen_size_bp: ScreenSizeBp,
708 selectors: &mut StyleSelectors,
709) -> Style {
710 *selectors |= style.selectors();
711
712 #[cfg(debug_assertions)]
714 debug_assert!(
715 style
716 .cached_selectors
717 .contains(style.compute_selectors_slow()),
718 "cached_selectors {:?} missing bits from computed {:?}",
719 style.cached_selectors,
720 style.compute_selectors_slow()
721 );
722
723 const MAX_DEPTH: u32 = 20;
724 let mut depth = 0;
725
726 loop {
727 if depth >= MAX_DEPTH {
728 break;
729 }
730 depth += 1;
731
732 let mut changed = false;
733
734 if let Some(structural_rules) = extract_structural_selectors(&mut style) {
738 for (selector, map) in structural_rules {
739 if selector.matches(interact_state.child_index, interact_state.sibling_count) {
740 style.apply_mut(map.as_ref());
741 changed = true;
742 }
743 }
744 }
745
746 if let Some(responsive_rules) = extract_responsive_selectors(&mut style) {
748 for (selector, map) in responsive_rules {
749 if selector.matches(interact_state.window_width) {
750 style.apply_mut(map.as_ref());
751 changed = true;
752 }
753 }
754 }
755
756 let apply_nested = |style: &mut Style, key: StyleKey| -> bool {
758 if let Some(map) = style.get_nested_map(key) {
759 style.apply_mut(&map);
760 style.remove_nested_map(key);
761 true
762 } else {
763 false
764 }
765 };
766
767 if apply_nested(&mut style, screen_size_bp_to_key(screen_size_bp)) {
769 changed = true;
770 }
771
772 if interact_state.is_dark_mode && apply_nested(&mut style, StyleSelector::DarkMode.to_key())
774 {
775 changed = true;
776 }
777
778 if interact_state.is_disabled || style.get(Disabled) {
780 if apply_nested(&mut style, StyleSelector::Disabled.to_key()) {
781 changed = true;
782 }
783 } else {
784 if (interact_state.is_selected || style.get(Selected))
786 && apply_nested(&mut style, StyleSelector::Selected.to_key())
787 {
788 changed = true;
789 }
790
791 if interact_state.is_hovered && apply_nested(&mut style, StyleSelector::Hover.to_key())
793 {
794 changed = true;
795 }
796
797 if interact_state.is_file_hover
799 && apply_nested(&mut style, StyleSelector::FileHover.to_key())
800 {
801 changed = true;
802 }
803
804 if interact_state.is_focused && apply_nested(&mut style, StyleSelector::Focus.to_key())
806 {
807 changed = true;
808 }
809
810 if interact_state.is_focus_within
811 && apply_nested(&mut style, StyleSelector::FocusWithin.to_key())
812 {
813 changed = true;
814 }
815
816 if interact_state.is_focused && interact_state.using_keyboard_navigation {
817 if apply_nested(&mut style, StyleSelector::FocusVisible.to_key()) {
818 changed = true;
819 }
820
821 if interact_state.is_active
822 && apply_nested(&mut style, StyleSelector::Active.to_key())
823 {
824 changed = true;
825 }
826 }
827
828 if interact_state.is_active
830 && !interact_state.using_keyboard_navigation
831 && apply_nested(&mut style, StyleSelector::Active.to_key())
832 {
833 changed = true;
834 }
835 }
836
837 if !changed {
838 break;
839 }
840 }
841
842 style
843}
844
845fn extract_structural_selectors(style: &mut Style) -> Option<StructuralSelectorRules> {
846 let key = structural_selectors_key();
847 style
848 .map_mut()
849 .remove(&key)
850 .map(|rc| take_any::<StructuralSelectors>(rc).0)
851}
852
853fn extract_responsive_selectors(style: &mut Style) -> Option<ResponsiveSelectorRules> {
854 let key = responsive_selectors_key();
855 style
856 .map_mut()
857 .remove(&key)
858 .map(|rc| take_any::<ResponsiveSelectors>(rc).0)
859}
860
861#[derive(Clone)]
862pub struct Style {
863 pub(crate) map: Rc<FxHashMap<StyleKey, Rc<dyn Any>>>,
864 inherited_context: Option<Rc<FxHashMap<StyleKey, Rc<dyn Any>>>>,
865 merge_id: u64,
867 has_class_maps: bool,
871 has_inherited: bool,
875 cached_selectors: StyleSelectors,
879 has_context_values: bool,
884 effect_context: Option<Rc<dyn floem_reactive::EffectTrait>>,
888}
889impl Default for Style {
890 fn default() -> Self {
891 Self::with_capacity(0)
892 }
893}
894
895impl Style {
896 fn with_capacity(capacity: usize) -> Self {
897 let effect_context = floem_reactive::Runtime::get_current_effect();
898 let map = Rc::new(fx_hash_map_with_capacity(capacity));
899 Self {
900 merge_id: next_style_merge_id(),
901 map,
902 inherited_context: None,
903 has_class_maps: false,
904 has_inherited: false,
905 cached_selectors: StyleSelectors::empty(),
906 has_context_values: false,
907 effect_context,
908 }
909 }
910
911 fn map_mut(&mut self) -> &mut FxHashMap<StyleKey, Rc<dyn Any>> {
912 Rc::make_mut(&mut self.map)
913 }
914
915 pub fn new() -> Self {
916 Self::with_capacity(0)
917 }
918
919 pub(crate) fn with_inherited_context(mut self, inherited: &Style) -> Self {
920 self.inherited_context = Some(inherited.map.clone());
921 self
922 }
923
924 pub fn apply_only_inherited(to: &mut Style, from: &Style) {
931 if from.any_inherited() {
932 for (k, v) in from.map.iter().filter(|(p, _)| p.inherited()) {
933 let StyleKeyInfo::Prop(info) = k.info else {
934 continue;
935 };
936 to.map_mut()
937 .insert(*k, (info.resolve_inherited_any)(&**v, from));
938 to.has_inherited = true;
939 }
940 to.merge_id = combine_merge_ids(to.merge_id, from.merge_id);
941 }
942 }
943
944 pub fn apply_inherited_and_class_maps(to: &mut Rc<Style>, from: &Style) {
950 let has_inherited = from.any_inherited();
951 let has_class_maps = from.has_class_maps;
953
954 if has_inherited || has_class_maps {
955 let mut new_style = (**to).clone();
956
957 if has_inherited {
959 for (k, v) in from.map.iter().filter(|(p, _)| p.inherited()) {
960 let StyleKeyInfo::Prop(info) = k.info else {
961 continue;
962 };
963 new_style
964 .map_mut()
965 .insert(*k, (info.resolve_inherited_any)(&**v, from));
966 new_style.has_inherited = true;
967 }
968 new_style.merge_id = combine_merge_ids(new_style.merge_id, from.merge_id);
969 }
970
971 if has_class_maps {
973 let class_maps = from
974 .map
975 .iter()
976 .filter(|(k, _)| matches!(k.info, StyleKeyInfo::Class(..)));
977 new_style.apply_iter(class_maps, None);
978 new_style.merge_id = combine_merge_ids(new_style.merge_id, from.merge_id);
979 }
980
981 *to = Rc::new(new_style);
982 }
983 }
984
985 pub fn apply_only_class_maps(to: &mut Style, from: &Style) {
990 if !from.has_class_maps {
991 return;
992 }
993 let class_maps = from
994 .map
995 .iter()
996 .filter(|(k, _)| matches!(k.info, StyleKeyInfo::Class(..)));
997 to.apply_iter(class_maps, None);
998 to.merge_id = combine_merge_ids(to.merge_id, from.merge_id);
999 }
1000
1001 pub(crate) fn merge_id(&self) -> u64 {
1002 self.merge_id
1003 }
1004
1005 pub(crate) fn map_ptr(&self) -> usize {
1008 Rc::as_ptr(&self.map) as usize
1009 }
1010
1011 pub(crate) fn has_context_values(&self) -> bool {
1013 self.has_context_values
1014 }
1015
1016 pub(crate) fn has_structural_selectors(&self) -> bool {
1020 self.map.contains_key(&structural_selectors_key())
1021 }
1022
1023 pub fn class_maps_eq(&self, other: &Style) -> SmallVec<[StyleClassRef; 4]> {
1024 let mut changed = SmallVec::new();
1026 for (k, v) in self.map.iter() {
1027 let StyleKeyInfo::Class(_) = k.info else {
1028 continue;
1029 };
1030
1031 match other.map.get(k) {
1032 Some(other_v) => {
1033 let v_style = v.downcast_ref::<Style>().unwrap();
1034 let other_v_style = other_v.downcast_ref::<Style>().unwrap();
1035
1036 if v_style.merge_id != other_v_style.merge_id {
1037 changed.push(StyleClassRef { key: *k });
1038 }
1039 }
1040 None => {
1041 changed.push(StyleClassRef { key: *k });
1042 }
1043 }
1044 }
1045
1046 for k in other.map.keys() {
1048 if !matches!(k.info, StyleKeyInfo::Class(..)) {
1049 continue;
1050 }
1051
1052 if !self.map.contains_key(k) {
1053 changed.push(StyleClassRef { key: *k });
1054 }
1055 }
1056
1057 changed
1058 }
1059
1060 pub(crate) fn get_transition<P: StyleProp>(&self) -> Option<Transition> {
1061 self.map
1062 .get(&P::prop_ref().info().transition_key)
1063 .map(|v| v.downcast_ref::<Transition>().unwrap().clone())
1064 }
1065
1066 fn get_prop_from_map<P: StyleProp>(
1067 map: &FxHashMap<StyleKey, Rc<dyn Any>>,
1068 context_style: &Style,
1069 ) -> Option<P::Type> {
1070 map.get(&P::key()).and_then(
1071 |v| match v.downcast_ref::<StyleMapValue<P::Type>>().unwrap() {
1072 StyleMapValue::Animated(v) | StyleMapValue::Val(v) => Some(v.clone()),
1073 StyleMapValue::Context(context_value) => Some(context_value.resolve(context_style)),
1074 StyleMapValue::Unset => None,
1075 },
1076 )
1077 }
1078
1079 fn get_style_value_from_map<P: StyleProp>(
1080 map: &FxHashMap<StyleKey, Rc<dyn Any>>,
1081 context_style: &Style,
1082 ) -> Option<StyleValue<P::Type>> {
1083 map.get(&P::key()).map(
1084 |v| match v.downcast_ref::<StyleMapValue<P::Type>>().unwrap() {
1085 StyleMapValue::Val(v) => StyleValue::Val(v.clone()),
1086 StyleMapValue::Animated(v) => StyleValue::Animated(v.clone()),
1087 StyleMapValue::Context(v) => StyleValue::Val(v.resolve(context_style)),
1088 StyleMapValue::Unset => StyleValue::Unset,
1089 },
1090 )
1091 }
1092
1093 pub(crate) fn get_prop_or_default<P: StyleProp>(&self) -> P::Type {
1094 self.get_prop::<P>().unwrap_or_else(|| P::default_value())
1095 }
1096
1097 pub(crate) fn get_prop<P: StyleProp>(&self) -> Option<P::Type> {
1098 Self::get_prop_from_map::<P>(&self.map, self).or_else(|| {
1099 self.inherited_context
1100 .as_ref()
1101 .and_then(|map| Self::get_prop_from_map::<P>(map, self))
1102 })
1103 }
1104
1105 pub(crate) fn get_prop_style_value<P: StyleProp>(&self) -> StyleValue<P::Type> {
1106 Self::get_style_value_from_map::<P>(&self.map, self)
1107 .or_else(|| {
1108 self.inherited_context
1109 .as_ref()
1110 .and_then(|map| Self::get_style_value_from_map::<P>(map, self))
1111 })
1112 .unwrap_or(StyleValue::Base)
1113 }
1114
1115 pub(crate) fn style_props(&self) -> impl Iterator<Item = StylePropRef> + '_ {
1116 self.map.keys().filter_map(|p| match p.info {
1117 StyleKeyInfo::Prop(..) => Some(StylePropRef { key: *p }),
1118 _ => None,
1119 })
1120 }
1121
1122 pub(crate) fn selectors(&self) -> StyleSelectors {
1123 self.cached_selectors
1124 }
1125
1126 #[cfg(debug_assertions)]
1128 fn compute_selectors_slow(&self) -> StyleSelectors {
1129 let mut result = StyleSelectors::empty();
1130
1131 for (k, v) in self.map.iter() {
1132 match k.info {
1133 StyleKeyInfo::Selector(selector) => {
1134 result = result
1135 .union(*selector)
1136 .union(v.downcast_ref::<Style>().unwrap().selectors());
1137 }
1138 StyleKeyInfo::StructuralSelectors => {
1139 let rules = &v.downcast_ref::<StructuralSelectors>().unwrap().0;
1140 for (_, nested_style) in rules {
1141 result = result.union(nested_style.as_ref().selectors());
1142 }
1143 }
1144 StyleKeyInfo::ResponsiveSelectors => {
1145 result = result.responsive();
1146 let rules = &v.downcast_ref::<ResponsiveSelectors>().unwrap().0;
1147 for (_, nested_style) in rules {
1148 result = result.union(nested_style.as_ref().selectors());
1149 }
1150 }
1151 StyleKeyInfo::DebugGroup(..) => {}
1152 _ => {}
1153 }
1154 }
1155
1156 result
1157 }
1158
1159 pub fn apply_class<C: StyleClass>(mut self, _class: C) -> Style {
1160 if let Some(map) = self.map.get(&C::key()).cloned() {
1161 self.apply_mut(map.downcast_ref::<Style>().unwrap());
1162 }
1163 self
1164 }
1165
1166 pub fn apply_selectors(mut self, selectors: &[StyleSelector]) -> Style {
1167 for selector in selectors {
1168 if let Some(map) = self.get_nested_map(selector.to_key()) {
1169 let resolved = map.apply_selectors(selectors);
1170 self.apply_mut(&resolved);
1171 }
1172 }
1173 if self.get(Selected)
1174 && let Some(map) = self.get_nested_map(StyleSelector::Selected.to_key())
1175 {
1176 let resolved = map.apply_selectors(&[StyleSelector::Selected]);
1177 self.apply_mut(&resolved);
1178 }
1179 self
1180 }
1181
1182 pub fn with<P: StyleProp>(self, f: impl FnOnce(ExprStyle, ContextRef<P>) -> ExprStyle) -> Self {
1188 f(ExprStyle { style: self }, ContextRef::default()).style
1189 }
1190
1191 pub(crate) fn get_nested_map(&self, key: StyleKey) -> Option<Style> {
1192 self.map
1193 .get(&key)
1194 .map(|map| map.downcast_ref::<Style>().unwrap().clone())
1195 }
1196
1197 pub(crate) fn debug_group_enabled(&self, key: StyleKey) -> bool {
1198 self.map
1199 .get(&key)
1200 .and_then(|value| value.downcast_ref::<bool>().copied())
1201 .unwrap_or(false)
1202 }
1203
1204 pub(crate) fn remove_nested_map(&mut self, key: StyleKey) -> Option<Style> {
1205 let removed = self.map_mut().remove(&key).map(take_any::<Style>);
1206 if removed.is_some() {
1207 self.merge_id = next_style_merge_id();
1208 }
1209 removed
1210 }
1211
1212 pub(crate) fn any_inherited(&self) -> bool {
1216 self.has_inherited
1217 }
1218
1219 pub(crate) fn inherited(&self) -> Style {
1220 let mut new = Style::new();
1221 if self.any_inherited() {
1222 let inherited = self.map.iter().filter(|(p, _)| p.inherited());
1223
1224 new.apply_iter(inherited, None);
1225 new.merge_id = combine_merge_ids(new.merge_id, self.merge_id);
1226 }
1227 new
1228 }
1229
1230 fn set_selector(&mut self, selector: StyleSelector, map: Style) {
1231 self.set_map_selector(selector.to_key(), map)
1232 }
1233
1234 fn set_structural_selector(&mut self, selector: StructuralSelector, map: Style) {
1235 self.cached_selectors |= map.cached_selectors;
1236 let key = structural_selectors_key();
1237 let mut rules = self
1238 .map_mut()
1239 .remove(&key)
1240 .map(|current| take_any::<StructuralSelectors>(current).0)
1241 .unwrap_or_default();
1242 rules.push((selector, Rc::new(map)));
1243 self.map_mut()
1244 .insert(key, Rc::new(StructuralSelectors(rules)));
1245 self.merge_id = next_style_merge_id();
1246 }
1247
1248 fn set_responsive_selector(&mut self, selector: ResponsiveSelector, map: Style) {
1249 self.cached_selectors |= StyleSelectors::RESPONSIVE;
1250 self.cached_selectors |= map.cached_selectors;
1251 let key = responsive_selectors_key();
1252 let mut rules = self
1253 .map_mut()
1254 .remove(&key)
1255 .map(|current| take_any::<ResponsiveSelectors>(current).0)
1256 .unwrap_or_default();
1257 rules.push((selector, Rc::new(map)));
1258 self.map_mut()
1259 .insert(key, Rc::new(ResponsiveSelectors(rules)));
1260 self.merge_id = next_style_merge_id();
1261 }
1262
1263 fn set_map_selector(&mut self, key: StyleKey, map: Style) {
1264 if let StyleKeyInfo::Selector(sel) = key.info {
1266 self.cached_selectors |= *sel;
1267 self.cached_selectors |= map.cached_selectors;
1268 }
1269 let value = if let Some(current) = self.map_mut().remove(&key) {
1270 let mut current: Style = take_any(current);
1271 current.apply_mut(&map);
1272 Rc::new(current)
1273 } else {
1274 Rc::new(map)
1275 };
1276 self.map_mut().insert(key, value);
1277 self.merge_id = next_style_merge_id();
1278 }
1279
1280 fn set_class(&mut self, class: StyleClassRef, map: Style) {
1281 self.has_class_maps = true;
1282 self.set_map_selector(class.key, map)
1283 }
1284
1285 pub fn debug_group<G: StyleDebugGroup>(mut self, _group: G) -> Self {
1286 self.map_mut().insert(G::key(), Rc::new(true));
1287 self.merge_id = next_style_merge_id();
1288 self
1289 }
1290
1291 pub fn unset_debug_group<G: StyleDebugGroup>(mut self, _group: G) -> Self {
1292 self.map_mut().insert(G::key(), Rc::new(false));
1293 self.merge_id = next_style_merge_id();
1294 self
1295 }
1296
1297 pub fn builtin(&self) -> BuiltinStyle<'_> {
1298 BuiltinStyle { style: self }
1299 }
1300
1301 pub(crate) fn apply_iter<'a>(
1302 &mut self,
1303 iter: impl Iterator<Item = (&'a StyleKey, &'a Rc<dyn Any>)>,
1304 source_effect_context: Option<Rc<dyn floem_reactive::EffectTrait>>,
1305 ) {
1306 if self.effect_context.is_none() && source_effect_context.is_some() {
1307 self.effect_context = source_effect_context;
1308 }
1309 for (k, v) in iter {
1310 match k.info {
1311 StyleKeyInfo::Class(..) | StyleKeyInfo::Selector(..) => {
1312 if matches!(k.info, StyleKeyInfo::Class(..)) {
1314 self.has_class_maps = true;
1315 }
1316 if let StyleKeyInfo::Selector(sel) = k.info {
1318 self.cached_selectors |= *sel;
1319 if let Some(nested) = v.downcast_ref::<Style>() {
1320 self.cached_selectors |= nested.cached_selectors;
1321 }
1322 }
1323 if let Some(existing_rc) = self.map_mut().remove(k) {
1324 if Rc::ptr_eq(&existing_rc, v) {
1325 self.map_mut().insert(*k, existing_rc);
1326 continue;
1327 }
1328
1329 let mut current: Style = take_any(existing_rc);
1330 current.apply_mut(v.downcast_ref::<Style>().unwrap());
1331 self.map_mut().insert(*k, Rc::new(current));
1332 } else {
1333 self.map_mut().insert(*k, v.clone());
1334 }
1335 }
1336 StyleKeyInfo::StructuralSelectors => {
1337 let rules = &v.downcast_ref::<StructuralSelectors>().unwrap().0;
1339 for (_, nested) in rules {
1340 self.cached_selectors |= nested.cached_selectors;
1341 }
1342 let merged = if let Some(current) = self.map_mut().remove(k) {
1343 let new_rules = &v.downcast_ref::<StructuralSelectors>().unwrap().0;
1344 let current: StructuralSelectors = take_any(current);
1345 let mut merged: StructuralSelectorRules = current.0;
1346 merged.extend(new_rules.iter().cloned());
1347 Rc::new(StructuralSelectors(merged))
1348 } else {
1349 v.clone()
1350 };
1351 self.map_mut().insert(*k, merged);
1352 }
1353 StyleKeyInfo::ResponsiveSelectors => {
1354 self.cached_selectors |= StyleSelectors::RESPONSIVE;
1355 let rules = &v.downcast_ref::<ResponsiveSelectors>().unwrap().0;
1357 for (_, nested) in rules {
1358 self.cached_selectors |= nested.cached_selectors;
1359 }
1360 let merged = if let Some(current) = self.map_mut().remove(k) {
1361 let new_rules = &v.downcast_ref::<ResponsiveSelectors>().unwrap().0;
1362 let current: ResponsiveSelectors = take_any(current);
1363 let mut merged: ResponsiveSelectorRules = current.0;
1364 merged.extend(new_rules.iter().cloned());
1365 Rc::new(ResponsiveSelectors(merged))
1366 } else {
1367 v.clone()
1368 };
1369 self.map_mut().insert(*k, merged);
1370 }
1371 StyleKeyInfo::DeferredEffects => {
1372 let merged = if let Some(current) = self.map_mut().remove(k) {
1373 let mut current: Vec<DeferredStyleEffect> = take_any(current);
1374 current.extend(
1375 v.downcast_ref::<Vec<DeferredStyleEffect>>()
1376 .unwrap()
1377 .iter()
1378 .cloned(),
1379 );
1380 Rc::new(current)
1381 } else {
1382 v.clone()
1383 };
1384 self.map_mut().insert(*k, merged);
1385 }
1386 StyleKeyInfo::Transition | StyleKeyInfo::DebugGroup(..) => {
1387 self.map_mut().insert(*k, v.clone());
1388 }
1389 StyleKeyInfo::Prop(info) => {
1390 if info.inherited {
1392 self.has_inherited = true;
1393 }
1394 self.map_mut().insert(*k, v.clone());
1395 }
1396 }
1397 }
1398 }
1399
1400 pub(crate) fn apply_mut(&mut self, over: &Style) {
1401 if self.merge_id == over.merge_id {
1403 return;
1404 }
1405 let over_merge_id = over.merge_id;
1406 let effect_context = over.effect_context.clone();
1407 self.apply_iter(over.map.iter(), effect_context);
1408 self.has_context_values |= over.has_context_values;
1409 self.merge_id = combine_merge_ids(self.merge_id, over_merge_id);
1410 }
1411
1412 pub fn apply(mut self, over: Style) -> Style {
1419 self.apply_mut(&over);
1420 self
1421 }
1422
1423 pub fn map(self, over: impl FnOnce(Self) -> Self) -> Self {
1424 over(self)
1425 }
1426
1427 pub fn apply_overriding_styles(self, overrides: impl Iterator<Item = Style>) -> Style {
1430 overrides.fold(self, |acc, x| acc.apply(x))
1431 }
1432}
1433
1434impl Debug for Style {
1435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1436 f.debug_struct("Style")
1437 .field(
1438 "map",
1439 &self
1440 .map
1441 .iter()
1442 .map(|(p, v)| (*p, (p.debug_any(&**v))))
1443 .collect::<HashMap<StyleKey, String>>(),
1444 )
1445 .finish()
1446 }
1447}
1448
1449style_key_selector!(
1450 hover,
1451 StyleSelectors::empty().set_selector(StyleSelector::Hover, true)
1452);
1453style_key_selector!(
1454 file_hover,
1455 StyleSelectors::empty().set_selector(StyleSelector::FileHover, true)
1456);
1457style_key_selector!(
1458 focus,
1459 StyleSelectors::empty().set_selector(StyleSelector::Focus, true)
1460);
1461style_key_selector!(
1462 focus_visible,
1463 StyleSelectors::empty().set_selector(StyleSelector::FocusVisible, true)
1464);
1465style_key_selector!(
1466 focus_within,
1467 StyleSelectors::empty().set_selector(StyleSelector::FocusWithin, true)
1468);
1469style_key_selector!(
1470 disabled,
1471 StyleSelectors::empty().set_selector(StyleSelector::Disabled, true)
1472);
1473style_key_selector!(
1474 active,
1475 StyleSelectors::empty().set_selector(StyleSelector::Active, true)
1476);
1477style_key_selector!(
1478 dragging,
1479 StyleSelectors::empty().set_selector(StyleSelector::Dragging, true)
1480);
1481style_key_selector!(
1482 selected,
1483 StyleSelectors::empty().set_selector(StyleSelector::Selected, true)
1484);
1485style_key_selector!(
1486 darkmode,
1487 StyleSelectors::empty().set_selector(StyleSelector::DarkMode, true)
1488);
1489
1490impl StyleSelector {
1491 fn to_key(self) -> StyleKey {
1492 match self {
1493 StyleSelector::Hover => hover(),
1494 StyleSelector::Focus => focus(),
1495 StyleSelector::FocusVisible => focus_visible(),
1496 StyleSelector::FocusWithin => focus_within(),
1497 StyleSelector::Disabled => disabled(),
1498 StyleSelector::Active => active(),
1499 StyleSelector::Dragging => dragging(),
1500 StyleSelector::Selected => selected(),
1501 StyleSelector::DarkMode => darkmode(),
1502 StyleSelector::FileHover => file_hover(),
1503 }
1504 }
1505}
1506
1507macro_rules! define_builtin_props {
1534 (
1535 $(
1536 $(#[$meta:meta])*
1537 $type_name:ident $name:ident $({ $($flags:ident),* })? :
1538 $typ:ty $( [$inner:ty] )? { $($options:tt)* } = $val:expr
1539 ),*
1540 $(,)?
1541 ) => {
1542 $(
1543 prop!($(#[$meta])* pub $type_name: $typ { $($options)* } = $val);
1544 )*
1545 impl Style {
1546 $(
1547 define_builtin_props!(decl: $(#[$meta])* $type_name $name $({ $($flags),* })? : $typ $( [$inner] )? = $val);
1548 )*
1549 $(
1550 define_builtin_props!(unset: $(#[$meta])* $type_name $name);
1551 )*
1552 $(
1553 define_builtin_props!(transition: $(#[$meta])* $type_name $name $({ $($flags),* })?);
1554 )*
1555 }
1556 impl BuiltinStyle<'_> {
1557 $(
1558 $(#[$meta])*
1559 pub fn $name(&self) -> $typ {
1560 self.style.get($type_name)
1561 }
1562 )*
1563 }
1564 impl ExprStyle {
1565 $(
1566 define_builtin_props!(expr_decl: $(#[$meta])* $type_name $name $({ $($flags),* })? : $typ $( [$inner] )? = $val);
1567 )*
1568 $(
1569 define_builtin_props!(expr_unset: $(#[$meta])* $type_name $name);
1570 )*
1571 }
1572 };
1573
1574 (decl: $(#[$meta:meta])* $type_name:ident $name:ident { $($flags:ident),* } : $typ:ty [$inner:ty] = $val:expr) => {
1576 define_builtin_props!(@opt_check_nocb $(#[$meta])* $type_name $name [$($flags)*]: $inner);
1577 };
1578 (decl: $(#[$meta:meta])* $type_name:ident $name:ident : $typ:ty [$inner:ty] = $val:expr) => {
1579 $(#[$meta])*
1580 pub fn $name(self, v: impl Into<$inner>) -> Self {
1581 self.set($type_name, Some(v.into()))
1582 }
1583 };
1584 (decl: $(#[$meta:meta])* $type_name:ident $name:ident { $($flags:ident),* } : $typ:ty = $val:expr) => {
1585 define_builtin_props!(@check_nocb $(#[$meta])* $type_name $name [$($flags)*]: $typ);
1586 };
1587 (decl: $(#[$meta:meta])* $type_name:ident $name:ident : $typ:ty = $val:expr) => {
1588 $(#[$meta])*
1589 pub fn $name(self, v: impl Into<$typ>) -> Self {
1590 self.set($type_name, v.into())
1591 }
1592 };
1593
1594 (expr_decl: $(#[$meta:meta])* $type_name:ident $name:ident { $($flags:ident),* } : $typ:ty [$inner:ty] = $val:expr) => {
1595 define_builtin_props!(@opt_check_nocb_expr $(#[$meta])* $type_name $name [$($flags)*]: $inner);
1596 };
1597 (expr_decl: $(#[$meta:meta])* $type_name:ident $name:ident : $typ:ty [$inner:ty] = $val:expr) => {
1598 $(#[$meta])*
1599 pub fn $name<T>(self, v: $crate::style::ContextValue<T>) -> Self
1600 where
1601 T: Into<$inner> + 'static,
1602 {
1603 self.set($type_name, v.map(|x| Some(x.into())))
1604 }
1605 };
1606 (expr_decl: $(#[$meta:meta])* $type_name:ident $name:ident { $($flags:ident),* } : $typ:ty = $val:expr) => {
1607 define_builtin_props!(@check_nocb_expr $(#[$meta])* $type_name $name [$($flags)*]: $typ);
1608 };
1609 (expr_decl: $(#[$meta:meta])* $type_name:ident $name:ident : $typ:ty = $val:expr) => {
1610 $(#[$meta])*
1611 pub fn $name<T>(self, v: $crate::style::ContextValue<T>) -> Self
1612 where
1613 T: Into<$typ> + 'static,
1614 {
1615 self.set($type_name, v.map(Into::into))
1616 }
1617 };
1618
1619 (@opt_check_nocb $(#[$meta:meta])* $type_name:ident $name:ident [nocb $($rest:ident)*]: $inner:ty) => {};
1620 (@opt_check_nocb $(#[$meta:meta])* $type_name:ident $name:ident [$first:ident $($rest:ident)*]: $inner:ty) => {
1621 define_builtin_props!(@opt_check_nocb $(#[$meta])* $type_name $name [$($rest)*]: $inner);
1622 };
1623 (@opt_check_nocb $(#[$meta:meta])* $type_name:ident $name:ident []: $inner:ty) => {
1624 $(#[$meta])*
1625 pub fn $name(self, v: impl Into<$inner>) -> Self {
1626 self.set($type_name, Some(v.into()))
1627 }
1628 };
1629
1630 (@opt_check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident [nocb $($rest:ident)*]: $inner:ty) => {};
1631 (@opt_check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident [$first:ident $($rest:ident)*]: $inner:ty) => {
1632 define_builtin_props!(@opt_check_nocb_expr $(#[$meta])* $type_name $name [$($rest)*]: $inner);
1633 };
1634 (@opt_check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident []: $inner:ty) => {
1635 $(#[$meta])*
1636 pub fn $name<T>(self, v: $crate::style::ContextValue<T>) -> Self
1637 where
1638 T: Into<$inner> + 'static,
1639 {
1640 self.set($type_name, v.map(|x| Some(x.into())))
1641 }
1642 };
1643
1644 (@check_nocb $(#[$meta:meta])* $type_name:ident $name:ident [nocb $($rest:ident)*]: $typ:ty) => {};
1649 (@check_nocb $(#[$meta:meta])* $type_name:ident $name:ident [$first:ident $($rest:ident)*]: $typ:ty) => {
1650 define_builtin_props!(@check_nocb $(#[$meta])* $type_name $name [$($rest)*]: $typ);
1651 };
1652 (@check_nocb $(#[$meta:meta])* $type_name:ident $name:ident []: $typ:ty) => {
1653 $(#[$meta])*
1654 pub fn $name(self, v: impl Into<$typ>) -> Self {
1655 self.set($type_name, v.into())
1656 }
1657 };
1658
1659 (@check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident [nocb $($rest:ident)*]: $typ:ty) => {};
1660 (@check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident [$first:ident $($rest:ident)*]: $typ:ty) => {
1661 define_builtin_props!(@check_nocb_expr $(#[$meta])* $type_name $name [$($rest)*]: $typ);
1662 };
1663 (@check_nocb_expr $(#[$meta:meta])* $type_name:ident $name:ident []: $typ:ty) => {
1664 $(#[$meta])*
1665 pub fn $name<T>(self, v: $crate::style::ContextValue<T>) -> Self
1666 where
1667 T: Into<$typ> + 'static,
1668 {
1669 self.set($type_name, v.map(Into::into))
1670 }
1671 };
1672
1673 (unset: $(#[$meta:meta])* $type_name:ident $name:ident) => {
1678 paste::paste! {
1679 #[doc = "Unsets the `" $name "` property."]
1680 pub fn [<unset_ $name>](self) -> Self {
1681 self.set_style_value($type_name, $crate::style::StyleValue::Unset)
1682 }
1683 }
1684 };
1685
1686 (expr_unset: $(#[$meta:meta])* $type_name:ident $name:ident) => {
1687 paste::paste! {
1688 #[doc = "Unsets the `" $name "` property."]
1689 pub fn [<unset_ $name>](self) -> Self {
1690 self.set($type_name, $crate::style::StyleValue::Unset)
1691 }
1692 }
1693 };
1694
1695 (transition: $(#[$meta:meta])* $type_name:ident $name:ident { $($flags:ident),* }) => {
1701 define_builtin_props!(@check_tr $(#[$meta])* $type_name $name [$($flags)*]);
1702 };
1703 (transition: $(#[$meta:meta])* $type_name:ident $name:ident) => {};
1705
1706 (@check_tr $(#[$meta:meta])* $type_name:ident $name:ident [tr $($rest:ident)*]) => {
1707 paste::paste! {
1708 #[doc = "Sets a transition for the `" $name "` property."]
1709 $(#[$meta])*
1710 pub fn [<transition_ $name>](self, transition: impl Into<Transition>) -> Self {
1711 self.transition($type_name, transition.into())
1712 }
1713 }
1714 };
1715 (@check_tr $(#[$meta:meta])* $type_name:ident $name:ident [$first:ident $($rest:ident)*]) => {
1716 define_builtin_props!(@check_tr $(#[$meta])* $type_name $name [$($rest)*]);
1717 };
1718 (@check_tr $(#[$meta:meta])* $type_name:ident $name:ident []) => {};
1719}
1720
1721pub struct BuiltinStyle<'a> {
1722 style: &'a Style,
1723}
1724
1725define_builtin_props!(
1726 DisplayProp display {}: Display {} = Display::Flex,
1730
1731 PositionProp position {}: Position {} = Position::Relative,
1735
1736 IsFixed is_fixed {}: bool {} = false,
1746
1747 Width width {tr}: LengthAuto {} = LengthAuto::Auto,
1751
1752 Height height {tr}: LengthAuto {} = LengthAuto::Auto,
1756
1757 MinWidth min_width {tr}: LengthAuto {} = LengthAuto::Auto,
1761
1762 MinHeight min_height {tr}: LengthAuto {} = LengthAuto::Auto,
1766
1767 MaxWidth max_width {tr}: LengthAuto {} = LengthAuto::Auto,
1771
1772 MaxHeight max_height {tr}: LengthAuto {} = LengthAuto::Auto,
1776
1777 FlexDirectionProp flex_direction {}: FlexDirection {} = FlexDirection::Row,
1781
1782 FlexWrapProp flex_wrap {}: FlexWrap {} = FlexWrap::NoWrap,
1786
1787 FlexGrow flex_grow {}: f32 {} = 0.0,
1791
1792 FlexShrink flex_shrink {}: f32 {} = 1.0,
1796
1797 FlexBasis flex_basis {tr}: LengthAuto {} = LengthAuto::Auto,
1801
1802 JustifyContentProp justify_content {}: Option<JustifyContent> [JustifyContent] {} = None,
1806
1807 JustifyItemsProp justify_items {}: Option<JustifyItems> [JustifyItems] {} = None,
1811
1812 BoxSizingProp box_sizing {}: Option<BoxSizing> [BoxSizing] {} = None,
1816
1817 JustifySelf justify_self {}: Option<AlignItems> [AlignItems] {} = None,
1821
1822 AlignItemsProp align_items {}: Option<AlignItems> [AlignItems] {} = None,
1826
1827 AlignContentProp align_content {}: Option<AlignContent> [AlignContent] {} = None,
1831
1832 GridTemplateRows grid_template_rows {}: Vec<GridTemplateComponent<String>> {} = Vec::new(),
1836
1837 GridTemplateColumns grid_template_columns {}: Vec<GridTemplateComponent<String>> {} = Vec::new(),
1841
1842 GridAutoRows grid_auto_rows {}: Vec<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> {} = Vec::new(),
1846
1847 GridAutoColumns grid_auto_columns {}: Vec<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> {} = Vec::new(),
1851
1852 GridAutoFlow grid_auto_flow {}: taffy::GridAutoFlow {} = taffy::GridAutoFlow::Row,
1856
1857 GridRow grid_row {}: Line<GridPlacement> {} = Line::default(),
1861
1862 GridColumn grid_column {}: Line<GridPlacement> {} = Line::default(),
1866
1867 AlignSelf align_self {}: Option<AlignItems> [AlignItems] {} = None,
1871
1872 OutlineColor outline_color {tr}: Brush {} = Brush::Solid(palette::css::TRANSPARENT),
1876
1877 Outline outline {nocb, tr}: Stroke {} = Stroke::new(0.),
1881
1882 OutlineProgress outline_progress {tr}: Pct {} = Pct(100.),
1886
1887 BorderProgress border_progress {tr}: Pct {} = Pct(100.),
1891
1892 BorderLeft border_left {nocb, tr}: Stroke {} = Stroke::new(0.),
1894 BorderTop border_top {nocb, tr}: Stroke {} = Stroke::new(0.),
1896 BorderRight border_right {nocb, tr}: Stroke {} = Stroke::new(0.),
1898 BorderBottom border_bottom {nocb, tr}: Stroke {} = Stroke::new(0.),
1900
1901 BorderLeftColor border_left_color { tr }: Option<Brush> [Brush] {} = None,
1903 BorderTopColor border_top_color { tr }: Option<Brush> [Brush] {} = None,
1905 BorderRightColor border_right_color { tr }: Option<Brush> [Brush] {} = None,
1907 BorderBottomColor border_bottom_color { tr }: Option<Brush> [Brush] {} = None,
1909
1910 BorderTopLeftRadius border_top_left_radius { tr }: Length {} = Length::Pt(0.),
1912 BorderTopRightRadius border_top_right_radius { tr }: Length {} = Length::Pt(0.),
1914 BorderBottomLeftRadius border_bottom_left_radius { tr }: Length {} = Length::Pt(0.),
1916 BorderBottomRightRadius border_bottom_right_radius { tr }: Length {} = Length::Pt(0.),
1918
1919 PaddingLeft padding_left { tr }: Length {} = Length::Pt(0.),
1921 PaddingTop padding_top { tr }: Length {} = Length::Pt(0.),
1923 PaddingRight padding_right { tr }: Length {} = Length::Pt(0.),
1925 PaddingBottom padding_bottom { tr }: Length {} = Length::Pt(0.),
1927
1928 MarginLeft margin_left { tr }: LengthAuto {} = LengthAuto::Pt(0.),
1930 MarginTop margin_top { tr }: LengthAuto {} = LengthAuto::Pt(0.),
1932 MarginRight margin_right { tr }: LengthAuto {} = LengthAuto::Pt(0.),
1934 MarginBottom margin_bottom { tr }: LengthAuto {} = LengthAuto::Pt(0.),
1936
1937 InsetLeft inset_left {tr}: LengthAuto {} = LengthAuto::Auto,
1939
1940 InsetTop inset_top {tr}: LengthAuto {} = LengthAuto::Auto,
1942
1943 InsetRight inset_right {tr}: LengthAuto {} = LengthAuto::Auto,
1945
1946 InsetBottom inset_bottom {tr}: LengthAuto {} = LengthAuto::Auto,
1948
1949 PointerEventsProp pointer_events {}: Option<PointerEvents> [PointerEvents] { inherited } = None,
1953
1954 ZIndex z_index { tr }: Option<i32> [i32] {} = None,
1961
1962 Cursor cursor { }: Option<CursorStyle> [CursorStyle] {} = None,
1966
1967 TextColor color { tr }: Option<Color> [Color] { inherited } = None,
1971
1972 Background background { tr }: Option<Brush> [Brush] {} = None,
1976
1977 Foreground foreground { tr }: Option<Brush> [Brush] {} = None,
1981
1982 BoxShadowProp box_shadow { tr }: SmallVec<[BoxShadow; 3]> {} = SmallVec::new(),
1986
1987 FontSize font_size { nocb, tr }: f64 { inherited } = 14.,
1991
1992 FontFamily font_family { }: Option<String> [String] { inherited } = None,
1996
1997 FontWeight font_weight { }: Option<FontWeightProp> [FontWeightProp] { inherited } = None,
2001
2002 FontStyle font_style { }: Option<crate::text::FontStyle> [crate::text::FontStyle] { inherited } = None,
2006
2007 CursorColor cursor_color { tr }: Brush {} = Brush::Solid(palette::css::BLACK.with_alpha(0.3)),
2011
2012 SelectionCornerRadius selection_corer_radius { nocb, tr }: f64 {} = 1.,
2016
2017 Selectable selectable {}: bool { inherited } = true,
2022
2023 TextOverflowProp text_overflow {}: TextOverflow { inherited } = TextOverflow::NoWrap(NoWrapOverflow::Clip),
2027
2028 TextAlignProp text_align {}: Option<crate::text::Alignment> [crate::text::Alignment] {} = None,
2032
2033 LineHeight line_height { tr }: LineHeightValue { inherited } = LineHeightValue::Normal(1.),
2037
2038 AspectRatio aspect_ratio {tr}: Option<f32> [f32] {} = None,
2042
2043 ObjectFitProp object_fit {}: ObjectFit {} = ObjectFit::Fill,
2049
2050 ObjectPositionProp object_position {}: ObjectPosition {} = ObjectPosition::Center,
2055
2056 ColGap col_gap { tr }: Length {} = Length::Pt(0.),
2060
2061 RowGap row_gap { tr }: Length {} = Length::Pt(0.),
2065
2066 ScrollbarWidth scrollbar_width {tr}: Pt {} = Pt(8.),
2088
2089 OverflowX overflow_x {}: Overflow {} = Overflow::default(),
2091
2092 OverflowY overflow_y {}: Overflow {} = Overflow::default(),
2094
2095 ScaleX scale_x {tr}: Pct {} = Pct(100.),
2102
2103 ScaleY scale_y {tr}: Pct {} = Pct(100.),
2110
2111 TranslateX translate_x {tr}: Length {} = Length::Pt(0.),
2118
2119 TranslateY translate_y {tr}: Length {} = Length::Pt(0.),
2126
2127 Rotation rotate {tr}: Angle {} = Angle::Rad(0.0),
2135
2136 RotateAbout rotate_about {}: AnchorAbout {} = AnchorAbout::CENTER,
2142
2143 ScaleAbout scale_about {tr}: AnchorAbout {} = AnchorAbout::CENTER,
2150
2151 Transform transform {tr}: Affine {} = Affine::IDENTITY,
2177
2178 Opacity opacity {tr}: f32 {} = 1.0,
2183
2184 Selected set_selected {}: bool { inherited } = false,
2188
2189 Disabled set_disabled {}: bool { inherited } = false,
2193
2194 Focusable set_focus {}: Focus { } = Focus::None,
2196);
2197
2198prop_extractor! {
2199 pub FontProps {
2200 pub size: FontSize,
2201 pub family: FontFamily,
2202 pub weight: FontWeight,
2203 pub style: FontStyle,
2204 }
2205}
2206
2207prop_extractor! {
2208 pub(crate) LayoutProps {
2209 pub border_left: BorderLeft,
2211 pub border_top: BorderTop,
2212 pub border_right: BorderRight,
2213 pub border_bottom: BorderBottom,
2214
2215 pub padding_left: PaddingLeft,
2216 pub padding_top: PaddingTop,
2217 pub padding_right: PaddingRight,
2218 pub padding_bottom: PaddingBottom,
2219
2220 pub margin_left: MarginLeft,
2221 pub margin_top: MarginTop,
2222 pub margin_right: MarginRight,
2223 pub margin_bottom: MarginBottom,
2224
2225 pub width: Width,
2226 pub height: Height,
2227
2228 pub min_width: MinWidth,
2229 pub min_height: MinHeight,
2230
2231 pub max_width: MaxWidth,
2232 pub max_height: MaxHeight,
2233
2234 pub flex_grow: FlexGrow,
2235 pub flex_shrink: FlexShrink,
2236 pub flex_basis: FlexBasis ,
2237
2238 pub inset_left: InsetLeft,
2239 pub inset_top: InsetTop,
2240 pub inset_right: InsetRight,
2241 pub inset_bottom: InsetBottom,
2242
2243 pub row_gap: RowGap,
2244 pub col_gap: ColGap,
2245
2246 pub font_size: FontSize,
2248 pub line_height: LineHeight,
2249 }
2250}
2251
2252prop_extractor! {
2253 pub TransformProps {
2255 pub scale_x: ScaleX,
2256 pub scale_y: ScaleY,
2257
2258 pub translate_x: TranslateX,
2259 pub translate_y: TranslateY,
2260
2261 pub rotation: Rotation,
2262 pub rotate_about: RotateAbout,
2263 pub scale_about: ScaleAbout,
2264
2265 pub transform: Transform,
2266
2267 pub overflow_x: OverflowX,
2268 pub overflow_y: OverflowY,
2269 pub border_top_left_radius: BorderTopLeftRadius,
2270 pub border_top_right_radius: BorderTopRightRadius,
2271 pub border_bottom_left_radius: BorderBottomLeftRadius,
2272 pub border_bottom_right_radius: BorderBottomRightRadius,
2273 }
2274}
2275impl TransformProps {
2276 pub fn border_radius(&self) -> BorderRadius {
2277 BorderRadius {
2278 top_left: Some(self.border_top_left_radius()),
2279 top_right: Some(self.border_top_right_radius()),
2280 bottom_left: Some(self.border_bottom_left_radius()),
2281 bottom_right: Some(self.border_bottom_right_radius()),
2282 }
2283 }
2284
2285 pub fn affine(&self, size: kurbo::Size, resolve_cx: &FontSizeCx) -> Affine {
2286 let mut result = Affine::IDENTITY;
2287 let transform_x = self.translate_x().resolve(size.width, resolve_cx);
2292 let transform_y = self.translate_y().resolve(size.height, resolve_cx);
2293 result *= Affine::translate(Vec2 {
2294 x: transform_x,
2295 y: transform_y,
2296 });
2297
2298 let rotation = self.rotation().to_radians();
2300 if rotation != 0.0 {
2301 let rotate_about = self.rotate_about();
2302 let (rotate_x_frac, rotate_y_frac) = rotate_about.as_fractions();
2303 let rotate_point = Vec2 {
2304 x: rotate_x_frac * size.width,
2305 y: rotate_y_frac * size.height,
2306 };
2307 result *= Affine::translate(rotate_point)
2308 * Affine::rotate(rotation)
2309 * Affine::translate(-rotate_point);
2310 }
2311
2312 let scale_x = self.scale_x().0 / 100.;
2314 let scale_y = self.scale_y().0 / 100.;
2315 if scale_x != 1.0 || scale_y != 1.0 {
2316 let scale_about = self.scale_about();
2317 let (scale_x_frac, scale_y_frac) = scale_about.as_fractions();
2318 let scale_point = Vec2 {
2319 x: scale_x_frac * size.width,
2320 y: scale_y_frac * size.height,
2321 };
2322 result *= Affine::translate(scale_point)
2323 * Affine::scale_non_uniform(scale_x, scale_y)
2324 * Affine::translate(-scale_point);
2325 }
2326
2327 result *= self.transform();
2329 result
2330 }
2331
2332 pub fn clip_rect(
2333 &self,
2334 mut local_rect: kurbo::Rect,
2335 resolve_cx: &FontSizeCx,
2336 ) -> Option<RoundedRect> {
2337 use Overflow::*;
2338
2339 let (overflow_x, overflow_y) = (self.overflow_x(), self.overflow_y());
2340
2341 if overflow_x == Visible && overflow_y == Visible {
2343 return None;
2344 }
2345
2346 let border_radius = self
2347 .border_radius()
2348 .resolve_border_radii(local_rect.size().min_side(), resolve_cx);
2349
2350 if overflow_x == Visible {
2352 local_rect.x0 = f64::NEG_INFINITY;
2353 local_rect.x1 = f64::INFINITY;
2354 }
2355 if overflow_y == Visible {
2356 local_rect.y0 = f64::NEG_INFINITY;
2357 local_rect.y1 = f64::INFINITY;
2358 }
2359
2360 Some(RoundedRect::from_rect(local_rect, border_radius))
2361 }
2362}
2363
2364impl LayoutProps {
2365 pub fn border(&self) -> Border {
2366 Border {
2367 left: Some(self.border_left()),
2368 top: Some(self.border_top()),
2369 right: Some(self.border_right()),
2370 bottom: Some(self.border_bottom()),
2371 }
2372 }
2373
2374 pub fn font_size_cx(&self) -> FontSizeCx {
2375 {
2376 let font_size = self.font_size();
2377 let line_height = self.line_height();
2378 let line_height = line_height.resolve(font_size as f32);
2379 FontSizeCx::new(font_size, line_height as f64)
2380 }
2381 }
2382
2383 pub fn apply_to_taffy_style(&self, style: &mut TaffyStyle) {
2384 let resolve_cx = &self.font_size_cx();
2385 style.size = taffy::prelude::Size {
2386 width: self.width().to_taffy_dim(resolve_cx),
2387 height: self.height().to_taffy_dim(resolve_cx),
2388 };
2389 style.min_size = taffy::prelude::Size {
2390 width: self.min_width().to_taffy_dim(resolve_cx),
2391 height: self.min_height().to_taffy_dim(resolve_cx),
2392 };
2393 style.max_size = taffy::prelude::Size {
2394 width: self.max_width().to_taffy_dim(resolve_cx),
2395 height: self.max_height().to_taffy_dim(resolve_cx),
2396 };
2397 style.flex_grow = self.flex_grow();
2398 style.flex_shrink = self.flex_shrink();
2399 style.flex_basis = self.flex_basis().to_taffy_dim(resolve_cx);
2400 style.border = Rect {
2401 left: LengthPercentage::length(self.border_left().width as f32),
2402 top: LengthPercentage::length(self.border_top().width as f32),
2403 right: LengthPercentage::length(self.border_right().width as f32),
2404 bottom: LengthPercentage::length(self.border_bottom().width as f32),
2405 };
2406 style.padding = Rect {
2407 left: self.padding_left().to_taffy(resolve_cx),
2408 top: self.padding_top().to_taffy(resolve_cx),
2409 right: self.padding_right().to_taffy(resolve_cx),
2410 bottom: self.padding_bottom().to_taffy(resolve_cx),
2411 };
2412 style.margin = Rect {
2413 left: self.margin_left().to_taffy_len_perc_auto(resolve_cx),
2414 top: self.margin_top().to_taffy_len_perc_auto(resolve_cx),
2415 right: self.margin_right().to_taffy_len_perc_auto(resolve_cx),
2416 bottom: self.margin_bottom().to_taffy_len_perc_auto(resolve_cx),
2417 };
2418 style.inset = Rect {
2419 left: self.inset_left().to_taffy_len_perc_auto(resolve_cx),
2420 top: self.inset_top().to_taffy_len_perc_auto(resolve_cx),
2421 right: self.inset_right().to_taffy_len_perc_auto(resolve_cx),
2422 bottom: self.inset_bottom().to_taffy_len_perc_auto(resolve_cx),
2423 };
2424 style.gap = Size {
2425 width: self.col_gap().to_taffy(resolve_cx),
2426 height: self.row_gap().to_taffy(resolve_cx),
2427 };
2428 }
2429}
2430
2431prop_extractor! {
2432 pub SelectionStyle {
2433 pub corner_radius: SelectionCornerRadius,
2434 pub selection_color: SelectionColor,
2435 }
2436}
2437
2438impl Style {
2439 fn deferred_effects(&self) -> impl Iterator<Item = &DeferredStyleEffect> {
2440 self.map
2441 .get(&DEFERRED_EFFECTS_KEY)
2442 .into_iter()
2443 .flat_map(|effects| {
2444 effects
2445 .downcast_ref::<Vec<DeferredStyleEffect>>()
2446 .into_iter()
2447 .flat_map(|effects| effects.iter())
2448 })
2449 }
2450
2451 fn run_deferred_effects(&self) {
2452 for effect in self.deferred_effects() {
2453 effect.run(self);
2454 }
2455 }
2456
2457 fn push_deferred_effect(mut self, effect: DeferredStyleEffect) -> Self {
2458 let mut effects = self
2459 .map
2460 .get(&DEFERRED_EFFECTS_KEY)
2461 .and_then(|effects| effects.downcast_ref::<Vec<DeferredStyleEffect>>())
2462 .cloned()
2463 .unwrap_or_default();
2464 effects.push(effect);
2465 self.map_mut()
2466 .insert(DEFERRED_EFFECTS_KEY, Rc::new(effects));
2467 self.merge_id = next_style_merge_id();
2468 self
2469 }
2470
2471 pub fn get<P: StyleProp>(&self, _prop: P) -> P::Type {
2473 self.get_prop_or_default::<P>()
2474 }
2475
2476 pub fn get_style_value<P: StyleProp>(&self, _prop: P) -> StyleValue<P::Type> {
2478 self.get_prop_style_value::<P>()
2479 }
2480
2481 pub fn set<P: StyleProp>(self, prop: P, value: impl Into<P::Type>) -> Self {
2483 self.set_style_value(prop, StyleValue::Val(value.into()))
2484 }
2485
2486 pub fn set_context<P: StyleProp>(self, prop: P, value: ContextValue<P::Type>) -> Self {
2488 self.set_style_value(prop, StyleValue::Context(value))
2489 }
2490
2491 pub fn defer<P: StyleProp>(self, f: impl Fn(P::Type) + 'static) -> Self
2500 where
2501 P::Type: 'static,
2502 {
2503 self.push_deferred_effect(ContextRef::<P>::default().into_deferred(f))
2504 }
2505
2506 pub fn set_from_context<C: StyleProp, P: StyleProp>(
2507 self,
2508 prop: P,
2509 context: ContextRef<C>,
2510 f: impl Fn(C::Type) -> P::Type + 'static,
2511 ) -> Self
2512 where
2513 C::Type: 'static,
2514 P::Type: 'static,
2515 {
2516 self.set_context(prop, context.def(f))
2517 }
2518
2519 pub fn set_context_opt<P: StyleProp<Type = Option<T>>, T: 'static>(
2523 self,
2524 prop: P,
2525 value: ContextValue<Option<T>>,
2526 ) -> Self {
2527 self.set_style_value(prop, StyleValue::Context(value))
2528 }
2529
2530 pub fn set_from_context_opt<C: StyleProp, P: StyleProp<Type = Option<T>>, T: 'static>(
2531 self,
2532 prop: P,
2533 context: ContextRef<C>,
2534 f: impl Fn(C::Type) -> Option<T> + 'static,
2535 ) -> Self
2536 where
2537 C::Type: 'static,
2538 {
2539 self.set_context_opt(prop, context.def(f))
2540 }
2541
2542 pub fn set_style_value<P: StyleProp>(mut self, _prop: P, value: StyleValue<P::Type>) -> Self {
2543 let previous_value = self.map.get(&P::key()).cloned();
2544 let insert = match value {
2545 StyleValue::Val(value) => StyleMapValue::Val(value),
2546 StyleValue::Animated(value) => StyleMapValue::Animated(value),
2547 StyleValue::Context(value) => {
2548 self.has_context_values = true;
2549 let previous_value = previous_value.clone();
2550 StyleMapValue::Context(ContextValue::new(move |style| {
2551 let mut base_style = style.clone();
2552 base_style.map_mut().remove(&P::key());
2553 if let Some(previous_value) = previous_value.clone() {
2562 let previous_value = match previous_value
2563 .downcast_ref::<StyleMapValue<P::Type>>()
2564 .unwrap()
2565 {
2566 StyleMapValue::Val(value) | StyleMapValue::Animated(value) => {
2567 Some(value.clone())
2568 }
2569 StyleMapValue::Context(context_value) => {
2570 Some(context_value.resolve(&base_style))
2571 }
2572 StyleMapValue::Unset => None,
2573 };
2574
2575 if let Some(previous_value) = previous_value {
2576 base_style
2577 .map_mut()
2578 .insert(P::key(), Rc::new(StyleMapValue::Val(previous_value)));
2579 }
2580 }
2581 value.resolve(&base_style)
2582 }))
2583 }
2584 StyleValue::Unset => StyleMapValue::Unset,
2585 StyleValue::Base => {
2586 if self.map_mut().remove(&P::key()).is_some() {
2587 self.merge_id = next_style_merge_id();
2588 }
2589 return self;
2590 }
2591 };
2592 if P::prop_ref().info().inherited {
2594 self.has_inherited = true;
2595 }
2596 self.map_mut().insert(P::key(), Rc::new(insert));
2597 self.merge_id = next_style_merge_id();
2598 self
2599 }
2600
2601 pub fn transition<P: StyleProp>(mut self, _prop: P, transition: Transition) -> Self {
2603 self.map_mut()
2604 .insert(P::prop_ref().info().transition_key, Rc::new(transition));
2605 self.merge_id = next_style_merge_id();
2606 self
2607 }
2608
2609 fn selector(mut self, selector: StyleSelector, style: impl FnOnce(Style) -> Style) -> Self {
2610 let over = style(Style::default());
2611 self.set_selector(selector, over);
2612 self
2613 }
2614
2615 pub(crate) fn structural_selector(
2616 mut self,
2617 selector: StructuralSelector,
2618 style: impl FnOnce(Style) -> Style,
2619 ) -> Self {
2620 let over = style(Style::default());
2621 self.set_structural_selector(selector, over);
2622 self
2623 }
2624
2625 pub fn hover(self, style: impl FnOnce(Style) -> Style) -> Self {
2627 self.selector(StyleSelector::Hover, style)
2628 }
2629
2630 pub fn focus(self, style: impl FnOnce(Style) -> Style) -> Self {
2632 self.selector(StyleSelector::Focus, style)
2633 }
2634
2635 pub fn focus_visible(self, style: impl FnOnce(Style) -> Style) -> Self {
2637 self.selector(StyleSelector::FocusVisible, style)
2638 }
2639
2640 pub fn focus_within(self, style: impl FnOnce(Style) -> Style) -> Self {
2643 self.selector(StyleSelector::FocusWithin, style)
2644 }
2645
2646 pub fn first_child(self, style: impl FnOnce(Style) -> Style) -> Self {
2648 self.structural_selector(StructuralSelector::FirstChild, style)
2649 }
2650
2651 pub fn last_child(self, style: impl FnOnce(Style) -> Style) -> Self {
2653 self.structural_selector(StructuralSelector::LastChild, style)
2654 }
2655
2656 pub fn nth_child(self, nth: NthChild, style: impl FnOnce(Style) -> Style) -> Self {
2658 self.structural_selector(StructuralSelector::NthChild(nth), style)
2659 }
2660
2661 pub fn odd(self, style: impl FnOnce(Style) -> Style) -> Self {
2663 self.nth_child(NthChild::odd(), style)
2664 }
2665
2666 pub fn even(self, style: impl FnOnce(Style) -> Style) -> Self {
2668 self.nth_child(NthChild::even(), style)
2669 }
2670
2671 pub fn selected(self, style: impl FnOnce(Style) -> Style) -> Self {
2673 self.selector(StyleSelector::Selected, style)
2674 }
2675
2676 pub fn drag(self, style: impl FnOnce(Style) -> Style) -> Self {
2678 self.selector(StyleSelector::Dragging, style)
2679 }
2680
2681 pub fn disabled(self, style: impl FnOnce(Style) -> Style) -> Self {
2683 self.selector(StyleSelector::Disabled, style)
2684 }
2685
2686 pub fn dark_mode(self, style: impl FnOnce(Style) -> Style) -> Self {
2688 self.selector(StyleSelector::DarkMode, style)
2689 }
2690
2691 pub fn file_hover(self, style: impl FnOnce(Style) -> Style) -> Self {
2693 self.selector(StyleSelector::FileHover, style)
2694 }
2695
2696 pub fn active(self, style: impl FnOnce(Style) -> Style) -> Self {
2698 self.selector(StyleSelector::Active, style)
2699 }
2700
2701 pub fn responsive(mut self, size: ScreenSize, style: impl FnOnce(Style) -> Style) -> Self {
2703 let over = style(Style::default());
2704 self.set_responsive_selector(ResponsiveSelector::ScreenSize(size), over);
2705 self
2706 }
2707
2708 pub fn min_window_width(
2710 mut self,
2711 min: impl Into<Pt>,
2712 style: impl FnOnce(Style) -> Style,
2713 ) -> Self {
2714 let over = style(Style::default());
2715 self.set_responsive_selector(ResponsiveSelector::MinWidth(min.into()), over);
2716 self
2717 }
2718
2719 pub fn max_window_width(
2721 mut self,
2722 max: impl Into<Pt>,
2723 style: impl FnOnce(Style) -> Style,
2724 ) -> Self {
2725 let over = style(Style::default());
2726 self.set_responsive_selector(ResponsiveSelector::MaxWidth(max.into()), over);
2727 self
2728 }
2729
2730 pub fn window_width_range(
2732 mut self,
2733 min: impl Into<Pt>,
2734 max: impl Into<Pt>,
2735 style: impl FnOnce(Style) -> Style,
2736 ) -> Self {
2737 let over = style(Style::default());
2738 self.set_responsive_selector(
2739 ResponsiveSelector::WidthRange {
2740 min: min.into(),
2741 max: max.into(),
2742 },
2743 over,
2744 );
2745 self
2746 }
2747
2748 pub fn class<C: StyleClass>(mut self, _class: C, style: impl FnOnce(Style) -> Style) -> Self {
2750 let over = style(Style::default());
2751 self.set_class(C::class_ref(), over);
2752 self
2753 }
2754
2755 pub fn custom_style_class<CS: CustomStyle>(mut self, style: impl FnOnce(CS) -> CS) -> Self {
2774 let over = style(CS::default());
2775 self.set_class(CS::StyleClass::class_ref(), over.into());
2776 self
2777 }
2778
2779 pub fn width_full(self) -> Self {
2781 self.width_pct(100.0)
2782 }
2783
2784 pub fn width_pct(self, width: f64) -> Self {
2786 self.width(width.pct())
2787 }
2788
2789 pub fn height_full(self) -> Self {
2791 self.height_pct(100.0)
2792 }
2793
2794 pub fn height_pct(self, height: f64) -> Self {
2796 self.height(height.pct())
2797 }
2798
2799 pub fn keyboard_navigable(self) -> Self {
2808 self.set(Focusable, Focus::Keyboard)
2809 }
2810
2811 pub fn focusable(self) -> Self {
2823 self.set(Focusable, Focus::PointerAndProgrammatic)
2824 }
2825
2826 pub fn font_size(self, size: impl Into<Pt>) -> Self {
2828 let px = size.into();
2829 self.set_style_value(FontSize, StyleValue::Val(px.0))
2830 }
2831
2832 pub fn focus_none(self) -> Self {
2839 self.set(Focusable, Focus::None)
2840 }
2841
2842 pub fn row_col_gap(self, width: impl Into<Length>, height: impl Into<Length>) -> Self {
2844 self.col_gap(width).row_gap(height)
2845 }
2846
2847 pub fn gap(self, gap: impl Into<Length>) -> Self {
2849 let gap = gap.into();
2850 self.col_gap(gap).row_gap(gap)
2851 }
2852
2853 pub fn size(self, width: impl Into<LengthAuto>, height: impl Into<LengthAuto>) -> Self {
2855 self.width(width).height(height)
2856 }
2857
2858 pub fn size_full(self) -> Self {
2860 self.size_pct(100.0, 100.0)
2861 }
2862
2863 pub fn size_pct(self, width: f64, height: f64) -> Self {
2865 self.width(width.pct()).height(height.pct())
2866 }
2867
2868 pub fn min_width_full(self) -> Self {
2870 self.min_width_pct(100.0)
2871 }
2872
2873 pub fn min_width_pct(self, min_width: f64) -> Self {
2875 self.min_width(min_width.pct())
2876 }
2877
2878 pub fn min_height_full(self) -> Self {
2880 self.min_height_pct(100.0)
2881 }
2882
2883 pub fn min_height_pct(self, min_height: f64) -> Self {
2885 self.min_height(min_height.pct())
2886 }
2887
2888 pub fn min_size_full(self) -> Self {
2890 self.min_size_pct(100.0, 100.0)
2891 }
2892
2893 pub fn min_size(
2895 self,
2896 min_width: impl Into<LengthAuto>,
2897 min_height: impl Into<LengthAuto>,
2898 ) -> Self {
2899 self.min_width(min_width).min_height(min_height)
2900 }
2901
2902 pub fn min_size_pct(self, min_width: f64, min_height: f64) -> Self {
2904 self.min_size(min_width.pct(), min_height.pct())
2905 }
2906
2907 pub fn max_width_full(self) -> Self {
2909 self.max_width_pct(100.0)
2910 }
2911
2912 pub fn max_width_pct(self, max_width: f64) -> Self {
2914 self.max_width(max_width.pct())
2915 }
2916
2917 pub fn max_height_full(self) -> Self {
2919 self.max_height_pct(100.0)
2920 }
2921
2922 pub fn max_height_pct(self, max_height: f64) -> Self {
2924 self.max_height(max_height.pct())
2925 }
2926
2927 pub fn max_size(
2929 self,
2930 max_width: impl Into<LengthAuto>,
2931 max_height: impl Into<LengthAuto>,
2932 ) -> Self {
2933 self.max_width(max_width).max_height(max_height)
2934 }
2935
2936 pub fn max_size_full(self) -> Self {
2938 self.max_size_pct(100.0, 100.0)
2939 }
2940
2941 pub fn max_size_pct(self, max_width: f64, max_height: f64) -> Self {
2943 self.max_size(max_width.pct(), max_height.pct())
2944 }
2945
2946 pub fn border_color(self, color: impl Into<Brush>) -> Self {
2948 let color = color.into();
2949 self.set(BorderLeftColor, Some(color.clone()))
2950 .set(BorderTopColor, Some(color.clone()))
2951 .set(BorderRightColor, Some(color.clone()))
2952 .set(BorderBottomColor, Some(color))
2953 }
2954
2955 pub fn border(self, border: impl Into<StrokeWrap>) -> Self {
2957 let border = border.into();
2958 self.set(BorderLeft, border.0.clone())
2959 .set(BorderTop, border.0.clone())
2960 .set(BorderRight, border.0.clone())
2961 .set(BorderBottom, border.0)
2962 }
2963
2964 pub fn outline(self, outline: impl Into<StrokeWrap>) -> Self {
2966 self.set_style_value(Outline, StyleValue::Val(outline.into().0))
2967 }
2968
2969 pub fn border_left(self, border: impl Into<StrokeWrap>) -> Self {
2971 self.set(BorderLeft, border.into().0)
2972 }
2973
2974 pub fn border_top(self, border: impl Into<StrokeWrap>) -> Self {
2976 self.set(BorderTop, border.into().0)
2977 }
2978
2979 pub fn border_right(self, border: impl Into<StrokeWrap>) -> Self {
2981 self.set(BorderRight, border.into().0)
2982 }
2983
2984 pub fn border_bottom(self, border: impl Into<StrokeWrap>) -> Self {
2986 self.set(BorderBottom, border.into().0)
2987 }
2988
2989 pub fn border_horiz(self, border: impl Into<StrokeWrap>) -> Self {
2991 let border = border.into();
2992 self.set(BorderLeft, border.0.clone())
2993 .set(BorderRight, border.0)
2994 }
2995
2996 pub fn border_vert(self, border: impl Into<StrokeWrap>) -> Self {
2998 let border = border.into();
2999 self.set(BorderTop, border.0.clone())
3000 .set(BorderBottom, border.0)
3001 }
3002
3003 pub fn padding_left_pct(self, padding: f64) -> Self {
3005 self.padding_left(padding.pct())
3006 }
3007
3008 pub fn padding_right_pct(self, padding: f64) -> Self {
3010 self.padding_right(padding.pct())
3011 }
3012
3013 pub fn padding_top_pct(self, padding: f64) -> Self {
3015 self.padding_top(padding.pct())
3016 }
3017
3018 pub fn padding_bottom_pct(self, padding: f64) -> Self {
3020 self.padding_bottom(padding.pct())
3021 }
3022
3023 pub fn padding(self, padding: impl Into<Length>) -> Self {
3025 let padding = padding.into();
3026 self.set(PaddingLeft, padding)
3027 .set(PaddingTop, padding)
3028 .set(PaddingRight, padding)
3029 .set(PaddingBottom, padding)
3030 }
3031
3032 pub fn padding_pct(self, padding: f64) -> Self {
3034 self.padding(padding.pct())
3035 }
3036
3037 pub fn padding_horiz(self, padding: impl Into<Length>) -> Self {
3039 let padding = padding.into();
3040 self.set(PaddingLeft, padding).set(PaddingRight, padding)
3041 }
3042
3043 pub fn padding_horiz_pct(self, padding: f64) -> Self {
3045 self.padding_horiz(padding.pct())
3046 }
3047
3048 pub fn padding_vert(self, padding: impl Into<Length>) -> Self {
3050 let padding = padding.into();
3051 self.set(PaddingTop, padding).set(PaddingBottom, padding)
3052 }
3053
3054 pub fn padding_vert_pct(self, padding: f64) -> Self {
3056 self.padding_vert(padding.pct())
3057 }
3058
3059 pub fn margin_left_pct(self, margin: f64) -> Self {
3061 self.margin_left(margin.pct())
3062 }
3063
3064 pub fn margin_right_pct(self, margin: f64) -> Self {
3066 self.margin_right(margin.pct())
3067 }
3068
3069 pub fn margin_top_pct(self, margin: f64) -> Self {
3071 self.margin_top(margin.pct())
3072 }
3073
3074 pub fn margin_bottom_pct(self, margin: f64) -> Self {
3076 self.margin_bottom(margin.pct())
3077 }
3078
3079 pub fn margin(self, margin: impl Into<LengthAuto>) -> Self {
3081 let margin = margin.into();
3082 self.set(MarginLeft, margin)
3083 .set(MarginTop, margin)
3084 .set(MarginRight, margin)
3085 .set(MarginBottom, margin)
3086 }
3087
3088 pub fn margin_pct(self, margin: f64) -> Self {
3090 self.margin(margin.pct())
3091 }
3092
3093 pub fn margin_horiz(self, margin: impl Into<LengthAuto>) -> Self {
3095 let margin = margin.into();
3096 self.set(MarginLeft, margin).set(MarginRight, margin)
3097 }
3098
3099 pub fn margin_horiz_pct(self, margin: f64) -> Self {
3101 self.margin_horiz(margin.pct())
3102 }
3103
3104 pub fn margin_vert(self, margin: impl Into<LengthAuto>) -> Self {
3106 let margin = margin.into();
3107 self.set(MarginTop, margin).set(MarginBottom, margin)
3108 }
3109
3110 pub fn margin_vert_pct(self, margin: f64) -> Self {
3112 self.margin_vert(margin.pct())
3113 }
3114
3115 pub fn apply_padding(self, padding: Padding) -> Self {
3117 let mut style = self;
3118 if let Some(left) = padding.left {
3119 style = style.set(PaddingLeft, left);
3120 }
3121 if let Some(top) = padding.top {
3122 style = style.set(PaddingTop, top);
3123 }
3124 if let Some(right) = padding.right {
3125 style = style.set(PaddingRight, right);
3126 }
3127 if let Some(bottom) = padding.bottom {
3128 style = style.set(PaddingBottom, bottom);
3129 }
3130 style
3131 }
3132 pub fn apply_margin(self, margin: Margin) -> Self {
3134 let mut style = self;
3135 if let Some(left) = margin.left {
3136 style = style.set(MarginLeft, left);
3137 }
3138 if let Some(top) = margin.top {
3139 style = style.set(MarginTop, top);
3140 }
3141 if let Some(right) = margin.right {
3142 style = style.set(MarginRight, right);
3143 }
3144 if let Some(bottom) = margin.bottom {
3145 style = style.set(MarginBottom, bottom);
3146 }
3147 style
3148 }
3149
3150 pub fn border_radius(self, radius: impl Into<Length>) -> Self {
3152 let radius = radius.into();
3153 self.set(BorderTopLeftRadius, radius)
3154 .set(BorderTopRightRadius, radius)
3155 .set(BorderBottomLeftRadius, radius)
3156 .set(BorderBottomRightRadius, radius)
3157 }
3158
3159 pub fn apply_border(self, border: Border) -> Self {
3161 let mut style = self;
3162 if let Some(left) = border.left {
3163 style = style.set(BorderLeft, left);
3164 }
3165 if let Some(top) = border.top {
3166 style = style.set(BorderTop, top);
3167 }
3168 if let Some(right) = border.right {
3169 style = style.set(BorderRight, right);
3170 }
3171 if let Some(bottom) = border.bottom {
3172 style = style.set(BorderBottom, bottom);
3173 }
3174 style
3175 }
3176 pub fn apply_border_color(self, border_color: BorderColor) -> Self {
3178 let mut style = self;
3179 if let Some(left) = border_color.left {
3180 style = style.set(BorderLeftColor, Some(left));
3181 }
3182 if let Some(top) = border_color.top {
3183 style = style.set(BorderTopColor, Some(top));
3184 }
3185 if let Some(right) = border_color.right {
3186 style = style.set(BorderRightColor, Some(right));
3187 }
3188 if let Some(bottom) = border_color.bottom {
3189 style = style.set(BorderBottomColor, Some(bottom));
3190 }
3191 style
3192 }
3193 pub fn apply_border_radius(self, border_radius: BorderRadius) -> Self {
3195 let mut style = self;
3196 if let Some(top_left) = border_radius.top_left {
3197 style = style.set(BorderTopLeftRadius, top_left);
3198 }
3199 if let Some(top_right) = border_radius.top_right {
3200 style = style.set(BorderTopRightRadius, top_right);
3201 }
3202 if let Some(bottom_left) = border_radius.bottom_left {
3203 style = style.set(BorderBottomLeftRadius, bottom_left);
3204 }
3205 if let Some(bottom_right) = border_radius.bottom_right {
3206 style = style.set(BorderBottomRightRadius, bottom_right);
3207 }
3208 style
3209 }
3210
3211 pub fn inset_left_pct(self, inset: f64) -> Self {
3213 self.inset_left(inset.pct())
3214 }
3215
3216 pub fn inset_right_pct(self, inset: f64) -> Self {
3218 self.inset_right(inset.pct())
3219 }
3220
3221 pub fn inset_top_pct(self, inset: f64) -> Self {
3223 self.inset_top(inset.pct())
3224 }
3225
3226 pub fn inset_bottom_pct(self, inset: f64) -> Self {
3228 self.inset_bottom(inset.pct())
3229 }
3230
3231 pub fn inset(self, inset: impl Into<LengthAuto>) -> Self {
3233 let inset = inset.into();
3234 self.inset_left(inset)
3235 .inset_top(inset)
3236 .inset_right(inset)
3237 .inset_bottom(inset)
3238 }
3239
3240 pub fn inset_pct(self, inset: f64) -> Self {
3242 let inset = inset.pct();
3243 self.inset_left(inset)
3244 .inset_top(inset)
3245 .inset_right(inset)
3246 .inset_bottom(inset)
3247 }
3248
3249 pub fn box_shadow_blur(self, blur_radius: impl Into<Length>) -> Self {
3252 let mut value = self.get(BoxShadowProp);
3253 if let Some(v) = value.first_mut() {
3254 v.blur_radius = blur_radius.into();
3255 } else {
3256 value.push(BoxShadow {
3257 blur_radius: blur_radius.into(),
3258 ..Default::default()
3259 });
3260 }
3261 self.set(BoxShadowProp, value)
3262 }
3263
3264 pub fn box_shadow_color(self, color: Color) -> Self {
3266 let mut value = self.get(BoxShadowProp);
3267 if let Some(v) = value.first_mut() {
3268 v.color = color;
3269 } else {
3270 value.push(BoxShadow {
3271 color,
3272 ..Default::default()
3273 });
3274 }
3275 self.set(BoxShadowProp, value)
3276 }
3277
3278 pub fn box_shadow_spread(self, spread: impl Into<Length>) -> Self {
3281 let mut value = self.get(BoxShadowProp);
3282 if let Some(v) = value.first_mut() {
3283 v.spread = spread.into();
3284 } else {
3285 value.push(BoxShadow {
3286 spread: spread.into(),
3287 ..Default::default()
3288 });
3289 }
3290 self.set(BoxShadowProp, value)
3291 }
3292
3293 pub fn apply_box_shadows(self, shadow: impl Into<SmallVec<[BoxShadow; 3]>>) -> Self {
3326 self.set(BoxShadowProp, shadow.into())
3327 }
3328
3329 pub fn box_shadow_h_offset(self, h_offset: impl Into<Length>) -> Self {
3332 let mut value = self.get(BoxShadowProp);
3333 let offset = h_offset.into();
3334 if let Some(v) = value.first_mut() {
3335 v.left_offset = -offset;
3336 v.right_offset = offset;
3337 } else {
3338 value.push(BoxShadow {
3339 left_offset: -offset,
3340 right_offset: offset,
3341 ..Default::default()
3342 });
3343 }
3344 self.set(BoxShadowProp, value)
3345 }
3346
3347 pub fn box_shadow_v_offset(self, v_offset: impl Into<Length>) -> Self {
3350 let mut value = self.get(BoxShadowProp);
3351 let offset = v_offset.into();
3352 if let Some(v) = value.first_mut() {
3353 v.top_offset = -offset;
3354 v.bottom_offset = offset;
3355 } else {
3356 value.push(BoxShadow {
3357 top_offset: -offset,
3358 bottom_offset: offset,
3359 ..Default::default()
3360 });
3361 }
3362 self.set(BoxShadowProp, value)
3363 }
3364
3365 pub fn box_shadow_left_offset(self, left_offset: impl Into<Length>) -> Self {
3367 let mut value = self.get(BoxShadowProp);
3368 if let Some(v) = value.first_mut() {
3369 v.left_offset = left_offset.into();
3370 } else {
3371 value.push(BoxShadow {
3372 left_offset: left_offset.into(),
3373 ..Default::default()
3374 });
3375 }
3376 self.set(BoxShadowProp, value)
3377 }
3378
3379 pub fn box_shadow_right_offset(self, right_offset: impl Into<Length>) -> Self {
3381 let mut value = self.get(BoxShadowProp);
3382 if let Some(v) = value.first_mut() {
3383 v.right_offset = right_offset.into();
3384 } else {
3385 value.push(BoxShadow {
3386 right_offset: right_offset.into(),
3387 ..Default::default()
3388 });
3389 }
3390 self.set(BoxShadowProp, value)
3391 }
3392
3393 pub fn box_shadow_top_offset(self, top_offset: impl Into<Length>) -> Self {
3395 let mut value = self.get(BoxShadowProp);
3396 if let Some(v) = value.first_mut() {
3397 v.top_offset = top_offset.into();
3398 } else {
3399 value.push(BoxShadow {
3400 top_offset: top_offset.into(),
3401 ..Default::default()
3402 });
3403 }
3404 self.set(BoxShadowProp, value)
3405 }
3406
3407 pub fn box_shadow_bottom_offset(self, bottom_offset: impl Into<Length>) -> Self {
3409 let mut value = self.get(BoxShadowProp);
3410 if let Some(v) = value.first_mut() {
3411 v.bottom_offset = bottom_offset.into();
3412 } else {
3413 value.push(BoxShadow {
3414 bottom_offset: bottom_offset.into(),
3415 ..Default::default()
3416 });
3417 }
3418 self.set(BoxShadowProp, value)
3419 }
3420
3421 pub fn font_bold(self) -> Self {
3423 self.font_weight(FontWeightProp::BOLD)
3424 }
3425
3426 pub fn pointer_events_auto(self) -> Self {
3428 self.pointer_events(PointerEvents::Auto)
3429 }
3430
3431 pub fn pointer_events_none(self) -> Self {
3433 self.pointer_events(PointerEvents::None)
3434 }
3435
3436 pub fn text_ellipsis(self) -> Self {
3438 self.text_overflow(TextOverflow::NoWrap(NoWrapOverflow::Ellipsis))
3439 }
3440
3441 pub fn text_clip(self) -> Self {
3443 self.text_overflow(TextOverflow::NoWrap(NoWrapOverflow::Clip))
3444 }
3445
3446 pub fn text_wrap(self) -> Self {
3448 self.text_overflow(TextOverflow::Wrap {
3449 overflow_wrap: OverflowWrap::Normal,
3450 word_break: WordBreakStrength::Normal,
3451 })
3452 }
3453
3454 pub fn absolute(self) -> Self {
3456 self.position(taffy::style::Position::Absolute)
3457 }
3458
3459 pub fn fixed(self) -> Self {
3475 self.position(taffy::style::Position::Absolute)
3476 .is_fixed(true)
3477 }
3478
3479 pub fn items_stretch(self) -> Self {
3481 self.align_items(taffy::style::AlignItems::Stretch)
3482 }
3483
3484 pub fn items_start(self) -> Self {
3486 self.align_items(taffy::style::AlignItems::FlexStart)
3487 }
3488
3489 pub fn items_center(self) -> Self {
3491 self.align_items(taffy::style::AlignItems::Center)
3492 }
3493
3494 pub fn items_end(self) -> Self {
3496 self.align_items(taffy::style::AlignItems::FlexEnd)
3497 }
3498
3499 pub fn items_baseline(self) -> Self {
3501 self.align_items(taffy::style::AlignItems::Baseline)
3502 }
3503
3504 pub fn justify_start(self) -> Self {
3506 self.justify_content(taffy::style::JustifyContent::FlexStart)
3507 }
3508
3509 pub fn justify_end(self) -> Self {
3511 self.justify_content(taffy::style::JustifyContent::FlexEnd)
3512 }
3513
3514 pub fn justify_center(self) -> Self {
3516 self.justify_content(taffy::style::JustifyContent::Center)
3517 }
3518
3519 pub fn justify_between(self) -> Self {
3521 self.justify_content(taffy::style::JustifyContent::SpaceBetween)
3522 }
3523
3524 pub fn justify_around(self) -> Self {
3526 self.justify_content(taffy::style::JustifyContent::SpaceAround)
3527 }
3528
3529 pub fn justify_evenly(self) -> Self {
3531 self.justify_content(taffy::style::JustifyContent::SpaceEvenly)
3532 }
3533
3534 pub fn hide(self) -> Self {
3536 self.set(DisplayProp, Display::None)
3537 }
3538
3539 pub fn flex(self) -> Self {
3541 self.display(taffy::style::Display::Flex)
3542 }
3543
3544 pub fn grid(self) -> Self {
3546 self.display(taffy::style::Display::Grid)
3547 }
3548
3549 pub fn flex_row(self) -> Self {
3551 self.flex_direction(taffy::style::FlexDirection::Row)
3552 }
3553
3554 pub fn flex_col(self) -> Self {
3556 self.flex_direction(taffy::style::FlexDirection::Column)
3557 }
3558
3559 pub fn scale(self, scale: impl Into<Pct>) -> Self {
3561 let val = scale.into();
3562 self.scale_x(val).scale_y(val)
3563 }
3564
3565 pub fn apply_opt<T>(self, opt: Option<T>, f: impl FnOnce(Self, T) -> Self) -> Self {
3577 if let Some(t) = opt { f(self, t) } else { self }
3578 }
3579
3580 pub fn apply_if(self, cond: bool, f: impl FnOnce(Self) -> Self) -> Self {
3589 if cond { f(self) } else { self }
3590 }
3591
3592 pub fn custom<CS: CustomStyle>(self, custom: impl FnOnce(CS) -> CS) -> Self {
3602 self.apply(custom(CS::default()).into())
3603 }
3604
3605 pub fn apply_custom<CS: Into<Style>>(self, custom_style: CS) -> Self {
3615 self.apply(custom_style.into())
3616 }
3617}
3618
3619impl Style {
3620 pub(crate) fn font_size_cx(&self) -> FontSizeCx {
3621 let builtin = self.builtin();
3622 let font_size = builtin.font_size();
3623 let line_height = builtin.line_height();
3624 let line_height = line_height.resolve(font_size as f32);
3625 FontSizeCx::new(font_size, line_height as f64)
3626 }
3627
3628 pub fn to_taffy_style(&self) -> TaffyStyle {
3629 let style = self.builtin();
3630 let font_size_cx = self.font_size_cx();
3631 TaffyStyle {
3632 display: style.display(),
3633 overflow: taffy::Point {
3634 x: self.get(OverflowX),
3635 y: self.get(OverflowY),
3636 },
3637 position: style.position(),
3638 size: taffy::prelude::Size {
3639 width: style.width().to_taffy_dim(&font_size_cx),
3640 height: style.height().to_taffy_dim(&font_size_cx),
3641 },
3642 min_size: taffy::prelude::Size {
3643 width: style.min_width().to_taffy_dim(&font_size_cx),
3644 height: style.min_height().to_taffy_dim(&font_size_cx),
3645 },
3646 max_size: taffy::prelude::Size {
3647 width: style.max_width().to_taffy_dim(&font_size_cx),
3648 height: style.max_height().to_taffy_dim(&font_size_cx),
3649 },
3650 flex_direction: style.flex_direction(),
3651 flex_grow: style.flex_grow(),
3652 flex_shrink: style.flex_shrink(),
3653 flex_basis: style.flex_basis().to_taffy_dim(&font_size_cx),
3654 flex_wrap: style.flex_wrap(),
3655 justify_content: style.justify_content(),
3656 justify_self: style.justify_self(),
3657 justify_items: style.justify_items(),
3658 align_items: style.align_items(),
3659 align_content: style.align_content(),
3660 align_self: style.align_self(),
3661 aspect_ratio: style.aspect_ratio(),
3662 border: {
3663 Rect {
3664 left: LengthPercentage::length(style.border_left().width as f32),
3665 top: LengthPercentage::length(style.border_top().width as f32),
3666 right: LengthPercentage::length(style.border_right().width as f32),
3667 bottom: LengthPercentage::length(style.border_bottom().width as f32),
3668 }
3669 },
3670 padding: {
3671 Rect {
3672 left: style.padding_left().to_taffy(&font_size_cx),
3673 top: style.padding_top().to_taffy(&font_size_cx),
3674 right: style.padding_right().to_taffy(&font_size_cx),
3675 bottom: style.padding_bottom().to_taffy(&font_size_cx),
3676 }
3677 },
3678 margin: {
3679 Rect {
3680 left: style.margin_left().to_taffy_len_perc_auto(&font_size_cx),
3681 top: style.margin_top().to_taffy_len_perc_auto(&font_size_cx),
3682 right: style.margin_right().to_taffy_len_perc_auto(&font_size_cx),
3683 bottom: style.margin_bottom().to_taffy_len_perc_auto(&font_size_cx),
3684 }
3685 },
3686 inset: Rect {
3687 left: style.inset_left().to_taffy_len_perc_auto(&font_size_cx),
3688 top: style.inset_top().to_taffy_len_perc_auto(&font_size_cx),
3689 right: style.inset_right().to_taffy_len_perc_auto(&font_size_cx),
3690 bottom: style.inset_bottom().to_taffy_len_perc_auto(&font_size_cx),
3691 },
3692 gap: Size {
3693 width: style.col_gap().to_taffy(&font_size_cx),
3694 height: style.row_gap().to_taffy(&font_size_cx),
3695 },
3696 grid_template_rows: style.grid_template_rows(),
3697 grid_template_columns: style.grid_template_columns(),
3698 grid_row: style.grid_row(),
3699 grid_column: style.grid_column(),
3700 grid_auto_rows: style.grid_auto_rows(),
3701 grid_auto_columns: style.grid_auto_columns(),
3702 grid_auto_flow: style.grid_auto_flow(),
3703 scrollbar_width: style.scrollbar_width().0 as f32,
3704 ..Default::default()
3705 }
3706 }
3707}