From c1f50e1efa78ef7f35ed6f44828976fb7328d85b Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 8 Jun 2025 02:04:09 +0200 Subject: feat: dialog improvements - "Unsaved changes" dialogs ask about saving the project - Trying to close the window also triggers an "unsaved changes" dialog when the editor is dirty. - Nicer API for dialogs (similar to what I do in `foghorn-rs/foghorn`) --- src/dialogs.rs | 118 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 31 deletions(-) (limited to 'src/dialogs.rs') diff --git a/src/dialogs.rs b/src/dialogs.rs index c1933ec..68bbd6e 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -1,47 +1,103 @@ -use iced::Task; +use std::borrow::Cow; + +use iced::widget::text; use iced_dialog::button; use crate::Message; -use crate::types::{DialogAction, DialogButtons, Element}; +use crate::types::Element; -pub const UNSAVED_CHANGES_TITLE: &str = "Unsaved changes"; +pub const UNSAVED_CHANGES_TITLE: &str = "Hold on for a sec!"; pub const WARNING_TITLE: &str = "Heads up!"; pub const ERROR_TITLE: &str = "Oops! Something went wrong."; -pub fn ok_button<'a>() -> Element<'a, Message> { - button("Ok", Message::DialogOk).into() +#[derive(Debug, Clone, Copy, Default)] +pub enum Action { + #[default] + None, + Close, + UnsavedChanges(UnsavedChanges), } -pub fn cancel_button<'a>() -> Element<'a, Message> { - button("Cancel", Message::DialogCancel).into() +#[derive(Debug, Clone, Copy)] +pub enum UnsavedChanges { + New, + Open, + Exit, } -pub fn error_dialog(description: impl Into) -> Task { - Task::done(Message::OpenDialog( - ERROR_TITLE, - description.into(), - DialogButtons::Ok, - DialogAction::None, - )) +impl From for Vec> { + fn from(action: Action) -> Self { + match action { + Action::None => vec![], + Action::Close => vec![button("Close", Message::DialogYes).into()], + Action::UnsavedChanges(_) => vec![ + button("Don't Save", Message::DialogNo).into(), + button("Save", Message::DialogYes).into(), + button("Cancel", Message::DialogCancel).into(), + ], + } + } } -pub fn warning_dialog(description: impl Into) -> Task { - Task::done(Message::OpenDialog( - WARNING_TITLE, - description.into(), - DialogButtons::Ok, - DialogAction::None, - )) +#[derive(Debug, Default)] +pub struct Dialog { + is_open: bool, + title: Cow<'static, str>, + content: Cow<'static, str>, + action: Action, } -pub fn unsaved_changes_dialog( - description: impl Into, - action: DialogAction, -) -> Task { - Task::done(Message::OpenDialog( - UNSAVED_CHANGES_TITLE, - description.into(), - DialogButtons::OkCancel, - action, - )) +impl Dialog { + pub fn new( + title: impl Into>, + content: impl Into>, + action: Action, + ) -> Self { + Self { + is_open: true, + title: title.into(), + content: content.into(), + action, + } + } + + pub fn error(content: impl Into>) -> Self { + Self::new(ERROR_TITLE, content, Action::Close) + } + + pub fn warning(content: impl Into>) -> Self { + Self::new(WARNING_TITLE, content, Action::Close) + } + + pub fn unsaved_changes( + content: impl Into>, + unsaved_changes: UnsavedChanges, + ) -> Self { + Self::new( + UNSAVED_CHANGES_TITLE, + content, + Action::UnsavedChanges(unsaved_changes), + ) + } + + pub fn close(&mut self) { + self.is_open = false; + } + + pub fn action(&self) -> Action { + self.action + } + + pub fn as_iced_dialog<'a>( + &'a self, + base: impl Into>, + ) -> iced_dialog::Dialog<'a, Message, material_theme::Theme> { + iced_dialog::Dialog::with_buttons( + self.is_open, + base, + text(&*self.content), + self.action.into(), + ) + .title(&*self.title) + } } -- cgit v1.2.3