tui_lipan/widgets/effect_scope/
mod.rs1mod layout;
2mod node;
3mod reconcile;
4
5use std::sync::Arc;
6
7pub(crate) use self::layout::measure_effect_scope;
8pub use self::node::EffectScopeNode;
9pub(crate) use self::reconcile::reconcile_effect_scope;
10
11use crate::app::ContrastPolicy;
12use crate::core::element::{Element, ElementKind};
13use crate::style::{CellEffect, Color, ColorTransform, LayoutConstraints, Length, VisualEffect};
14
15#[derive(Clone, Default)]
22pub struct EffectScope {
23 pub(crate) child: Option<Box<Element>>,
24 pub(crate) effects: Vec<VisualEffect>,
25}
26
27impl EffectScope {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn child(mut self, child: impl Into<Element>) -> Self {
35 self.child = Some(Box::new(child.into()));
36 self
37 }
38
39 pub fn dim_by(self, amount: f32) -> Self {
41 self.effect(VisualEffect::ColorTransform {
42 fg: Some(ColorTransform::Dim(amount)),
43 bg: Some(ColorTransform::Dim(amount)),
44 })
45 }
46
47 pub fn lighten_by(self, amount: f32) -> Self {
49 self.effect(VisualEffect::ColorTransform {
50 fg: Some(ColorTransform::Lighten(amount)),
51 bg: Some(ColorTransform::Lighten(amount)),
52 })
53 }
54
55 pub fn tint_by(self, color: Color, alpha: f32) -> Self {
57 self.effect(VisualEffect::ColorTransform {
58 fg: Some(ColorTransform::Tint(color, alpha)),
59 bg: Some(ColorTransform::Tint(color, alpha)),
60 })
61 }
62
63 pub fn transform_fg(self, transform: ColorTransform) -> Self {
65 self.effect(VisualEffect::transform_fg(transform))
66 }
67
68 pub fn transform_bg(self, transform: ColorTransform) -> Self {
70 self.effect(VisualEffect::transform_bg(transform))
71 }
72
73 pub fn contrast_policy(self, policy: ContrastPolicy) -> Self {
75 self.effect(VisualEffect::ContrastPolicy(policy))
76 }
77
78 pub fn effect(mut self, effect: VisualEffect) -> Self {
80 self.effects.push(effect);
81 self
82 }
83
84 pub fn custom_effect(self, effect: impl CellEffect) -> Self {
86 self.effect(VisualEffect::Custom(Arc::new(effect)))
87 }
88
89 pub fn effects<I>(mut self, effects: I) -> Self
91 where
92 I: IntoIterator<Item = VisualEffect>,
93 {
94 self.effects.extend(effects);
95 self
96 }
97
98 pub fn clear_effects(mut self) -> Self {
100 self.effects.clear();
101 self
102 }
103}
104
105impl From<EffectScope> for Element {
106 fn from(value: EffectScope) -> Self {
107 let (min_w, min_h) = measure_effect_scope(&value, None, None);
108 Element::new(ElementKind::EffectScope(value)).with_layout(
109 LayoutConstraints::default()
110 .min_width(Length::Px(min_w))
111 .min_height(Length::Px(min_h)),
112 )
113 }
114}
115
116impl crate::layout::hash::LayoutHash for EffectScope {
117 fn layout_hash(
118 &self,
119 hasher: &mut impl std::hash::Hasher,
120 recurse: &dyn Fn(&Element) -> Option<u64>,
121 ) -> Option<()> {
122 use std::hash::Hash;
123 self.effects.hash(hasher);
124 if let Some(child) = self.child.as_ref() {
125 recurse(child.as_ref())?.hash(hasher);
126 } else {
127 0u8.hash(hasher);
128 }
129 Some(())
130 }
131}