floem/views/
container.rs

1#![deny(missing_docs)]
2
3use floem_reactive::{Scope, UpdaterEffect};
4
5use crate::{
6    context::UpdateCx,
7    view::ViewId,
8    view::{IntoView, View},
9};
10
11/// A simple wrapper around another View.
12///
13/// Wrapping a [View](crate::view::View) with a [`Container`] allows using another
14/// set of styles completely separate from the child View that is being wrapped.
15pub struct Container {
16    id: ViewId,
17    child_scope: Scope,
18}
19
20impl Container {
21    /// Creates a new container wrapping the given child view.
22    ///
23    /// ## Example
24    /// ```rust
25    /// use floem::views::{Container, Label};
26    ///
27    /// let wrapped = Container::new(Label::new("Content"));
28    /// ```
29    pub fn new(child: impl IntoView) -> Self {
30        let id = ViewId::new();
31        id.set_children([child.into_view()]);
32        Container {
33            id,
34            child_scope: Scope::current(),
35        }
36    }
37
38    /// Creates a new container with derived (reactive) content.
39    ///
40    /// The content function is called initially and re-called whenever
41    /// its reactive dependencies change, replacing the container's child.
42    ///
43    /// ## Example
44    /// ```rust
45    /// use floem::prelude::*;
46    /// use floem::views::{Container, Label};
47    ///
48    /// let count = RwSignal::new(0);
49    ///
50    /// Container::derived(move || {
51    ///     Label::derived(move || format!("Count: {}", count.get()))
52    /// });
53    /// ```
54    pub fn derived<CF, IV>(content: CF) -> Self
55    where
56        CF: Fn() -> IV + 'static,
57        IV: IntoView + 'static,
58    {
59        let id = ViewId::new();
60        let content_fn = Box::new(Scope::current().enter_child(move |_| content().into_view()));
61
62        let (child, child_scope) = UpdaterEffect::new(
63            move || content_fn(()),
64            move |(new_view, new_scope)| {
65                let old_child = id.children();
66                id.set_children([new_view]);
67                id.update_state((old_child, new_scope));
68            },
69        );
70
71        id.set_children([child]);
72        Container { id, child_scope }
73    }
74
75    /// Creates a new container with a specific ViewId wrapping the given child view.
76    ///
77    /// This is useful when you need to control the ViewId for lazy view creation.
78    pub fn with_id(id: ViewId, child: impl IntoView) -> Self {
79        id.set_children([child.into_view()]);
80        Container {
81            id,
82            child_scope: Scope::current(),
83        }
84    }
85}
86
87/// A simple wrapper around another View
88///
89/// Wrapping a [View](crate::view::View) with a [`Container`] allows using another
90/// set of styles completely separate from the child View that is being wrapped.
91#[deprecated(since = "0.2.0", note = "Use Container::new() instead")]
92pub fn container<V: IntoView + 'static>(child: V) -> Container {
93    Container::new(child)
94}
95
96impl View for Container {
97    fn id(&self) -> ViewId {
98        self.id
99    }
100
101    fn debug_name(&self) -> std::borrow::Cow<'static, str> {
102        "Container".into()
103    }
104
105    fn update(&mut self, cx: &mut UpdateCx, state: Box<dyn std::any::Any>) {
106        if let Ok(val) = state.downcast::<(Vec<ViewId>, Scope)>() {
107            let old_child_scope = self.child_scope;
108            let (old_children, child_scope) = *val;
109            self.child_scope = child_scope;
110            for child in old_children {
111                cx.window_state.remove_view(child);
112            }
113            old_child_scope.dispose();
114            self.id.request_all();
115        }
116    }
117}
118
119/// A trait that adds a `container` method to any type that implements `IntoView`.
120pub trait ContainerExt {
121    /// Wrap the view in a container.
122    fn container(self) -> Container;
123}
124
125impl<T: IntoView + 'static> ContainerExt for T {
126    fn container(self) -> Container {
127        Container::new(self)
128    }
129}