fix(ui): make modal layouts intrinsic

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

No files matched your search

+18 -17
View File
@@ -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()
}
+22 -20
View File
@@ -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,
+18 -12
View File
@@ -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,
+8 -4
View File
@@ -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,
+33 -32
View File
@@ -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()
}
+19 -8
View File
@@ -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()
}
+24 -23
View File
@@ -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()
}
+1 -1
View File
@@ -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),
+28 -25
View File
@@ -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()
})
+15 -11
View File
@@ -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,
+45 -34
View File
@@ -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,