audio_processor_iced_design_system/
container.rs1pub use hover_container::HoverContainer;
24
25pub mod hover_container {
27 use iced::{Alignment, Color, Length, Point, Rectangle};
28 use iced_native::layout::{Limits, Node};
29 use iced_native::renderer::Quad;
30 use iced_native::widget::{Operation, Tree};
31 use iced_native::{overlay, Clipboard, Element, Event, Layout, Padding, Shell, Widget};
32
33 pub struct HoverContainer<'a, Message, Renderer: iced_native::Renderer> {
34 padding: Padding,
35 content: Element<'a, Message, Renderer>,
36 width: Length,
37 height: Length,
38 max_width: u32,
39 max_height: u32,
40 horizontal_alignment: Alignment,
41 vertical_alignment: Alignment,
42 style: Box<dyn self::style::StyleSheet>,
43 }
44
45 impl<'a, Message, Renderer> HoverContainer<'a, Message, Renderer>
46 where
47 Renderer: iced_native::Renderer,
48 {
49 pub fn new<T>(content: T) -> Self
50 where
51 T: Into<Element<'a, Message, Renderer>>,
52 {
53 HoverContainer {
54 padding: Padding::ZERO,
55 width: Length::Shrink,
56 height: Length::Shrink,
57 max_width: u32::MAX,
58 max_height: u32::MAX,
59 horizontal_alignment: Alignment::Start,
60 vertical_alignment: Alignment::Start,
61 style: Box::<crate::style::HoverContainer>::default(),
62 content: content.into(),
63 }
64 }
65
66 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
68 self.padding = padding.into();
69 self
70 }
71
72 pub fn width(mut self, width: Length) -> Self {
74 self.width = width;
75 self
76 }
77
78 pub fn height(mut self, height: Length) -> Self {
80 self.height = height;
81 self
82 }
83
84 pub fn max_width(mut self, max_width: u32) -> Self {
86 self.max_width = max_width;
87 self
88 }
89
90 pub fn max_height(mut self, max_height: u32) -> Self {
92 self.max_height = max_height;
93 self
94 }
95
96 pub fn align_x(mut self, alignment: Alignment) -> Self {
98 self.horizontal_alignment = alignment;
99 self
100 }
101
102 pub fn align_y(mut self, alignment: Alignment) -> Self {
104 self.vertical_alignment = alignment;
105 self
106 }
107
108 pub fn center_x(mut self) -> Self {
110 self.horizontal_alignment = Alignment::Center;
111 self
112 }
113
114 pub fn center_y(mut self) -> Self {
116 self.vertical_alignment = Alignment::Center;
117 self
118 }
119
120 pub fn style(mut self, stylesheet: impl Into<Box<dyn self::style::StyleSheet>>) -> Self {
122 self.style = stylesheet.into();
123 self
124 }
125 }
126
127 impl<'a, Message, Renderer> Widget<Message, Renderer> for HoverContainer<'a, Message, Renderer>
128 where
129 Renderer: iced_native::Renderer,
130 {
131 fn width(&self) -> Length {
132 self.width
133 }
134
135 fn height(&self) -> Length {
136 self.height
137 }
138
139 fn layout(&self, renderer: &Renderer, limits: &Limits) -> Node {
140 let limits = limits
141 .loose()
142 .max_width(self.max_width as f32)
143 .max_height(self.max_height as f32)
144 .width(self.width)
145 .height(self.height)
146 .pad(self.padding);
147
148 let mut content = self.content.as_widget().layout(renderer, &limits.loose());
149 let size = limits.resolve(content.size());
150
151 content.move_to(Point::new(
152 self.padding.left.into(),
153 self.padding.top.into(),
154 ));
155 content.align(self.horizontal_alignment, self.vertical_alignment, size);
156
157 Node::with_children(size.pad(self.padding), vec![content])
158 }
159
160 fn draw(
161 &self,
162 state: &iced_native::widget::Tree,
163 renderer: &mut Renderer,
164 theme: &Renderer::Theme,
165 style: &iced_native::renderer::Style,
166 layout: Layout<'_>,
167 cursor_position: Point,
168 viewport: &Rectangle,
169 ) {
170 let is_hovered = layout.bounds().contains(cursor_position);
171 let container_style = if is_hovered {
172 self.style.hovered()
173 } else {
174 self.style.style()
175 };
176 renderer.fill_quad(
177 Quad {
178 bounds: layout.bounds(),
179 border_radius: iced_native::renderer::BorderRadius::from(
180 container_style.border_radius,
181 ),
182 border_color: container_style.border_color,
183 border_width: container_style.border_width,
184 },
185 container_style
186 .background
187 .unwrap_or_else(|| Color::TRANSPARENT.into()),
188 );
189 self.content.as_widget().draw(
190 &state.children[0],
191 renderer,
192 theme,
193 &iced_native::renderer::Style {
194 text_color: container_style.text_color.unwrap_or(style.text_color),
195 },
196 layout.children().next().unwrap(),
197 cursor_position,
198 viewport,
199 );
200 }
201
202 fn diff(&self, tree: &mut Tree) {
203 tree.diff_children(std::slice::from_ref(&self.content))
204 }
205
206 fn children(&self) -> Vec<Tree> {
207 vec![Tree::new(&self.content)]
208 }
209
210 fn operate(
211 &self,
212 tree: &mut Tree,
213 layout: Layout<'_>,
214 renderer: &Renderer,
215 operation: &mut dyn Operation<Message>,
216 ) {
217 operation.container(None, &mut |operation| {
218 self.content.as_widget().operate(
219 &mut tree.children[0],
220 layout.children().next().unwrap(),
221 renderer,
222 operation,
223 );
224 });
225 }
226
227 fn overlay<'b>(
228 &'b mut self,
229 state: &'b mut Tree,
230 layout: Layout<'_>,
231 renderer: &Renderer,
232 ) -> Option<overlay::Element<'b, Message, Renderer>> {
233 self.content.as_widget_mut().overlay(
234 &mut state.children[0],
235 layout.children().next().unwrap(),
236 renderer,
237 )
238 }
239
240 fn on_event(
241 &mut self,
242 state: &mut iced_native::widget::Tree,
243 event: Event,
244 layout: Layout<'_>,
245 cursor_position: Point,
246 renderer: &Renderer,
247 clipboard: &mut dyn Clipboard,
248 shell: &mut Shell<'_, Message>,
249 ) -> iced_native::event::Status {
250 self.content.as_widget_mut().on_event(
251 &mut state.children[0],
252 event,
253 layout.children().next().unwrap(),
254 cursor_position,
255 renderer,
256 clipboard,
257 shell,
258 )
259 }
260 }
261
262 impl<'a, Message, Renderer> From<HoverContainer<'a, Message, Renderer>>
263 for Element<'a, Message, Renderer>
264 where
265 Renderer: 'a + iced_native::Renderer,
266 Message: 'a,
267 {
268 fn from(
269 container: HoverContainer<'a, Message, Renderer>,
270 ) -> Element<'a, Message, Renderer> {
271 Element::new(container)
272 }
273 }
274
275 pub mod style {
276 use iced::{Background, Color};
277
278 #[derive(Debug, Clone)]
279 pub struct Style {
280 pub text_color: Option<Color>,
281 pub background: Option<Background>,
282 pub border_radius: f32,
283 pub border_width: f32,
284 pub border_color: Color,
285 }
286
287 impl std::default::Default for Style {
288 fn default() -> Self {
289 Self {
290 text_color: None,
291 background: None,
292 border_radius: 0.0,
293 border_width: 0.0,
294 border_color: Color::TRANSPARENT,
295 }
296 }
297 }
298
299 pub trait StyleSheet {
301 fn style(&self) -> Style;
303
304 fn hovered(&self) -> Style;
305 }
306
307 struct Default;
308
309 impl StyleSheet for Default {
310 fn style(&self) -> Style {
311 Style {
312 text_color: None,
313 background: None,
314 border_radius: 0.0,
315 border_width: 0.0,
316 border_color: Color::TRANSPARENT,
317 }
318 }
319
320 fn hovered(&self) -> Style {
321 self.style()
322 }
323 }
324
325 impl std::default::Default for Box<dyn StyleSheet> {
326 fn default() -> Self {
327 Box::new(Default)
328 }
329 }
330
331 impl<T> From<T> for Box<dyn StyleSheet>
332 where
333 T: 'static + StyleSheet,
334 {
335 fn from(style: T) -> Self {
336 Box::new(style)
337 }
338 }
339 }
340}