diff --git a/src/app/mod.rs b/src/app/mod.rs index ff41c4c22..bd6c9435d 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -606,6 +606,9 @@ pub enum ModalKind { MlStyle, MLeaderStyle, DimStyle, + Unsaved, + SaveDialog, + AssocPrompt, } /// Identifies a DimStyle field that can be edited in the dialog. @@ -1687,18 +1690,10 @@ impl OpenCADStudio { // One-time prompt offering to make Open CAD Studio the default app for // .dwg / .dxf. Shown only on the first launch that hasn't answered it // yet; the flag is persisted so we never ask twice. - let assoc_prompt: Task = if s.default_assoc_prompted { - Task::none() - } else { - let (id, open) = window::open(window::Settings { - size: iced::Size::new(440.0, 210.0), - resizable: false, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - s.assoc_prompt_window = Some(id); - open.map(|_| Message::Noop) - }; + let assoc_prompt: Task = Task::none(); + if !s.default_assoc_prompted { + s.active_modal = Some(ModalKind::AssocPrompt); + } ( s, Task::batch([open_main, check_update, focus_cmd, cli_open, assoc_prompt]), diff --git a/src/app/update.rs b/src/app/update.rs index 76a341952..75efe3bd0 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -117,6 +117,9 @@ impl OpenCADStudio { self.ribbon.deactivate_tool_if("KEYBOARD"); } Some(About) => self.ribbon.deactivate_tool_if("ABOUT"), + // Dismissing these via ✕ is the cancel/decline path. + Some(Unsaved) => self.pending_close = None, + Some(AssocPrompt) => self.mark_assoc_prompted(), _ => {} } self.active_modal = None; @@ -5784,24 +5787,16 @@ impl OpenCADStudio { } Message::AssocPromptYes => { self.mark_assoc_prompted(); - let close = if let Some(id) = self.assoc_prompt_window.take() { - window::close(id) - } else { - Task::none() - }; - let run = Task::perform( + self.active_modal = None; + Task::perform( crate::io::file_association::set_default_app(), Message::AssocResult, - ); - Task::batch([close, run]) + ) } Message::AssocPromptNo => { self.mark_assoc_prompted(); - if let Some(id) = self.assoc_prompt_window.take() { - window::close(id) - } else { - Task::none() - } + self.active_modal = None; + Task::none() } Message::AssocResult(result) => { match result { @@ -8534,44 +8529,27 @@ impl OpenCADStudio { self.save_dialog_filename = format!("{}.{ext}", self.tabs[tab_idx].tab_display_name()); } self.save_dialog_entries = crate::io::read_dir_entries(&self.save_dialog_folder.clone()); - let (id, task) = window::open(window::Settings { - size: iced::Size::new(560.0, 480.0), - resizable: true, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.save_dialog_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::SaveDialog); + Task::none() } fn close_save_dialog_window(&mut self) -> Task { - if let Some(id) = self.save_dialog_window.take() { - window::close(id) - } else { - Task::none() + if self.active_modal == Some(super::ModalKind::SaveDialog) { + self.active_modal = None; } + Task::none() } fn open_unsaved_dialog_window(&mut self) -> Task { - if let Some(id) = self.unsaved_dialog_window { - return window::gain_focus(id); - } - let (id, task) = window::open(window::Settings { - size: iced::Size::new(420.0, 155.0), - resizable: false, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.unsaved_dialog_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::Unsaved); + Task::none() } fn close_unsaved_dialog_window(&mut self) -> Task { - if let Some(id) = self.unsaved_dialog_window.take() { - window::close(id) - } else { - Task::none() + if self.active_modal == Some(super::ModalKind::Unsaved) { + self.active_modal = None; } + Task::none() } pub(super) fn load_textstyle_bufs(&mut self, tab: usize) { diff --git a/src/app/view.rs b/src/app/view.rs index a0aa8841b..4cc034986 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -40,35 +40,9 @@ impl std::fmt::Display for RenderModeChoice { impl OpenCADStudio { pub fn view(&self, window_id: window::Id) -> Element<'_, Message> { // ── Floating panel windows ───────────────────────────────────────── - if Some(window_id) == self.assoc_prompt_window { - return default_assoc_dialog_window(); - } - if Some(window_id) == self.unsaved_dialog_window { - let tab_name = match &self.pending_close { - Some(super::PendingClose::Tab(idx)) => self - .tabs - .get(*idx) - .map(|t| t.tab_display_name()) - .unwrap_or_default(), - Some(super::PendingClose::Quit) => self - .tabs - .iter() - .find(|t| t.dirty) - .map(|t| t.tab_display_name()) - .unwrap_or_default(), - None => String::new(), - }; - return unsaved_changes_dialog_window(&tab_name); - } - if Some(window_id) == self.save_dialog_window { - return save_as_dialog_window( - &self.save_dialog_filename, - &self.save_dialog_folder, - &self.save_dialog_entries, - &self.save_dialog_format, - ); - } - + // All dialogs are in-canvas modals now (Plan B); view_main stacks the + // active one. `window_id` is unused — there is only the main window. + let _ = window_id; self.view_main() } @@ -1543,6 +1517,34 @@ impl OpenCADStudio { &self.style_rename_buf, ), 720, 560) } + super::ModalKind::AssocPrompt => sized(default_assoc_dialog_window(), 440, 210), + super::ModalKind::Unsaved => { + let tab_name = match &self.pending_close { + Some(super::PendingClose::Tab(idx)) => self + .tabs + .get(*idx) + .map(|t| t.tab_display_name()) + .unwrap_or_default(), + Some(super::PendingClose::Quit) => self + .tabs + .iter() + .find(|t| t.dirty) + .map(|t| t.tab_display_name()) + .unwrap_or_default(), + None => String::new(), + }; + sized(unsaved_changes_dialog_window(&tab_name), 420, 160) + } + super::ModalKind::SaveDialog => sized( + save_as_dialog_window( + &self.save_dialog_filename, + &self.save_dialog_folder, + &self.save_dialog_entries, + &self.save_dialog_format, + ), + 560, + 480, + ), }) }