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:
parent
284d6ef517
commit
3ab8dc3ca5
59 changed files with 2194 additions and 1649 deletions
854
Cargo.lock
generated
854
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
15
Cargo.toml
15
Cargo.toml
|
|
@ -48,8 +48,11 @@ semver = "1"
|
|||
# Forcing the `static` feature builds liblzma from the bundled source, making
|
||||
# the binary self-contained on every platform.
|
||||
lzma-sys = { version = "0.1", features = ["static"], optional = true }
|
||||
iced = { version = "0.14", features = ["image", "svg", "advanced", "canvas", "smol", "markdown"] }
|
||||
iced_aw = { version = "0.14.1", features = ["menu"] }
|
||||
iced = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39", features = ["image", "svg", "advanced", "canvas", "smol", "markdown"] }
|
||||
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
# iced_aw 0.15 compatibility is pending upstream in PR #432. Pin the exact
|
||||
# reviewed pair of commits so Iced and its additional widgets cannot drift.
|
||||
iced_aw = { git = "https://github.com/tsuza/iced_aw.git", rev = "a9301708a4d008dc17f63cbbbb2b2aa06e0e7352", features = ["menu", "context_menu"] }
|
||||
bytemuck = { version = "1.25", features = ["derive"] }
|
||||
glam = { version = "0.33", features = ["bytemuck"] }
|
||||
truck-modeling = "0.6"
|
||||
|
|
@ -101,6 +104,10 @@ windows-sys = { version = "0.61", features = ["Win32_UI_Shell", "Win32_UI_Window
|
|||
[patch.crates-io]
|
||||
# Track standard DWG object relationships used by the scene integration.
|
||||
acadrust = { git = "https://github.com/OpenAEC-Foundation/acadifc.git", rev = "a7b1e07" }
|
||||
# iced_aw's 0.15 branch declares the split Iced crates by version. Resolve
|
||||
# those declarations to the same Iced commit as the application dependency.
|
||||
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
iced_widget = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
# Native enables the plugin host runtime (out-of-process plugins).
|
||||
|
|
@ -132,7 +139,7 @@ js-sys = "0.3"
|
|||
bincode = "1.3"
|
||||
# window.open (external URLs) + Blob/anchor file downloads (Save) + fetch()
|
||||
# (Response) for the lazy per-script web font loader (#141).
|
||||
web-sys = { version = "0.3", features = [
|
||||
web-sys = { version = "=0.3.85", features = [
|
||||
"Window",
|
||||
"Storage",
|
||||
"StorageManager",
|
||||
|
|
@ -176,7 +183,7 @@ web-sys = { version = "0.3", features = [
|
|||
# `webgl` enables it. `fira-sans` embeds the default UI font — the web has no
|
||||
# system fonts, so without it all iced text (ribbon labels, command line) is
|
||||
# blank. Features merge with the main `iced` dependency.
|
||||
iced = { version = "0.14", features = ["webgl", "fira-sans"] }
|
||||
iced = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39", features = ["webgl", "fira-sans"] }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
¤t,
|
||||
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,
|
||||
¤t,
|
||||
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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl DeviceCapabilities {
|
|||
fn from_limits(limits: &wgpu::Limits) -> Self {
|
||||
Self {
|
||||
max_storage_buffers_per_shader_stage: limits.max_storage_buffers_per_shader_stage,
|
||||
max_inter_stage_shader_components: limits.max_inter_stage_shader_components,
|
||||
max_inter_stage_shader_components: limits.max_inter_stage_shader_variables,
|
||||
max_vertex_attributes: limits.max_vertex_attributes,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ impl HatchGpu {
|
|||
};
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("hatch.pipeline_layout"),
|
||||
bind_group_layouts: &[frame_bind_group_layout, &bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[frame_bind_group_layout, &bind_group_layout].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some(if uses_storage {
|
||||
|
|
@ -108,8 +108,8 @@ impl HatchGpu {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -132,7 +132,7 @@ impl HatchGpu {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let backend = match backend_kind {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ impl ImageGpu {
|
|||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ pub fn create_material_bind_group(
|
|||
address_mode_w: address,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::MipmapFilterMode::Linear,
|
||||
..Default::default()
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -380,14 +380,14 @@ impl Pipeline {
|
|||
let wire_const_bgl = wire_mode
|
||||
.uses_storage()
|
||||
.then(|| wire_gpu::WireConst::bind_group_layout(device));
|
||||
let mut wire_bgls: Vec<&wgpu::BindGroupLayout> = vec![&frame_bgl];
|
||||
let mut wire_bgls: Vec<Option<&wgpu::BindGroupLayout>> = vec![Some(&frame_bgl)];
|
||||
if let Some(bgl) = &wire_const_bgl {
|
||||
wire_bgls.push(bgl);
|
||||
wire_bgls.push(Some(bgl));
|
||||
}
|
||||
let wire_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("wire.pipeline_layout"),
|
||||
bind_group_layouts: &wire_bgls,
|
||||
push_constant_ranges: &[],
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let depth_tex = create_depth_texture(device, Size::new(1, 1));
|
||||
|
|
@ -438,8 +438,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -458,7 +458,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -476,7 +476,7 @@ impl Pipeline {
|
|||
let clip_mask_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("clip_mask.pipeline_layout"),
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[],
|
||||
immediate_size: 0,
|
||||
});
|
||||
let clip_mask_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("clip_mask.pipeline"),
|
||||
|
|
@ -502,8 +502,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::Always,
|
||||
depth_write_enabled: Some(false),
|
||||
depth_compare: Some(wgpu::CompareFunction::Always),
|
||||
stencil: wgpu::StencilState {
|
||||
front: wgpu::StencilFaceState {
|
||||
compare: wgpu::CompareFunction::Always,
|
||||
|
|
@ -537,7 +537,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -559,8 +559,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -579,7 +579,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -602,8 +602,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::Always,
|
||||
depth_write_enabled: Some(false),
|
||||
depth_compare: Some(wgpu::CompareFunction::Always),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -622,7 +622,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -654,8 +654,8 @@ impl Pipeline {
|
|||
|
||||
let wipeout_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("wipeout.pipeline_layout"),
|
||||
bind_group_layouts: &[&frame_bgl, &wipeout_bgl1],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&frame_bgl, &wipeout_bgl1].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let wipeout_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
|
|
@ -681,8 +681,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
// Bias TOWARD the camera: a wipeout must win against geometry at
|
||||
// its own depth (a block's wipeout + shapes are coincident at
|
||||
|
|
@ -710,7 +710,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -850,8 +850,8 @@ impl Pipeline {
|
|||
let layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("mesh.cull.layout"),
|
||||
bind_group_layouts: &[&bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
let pipeline =
|
||||
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||
|
|
@ -1027,8 +1027,8 @@ impl Pipeline {
|
|||
|
||||
let mesh_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("mesh.pipeline_layout"),
|
||||
bind_group_layouts: &[&frame_bgl, &mesh_material_bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&frame_bgl, &mesh_material_bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let mesh_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
|
|
@ -1047,8 +1047,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -1071,7 +1071,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1096,8 +1096,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(false),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -1120,7 +1120,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1144,8 +1144,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: wgpu::CompareFunction::Always,
|
||||
depth_write_enabled: Some(false),
|
||||
depth_compare: Some(wgpu::CompareFunction::Always),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -1164,7 +1164,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
};
|
||||
|
|
@ -1199,8 +1199,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -1219,7 +1219,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
};
|
||||
|
|
@ -1246,8 +1246,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -1270,7 +1270,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1284,8 +1284,8 @@ impl Pipeline {
|
|||
|
||||
let face3d_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("face3d.pipeline_layout"),
|
||||
bind_group_layouts: &[&frame_bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&frame_bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let face3d_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
|
|
@ -1304,8 +1304,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -1328,7 +1328,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1351,8 +1351,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState {
|
||||
constant: 1,
|
||||
|
|
@ -1375,7 +1375,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1418,8 +1418,8 @@ impl Pipeline {
|
|||
|
||||
let image_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("image.pipeline_layout"),
|
||||
bind_group_layouts: &[&frame_bgl, &image_bgl1],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&frame_bgl, &image_bgl1].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let image_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
|
|
@ -1445,8 +1445,8 @@ impl Pipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::LessEqual),
|
||||
stencil: content_stencil.clone(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -1465,7 +1465,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -1533,8 +1533,8 @@ impl Pipeline {
|
|||
|
||||
let blit_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("blit.pipeline_layout"),
|
||||
bind_group_layouts: &[&blit_bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&blit_bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
let blit_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
|
|
@ -1572,7 +1572,7 @@ impl Pipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
|
@ -2874,6 +2874,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
// MSAA texture is clip-bounds-sized, so viewport starts at (0, 0).
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
|
|
@ -2918,6 +2919,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_pipeline(&self.image_pipeline);
|
||||
|
|
@ -2968,6 +2970,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
|
|
@ -3373,6 +3376,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
|
|
@ -3423,6 +3427,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_pipeline(&self.wire_pipeline);
|
||||
|
|
@ -3465,6 +3470,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_pipeline(&self.wire_pipeline);
|
||||
|
|
@ -3559,6 +3565,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_pipeline(&self.text_pipeline);
|
||||
|
|
@ -3604,6 +3611,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_pipeline(&self.wipeout_pipeline);
|
||||
|
|
@ -3646,6 +3654,7 @@ impl Pipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(0.0, 0.0, vp.width as f32, vp.height as f32, 0.0, 1.0);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
|
|
@ -3697,6 +3706,7 @@ impl Pipeline {
|
|||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
// No draw calls — the pass itself triggers the MSAA resolve.
|
||||
}
|
||||
|
|
@ -3722,6 +3732,7 @@ impl Pipeline {
|
|||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(
|
||||
surface_dest.x as f32,
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ impl TextAtlasGpu {
|
|||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
|
||||
..Default::default()
|
||||
});
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
|
|
@ -267,8 +267,8 @@ pub fn create_pipelines(
|
|||
});
|
||||
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("text.pipeline.layout"),
|
||||
bind_group_layouts: &[frame_bgl, atlas_bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[frame_bgl, atlas_bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
let create = |label, depth_write_enabled, depth_compare| {
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
|
|
@ -306,16 +306,20 @@ pub fn create_pipelines(
|
|||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
};
|
||||
(
|
||||
create("text.pipeline", true, wgpu::CompareFunction::LessEqual),
|
||||
create(
|
||||
"text.pipeline",
|
||||
Some(true),
|
||||
Some(wgpu::CompareFunction::LessEqual),
|
||||
),
|
||||
create(
|
||||
"text.highlight.pipeline",
|
||||
false,
|
||||
wgpu::CompareFunction::Always,
|
||||
Some(false),
|
||||
Some(wgpu::CompareFunction::Always),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -510,8 +510,8 @@ impl ViewCubeText {
|
|||
});
|
||||
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("vc.text_layout"),
|
||||
bind_group_layouts: &[&bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("vc.text_shader"),
|
||||
|
|
@ -545,7 +545,7 @@ impl ViewCubeText {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let vertex_capacity = MAX_VERTS as u32;
|
||||
|
|
@ -782,6 +782,7 @@ impl ViewCubeText {
|
|||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(
|
||||
clip.x as f32,
|
||||
|
|
@ -1172,8 +1173,8 @@ impl ViewCubePipeline {
|
|||
});
|
||||
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("vc.layout"),
|
||||
bind_group_layouts: &[&bgl],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[&bgl].map(Some),
|
||||
immediate_size: 0,
|
||||
});
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("vc.shader"),
|
||||
|
|
@ -1199,8 +1200,8 @@ impl ViewCubePipeline {
|
|||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
depth_write_enabled: Some(true),
|
||||
depth_compare: Some(wgpu::CompareFunction::Less),
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
|
|
@ -1215,7 +1216,7 @@ impl ViewCubePipeline {
|
|||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let text = ViewCubeText::new(device, queue, format);
|
||||
|
|
@ -1303,6 +1304,7 @@ impl ViewCubePipeline {
|
|||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_viewport(
|
||||
clip.x as f32,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,9 @@ fn instance_buffer_mapped<T: bytemuck::Pod>(
|
|||
});
|
||||
{
|
||||
let mut view = buf.slice(..).get_mapped_range_mut();
|
||||
view[..bytes.len()].copy_from_slice(bytes);
|
||||
if !bytes.is_empty() {
|
||||
view.slice(..bytes.len()).copy_from_slice(bytes);
|
||||
}
|
||||
}
|
||||
buf.unmap();
|
||||
buf
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::ui::properties::acad_color_display;
|
|||
use acadrust::types::Color as AcadColor;
|
||||
use iced::advanced::layout::{self, Layout};
|
||||
use iced::advanced::widget::{self, Widget};
|
||||
use iced::advanced::{mouse, overlay, renderer, Clipboard, Shell};
|
||||
use iced::advanced::{mouse, overlay, renderer, Shell};
|
||||
use iced::widget::{button, column, container, row, scrollable, text};
|
||||
use iced::{Background, Border, Color, Element, Event, Length, Point, Rectangle, Renderer, Size, Theme, Vector};
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ fn swatch<'a>(bg: Color) -> Element<'a, Message> {
|
|||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(bg)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 2.0.into(),
|
||||
},
|
||||
|
|
@ -118,7 +118,7 @@ pub fn color_selector<'a>(
|
|||
|
||||
let popup = container(color_list(extras, on_select, on_more))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -141,7 +141,7 @@ pub fn color_selector<'a>(
|
|||
}
|
||||
|
||||
fn list_row_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let hovered = matches!(status, button::Status::Hovered);
|
||||
let text_color = if hovered {
|
||||
palette.background.strong.text
|
||||
|
|
@ -230,9 +230,9 @@ pub fn color_grid_window(on_pick: impl Fn(AcadColor) -> Message) -> Element<'sta
|
|||
background: Some(Background::Color(bg)),
|
||||
border: Border {
|
||||
color: if matches!(status, button::Status::Hovered) {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
} else {
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
},
|
||||
width: if matches!(status, button::Status::Hovered) {
|
||||
1.5
|
||||
|
|
@ -241,7 +241,7 @@ pub fn color_grid_window(on_pick: impl Fn(AcadColor) -> Message) -> Element<'sta
|
|||
},
|
||||
radius: 1.0.into(),
|
||||
},
|
||||
text_color: theme.extended_palette().background.base.text,
|
||||
text_color: theme.palette().background.base.text,
|
||||
..Default::default()
|
||||
})
|
||||
.padding(0),
|
||||
|
|
@ -255,19 +255,19 @@ pub fn color_grid_window(on_pick: impl Fn(AcadColor) -> Message) -> Element<'sta
|
|||
column![
|
||||
text("Select Color").size(13),
|
||||
row![chip(AcadColor::ByLayer, "ByLayer"), chip(AcadColor::ByBlock, "ByBlock")].spacing(6),
|
||||
scrollable(grid).height(Length::Fill),
|
||||
scrollable(grid).height(Length::Fit),
|
||||
]
|
||||
.spacing(8),
|
||||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color
|
||||
theme.palette().background.weak.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.padding(10)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fit)
|
||||
.height(Length::Fit)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -289,22 +289,14 @@ struct Floating<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for Floating<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
vec![widget::Tree::new(&self.base), widget::Tree::new(&self.popup)]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&[self.base.as_widget(), self.popup.as_widget()]);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&mut [&mut self.base, &mut self.popup]);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
self.base.as_widget().size()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Size<Length> {
|
||||
self.base.as_widget().size_hint()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
|
|
@ -323,7 +315,6 @@ impl<'a> Widget<Message, Theme, Renderer> for Floating<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -333,7 +324,6 @@ impl<'a> Widget<Message, Theme, Renderer> for Floating<'a> {
|
|||
layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -469,13 +459,12 @@ impl overlay::Overlay<Message, Theme, Renderer> for FloatingOverlay<'_, '_> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
) {
|
||||
let child = layout.children().next().unwrap();
|
||||
let vp = child.bounds();
|
||||
self.popup.as_widget_mut().update(
|
||||
self.tree, event, child, cursor, renderer, clipboard, shell, &vp,
|
||||
self.tree, event, child, cursor, renderer, shell, &vp,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ impl CommandLine {
|
|||
.on_press(Message::CommandOptionPick(opt.keyword.clone()))
|
||||
.padding([1, 6])
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if matches!(
|
||||
status,
|
||||
button::Status::Hovered | button::Status::Pressed
|
||||
|
|
@ -431,7 +431,7 @@ impl CommandLine {
|
|||
});
|
||||
let prompt = container(
|
||||
text("Command:").size(11).style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().success.base.color),
|
||||
color: Some(theme.palette().success.base.color),
|
||||
}),
|
||||
)
|
||||
.padding([5, 8]);
|
||||
|
|
@ -445,7 +445,7 @@ impl CommandLine {
|
|||
.on_press(Message::CommandLiteralToggle)
|
||||
.padding([2, 6])
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if literal_active {
|
||||
palette.primary.weak
|
||||
} else if matches!(
|
||||
|
|
@ -508,7 +508,7 @@ impl CommandLine {
|
|||
.width(Length::Fill)
|
||||
.padding([2, 8])
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if is_selected {
|
||||
palette.primary.weak
|
||||
} else if matches!(
|
||||
|
|
@ -567,9 +567,9 @@ impl CommandLine {
|
|||
.on_action(Message::CommandHistoryEdit)
|
||||
.size(11)
|
||||
.padding([2, 8])
|
||||
.max_height(180.0)
|
||||
.height(Length::Fit.max(180.0))
|
||||
.style(|theme: &Theme, _status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
text_editor::Style {
|
||||
background: Background::Color(palette.background.base.color),
|
||||
border: Border::default(),
|
||||
|
|
@ -625,7 +625,7 @@ impl CommandLine {
|
|||
container(history_rows)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -646,7 +646,7 @@ impl CommandLine {
|
|||
history_divider,
|
||||
container(input_row)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weakest.color)),
|
||||
..Default::default()
|
||||
|
|
@ -658,7 +658,7 @@ impl CommandLine {
|
|||
.center_y(Length::Fixed(30.0)),
|
||||
])
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -669,8 +669,7 @@ impl CommandLine {
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Length::Fill)
|
||||
.max_width(720.0)
|
||||
.width(Length::Fill.max(720.0))
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
@ -733,7 +732,7 @@ pub fn ranked_matches(
|
|||
/// Flat button style for the history dropdown's Copy / Clear strip: a subtle
|
||||
/// filled pill that brightens on hover.
|
||||
fn header_btn_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if matches!(status, button::Status::Hovered | button::Status::Pressed) {
|
||||
palette.background.weak
|
||||
} else {
|
||||
|
|
@ -752,7 +751,7 @@ fn header_btn_style(theme: &Theme, status: button::Status) -> button::Style {
|
|||
}
|
||||
|
||||
fn history_color(theme: &Theme, kind: &EntryKind) -> Color {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
match kind {
|
||||
EntryKind::Command => palette.background.base.text,
|
||||
EntryKind::Output => palette.background.base.text.scale_alpha(0.72),
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ pub const SAVE: &[u8] = include_bytes!("../../assets/icons/ui/save.svg");
|
|||
pub const FILE_EXPORT: &[u8] = include_bytes!("../../assets/icons/ui/file_export.svg");
|
||||
pub const PRINT: &[u8] = include_bytes!("../../assets/icons/ui/print.svg");
|
||||
pub const HEART: &[u8] = include_bytes!("../../assets/icons/ui/heart.svg");
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub const GEAR: &[u8] = include_bytes!("../../assets/icons/ui/gear.svg");
|
||||
pub const DOT: &[u8] = include_bytes!("../../assets/icons/ui/dot.svg");
|
||||
pub const DIRTY_DOT: &[u8] = include_bytes!("../../assets/icons/ui/dirty_dot.svg");
|
||||
pub const ARROW_LONG_RIGHT: &[u8] = include_bytes!("../../assets/icons/ui/arrow_long_right.svg");
|
||||
|
|
@ -130,7 +132,7 @@ struct SemanticColors {
|
|||
|
||||
impl SemanticColors {
|
||||
fn from_theme(theme: &Theme) -> Self {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
Self {
|
||||
background: color_hex(palette.background.strong.color),
|
||||
text: color_hex(palette.background.base.text),
|
||||
|
|
@ -257,12 +259,12 @@ fn semantic_handle(bytes: &'static [u8], theme: &Theme) -> svg::Handle {
|
|||
fn palette_key(theme: &Theme) -> [[u8; 4]; 6] {
|
||||
let palette = theme.palette();
|
||||
[
|
||||
palette.background.into_rgba8(),
|
||||
palette.text.into_rgba8(),
|
||||
palette.primary.into_rgba8(),
|
||||
palette.success.into_rgba8(),
|
||||
palette.warning.into_rgba8(),
|
||||
palette.danger.into_rgba8(),
|
||||
palette.background.base.color.into_rgba8(),
|
||||
palette.background.base.text.into_rgba8(),
|
||||
palette.primary.base.color.into_rgba8(),
|
||||
palette.success.base.color.into_rgba8(),
|
||||
palette.warning.base.color.into_rgba8(),
|
||||
palette.danger.base.color.into_rgba8(),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -395,7 +397,7 @@ pub fn themed<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a, M> {
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().background.base.text),
|
||||
color: Some(theme.palette().background.base.text),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
@ -408,7 +410,7 @@ pub fn themed_secondary<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'
|
|||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -426,7 +428,7 @@ pub fn themed_disabled<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a
|
|||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -442,7 +444,7 @@ pub fn themed_primary<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a,
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().primary.base.color),
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
@ -453,7 +455,7 @@ pub fn themed_success<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a,
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().success.base.color),
|
||||
color: Some(theme.palette().success.base.color),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
@ -464,7 +466,7 @@ pub fn themed_warning<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a,
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().warning.base.color),
|
||||
color: Some(theme.palette().warning.base.color),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
@ -475,7 +477,7 @@ pub fn themed_danger<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element<'a,
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().danger.base.color),
|
||||
color: Some(theme.palette().danger.base.color),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
@ -486,7 +488,7 @@ pub fn themed_danger_text<'a, M: 'a>(bytes: &'static [u8], size: f32) -> Element
|
|||
.width(size)
|
||||
.height(size)
|
||||
.style(|theme: &Theme, _| svg::Style {
|
||||
color: Some(theme.extended_palette().danger.base.text),
|
||||
color: Some(theme.palette().danger.base.text),
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,23 @@
|
|||
/// Change this to scale the ribbon, layer manager rows, and property panel rows uniformly.
|
||||
pub const ROW_H: f32 = 26.0;
|
||||
|
||||
/// Iced 0.15 separates pick-list construction from the selection callback.
|
||||
/// Keep the application's established call shape while the rest of the UI
|
||||
/// migrates independently.
|
||||
pub fn pick_list<'a, T, L, V, Message>(
|
||||
options: L,
|
||||
selected: Option<V>,
|
||||
on_select: impl Fn(T) -> Message + 'a,
|
||||
) -> iced::widget::PickList<'a, T, L, V, Message>
|
||||
where
|
||||
T: PartialEq + Clone + ToString + 'a,
|
||||
L: std::borrow::Borrow<[T]> + 'a,
|
||||
V: std::borrow::Borrow<T> + 'a,
|
||||
Message: Clone + 'a,
|
||||
{
|
||||
iced::widget::pick_list(selected, options, |value| value.to_string()).on_select(on_select)
|
||||
}
|
||||
|
||||
/// Place `content` at fixed top-left coordinates inside a fill-sized layer.
|
||||
/// Negative coordinates clamp to the layer edge.
|
||||
pub fn pin_at<'a, Message: 'a>(
|
||||
|
|
|
|||
371
src/ui/modal.rs
371
src/ui/modal.rs
|
|
@ -6,106 +6,324 @@
|
|||
//! so both stack dialogs here — one code path for every platform.
|
||||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{button, column, container, mouse_area, opaque, row, stack};
|
||||
use iced::{Background, Border, Element, Length, Padding, Theme, Vector};
|
||||
use iced::advanced::layout::{self, Layout};
|
||||
use iced::advanced::widget::{self, Widget};
|
||||
use iced::advanced::{mouse, overlay, renderer, Shell};
|
||||
use iced::widget::{button, column, container, mouse_area, opaque, row, stack, Space};
|
||||
use iced::{
|
||||
Background, Border, Element, Event, Length, Padding, Rectangle, Renderer, Size, Theme, Vector,
|
||||
};
|
||||
|
||||
/// Stack `content` over `base` behind a dimmed backdrop, framed with a
|
||||
/// draggable title bar (the ✕ close button at its right end). The backdrop only
|
||||
/// dims and blocks clicks from reaching the view beneath — it does **not**
|
||||
/// dismiss the dialog; closing is the ✕ button alone (`on_close`).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ModalOptions {
|
||||
movable: bool,
|
||||
resizable: bool,
|
||||
neutral_close: bool,
|
||||
}
|
||||
|
||||
/// Sizing used inside an intrinsically measured modal.
|
||||
///
|
||||
/// [`INTRINSIC`](Self::INTRINSIC) lets each widget report the most space it can
|
||||
/// use, while [`FILL`](Self::FILL) distributes the resulting shared frame to
|
||||
/// sibling toolbars, panes and scroll areas.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ModalSizing {
|
||||
pub width: Length,
|
||||
pub height: Length,
|
||||
}
|
||||
|
||||
impl ModalSizing {
|
||||
pub const INTRINSIC: Self = Self {
|
||||
width: Length::Fluid(iced_core::length::Constraint::Max),
|
||||
height: Length::Fluid(iced_core::length::Constraint::Max),
|
||||
};
|
||||
|
||||
pub const FILL: Self = Self {
|
||||
width: Length::Fill,
|
||||
height: Length::Fill,
|
||||
};
|
||||
|
||||
pub fn from_resize(_resize: Vector) -> Self {
|
||||
Self::FILL
|
||||
}
|
||||
}
|
||||
|
||||
/// Measure an intrinsic copy of `content`, then lay the fill copy out in the
|
||||
/// resulting shared frame. `extra` grows that frame when the resize handle is
|
||||
/// dragged; `max` only caps the initial intrinsic pass.
|
||||
pub fn intrinsic<'a>(
|
||||
measurement: impl Into<Element<'a, Message>>,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
max: Size,
|
||||
extra: Vector,
|
||||
) -> Element<'a, Message> {
|
||||
Element::new(Intrinsic {
|
||||
children: [measurement.into(), content.into()],
|
||||
max,
|
||||
extra,
|
||||
})
|
||||
}
|
||||
|
||||
struct Intrinsic<'a> {
|
||||
children: [Element<'a, Message>; 2],
|
||||
max: Size,
|
||||
extra: Vector,
|
||||
}
|
||||
|
||||
impl Widget<Message, Theme, Renderer> for Intrinsic<'_> {
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&mut self.children);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
Size::new(
|
||||
Length::Fit.max(self.max.width + self.extra.x),
|
||||
Length::Fit.max(self.max.height + self.extra.y),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
renderer: &Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
let measure_max = Size::new(
|
||||
self.max.width.min(limits.max().width),
|
||||
self.max.height.min(limits.max().height),
|
||||
);
|
||||
let measure_limits = layout::Limits::new(Size::ZERO, measure_max);
|
||||
let measured = self.children[0]
|
||||
.as_widget_mut()
|
||||
.layout(&mut tree.children[0], renderer, &measure_limits);
|
||||
let size = Size::new(
|
||||
(measured.size().width + self.extra.x).min(limits.max().width),
|
||||
(measured.size().height + self.extra.y).min(limits.max().height),
|
||||
);
|
||||
let final_limits = layout::Limits::new(size, size);
|
||||
let content = self.children[1]
|
||||
.as_widget_mut()
|
||||
.layout(&mut tree.children[1], renderer, &final_limits);
|
||||
|
||||
layout::Node::with_children(size, vec![measured, content])
|
||||
}
|
||||
|
||||
fn operate(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
layout: Layout<'_>,
|
||||
renderer: &Renderer,
|
||||
operation: &mut dyn widget::Operation,
|
||||
) {
|
||||
self.children[1]
|
||||
.as_widget_mut()
|
||||
.operate(&mut tree.children[1], layout.child(1), renderer, operation);
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
event: &Event,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.children[1].as_widget_mut().update(
|
||||
&mut tree.children[1],
|
||||
event,
|
||||
layout.child(1),
|
||||
cursor,
|
||||
renderer,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
tree: &widget::Tree,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
self.children[1]
|
||||
.as_widget()
|
||||
.mouse_interaction(
|
||||
&tree.children[1],
|
||||
layout.child(1),
|
||||
cursor,
|
||||
viewport,
|
||||
renderer,
|
||||
)
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&self,
|
||||
tree: &widget::Tree,
|
||||
renderer: &mut Renderer,
|
||||
theme: &Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.children[1]
|
||||
.as_widget()
|
||||
.draw(
|
||||
&tree.children[1],
|
||||
renderer,
|
||||
theme,
|
||||
style,
|
||||
layout.child(1),
|
||||
cursor,
|
||||
viewport,
|
||||
);
|
||||
}
|
||||
|
||||
fn overlay<'b>(
|
||||
&'b mut self,
|
||||
tree: &'b mut widget::Tree,
|
||||
layout: Layout<'b>,
|
||||
renderer: &Renderer,
|
||||
viewport: &Rectangle,
|
||||
translation: Vector,
|
||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
||||
self.children[1]
|
||||
.as_widget_mut()
|
||||
.overlay(
|
||||
&mut tree.children[1],
|
||||
layout.child(1),
|
||||
renderer,
|
||||
viewport,
|
||||
translation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModalOptions {
|
||||
pub const STANDARD: Self = Self {
|
||||
movable: true,
|
||||
resizable: true,
|
||||
neutral_close: false,
|
||||
};
|
||||
|
||||
pub const MOVABLE_FIXED: Self = Self {
|
||||
movable: true,
|
||||
resizable: false,
|
||||
neutral_close: false,
|
||||
};
|
||||
|
||||
pub const NOTICE: Self = Self {
|
||||
movable: true,
|
||||
resizable: false,
|
||||
neutral_close: true,
|
||||
};
|
||||
}
|
||||
|
||||
/// Stack `content` over `base` behind a dimmed backdrop, framed with a title bar
|
||||
/// (the ✕ close button at its right end). The backdrop only dims and blocks
|
||||
/// clicks from reaching the view beneath — it does **not** dismiss the dialog;
|
||||
/// closing is the ✕ button alone (`on_close`).
|
||||
///
|
||||
/// `offset` shifts the dialog from screen-centre so it can be dragged by its
|
||||
/// title bar; pass `Vector::ZERO` to keep it centred.
|
||||
pub fn modal<'a>(
|
||||
base: impl Into<Element<'a, Message>>,
|
||||
title: &'a str,
|
||||
title_width: f32,
|
||||
content: impl Into<Element<'a, Message>>,
|
||||
on_close: Message,
|
||||
offset: Vector,
|
||||
resizable: bool,
|
||||
options: ModalOptions,
|
||||
) -> Element<'a, Message> {
|
||||
let close = button(crate::ui::icons::themed_danger(
|
||||
crate::ui::icons::CLOSE,
|
||||
13.0,
|
||||
))
|
||||
.on_press(on_close)
|
||||
.padding([1, 7])
|
||||
.style(close_style);
|
||||
let close = if options.neutral_close {
|
||||
button(crate::ui::icons::themed_secondary(
|
||||
crate::ui::icons::CLOSE,
|
||||
13.0,
|
||||
))
|
||||
.on_press(on_close)
|
||||
.padding([1, 7])
|
||||
.style(neutral_close_style)
|
||||
} else {
|
||||
button(crate::ui::icons::themed_danger(
|
||||
crate::ui::icons::CLOSE,
|
||||
13.0,
|
||||
))
|
||||
.on_press(on_close)
|
||||
.padding([1, 7])
|
||||
.style(close_style)
|
||||
};
|
||||
|
||||
// Draggable title bar: a grip handle next to the ✕. Kept `Shrink` (no
|
||||
// `Fill`) so a single Fill child can't blow the dialog out to the full
|
||||
// screen width — the dialog stays sized to its content. Pressing the grip
|
||||
// starts a drag (handled in `update`).
|
||||
let grip = mouse_area(
|
||||
container(crate::ui::icons::themed_primary(crate::ui::icons::MOVE, 14.0))
|
||||
.padding([1, 7])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
)),
|
||||
border: Border {
|
||||
radius: 4.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
.on_press(Message::ModalGrab)
|
||||
.interaction(iced::mouse::Interaction::Grab);
|
||||
|
||||
// The dialog name is centred across the dialog width with the grip + ✕
|
||||
// overlaid at the right edge. The bar takes an explicit `title_width`
|
||||
// (the caller's content width) instead of `Fill` — a Fill child inside
|
||||
// the Shrink frame would blow the dialog out to the full screen.
|
||||
// The dialog name is centred across the content width with the ✕ overlaid
|
||||
// at the right edge. The title bar is itself an overlay: the content layer
|
||||
// below determines the intrinsic modal width before `Fill` is resolved.
|
||||
let title_text = iced::widget::text(title).size(15);
|
||||
let title_surface: Element<'a, Message> = container(title_text)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.align_y(iced::alignment::Vertical::Center)
|
||||
.into();
|
||||
let title_surface: Element<'a, Message> = if options.movable {
|
||||
mouse_area(title_surface)
|
||||
.on_press(Message::ModalGrab)
|
||||
.interaction(iced::mouse::Interaction::Grab)
|
||||
.into()
|
||||
} else {
|
||||
title_surface
|
||||
};
|
||||
let controls: Element<'a, Message> = row![close].align_y(iced::Center).into();
|
||||
let title_bar = stack![
|
||||
container(title_text)
|
||||
.width(Length::Fixed(title_width))
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.align_y(iced::alignment::Vertical::Center),
|
||||
container(row![grip, close].spacing(6).align_y(iced::Center))
|
||||
.width(Length::Fixed(title_width))
|
||||
title_surface,
|
||||
container(controls)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_x(iced::alignment::Horizontal::Right)
|
||||
.align_y(iced::alignment::Vertical::Center),
|
||||
];
|
||||
]
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0));
|
||||
|
||||
let panel_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: 6.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// The dialog is always sized to its content (the caller fixes the content's
|
||||
// width/height, growing it by the shared resize delta). When `resizable`, a
|
||||
// corner grip is appended bottom-right; dragging it drives `ModalResizeGrab`
|
||||
// + the shared drag move/release, which bumps that delta. The title bar sits
|
||||
// top-right above the content either way (`align_x(Right)`).
|
||||
let body = if resizable {
|
||||
// The first stack layer dictates its intrinsic size. Its top spacer reserves
|
||||
// room for the title, while the actual title bar and resize grip overlay it
|
||||
// without influencing the modal dimensions.
|
||||
let body_base = column![
|
||||
Space::new().height(Length::Fixed(24.0)),
|
||||
content.into(),
|
||||
]
|
||||
.spacing(6);
|
||||
let mut body = stack![body_base, title_bar];
|
||||
if options.resizable {
|
||||
let resize = mouse_area(
|
||||
container(crate::ui::icons::themed_primary(crate::ui::icons::RESIZE, 15.0))
|
||||
.padding([0, 2]),
|
||||
)
|
||||
.on_press(Message::ModalResizeGrab)
|
||||
.interaction(iced::mouse::Interaction::Grab);
|
||||
column![title_bar, content.into(), resize]
|
||||
} else {
|
||||
column![title_bar, content.into()]
|
||||
};
|
||||
let framed: Element<'a, Message> = container(
|
||||
body.spacing(6).align_x(iced::alignment::Horizontal::Right),
|
||||
)
|
||||
.padding(10)
|
||||
.style(panel_style)
|
||||
.into();
|
||||
body = body.push(
|
||||
container(resize)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.align_x(iced::alignment::Horizontal::Right)
|
||||
.align_y(iced::alignment::Vertical::Bottom),
|
||||
);
|
||||
}
|
||||
let framed: Element<'a, Message> =
|
||||
container(body).padding(10).style(panel_style).into();
|
||||
|
||||
// Position via asymmetric padding (padding is non-negative): shifting a
|
||||
// centred box by `d` on an axis needs (near − far) padding = 2·d there.
|
||||
|
|
@ -126,7 +344,7 @@ pub fn modal<'a>(
|
|||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.strongest
|
||||
.color
|
||||
|
|
@ -148,7 +366,7 @@ pub fn modal<'a>(
|
|||
}
|
||||
|
||||
fn close_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.danger.strong,
|
||||
_ => palette.background.weakest,
|
||||
|
|
@ -163,3 +381,20 @@ fn close_style(theme: &Theme, status: button::Status) -> button::Style {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn neutral_close_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.background.weak,
|
||||
_ => palette.background.weakest,
|
||||
};
|
||||
button::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
text_color: pair.text,
|
||||
border: Border {
|
||||
radius: 4.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,9 +332,9 @@ fn draw_grip_marker(frame: &mut canvas::Frame, grip: &GripMarker, theme: &Theme)
|
|||
};
|
||||
|
||||
if grip.is_hot {
|
||||
frame.fill(&path, theme.extended_palette().danger.base.color);
|
||||
frame.fill(&path, theme.palette().danger.base.color);
|
||||
} else {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let color = palette.primary.base.color;
|
||||
frame.fill(
|
||||
&path,
|
||||
|
|
@ -435,7 +435,7 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
// Filled bars in the pane_grid spacing gaps, so adjacent panes read as
|
||||
// distinct viewports. Drawn first so all other overlays sit on top.
|
||||
if !self.dividers.is_empty() {
|
||||
let divider = theme.extended_palette().background.neutral.color;
|
||||
let divider = theme.palette().background.neutral.color;
|
||||
for d in &self.dividers {
|
||||
let bar = canvas::Path::rectangle(
|
||||
Point::new(d.x, d.y),
|
||||
|
|
@ -450,13 +450,13 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
// under the cursor, and drag a translucent ghost card along the cursor
|
||||
// so the pane is visibly "moving".
|
||||
if let Some(src) = self.pane_move_rect {
|
||||
let accent = theme.extended_palette().primary.base.color;
|
||||
let accent = theme.palette().primary.base.color;
|
||||
// Source pane: dimmed + dashed-feel outline (it has been lifted).
|
||||
let src_path =
|
||||
canvas::Path::rectangle(Point::new(src.x, src.y), iced::Size::new(src.width, src.height));
|
||||
frame.fill(
|
||||
&src_path,
|
||||
theme.extended_palette().background.strong.color.scale_alpha(0.28),
|
||||
theme.palette().background.strong.color.scale_alpha(0.28),
|
||||
);
|
||||
frame.stroke(
|
||||
&src_path,
|
||||
|
|
@ -515,9 +515,9 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
theme: &Theme,
|
||||
) {
|
||||
let base = if crossing {
|
||||
theme.extended_palette().success.base.color
|
||||
theme.palette().success.base.color
|
||||
} else {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
};
|
||||
let fill = base.scale_alpha(0.12);
|
||||
let stroke = base.scale_alpha(0.9);
|
||||
|
|
@ -547,9 +547,9 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
|
||||
if self.selection.poly_active && self.selection.poly_points.len() > 1 {
|
||||
let base = if self.selection.poly_crossing {
|
||||
theme.extended_palette().success.base.color
|
||||
theme.palette().success.base.color
|
||||
} else {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
};
|
||||
let fill = base.scale_alpha(0.12);
|
||||
let stroke = base.scale_alpha(0.9);
|
||||
|
|
@ -909,7 +909,7 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
if !over_viewcube && !over_divider && !self.pan_mode && !self.suppressed {
|
||||
if let Some(cp) = self.selection.last_move_pos {
|
||||
let color = theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -956,7 +956,7 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
// the hovered object sits on a locked layer (issue: locked
|
||||
// objects are visible + snappable but not selectable/editable).
|
||||
if self.hover_locked {
|
||||
let warning = theme.extended_palette().warning.base;
|
||||
let warning = theme.palette().warning.base;
|
||||
let amber = warning.color.scale_alpha(0.98);
|
||||
let dark = warning.text;
|
||||
let bx = cp.x + sq + 7.0;
|
||||
|
|
@ -1005,7 +1005,7 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||
}
|
||||
|
||||
// ── Object Snap Tracking ─────────────────────────────────────────────
|
||||
let track_color = theme.extended_palette().primary.base.color.scale_alpha(0.7);
|
||||
let track_color = theme.palette().primary.base.color.scale_alpha(0.7);
|
||||
// The alignment line the cursor is currently locked to — drawn at its
|
||||
// real angle from the acquired point through the lock and a little
|
||||
// beyond, dashed so it reads as a construction guide. This covers the
|
||||
|
|
@ -2110,7 +2110,7 @@ impl DynInputCanvas {
|
|||
canvas::Stroke {
|
||||
width: 1.0,
|
||||
style: canvas::Style::Solid(
|
||||
theme.extended_palette().background.neutral.color.scale_alpha(0.9)
|
||||
theme.palette().background.neutral.color.scale_alpha(0.9)
|
||||
),
|
||||
line_dash: canvas::LineDash { segments: &[2.0, 3.0], offset: 0 },
|
||||
..Default::default()
|
||||
|
|
@ -2161,7 +2161,7 @@ impl DynInputCanvas {
|
|||
}
|
||||
|
||||
fn box_colors(b: &DynBox, theme: &Theme) -> (Color, Color, Color) {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
if b.active {
|
||||
(
|
||||
palette.primary.weak.color,
|
||||
|
|
@ -2188,7 +2188,7 @@ impl DynInputCanvas {
|
|||
if self.prompt.is_empty() {
|
||||
return;
|
||||
}
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pw = (self.prompt.len() as f32 * DYN_CHAR_W) + DYN_PAD * 2.0;
|
||||
let rect = canvas::Path::rectangle(pos, Size { width: pw, height: DYN_BOX_H });
|
||||
frame.fill(&rect, palette.background.strong.color);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub fn menu_entries(
|
|||
let divider = container(iced::widget::Space::new().height(1))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color,
|
||||
theme.palette().background.weak.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -83,7 +83,7 @@ fn empty_row() -> Element<'static, Message> {
|
|||
text("No objects").size(11).style(|theme: &Theme| text::Style {
|
||||
color: Some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub fn menu_entries<'a>(snapper: &'a Snapper) -> Vec<Entry<'a>> {
|
|||
let divider = container(iced::widget::Space::new().height(1))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color,
|
||||
theme.palette().background.weak.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl canvas::Program<Message> for HatchPatternPreview {
|
|||
use crate::scene::model::hatch_model::{HatchModel, HatchPattern};
|
||||
|
||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pad = 4.0;
|
||||
let sample = canvas::Path::rectangle(
|
||||
Point::new(pad, pad),
|
||||
|
|
@ -342,7 +342,7 @@ impl PropertiesPanel {
|
|||
let header = container(text("Properties").size(12))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color,
|
||||
theme.palette().background.weak.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -372,7 +372,7 @@ impl PropertiesPanel {
|
|||
|
||||
let title_bar = container(title_content)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weakest.color)),
|
||||
border: Border {
|
||||
|
|
@ -405,7 +405,7 @@ impl PropertiesPanel {
|
|||
|
||||
container(column![header, title_bar, content])
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -434,7 +434,7 @@ impl PropertiesPanel {
|
|||
.style(muted_text_style),
|
||||
)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weakest.color)),
|
||||
border: Border {
|
||||
|
|
@ -456,7 +456,7 @@ impl PropertiesPanel {
|
|||
Some(
|
||||
container(col)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -478,7 +478,7 @@ impl PropertiesPanel {
|
|||
// Section header
|
||||
let hdr = container(text(§ion.title).size(10))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -665,7 +665,7 @@ impl PropertiesPanel {
|
|||
row![
|
||||
container(text("?").size(10))
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.strong.color)),
|
||||
border: Border {
|
||||
|
|
@ -896,7 +896,7 @@ impl PropertiesPanel {
|
|||
)
|
||||
.on_press(Message::PropEditChoiceToggle)
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.background.weak,
|
||||
_ => palette.background.base,
|
||||
|
|
@ -917,7 +917,7 @@ impl PropertiesPanel {
|
|||
.height(Length::Fixed(ROW_H - 6.0));
|
||||
let head = container(row![input, caret].align_y(iced::Center))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -956,7 +956,7 @@ impl PropertiesPanel {
|
|||
.style(container::bordered_box)
|
||||
.padding(2)
|
||||
.width(200)
|
||||
.max_height(220.0);
|
||||
.height(Length::Fit.max(220.0));
|
||||
|
||||
prop_row_widget(
|
||||
label,
|
||||
|
|
@ -1011,7 +1011,7 @@ impl PropertiesPanel {
|
|||
)
|
||||
.on_press(Message::PropHatchPatternPickerToggle(current.to_string()))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let hovered = matches!(status, button::Status::Hovered | button::Status::Pressed);
|
||||
button::Style {
|
||||
background: Some(Background::Color(if hovered {
|
||||
|
|
@ -1072,7 +1072,7 @@ impl PropertiesPanel {
|
|||
)
|
||||
.on_press(Message::PropHatchPatternChanged(name))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let hovered =
|
||||
matches!(status, button::Status::Hovered | button::Status::Pressed);
|
||||
let pair = if selected {
|
||||
|
|
@ -1126,7 +1126,7 @@ impl PropertiesPanel {
|
|||
.style(container::bordered_box)
|
||||
.padding(8)
|
||||
.width(348)
|
||||
.max_height(360.0);
|
||||
.height(Length::Fit.max(360.0));
|
||||
|
||||
prop_row_widget(
|
||||
label,
|
||||
|
|
@ -1175,9 +1175,9 @@ pub fn color_picker_dropdown<'a>(
|
|||
background: Some(Background::Color(bg)),
|
||||
border: Border {
|
||||
color: if matches!(status, button::Status::Hovered) {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
} else {
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
},
|
||||
width: if matches!(status, button::Status::Hovered) {
|
||||
1.5
|
||||
|
|
@ -1186,7 +1186,7 @@ pub fn color_picker_dropdown<'a>(
|
|||
},
|
||||
radius: 2.0.into(),
|
||||
},
|
||||
text_color: theme.extended_palette().background.base.text,
|
||||
text_color: theme.palette().background.base.text,
|
||||
..Default::default()
|
||||
})
|
||||
.padding(0),
|
||||
|
|
@ -1222,7 +1222,7 @@ pub fn color_picker_dropdown<'a>(
|
|||
|
||||
let mut col = column![container(inner)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -1258,9 +1258,9 @@ pub fn color_picker_dropdown<'a>(
|
|||
background: Some(Background::Color(bg)),
|
||||
border: Border {
|
||||
color: if matches!(status, button::Status::Hovered) {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
} else {
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
},
|
||||
width: if matches!(status, button::Status::Hovered) {
|
||||
1.5
|
||||
|
|
@ -1269,7 +1269,7 @@ pub fn color_picker_dropdown<'a>(
|
|||
},
|
||||
radius: 1.0.into(),
|
||||
},
|
||||
text_color: theme.extended_palette().background.base.text,
|
||||
text_color: theme.palette().background.base.text,
|
||||
..Default::default()
|
||||
})
|
||||
.padding(0),
|
||||
|
|
@ -1281,7 +1281,7 @@ pub fn color_picker_dropdown<'a>(
|
|||
col = col.push(
|
||||
container(scrollable(rows).height(160))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -1309,7 +1309,7 @@ fn render_stepper_row<'a>(label: &'a str, display: &'a str) -> Element<'a, Messa
|
|||
.on_press(Message::PropVertexStep(delta))
|
||||
.padding([0, 6])
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.background.weak,
|
||||
_ => palette.background.base,
|
||||
|
|
@ -1346,12 +1346,12 @@ fn render_bool_row<'a>(label: &'a str, field: &'static str, value: bool) -> Elem
|
|||
text(btn_label)
|
||||
.size(FONT_SZ)
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: value.then_some(theme.extended_palette().warning.base.color),
|
||||
color: value.then_some(theme.palette().warning.base.color),
|
||||
}),
|
||||
)
|
||||
.on_press(Message::PropBoolToggle(field))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.background.weak,
|
||||
_ => palette.background.base,
|
||||
|
|
@ -1480,7 +1480,7 @@ fn render_group_row(
|
|||
let label_col = container(label_btn)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -1498,7 +1498,7 @@ fn render_group_row(
|
|||
let value_col = container(value_field)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -1516,7 +1516,7 @@ fn render_group_row(
|
|||
.height(Length::Fixed(ROW_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: 0.0.into(),
|
||||
},
|
||||
|
|
@ -1548,7 +1548,7 @@ fn prop_row_widget<'a>(label: &'a str, widget: Element<'a, Message>) -> Element<
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -1564,7 +1564,7 @@ fn prop_row_widget<'a>(label: &'a str, widget: Element<'a, Message>) -> Element<
|
|||
let value_col = container(widget)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -1581,7 +1581,7 @@ fn prop_row_widget<'a>(label: &'a str, widget: Element<'a, Message>) -> Element<
|
|||
.height(Length::Fixed(ROW_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: 0.0.into(),
|
||||
},
|
||||
|
|
@ -1655,7 +1655,7 @@ fn aci_label(idx: u8) -> &'static str {
|
|||
// ── Widget style helpers ──────────────────────────────────────────────────
|
||||
|
||||
fn combo_btn_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => palette.background.weak,
|
||||
_ => palette.background.base,
|
||||
|
|
@ -1673,7 +1673,7 @@ fn combo_btn_style(theme: &Theme, status: button::Status) -> button::Style {
|
|||
}
|
||||
|
||||
fn text_input_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border_color = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -1700,7 +1700,7 @@ fn combo_input_style(theme: &Theme, status: text_input::Status) -> text_input::S
|
|||
/// focus highlight, so it reads as plain text, unlike the bordered editable
|
||||
/// fields) yet with a visible selection colour so Ctrl+C copy is discoverable.
|
||||
fn ro_input_style(theme: &Theme, _status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
text_input::Style {
|
||||
background: Background::Color(palette.background.base.color),
|
||||
border: Border {
|
||||
|
|
@ -1717,13 +1717,13 @@ fn ro_input_style(theme: &Theme, _status: text_input::Status) -> text_input::Sty
|
|||
|
||||
fn muted_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.72)),
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.72)),
|
||||
}
|
||||
}
|
||||
|
||||
fn hint_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.48)),
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.48)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use std::sync::Arc;
|
|||
|
||||
use iced::advanced::layout::{self, Layout};
|
||||
use iced::advanced::widget::{self, Widget};
|
||||
use iced::advanced::{mouse, overlay, renderer, Clipboard, Renderer as _, Shell};
|
||||
use iced::advanced::{mouse, overlay, renderer, Renderer as _, Shell};
|
||||
use iced::{
|
||||
Background, Border, Element, Event, Length, Point, Rectangle, Renderer, Shadow, Size,
|
||||
Theme, Vector,
|
||||
|
|
@ -184,28 +184,16 @@ impl<'a> CollapsePanels<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
let mut v = Vec::with_capacity(self.panels.len() * SLOTS);
|
||||
for p in &self.panels {
|
||||
v.push(widget::Tree::new(&p.full));
|
||||
v.push(widget::Tree::new(&p.compact));
|
||||
v.push(widget::Tree::new(&p.button));
|
||||
v.push(widget::Tree::new(&p.tight));
|
||||
v.push(widget::Tree::new(&p.flyout));
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
let mut refs = Vec::with_capacity(self.panels.len() * SLOTS);
|
||||
for p in &mut self.panels {
|
||||
refs.push(&mut p.full);
|
||||
refs.push(&mut p.compact);
|
||||
refs.push(&mut p.button);
|
||||
refs.push(&mut p.tight);
|
||||
refs.push(&mut p.flyout);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
let mut refs: Vec<&dyn Widget<Message, Theme, Renderer>> = Vec::new();
|
||||
for p in &self.panels {
|
||||
refs.push(p.full.as_widget());
|
||||
refs.push(p.compact.as_widget());
|
||||
refs.push(p.button.as_widget());
|
||||
refs.push(p.tight.as_widget());
|
||||
refs.push(p.flyout.as_widget());
|
||||
}
|
||||
tree.diff_children(&refs);
|
||||
tree.diff_children(&mut refs);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -362,7 +350,6 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -376,7 +363,6 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
|||
child_layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -477,7 +463,7 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
|||
shadow: Shadow::default(),
|
||||
snap: true,
|
||||
},
|
||||
Background::Color(theme.extended_palette().background.neutral.color),
|
||||
Background::Color(theme.palette().background.neutral.color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -611,7 +597,6 @@ impl overlay::Overlay<Message, Theme, Renderer> for FlyoutOverlay<'_, '_> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
) {
|
||||
let child = layout.children().next().unwrap();
|
||||
|
|
@ -627,7 +612,7 @@ impl overlay::Overlay<Message, Theme, Renderer> for FlyoutOverlay<'_, '_> {
|
|||
|
||||
self.flyout
|
||||
.as_widget_mut()
|
||||
.update(self.tree, event, child, cursor, renderer, clipboard, shell, &vp);
|
||||
.update(self.tree, event, child, cursor, renderer, shell, &vp);
|
||||
}
|
||||
|
||||
fn operate(
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ impl Ribbon {
|
|||
button(text(module.title()).size(12))
|
||||
.on_press(Message::RibbonSelectTab(i))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let accent = if is_contextual {
|
||||
palette.warning.base
|
||||
} else {
|
||||
|
|
@ -470,9 +470,9 @@ impl Ribbon {
|
|||
border: Border {
|
||||
color: if is_active {
|
||||
if is_contextual {
|
||||
theme.extended_palette().warning.base.color
|
||||
theme.palette().warning.base.color
|
||||
} else {
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
}
|
||||
} else {
|
||||
Color::TRANSPARENT
|
||||
|
|
@ -526,7 +526,7 @@ impl Ribbon {
|
|||
let tab_bar = container(tab_row)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -647,10 +647,10 @@ impl Ribbon {
|
|||
))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
|
|
@ -672,10 +672,10 @@ impl Ribbon {
|
|||
let tool_bar = container(tool_area)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
|
|
@ -827,7 +827,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_current).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -895,7 +895,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(lc)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.strong.color,
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 1.0.into(),
|
||||
},
|
||||
|
|
@ -924,7 +924,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_active).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -981,7 +981,7 @@ impl Ribbon {
|
|||
.padding([3, 4])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
|
|
@ -1055,7 +1055,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_sel).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -1154,7 +1154,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_cur).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -1207,7 +1207,7 @@ impl Ribbon {
|
|||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_cur).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ pub(super) fn make_icon_dim(icon: IconKind, size: f32, dim: bool) -> Element<'st
|
|||
IconKind::Glyph(s) => text(s)
|
||||
.size(size * 0.7)
|
||||
.style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.42)),
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.42)),
|
||||
})
|
||||
.into(),
|
||||
IconKind::Svg(bytes) => icons::semantic_disabled(bytes, size),
|
||||
|
|
@ -179,7 +179,7 @@ pub(super) fn tool_btn_style(
|
|||
is_active: bool,
|
||||
status: button::Status,
|
||||
) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (is_active, status) {
|
||||
(true, _) => palette.primary.weak,
|
||||
(_, button::Status::Hovered) => palette.background.weak,
|
||||
|
|
@ -208,7 +208,7 @@ pub(super) fn combo_btn_style(
|
|||
status: button::Status,
|
||||
radius: f32,
|
||||
) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if is_open {
|
||||
palette.primary.weak
|
||||
} else if matches!(status, button::Status::Hovered | button::Status::Pressed) {
|
||||
|
|
@ -233,7 +233,7 @@ pub(super) fn combo_btn_style(
|
|||
}
|
||||
|
||||
pub(super) fn popup_row_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if matches!(status, button::Status::Hovered | button::Status::Pressed) {
|
||||
palette.background.weak
|
||||
} else {
|
||||
|
|
@ -247,7 +247,7 @@ pub(super) fn popup_row_style(theme: &Theme, status: button::Status) -> button::
|
|||
}
|
||||
|
||||
pub(super) fn popup_panel_style(theme: &Theme) -> container::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -261,14 +261,14 @@ pub(super) fn popup_panel_style(theme: &Theme) -> container::Style {
|
|||
|
||||
pub(super) fn muted_text_style(theme: &Theme) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.72)),
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.72)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn tool_label_style(theme: &Theme, dim: bool) -> iced::widget::text::Style {
|
||||
iced::widget::text::Style {
|
||||
color: dim.then_some(
|
||||
theme.extended_palette().background.base.text.scale_alpha(0.42),
|
||||
theme.palette().background.base.text.scale_alpha(0.42),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +280,7 @@ pub(super) fn make_tip(tip: String) -> Element<'static, Message> {
|
|||
}
|
||||
|
||||
pub(super) fn tip_style(theme: &Theme) -> container::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.strong.color)),
|
||||
border: Border {
|
||||
|
|
@ -632,7 +632,7 @@ pub(super) fn render_large<'a>(
|
|||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(lc)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.strong.color,
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 1.0.into(),
|
||||
},
|
||||
|
|
@ -778,7 +778,7 @@ pub(super) fn render_large<'a>(
|
|||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(c)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.strong.color,
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 1.0.into(),
|
||||
},
|
||||
|
|
@ -1088,7 +1088,7 @@ pub(super) fn top_hist_btn_style(
|
|||
open: bool,
|
||||
status: button::Status,
|
||||
) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (active, open, status) {
|
||||
(false, _, _) => palette.background.weakest,
|
||||
(_, true, _) => palette.primary.weak,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ fn tip_panel(label: &'static str) -> Element<'static, Message> {
|
|||
container(text(label).size(11))
|
||||
.padding([2, 6])
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.strong.color)),
|
||||
border: Border {
|
||||
|
|
@ -62,7 +62,7 @@ pub fn view(tools: &[ToolDef]) -> Option<Element<'static, Message>> {
|
|||
.width(Length::Fixed(BTN_SIZE))
|
||||
.height(Length::Fixed(BTN_SIZE))
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let hovered = matches!(
|
||||
status,
|
||||
button::Status::Hovered | button::Status::Pressed
|
||||
|
|
@ -85,7 +85,7 @@ pub fn view(tools: &[ToolDef]) -> Option<Element<'static, Message>> {
|
|||
}
|
||||
|
||||
let panel = container(col).padding(4).style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ impl StatusBar {
|
|||
|
||||
container(wrap)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -581,7 +581,7 @@ fn toggle_pill(icon: &'static [u8], active: bool, msg: Message) -> Element<'stat
|
|||
.style(move |theme: &Theme, status| {
|
||||
let mut style = button::subtle(theme, status);
|
||||
if active {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
style.background = Some(Background::Color(match status {
|
||||
button::Status::Hovered => palette.primary.base.color,
|
||||
_ => palette.primary.weak.color,
|
||||
|
|
@ -612,7 +612,7 @@ fn split_pill<'a>(
|
|||
) -> Element<'a, Message> {
|
||||
container(row![main, caret].spacing(3).align_y(iced::Center))
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(if active {
|
||||
palette.primary.weak.color
|
||||
|
|
@ -667,7 +667,7 @@ fn polar_pill<'a>(
|
|||
row![
|
||||
polar_icon,
|
||||
text(angle).size(11).style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
text::Style {
|
||||
color: Some(if active {
|
||||
palette.primary.base.color
|
||||
|
|
@ -796,7 +796,7 @@ fn space_tab<'a>(
|
|||
report_key_prefix: &'static str,
|
||||
) -> Element<'a, Message> {
|
||||
let tab_style = move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let text_color = if !enabled {
|
||||
palette.background.base.text.scale_alpha(0.42)
|
||||
} else if is_active {
|
||||
|
|
@ -912,7 +912,7 @@ fn space_mode_btn(current_layout: &str, in_mspace: bool) -> Element<'static, Mes
|
|||
.style(move |theme: &Theme, status| {
|
||||
let mut style = button::subtle(theme, status);
|
||||
if active {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
style.background = Some(Background::Color(match status {
|
||||
button::Status::Hovered if clickable => palette.primary.base.color,
|
||||
_ => palette.primary.weak.color,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ pub fn menu_bar<'a>(
|
|||
.close_on_background_click_global(true)
|
||||
.draw_path(DrawPath::Backdrop)
|
||||
.style(|theme: &Theme, _| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
iced_aw::style::menu_bar::Style {
|
||||
bar_background: Background::Color(Color::TRANSPARENT),
|
||||
bar_border: Border::default(),
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ fn layout_row<'a>(name: String, is_current: bool) -> Element<'a, Message> {
|
|||
.style(move |theme: &Theme, status| {
|
||||
let mut style = button::subtle(theme, status);
|
||||
if is_current && status == button::Status::Active {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
style.background = Some(Background::Color(palette.primary.weak.color));
|
||||
style.text_color = palette.primary.weak.text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,18 +9,19 @@
|
|||
use crate::app::Message;
|
||||
use crate::ui::style::style_manager::{hdivider, muted_text_style, tb_button};
|
||||
use iced::widget::{column, container, mouse_area, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
/// `scales` is `(name, "paper:drawing" ratio, is_member)`. Every label is cloned
|
||||
/// into the widget tree, so the returned element borrows nothing from the args.
|
||||
pub fn view_window(
|
||||
object_label: &str,
|
||||
scales: &[(String, String, bool)],
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'static, Message> {
|
||||
let toolbar = container(
|
||||
row![
|
||||
text(format!("Object: {object_label}")).size(11),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
tb_button("Close", Message::CloseModal, true),
|
||||
]
|
||||
.spacing(4)
|
||||
|
|
@ -28,11 +29,11 @@ pub fn view_window(
|
|||
)
|
||||
.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(sizing.width)
|
||||
.padding([5, 8]);
|
||||
|
||||
let rows: Vec<Element<'_, Message>> = scales
|
||||
|
|
@ -41,23 +42,23 @@ pub fn view_window(
|
|||
let check = crate::ui::icons::themed_check_cell(*member);
|
||||
let label = row![
|
||||
check,
|
||||
text(name.clone()).size(11).width(Fill),
|
||||
text(name.clone()).size(11).width(sizing.width),
|
||||
text(ratio.clone()).size(10).style(muted_text_style),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center);
|
||||
let cell = container(label)
|
||||
.padding([4, 8])
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
mouse_area(cell)
|
||||
.on_press(Message::AnnoObjectScaleToggle(name.clone()))
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let list = container(scrollable(column(rows).spacing(1)).height(Fill))
|
||||
let list = container(scrollable(column(rows).spacing(1)).height(sizing.height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -68,8 +69,8 @@ pub fn view_window(
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2);
|
||||
|
||||
let body = container(
|
||||
|
|
@ -80,20 +81,20 @@ pub fn view_window(
|
|||
list,
|
||||
]
|
||||
.spacing(6)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(12);
|
||||
|
||||
container(column![toolbar, hdivider(), body])
|
||||
container(column![toolbar, hdivider(sizing.width), body])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use crate::app::{ColorPickTarget, DsField, Message};
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space,
|
||||
button, checkbox, column, container, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
/// All DimStyle field values needed by the view.
|
||||
pub struct DimStyleValues<'a> {
|
||||
|
|
@ -95,7 +95,7 @@ pub struct DimStyleValues<'a> {
|
|||
|
||||
fn tab_btn_style(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (active, st) {
|
||||
(true, _) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -117,7 +117,7 @@ fn tab_btn_style(active: bool) -> impl Fn(&Theme, button::Status) -> button::Sty
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -138,23 +138,23 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -169,6 +169,7 @@ pub fn view_window<'a>(
|
|||
vals: DimStyleValues<'a>,
|
||||
rename_active: Option<&'a str>,
|
||||
rename_buf: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Tab bar ───────────────────────────────────────────────────────────
|
||||
let tabs = row![
|
||||
|
|
@ -234,7 +235,7 @@ pub fn view_window<'a>(
|
|||
.unwrap_or_else(|| val.to_string());
|
||||
row![
|
||||
lbl(label),
|
||||
pick_list(labels, Some(cur), move |chosen| {
|
||||
crate::ui::pick_list(labels, Some(cur), move |chosen| {
|
||||
let code = opts
|
||||
.iter()
|
||||
.find(|(_, l)| *l == chosen.as_str())
|
||||
|
|
@ -288,7 +289,7 @@ pub fn view_window<'a>(
|
|||
Message::DsColorMore(fld.clone()),
|
||||
Message::OpenColorWindow(ColorPickTarget::DimStyle(fld.clone())),
|
||||
);
|
||||
row![lbl(label), selector]
|
||||
row![lbl(label), container(selector).width(150)]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
.into()
|
||||
|
|
@ -303,7 +304,7 @@ pub fn view_window<'a>(
|
|||
-> Element<'a, Message> {
|
||||
row![
|
||||
lbl(label),
|
||||
pick_list(options, Some(selected), move |value| {
|
||||
crate::ui::pick_list(options, Some(selected), move |value| {
|
||||
Message::DsSetHandle { field, value }
|
||||
})
|
||||
.text_size(11)
|
||||
|
|
@ -753,16 +754,16 @@ pub fn view_window<'a>(
|
|||
column![
|
||||
text(format!("Editing: {selected}")).size(11).style(muted_style),
|
||||
tabs,
|
||||
hdivider(),
|
||||
scrollable(container(tab_content).padding([12, 12]).width(Fill))
|
||||
.width(Fill)
|
||||
.height(Fill),
|
||||
hdivider(sizing.width),
|
||||
scrollable(container(tab_content).padding([12, 12]).width(sizing.width))
|
||||
.width(sizing.width)
|
||||
.height(sizing.height),
|
||||
]
|
||||
.spacing(6)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.height(Fill)
|
||||
.width(Fill)
|
||||
.height(sizing.height)
|
||||
.width(sizing.width)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 0.0,
|
||||
|
|
@ -771,6 +772,7 @@ pub fn view_window<'a>(
|
|||
});
|
||||
|
||||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||||
sizing,
|
||||
kind: crate::app::StyleKind::Dim,
|
||||
styles: &styles,
|
||||
selected,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input,
|
||||
button, checkbox, column, container, row, scrollable, text, text_input,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (accent, st) {
|
||||
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -32,13 +32,13 @@ fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ fn enum_row<'a>(
|
|||
) -> Element<'a, Message> {
|
||||
row![
|
||||
text(label).size(11).style(muted_style).width(150),
|
||||
pick_list(options, Some(selected), move |value| {
|
||||
crate::ui::pick_list(options, Some(selected), move |value| {
|
||||
Message::MLeaderStyleSetEnum { field, value }
|
||||
})
|
||||
.text_size(11)
|
||||
|
|
@ -157,7 +157,7 @@ fn lineweight_row<'a>(selected: acadrust::types::LineWeight) -> Element<'a, Mess
|
|||
let selected = crate::ui::properties::LwItem(selected);
|
||||
row![
|
||||
text("Line weight:").size(11).style(muted_style).width(150),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
crate::ui::properties::lw_options(),
|
||||
Some(selected),
|
||||
|item| Message::MLeaderStyleLineWeightChanged(item.0)
|
||||
|
|
@ -199,7 +199,7 @@ fn handle_row<'a>(
|
|||
) -> Element<'a, Message> {
|
||||
row![
|
||||
text(label).size(11).style(muted_style).width(150),
|
||||
pick_list(options, Some(selected), move |value| {
|
||||
crate::ui::pick_list(options, Some(selected), move |value| {
|
||||
Message::MLeaderStyleSetHandle { field, value }
|
||||
})
|
||||
.text_size(11)
|
||||
|
|
@ -219,7 +219,10 @@ fn chk<'a>(label: &'static str, val: bool, field: &'static str) -> Element<'a, M
|
|||
.into()
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> {
|
||||
pub fn view_window<'a>(
|
||||
v: MLeaderStyleView<'a>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Right: Details panel ──────────────────────────────────────────────
|
||||
let details: Element<'_, Message> = if let Some(s) = v.style {
|
||||
scrollable(
|
||||
|
|
@ -396,8 +399,8 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> {
|
|||
.spacing(6)
|
||||
.padding([12, 12]),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
} else {
|
||||
container(text("Select a style to view details.").size(11).style(muted_style))
|
||||
|
|
@ -405,9 +408,12 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> {
|
|||
.into()
|
||||
};
|
||||
|
||||
let right_panel = container(details).width(Fill).height(Fill);
|
||||
let right_panel = container(details)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||||
sizing,
|
||||
kind: crate::app::StyleKind::MLeader,
|
||||
styles: &v.styles,
|
||||
selected: v.selected,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{column, container, row, scrollable, text};
|
||||
use iced::{Element, Fill, Theme};
|
||||
use iced::{Element, Theme};
|
||||
|
||||
fn 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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ pub fn view_window<'a>(
|
|||
current_style: String,
|
||||
rename_active: Option<&'a str>,
|
||||
rename_buf: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Right: Details panel ──────────────────────────────────────────────
|
||||
let info_row = |label: &'static str, val: String| -> Element<'_, Message> {
|
||||
|
|
@ -69,7 +70,7 @@ pub fn view_window<'a>(
|
|||
];
|
||||
col_items.extend(elem_rows);
|
||||
scrollable(column(col_items).spacing(6).padding([12, 12]))
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
} else {
|
||||
container(text("Select a style to view details.").size(11).style(muted_style))
|
||||
|
|
@ -77,9 +78,12 @@ pub fn view_window<'a>(
|
|||
.into()
|
||||
};
|
||||
|
||||
let right_panel = container(details).width(Fill).height(Fill);
|
||||
let right_panel = container(details)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||||
sizing,
|
||||
kind: crate::app::StyleKind::MLine,
|
||||
styles: &styles,
|
||||
selected,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (accent, st) {
|
||||
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -29,7 +29,7 @@ fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -50,30 +50,30 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
|
||||
fn 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 hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn vsep<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(Fill))
|
||||
fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -86,6 +86,7 @@ pub fn view_window<'a>(
|
|||
color_buf: &'a str,
|
||||
lw_buf: &'a str,
|
||||
screen_buf: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let table_name = table
|
||||
.map(|t| t.name.as_str())
|
||||
|
|
@ -106,7 +107,7 @@ pub fn view_window<'a>(
|
|||
.on_press(Message::PlotStyleClear)
|
||||
.style(btn_s(false))
|
||||
.padding([4, 10]),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
text(table_name).size(10).style(muted_style),
|
||||
]
|
||||
.spacing(4)
|
||||
|
|
@ -114,11 +115,11 @@ pub fn view_window<'a>(
|
|||
)
|
||||
.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(sizing.width)
|
||||
.padding([5, 8]);
|
||||
|
||||
// ── Left: ACI list ────────────────────────────────────────────────────
|
||||
|
|
@ -153,7 +154,7 @@ pub fn view_window<'a>(
|
|||
button(text(label).size(10).font(iced::Font::MONOSPACE))
|
||||
.on_press(Message::PlotStylePanelSelectAci(aci))
|
||||
.style(move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (is_sel, st) {
|
||||
(true, _) => Some(palette.primary.strong),
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -170,7 +171,7 @@ pub fn view_window<'a>(
|
|||
}
|
||||
})
|
||||
.padding([2, 8])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -178,9 +179,9 @@ pub fn view_window<'a>(
|
|||
let aci_list = container(
|
||||
column![
|
||||
text("ACI Color Index").size(10).style(muted_style),
|
||||
container(scrollable(column(aci_items).spacing(1)).height(Fill))
|
||||
container(scrollable(column(aci_items).spacing(1)).height(sizing.height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -191,15 +192,15 @@ pub fn view_window<'a>(
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2),
|
||||
]
|
||||
.spacing(4)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(280)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -261,29 +262,29 @@ pub fn view_window<'a>(
|
|||
text(format!(" Color: {cur_color}")).size(10),
|
||||
text(format!(" Lineweight: {cur_lw}")).size(10),
|
||||
text(format!(" Screening: {cur_scr}")).size(10),
|
||||
Space::new().height(Fill),
|
||||
Space::new().height(sizing.height),
|
||||
button(text("Apply to ACI").size(11))
|
||||
.on_press(Message::PlotStylePanelApply)
|
||||
.style(btn_s(true))
|
||||
.padding([5, 10]),
|
||||
]
|
||||
.spacing(8)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding([12, 12]);
|
||||
|
||||
let body = row![aci_list, vsep(), edit_panel].height(Fill);
|
||||
let body = row![aci_list, vsep(sizing.height), edit_panel].height(sizing.height);
|
||||
|
||||
container(column![toolbar, hdivider(), body].spacing(0))
|
||||
container(column![toolbar, hdivider(sizing.width), body].spacing(0))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl canvas::Program<Message> for GlyphCanvas {
|
|||
_cursor: mouse::Cursor,
|
||||
) -> Vec<canvas::Geometry> {
|
||||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||||
let glyph = theme.extended_palette().background.base.text;
|
||||
let glyph = theme.palette().background.base.text;
|
||||
let (cx, cy) = (bounds.width * 0.5, bounds.height * 0.5);
|
||||
let r = bounds.width.min(bounds.height) * 0.30;
|
||||
let stroke = canvas::Stroke {
|
||||
|
|
@ -83,7 +83,7 @@ fn cell<'a>(value: i16, selected: bool) -> Element<'a, Message> {
|
|||
.padding(0)
|
||||
.on_press(Message::PointStyleSetMode(value))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if selected {
|
||||
palette.primary.strong
|
||||
} else if matches!(status, button::Status::Hovered | button::Status::Pressed) {
|
||||
|
|
@ -106,7 +106,7 @@ fn cell<'a>(value: i16, selected: bool) -> Element<'a, Message> {
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -127,11 +127,18 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
|
||||
fn 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)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'a, Message> {
|
||||
pub fn view_window<'a>(
|
||||
pdmode: i16,
|
||||
relative: bool,
|
||||
size_buf: &str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let width = sizing.width;
|
||||
let height = sizing.height;
|
||||
// Glyph grid: a row per enclosure, a cell per shape.
|
||||
let mut grid = column![].spacing(6);
|
||||
for enc in ENCLOSURES {
|
||||
|
|
@ -192,16 +199,20 @@ pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'
|
|||
Space::new().height(8),
|
||||
radios,
|
||||
Space::new().height(12),
|
||||
row![Space::new().width(Length::Fill), ok],
|
||||
row![Space::new().width(width), ok].width(width),
|
||||
]
|
||||
.spacing(4)
|
||||
.padding(20),
|
||||
.padding(20)
|
||||
.width(width)
|
||||
.height(height),
|
||||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::ui::style::style_manager::{
|
|||
use iced::widget::{
|
||||
column, container, mouse_area, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
/// Inline-rename text-input id, so the rename-start handler can focus it.
|
||||
pub fn rename_input_id() -> iced::widget::Id {
|
||||
|
|
@ -20,7 +20,7 @@ pub fn rename_input_id() -> iced::widget::Id {
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -49,6 +49,7 @@ pub fn view_window<'a, 'b>(
|
|||
rename_buf: &'a str,
|
||||
paper_buf: &'a str,
|
||||
drawing_buf: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Toolbar: New / Delete | Set Current / Apply ───────────────────────
|
||||
let toolbar = container(
|
||||
|
|
@ -56,7 +57,7 @@ pub fn view_window<'a, 'b>(
|
|||
tb_button("New", Message::ScaleManagerNew, false),
|
||||
tb_button("Copy", Message::ScaleManagerCopy, false),
|
||||
tb_button("Delete", Message::ScaleManagerDelete, false),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
tb_button("Set Current", Message::ScaleManagerSetCurrent, false),
|
||||
tb_button("Apply", Message::ScaleManagerApply, true),
|
||||
]
|
||||
|
|
@ -65,11 +66,11 @@ pub fn view_window<'a, 'b>(
|
|||
)
|
||||
.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(sizing.width)
|
||||
.padding([5, 8]);
|
||||
|
||||
// ── Left: scale list ──────────────────────────────────────────────────
|
||||
|
|
@ -85,7 +86,7 @@ pub fn view_window<'a, 'b>(
|
|||
.on_submit(Message::ScaleRenameCommit)
|
||||
.size(11)
|
||||
.padding([4, 8])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into();
|
||||
}
|
||||
let is_sel = name.as_str() == selected;
|
||||
|
|
@ -93,16 +94,16 @@ pub fn view_window<'a, 'b>(
|
|||
let check = crate::ui::icons::themed_check_cell(is_cur);
|
||||
let label = row![
|
||||
check,
|
||||
text(name.clone()).size(11).width(Fill),
|
||||
text(name.clone()).size(11).width(sizing.width),
|
||||
text(ratio.clone()).size(10).style(muted_text_style),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center);
|
||||
let cell = container(label)
|
||||
.padding([4, 8])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.style(move |theme: &Theme| {
|
||||
let pair = theme.extended_palette().primary.strong;
|
||||
let pair = theme.palette().primary.strong;
|
||||
container::Style {
|
||||
background: is_sel.then_some(Background::Color(pair.color)),
|
||||
text_color: is_sel.then_some(pair.text),
|
||||
|
|
@ -119,9 +120,9 @@ pub fn view_window<'a, 'b>(
|
|||
let list_panel = container(
|
||||
column![
|
||||
text("Scales").size(10).style(muted_text_style),
|
||||
container(scrollable(column(rows).spacing(1)).height(Fill))
|
||||
container(scrollable(column(rows).spacing(1)).height(sizing.height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -132,15 +133,15 @@ pub fn view_window<'a, 'b>(
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2),
|
||||
]
|
||||
.spacing(4)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(190)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -158,7 +159,7 @@ pub fn view_window<'a, 'b>(
|
|||
.style(field_style)
|
||||
.size(12)
|
||||
.padding([5, 8])
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.align_y(iced::Center)
|
||||
.spacing(6)
|
||||
|
|
@ -176,20 +177,20 @@ pub fn view_window<'a, 'b>(
|
|||
]
|
||||
.spacing(8),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(12);
|
||||
|
||||
let body = row![list_panel, vsep(), editor].height(Fill);
|
||||
let body = row![list_panel, vsep(sizing.height), editor].height(sizing.height);
|
||||
|
||||
container(column![toolbar, hdivider(), body])
|
||||
container(column![toolbar, hdivider(sizing.width), body])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub fn item<'a>(
|
|||
.padding([4, 8])
|
||||
.width(Fill)
|
||||
.style(move |theme: &Theme| {
|
||||
let pair = theme.extended_palette().primary.strong;
|
||||
let pair = theme.palette().primary.strong;
|
||||
container::Style {
|
||||
background: is_selected.then_some(Background::Color(pair.color)),
|
||||
text_color: is_selected.then_some(pair.text),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
use crate::app::{Message, StyleKind};
|
||||
use iced::widget::button::{Status, Style};
|
||||
use iced::widget::{button, column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
/// Everything the shared frame needs. The per-manager `editor` element is the
|
||||
/// only bespoke part.
|
||||
|
|
@ -24,6 +24,7 @@ use iced::{Background, Border, Element, Fill, Theme};
|
|||
/// list data (`styles`, `selected`, …) that the frame only reads while building
|
||||
/// rows, so callers may pass a locally-built `Vec`.
|
||||
pub struct Scaffold<'a, 'b> {
|
||||
pub sizing: crate::ui::modal::ModalSizing,
|
||||
pub kind: StyleKind,
|
||||
pub styles: &'b [String],
|
||||
pub selected: &'b str,
|
||||
|
|
@ -46,12 +47,14 @@ pub struct Scaffold<'a, 'b> {
|
|||
}
|
||||
|
||||
pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
||||
let width = s.sizing.width;
|
||||
let height = s.sizing.height;
|
||||
// ── Toolbar: New / Copy / Delete | … | Set Current / Apply ────────────
|
||||
let bar = row![
|
||||
tb_button("New", s.on_new, false),
|
||||
tb_button("Copy", s.on_copy, false),
|
||||
tb_button("Delete", s.on_delete, false),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(width),
|
||||
tb_button("Set Current", s.on_set_current, false),
|
||||
tb_button("Apply", s.on_apply, true),
|
||||
]
|
||||
|
|
@ -60,11 +63,11 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
|||
let toolbar = container(bar)
|
||||
.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]);
|
||||
|
||||
// ── Left: style list (single click selects, double click renames) ─────
|
||||
|
|
@ -89,9 +92,9 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
|||
let list_panel = container(
|
||||
column![
|
||||
text("Styles").size(10).style(muted_text_style),
|
||||
container(scrollable(column(rows).spacing(1)).height(Fill))
|
||||
container(scrollable(column(rows).spacing(1)).height(height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -102,15 +105,15 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.padding(2),
|
||||
]
|
||||
.spacing(4)
|
||||
.height(Fill),
|
||||
.height(height),
|
||||
)
|
||||
.width(170)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -118,17 +121,17 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
|
|||
left: 12.0,
|
||||
});
|
||||
|
||||
let body = row![list_panel, vsep(), s.editor].height(Fill);
|
||||
let body = row![list_panel, vsep(height), s.editor].height(height);
|
||||
|
||||
container(column![toolbar, hdivider(), body])
|
||||
container(column![toolbar, hdivider(width), body])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +148,7 @@ pub(crate) fn tb_button<'a>(label: &'a str, msg: Message, accent: bool) -> Eleme
|
|||
|
||||
fn btn_s(accent: bool) -> impl Fn(&Theme, Status) -> Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (accent, st) {
|
||||
(true, Status::Hovered | Status::Pressed) => palette.primary.strong,
|
||||
(false, Status::Hovered | Status::Pressed) => palette.background.strong,
|
||||
|
|
@ -167,30 +170,30 @@ fn btn_s(accent: bool) -> impl Fn(&Theme, Status) -> Style {
|
|||
|
||||
pub(crate) fn 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)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
pub(crate) fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn vsep<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(Fill))
|
||||
pub(crate) fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Column,
|
||||
button, checkbox, column, container, row, scrollable, text, text_input, Column,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (accent, st) {
|
||||
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -32,13 +32,13 @@ fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +63,7 @@ pub fn view_window<'a>(
|
|||
rename_active: Option<&'a str>,
|
||||
rename_buf: &'a str,
|
||||
color_open: Option<(u8, &'static str)>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Right: Details panel ──────────────────────────────────────────────
|
||||
let info_row = |label: &'static str, val: String| -> Element<'_, Message> {
|
||||
|
|
@ -140,7 +141,7 @@ pub fn view_window<'a>(
|
|||
.push(
|
||||
row![
|
||||
text(" Alignment:").size(11).style(muted_style).width(150),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
[
|
||||
"TopLeft",
|
||||
"TopCenter",
|
||||
|
|
@ -193,7 +194,7 @@ pub fn view_window<'a>(
|
|||
col = col.push(
|
||||
row![
|
||||
text(format!(" {bname}")).size(11).style(muted_style).width(28),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
["Single", "Double"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
|
|
@ -273,7 +274,7 @@ pub fn view_window<'a>(
|
|||
.align_y(iced::Center),
|
||||
row![
|
||||
text("Flow direction:").size(11).style(muted_style).width(160),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
["Down", "Up"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
|
|
@ -336,8 +337,8 @@ pub fn view_window<'a>(
|
|||
.spacing(6)
|
||||
.padding([12, 12]),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
} else {
|
||||
container(text("Select a style to view details.").size(11).style(muted_style))
|
||||
|
|
@ -345,9 +346,12 @@ pub fn view_window<'a>(
|
|||
.into()
|
||||
};
|
||||
|
||||
let right_panel = container(details).width(Fill).height(Fill);
|
||||
let right_panel = container(details)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||||
sizing,
|
||||
kind: crate::app::StyleKind::Table,
|
||||
styles: &styles,
|
||||
selected,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::app::StyleKind;
|
|||
use iced::widget::{
|
||||
button, canvas, checkbox, column, container, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{mouse, Background, Border, Element, Fill, Length, Point, Rectangle, Theme};
|
||||
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Theme};
|
||||
|
||||
/// View-model for the Text Style editor window.
|
||||
pub struct TextStyleView<'a> {
|
||||
|
|
@ -36,7 +36,7 @@ const BUILTIN_FONTS: &[&str] = &[
|
|||
|
||||
fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (active, st) {
|
||||
(true, _) => Some(palette.primary.strong),
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -53,7 +53,7 @@ fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -74,23 +74,23 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
fn vsep<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(Fill))
|
||||
fn vsep<'a>(height: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -162,7 +162,7 @@ impl canvas::Program<Message> for TextPreviewCanvas {
|
|||
};
|
||||
let stroke = canvas::Stroke {
|
||||
width: 1.4,
|
||||
style: canvas::Style::Solid(theme.extended_palette().background.base.text),
|
||||
style: canvas::Style::Solid(theme.palette().background.base.text),
|
||||
..Default::default()
|
||||
};
|
||||
for s in &strokes {
|
||||
|
|
@ -181,7 +181,10 @@ impl canvas::Program<Message> for TextPreviewCanvas {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
||||
pub fn view_window<'a>(
|
||||
v: TextStyleView<'a>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let TextStyleView {
|
||||
styles,
|
||||
selected,
|
||||
|
|
@ -207,7 +210,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
.on_press(Message::TextStyleFontPick(f.to_string()))
|
||||
.style(list_item(is_sel))
|
||||
.padding([3, 8])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -215,9 +218,9 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
let font_panel = container(
|
||||
column![
|
||||
text("Font File").size(10).style(muted_style),
|
||||
container(scrollable(column(font_items).spacing(1)).height(Fill))
|
||||
container(scrollable(column(font_items).spacing(1)).height(sizing.height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -228,8 +231,8 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2),
|
||||
text_input("font file…", font_buf)
|
||||
.on_input(|v| Message::TextStyleEdit {
|
||||
|
|
@ -238,13 +241,13 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
})
|
||||
.style(field_style)
|
||||
.size(11)
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(6)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(190)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding([12, 8]);
|
||||
|
||||
// Labeled numeric/text field row → TextStyleEdit { field, value }.
|
||||
|
|
@ -286,7 +289,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
oblique: oblique_buf.trim().parse::<f32>().unwrap_or(0.0).to_radians(),
|
||||
rotation: if upside_down { std::f32::consts::PI } else { 0.0 },
|
||||
})
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.height(Length::Fixed(56.0));
|
||||
|
||||
// ── Right: Properties ─────────────────────────────────────────────────
|
||||
|
|
@ -320,7 +323,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
text("Preview").size(10).style(muted_style),
|
||||
container(preview)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -332,13 +335,13 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
}
|
||||
})
|
||||
.padding(8)
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(10)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 12.0,
|
||||
|
|
@ -358,7 +361,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
})
|
||||
.style(list_item(is_sel))
|
||||
.padding([3, 8])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -366,9 +369,9 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
let ttf_panel = container(
|
||||
column![
|
||||
text("TrueType (system)").size(10).style(muted_style),
|
||||
container(scrollable(column(ttf_items).spacing(1)).height(Fill))
|
||||
container(scrollable(column(ttf_items).spacing(1)).height(sizing.height))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -379,8 +382,8 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2),
|
||||
text_input("TrueType font…", ttf_buf)
|
||||
.on_input(|v| Message::TextStyleEdit {
|
||||
|
|
@ -389,18 +392,26 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
|
|||
})
|
||||
.style(field_style)
|
||||
.size(11)
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(6)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(190)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding([12, 8]);
|
||||
|
||||
let editor = row![font_panel, vsep(), ttf_panel, vsep(), props_panel].height(Fill);
|
||||
let editor = row![
|
||||
font_panel,
|
||||
vsep(sizing.height),
|
||||
ttf_panel,
|
||||
vsep(sizing.height),
|
||||
props_panel
|
||||
]
|
||||
.height(sizing.height);
|
||||
|
||||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||||
sizing,
|
||||
kind: StyleKind::Text,
|
||||
styles: &styles,
|
||||
selected,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ fn info_row<'a>(label: &'static str, value: String) -> Element<'a, Message> {
|
|||
text(label)
|
||||
.size(11)
|
||||
.style(|theme: &Theme| 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)),
|
||||
})
|
||||
.width(100),
|
||||
text(value).size(11),
|
||||
|
|
@ -28,12 +28,12 @@ pub fn view_window<'a>() -> Element<'a, Message> {
|
|||
text("Open CAD Studio")
|
||||
.size(32)
|
||||
.style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().primary.base.color),
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
}),
|
||||
text("CAD application for Architecture & Engineering")
|
||||
.size(11)
|
||||
.style(|theme: &Theme| 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)),
|
||||
}),
|
||||
]
|
||||
.spacing(4)
|
||||
|
|
@ -84,7 +84,7 @@ pub fn view_window<'a>() -> Element<'a, Message> {
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Element, Fill, Length, Theme};
|
||||
use iced::{Background, Element, Length, Theme};
|
||||
|
||||
/// Which column of an alias row a text edit targets.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
|
@ -20,12 +20,15 @@ const GUTTER: f32 = 16.0;
|
|||
|
||||
fn 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)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the alias editor content. `rows` is the live working buffer.
|
||||
pub fn view_window(rows: &[(String, String)]) -> Element<'_, Message> {
|
||||
pub fn view_window(
|
||||
rows: &[(String, String)],
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'_, Message> {
|
||||
let title = text("Command Aliases").size(15);
|
||||
let hint = text(
|
||||
"Type an alias and the command it runs (e.g. L → LINE). \
|
||||
|
|
@ -42,7 +45,7 @@ pub fn view_window(rows: &[(String, String)]) -> Element<'_, Message> {
|
|||
let head = container(
|
||||
row![
|
||||
container(text("Alias").size(11).style(muted_style)).width(Length::Fixed(120.0)),
|
||||
container(text("Command").size(11).style(muted_style)).width(Fill),
|
||||
container(text("Command").size(11).style(muted_style)).width(sizing.width),
|
||||
Space::new().width(Length::Fixed(30.0)),
|
||||
]
|
||||
.spacing(8),
|
||||
|
|
@ -60,7 +63,7 @@ pub fn view_window(rows: &[(String, String)]) -> Element<'_, Message> {
|
|||
.on_input(move |v| Message::AliasEditorInput { idx, field: AliasField::Command, value: v })
|
||||
.size(13)
|
||||
.padding([3, 6])
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
let del = button(crate::ui::icons::themed_danger(crate::ui::icons::CLOSE, 12.0))
|
||||
.on_press(Message::AliasEditorRemove(idx))
|
||||
.padding([2, 6])
|
||||
|
|
@ -89,20 +92,20 @@ pub fn view_window(rows: &[(String, String)]) -> Element<'_, Message> {
|
|||
hint,
|
||||
Space::new().height(6),
|
||||
head,
|
||||
scrollable(container(list).padding(gutter)).height(Fill),
|
||||
scrollable(container(list).padding(gutter)).height(sizing.height),
|
||||
Space::new().height(6),
|
||||
row![add, Space::new().width(Fill), apply].align_y(iced::Center),
|
||||
row![add, Space::new().width(sizing.width), apply].align_y(iced::Center),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(Fill)
|
||||
.height(Fill),
|
||||
.width(sizing.width)
|
||||
.height(sizing.height),
|
||||
)
|
||||
.padding(12)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::app::Message;
|
|||
use acadrust::entities::{HorizontalAlignment, VerticalAlignment};
|
||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space,
|
||||
button, checkbox, column, container, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Length, Theme};
|
||||
|
||||
|
|
@ -135,12 +135,12 @@ pub fn color_from_label(label: &str) -> Option<AcadColor> {
|
|||
|
||||
fn 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 field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -156,13 +156,13 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
}
|
||||
|
||||
/// Horizontal 1px divider in the shared border colour (matches style windows).
|
||||
fn hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Length::Fill).height(1))
|
||||
.width(Length::Fill)
|
||||
fn hdivider<'a>(width: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -170,13 +170,18 @@ fn hdivider<'a>() -> Element<'a, Message> {
|
|||
}
|
||||
|
||||
/// One `label : widget` row with a fixed-width label column.
|
||||
fn field_row<'a>(label: &'a str, widget: Element<'a, Message>) -> Element<'a, Message> {
|
||||
fn field_row<'a>(
|
||||
label: &'a str,
|
||||
widget: Element<'a, Message>,
|
||||
width: Length,
|
||||
) -> Element<'a, Message> {
|
||||
row![
|
||||
container(text(label).size(12).style(muted_style)).width(LABEL_W),
|
||||
widget,
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
.width(width)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -185,6 +190,7 @@ fn edit_field<'a>(
|
|||
label: &'a str,
|
||||
value: &'a str,
|
||||
on_input: impl Fn(String) -> Message + 'a,
|
||||
width: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let ti = text_input("", value)
|
||||
.on_input(on_input)
|
||||
|
|
@ -192,8 +198,8 @@ fn edit_field<'a>(
|
|||
.style(field_style)
|
||||
.size(13)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill);
|
||||
field_row(label, ti.into())
|
||||
.width(width);
|
||||
field_row(label, ti.into(), width)
|
||||
}
|
||||
|
||||
/// A labelled pick_list of owned string options.
|
||||
|
|
@ -202,12 +208,13 @@ fn pick_field<'a>(
|
|||
options: Vec<String>,
|
||||
selected: Option<String>,
|
||||
on_select: impl Fn(String) -> Message + 'a,
|
||||
width: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let pl = pick_list(options, selected, on_select)
|
||||
let pl = crate::ui::pick_list(options, selected, on_select)
|
||||
.text_size(13)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill);
|
||||
field_row(label, pl.into())
|
||||
.width(width);
|
||||
field_row(label, pl.into(), width)
|
||||
}
|
||||
|
||||
fn tab_button<'a>(label: &'a str, this: AttrTab, active: AttrTab) -> Element<'a, Message> {
|
||||
|
|
@ -216,7 +223,7 @@ fn tab_button<'a>(label: &'a str, this: AttrTab, active: AttrTab) -> Element<'a,
|
|||
.padding([4, 12])
|
||||
.on_press(Message::AttrEditorTab(this))
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (is_active, status) {
|
||||
(true, _) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -250,7 +257,10 @@ pub fn view_window<'a>(
|
|||
layers: Vec<String>,
|
||||
linetypes: Vec<String>,
|
||||
styles: Vec<String>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let width = sizing.width;
|
||||
let height = sizing.height;
|
||||
// ── Top toolbar: block name on the left, Apply on the right ───────────
|
||||
// Mirrors the style-manager windows (actions left, primary action right).
|
||||
let apply = button(text("Apply").size(11))
|
||||
|
|
@ -260,18 +270,18 @@ pub fn view_window<'a>(
|
|||
let toolbar = container(
|
||||
row![
|
||||
text(format!("Block: {block}")).size(12).style(muted_style),
|
||||
Space::new().width(Length::Fill),
|
||||
Space::new().width(width),
|
||||
apply,
|
||||
]
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color
|
||||
theme.palette().background.weak.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Length::Fill)
|
||||
.width(width)
|
||||
.padding([5, 8]);
|
||||
|
||||
let tabs = row![
|
||||
|
|
@ -285,36 +295,49 @@ pub fn view_window<'a>(
|
|||
text("This block has no attributes.").size(13).style(muted_style).into()
|
||||
} else {
|
||||
match tab {
|
||||
AttrTab::Attribute => attribute_tab(rows, selected),
|
||||
AttrTab::TextOptions => text_options_tab(&rows[selected.min(rows.len() - 1)], styles),
|
||||
AttrTab::Attribute => attribute_tab(rows, selected, width, height),
|
||||
AttrTab::TextOptions => {
|
||||
text_options_tab(&rows[selected.min(rows.len() - 1)], styles, width, height)
|
||||
}
|
||||
AttrTab::Properties => {
|
||||
properties_tab(&rows[selected.min(rows.len() - 1)], layers, linetypes)
|
||||
properties_tab(
|
||||
&rows[selected.min(rows.len() - 1)],
|
||||
layers,
|
||||
linetypes,
|
||||
width,
|
||||
height,
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let content = container(column![tabs, body].spacing(8))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.padding(12);
|
||||
|
||||
container(column![toolbar, hdivider(), content])
|
||||
container(column![toolbar, hdivider(width), content])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Attribute tab: tag / prompt / value list with row-select, plus a value box.
|
||||
fn attribute_tab<'a>(rows: &'a [AttrRow], selected: usize) -> Element<'a, Message> {
|
||||
fn attribute_tab<'a>(
|
||||
rows: &'a [AttrRow],
|
||||
selected: usize,
|
||||
width: Length,
|
||||
height: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let head = row![
|
||||
container(text("Tag").size(11).style(muted_style)).width(130),
|
||||
container(text("Prompt").size(11).style(muted_style)).width(Length::Fill),
|
||||
container(text("Prompt").size(11).style(muted_style)).width(width),
|
||||
container(text("Value").size(11).style(muted_style)).width(140),
|
||||
]
|
||||
.spacing(6);
|
||||
|
|
@ -324,16 +347,16 @@ fn attribute_tab<'a>(rows: &'a [AttrRow], selected: usize) -> Element<'a, Messag
|
|||
let is_sel = idx == selected;
|
||||
let line = row![
|
||||
container(text(r.tag.as_str()).size(12)).width(130),
|
||||
container(text(r.prompt.as_str()).size(12).style(muted_style)).width(Length::Fill),
|
||||
container(text(r.prompt.as_str()).size(12).style(muted_style)).width(width),
|
||||
container(text(r.value.as_str()).size(12)).width(140),
|
||||
]
|
||||
.spacing(6);
|
||||
let btn = button(line)
|
||||
.on_press(Message::AttrEditorSelect(idx))
|
||||
.padding([3, 4])
|
||||
.width(Length::Fill)
|
||||
.width(width)
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let hovered = matches!(status, button::Status::Hovered);
|
||||
let pair = if is_sel {
|
||||
palette.primary.strong
|
||||
|
|
@ -359,20 +382,27 @@ fn attribute_tab<'a>(rows: &'a [AttrRow], selected: usize) -> Element<'a, Messag
|
|||
.style(field_style)
|
||||
.size(13)
|
||||
.padding([4, 6])
|
||||
.width(Length::Fill);
|
||||
.width(width);
|
||||
|
||||
column![
|
||||
head,
|
||||
scrollable(list).height(Length::Fill),
|
||||
scrollable(list).width(width).height(height),
|
||||
Space::new().height(8),
|
||||
field_row("Value:", value_box.into()),
|
||||
field_row("Value:", value_box.into(), width),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Text Options tab: the selected attribute's text formatting.
|
||||
fn text_options_tab<'a>(r: &'a AttrRow, styles: Vec<String>) -> Element<'a, Message> {
|
||||
fn text_options_tab<'a>(
|
||||
r: &'a AttrRow,
|
||||
styles: Vec<String>,
|
||||
width: Length,
|
||||
height: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let style_sel = if r.text_style.is_empty() {
|
||||
None
|
||||
} else {
|
||||
|
|
@ -384,14 +414,14 @@ fn text_options_tab<'a>(r: &'a AttrRow, styles: Vec<String>) -> Element<'a, Mess
|
|||
column![
|
||||
pick_field("Text Style", styles, style_sel, |s| {
|
||||
Message::AttrEditorTextStyle(s)
|
||||
}),
|
||||
}, width),
|
||||
pick_field("Justification", justify_opts, justify_sel, |s| {
|
||||
Message::AttrEditorJustify(s)
|
||||
}),
|
||||
edit_field("Height", &r.height, Message::AttrEditorHeight),
|
||||
edit_field("Rotation", &r.rotation, Message::AttrEditorRotation),
|
||||
edit_field("Width Factor", &r.width_factor, Message::AttrEditorWidth),
|
||||
edit_field("Oblique Angle", &r.oblique, Message::AttrEditorOblique),
|
||||
}, width),
|
||||
edit_field("Height", &r.height, Message::AttrEditorHeight, width),
|
||||
edit_field("Rotation", &r.rotation, Message::AttrEditorRotation, width),
|
||||
edit_field("Width Factor", &r.width_factor, Message::AttrEditorWidth, width),
|
||||
edit_field("Oblique Angle", &r.oblique, Message::AttrEditorOblique, width),
|
||||
field_row(
|
||||
"",
|
||||
checkbox(r.backwards)
|
||||
|
|
@ -400,6 +430,7 @@ fn text_options_tab<'a>(r: &'a AttrRow, styles: Vec<String>) -> Element<'a, Mess
|
|||
.size(15)
|
||||
.text_size(12)
|
||||
.into(),
|
||||
width,
|
||||
),
|
||||
field_row(
|
||||
"",
|
||||
|
|
@ -409,9 +440,12 @@ fn text_options_tab<'a>(r: &'a AttrRow, styles: Vec<String>) -> Element<'a, Mess
|
|||
.size(15)
|
||||
.text_size(12)
|
||||
.into(),
|
||||
width,
|
||||
),
|
||||
]
|
||||
.spacing(8)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -420,6 +454,8 @@ fn properties_tab<'a>(
|
|||
r: &'a AttrRow,
|
||||
layers: Vec<String>,
|
||||
linetypes: Vec<String>,
|
||||
width: Length,
|
||||
height: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let layer_sel = Some(r.layer.clone());
|
||||
let lt_sel = Some(if r.linetype.is_empty() {
|
||||
|
|
@ -439,21 +475,23 @@ fn properties_tab<'a>(
|
|||
|
||||
let lw_opts = lw_options();
|
||||
let lw_sel = LwItem(r.line_weight);
|
||||
let lw = pick_list(lw_opts, Some(lw_sel), |it: LwItem| {
|
||||
let lw = crate::ui::pick_list(lw_opts, Some(lw_sel), |it: LwItem| {
|
||||
Message::AttrEditorLineweight(it.0)
|
||||
})
|
||||
.text_size(13)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill);
|
||||
.width(width);
|
||||
|
||||
column![
|
||||
pick_field("Layer", layers, layer_sel, Message::AttrEditorLayer),
|
||||
pick_field("Linetype", linetypes, lt_sel, Message::AttrEditorLinetype),
|
||||
pick_field("Layer", layers, layer_sel, Message::AttrEditorLayer, width),
|
||||
pick_field("Linetype", linetypes, lt_sel, Message::AttrEditorLinetype, width),
|
||||
pick_field("Color", color_opts, color_sel, |s| {
|
||||
Message::AttrEditorColor(s)
|
||||
}),
|
||||
field_row("Lineweight", lw.into()),
|
||||
}, width),
|
||||
field_row("Lineweight", lw.into(), width),
|
||||
]
|
||||
.spacing(8)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::app::{LayerStateLayerFlag, LayerStateProperty, Message};
|
|||
use crate::ui::properties::{lw_options, LwItem};
|
||||
use acadrust::{LayerState, LayerStateMask};
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space,
|
||||
button, checkbox, column, container, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Length, Theme};
|
||||
use std::fmt;
|
||||
|
|
@ -39,7 +39,7 @@ fn muted(theme: &Theme) -> iced::widget::text::Style {
|
|||
iced::widget::text::Style {
|
||||
color: Some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
|
|
@ -68,13 +68,13 @@ fn list_style(selected: bool) -> impl Fn(&Theme, button::Status) -> button::Styl
|
|||
}
|
||||
}
|
||||
|
||||
fn divider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn divider<'a>(width: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color,
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -107,6 +107,7 @@ pub fn view_window<'a>(
|
|||
name: &'a str,
|
||||
description: &'a str,
|
||||
filter: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let selected_state = selected.and_then(|selected| {
|
||||
states
|
||||
|
|
@ -139,7 +140,7 @@ pub fn view_window<'a>(
|
|||
.on_press(Message::LayerStateManagerSelect(state.name.clone()))
|
||||
.style(list_style(is_selected))
|
||||
.padding([6, 9])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -165,7 +166,9 @@ pub fn view_window<'a>(
|
|||
let state_list: Element<'_, Message> = if rows.is_empty() {
|
||||
empty
|
||||
} else {
|
||||
scrollable(column(rows).spacing(2)).height(Fill).into()
|
||||
scrollable(column(rows).spacing(2))
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
};
|
||||
|
||||
let left = container(
|
||||
|
|
@ -175,12 +178,12 @@ pub fn view_window<'a>(
|
|||
.size(11)
|
||||
.padding([5, 8]),
|
||||
container(state_list)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(3)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
|
|
@ -188,10 +191,10 @@ pub fn view_window<'a>(
|
|||
}),
|
||||
]
|
||||
.spacing(8)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(280)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -261,13 +264,13 @@ pub fn view_window<'a>(
|
|||
.style(button_style(false))
|
||||
.padding([5, 12]),
|
||||
edit.padding([5, 12]),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
restore.padding([5, 12]),
|
||||
delete.padding([5, 12]),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
divider(),
|
||||
divider(sizing.width),
|
||||
text("Name").size(10).style(muted),
|
||||
text_input("Layer state name", name)
|
||||
.on_input(Message::LayerStateManagerName)
|
||||
|
|
@ -281,7 +284,7 @@ pub fn view_window<'a>(
|
|||
.padding([5, 8]),
|
||||
Space::new().height(8),
|
||||
details,
|
||||
Space::new().height(Fill),
|
||||
Space::new().height(sizing.height),
|
||||
text("Layer states are stored inside the drawing and remain available after reopening it.")
|
||||
.size(10)
|
||||
.style(muted),
|
||||
|
|
@ -296,15 +299,15 @@ pub fn view_window<'a>(
|
|||
.padding([6, 14]),
|
||||
]
|
||||
.spacing(7)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding([12, 12]);
|
||||
|
||||
container(row![left, right].height(Fill))
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
container(row![left, right].height(sizing.height))
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -380,10 +383,10 @@ fn editor_header<'a>() -> Element<'a, Message> {
|
|||
.padding([5, 8])
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weak.color,
|
||||
theme.palette().background.weak.color,
|
||||
)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
|
|
@ -429,13 +432,13 @@ fn editor_layer_row<'a>(
|
|||
54.0
|
||||
),
|
||||
container(color).width(Length::Fixed(135.0)),
|
||||
pick_list(linetypes, current_linetype, move |value| {
|
||||
crate::ui::pick_list(linetypes, current_linetype, move |value| {
|
||||
Message::LayerStateEditorLayerLinetype(index, value)
|
||||
})
|
||||
.text_size(11)
|
||||
.padding([3, 5])
|
||||
.width(Length::Fixed(150.0)),
|
||||
pick_list(lw_options(), current_lineweight, move |item: LwItem| {
|
||||
crate::ui::pick_list(lw_options(), current_lineweight, move |item: LwItem| {
|
||||
Message::LayerStateEditorLayerLineweight(index, item.0)
|
||||
})
|
||||
.text_size(11)
|
||||
|
|
@ -446,7 +449,7 @@ fn editor_layer_row<'a>(
|
|||
.size(11)
|
||||
.padding([3, 5])
|
||||
.width(Length::Fixed(135.0)),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
transparency_options(layer.transparency),
|
||||
Some(TransparencyItem(layer.transparency)),
|
||||
move |item| Message::LayerStateEditorLayerTransparency(index, item.0),
|
||||
|
|
@ -461,7 +464,7 @@ fn editor_layer_row<'a>(
|
|||
.padding([3, 8])
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: (index % 2 == 1).then_some(Background::Color(
|
||||
theme.extended_palette().background.weak.color,
|
||||
theme.palette().background.weak.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -474,6 +477,7 @@ pub fn view_editor<'a>(
|
|||
filter: &'a str,
|
||||
color_open: Option<usize>,
|
||||
linetypes: Vec<String>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let properties = [
|
||||
("On / Off", LayerStateProperty::On),
|
||||
|
|
@ -529,7 +533,7 @@ pub fn view_editor<'a>(
|
|||
.on_input(Message::LayerStateEditorDescription)
|
||||
.size(11)
|
||||
.padding([3, 6])
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
|
|
@ -537,9 +541,9 @@ pub fn view_editor<'a>(
|
|||
text(format!("{} saved layers", state.layers.len()))
|
||||
.size(10)
|
||||
.style(muted),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
text("Current layer").size(10).style(muted),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
layer_names,
|
||||
Some(state.current_layer.clone()),
|
||||
Message::LayerStateEditorCurrentLayer,
|
||||
|
|
@ -550,12 +554,12 @@ pub fn view_editor<'a>(
|
|||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
divider(),
|
||||
divider(sizing.width),
|
||||
text("Properties restored by this state").size(10).style(muted),
|
||||
mask_controls,
|
||||
row![
|
||||
text("Saved layer values").size(12),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
text_input("Search layers…", filter)
|
||||
.on_input(Message::LayerStateEditorFilter)
|
||||
.size(11)
|
||||
|
|
@ -564,14 +568,14 @@ pub fn view_editor<'a>(
|
|||
]
|
||||
.align_y(iced::Center),
|
||||
container(
|
||||
column![editor_header(), scrollable(rows).height(Fill)]
|
||||
column![editor_header(), scrollable(rows).height(sizing.height)]
|
||||
.spacing(0)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
color: theme.palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
|
|
@ -581,7 +585,7 @@ pub fn view_editor<'a>(
|
|||
text("Changes affect the saved state only; the drawing is unchanged until Restore.")
|
||||
.size(10)
|
||||
.style(muted),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
button(text("Cancel").size(11))
|
||||
.on_press(Message::LayerStateEditorCancel)
|
||||
.style(button_style(false))
|
||||
|
|
@ -595,10 +599,10 @@ pub fn view_editor<'a>(
|
|||
.align_y(iced::Center),
|
||||
]
|
||||
.spacing(8)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.padding(12)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub const LAYER_TABLE_SCROLL_ID: &str = "layer-manager-table-scroll";
|
|||
|
||||
fn 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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ fn table_input_style(
|
|||
theme: &Theme,
|
||||
status: iced::widget::text_input::Status,
|
||||
) -> iced::widget::text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
iced::widget::text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -308,11 +308,19 @@ impl LayerPanel {
|
|||
}
|
||||
|
||||
/// Render the layer panel as the full content of its own OS window.
|
||||
pub fn view_window(&self, name_col_w: f32) -> Element<'_, Message> {
|
||||
self.view_content(name_col_w)
|
||||
pub fn view_window(
|
||||
&self,
|
||||
name_col_w: f32,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'_, Message> {
|
||||
self.view_content(name_col_w, sizing)
|
||||
}
|
||||
|
||||
fn view_content(&self, name_col_w: f32) -> Element<'_, Message> {
|
||||
fn view_content(
|
||||
&self,
|
||||
name_col_w: f32,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'_, Message> {
|
||||
let has_sel = self.selected.is_some();
|
||||
let sel_is_zero = self
|
||||
.selected
|
||||
|
|
@ -335,7 +343,7 @@ impl LayerPanel {
|
|||
Message::LayerSetCurrent,
|
||||
has_sel,
|
||||
),
|
||||
iced::widget::Space::new().width(Fill),
|
||||
iced::widget::Space::new().width(sizing.width),
|
||||
// Search box: filters rows by name as the user types (#343).
|
||||
text_input("Search…", &self.filter)
|
||||
.on_input(Message::LayerManagerFilterChanged)
|
||||
|
|
@ -349,11 +357,11 @@ impl LayerPanel {
|
|||
)
|
||||
.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(sizing.width)
|
||||
.padding([4, 8]);
|
||||
|
||||
// ── Column header ─────────────────────────────────────────────────
|
||||
|
|
@ -367,7 +375,7 @@ impl LayerPanel {
|
|||
container(iced::widget::Space::new().width(2).height(14)).style(
|
||||
|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
@ -390,7 +398,7 @@ impl LayerPanel {
|
|||
),
|
||||
]
|
||||
.spacing(4)
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.align_y(iced::Center);
|
||||
|
||||
for vp in &self.vp_cols {
|
||||
|
|
@ -404,7 +412,7 @@ impl LayerPanel {
|
|||
|
||||
let col_header = container(header_row)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -416,7 +424,7 @@ impl LayerPanel {
|
|||
}
|
||||
})
|
||||
.padding([4, 8])
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
|
||||
// ── Layer rows ────────────────────────────────────────────────────
|
||||
let mut rows_col = column![].spacing(0);
|
||||
|
|
@ -457,18 +465,18 @@ impl LayerPanel {
|
|||
|
||||
let table = scrollable(rows_col)
|
||||
.id(iced::advanced::widget::Id::new(LAYER_TABLE_SCROLL_ID))
|
||||
.height(Fill);
|
||||
.height(sizing.height.min(240.0));
|
||||
|
||||
// ── Full-window frame ─────────────────────────────────────────────
|
||||
container(column![toolbar, col_header, table].spacing(0))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
@ -481,7 +489,7 @@ fn layer_cell_button_style(
|
|||
is_selected: bool,
|
||||
index: usize,
|
||||
) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let highlighted = matches!(status, button::Status::Hovered);
|
||||
let pair = if highlighted {
|
||||
palette.background.strong
|
||||
|
|
@ -500,7 +508,7 @@ fn layer_cell_button_style(
|
|||
}
|
||||
|
||||
fn layer_header_button_style(theme: &Theme, status: button::Status) -> button::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let highlighted = matches!(
|
||||
status,
|
||||
button::Status::Hovered | button::Status::Pressed
|
||||
|
|
@ -568,7 +576,7 @@ fn toolbar_btn<'a>(icon: &'static [u8], label: &'a str, msg: Message) -> Element
|
|||
)
|
||||
.on_press(msg)
|
||||
.style(|theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered | button::Status::Pressed => {
|
||||
palette.background.strong
|
||||
|
|
@ -608,7 +616,7 @@ fn toolbar_btn_cond<'a>(
|
|||
} else {
|
||||
text(label).size(11).style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(
|
||||
theme.extended_palette().background.base.text.scale_alpha(0.42)
|
||||
theme.palette().background.base.text.scale_alpha(0.42)
|
||||
),
|
||||
})
|
||||
},
|
||||
|
|
@ -617,7 +625,7 @@ fn toolbar_btn_cond<'a>(
|
|||
.align_y(iced::Center),
|
||||
)
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match status {
|
||||
button::Status::Hovered if enabled => palette.background.strong,
|
||||
_ => palette.background.weak,
|
||||
|
|
@ -657,7 +665,7 @@ fn name_tip<'a>(name: &'a str) -> Element<'a, Message> {
|
|||
right: 7.0,
|
||||
})
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.strong.color)),
|
||||
border: Border {
|
||||
|
|
@ -891,7 +899,7 @@ fn layer_row<'a>(
|
|||
mouse_area(
|
||||
container(row_content)
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if is_selected {
|
||||
palette.primary.weak
|
||||
} else if index % 2 == 0 {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
|
||||
use iced::{Background, Element, Fill, Theme};
|
||||
use iced::{Background, Element, Theme};
|
||||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,26 +36,26 @@ fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color,
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn vsep<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(Fill))
|
||||
fn vsep<'a>(height: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color,
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -67,6 +67,7 @@ pub fn view_window<'a>(
|
|||
selected: &'a str,
|
||||
rename_buf: &'a str,
|
||||
current: String,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let is_model = selected == "Model";
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ pub fn view_window<'a>(
|
|||
}
|
||||
})
|
||||
.padding([4, 10]),
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(sizing.width),
|
||||
button(
|
||||
row![
|
||||
crate::ui::icons::themed_arrow_left(9.0),
|
||||
|
|
@ -120,11 +121,11 @@ pub fn view_window<'a>(
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.padding([5, 8]);
|
||||
|
||||
// ── Left: Layout list ─────────────────────────────────────────────────
|
||||
|
|
@ -143,7 +144,7 @@ pub fn view_window<'a>(
|
|||
.on_press(Message::LayoutManagerSelect(name.clone()))
|
||||
.style(list_item(is_sel))
|
||||
.padding([5, 10])
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -151,17 +152,17 @@ pub fn view_window<'a>(
|
|||
let layout_list = container(
|
||||
column![
|
||||
text("Layouts").size(10).style(muted_style),
|
||||
container(scrollable(column(list_items).spacing(2)).height(Fill))
|
||||
container(scrollable(column(list_items).spacing(2)).height(sizing.height))
|
||||
.style(container::bordered_box)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.padding(2),
|
||||
]
|
||||
.spacing(4)
|
||||
.height(Fill),
|
||||
.height(sizing.height),
|
||||
)
|
||||
.width(220)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -221,19 +222,19 @@ pub fn view_window<'a>(
|
|||
]
|
||||
.spacing(8),
|
||||
)
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.padding([12, 12]);
|
||||
|
||||
let body = row![layout_list, vsep(), details].height(Fill);
|
||||
let body = row![layout_list, vsep(sizing.height), details].height(sizing.height);
|
||||
|
||||
container(column![toolbar, hdivider(), body].spacing(0))
|
||||
container(column![toolbar, hdivider(sizing.width), body].spacing(0))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().primary.base.color
|
||||
theme.palette().primary.base.color
|
||||
)),
|
||||
border: Border {
|
||||
radius: 3.0.into(),
|
||||
|
|
@ -85,7 +85,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
container(Space::new().width(Length::Fixed(BAR_TRACK_WIDTH)).height(Length::Fixed(BAR_TRACK_HEIGHT)))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.strong.color
|
||||
theme.palette().background.strong.color
|
||||
)),
|
||||
border: Border {
|
||||
radius: 3.0.into(),
|
||||
|
|
@ -110,7 +110,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
))
|
||||
.size(13)
|
||||
.style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.82)),
|
||||
color: Some(theme.palette().background.base.text.scale_alpha(0.82)),
|
||||
});
|
||||
|
||||
let phase_line = text(format!(
|
||||
|
|
@ -120,7 +120,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
))
|
||||
.size(12)
|
||||
.style(|theme: &Theme| iced::widget::text::Style {
|
||||
color: Some(theme.extended_palette().primary.base.color),
|
||||
color: Some(theme.palette().primary.base.color),
|
||||
});
|
||||
|
||||
let cancel_btn: Element<'_, Message> = button(text("Cancel").size(12))
|
||||
|
|
@ -138,7 +138,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
)
|
||||
.padding([18, 22])
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -154,7 +154,7 @@ pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Messag
|
|||
let backdrop: Element<'_, Message> = container(Space::new().width(Fill).height(Fill))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.strong.color.scale_alpha(0.72)
|
||||
theme.palette().background.strong.color.scale_alpha(0.72)
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use crate::app::config::UiThemeConfig;
|
||||
use crate::app::Message;
|
||||
use iced::widget::{
|
||||
button, column, container, pick_list, row, scrollable, text, text_input, Space,
|
||||
button, column, container, row, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
pub fn view_window<'a>(
|
||||
default_save_format: &'a str,
|
||||
ui_theme: &'a UiThemeConfig,
|
||||
theme_color_inputs: &'a [String; 6],
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let selected_format = crate::io::SAVE_FORMAT_OPTIONS
|
||||
.iter()
|
||||
|
|
@ -40,7 +41,7 @@ pub fn view_window<'a>(
|
|||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(color)),
|
||||
border: Border {
|
||||
color: theme.extended_palette().background.strong.color,
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
|
|
@ -69,12 +70,12 @@ pub fn view_window<'a>(
|
|||
Space::new().height(10),
|
||||
row![
|
||||
text("Default save format:").size(12).width(150),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
crate::io::SAVE_FORMAT_OPTIONS,
|
||||
selected_format,
|
||||
|format: &str| Message::DefaultSaveFormatChanged(format.to_string())
|
||||
)
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(12)
|
||||
.align_y(iced::Center),
|
||||
|
|
@ -82,18 +83,19 @@ pub fn view_window<'a>(
|
|||
text(
|
||||
"Used for the first save of a new drawing. Existing drawings keep their file type and version."
|
||||
)
|
||||
.size(11),
|
||||
.size(11)
|
||||
.width(sizing.width),
|
||||
Space::new().height(22),
|
||||
text("Theme").size(15),
|
||||
Space::new().height(10),
|
||||
row![
|
||||
text("Iced theme:").size(12).width(150),
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
theme_options,
|
||||
selected_theme,
|
||||
Message::OptionsThemeChanged,
|
||||
)
|
||||
.width(Fill),
|
||||
.width(sizing.width),
|
||||
]
|
||||
.spacing(12)
|
||||
.align_y(iced::Center),
|
||||
|
|
@ -101,25 +103,26 @@ pub fn view_window<'a>(
|
|||
text(
|
||||
"Changing a base colour switches to Custom. Iced generates every component shade from these six colours."
|
||||
)
|
||||
.size(11),
|
||||
.size(11)
|
||||
.width(sizing.width),
|
||||
Space::new().height(12),
|
||||
color_controls,
|
||||
]
|
||||
.spacing(0)
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
|
||||
let body = column![
|
||||
scrollable(content).height(Fill),
|
||||
scrollable(content).height(sizing.height),
|
||||
Space::new().height(12),
|
||||
row![Space::new().width(Fill), close],
|
||||
row![Space::new().width(sizing.width), close],
|
||||
]
|
||||
.width(Fill)
|
||||
.height(Fill);
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
container(body)
|
||||
.style(container::rounded_box)
|
||||
.padding([16, 18])
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
use crate::app::Message;
|
||||
use crate::io::paper_sizes::PaperSize;
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, mouse_area, pick_list, row, scrollable, text, text_input,
|
||||
button, checkbox, column, container, mouse_area, row, scrollable, text, text_input,
|
||||
Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Length, Theme};
|
||||
use iced::{Background, Border, Element, Fit, Length, Theme};
|
||||
|
||||
/// Sentinel entries in the printer dropdown (not real printer names).
|
||||
pub const OUT_DEFAULT: &str = "System default printer";
|
||||
|
|
@ -212,7 +212,7 @@ impl PlotDialogState {
|
|||
|
||||
fn btn(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||||
move |theme: &Theme, st| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match (accent, st) {
|
||||
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
|
||||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||||
|
|
@ -236,7 +236,7 @@ fn btn(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
|||
}
|
||||
|
||||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let border = match status {
|
||||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||||
_ => palette.background.neutral.color,
|
||||
|
|
@ -253,17 +253,17 @@ fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
|||
|
||||
fn 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 hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn hdivider<'a>(width: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -274,13 +274,13 @@ fn section_label<'a>(s: &'static str) -> Element<'a, Message> {
|
|||
text(s).size(11).style(muted_style).into()
|
||||
}
|
||||
|
||||
fn vsep<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(Fill))
|
||||
fn vsep<'a>(height: Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(1).height(height))
|
||||
.width(1)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color
|
||||
theme.palette().background.neutral.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -302,15 +302,15 @@ fn setup_row<'a>(
|
|||
.style(field_style)
|
||||
.size(11)
|
||||
.padding([4, 8])
|
||||
.width(Fill)
|
||||
.width(Fit)
|
||||
.into();
|
||||
}
|
||||
let is_sel = name == selected;
|
||||
let cell = container(text(name.to_string()).size(11))
|
||||
.padding([4, 8])
|
||||
.width(Fill)
|
||||
.width(Fit)
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: is_sel.then_some(Background::Color(palette.primary.strong.color)),
|
||||
text_color: is_sel.then_some(palette.primary.strong.text),
|
||||
|
|
@ -330,11 +330,12 @@ fn drop_row<'a>(
|
|||
options: Vec<String>,
|
||||
selected: Option<String>,
|
||||
ctor: fn(String) -> PlotDlgMsg,
|
||||
width: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let pl = pick_list(options, selected, move |s| Message::PlotDlg(ctor(s)))
|
||||
let pl = crate::ui::pick_list(options, selected, move |s| Message::PlotDlg(ctor(s)))
|
||||
.text_size(12)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill);
|
||||
.width(width);
|
||||
row![text(label).size(11).style(muted_style).width(92), pl]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
|
|
@ -375,7 +376,12 @@ fn strs(items: &[&str]) -> Vec<String> {
|
|||
items.iter().map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
||||
pub fn view_window(
|
||||
s: &PlotDialogState,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'_, Message> {
|
||||
let width = sizing.width;
|
||||
let height = sizing.height;
|
||||
// ── Toolbar: Cancel … Preview Print/Export ──────────────────────────
|
||||
let action = if s.to_file { "Export PDF" } else { "Print" };
|
||||
// `<none>` / `<previous>` are pseudo-entries; layout rows are `*name*`.
|
||||
|
|
@ -409,7 +415,7 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
let toolbar = container(
|
||||
row![
|
||||
left_bar,
|
||||
Space::new().width(Fill),
|
||||
Space::new().width(width),
|
||||
button(text("Set current").size(11))
|
||||
.on_press(Message::PlotDlg(PlotDlgMsg::SetCurrent))
|
||||
.style(btn(false))
|
||||
|
|
@ -429,11 +435,11 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
)
|
||||
.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, 10]);
|
||||
|
||||
// ── Printer dropdown: default + discovered printers + PDF sentinel ────
|
||||
|
|
@ -465,14 +471,14 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
.padding([6, 8])
|
||||
.into()
|
||||
} else {
|
||||
scrollable(column(rows).spacing(1)).height(Fill).into()
|
||||
scrollable(column(rows).spacing(1)).height(height).into()
|
||||
};
|
||||
let list_panel = container(
|
||||
column![
|
||||
text("Page setups").size(10).style(muted_style),
|
||||
container(list_body)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.weak.color)),
|
||||
border: Border {
|
||||
|
|
@ -483,15 +489,15 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
..Default::default()
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(Length::Fill)
|
||||
.height(height)
|
||||
.padding(2),
|
||||
]
|
||||
.spacing(4)
|
||||
.height(Fill),
|
||||
.height(height),
|
||||
)
|
||||
.width(160)
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.padding(iced::Padding {
|
||||
top: 12.0,
|
||||
right: 8.0,
|
||||
|
|
@ -507,37 +513,39 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
};
|
||||
let left = column![
|
||||
section_label("Printer / plotter"),
|
||||
drop_row("Output", printer_opts, printer_sel, PlotDlgMsg::Printer),
|
||||
drop_row("Output", printer_opts, printer_sel, PlotDlgMsg::Printer, width),
|
||||
field_row("Copies", &s.copies, PlotDlgMsg::Copies, 60),
|
||||
hdivider(),
|
||||
hdivider(width),
|
||||
section_label("Paper"),
|
||||
drop_row("Size", paper_opts, Some(s.paper.clone()), PlotDlgMsg::Paper),
|
||||
drop_row("Size", paper_opts, Some(s.paper.clone()), PlotDlgMsg::Paper, width),
|
||||
drop_row(
|
||||
"Orientation",
|
||||
strs(&["Portrait", "Landscape"]),
|
||||
Some(s.orientation.clone()),
|
||||
PlotDlgMsg::Orientation,
|
||||
width,
|
||||
),
|
||||
drop_row(
|
||||
"Rotation",
|
||||
strs(&["0°", "90°", "180°", "270°"]),
|
||||
Some(s.rotation.clone()),
|
||||
PlotDlgMsg::Rotation,
|
||||
width,
|
||||
),
|
||||
hdivider(),
|
||||
hdivider(width),
|
||||
section_label("Plot area"),
|
||||
row![
|
||||
container(
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
strs(&["Layout", "Extents", "Display", "Window"]),
|
||||
Some(s.area.clone()),
|
||||
move |v| Message::PlotDlg(PlotDlgMsg::Area(v)),
|
||||
)
|
||||
.text_size(12)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill)
|
||||
.width(width)
|
||||
)
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
button(text("Pick…").size(11))
|
||||
.on_press(Message::PlotDlg(PlotDlgMsg::PickWindow))
|
||||
.style(btn(false))
|
||||
|
|
@ -554,7 +562,7 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
check("Center the plot", s.center, PlotFlag::Center),
|
||||
]
|
||||
.spacing(9)
|
||||
.width(Fill);
|
||||
.width(width);
|
||||
|
||||
// ── Right column ─────────────────────────────────────────────────────
|
||||
let right = column![
|
||||
|
|
@ -564,14 +572,15 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
strs(&["Fit", "1:1", "1:2", "1:5", "1:10", "1:20", "1:50", "1:100", "2:1"]),
|
||||
Some(s.scale.clone()),
|
||||
PlotDlgMsg::Scale,
|
||||
width,
|
||||
),
|
||||
check("Scale lineweights", s.scale_lw, PlotFlag::ScaleLw),
|
||||
hdivider(),
|
||||
hdivider(width),
|
||||
section_label("Plot style table (pen assignments)"),
|
||||
row![
|
||||
container(text(style_label).size(12))
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: Some(Background::Color(palette.background.base.color)),
|
||||
border: Border {
|
||||
|
|
@ -583,7 +592,7 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
}
|
||||
})
|
||||
.padding([4, 8])
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
button(text("Load…").size(11))
|
||||
.on_press(Message::PlotDlg(PlotDlgMsg::LoadStyle))
|
||||
.style(btn(false))
|
||||
|
|
@ -595,20 +604,20 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
hdivider(),
|
||||
hdivider(width),
|
||||
section_label("Quality"),
|
||||
row![
|
||||
container(
|
||||
pick_list(
|
||||
crate::ui::pick_list(
|
||||
strs(&["Draft", "Normal", "High", "Maximum"]),
|
||||
Some(s.quality.clone()),
|
||||
move |v| Message::PlotDlg(PlotDlgMsg::Quality(v)),
|
||||
)
|
||||
.text_size(12)
|
||||
.padding([3, 6])
|
||||
.width(Length::Fill)
|
||||
.width(width)
|
||||
)
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
text("DPI").size(11).style(muted_style),
|
||||
text_input("", &s.dpi)
|
||||
.on_input(move |v| Message::PlotDlg(PlotDlgMsg::Dpi(v)))
|
||||
|
|
@ -623,8 +632,9 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
strs(&["As displayed", "Wireframe", "Hidden", "Rendered"]),
|
||||
Some(s.shade.clone()),
|
||||
PlotDlgMsg::Shade,
|
||||
width,
|
||||
),
|
||||
hdivider(),
|
||||
hdivider(width),
|
||||
section_label("Plot options"),
|
||||
row![
|
||||
column![
|
||||
|
|
@ -634,7 +644,7 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
check("Plot transparency", s.transparency, PlotFlag::Transparency),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
column![
|
||||
check("Paperspace last", s.paperspace_last, PlotFlag::PaperspaceLast),
|
||||
check("Hide paperspace", s.hide_paperspace, PlotFlag::HidePaperspace),
|
||||
|
|
@ -642,28 +652,30 @@ pub fn view_window(s: &PlotDialogState) -> Element<'_, Message> {
|
|||
check("Save to layout", s.save_layout, PlotFlag::SaveLayout),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
]
|
||||
.spacing(10),
|
||||
]
|
||||
.spacing(9)
|
||||
.width(Fill);
|
||||
.width(width);
|
||||
|
||||
let detail = scrollable(
|
||||
container(row![left, right].spacing(18).width(Fill)).padding(14),
|
||||
container(row![left, right].spacing(18).width(width)).padding(14),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill);
|
||||
let body = row![list_panel, vsep(), detail].height(Fill);
|
||||
.width(width)
|
||||
.height(height);
|
||||
let body = row![list_panel, vsep(height), detail]
|
||||
.width(width)
|
||||
.height(height);
|
||||
|
||||
container(column![toolbar, hdivider(), body].spacing(0))
|
||||
container(column![toolbar, hdivider(width), body].spacing(0))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color
|
||||
theme.palette().background.base.color
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
use crate::app::Message;
|
||||
use crate::plugin::external::{ExternalPlugin, RegistryEntry};
|
||||
use iced::widget::{
|
||||
button, column, container, markdown, pick_list, row, rule, scrollable, text, text_input, Space,
|
||||
button, column, container, markdown, row, rule, scrollable, text, text_input, Space,
|
||||
};
|
||||
use iced::{Background, Border, Element, Fill, Length, Theme};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
|
@ -48,13 +48,13 @@ inventory::submit!(crate::command::CommandRegistration {
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ fn badge<'a>(label: String) -> Element<'a, Message> {
|
|||
container(text(label).size(11))
|
||||
.padding([2, 8])
|
||||
.style(|theme: &Theme| {
|
||||
let pair = theme.extended_palette().primary.weak;
|
||||
let pair = theme.palette().primary.weak;
|
||||
container::Style {
|
||||
background: Some(Background::Color(pair.color)),
|
||||
text_color: Some(pair.text),
|
||||
|
|
@ -105,7 +105,7 @@ fn status_badge<'a>(label: &str, kind: StatusKind) -> Element<'a, Message> {
|
|||
container(text(label.to_string()).size(11))
|
||||
.padding([2, 8])
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = match kind {
|
||||
StatusKind::Muted => palette.background.weak,
|
||||
StatusKind::Success => palette.success.weak,
|
||||
|
|
@ -126,7 +126,7 @@ fn status_badge<'a>(label: &str, kind: StatusKind) -> Element<'a, Message> {
|
|||
}
|
||||
|
||||
fn card_style(theme: &Theme, selected: bool) -> container::Style {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
container::Style {
|
||||
background: selected
|
||||
.then(|| Background::Color(palette.primary.weak.color.scale_alpha(0.18))),
|
||||
|
|
@ -325,7 +325,7 @@ fn install_controls<'a>(
|
|||
text("no releases").size(11).style(muted_style).into()
|
||||
} else {
|
||||
let r = repo_s.clone();
|
||||
pick_list(tags, selected, move |tag| {
|
||||
crate::ui::pick_list(tags, selected, move |tag| {
|
||||
Message::PluginReleaseSelect(r.clone(), tag)
|
||||
})
|
||||
.text_size(12)
|
||||
|
|
@ -490,7 +490,7 @@ fn registry_notice<'a>(m: &MarketView) -> Option<Element<'a, Message>> {
|
|||
container(body.padding([10, 12]))
|
||||
.width(Fill)
|
||||
.style(|theme: &Theme| {
|
||||
let pair = theme.extended_palette().warning.weak;
|
||||
let pair = theme.palette().warning.weak;
|
||||
container::Style {
|
||||
background: Some(Background::Color(pair.color.scale_alpha(0.16))),
|
||||
border: Border {
|
||||
|
|
@ -638,7 +638,12 @@ fn resolve_readme_link(repo: &str, uri: &str) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Message> {
|
||||
fn readme_panel<'a>(
|
||||
market: &MarketView<'a>,
|
||||
theme: &Theme,
|
||||
width: Length,
|
||||
height: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let Some(repo) = market.selected_repo else {
|
||||
return container(
|
||||
column![
|
||||
|
|
@ -649,9 +654,10 @@ fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Messa
|
|||
]
|
||||
.spacing(8),
|
||||
)
|
||||
.center(Fill)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.center_x(width)
|
||||
.center_y(height)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.style(container::bordered_box)
|
||||
.into();
|
||||
};
|
||||
|
|
@ -667,7 +673,7 @@ fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Messa
|
|||
text(repo.to_string()).size(11).style(primary_style),
|
||||
]
|
||||
.spacing(3)
|
||||
.width(Fill),
|
||||
.width(width),
|
||||
pill_button(
|
||||
"View on GitHub",
|
||||
Message::OpenUrl(format!("https://github.com/{repo}")),
|
||||
|
|
@ -686,9 +692,10 @@ fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Messa
|
|||
]
|
||||
.spacing(6),
|
||||
)
|
||||
.center(Fill)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.center_x(width)
|
||||
.center_y(height)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
} else {
|
||||
match market.readmes.get(repo) {
|
||||
|
|
@ -715,18 +722,20 @@ fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Messa
|
|||
]
|
||||
.spacing(6),
|
||||
)
|
||||
.center(Fill)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.center_x(width)
|
||||
.center_y(height)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into(),
|
||||
None => container(
|
||||
text("Select the plugin again to load its README.")
|
||||
.size(12)
|
||||
.style(muted_style),
|
||||
)
|
||||
.center(Fill)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.center_x(width)
|
||||
.center_y(height)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into(),
|
||||
}
|
||||
};
|
||||
|
|
@ -738,18 +747,18 @@ fn readme_panel<'a>(market: &MarketView<'a>, theme: &Theme) -> Element<'a, Messa
|
|||
left: 0.0,
|
||||
};
|
||||
let readme = scrollable(container(content).padding(gutter))
|
||||
.height(Fill)
|
||||
.width(Fill);
|
||||
.height(height)
|
||||
.width(width);
|
||||
|
||||
container(
|
||||
column![header, rule::horizontal(1), readme]
|
||||
.spacing(10)
|
||||
.padding([12, 14])
|
||||
.width(Fill)
|
||||
.height(Fill),
|
||||
.width(width)
|
||||
.height(height),
|
||||
)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.style(container::bordered_box)
|
||||
.into()
|
||||
}
|
||||
|
|
@ -760,7 +769,10 @@ pub fn view_window<'a>(
|
|||
loaded: &FxHashSet<String>,
|
||||
market: MarketView<'a>,
|
||||
theme: &'a Theme,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let width = sizing.width;
|
||||
let height = sizing.height;
|
||||
let title = text("Plugins").size(20);
|
||||
let subtitle = text("Browse, install, and manage add-ons. Select one to view its README.")
|
||||
.size(12)
|
||||
|
|
@ -813,40 +825,43 @@ pub fn view_window<'a>(
|
|||
left: 0.0,
|
||||
};
|
||||
let catalog = scrollable(container(list.width(Fill)).padding(gutter))
|
||||
.height(Fill)
|
||||
.height(height)
|
||||
.width(Fill);
|
||||
let search = text_input("Search plugins…", market.search)
|
||||
.on_input(Message::PluginSearchInput)
|
||||
.size(13)
|
||||
.padding([7, 10])
|
||||
.width(Fill);
|
||||
let catalog_pane = column![search, catalog].spacing(10).width(Fill).height(Fill);
|
||||
let details = readme_panel(&market, theme);
|
||||
let catalog_pane = column![search, catalog]
|
||||
.spacing(10)
|
||||
.width(Fill)
|
||||
.height(height);
|
||||
let details = readme_panel(&market, theme, width, height);
|
||||
let body = row![
|
||||
container(catalog_pane)
|
||||
.width(Length::Fixed(410.0))
|
||||
.height(Fill),
|
||||
.height(height),
|
||||
details,
|
||||
]
|
||||
.spacing(14)
|
||||
.height(Fill)
|
||||
.width(Fill);
|
||||
.height(height)
|
||||
.width(width);
|
||||
|
||||
container(
|
||||
column![title, subtitle, Space::new().height(12), body]
|
||||
.spacing(4)
|
||||
.padding(18)
|
||||
.width(Fill)
|
||||
.height(Fill),
|
||||
.width(width)
|
||||
.height(height),
|
||||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
@ -855,28 +870,58 @@ pub fn view_window<'a>(
|
|||
pub fn view_web_notice<'a>() -> Element<'a, Message> {
|
||||
let download = button(text("Download desktop app").size(13))
|
||||
.on_press(Message::OpenUrl(DESKTOP_DOWNLOAD_URL.to_string()))
|
||||
.padding([8, 16])
|
||||
.style(button::primary);
|
||||
.padding([9, 18])
|
||||
.style(|theme: &Theme, status| {
|
||||
let mut style = button::primary(theme, status);
|
||||
style.text_color = iced::Color::WHITE;
|
||||
style
|
||||
});
|
||||
|
||||
container(
|
||||
let icon = container(crate::ui::icons::themed_primary(
|
||||
crate::ui::icons::GEAR,
|
||||
26.0,
|
||||
))
|
||||
.center(Length::Fixed(44.0))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().primary.weak.color,
|
||||
)),
|
||||
border: Border {
|
||||
radius: 12.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let notice = container(
|
||||
column![
|
||||
text("Plugins require the desktop app").size(20),
|
||||
icon,
|
||||
text("Plugins are available in the desktop app")
|
||||
.size(20)
|
||||
.width(Length::Fit)
|
||||
.align_x(iced::alignment::Horizontal::Center),
|
||||
text(
|
||||
"Open CAD Studio plugins are native packages and cannot run inside a browser. \
|
||||
Install the desktop app to browse, install, and use plugins.",
|
||||
Download the desktop app to browse, install, and use plugins.",
|
||||
)
|
||||
.size(13)
|
||||
.width(Length::Fit)
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.style(muted_style),
|
||||
Space::new().height(8),
|
||||
Space::new().height(4),
|
||||
download,
|
||||
]
|
||||
.spacing(8)
|
||||
.padding(24)
|
||||
.width(Fill),
|
||||
.spacing(10)
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.width(Length::Fit),
|
||||
)
|
||||
.center(Fill)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(Length::Fit.max(380.0));
|
||||
|
||||
container(notice)
|
||||
.center_x(Length::Fit)
|
||||
.padding([16, 20])
|
||||
.width(Length::Fit)
|
||||
.height(Length::Fit)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Element, Fill, Theme};
|
||||
use iced::{Background, Element, Theme};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Display name of the primary accelerator modifier on this platform.
|
||||
|
|
@ -16,23 +16,23 @@ const MOD: &str = "Ctrl";
|
|||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
fn hdivider<'a>() -> Element<'a, Message> {
|
||||
container(Space::new().width(Fill).height(1))
|
||||
.width(Fill)
|
||||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||||
container(Space::new().width(width).height(1))
|
||||
.width(width)
|
||||
.height(1)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.neutral.color,
|
||||
theme.palette().background.neutral.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
@ -70,6 +70,7 @@ fn section<'a>(title: impl Into<Cow<'static, str>>) -> Element<'a, Message> {
|
|||
|
||||
pub fn view_window<'a>(
|
||||
overrides: &'a rustc_hash::FxHashMap<String, String>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
// ── Toolbar ───────────────────────────────────────────────────────────
|
||||
let toolbar = container(
|
||||
|
|
@ -82,11 +83,11 @@ pub fn view_window<'a>(
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
theme.palette().background.weakest.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.padding([5, 10]);
|
||||
|
||||
// ── Shortcut entries ──────────────────────────────────────────────────
|
||||
|
|
@ -152,8 +153,8 @@ pub fn view_window<'a>(
|
|||
|
||||
// ── Section headers styled separately ────────────────────────────────
|
||||
let content = scrollable(column(rows).spacing(3).padding([12, 16]))
|
||||
.width(Fill)
|
||||
.height(Fill);
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
// ── Header row with accent ────────────────────────────────────────────
|
||||
let header = container(
|
||||
|
|
@ -166,20 +167,29 @@ pub fn view_window<'a>(
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().primary.weak.color,
|
||||
theme.palette().primary.weak.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
|
||||
container(column![toolbar, hdivider(), header, hdivider(), content].spacing(0))
|
||||
container(
|
||||
column![
|
||||
toolbar,
|
||||
hdivider(sizing.width),
|
||||
header,
|
||||
hdivider(sizing.width),
|
||||
content
|
||||
]
|
||||
.spacing(0),
|
||||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,28 @@
|
|||
use crate::app::Message;
|
||||
use iced::widget::{button, column, container, row, scrollable, text, Space};
|
||||
use iced::{Background, Border, Element, Fill, Theme};
|
||||
use iced::{Background, Border, Element, Theme};
|
||||
|
||||
fn 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 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),
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders one of the two "Installed" / "Latest" cards. The `highlight`
|
||||
/// flag tints the border + label with the accent colour, making the new
|
||||
/// version the visual anchor of the row.
|
||||
fn version_card<'a>(label: &'static str, value: String, highlight: bool) -> Element<'a, Message> {
|
||||
fn version_card<'a>(
|
||||
label: &'static str,
|
||||
value: String,
|
||||
highlight: bool,
|
||||
width: iced::Length,
|
||||
) -> Element<'a, Message> {
|
||||
container(
|
||||
column![
|
||||
text(label)
|
||||
|
|
@ -32,7 +37,7 @@ fn version_card<'a>(label: &'static str, value: String, highlight: bool) -> Elem
|
|||
.spacing(4)
|
||||
.align_x(iced::Center),
|
||||
)
|
||||
.width(Fill)
|
||||
.width(width)
|
||||
.padding(iced::Padding {
|
||||
top: 14.0,
|
||||
right: 12.0,
|
||||
|
|
@ -41,7 +46,7 @@ fn version_card<'a>(label: &'static str, value: String, highlight: bool) -> Elem
|
|||
})
|
||||
.align_x(iced::Center)
|
||||
.style(move |theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
let palette = theme.palette();
|
||||
let pair = if highlight {
|
||||
palette.primary.weak
|
||||
} else {
|
||||
|
|
@ -120,7 +125,11 @@ fn strip_inline_md(s: &str) -> String {
|
|||
out
|
||||
}
|
||||
|
||||
pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
||||
pub fn view_window<'a>(
|
||||
latest: &'a str,
|
||||
body: &'a str,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let header = container(
|
||||
column![
|
||||
text("New Release Available").size(20).style(primary_style),
|
||||
|
|
@ -131,7 +140,7 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
|||
.spacing(4)
|
||||
.align_x(iced::Center),
|
||||
)
|
||||
.width(Fill)
|
||||
.width(sizing.width)
|
||||
.padding(iced::Padding {
|
||||
top: 14.0,
|
||||
right: 0.0,
|
||||
|
|
@ -147,20 +156,21 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
|||
"Installed",
|
||||
format!("v{}", env!("CARGO_PKG_VERSION")),
|
||||
false,
|
||||
sizing.width,
|
||||
);
|
||||
let latest_card = version_card("Latest", format!("v{}", latest), true);
|
||||
let latest_card = version_card("Latest", format!("v{}", latest), true, sizing.width);
|
||||
let arrow = container(crate::ui::icons::themed_secondary(
|
||||
crate::ui::icons::ARROW_LONG_RIGHT,
|
||||
20.0,
|
||||
))
|
||||
.width(iced::Length::Fixed(32.0))
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.align_x(iced::Center)
|
||||
.align_y(iced::Center);
|
||||
let info_block = row![installed, arrow, latest_card]
|
||||
.spacing(0)
|
||||
.align_y(iced::Center)
|
||||
.width(Fill);
|
||||
.width(sizing.width);
|
||||
|
||||
let later_btn = button(text("Later").size(11))
|
||||
.on_press(Message::UpdateNoticeClose)
|
||||
|
|
@ -172,7 +182,7 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
|||
.style(button::primary)
|
||||
.padding([6, 16]);
|
||||
|
||||
let footer = row![Space::new().width(Fill), later_btn, open_btn]
|
||||
let footer = row![Space::new().width(sizing.width), later_btn, open_btn]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
.padding(iced::Padding {
|
||||
|
|
@ -203,27 +213,26 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
|||
for line in body.lines() {
|
||||
col = col.push(render_notes_line(line));
|
||||
}
|
||||
scrollable(container(col).padding([10, 14])).height(Fill).into()
|
||||
scrollable(container(col).padding([10, 14]))
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
};
|
||||
|
||||
let notes_block = container(notes_body)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.style(container::bordered_box);
|
||||
|
||||
// Wrap notes_block in a Fill-height container outside the column so it
|
||||
// greedily claims every pixel left over after the fixed-height rows
|
||||
// (header, version cards, heading, footer). Without this iced lets the
|
||||
// notes panel shrink to its content height, leaving a gap above the
|
||||
// footer.
|
||||
// Keep the notes panel content-sized. The outer modal supplies the maximum
|
||||
// height, so long release notes scroll instead of stretching the dialog.
|
||||
let notes_fill = container(notes_block)
|
||||
.width(Fill)
|
||||
.height(Fill);
|
||||
.width(sizing.width)
|
||||
.height(sizing.height);
|
||||
|
||||
container(
|
||||
column![header, info_block, notes_heading, notes_fill, footer]
|
||||
.spacing(0)
|
||||
.height(Fill)
|
||||
.height(sizing.height)
|
||||
.padding(iced::Padding {
|
||||
top: 0.0,
|
||||
right: 20.0,
|
||||
|
|
@ -233,11 +242,11 @@ pub fn view_window<'a>(latest: &'a str, body: &'a str) -> Element<'a, Message> {
|
|||
)
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
theme.palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.width(sizing.width)
|
||||
.height(sizing.height)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use rustc_hash::FxHashMap;
|
|||
|
||||
use iced::advanced::layout::{self, Layout};
|
||||
use iced::advanced::widget::{self, tree, Widget};
|
||||
use iced::advanced::{mouse, overlay, renderer, Clipboard, Renderer as _, Shell};
|
||||
use iced::advanced::{mouse, overlay, renderer, Renderer as _, Shell};
|
||||
use iced::{
|
||||
Background, Border, Element, Event, Length, Point, Rectangle, Renderer, Shadow, Size,
|
||||
Theme, Vector,
|
||||
|
|
@ -121,13 +121,9 @@ impl<'a> WrapBar<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for WrapBar<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
self.refs().iter().map(|e| widget::Tree::new(*e)).collect()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
let refs: Vec<_> = self.refs().iter().map(|e| e.as_widget()).collect();
|
||||
tree.diff_children(&refs);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
let mut refs = self.refs_mut();
|
||||
tree.diff_children(&mut refs);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -300,7 +296,6 @@ impl<'a> Widget<Message, Theme, Renderer> for WrapBar<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -316,7 +311,6 @@ impl<'a> Widget<Message, Theme, Renderer> for WrapBar<'a> {
|
|||
child_layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -529,13 +523,8 @@ impl<'a> WrapFlow<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for WrapFlow<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
self.items.iter().map(widget::Tree::new).collect()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
let refs: Vec<_> = self.items.iter().map(|e| e.as_widget()).collect();
|
||||
tree.diff_children(&refs);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&mut self.items);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -633,7 +622,6 @@ impl<'a> Widget<Message, Theme, Renderer> for WrapFlow<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -649,7 +637,6 @@ impl<'a> Widget<Message, Theme, Renderer> for WrapFlow<'a> {
|
|||
child_layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -789,13 +776,8 @@ impl<'a> DensitySwap<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
self.variants.iter().map(widget::Tree::new).collect()
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
let refs: Vec<_> = self.variants.iter().map(|e| e.as_widget()).collect();
|
||||
tree.diff_children(&refs);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&mut self.variants);
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
|
|
@ -847,7 +829,6 @@ impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -859,7 +840,6 @@ impl<'a> Widget<Message, Theme, Renderer> for DensitySwap<'a> {
|
|||
child_layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -980,22 +960,14 @@ impl<'a> PosReport<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget<Message, Theme, Renderer> for PosReport<'a> {
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
vec![widget::Tree::new(&self.child)]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&[self.child.as_widget()]);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(std::slice::from_mut(&mut self.child));
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
self.child.as_widget().size()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Size<Length> {
|
||||
self.child.as_widget().size_hint()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
|
|
@ -1014,7 +986,6 @@ impl<'a> Widget<Message, Theme, Renderer> for PosReport<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -1024,7 +995,6 @@ impl<'a> Widget<Message, Theme, Renderer> for PosReport<'a> {
|
|||
layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -1211,22 +1181,14 @@ impl<'a> Widget<Message, Theme, Renderer> for ReorderTab<'a> {
|
|||
tree::State::new(ReorderState::default())
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
vec![widget::Tree::new(&self.child)]
|
||||
}
|
||||
|
||||
fn diff(&self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(&[self.child.as_widget()]);
|
||||
fn diff(&mut self, tree: &mut widget::Tree) {
|
||||
tree.diff_children(std::slice::from_mut(&mut self.child));
|
||||
}
|
||||
|
||||
fn size(&self) -> Size<Length> {
|
||||
self.child.as_widget().size()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Size<Length> {
|
||||
self.child.as_widget().size_hint()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
tree: &mut widget::Tree,
|
||||
|
|
@ -1245,7 +1207,6 @@ impl<'a> Widget<Message, Theme, Renderer> for ReorderTab<'a> {
|
|||
layout: Layout<'_>,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
|
|
@ -1295,7 +1256,6 @@ impl<'a> Widget<Message, Theme, Renderer> for ReorderTab<'a> {
|
|||
layout,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
viewport,
|
||||
);
|
||||
|
|
@ -1374,7 +1334,7 @@ impl<'a> Widget<Message, Theme, Renderer> for ReorderTab<'a> {
|
|||
shadow: Shadow::default(),
|
||||
snap: true,
|
||||
},
|
||||
Background::Color(theme.extended_palette().primary.base.color),
|
||||
Background::Color(theme.palette().primary.base.color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue