1use crate::container;
2use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget::{self, Tree, Void};
7use crate::core::{self, Event, Layout, Point, Rectangle, Shell, Size, Vector, Widget};
8use crate::pane_grid::{Draggable, TitleBar};
9
10pub struct Content<'a, Message, T, W, Theme = crate::Theme, Renderer = crate::Renderer>
14where
15 Theme: container::Catalog,
16 Renderer: core::Renderer,
17{
18 title_bar: Option<TitleBar<'a, Message, T, Theme, Renderer>>,
19 body: W,
20 class: Theme::Class<'a>,
21}
22
23impl<'a, Message, W, Theme, Renderer> Content<'a, Message, Void, W, Theme, Renderer>
24where
25 Theme: container::Catalog,
26 Renderer: core::Renderer,
27{
28 pub fn new(body: W) -> Self {
30 Self {
31 title_bar: None,
32 body,
33 class: Theme::default(),
34 }
35 }
36}
37
38impl<'a, Message, T, W, Theme, Renderer> Content<'a, Message, T, W, Theme, Renderer>
39where
40 Theme: container::Catalog,
41 Renderer: core::Renderer,
42{
43 pub fn title_bar<Title>(
45 self,
46 title_bar: TitleBar<'a, Message, Title, Theme, Renderer>,
47 ) -> Content<'a, Message, Title, W, Theme, Renderer> {
48 Content {
49 title_bar: Some(title_bar),
50 body: self.body,
51 class: self.class,
52 }
53 }
54
55 #[must_use]
57 pub fn style(mut self, style: impl Fn(&Theme) -> container::Style + 'a) -> Self
58 where
59 Theme::Class<'a>: From<container::StyleFn<'a, Theme>>,
60 {
61 self.class = (Box::new(style) as container::StyleFn<'a, Theme>).into();
62 self
63 }
64
65 #[cfg(feature = "advanced")]
67 #[must_use]
68 pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {
69 self.class = class.into();
70 self
71 }
72}
73
74impl<Message, T, W, Theme, Renderer> Content<'_, Message, T, W, Theme, Renderer>
75where
76 Theme: container::Catalog,
77 Renderer: core::Renderer,
78 T: Widget<Message, Theme, Renderer>,
79 W: Widget<Message, Theme, Renderer>,
80{
81 pub(super) fn state(&self) -> Tree {
82 let children = if let Some(title_bar) = self.title_bar.as_ref() {
83 vec![Tree::new(&self.body), title_bar.state()]
84 } else {
85 vec![Tree::new(&self.body), Tree::empty()]
86 };
87
88 Tree {
89 children,
90 ..Tree::empty()
91 }
92 }
93
94 pub(super) fn diff(&mut self, tree: &mut Tree) {
95 if tree.children.len() == 2 {
96 if let Some(title_bar) = &mut self.title_bar {
97 title_bar.diff(&mut tree.children[1]);
98 }
99
100 tree.children[0].diff(&mut self.body);
101 } else {
102 *tree = self.state();
103 }
104 }
105
106 pub fn draw(
110 &self,
111 tree: &Tree,
112 renderer: &mut Renderer,
113 theme: &Theme,
114 style: &renderer::Style,
115 layout: Layout,
116 cursor: mouse::Cursor,
117 viewport: &Rectangle,
118 ) {
119 let bounds = layout.bounds();
120
121 {
122 let style = theme.style(&self.class);
123
124 container::draw_background(renderer, &style, bounds);
125 }
126
127 if let Some(title_bar) = &self.title_bar {
128 let mut children = layout.iter(&tree.children);
129 let (body_layout, body_tree) = children.next().unwrap();
130 let (title_bar_layout, title_bar_tree) = children.next().unwrap();
131
132 let show_controls = cursor.is_over(bounds);
133
134 self.body.draw(
135 body_tree,
136 renderer,
137 theme,
138 style,
139 body_layout,
140 cursor,
141 viewport,
142 );
143
144 title_bar.draw(
145 title_bar_tree,
146 renderer,
147 theme,
148 style,
149 title_bar_layout,
150 cursor,
151 viewport,
152 show_controls,
153 );
154 } else {
155 self.body.draw(
156 &tree.children[0],
157 renderer,
158 theme,
159 style,
160 layout,
161 cursor,
162 viewport,
163 );
164 }
165 }
166
167 pub(crate) fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
168 if let Some(title_bar) = &mut self.title_bar {
169 let max_size = limits.max;
170
171 title_bar.layout(
172 &mut tree.children[1],
173 renderer,
174 &layout::Limits::new(Size::ZERO, max_size),
175 );
176
177 let title_bar_size = tree.children[1].size;
178
179 self.body.layout(
180 &mut tree.children[0],
181 renderer,
182 &layout::Limits::new(
183 Size::ZERO,
184 Size::new(max_size.width, max_size.height - title_bar_size.height),
185 ),
186 );
187
188 tree.children[1].translation = Vector::ZERO;
189 tree.children[0].translation = Vector::new(0.0, title_bar_size.height);
190
191 tree.size = max_size;
192 } else {
193 self.body.layout(&mut tree.children[0], renderer, limits);
194
195 tree.size = tree.children[0].size;
196 }
197 }
198
199 pub(crate) fn operate(
200 &mut self,
201 tree: &mut Tree,
202 layout: Layout,
203 viewport: &Rectangle,
204 renderer: &Renderer,
205 operation: &mut dyn widget::Operation,
206 ) {
207 let (body_layout, body_tree) = if let Some(title_bar) = &mut self.title_bar {
208 let mut children = layout.iter_mut(&mut tree.children);
209 let (body_layout, body_tree) = children.next().unwrap();
210 let (title_bar_layout, title_bar_tree) = children.next().unwrap();
211
212 title_bar.operate(
213 title_bar_tree,
214 title_bar_layout,
215 viewport,
216 renderer,
217 operation,
218 );
219
220 (body_layout, body_tree)
221 } else {
222 layout.iter_mut(&mut tree.children).next().unwrap()
223 };
224
225 self.body
226 .operate(body_tree, body_layout, viewport, renderer, operation);
227 }
228
229 pub(crate) fn update(
230 &mut self,
231 tree: &mut Tree,
232 event: &Event,
233 layout: Layout,
234 cursor: mouse::Cursor,
235 renderer: &Renderer,
236 shell: &mut Shell<'_, Message>,
237 viewport: &Rectangle,
238 is_picked: bool,
239 ) {
240 let (body_layout, body_tree) = if let Some(title_bar) = &mut self.title_bar {
241 let mut children = layout.iter_mut(&mut tree.children);
242 let (body_layout, body_tree) = children.next().unwrap();
243 let (title_bar_layout, title_bar_tree) = children.next().unwrap();
244
245 title_bar.update(
246 title_bar_tree,
247 event,
248 title_bar_layout,
249 cursor,
250 renderer,
251 shell,
252 viewport,
253 );
254
255 (body_layout, body_tree)
256 } else {
257 layout.iter_mut(&mut tree.children).next().unwrap()
258 };
259
260 if !is_picked {
261 self.body.update(
262 body_tree,
263 event,
264 body_layout,
265 cursor,
266 renderer,
267 shell,
268 viewport,
269 );
270 }
271 }
272
273 pub(crate) fn grid_interaction(
274 &self,
275 tree: &Tree,
276 layout: Layout,
277 cursor: mouse::Cursor,
278 drag_enabled: bool,
279 ) -> Option<mouse::Interaction> {
280 let title_bar = self.title_bar.as_ref()?;
281
282 let (title_bar_layout, _) = layout.iter(&tree.children).nth(1).unwrap();
283
284 let is_over_pick_area = cursor
285 .position()
286 .map(|cursor_position| {
287 title_bar.is_over_pick_area(&tree.children[1], title_bar_layout, cursor_position)
288 })
289 .unwrap_or_default();
290
291 if is_over_pick_area && drag_enabled {
292 return Some(mouse::Interaction::Grab);
293 }
294
295 None
296 }
297
298 pub(crate) fn mouse_interaction(
299 &self,
300 tree: &Tree,
301 layout: Layout,
302 cursor: mouse::Cursor,
303 viewport: &Rectangle,
304 renderer: &Renderer,
305 drag_enabled: bool,
306 ) -> mouse::Interaction {
307 let (body_layout, title_bar_interaction) = if let Some(title_bar) = &self.title_bar {
308 let mut children = layout.iter(&tree.children);
309 let (body_layout, _) = children.next().unwrap();
310 let (title_bar_layout, title_bar_tree) = children.next().unwrap();
311
312 let is_over_pick_area = cursor
313 .position()
314 .map(|cursor_position| {
315 title_bar.is_over_pick_area(title_bar_tree, title_bar_layout, cursor_position)
316 })
317 .unwrap_or_default();
318
319 if is_over_pick_area && drag_enabled {
320 return mouse::Interaction::Grab;
321 }
322
323 let mouse_interaction = title_bar.mouse_interaction(
324 title_bar_tree,
325 title_bar_layout,
326 cursor,
327 viewport,
328 renderer,
329 );
330
331 (body_layout, mouse_interaction)
332 } else {
333 (layout, mouse::Interaction::default())
334 };
335
336 self.body
337 .mouse_interaction(&tree.children[0], body_layout, cursor, viewport, renderer)
338 .max(title_bar_interaction)
339 }
340
341 pub(crate) fn overlay<'b>(
342 &'b mut self,
343 tree: &'b mut Tree,
344 layout: Layout,
345 renderer: &Renderer,
346 viewport: &Rectangle,
347 translation: Vector,
348 window: Size,
349 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
350 if let Some(title_bar) = self.title_bar.as_mut() {
351 let mut children = layout.iter_mut(&mut tree.children);
352 let (body_layout, body_tree) = children.next().unwrap();
353 let (title_bar_layout, title_bar_tree) = children.next().unwrap();
354
355 let title_bar_overlays = title_bar.overlay(
356 title_bar_tree,
357 title_bar_layout,
358 renderer,
359 viewport,
360 translation,
361 window,
362 );
363
364 let body_overlays = self.body.overlay(
365 body_tree,
366 body_layout,
367 renderer,
368 viewport,
369 translation,
370 window,
371 );
372
373 title_bar_overlays
374 .into_iter()
375 .chain(body_overlays)
376 .collect()
377 } else {
378 let (layout, body_tree) = layout.iter_mut(&mut tree.children).next().unwrap();
379
380 self.body
381 .overlay(body_tree, layout, renderer, viewport, translation, window)
382 }
383 }
384}
385
386impl<Message, T, W, Theme, Renderer> Draggable for &Content<'_, Message, T, W, Theme, Renderer>
387where
388 Theme: container::Catalog,
389 Renderer: core::Renderer,
390 T: Widget<Message, Theme, Renderer>,
391{
392 fn can_be_dragged_at(&self, tree: &Tree, layout: Layout, cursor_position: Point) -> bool {
393 if let Some(title_bar) = &self.title_bar {
394 let (title_bar_layout, _) = layout.iter(&tree.children).nth(1).unwrap();
395
396 title_bar.is_over_pick_area(&tree.children[1], title_bar_layout, cursor_position)
397 } else {
398 false
399 }
400 }
401}