Skip to main content

guise/overlay/
loading.rs

1//! `LoadingOverlay` — a dimming busy layer over a container.
2//!
3//! Stateless: render it as the **last child** of a `.relative()` container and
4//! flip [`LoadingOverlay::visible`]. While visible it fills the parent with
5//! the body color at 60% opacity, centers a [`Loader`], and occludes the mouse
6//! so the content underneath can't be interacted with.
7//!
8//! ```ignore
9//! div()
10//!     .relative() // required: the overlay is absolutely positioned
11//!     .child(form)
12//!     .child(LoadingOverlay::new().visible(self.saving))
13//! ```
14
15use gpui::prelude::*;
16use gpui::{div, px, App, IntoElement, Window};
17
18use crate::devtools::ProbedAny;
19use crate::feedback::Loader;
20use crate::theme::theme;
21
22/// A busy overlay for one container.
23#[derive(IntoElement)]
24pub struct LoadingOverlay {
25    visible: bool,
26    loader: Option<Loader>,
27}
28
29impl LoadingOverlay {
30    pub fn new() -> Self {
31        LoadingOverlay {
32            visible: false,
33            loader: None,
34        }
35    }
36
37    /// Show or hide the overlay. Hidden renders nothing at all.
38    pub fn visible(mut self, visible: bool) -> Self {
39        self.visible = visible;
40        self
41    }
42
43    /// Replace the default centered [`Loader`] (e.g. to change variant/color).
44    pub fn loader(mut self, loader: Loader) -> Self {
45        self.loader = Some(loader);
46        self
47    }
48}
49
50impl Default for LoadingOverlay {
51    fn default() -> Self {
52        LoadingOverlay::new()
53    }
54}
55
56impl RenderOnce for LoadingOverlay {
57    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
58        if !self.visible {
59            return div().into_any_element();
60        }
61
62        let t = theme(cx);
63        let scrim = t.body().alpha(0.6);
64
65        div()
66            .id("guise-loading-overlay")
67            .occlude()
68            .absolute()
69            .top(px(0.0))
70            .left(px(0.0))
71            .size_full()
72            .flex()
73            .items_center()
74            .justify_center()
75            .bg(scrim)
76            .child(self.loader.unwrap_or_default())
77            .into_any_element()
78            .probe_any("LoadingOverlay")
79            .into_any_element()
80    }
81}