egui-modal 0.6.0

a modal library for egui
Documentation
use egui::{self, DragValue};
use egui_modal::{Icon, Modal, ModalStyle};

struct ExampleApp {
    modal_style: ModalStyle,
    modal_title: String,
    modal_body: String,
    nested_modal_text: String,

    include_title: bool,
    include_body: bool,
    include_buttons: bool,
    close_on_outside_click: bool,

    dialog_icon: Option<Icon>,
}

impl Default for ExampleApp {
    fn default() -> Self {
        Self {
            modal_style: ModalStyle::default(),
            modal_title: "a modal".to_string(),
            modal_body: "here is the modal body".to_string(),

            nested_modal_text: String::new(),
            include_title: true,
            include_body: true,
            include_buttons: true,
            close_on_outside_click: false,

            dialog_icon: Some(Icon::Info),
        }
    }
}

impl eframe::App for ExampleApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::Window::new("egui-modal").show(ctx, |ui| {
            // you can put the modal creation and show logic wherever you want
            // (though of course it needs to be created before it can be used)
            let nested_modal = Modal::new(ctx, "nested_modal");
            let modal = Modal::new(ctx, "modal")
                .with_style(&self.modal_style)
                .with_close_on_outside_click(self.close_on_outside_click || !self.include_buttons);

            // the show function defines what is shown in the modal, but the modal
            // won't actually show until you do modal.open()
            modal.show(|ui| {
                // these helper functions are NOT mandatory to use, they just
                // help implement some styling with margins and separators
                // you can put whatever you like in here
                if self.include_title {
                    modal.title(ui, &mut self.modal_title);
                }
                // the "frame" of the modal refers to the container of the icon and body.
                // this helper just applies a margin specified by the ModalStyle
                modal.frame(ui, |ui| {
                    if self.include_body {
                        modal.body(ui, &self.modal_body);
                    }
                });
                if self.include_buttons {
                    modal.buttons(ui, |ui| {
                        if modal.button(ui, "close").clicked()
                            || (self.close_on_outside_click && modal.was_outside_clicked())
                        {
                            // all buttons created with the helper functions automatically
                            // close the modal on click, but you can close it yourself with
                            // ['modal.close()']
                            println!("hello world!")
                        }

                        modal.caution_button(ui, "button, but caution");
                        if modal.suggested_button(ui, "open another modal").clicked() {
                            // always close your previous modal before opening a new one otherwise weird
                            // layering things will happen. again, the helper functions for the buttons automatically
                            // close the modal on click, so we don't have to manually do that here
                            nested_modal.open();
                        }
                    })
                }
            });

            // a dialog is useful when you have a one-time occurance and you want to relay information to the user
            let mut dialog_modal = Modal::new(ctx, "dialog_modal").with_style(&self.modal_style);
            // make sure you don't forget to show the dialog!
            dialog_modal.show_dialog();

            ui.with_layout(egui::Layout::top_down_justified(egui::Align::Min), |ui| {
                if ui.button("open modal").clicked() {
                    modal.open();
                }

                if ui.button("open dialog").clicked() {
                    // [`.dialog()`] can be used to both set the visual info for the dialog
                    // and open it at the same time
                    let mut dialog_builder = dialog_modal
                        .dialog()
                        .with_title("this is a dialog")
                        .with_body("this helps for showing information about one-time events");
                    if let Some(dialog_icon) = self.dialog_icon.clone() {
                        dialog_builder = dialog_builder.with_icon(dialog_icon);
                    }
                    dialog_builder.open();
                }

                ui.separator();
                // to prevent locking the example window without any way to close the modal :)
                // remember to implement this yourself if you don't use buttons in your modal
                let mut cooc_enabled = self.close_on_outside_click || !self.include_buttons;
                ui.add_enabled_ui(self.include_buttons, |ui| {
                    if ui
                        .checkbox(&mut cooc_enabled, "close if click outside modal")
                        .clicked()
                    {
                        self.close_on_outside_click = !self.close_on_outside_click
                    };
                });
                ui.checkbox(&mut self.include_title, "include title");
                ui.checkbox(&mut self.include_body, "include body");
                ui.checkbox(&mut self.include_buttons, "include buttons");
                ui.separator();
                egui::Grid::new("options_grid")
                    .min_col_width(200.)
                    .striped(true)
                    .show(ui, |ui| {
                        ui.label("title");
                        ui.text_edit_singleline(&mut self.modal_title);
                        ui.end_row();

                        ui.label("body");
                        ui.text_edit_singleline(&mut self.modal_body);
                        ui.end_row();

                        let mut has_height = self.modal_style.default_height.is_some();
                        let mut has_width = self.modal_style.default_width.is_some();
                        if ui.checkbox(&mut has_height, "default height").changed() {
                            if has_height {
                                self.modal_style.default_height = Some(100.)
                            } else {
                                self.modal_style.default_height = None
                            }
                        }
                        if let Some(modal_height) = self.modal_style.default_height.as_mut() {
                            let modal_height = DragValue::new(modal_height).range(0..=1000);
                            ui.add_sized(ui.available_rect_before_wrap().size(), modal_height);
                        }
                        ui.end_row();

                        if ui.checkbox(&mut has_width, "default width").changed() {
                            if has_width {
                                self.modal_style.default_width = Some(100.)
                            } else {
                                self.modal_style.default_width = None
                            }
                        }
                        if let Some(modal_width) = self.modal_style.default_width.as_mut() {
                            let modal_width = DragValue::new(modal_width).range(0..=1000);
                            ui.add_sized(ui.available_rect_before_wrap().size(), modal_width);
                        }
                        ui.end_row();

                        ui.label("body margin");
                        let body_margin =
                            DragValue::new(&mut self.modal_style.body_margin).range(0..=20);
                        ui.add_sized(ui.available_rect_before_wrap().size(), body_margin);
                        ui.end_row();

                        ui.label("frame margin");
                        let frame_margin =
                            DragValue::new(&mut self.modal_style.frame_margin).range(0..=20);
                        ui.add_sized(ui.available_rect_before_wrap().size(), frame_margin);
                        ui.end_row();

                        ui.label("icon margin");
                        let icon_margin =
                            DragValue::new(&mut self.modal_style.icon_margin).range(0..=20);
                        ui.add_sized(ui.available_rect_before_wrap().size(), icon_margin);
                        ui.end_row();

                        ui.label("icon size");
                        let icon_size =
                            DragValue::new(&mut self.modal_style.icon_size).range(8..=48);
                        ui.add_sized(ui.available_rect_before_wrap().size(), icon_size);
                        ui.end_row();

                        ui.label("dialog icon");
                        let mut use_icon = self.dialog_icon.is_some();
                        ui.horizontal(|ui| {
                            if ui.checkbox(&mut use_icon, "use a dialog icon").clicked() {
                                if use_icon {
                                    self.dialog_icon = Some(Icon::Info);
                                } else {
                                    self.dialog_icon = None;
                                }
                            }
                            if let Some(icon) = self.dialog_icon.as_mut() {
                                ui.selectable_value(icon, Icon::Info, "info");
                                ui.selectable_value(icon, Icon::Warning, "warning");
                                ui.selectable_value(icon, Icon::Success, "success");
                                ui.selectable_value(icon, Icon::Error, "error");
                            }
                        });
                        ui.end_row();

                        ui.label("body alignment");
                        ui.horizontal(|ui| {
                            ui.selectable_value(
                                &mut self.modal_style.body_alignment,
                                egui::Align::Min,
                                "min",
                            );
                            ui.selectable_value(
                                &mut self.modal_style.body_alignment,
                                egui::Align::Center,
                                "center",
                            );
                            ui.selectable_value(
                                &mut self.modal_style.body_alignment,
                                egui::Align::Max,
                                "max",
                            );
                        });
                        ui.end_row();

                        ui.label("overlay color");
                        ui.color_edit_button_srgba(&mut self.modal_style.overlay_color);
                        ui.end_row();

                        ui.label("caution button (fill, text)");
                        ui.horizontal(|ui| {
                            ui.color_edit_button_srgba(&mut self.modal_style.caution_button_fill);
                            ui.color_edit_button_srgba(
                                &mut self.modal_style.caution_button_text_color,
                            );
                        });
                        ui.end_row();

                        ui.label("suggested button (fill, text)");
                        ui.horizontal(|ui| {
                            ui.color_edit_button_srgba(&mut self.modal_style.suggested_button_fill);
                            ui.color_edit_button_srgba(
                                &mut self.modal_style.suggested_button_text_color,
                            );
                        });
                        ui.end_row();

                        ui.label("icon colors (info, warning, success, error)");
                        ui.horizontal(|ui| {
                            ui.color_edit_button_srgba(&mut self.modal_style.info_icon_color);
                            ui.color_edit_button_srgba(&mut self.modal_style.warning_icon_color);
                            ui.color_edit_button_srgba(&mut self.modal_style.success_icon_color);
                            ui.color_edit_button_srgba(&mut self.modal_style.error_icon_color);
                        });
                        ui.end_row();
                    });
            });

            // why is this down here?? just wanted to show that you can put
            // the modal's [`.show()`] anywhere but we could have put this above
            // modal if we wanted
            nested_modal.show(|ui| {
                nested_modal.frame(ui, |ui| {
                    nested_modal.body(ui, "hello there!");
                    // you can put textboxes in here.
                    ui.text_edit_singleline(&mut self.nested_modal_text);
                });
                nested_modal.buttons(ui, |ui| {
                    nested_modal.button(ui, "close");
                })
            });
        });
    }
}
fn main() {
    let _ = eframe::run_native(
        "egui-modal example",
        eframe::NativeOptions::default(),
        Box::new(|_cc| Ok(Box::new(ExampleApp::default()))),
    );
}