diff --git a/src/app/mod.rs b/src/app/mod.rs index f64f97c79..0a611403f 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -597,6 +597,10 @@ pub enum ModalKind { Shortcuts, PluginManager, UpdateNotice, + Layers, + PageSetup, + LayoutManager, + Plotstyle, } /// Identifies a DimStyle field that can be edited in the dialog. diff --git a/src/app/update.rs b/src/app/update.rs index 3daafa56f..b37a36370 100644 --- a/src/app/update.rs +++ b/src/app/update.rs @@ -1600,24 +1600,14 @@ impl OpenCADStudio { } Message::ToggleLayers => { - if let Some(id) = self.layer_window.take() { - // Close path: `OsWindowClosed`'s deactivate guard - // sees `layer_window == None` after the take(), so do - // it here so the button flips off in the same frame - // (#40). + if self.active_modal == Some(super::ModalKind::Layers) { self.ribbon.deactivate_tool_if("LAYERS"); - window::close(id) + self.active_modal = None; } else { self.sync_ribbon_layers(); - let (id, task) = window::open(window::Settings { - size: iced::Size::new(900.0, 360.0), - resizable: true, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.layer_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::Layers); } + Task::none() } Message::WindowCloseRequested(id) => { @@ -5299,24 +5289,12 @@ impl OpenCADStudio { } else { current }; - if let Some(id) = self.layout_manager_window { - return window::gain_focus(id); - } - let (id, task) = window::open(window::Settings { - size: iced::Size::new(640.0, 320.0), - resizable: true, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.layout_manager_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::LayoutManager); + Task::none() } Message::LayoutManagerClose => { - if let Some(id) = self.layout_manager_window.take() { - window::close(id) - } else { - Task::none() - } + self.active_modal = None; + Task::none() } Message::LayoutManagerSelect(name) => { self.layout_manager_rename_buf = if name == "Model" { @@ -5739,24 +5717,12 @@ impl OpenCADStudio { }; self.page_setup_w = format!("{w:.1}"); self.page_setup_h = format!("{h:.1}"); - if let Some(id) = self.page_setup_window { - return window::gain_focus(id); - } - let (id, task) = window::open(window::Settings { - size: iced::Size::new(520.0, 460.0), - resizable: false, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.page_setup_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::PageSetup); + Task::none() } Message::PageSetupClose => { - if let Some(id) = self.page_setup_window.take() { - window::close(id) - } else { - Task::none() - } + self.active_modal = None; + Task::none() } Message::UpdateCheckResult(latest) => { let Some(info) = latest else { @@ -6232,24 +6198,12 @@ impl OpenCADStudio { self.ps_screening_buf = entry .map(|e| e.screening.to_string()) .unwrap_or("100".into()); - if let Some(id) = self.plotstyle_window { - return window::gain_focus(id); - } - let (id, task) = window::open(window::Settings { - size: iced::Size::new(780.0, 540.0), - resizable: true, - level: window::Level::AlwaysOnTop, - ..Default::default() - }); - self.plotstyle_window = Some(id); - task.map(|_| Message::Noop) + self.active_modal = Some(super::ModalKind::Plotstyle); + Task::none() } Message::PlotStylePanelClose => { - if let Some(id) = self.plotstyle_window.take() { - window::close(id) - } else { - Task::none() - } + self.active_modal = None; + Task::none() } Message::PlotStylePanelSelectAci(aci) => { self.plotstyle_panel_aci = aci; diff --git a/src/app/view.rs b/src/app/view.rs index 107608e2d..d8ae4420c 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -40,22 +40,6 @@ 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.layer_window { - let tab = &self.tabs[self.active_tab]; - return tab.layers.view_window(); - } - if Some(window_id) == self.page_setup_window { - return crate::ui::page_setup::view_window( - &self.page_setup_w, - &self.page_setup_h, - &self.page_setup_plot_area, - self.page_setup_center, - &self.page_setup_offset_x, - &self.page_setup_offset_y, - &self.page_setup_rotation, - &self.page_setup_scale, - ); - } if Some(window_id) == self.textstyle_window { let tab = &self.tabs[self.active_tab]; let styles: Vec = tab @@ -291,26 +275,6 @@ impl OpenCADStudio { }, ); } - if Some(window_id) == self.layout_manager_window { - let i = self.active_tab; - let layouts = self.tabs[i].scene.layout_names(); - let current = self.tabs[i].scene.current_layout.clone(); - return crate::ui::layout_manager::view_window( - layouts, - &self.layout_manager_selected, - &self.layout_manager_rename_buf, - current, - ); - } - if Some(window_id) == self.plotstyle_window { - return crate::ui::plotstyle::view_window( - self.active_plot_style.as_ref(), - self.plotstyle_panel_aci, - &self.ps_color_buf, - &self.ps_lineweight_buf, - &self.ps_screening_buf, - ); - } if Some(window_id) == self.dimstyle_window { let tab = &self.tabs[self.active_tab]; let styles: Vec = tab @@ -468,20 +432,6 @@ impl OpenCADStudio { if Some(window_id) == self.color_pick_window { return crate::ui::color_select::color_grid_window(Message::ColorWindowPick); } - if Some(window_id) == self.shortcuts_window { - return crate::ui::shortcuts::view_window(&self.shortcut_overrides); - } - if Some(window_id) == self.about_window { - return crate::ui::about::view_window(); - } - if Some(window_id) == self.plugin_manager_window { - return crate::ui::plugin_manager::view_window(&crate::plugin::installed_manifests()); - } - if Some(window_id) == self.update_notice_window { - let latest = self.update_notice_version.as_deref().unwrap_or("?"); - let body = self.update_notice_body.as_deref().unwrap_or(""); - return crate::ui::update_notice::view_window(latest, body); - } if Some(window_id) == self.assoc_prompt_window { return default_assoc_dialog_window(); } @@ -1517,46 +1467,84 @@ impl OpenCADStudio { // ── In-canvas modal dialogs (Plan B) ─────────────────────────────── // Former pop-up windows render as overlays here, so they work on both // the native (single main window) and web builds. - use crate::ui::modal::modal; - match self.active_modal { - Some(super::ModalKind::About) => { - modal(composed, crate::ui::about::view_window(), Message::CloseModal) - } - Some(super::ModalKind::Shortcuts) => modal( - composed, - // Content-heavy dialogs (lists / scroll) keep a bounded size — - // their inner `Fill` widgets fill it — instead of shrinking. - iced::widget::container(crate::ui::shortcuts::view_window( - &self.shortcut_overrides, - )) - .width(720) - .height(520), - Message::CloseModal, - ), - Some(super::ModalKind::PluginManager) => modal( - composed, - iced::widget::container(crate::ui::plugin_manager::view_window( - &crate::plugin::installed_manifests(), - )) - .width(520) - .height(460), - Message::CloseModal, - ), - Some(super::ModalKind::UpdateNotice) => { - let latest = self.update_notice_version.as_deref().unwrap_or("?"); - let body = self.update_notice_body.as_deref().unwrap_or(""); - modal( - composed, - iced::widget::container(crate::ui::update_notice::view_window(latest, body)) - .width(560) - .height(460), - Message::CloseModal, - ) - } + match self.modal_content() { + Some(content) => crate::ui::modal::modal(composed, content, Message::CloseModal), None => composed.into(), } } + /// Build the currently-open modal dialog's content (Plan B), or `None`. + /// Each former pop-up window is constructed here and given a bounded size + /// (About shrinks to its content). Rendered as an overlay by `view_main`. + fn modal_content(&self) -> Option> { + fn sized<'a>(e: Element<'a, Message>, w: u16, h: u16) -> Element<'a, Message> { + iced::widget::container(e) + .width(iced::Length::Fixed(w as f32)) + .height(iced::Length::Fixed(h as f32)) + .into() + } + Some(match self.active_modal? { + super::ModalKind::About => crate::ui::about::view_window(), + super::ModalKind::Shortcuts => { + sized(crate::ui::shortcuts::view_window(&self.shortcut_overrides), 720, 520) + } + super::ModalKind::PluginManager => sized( + crate::ui::plugin_manager::view_window(&crate::plugin::installed_manifests()), + 520, + 460, + ), + super::ModalKind::UpdateNotice => { + let latest = self.update_notice_version.as_deref().unwrap_or("?"); + let body = self.update_notice_body.as_deref().unwrap_or(""); + sized(crate::ui::update_notice::view_window(latest, body), 560, 460) + } + super::ModalKind::Layers => { + let tab = &self.tabs[self.active_tab]; + sized(tab.layers.view_window(), 900, 360) + } + super::ModalKind::PageSetup => sized( + crate::ui::page_setup::view_window( + &self.page_setup_w, + &self.page_setup_h, + &self.page_setup_plot_area, + self.page_setup_center, + &self.page_setup_offset_x, + &self.page_setup_offset_y, + &self.page_setup_rotation, + &self.page_setup_scale, + ), + 520, + 460, + ), + super::ModalKind::LayoutManager => { + let i = self.active_tab; + let layouts = self.tabs[i].scene.layout_names(); + let current = self.tabs[i].scene.current_layout.clone(); + sized( + crate::ui::layout_manager::view_window( + layouts, + &self.layout_manager_selected, + &self.layout_manager_rename_buf, + current, + ), + 640, + 320, + ) + } + super::ModalKind::Plotstyle => sized( + crate::ui::plotstyle::view_window( + self.active_plot_style.as_ref(), + self.plotstyle_panel_aci, + &self.ps_color_buf, + &self.ps_lineweight_buf, + &self.ps_screening_buf, + ), + 780, + 540, + ), + }) + } + pub fn subscription(&self) -> Subscription { use iced::event; // Only request per-frame ticks while something on screen is animating