Skip to main content

iced_widget/pane_grid/
content.rs

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
10/// The content of a [`Pane`].
11///
12/// [`Pane`]: super::Pane
13pub 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    /// Creates a new [`Content`] with the provided body.
29    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    /// Sets the [`TitleBar`] of the [`Content`].
44    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    /// Sets the style of the [`Content`].
56    #[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    /// Sets the style class of the [`Content`].
66    #[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    /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].
107    ///
108    /// [`Renderer`]: core::Renderer
109    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}