fix(ui): make modal layouts intrinsic

Pin Iced 0.15 so dialogs can measure content before distributing the resolved frame across child panels. Keep the web plugin notice compact and non-resizable.\n\nCloses #582
This commit is contained in:
Hakan Seven committed 2026-07-30 14:47:28 +03:00
1 parent 284d6ef517
commit 3ab8dc3ca5
59 files changed
+2197 -1652

No files matched your search

+1 -1
View File
@@ -61,7 +61,7 @@ impl OpenCADStudio {
Some(text) => {
self.command_line
.push_info("Copied selected text to clipboard.");
Some(iced::clipboard::write(text))
Some(iced::clipboard::write(text).discard())
}
None => Some(Task::none()),
};
+5 -5
View File
@@ -60,7 +60,7 @@ impl Default for UiThemeConfig {
let theme = iced::Theme::Oxocarbon;
Self {
name: theme.to_string(),
palette: UiThemePalette::from_iced(theme.palette()),
palette: UiThemePalette::from_iced(theme.seed()),
}
}
}
@@ -88,12 +88,12 @@ pub struct UiThemePalette {
impl Default for UiThemePalette {
fn default() -> Self {
Self::from_iced(iced::Theme::Oxocarbon.palette())
Self::from_iced(iced::Theme::Oxocarbon.seed())
}
}
impl UiThemePalette {
pub fn from_iced(palette: iced::theme::Palette) -> Self {
pub fn from_iced(palette: iced::theme::palette::Seed) -> Self {
Self {
background: color_to_rgb(palette.background),
text: color_to_rgb(palette.text),
@@ -104,8 +104,8 @@ impl UiThemePalette {
}
}
pub fn to_iced(self) -> iced::theme::Palette {
iced::theme::Palette {
pub fn to_iced(self) -> iced::theme::palette::Seed {
iced::theme::palette::Seed {
background: rgb_to_color(self.background),
text: rgb_to_color(self.text),
primary: rgb_to_color(self.primary),
+3 -1
View File
@@ -1044,7 +1044,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
Message::MTextPasteClip,
);
#[cfg(not(target_arch = "wasm32"))]
return iced::clipboard::read().map(Message::MTextPasteClip);
return iced::clipboard::read_text().map(|result| {
Message::MTextPasteClip(result.ok().map(|text| (*text).clone()))
});
}
if self.text_inline.is_some() {
// Web: the iced text_input can't reach the async clipboard,
+9 -7
View File
@@ -1149,7 +1149,8 @@ impl OpenCADStudio {
});
self.command_line
.push_output(&format!("Copied path: {}", full_path.display()));
return iced::clipboard::write(full_path.to_string_lossy().into_owned());
return iced::clipboard::write(full_path.to_string_lossy().into_owned())
.discard();
}
#[cfg(target_arch = "wasm32")]
{
@@ -1319,7 +1320,7 @@ impl OpenCADStudio {
if text.is_empty() {
Task::none()
} else {
iced::clipboard::write(text)
iced::clipboard::write(text).discard()
}
}
@@ -1334,7 +1335,7 @@ impl OpenCADStudio {
if text.is_empty() {
Task::none()
} else {
iced::clipboard::write(text)
iced::clipboard::write(text).discard()
}
}
@@ -4143,7 +4144,7 @@ impl OpenCADStudio {
Message::SetTheme(theme) => {
self.ui_theme.name = theme.to_string();
self.ui_theme.palette =
crate::app::config::UiThemePalette::from_iced(theme.palette());
crate::app::config::UiThemePalette::from_iced(theme.seed());
self.theme_color_inputs = self.ui_theme.palette.hex_values();
self.active_theme = theme;
self.persist_settings_if_changed();
@@ -4225,7 +4226,7 @@ impl OpenCADStudio {
crate::app::config::builtin_theme(&self.ui_theme.name)
{
self.ui_theme.palette =
crate::app::config::UiThemePalette::from_iced(theme.palette());
crate::app::config::UiThemePalette::from_iced(theme.seed());
self.theme_color_inputs = self.ui_theme.palette.hex_values();
self.active_theme = theme;
} else {
@@ -4441,7 +4442,7 @@ impl OpenCADStudio {
std::env::consts::OS,
std::env::consts::ARCH,
);
iced::clipboard::write(info)
iced::clipboard::write(info).discard()
}
// ── Plugin Manager window ─────────────────────────────────────
@@ -4652,7 +4653,8 @@ impl OpenCADStudio {
std::env::consts::ARCH,
crate::plugin::marketplace::REGISTRY_URL,
error,
));
))
.discard();
}
Task::none()
}
+7 -7
View File
@@ -34,13 +34,13 @@ pub(super) fn viewport_controls<'a>(
| iced::widget::button::Status::Pressed
)
.then_some(Background::Color(
theme.extended_palette().danger.weak.color
theme.palette().danger.weak.color
)),
border: Border {
radius: 3.0.into(),
..Default::default()
},
text_color: theme.extended_palette().danger.base.color,
text_color: theme.palette().danger.base.color,
..Default::default()
})
};
@@ -56,7 +56,7 @@ pub(super) fn viewport_controls<'a>(
.on_press(msg)
.padding([4, 6])
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match (active, status) {
(_, iced::widget::button::Status::Hovered) => {
Some(palette.background.strong)
@@ -79,7 +79,7 @@ pub(super) fn viewport_controls<'a>(
};
// Render-mode picker, restyled borderless so the outer chip frames it.
let picker = iced::widget::pick_list(
let picker = crate::ui::pick_list(
render_modes,
Some(RenderModeChoice(render_mode)),
|c| Message::SetRenderMode(c.0),
@@ -87,7 +87,7 @@ pub(super) fn viewport_controls<'a>(
.text_size(11)
.padding([4, 6])
.style(move |theme: &Theme, _| {
let text = theme.extended_palette().background.base.text;
let text = theme.palette().background.base.text;
iced::widget::pick_list::Style {
background: Background::Color(iced::Color::TRANSPARENT),
border: Border {
@@ -105,7 +105,7 @@ pub(super) fn viewport_controls<'a>(
container(iced::widget::Space::new().width(1.0).height(16.0)).style(|theme: &Theme| {
iced::widget::container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color.scale_alpha(0.7)
theme.palette().background.neutral.color.scale_alpha(0.7)
)),
..Default::default()
}
@@ -156,7 +156,7 @@ pub(super) fn viewport_controls<'a>(
container(bar)
.padding(2)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
iced::widget::container::Style {
background: Some(Background::Color(
palette.background.weak.color.scale_alpha(0.92)
+62 -50
View File
@@ -109,7 +109,7 @@ impl OpenCADStudio {
pub fn view_main(&self) -> Element<'_, Message> {
let i = self.active_tab;
let tab = &self.tabs[i];
let theme_text = self.active_theme.extended_palette().background.base.text;
let theme_text = self.active_theme.palette().background.base.text;
let viewcube_text_color = [
theme_text.r,
theme_text.g,
@@ -197,7 +197,7 @@ impl OpenCADStudio {
sel.vp_size = (size.width, size.height);
}
scene.sync_tiles_from_panes(size.width, size.height);
Space::new().width(Fill).height(Fill).into()
Space::new().width(Fill).height(Fill)
})
.into();
let shaders = pane_grid::PaneGrid::new(
@@ -978,7 +978,7 @@ impl OpenCADStudio {
.padding([3, 10])
.width(Fill)
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match (is_sel, status) {
(true, _) => Some(palette.primary.strong),
(_, iced::widget::button::Status::Hovered) => {
@@ -1004,7 +1004,7 @@ impl OpenCADStudio {
let menu_panel = container(col)
.padding(2)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -1055,7 +1055,7 @@ impl OpenCADStudio {
.padding([3, 10])
.width(Fill)
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
iced::widget::button::Style {
background: matches!(
status,
@@ -1074,10 +1074,10 @@ impl OpenCADStudio {
col = col.push(btn);
}
let panel = container(iced::widget::scrollable(col).height(iced::Length::Shrink))
.max_height(360.0)
.height(iced::Length::Fit.max(360.0))
.padding(2)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -1154,7 +1154,7 @@ impl OpenCADStudio {
trace
};
let perf_button_style = |theme: &Theme, status: button::Status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = if matches!(status, button::Status::Hovered) {
palette.background.strong
} else {
@@ -1195,7 +1195,7 @@ impl OpenCADStudio {
.padding([2, 6]);
let header = row![
text("PERF").size(12).style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.extended_palette().success.base.color),
color: Some(theme.palette().success.base.color),
}),
Space::new().width(iced::Length::Fill),
copy_btn,
@@ -1210,7 +1210,7 @@ impl OpenCADStudio {
column![
header,
text(summary).size(11).style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.extended_palette().success.base.color),
color: Some(theme.palette().success.base.color),
}),
log,
]
@@ -1486,7 +1486,7 @@ impl OpenCADStudio {
})
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
theme.palette().background.base.color
)),
..Default::default()
})
@@ -1536,15 +1536,20 @@ impl OpenCADStudio {
// the native (single main window) and web builds.
let base: Element<'_, Message> = match self.modal_content() {
Some(content) => {
let modal_options = if cfg!(target_arch = "wasm32")
&& matches!(self.active_modal, Some(super::ModalKind::PluginManager))
{
crate::ui::modal::ModalOptions::NOTICE
} else {
crate::ui::modal::ModalOptions::STANDARD
};
crate::ui::modal::modal(
composed,
self.modal_title(),
// Content width — outer size minus the frame padding.
self.modal_outer_size().map(|s| s.0 - 20.0).unwrap_or(420.0),
content,
Message::CloseModal,
self.modal_offset,
true,
modal_options,
)
}
None => composed.into(),
@@ -1555,25 +1560,24 @@ impl OpenCADStudio {
crate::ui::modal::modal(
base,
"Select Color",
420.0,
iced::widget::container(crate::ui::color_select::color_grid_window(
Message::ColorWindowPick,
))
.width(iced::Length::Fixed(420.0))
.height(iced::Length::Fixed(470.0)),
.width(iced::Length::Fit.max(420.0))
.height(iced::Length::Fit.max(470.0)),
Message::CloseColorPicker,
iced::Vector::ZERO,
false,
crate::ui::modal::ModalOptions::MOVABLE_FIXED,
)
} else {
base
}
}
/// Outer pixel size (content + title-bar/padding chrome) of the active
/// modal, used to clamp drag so it cannot be pushed off-screen. Mirrors the
/// `sized(..)` dimensions in [`Self::modal_content`]; keep the two in sync.
/// `None` has no active modal. About (content-sized) uses a safe estimate.
/// Conservative outer pixel bounds for the active modal, used to clamp drag
/// so it cannot be pushed off-screen. Mirrors the maximum dimensions in
/// [`Self::modal_content`]; content-sized dialogs may render smaller.
/// `None` has no active modal. About uses a safe estimate.
pub(crate) fn modal_outer_size(&self) -> Option<(f32, f32)> {
use super::ModalKind::*;
// Title bar (~26) + spacing (6) + frame padding (10·2) → ~52 vertical;
@@ -1583,8 +1587,17 @@ impl OpenCADStudio {
let (w, h) = match self.active_modal? {
About => (440, 360),
Shortcuts => (720, 520),
Options => (480, 190),
PluginManager => (940, 600),
Options => (520, 500),
PluginManager => {
#[cfg(target_arch = "wasm32")]
{
(self.web_plugin_notice_width(), 230)
}
#[cfg(not(target_arch = "wasm32"))]
{
(940, 600)
}
}
UpdateNotice => (560, 460),
Layers => (900, 360),
LayerStateManager => (720, 420),
@@ -2005,7 +2018,7 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
.height(Fill)
.padding([4, 12])
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let background = match (is_active, status) {
(false, button::Status::Hovered) => {
Some(Background::Color(palette.background.weak.color))
@@ -2053,7 +2066,7 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
let tab_container = container(row_inner)
.height(iced::Length::Fixed(23.0))
.style(move |theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(if is_active {
palette.primary.weak.color
@@ -2112,10 +2125,10 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
container(WrapFlow::new(items).spacing_x(0.0).row_h(30.0))
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color,
theme.palette().background.base.color,
)),
border: Border {
color: theme.extended_palette().background.neutral.color,
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 0.0.into(),
},
@@ -2146,13 +2159,13 @@ pub(super) fn doc_tab_bar<'a>(tabs: &'a [DocumentTab], active_tab: usize) -> Ele
//
fn start_muted_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.68)),
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
}
}
fn start_primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().primary.base.color),
color: Some(theme.palette().primary.base.color),
}
}
@@ -2196,7 +2209,7 @@ impl canvas::Program<Message> for VBarLabel {
frame.fill_text(canvas::Text {
content: self.text.clone(),
position: iced::Point::ORIGIN,
color: theme.extended_palette().background.base.text.scale_alpha(0.72),
color: theme.palette().background.base.text.scale_alpha(0.72),
size: iced::Pixels(13.0),
align_x: iced::advanced::text::Alignment::Center,
align_y: iced::alignment::Vertical::Center,
@@ -2223,10 +2236,10 @@ pub(super) fn collapse_bar<'a>(name: &str, on_press: Message) -> Element<'a, Mes
.height(Fill)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color,
theme.palette().background.base.color,
)),
border: Border {
color: theme.extended_palette().background.neutral.color,
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 0.0.into(),
},
@@ -2264,7 +2277,7 @@ pub(super) fn start_page_view<'a>(
.on_press(msg)
.padding([10, 22])
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match status {
button::Status::Hovered => palette.background.strong,
_ => palette.background.weak,
@@ -2354,8 +2367,7 @@ pub(super) fn start_page_view<'a>(
.height(iced::Length::Fixed(120.0))
.content_fit(iced::ContentFit::Contain),
)
.width(Fill)
.max_width(300.0),
.width(Fill.max(300.0)),
)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl("https://open-aec.com/".to_string())),
@@ -2469,7 +2481,7 @@ pub(super) fn start_page_view<'a>(
.height(iced::Length::Fixed(thumb_h))
.style(|theme: &Theme| container::Style {
border: Border {
color: theme.extended_palette().background.neutral.color,
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 6.0.into(),
},
@@ -2499,7 +2511,7 @@ pub(super) fn start_page_view<'a>(
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.extended_palette().danger.base;
let pair = theme.palette().danger.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
@@ -2529,7 +2541,7 @@ pub(super) fn start_page_view<'a>(
.height(Fill)
.padding(VIDEO_PANEL_PADDING)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -2582,7 +2594,7 @@ pub(super) fn start_page_view<'a>(
.padding([8, 10])
.width(Fill)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(
palette.background.base.color.scale_alpha(0.42),
@@ -2615,7 +2627,7 @@ pub(super) fn start_page_view<'a>(
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.extended_palette().primary.base;
let pair = theme.palette().primary.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
@@ -2648,7 +2660,7 @@ pub(super) fn start_page_view<'a>(
.height(Fill)
.padding(16)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -2697,7 +2709,7 @@ pub(super) fn start_page_view<'a>(
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.extended_palette().danger.base;
let pair = theme.palette().danger.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
@@ -2731,7 +2743,7 @@ pub(super) fn start_page_view<'a>(
.height(Fill)
.padding(20)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -2779,7 +2791,7 @@ pub(super) fn start_page_view<'a>(
.on_press(Message::StartSectionSelect(section))
.padding([8, 18])
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match (is_active, status) {
(true, _) => Some(palette.primary.weak),
(false, button::Status::Hovered) => {
@@ -2851,7 +2863,7 @@ pub(super) fn start_page_view<'a>(
container(body)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
theme.palette().background.base.color
)),
..Default::default()
})
@@ -2956,7 +2968,7 @@ pub(super) fn recent_files_panel<'a>(
.padding([6, 12])
.width(Fill)
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
button::Style {
background: matches!(status, button::Status::Hovered).then_some(
Background::Color(palette.background.strong.color)
@@ -2979,7 +2991,7 @@ pub(super) fn recent_files_panel<'a>(
.on_press(Message::RecentRemove(path_for_remove))
.padding([4, 8])
.style(|theme: &Theme, status| {
let palette = theme.extended_palette();
let palette = theme.palette();
button::Style {
background: matches!(status, button::Status::Hovered)
.then_some(Background::Color(palette.danger.weak.color)),
@@ -3004,7 +3016,7 @@ pub(super) fn recent_files_panel<'a>(
// so an over-max entry snaps to the max.
const STEP: usize = 5;
let step_style = |theme: &Theme, status: button::Status| {
let palette = theme.extended_palette();
let palette = theme.palette();
button::Style {
background: matches!(status, button::Status::Hovered).then_some(
Background::Color(palette.background.strong.color)
@@ -3058,7 +3070,7 @@ pub(super) fn recent_files_panel<'a>(
.height(Fill)
.padding(20)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
+351 -229
View File
@@ -1,10 +1,15 @@
use super::super::{Message, OpenCADStudio};
use iced::widget::{button, column, container, pick_list, row, text, Space};
use iced::{Background, Element, Fill, Theme};
use iced::widget::{button, column, container, row, text, Space};
use iced::{Background, Element, Fit, Theme};
impl OpenCADStudio {
/// Title shown in the active modal's title bar, left of the move/close
/// buttons. Keep in sync with the [`Self::modal_content`] dispatch.
#[cfg(target_arch = "wasm32")]
pub(super) fn web_plugin_notice_width(&self) -> u16 {
(self.win_size.0 - 48.0).clamp(280.0, 460.0) as u16
}
/// Title shown in the active modal's title bar. Keep in sync with the
/// [`Self::modal_content`] dispatch.
pub(super) fn modal_title(&self) -> &'static str {
use super::super::ModalKind as K;
match self.active_modal {
@@ -43,96 +48,138 @@ impl OpenCADStudio {
}
/// 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`.
/// Each former pop-up window is constructed here and given a maximum size.
/// Iced 0.15 measures the content first, so smaller dialogs stop at their
/// intrinsic size while overflowing regions become scrollable at the cap.
pub(super) fn modal_content<'s>(&'s self) -> Option<Element<'s, Message>> {
// Grow every dialog by the shared corner-resize delta (grow-only, so the
// natural size is the floor). The delta resets to zero whenever a modal
// opens/closes, so each dialog starts at its own size.
let ex = self.modal_resize;
let sized = |e: Element<'s, Message>, w: u16, h: u16| -> Element<'s, Message> {
iced::widget::container(e)
.width(iced::Length::Fixed(w as f32 + ex.x))
.height(iced::Length::Fixed(h as f32 + ex.y))
container(e)
.width(Fit.max(w as f32 + ex.x))
.height(Fit.max(h as f32 + ex.y))
.into()
};
Some(match self.active_modal? {
super::super::ModalKind::About => crate::ui::window::about::view_window(),
super::super::ModalKind::About => {
sized(crate::ui::window::about::view_window(), 440, 360)
}
super::super::ModalKind::Shortcuts => {
sized(crate::ui::window::shortcuts::view_window(&self.shortcut_overrides), 720, 520)
sized_flow(
ex,
720,
520,
|flow| {
crate::ui::window::shortcuts::view_window(
&self.shortcut_overrides,
flow,
)
},
)
}
super::super::ModalKind::Aliases => {
sized(crate::ui::window::alias_editor::view_window(&self.alias_editor_rows), 480, 520)
sized_flow(
ex,
480,
520,
|flow| {
crate::ui::window::alias_editor::view_window(
&self.alias_editor_rows,
flow,
)
},
)
}
super::super::ModalKind::Options => sized(
crate::ui::window::options::view_window(
&self.default_save_format,
&self.ui_theme,
&self.theme_color_inputs,
),
super::super::ModalKind::Options => sized_flow(
ex,
520,
500,
|flow| {
crate::ui::window::options::view_window(
&self.default_save_format,
&self.ui_theme,
&self.theme_color_inputs,
flow,
)
},
),
super::super::ModalKind::PluginManager => {
#[cfg(not(target_arch = "wasm32"))]
{
sized(
crate::ui::window::plugin_manager::view_window(
&self.disabled_plugins,
&self.external_plugins,
&self.loaded_plugin_ids,
crate::ui::window::plugin_manager::MarketView {
registry: &self.plugin_registry,
registry_loading: self.plugin_registry_loading,
registry_error: self.plugin_registry_error.as_deref(),
registry_error_details_open: self
.plugin_registry_error_details_open,
input: &self.plugin_repo_input,
search: &self.plugin_search_input,
repos: &self.plugin_repos,
release_tags: &self.repo_release_tags,
selected_tag: &self.repo_selected_tag,
selected_repo: self.selected_plugin_repo.as_deref(),
readmes: &self.plugin_readmes,
readme_loading: &self.plugin_readme_loading,
status: &self.marketplace_status,
},
&self.active_theme,
),
sized_flow(
ex,
940,
600,
|flow| {
crate::ui::window::plugin_manager::view_window(
&self.disabled_plugins,
&self.external_plugins,
&self.loaded_plugin_ids,
crate::ui::window::plugin_manager::MarketView {
registry: &self.plugin_registry,
registry_loading: self.plugin_registry_loading,
registry_error: self.plugin_registry_error.as_deref(),
registry_error_details_open: self
.plugin_registry_error_details_open,
input: &self.plugin_repo_input,
search: &self.plugin_search_input,
repos: &self.plugin_repos,
release_tags: &self.repo_release_tags,
selected_tag: &self.repo_selected_tag,
selected_repo: self.selected_plugin_repo.as_deref(),
readmes: &self.plugin_readmes,
readme_loading: &self.plugin_readme_loading,
status: &self.marketplace_status,
},
&self.active_theme,
flow,
)
},
)
}
#[cfg(target_arch = "wasm32")]
{
sized(
crate::ui::window::plugin_manager::view_web_notice(),
520,
260,
self.web_plugin_notice_width(),
230,
)
}
}
super::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::window::update_notice::view_window(latest, body), 560, 460)
sized_flow(
ex,
560,
460,
|flow| crate::ui::window::update_notice::view_window(latest, body, flow),
)
}
super::super::ModalKind::Layers => {
let tab = &self.tabs[self.active_tab];
sized(tab.layers.view_window(self.layer_name_col_w), 900, 360)
sized_flow(
ex,
900,
360,
|flow| tab.layers.view_window(self.layer_name_col_w, flow),
)
}
super::super::ModalKind::LayerStateManager => {
let states = self.tabs[self.active_tab].scene.document.layer_states();
sized(
crate::ui::window::layer_state_manager::view_window(
states,
self.layer_state_selected.as_deref(),
&self.layer_state_name_buf,
&self.layer_state_description_buf,
&self.layer_state_filter,
),
sized_flow(
ex,
720,
420,
|flow| {
crate::ui::window::layer_state_manager::view_window(
states.clone(),
self.layer_state_selected.as_deref(),
&self.layer_state_name_buf,
&self.layer_state_description_buf,
&self.layer_state_filter,
flow,
)
},
)
}
super::super::ModalKind::LayerStateEditor => {
@@ -155,15 +202,19 @@ impl OpenCADStudio {
}
}
linetypes.sort_by_key(|name| name.to_lowercase());
sized(
crate::ui::window::layer_state_manager::view_editor(
state,
&self.layer_state_edit_filter,
self.layer_state_edit_color_open,
linetypes,
),
sized_flow(
ex,
1180,
560,
|flow| {
crate::ui::window::layer_state_manager::view_editor(
state,
&self.layer_state_edit_filter,
self.layer_state_edit_color_open,
linetypes.clone(),
flow,
)
},
)
} else {
sized(
@@ -176,21 +227,30 @@ impl OpenCADStudio {
}
}
super::super::ModalKind::Plot => {
sized(crate::ui::window::plot::view_window(&self.plot_dialog), 760, 540)
sized_flow(
ex,
760,
540,
|flow| crate::ui::window::plot::view_window(&self.plot_dialog, flow),
)
}
super::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::window::layout_manager::view_window(
layouts,
&self.layout_manager_selected,
&self.layout_manager_rename_buf,
current,
),
sized_flow(
ex,
640,
320,
|flow| {
crate::ui::window::layout_manager::view_window(
layouts.clone(),
&self.layout_manager_selected,
&self.layout_manager_rename_buf,
current.clone(),
flow,
)
},
)
}
super::super::ModalKind::ScaleManager => {
@@ -206,21 +266,25 @@ impl OpenCADStudio {
.map(|(p, d)| format!("{p}:{d}"))
.unwrap_or_default();
(name, ratio)
})
})
.collect();
let current = tab.scene.document.header.current_annotation_scale.clone();
sized(
crate::ui::style::scale_manager::view_window(
&scales,
&self.scale_manager_selected,
&current,
self.scale_rename.as_deref(),
&self.scale_rename_buf,
&self.scale_manager_paper_buf,
&self.scale_manager_drawing_buf,
),
sized_flow(
ex,
520,
360,
|flow| {
crate::ui::style::scale_manager::view_window(
&scales,
&self.scale_manager_selected,
&current,
self.scale_rename.as_deref(),
&self.scale_rename_buf,
&self.scale_manager_paper_buf,
&self.scale_manager_drawing_buf,
flow,
)
},
)
}
super::super::ModalKind::AnnoObjectScale => {
@@ -263,22 +327,33 @@ impl OpenCADStudio {
(name, ratio, is_member)
})
.collect();
sized(
crate::ui::style::anno_object_scale::view_window(&label, &scales),
sized_flow(
ex,
360,
420,
|flow| {
crate::ui::style::anno_object_scale::view_window(
&label,
&scales,
flow,
)
},
)
}
super::super::ModalKind::Plotstyle => sized(
crate::ui::style::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,
),
super::super::ModalKind::Plotstyle => sized_flow(
ex,
780,
540,
|flow| {
crate::ui::style::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,
flow,
)
},
),
super::super::ModalKind::TextStyle => {
let tab = &self.tabs[self.active_tab];
@@ -296,27 +371,31 @@ impl OpenCADStudio {
.get(&self.textstyle_selected)
.map(|s| (s.flags.backward, s.flags.upside_down, s.annotative))
.unwrap_or((false, false, false));
sized(
crate::ui::style::textstyle::view_window(crate::ui::style::textstyle::TextStyleView {
styles,
selected: &self.textstyle_selected,
current: &tab.scene.document.header.current_text_style_name,
font_buf: &self.textstyle_font,
width_buf: &self.textstyle_width,
oblique_buf: &self.textstyle_oblique,
height_buf: &self.textstyle_height,
bigfont_buf: &self.textstyle_bigfont,
ttf_buf: &self.textstyle_ttf,
backward,
upside_down,
annotative,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
}),
// Wider than the old 620 window: the TTF system-font panel
// (Plan B / web fonts) added a column.
sized_flow(
ex,
860,
480,
|flow| {
crate::ui::style::textstyle::view_window(
crate::ui::style::textstyle::TextStyleView {
styles: styles.clone(),
selected: &self.textstyle_selected,
current: &tab.scene.document.header.current_text_style_name,
font_buf: &self.textstyle_font,
width_buf: &self.textstyle_width,
oblique_buf: &self.textstyle_oblique,
height_buf: &self.textstyle_height,
bigfont_buf: &self.textstyle_bigfont,
ttf_buf: &self.textstyle_ttf,
backward,
upside_down,
annotative,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
},
flow,
)
},
)
}
super::super::ModalKind::MlStyle => {
@@ -336,17 +415,21 @@ impl OpenCADStudio {
ObjectType::MLineStyle(s) if s.name == self.mlstyle_selected => Some(s),
_ => None,
});
sized(
crate::ui::style::mlstyle::view_window(
styles,
&self.mlstyle_selected,
selected_style,
tab.scene.document.header.multiline_style.clone(),
self.style_rename.as_deref(),
&self.style_rename_buf,
),
sized_flow(
ex,
620,
420,
|flow| {
crate::ui::style::mlstyle::view_window(
styles.clone(),
&self.mlstyle_selected,
selected_style,
tab.scene.document.header.multiline_style.clone(),
self.style_rename.as_deref(),
&self.style_rename_buf,
flow,
)
},
)
}
super::super::ModalKind::TableStyle => {
@@ -366,31 +449,35 @@ impl OpenCADStudio {
ObjectType::TableStyle(s) if s.name == self.tablestyle_selected => Some(s),
_ => None,
});
sized(
crate::ui::style::tablestyle::view_window(
styles,
&self.tablestyle_selected,
&self.ribbon.active_table_style,
selected_style,
&self.ts_hmargin,
&self.ts_vmargin,
&self.ts_description,
&self.ts_cell_textstyle,
&self.ts_cell_height,
&self.ts_cell_textcolor,
&self.ts_cell_fillcolor,
&self.ts_cell_datatype,
&self.ts_cell_unittype,
&self.ts_cell_format,
&self.ts_border_lw,
&self.ts_border_color,
&self.ts_border_spacing,
self.style_rename.as_deref(),
&self.style_rename_buf,
self.ts_color_open,
),
sized_flow(
ex,
620,
420,
|flow| {
crate::ui::style::tablestyle::view_window(
styles.clone(),
&self.tablestyle_selected,
&self.ribbon.active_table_style,
selected_style,
&self.ts_hmargin,
&self.ts_vmargin,
&self.ts_description,
&self.ts_cell_textstyle,
&self.ts_cell_height,
&self.ts_cell_textcolor,
&self.ts_cell_fillcolor,
&self.ts_cell_datatype,
&self.ts_cell_unittype,
&self.ts_cell_format,
&self.ts_border_lw,
&self.ts_border_color,
&self.ts_border_spacing,
self.style_rename.as_deref(),
&self.style_rename_buf,
self.ts_color_open,
flow,
)
},
)
}
super::super::ModalKind::MLeaderStyle => {
@@ -462,44 +549,50 @@ impl OpenCADStudio {
),
None => Default::default(),
};
sized(
crate::ui::style::mleaderstyle::view_window(crate::ui::style::mleaderstyle::MLeaderStyleView {
styles,
selected: &self.mleaderstyle_selected,
style: selected_style,
current: tab.active_mleader_style.clone(),
landing_distance: &self.mls_landing_distance,
landing_gap: &self.mls_landing_gap,
arrowhead_size: &self.mls_arrowhead_size,
text_height: &self.mls_text_height,
scale_factor: &self.mls_scale_factor,
break_gap: &self.mls_break_gap,
first_seg_angle: &self.mls_first_seg_angle,
second_seg_angle: &self.mls_second_seg_angle,
max_points: &self.mls_max_points,
default_text: &self.mls_default_text,
line_color: &self.mls_line_color,
text_color: &self.mls_text_color,
description: &self.mls_description,
align_space: &self.mls_align_space,
block_color: &self.mls_block_color,
block_rotation: &self.mls_block_rotation,
block_scale_x: &self.mls_block_scale_x,
block_scale_y: &self.mls_block_scale_y,
block_scale_z: &self.mls_block_scale_z,
block_opts,
lt_opts,
textstyle_opts,
line_type_name,
arrowhead_name,
text_style_name,
block_content_name,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
color_open: self.mls_color_open,
}),
sized_flow(
ex,
560,
560,
|flow| {
crate::ui::style::mleaderstyle::view_window(
crate::ui::style::mleaderstyle::MLeaderStyleView {
styles: styles.clone(),
selected: &self.mleaderstyle_selected,
style: selected_style,
current: tab.active_mleader_style.clone(),
landing_distance: &self.mls_landing_distance,
landing_gap: &self.mls_landing_gap,
arrowhead_size: &self.mls_arrowhead_size,
text_height: &self.mls_text_height,
scale_factor: &self.mls_scale_factor,
break_gap: &self.mls_break_gap,
first_seg_angle: &self.mls_first_seg_angle,
second_seg_angle: &self.mls_second_seg_angle,
max_points: &self.mls_max_points,
default_text: &self.mls_default_text,
line_color: &self.mls_line_color,
text_color: &self.mls_text_color,
description: &self.mls_description,
align_space: &self.mls_align_space,
block_color: &self.mls_block_color,
block_rotation: &self.mls_block_rotation,
block_scale_x: &self.mls_block_scale_x,
block_scale_y: &self.mls_block_scale_y,
block_scale_z: &self.mls_block_scale_z,
block_opts: block_opts.clone(),
lt_opts: lt_opts.clone(),
textstyle_opts: textstyle_opts.clone(),
line_type_name: line_type_name.clone(),
arrowhead_name: arrowhead_name.clone(),
text_style_name: text_style_name.clone(),
block_content_name: block_content_name.clone(),
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
color_open: self.mls_color_open,
},
flow,
)
},
)
}
super::super::ModalKind::DimStyle => {
@@ -562,8 +655,9 @@ impl OpenCADStudio {
),
None => Default::default(),
};
sized(crate::ui::style::dimstyle::view_window(
styles,
sized_flow(ex, 720, 560, |flow| {
crate::ui::style::dimstyle::view_window(
styles.clone(),
&self.dimstyle_selected,
&self.tabs[self.active_tab]
.scene
@@ -642,20 +736,22 @@ impl OpenCADStudio {
dimalttz: &self.ds_dimalttz,
dimtolj: &self.ds_dimtolj,
dimtzin: &self.ds_dimtzin,
dimblk_name,
dimblk1_name,
dimblk2_name,
dimldrblk_name,
dimltex_name,
dimltex1_name,
dimltex2_name,
block_opts,
lt_opts,
dimblk_name: dimblk_name.clone(),
dimblk1_name: dimblk1_name.clone(),
dimblk2_name: dimblk2_name.clone(),
dimldrblk_name: dimldrblk_name.clone(),
dimltex_name: dimltex_name.clone(),
dimltex1_name: dimltex1_name.clone(),
dimltex2_name: dimltex2_name.clone(),
block_opts: block_opts.clone(),
lt_opts: lt_opts.clone(),
color_open: self.ds_color_open.clone(),
},
self.style_rename.as_deref(),
&self.style_rename_buf,
), 720, 560)
flow,
)
})
}
super::super::ModalKind::AssocPrompt => sized(default_assoc_dialog_window(), 440, 210),
super::super::ModalKind::AecDropWarning => {
@@ -738,14 +834,22 @@ impl OpenCADStudio {
};
sized(unsaved_changes_dialog_window(&tab_name), 420, 160)
}
super::super::ModalKind::PointStyle => sized(
crate::ui::style::point_style::view_window(
self.tabs[self.active_tab].scene.document.header.point_display_mode,
self.point_size_relative,
&self.point_size_buf,
),
super::super::ModalKind::PointStyle => sized_flow(
ex,
360,
470,
|flow| {
crate::ui::style::point_style::view_window(
self.tabs[self.active_tab]
.scene
.document
.header
.point_display_mode,
self.point_size_relative,
&self.point_size_buf,
flow,
)
},
),
super::super::ModalKind::AttributeEditor => {
let doc = &self.tabs[self.active_tab].scene.document;
@@ -763,18 +867,22 @@ impl OpenCADStudio {
.map(|s| s.name.trim().to_string())
.filter(|n| !n.is_empty())
.collect();
sized(
crate::ui::window::attribute_editor::view_window(
&self.attr_editor_block,
&self.attr_editor_rows,
self.attr_editor_selected,
self.attr_editor_tab,
layers,
linetypes,
styles,
),
sized_flow(
ex,
640,
500,
|flow| {
crate::ui::window::attribute_editor::view_window(
&self.attr_editor_block,
&self.attr_editor_rows,
self.attr_editor_selected,
self.attr_editor_tab,
layers.clone(),
linetypes.clone(),
styles.clone(),
flow,
)
},
)
}
super::super::ModalKind::SaveDialog => {
@@ -794,6 +902,20 @@ impl OpenCADStudio {
}
}
fn sized_flow<'a>(
extra: iced::Vector,
max_width: u16,
max_height: u16,
mut build: impl FnMut(crate::ui::modal::ModalSizing) -> Element<'a, Message>,
) -> Element<'a, Message> {
crate::ui::modal::intrinsic(
build(crate::ui::modal::ModalSizing::INTRINSIC),
build(crate::ui::modal::ModalSizing::FILL),
iced::Size::new(max_width as f32, max_height as f32),
extra,
)
}
fn dialog_button(
label: &'static str,
message: Message,
@@ -807,7 +929,7 @@ fn dialog_button(
}
fn dialog_body_style(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.base.color)),
text_color: Some(palette.background.base.text),
@@ -817,7 +939,7 @@ fn dialog_body_style(theme: &Theme) -> container::Style {
fn dialog_muted_text_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.68)),
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
}
}
@@ -846,7 +968,7 @@ fn save_as_dialog_window<'a>(filename: &'a str, format: &'a str) -> Element<'a,
.on_input(Message::SaveDialogFilenameChanged)
.size(13)
.padding([5, 8])
.width(Fill),
.width(Fit),
]
.align_y(iced::Alignment::Center)
.spacing(6)
@@ -860,10 +982,10 @@ fn save_as_dialog_window<'a>(filename: &'a str, format: &'a str) -> Element<'a,
items.push(
row![
label("Format:").width(70),
pick_list(crate::io::SAVE_FORMAT_OPTIONS, sel_fmt, |s: &str| {
crate::ui::pick_list(crate::io::SAVE_FORMAT_OPTIONS, sel_fmt, |s: &str| {
Message::SaveDialogFormatChanged(s.to_string())
})
.width(Fill),
.width(Fit),
]
.align_y(iced::Alignment::Center)
.spacing(6)
@@ -872,7 +994,7 @@ fn save_as_dialog_window<'a>(filename: &'a str, format: &'a str) -> Element<'a,
items.push(Space::new().height(16).into());
items.push(
row![
Space::new().width(Fill),
Space::new().width(Fit),
dialog_button("Save as...", Message::SaveDialogConfirm, button::primary),
Space::new().width(8),
dialog_button("Cancel", Message::SaveDialogCancel, button::secondary),
@@ -885,8 +1007,8 @@ fn save_as_dialog_window<'a>(filename: &'a str, format: &'a str) -> Element<'a,
container(body)
.style(dialog_body_style)
.padding([14, 16])
.width(Fill)
.height(Fill)
.width(Fit)
.height(Fit)
.into()
}
@@ -908,7 +1030,7 @@ fn unsaved_changes_dialog_window(name: &str) -> Element<'static, Message> {
.spacing(0),
)
.style(dialog_body_style)
.center(Fill)
.center(Fit)
.padding([24, 28])
.into()
}
@@ -932,11 +1054,11 @@ fn file_in_use_dialog_window(path: &str, error: &str) -> Element<'static, Messag
Close it there and retry, or save this drawing under a different name."
)
.size(13)
.width(Fill),
.width(Fit),
Space::new().height(12),
text(path_line).size(11).style(dialog_muted_text_style).width(Fill),
text(path_line).size(11).style(dialog_muted_text_style).width(Fit),
Space::new().height(4),
text(details).size(11).style(dialog_muted_text_style).width(Fill),
text(details).size(11).style(dialog_muted_text_style).width(Fit),
Space::new().height(18),
row![
dialog_button(
@@ -962,8 +1084,8 @@ fn file_in_use_dialog_window(path: &str, error: &str) -> Element<'static, Messag
)
.style(dialog_body_style)
.padding([18, 20])
.width(Fill)
.height(Fill)
.width(Fit)
.height(Fit)
.into()
}
@@ -985,9 +1107,9 @@ fn external_change_dialog_window(path: &str) -> Element<'static, Message> {
save your local work elsewhere, or explicitly overwrite it."
)
.size(13)
.width(Fill),
.width(Fit),
Space::new().height(12),
text(path_line).size(11).style(dialog_muted_text_style).width(Fill),
text(path_line).size(11).style(dialog_muted_text_style).width(Fit),
Space::new().height(18),
row![
dialog_button(
@@ -1019,8 +1141,8 @@ fn external_change_dialog_window(path: &str) -> Element<'static, Message> {
)
.style(dialog_body_style)
.padding([18, 20])
.width(Fill)
.height(Fill)
.width(Fit)
.height(Fit)
.into()
}
@@ -1054,7 +1176,7 @@ fn aec_drop_dialog_window(count: usize, target: &str, src_version: &str) -> Elem
.spacing(0),
)
.style(dialog_body_style)
.center(Fill)
.center(Fit)
.padding([24, 28])
.into()
}
@@ -1093,7 +1215,7 @@ fn layer_delete_warning_window(names: &[String], count: usize) -> Element<'stati
.spacing(0),
)
.style(dialog_body_style)
.center(Fill)
.center(Fit)
.padding([24, 28])
.into()
}
@@ -1113,7 +1235,7 @@ fn default_assoc_dialog_window() -> Element<'static, Message> {
.style(dialog_muted_text_style),
iced::widget::Space::new().height(22),
row![
iced::widget::Space::new().width(Fill),
iced::widget::Space::new().width(Fit),
dialog_button("Not now", Message::AssocPromptNo, button::secondary),
iced::widget::Space::new().width(8),
dialog_button(
@@ -1127,7 +1249,7 @@ fn default_assoc_dialog_window() -> Element<'static, Message> {
.spacing(0),
)
.style(dialog_body_style)
.center(Fill)
.center(Fit)
.padding([24, 28])
.into()
}
+43 -40
View File
@@ -1,6 +1,6 @@
use super::super::Message;
use iced::widget::{
button, column, container, mouse_area, pick_list, row, stack, text, text_input,
button, column, container, mouse_area, row, stack, text, text_input,
Space,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
@@ -36,7 +36,7 @@ pub(super) fn text_inline_overlay(
let panel = container(field)
.style(move |theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -211,7 +211,7 @@ impl iced::widget::canvas::Program<Message> for MTextPreview {
);
frame.fill(
&rect,
theme.extended_palette().primary.base.color.scale_alpha(0.45),
theme.palette().primary.base.color.scale_alpha(0.45),
);
}
}
@@ -247,7 +247,7 @@ impl iced::widget::canvas::Program<Message> for MTextPreview {
frame.stroke(
&path,
Stroke::default()
.with_color(theme.extended_palette().warning.base.color)
.with_color(theme.palette().warning.base.color)
.with_width(1.5),
);
} else if collapsed {
@@ -271,7 +271,7 @@ impl iced::widget::canvas::Program<Message> for MTextPreview {
frame.stroke(
&path,
Stroke::default()
.with_color(theme.extended_palette().warning.base.color)
.with_color(theme.palette().warning.base.color)
.with_width(1.5),
);
}
@@ -318,11 +318,14 @@ pub(super) fn mtext_editor_overlay<'a>(
modal_offset: iced::Vector,
modal_resize: iced::Vector,
) -> Element<'a, Message> {
let sizing = crate::ui::modal::ModalSizing::from_resize(modal_resize);
let width = sizing.width;
let height = sizing.height;
use super::super::mtext_editor::{JustifyChoice, MTextFmt, ParaAlign};
use iced::widget::canvas;
let btn_style = |theme: &Theme, status: button::Status| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match status {
button::Status::Hovered | button::Status::Pressed => palette.background.strong,
_ => palette.background.weak,
@@ -366,7 +369,7 @@ pub(super) fn mtext_editor_overlay<'a>(
} else {
styles
};
let style_pl = pick_list(style_opts, Some(ed.style.clone()), Message::MTextStyle)
let style_pl = crate::ui::pick_list(style_opts, Some(ed.style.clone()), Message::MTextStyle)
.text_size(11)
.width(iced::Length::Fixed(96.0));
let font_sel = if ed.font.trim().is_empty() {
@@ -374,7 +377,7 @@ pub(super) fn mtext_editor_overlay<'a>(
} else {
ed.font.clone()
};
let font_pl = pick_list(
let font_pl = crate::ui::pick_list(
MTEXT_FONTS
.iter()
.map(|s| s.to_string())
@@ -432,14 +435,15 @@ pub(super) fn mtext_editor_overlay<'a>(
include_bytes!("../../../assets/icons/mt_lower.svg"),
Message::MTextFmt(MTextFmt::Lowercase)
),
iced::widget::Space::new().width(Fill),
iced::widget::Space::new().width(width),
color_pl,
]
.spacing(4)
.align_y(iced::Alignment::Center);
.align_y(iced::Alignment::Center)
.width(width);
// ── Row 2: oblique / width / char-spacing · align · line spacing · OK ─
let justify = pick_list(
let justify = crate::ui::pick_list(
JustifyChoice::ALL,
Some(JustifyChoice(ed.attachment)),
|c| Message::MTextJustify(c.0),
@@ -487,7 +491,8 @@ pub(super) fn mtext_editor_overlay<'a>(
.style(btn_style),
]
.spacing(4)
.align_y(iced::Alignment::Center);
.align_y(iced::Alignment::Center)
.width(width);
// ── Body: the rendered preview (the editor is preview-only). It fills the
// space left by the toolbars, so the resizable modal's extra height flows
@@ -587,11 +592,11 @@ pub(super) fn mtext_editor_overlay<'a>(
vertical: Scrollbar::default(),
horizontal: Scrollbar::default(),
})
.width(Fill)
.height(Fill),
.width(width)
.height(height),
)
.style(move |theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.base.color)),
border: Border {
@@ -603,8 +608,8 @@ pub(super) fn mtext_editor_overlay<'a>(
}
})
.padding(2)
.width(Fill)
.height(Fill)
.width(width)
.height(height)
.into()
};
@@ -613,32 +618,31 @@ pub(super) fn mtext_editor_overlay<'a>(
// buffer, so there is no separate Cancel.
let action_bar = container(
row![
iced::widget::Space::new().width(Fill),
iced::widget::Space::new().width(width),
crate::ui::style::style_manager::tb_button("Apply", Message::MTextApply, true),
]
.align_y(iced::Alignment::Center),
)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color
theme.palette().background.weak.color
)),
..Default::default()
})
.width(Fill)
.width(width)
.padding([5, 8]);
// The shared modal frame supplies the panel background, drag title bar,
// ✕ (which also cancels) and the resize grip. The content is a Fill column
// wrapped here in a fixed box (natural 660×480, grown by the shared resize
// delta) so the modal frame shrinks to it and the corner grip can drag it.
// ✕ (which also cancels) and the resize grip. Iced 0.15 measures this
// content first and clamps it to the user-growable maximum.
let content = container(
column![action_bar, row1, row2, body]
.spacing(6)
.width(Fill)
.height(Fill),
.width(width)
.height(height),
)
.width(iced::Length::Fixed(660.0 + modal_resize.x))
.height(iced::Length::Fixed(480.0 + modal_resize.y));
.width(iced::Length::Fit.max(660.0 + modal_resize.x))
.height(iced::Length::Fit.max(480.0 + modal_resize.y));
let _ = canvas_size; // positioned & sized by the modal frame now
// `modal` sizes its stack from the base layer, so the base must fill the
@@ -647,11 +651,10 @@ pub(super) fn mtext_editor_overlay<'a>(
crate::ui::modal::modal(
iced::widget::Space::new().width(Fill).height(Fill),
"Text Editor",
660.0 + modal_resize.x,
content,
Message::MTextCancel,
modal_offset,
true,
crate::ui::modal::ModalOptions::STANDARD,
)
}
@@ -678,7 +681,7 @@ pub(super) fn viewport_context_menu_overlay(
container(iced::widget::Space::new().width(Fill).height(1))
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color,
theme.palette().background.weak.color,
)),
..Default::default()
})
@@ -838,10 +841,10 @@ pub(super) fn snap_override_overlay(pos: iced::Point) -> Element<'static, Messag
button::Status::Hovered | button::Status::Pressed
)
.then_some(Background::Color(
theme.extended_palette().primary.weak.color
theme.palette().primary.weak.color
)),
border: Border::default(),
text_color: theme.extended_palette().background.base.text,
text_color: theme.palette().background.base.text,
..Default::default()
})
.padding(2);
@@ -849,7 +852,7 @@ pub(super) fn snap_override_overlay(pos: iced::Point) -> Element<'static, Messag
btn,
container(text(label).size(11))
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.strong.color)),
border: Border {
@@ -878,7 +881,7 @@ pub(super) fn snap_override_overlay(pos: iced::Point) -> Element<'static, Messag
let panel = container(grid)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
@@ -919,7 +922,7 @@ pub(super) fn qselect_overlay<'a>(
types: &[String],
properties: &[(String, String)],
) -> Element<'a, Message> {
use iced::widget::{checkbox, pick_list};
use iced::widget::{checkbox};
let mut type_options: Vec<String> = vec![QSELECT_ANY_TYPE.to_string()];
type_options.extend(types.iter().cloned());
@@ -971,7 +974,7 @@ pub(super) fn qselect_overlay<'a>(
button(text(lbl).size(12))
.on_press(msg)
.style(move |theme: &Theme, st| {
let palette = theme.extended_palette();
let palette = theme.palette();
let pair = match (
primary,
matches!(st, button::Status::Hovered | button::Status::Pressed),
@@ -1005,7 +1008,7 @@ pub(super) fn qselect_overlay<'a>(
Space::new().height(10),
row![
label("Object type:"),
pick_list(type_options, Some(type_sel), |s: String| {
crate::ui::pick_list(type_options, Some(type_sel), |s: String| {
if s == QSELECT_ANY_TYPE {
Message::QSelectSetType(None)
} else {
@@ -1019,7 +1022,7 @@ pub(super) fn qselect_overlay<'a>(
Space::new().height(6),
row![
label("Property:"),
pick_list(
crate::ui::pick_list(
prop_options,
Some(prop_sel),
|p: crate::app::QSelectPropertyChoice| {
@@ -1037,7 +1040,7 @@ pub(super) fn qselect_overlay<'a>(
Space::new().height(6),
row![
label("Operator:"),
pick_list(
crate::ui::pick_list(
op_options,
Some(state.operator),
Message::QSelectSetOperator
@@ -1074,7 +1077,7 @@ pub(super) fn qselect_overlay<'a>(
.padding(16)
.width(iced::Length::Fixed(400.0))
.style(|theme: &Theme| {
let palette = theme.extended_palette();
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
+5 -5
View File
@@ -1,7 +1,7 @@
use super::super::Message;
use crate::scene::{VIEWCUBE_PX, VIEWCUBE_REGION_PX};
use iced::widget::{
button, container, mouse_area, pick_list, stack, Space,
button, container, mouse_area, stack, Space,
};
use iced::{Background, Border, Element, Theme};
@@ -36,13 +36,13 @@ fn vc_btn<'a>(content: Element<'a, Message>, size: f32, msg: Message) -> Element
iced::widget::button::Status::Hovered | iced::widget::button::Status::Pressed
)
.then_some(Background::Color(
theme.extended_palette().primary.weak.color
theme.palette().primary.weak.color
)),
border: Border {
radius: 3.0.into(),
..Default::default()
},
text_color: theme.extended_palette().background.base.text,
text_color: theme.palette().background.base.text,
..Default::default()
})
.into()
@@ -155,14 +155,14 @@ pub(super) fn viewcube_ucs_picker<'a>(current: String, names: Vec<String>) -> El
} else {
current
};
pick_list(options, Some(selected), Message::SetViewcubeUcs)
crate::ui::pick_list(options, Some(selected), Message::SetViewcubeUcs)
.text_size(11)
.padding([2, 6])
// Fixed width so the caller can centre it under the cube centre with a
// simple half-width offset (content-sized width would drift off-centre).
.width(iced::Length::Fixed(UCS_PICKER_W))
.style(move |theme: &Theme, _| {
let palette = theme.extended_palette();
let palette = theme.palette();
iced::widget::pick_list::Style {
background: Background::Color(palette.background.weak.color),
border: Border {