diff --git a/crates/egui/src/containers/modal.rs b/crates/egui/src/containers/modal.rs index 83ff3d0684a..ab457b36dbd 100644 --- a/crates/egui/src/containers/modal.rs +++ b/crates/egui/src/containers/modal.rs @@ -3,6 +3,12 @@ use crate::{ }; use emath::{Align2, Vec2}; +/// A modal dialog. +/// Similar to a [`crate::Window`] but centered and with a backdrop that +/// blocks input to the rest of the UI. +/// +/// You can show multiple modals on top of each other. The top most modal will always be +/// the most recently shown one. pub struct Modal { pub area: Area, pub backdrop_color: Color32, @@ -10,17 +16,52 @@ pub struct Modal { } impl Modal { + /// Create a new Modal. The id is passed to the area. pub fn new(id: Id) -> Self { Self { - area: Area::new(id) - .sense(Sense::hover()) - .anchor(Align2::CENTER_CENTER, Vec2::ZERO) - .order(Order::Foreground), + area: Self::default_area(id), backdrop_color: Color32::from_black_alpha(100), frame: None, } } + /// Returns an area customized for a modal. + /// Makes these changes to the default area: + /// - sense: hover + /// - anchor: center + /// - order: foreground + pub fn default_area(id: Id) -> Area { + Area::new(id) + .sense(Sense::hover()) + .anchor(Align2::CENTER_CENTER, Vec2::ZERO) + .order(Order::Foreground) + } + + /// Set the frame of the modal. + /// + /// Default is [`Frame::popup`]. + pub fn frame(mut self, frame: Frame) -> Self { + self.frame = Some(frame); + self + } + + /// Set the backdrop color of the modal. + /// + /// Default is `Color32::from_black_alpha(100)`. + pub fn backdrop_color(mut self, color: Color32) -> Self { + self.backdrop_color = color; + self + } + + /// Set the area of the modal. + /// + /// Default is [`Modal::default_area`]. + pub fn area(mut self, area: Area) -> Self { + self.area = area; + self + } + + /// Show the modal. pub fn show(self, ctx: &Context, content: impl FnOnce(&mut Ui) -> T) -> ModalResponse { let (is_top_modal, any_popup_open) = ctx.memory_mut(|mem| { mem.set_modal_layer(self.area.layer()); @@ -33,7 +74,6 @@ impl Modal { inner: (inner, backdrop_response), response, } = self.area.show(ctx, |ui| { - // TODO: Is screen_rect the right thing to use here? let mut backdrop = ui.new_child(UiBuilder::new().max_rect(ui.ctx().screen_rect())); let backdrop_response = backdrop_ui(&mut backdrop, self.backdrop_color); @@ -81,11 +121,20 @@ fn backdrop_ui(ui: &mut Ui, color: Color32) -> Response { response } +/// The response of a modal dialog. pub struct ModalResponse { + /// The response of the modal contents pub response: Response, + + /// The response of the modal backdrop pub backdrop_response: Response, + + /// The inner response from the content closure pub inner: T, + + /// Is this the top most modal? pub is_top_modal: bool, + /// Is there any popup open? /// We need to check this before the modal contents are shown, so we can know if any popup /// was open when checking if the escape key was clicked.