Skip to main content

egui_charts/ui_kit/modal/dialogs/
confirm.rs

1//! Confirm Dialog
2//!
3//! A standard confirmation dialog with confirm/cancel buttons.
4
5use crate::localization as l10n;
6use egui::{Context, Id};
7
8use crate::tokens::DESIGN_TOKENS;
9use crate::ui_kit::dialog::DialogFooter;
10use crate::ui_kit::modal::Modal;
11
12/// Result of showing a confirm dialog
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ConfirmResult {
15    /// Dialog is still open, no action taken
16    None,
17    /// User confirmed the action
18    Confirmed,
19    /// User cancelled the action
20    Cancelled,
21}
22
23impl ConfirmResult {
24    /// Check if the user confirmed
25    pub fn is_confirmed(&self) -> bool {
26        matches!(self, ConfirmResult::Confirmed)
27    }
28
29    /// Check if the user cancelled
30    pub fn is_cancelled(&self) -> bool {
31        matches!(self, ConfirmResult::Cancelled)
32    }
33
34    /// Check if the dialog is still open
35    pub fn is_open(&self) -> bool {
36        matches!(self, ConfirmResult::None)
37    }
38}
39
40/// A confirmation dialog
41pub struct ConfirmDialog {
42    id: Id,
43    title: String,
44    message: String,
45    confirm_text: String,
46    cancel_text: String,
47    danger: bool,
48}
49
50impl ConfirmDialog {
51    /// Create a new confirm dialog
52    pub fn new(
53        id: impl std::hash::Hash + std::fmt::Debug,
54        title: impl Into<String>,
55        message: impl Into<String>,
56    ) -> Self {
57        Self {
58            id: Id::unique(id),
59            title: title.into(),
60            message: message.into(),
61            confirm_text: "Confirm".to_string(),
62            cancel_text: "Cancel".to_string(),
63            danger: false,
64        }
65    }
66
67    /// Set the confirm button text
68    pub fn confirm_text(mut self, text: impl Into<String>) -> Self {
69        self.confirm_text = text.into();
70        self
71    }
72
73    /// Set the cancel button text
74    pub fn cancel_text(mut self, text: impl Into<String>) -> Self {
75        self.cancel_text = text.into();
76        self
77    }
78
79    /// Mark this as a dangerous action (confirm button in the danger colour)
80    pub fn danger(mut self) -> Self {
81        self.danger = true;
82        self
83    }
84
85    /// Show the confirm dialog
86    ///
87    /// Returns the result of the dialog interaction. Escape, the close button and a click on
88    /// the backdrop cancel.
89    pub fn show(self, ctx: &Context, open: &mut bool) -> ConfirmResult {
90        let footer = DialogFooter::new(&self.confirm_text).secondary(&self.cancel_text);
91        let footer = if self.danger { footer.danger() } else { footer };
92
93        let Some(response) = Modal::new(self.id, &self.title)
94            .width(DESIGN_TOKENS.sizing.dialog.confirm_width)
95            .show(ctx, open, |ui| {
96                ui.label(l10n::text(ui.ctx(), &self.message));
97                footer.show(ui)
98            })
99        else {
100            return ConfirmResult::None;
101        };
102
103        let result = match response.inner {
104            (true, _) => ConfirmResult::Confirmed,
105            (_, true) => ConfirmResult::Cancelled,
106            _ if response.close_requested => ConfirmResult::Cancelled,
107            _ => ConfirmResult::None,
108        };
109        if result != ConfirmResult::None {
110            *open = false;
111        }
112        result
113    }
114}
115
116/// Show a simple confirm dialog
117pub fn confirm(
118    ctx: &Context,
119    id: impl std::hash::Hash + std::fmt::Debug,
120    title: impl Into<String>,
121    message: impl Into<String>,
122    open: &mut bool,
123) -> ConfirmResult {
124    ConfirmDialog::new(id, title, message).show(ctx, open)
125}
126
127/// Show a danger confirm dialog
128pub fn confirm_danger(
129    ctx: &Context,
130    id: impl std::hash::Hash + std::fmt::Debug,
131    title: impl Into<String>,
132    message: impl Into<String>,
133    open: &mut bool,
134) -> ConfirmResult {
135    ConfirmDialog::new(id, title, message)
136        .danger()
137        .show(ctx, open)
138}