Crates.io | egui_dialogs |
lib.rs | egui_dialogs |
version | 0.3.5 |
source | src |
created_at | 2024-09-21 06:47:10.05915 |
updated_at | 2024-10-14 14:22:17.224558 |
description | Platform-agnostic, customizable dialogs for egui library. |
homepage | https://github.com/a-littlebit/egui_dialogs |
repository | https://github.com/a-littlebit/egui_dialogs |
max_upload_size | |
id | 1381990 |
size | 92,297 |
Platform-agnostic, customizable dialogs for egui library.
# cd into the crate directory
cargo run --example dialogs
Install the crate:
cargo add egui_dialogs
Then add a Dialogs
field to your App
struct:
use egui_dialogs::Dialogs;
pub struct MyApp<'a> {
// ... your other app states
dialogs: Dialogs<'a>,
}
Then somewhere in your App::update
function:
impl MyApp<'_> {
// ... your other app logic
pub fn update(&mut self, ctx: &egui::Context) {
self.dialogs.show(ctx);
// ... your other rendering logic
}
}
And when you want to show a dialog:
self.dialogs.info("Information", "This is an info dialog");
Use DialogDetails
struct to build
a dialog with custom attributes.
The following is an example to comfirm a window close request:
use std::{cell::RefCell, rc::Rc};
use egui_dialogs::{DialogDetails, StandardReply};
// in your app state
pub allow_to_close: Rc<RefCell<bool>>,
// and initialize it with false
// when received a close request in the update function
if ctx.input(|i| i.viewport().close_requested()) {
let ctx = ctx.clone();
let allow_to_close = Rc::clone(&self.allow_to_close);
if *allow_to_close.borrow() {
// run your close logic
} else {
// build and show a confirm dialog
DialogDetails::confirm("Close", "Are you sure you want to close the window?")
.on_reply(move |res| {
if res == StandardReply::Ok {
*allow_to_close.borrow_mut() = true;
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
})
.show(&mut self.dialogs);
}
}
As rust compiler thinks that your dialog callbacks may be called at any time, it limits your callback from visiting your app states.
To avoid filling your app state struct with Rc
and RefCell
, you can specify an ID for your dialog and use it to identify the dialog reply when a dialog is closed:
use egui::Id;
use egui_dialogs::{DialogDetails, StandardReply};
// in your app state
pub allow_to_close: bool,
// and initialize it with false
// define an ID for your dialog
const CLOSE_CONFIRM_DIALOG_ID: &str = "close_confirm_dialog";
// in your update function
if let Some(res) = self.dialogs.show(ctx) {
// handle reply from close confirmation dialog
if res.is_reply_of(CLOSE_CONFIRM_DIALOG_ID) {
match res.reply() {
Ok(StandardReply::Yes) => {
self.allow_to_close = true;
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
},
_ => {},
}
}
}
// when you want to show the dialog
if ctx.input(|i| i.viewport().close_requested()) {
if !self.allow_to_close {
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
DialogDetails::confirm("Close", "Are you sure you want to close the window?")
// specify the dialog ID
.with_id(CLOSE_CONFIRM_DIALOG_ID)
.show_if_absent(&mut self.dialogs);
}
}
You can show a customized dialog based on the standard dialogs:
use egui::include_image;
use egui_dialogs::{DialogDetails, StandardDialog, StandardReply};
let standard_dialog = StandardDialog::info("Information", "Now you can customize the dialog!")
.buttons(vec![
// use the standard buttons
StandardReply::Yes.into(),
// or add custom buttons with specific replies
("What?".into(), StandardReply::No)
])
.image(include_image!("assets/info.svg"));
DialogDetails::new(standard_dialog)
.on_reply(|res| {
match res {
StandardReply::Yes => println!("That's great!"),
StandardReply::No => println!("Emm...maybe you can try to see the example?"),
_ => panic!("I've never added such a reply!")
}
})
.show(&mut self.dialogs);
To show a completely customized dialog, you can first design your dialog state struct like this:
pub struct NameConfirmDialog {
name: String,
}
Then implement the Dialog
trait to implement dialog logic
with a generic type parameter to specify the dialog reply type:
use egui_dialogs::{Dialog, dialog_window, DialogContext};
impl Dialog<String> for NameConfirmDialog {
fn show(&mut self, ctx: &egui::Context, dctx: &DialogContext) -> Option<String> {
// return None if the user hasn't replied
let mut res = None;
// draw the dialog
dialog_window(ctx, dctx, "Confirm name")
.show(ctx, |ui| {
ui.label("What's your name: ");
ui.text_edit_singleline(&mut self.name);
if ui.button("Done").clicked() {
// set the reply and end the dialog
res = Some(self.name.clone());
}
});
res
}
}
The dialog_window
function is a helper function
to draw a suggested dialog window with a title and a close button.
Now you can show your customized dialog:
DialogDetails::new(NameConfirmDialog { name: "".into() })
.on_reply(|res| {
println!("Your name is {}", res);
})
.show(&mut self.dialogs);