1use iced::{Limits, Size};
5use iced_core::layout::Node;
6
7use iced_core::Element;
8use iced_core::Overlay;
9use iced_core::event::{self, Event};
10use iced_core::layout;
11use iced_core::mouse;
12use iced_core::overlay;
13use iced_core::renderer::{self};
14use iced_core::widget::Operation;
15use iced_core::widget::tree::Tree;
16use iced_core::{Clipboard, Layout, Length, Point, Rectangle, Shell, Vector, Widget};
17
18pub struct Toaster<'a, Message, Theme, Renderer> {
19 toasts: Element<'a, Message, Theme, Renderer>,
20 content: Element<'a, Message, Theme, Renderer>,
21 is_empty: bool,
22}
23
24impl<'a, Message, Theme, Renderer> Toaster<'a, Message, Theme, Renderer> {
25 pub fn new(
26 toasts: Element<'a, Message, Theme, Renderer>,
27 content: Element<'a, Message, Theme, Renderer>,
28 is_empty: bool,
29 ) -> Self {
30 Self {
31 toasts,
32 content,
33 is_empty,
34 }
35 }
36}
37
38impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
39 for Toaster<'_, Message, Theme, Renderer>
40where
41 Renderer: iced_core::Renderer,
42{
43 fn size(&self) -> Size<Length> {
44 self.content.as_widget().size()
45 }
46
47 fn layout(
48 &mut self,
49 tree: &mut Tree,
50 renderer: &Renderer,
51 limits: &layout::Limits,
52 ) -> layout::Node {
53 self.content
54 .as_widget_mut()
55 .layout(&mut tree.children[0], renderer, limits)
56 }
57
58 fn draw(
59 &self,
60 tree: &Tree,
61 renderer: &mut Renderer,
62 theme: &Theme,
63 style: &renderer::Style,
64 layout: Layout<'_>,
65 cursor: mouse::Cursor,
66 viewport: &Rectangle,
67 ) {
68 self.content.as_widget().draw(
69 &tree.children[0],
70 renderer,
71 theme,
72 style,
73 layout,
74 cursor,
75 viewport,
76 );
77 }
78
79 fn children(&self) -> Vec<Tree> {
80 vec![Tree::new(&self.content), Tree::new(&self.toasts)]
81 }
82
83 fn diff(&mut self, tree: &mut Tree) {
84 tree.diff_children(&mut [&mut self.content, &mut self.toasts]);
85 }
86
87 fn operate<'b>(
88 &'b mut self,
89 state: &'b mut Tree,
90 layout: Layout<'_>,
91 renderer: &Renderer,
92 operation: &mut dyn Operation<()>,
93 ) {
94 self.content
95 .as_widget_mut()
96 .operate(&mut state.children[0], layout, renderer, operation);
97 }
98
99 fn update(
100 &mut self,
101 state: &mut Tree,
102 event: &Event,
103 layout: Layout<'_>,
104 cursor: mouse::Cursor,
105 renderer: &Renderer,
106 clipboard: &mut dyn Clipboard,
107 shell: &mut Shell<'_, Message>,
108 viewport: &Rectangle,
109 ) {
110 self.content.as_widget_mut().update(
111 &mut state.children[0],
112 event,
113 layout,
114 cursor,
115 renderer,
116 clipboard,
117 shell,
118 viewport,
119 )
120 }
121
122 fn mouse_interaction(
123 &self,
124 state: &Tree,
125 layout: Layout<'_>,
126 cursor: mouse::Cursor,
127 viewport: &Rectangle,
128 renderer: &Renderer,
129 ) -> mouse::Interaction {
130 self.content.as_widget().mouse_interaction(
131 &state.children[0],
132 layout,
133 cursor,
134 viewport,
135 renderer,
136 )
137 }
138
139 fn overlay<'b>(
140 &'b mut self,
141 state: &'b mut Tree,
142 layout: Layout<'b>,
143 renderer: &Renderer,
144 viewport: &Rectangle,
145 translation: Vector,
146 ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
147 if self.is_empty {
149 self.content.as_widget_mut().overlay(
150 &mut state.children[0],
151 layout,
152 renderer,
153 viewport,
154 translation,
155 )
156 } else {
157 let bounds = layout.bounds();
158
159 Some(overlay::Element::new(Box::new(ToasterOverlay::new(
160 &mut state.children[1],
161 &mut self.toasts,
162 ))))
163 }
164 }
165
166 fn drag_destinations(
167 &self,
168 state: &Tree,
169 layout: Layout<'_>,
170 renderer: &Renderer,
171 dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
172 ) {
173 self.content.as_widget().drag_destinations(
174 &state.children[0],
175 layout,
176 renderer,
177 dnd_rectangles,
178 );
179 }
180}
181
182struct ToasterOverlay<'a, 'b, Message, Theme = iced::Theme, Renderer = iced::Renderer> {
183 state: &'b mut Tree,
184 element: &'b mut Element<'a, Message, Theme, Renderer>,
185}
186
187impl<'a, 'b, Message, Theme, Renderer> ToasterOverlay<'a, 'b, Message, Theme, Renderer>
188where
189 Renderer: renderer::Renderer,
190{
191 fn new(state: &'b mut Tree, element: &'b mut Element<'a, Message, Theme, Renderer>) -> Self {
192 Self { state, element }
193 }
194}
195
196impl<Message, Theme, Renderer> Overlay<Message, Theme, Renderer>
197 for ToasterOverlay<'_, '_, Message, Theme, Renderer>
198where
199 Renderer: renderer::Renderer,
200{
201 fn layout(&mut self, renderer: &Renderer, bounds: Size) -> Node {
202 let limits = Limits::new(Size::ZERO, bounds);
203
204 let node = self
205 .element
206 .as_widget_mut()
207 .layout(self.state, renderer, &limits);
208
209 let offset = 15.;
210
211 let position = Point::new(
212 (bounds.width / 2.) - (node.size().width / 2.),
213 bounds.height - (node.size().height + offset),
214 );
215
216 node.move_to(position)
217 }
218
219 fn draw(
220 &self,
221 renderer: &mut Renderer,
222 theme: &Theme,
223 style: &renderer::Style,
224 layout: Layout<'_>,
225 cursor: mouse::Cursor,
226 ) {
227 let bounds = layout.bounds();
228 self.element
229 .as_widget()
230 .draw(self.state, renderer, theme, style, layout, cursor, &bounds);
231 }
232
233 fn update(
234 &mut self,
235 event: &Event,
236 layout: Layout<'_>,
237 cursor: mouse::Cursor,
238 renderer: &Renderer,
239 clipboard: &mut dyn Clipboard,
240 shell: &mut Shell<Message>,
241 ) {
242 self.element.as_widget_mut().update(
243 self.state,
244 event,
245 layout,
246 cursor,
247 renderer,
248 clipboard,
249 shell,
250 &layout.bounds(),
251 );
252 }
253
254 fn mouse_interaction(
255 &self,
256 layout: Layout<'_>,
257 cursor: mouse::Cursor,
258 renderer: &Renderer,
259 ) -> mouse::Interaction {
260 self.element.as_widget().mouse_interaction(
261 self.state,
262 layout,
263 cursor,
264 &layout.bounds(),
265 renderer,
266 )
267 }
268
269 fn overlay<'c>(
270 &'c mut self,
271 layout: Layout<'c>,
272 renderer: &Renderer,
273 ) -> Option<overlay::Element<'c, Message, Theme, Renderer>> {
274 self.element.as_widget_mut().overlay(
275 self.state,
276 layout,
277 renderer,
278 &layout.bounds(),
279 Default::default(),
280 )
281 }
282}
283
284impl<'a, Message, Theme, Renderer> From<Toaster<'a, Message, Theme, Renderer>>
285 for Element<'a, Message, Theme, Renderer>
286where
287 Renderer: renderer::Renderer + 'a,
288 Theme: 'a,
289 Message: 'a,
290{
291 fn from(
292 toaster: Toaster<'a, Message, Theme, Renderer>,
293 ) -> Element<'a, Message, Theme, Renderer> {
294 Element::new(toaster)
295 }
296}