ravenrs_widgets/
modifiers.rs1use ravenrs_core::{Border, Insets, Shadow};
2use ravenrs_layout::{Align, Axis, LayoutStyle};
3
4use crate::context::{BuildCx, NodeId, Paint, QuadPaint};
5use crate::{Fill, Tooltip, View};
6
7#[derive(Debug)]
9pub struct Styled<V> {
10 content: V,
11 style: LayoutStyle,
12 background: Option<Fill>,
13 radius: f32,
14 border: Option<(f32, Fill)>,
15 shadow: Option<Shadow>,
16}
17
18pub trait ViewExt: View + Sized {
27 fn padding(self, padding: impl Into<Insets>) -> Styled<Self> {
29 Styled::new(self).padding(padding)
30 }
31 fn background(self, fill: impl Into<Fill>) -> Styled<Self> {
33 Styled::new(self).background(fill)
34 }
35 fn frame(self, width: Option<f32>, height: Option<f32>) -> Styled<Self> {
37 Styled::new(self).frame(width, height)
38 }
39 fn width(self, width: f32) -> Styled<Self> {
41 Styled::new(self).width(width)
42 }
43 fn height(self, height: f32) -> Styled<Self> {
45 Styled::new(self).height(height)
46 }
47 fn grow(self, grow: f32) -> Styled<Self> {
49 Styled::new(self).grow(grow)
50 }
51 fn stretch(self) -> Styled<Self> {
53 Styled::new(self).stretch()
54 }
55 fn centered(self) -> Styled<Self> {
57 Styled::new(self).centered()
58 }
59 fn tooltip(self, text: impl Into<String>) -> Tooltip<Self> {
61 Tooltip::new(self, text)
62 }
63 fn opacity(self, opacity: f32) -> Faded<Self> {
66 Faded { content: self, opacity: opacity.clamp(0.0, 1.0) }
67 }
68}
69
70#[derive(Debug)]
74pub struct Faded<V> {
75 content: V,
76 opacity: f32,
77}
78
79impl<V: View> View for Faded<V> {
80 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
81 let node = self.content.build(cx);
82 let effect = ravenrs_core::Effect { opacity: self.opacity, ..ravenrs_core::Effect::IDENTITY };
83 let transition = cx.theme().motion.fast;
84 cx.motion(node, crate::Motion::new().effect(effect, transition));
85 node
86 }
87}
88
89impl<V: View> ViewExt for V {}
90
91#[cfg_attr(feature = "live", ravenrs_live::expose)]
92impl<V: View> Styled<V> {
93 fn new(content: V) -> Self {
94 Self {
95 content,
96 style: LayoutStyle { align: Align::Stretch, ..LayoutStyle::stack(Axis::Vertical) },
97 background: None,
98 radius: 0.0,
99 border: None,
100 shadow: None,
101 }
102 }
103
104 pub fn padding(mut self, padding: impl Into<Insets>) -> Self {
106 self.style.padding = padding.into();
107 self
108 }
109
110 pub fn background(mut self, fill: impl Into<Fill>) -> Self {
112 self.background = Some(fill.into());
113 self
114 }
115
116 pub fn corner_radius(mut self, radius: f32) -> Self {
118 self.radius = radius;
119 self
120 }
121
122 pub fn border(mut self, width: f32, fill: impl Into<Fill>) -> Self {
124 self.border = Some((width, fill.into()));
125 self
126 }
127
128 pub fn shadow(mut self, shadow: Shadow) -> Self {
130 self.shadow = Some(shadow);
131 self
132 }
133
134 pub fn frame(mut self, width: Option<f32>, height: Option<f32>) -> Self {
136 self.style.width = width;
137 self.style.height = height;
138 self
139 }
140
141 pub fn width(mut self, width: f32) -> Self {
143 self.style.width = Some(width);
144 self
145 }
146
147 pub fn height(mut self, height: f32) -> Self {
149 self.style.height = Some(height);
150 self
151 }
152
153 pub fn max_width(mut self, width: f32) -> Self {
155 self.style.max_width = Some(width);
156 self
157 }
158
159 pub fn grow(mut self, grow: f32) -> Self {
161 self.style.grow = grow;
162 self.style.min_width.get_or_insert(0.0);
163 self.style.min_height.get_or_insert(0.0);
164 self
165 }
166
167 pub fn stretch(mut self) -> Self {
169 self.style.align_self = Some(Align::Stretch);
170 self
171 }
172
173 pub fn centered(mut self) -> Self {
175 self.style.align = Align::Center;
176 self.style.justify = ravenrs_layout::Justify::Center;
177 self
178 }
179}
180
181impl<V: View> View for Styled<V> {
182 fn build(&self, cx: &mut BuildCx<'_>) -> NodeId {
183 let child = cx.child(&self.content);
184 let theme = *cx.theme();
185 let paint = if self.background.is_some() || self.border.is_some() || self.shadow.is_some() {
186 let fill = self.background.map_or(ravenrs_core::Color::TRANSPARENT, |f| f.resolve(&theme));
187 Paint::Quad(QuadPaint {
188 fill: fill.into(),
189 corner_radius: self.radius,
190 border: self.border.map(|(width, f)| Border { width, color: f.resolve(&theme) }),
191 shadow: self.shadow,
192 })
193 } else {
194 Paint::None
195 };
196 cx.container(self.style, &[child], paint)
197 }
198}