feat(ui): add configurable Iced themes

This commit is contained in:
Hakan Seven committed 2026-07-28 09:33:12 +03:00
1 parent 73545520c8
commit 4bf14baea4
52 files changed
+3063 -5670

No files matched your search

+22 -28
View File
@@ -7,16 +7,9 @@
//! the style / scale managers' frame so it looks consistent.
use crate::app::Message;
use crate::ui::style::style_manager::{hdivider, tb_button, BG, BORDER, DIM, LIST, TB, TEXT};
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, Color, Element, Fill, Theme};
const MEMBER_CHECK: Color = Color {
r: 0.30,
g: 0.82,
b: 0.36,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, 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.
@@ -26,17 +19,17 @@ pub fn view_window(
) -> Element<'static, Message> {
let toolbar = container(
row![
text(format!("Object: {object_label}"))
.size(11)
.color(TEXT),
text(format!("Object: {object_label}")).size(11),
Space::new().width(Fill),
tb_button("Close", Message::CloseModal, true),
]
.spacing(4)
.align_y(iced::Center),
)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(TB)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color
)),
..Default::default()
})
.width(Fill)
@@ -45,21 +38,17 @@ pub fn view_window(
let rows: Vec<Element<'_, Message>> = scales
.iter()
.map(|(name, ratio, member)| {
let check = crate::ui::icons::check_cell(*member, MEMBER_CHECK);
let check = crate::ui::icons::themed_check_cell(*member);
let label = row![
check,
text(name.clone()).size(11).color(TEXT).width(Fill),
text(ratio.clone()).size(10).color(DIM),
text(name.clone()).size(11).width(Fill),
text(ratio.clone()).size(10).style(muted_text_style),
]
.spacing(4)
.align_y(iced::Center);
let cell = container(label)
.padding([4, 8])
.width(Fill)
.style(move |_: &Theme| container::Style {
text_color: Some(TEXT),
..Default::default()
});
.width(Fill);
mouse_area(cell)
.on_press(Message::AnnoObjectScaleToggle(name.clone()))
.into()
@@ -67,14 +56,17 @@ pub fn view_window(
.collect();
let list = container(scrollable(column(rows).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
}
})
.width(Fill)
.height(Fill)
@@ -84,7 +76,7 @@ pub fn view_window(
column![
text("Click a scale to add or remove the object's representation for it.")
.size(10)
.color(DIM),
.style(muted_text_style),
list,
]
.spacing(6)
@@ -95,8 +87,10 @@ pub fn view_window(
.padding(12);
container(column![toolbar, hdivider(), body])
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BG)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
)),
..Default::default()
})
.width(Fill)
+54 -76
View File
@@ -4,44 +4,7 @@ use crate::app::{ColorPickTarget, DsField, Message};
use iced::widget::{
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
const ACTIVE: Color = Color {
r: 0.20,
g: 0.40,
b: 0.70,
a: 1.0,
};
const FIELD: Color = Color {
r: 0.10,
g: 0.10,
b: 0.10,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, Theme};
/// All DimStyle field values needed by the view.
pub struct DimStyleValues<'a> {
@@ -131,44 +94,57 @@ pub struct DimStyleValues<'a> {
}
fn tab_btn_style(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (active, st) {
(true, _) => ACTIVE,
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.28,
g: 0.28,
b: 0.28,
a: 1.0,
},
_ => Color {
r: 0.20,
g: 0.20,
b: 0.20,
a: 1.0,
},
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (active, st) {
(true, _) => palette.primary.strong,
(false, button::Status::Hovered | button::Status::Pressed) => {
palette.background.strong
}
_ => palette.background.weak,
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
}
}
}
fn field_style(_: &Theme, _: text_input::Status) -> text_input::Style {
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.extended_palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(FIELD),
background: Background::Color(palette.background.base.color),
border: Border {
color: BORDER,
color: border,
width: 1.0,
radius: 3.0.into(),
},
icon: TEXT,
placeholder: DIM,
value: TEXT,
selection: ACCENT,
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
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)),
}
}
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().primary.base.color),
}
}
@@ -176,8 +152,10 @@ fn hdivider<'a>() -> Element<'a, Message> {
container(Space::new().width(Fill).height(1))
.width(Fill)
.height(1)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
@@ -221,7 +199,7 @@ pub fn view_window<'a>(
]
.spacing(2);
let lbl = |s: &'static str| text(s).size(11).color(DIM).width(180);
let lbl = |s: &'static str| text(s).size(11).style(muted_style).width(180);
let mk_field = |fld: DsField, val: &'a str| -> Element<'a, Message> {
text_input("", val)
@@ -338,7 +316,7 @@ pub fn view_window<'a>(
let tab_content: Element<'_, Message> = match tab {
0 => column![
text("Dimension Line").size(11).color(ACCENT),
text("Dimension Line").size(11).style(primary_style),
row![
lbl("Extension (DIMDLE)"),
mk_field(DsField::Dimdle, vals.dimdle)
@@ -359,7 +337,7 @@ pub fn view_window<'a>(
.align_y(iced::Center),
chk("Suppress 1st line (DIMSD1)", vals.dimsd1, DsField::Dimsd1),
chk("Suppress 2nd line (DIMSD2)", vals.dimsd2, DsField::Dimsd2),
text("Extension Line").size(11).color(ACCENT),
text("Extension Line").size(11).style(primary_style),
row![
lbl("Extension (DIMEXE)"),
mk_field(DsField::Dimexe, vals.dimexe)
@@ -421,7 +399,7 @@ pub fn view_window<'a>(
.spacing(7)
.into(),
1 => column![
text("Arrows").size(11).color(ACCENT),
text("Arrows").size(11).style(primary_style),
hrow(
"Arrowhead (DIMBLK)",
vals.block_opts.clone(),
@@ -485,7 +463,7 @@ pub fn view_window<'a>(
.spacing(7)
.into(),
2 => column![
text("Text").size(11).color(ACCENT),
text("Text").size(11).style(primary_style),
row![
lbl("Height (DIMTXT)"),
mk_field(DsField::Dimtxt, vals.dimtxt)
@@ -551,7 +529,7 @@ pub fn view_window<'a>(
.spacing(7)
.into(),
3 => column![
text("Scale").size(11).color(ACCENT),
text("Scale").size(11).style(primary_style),
chk("Annotative", vals.annotative, DsField::Annotative),
row![
lbl("Overall scale (DIMSCALE)"),
@@ -565,7 +543,7 @@ pub fn view_window<'a>(
]
.spacing(8)
.align_y(iced::Center),
text("Units").size(11).color(ACCENT),
text("Units").size(11).style(primary_style),
enum_field("Format (DIMLUNIT)", DsField::Dimlunit, vals.dimlunit, OPT_LUNIT),
row![
lbl("Decimals (DIMDEC)"),
@@ -636,7 +614,7 @@ pub fn view_window<'a>(
("3", "Leading & trailing"),
],
),
text("Fit").size(11).color(ACCENT),
text("Fit").size(11).style(primary_style),
enum_field(
"Fit (DIMATFIT)",
DsField::Dimatfit,
@@ -680,7 +658,7 @@ pub fn view_window<'a>(
.spacing(7)
.into(),
5 => column![
text("Alternate Units").size(11).color(ACCENT),
text("Alternate Units").size(11).style(primary_style),
chk(
"Enable alternate units (DIMALT)",
vals.dimalt,
@@ -728,7 +706,7 @@ pub fn view_window<'a>(
.spacing(7)
.into(),
_ => column![
text("Tolerances").size(11).color(ACCENT),
text("Tolerances").size(11).style(primary_style),
chk("Generate tolerances (DIMTOL)", vals.dimtol, DsField::Dimtol),
chk("Limits generation (DIMLIM)", vals.dimlim, DsField::Dimlim),
row![
@@ -773,7 +751,7 @@ pub fn view_window<'a>(
// content container instead of the panel padding.
let right_panel = container(
column![
text(format!("Editing: {selected}")).size(11).color(DIM),
text(format!("Editing: {selected}")).size(11).style(muted_style),
tabs,
hdivider(),
scrollable(container(tab_content).padding([12, 12]).width(Fill))
+36 -58
View File
@@ -4,63 +4,41 @@ use crate::app::Message;
use iced::widget::{
button, checkbox, column, container, pick_list, row, scrollable, text, text_input,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, Theme};
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.20,
g: 0.42,
b: 0.72,
a: 1.0,
},
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.28,
g: 0.28,
b: 0.28,
a: 1.0,
},
(true, _) => ACCENT,
_ => Color {
r: 0.22,
g: 0.22,
b: 0.22,
a: 1.0,
},
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
(false, button::Status::Hovered | button::Status::Pressed) => {
palette.background.strong
}
(true, _) => palette.primary.base,
_ => palette.background.weak,
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into(),
},
..Default::default()
}
}
}
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)),
}
}
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().primary.base.color),
}
}
@@ -106,7 +84,7 @@ pub struct MLeaderStyleView<'a> {
}
fn section<'a>(label: &'static str) -> Element<'a, Message> {
text(label).size(11).color(ACCENT).into()
text(label).size(11).style(primary_style).into()
}
fn num_row<'a>(
@@ -116,7 +94,7 @@ fn num_row<'a>(
field: &'static str,
) -> Element<'a, Message> {
row![
text(label).size(11).color(DIM).width(150),
text(label).size(11).style(muted_style).width(150),
text_input(placeholder, value)
.on_input(move |v| Message::MLeaderStyleEdit { field, value: v })
.size(11)
@@ -150,7 +128,7 @@ fn color_row<'a>(
Message::MLeaderColorMore(field),
Message::OpenColorWindow(crate::app::ColorPickTarget::MLeader(field)),
);
row![text(label).size(11).color(DIM).width(150), selector]
row![text(label).size(11).style(muted_style).width(150), selector]
.spacing(8)
.align_y(iced::Center)
.into()
@@ -163,7 +141,7 @@ fn enum_row<'a>(
field: &'static str,
) -> Element<'a, Message> {
row![
text(label).size(11).color(DIM).width(150),
text(label).size(11).style(muted_style).width(150),
pick_list(options, Some(selected), move |value| {
Message::MLeaderStyleSetEnum { field, value }
})
@@ -178,7 +156,7 @@ fn enum_row<'a>(
fn lineweight_row<'a>(selected: acadrust::types::LineWeight) -> Element<'a, Message> {
let selected = crate::ui::properties::LwItem(selected);
row![
text("Line weight:").size(11).color(DIM).width(150),
text("Line weight:").size(11).style(muted_style).width(150),
pick_list(
crate::ui::properties::lw_options(),
Some(selected),
@@ -220,7 +198,7 @@ fn handle_row<'a>(
field: &'static str,
) -> Element<'a, Message> {
row![
text(label).size(11).color(DIM).width(150),
text(label).size(11).style(muted_style).width(150),
pick_list(options, Some(selected), move |value| {
Message::MLeaderStyleSetHandle { field, value }
})
@@ -247,7 +225,7 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> {
scrollable(
column![
row![
text("Name:").size(11).color(DIM).width(150),
text("Name:").size(11).style(muted_style).width(150),
text(s.name.clone()).size(11),
]
.spacing(8),
@@ -422,7 +400,7 @@ pub fn view_window<'a>(v: MLeaderStyleView<'a>) -> Element<'a, Message> {
.height(Fill)
.into()
} else {
container(text("Select a style to view details.").size(11).color(DIM))
container(text("Select a style to view details.").size(11).style(muted_style))
.padding([12, 12])
.into()
};
+10 -11
View File
@@ -2,14 +2,13 @@
use crate::app::Message;
use iced::widget::{column, container, row, scrollable, text};
use iced::{Color, Element, Fill};
use iced::{Element, Fill, Theme};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.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)),
}
}
pub fn view_window<'a>(
styles: Vec<String>,
@@ -22,7 +21,7 @@ pub fn view_window<'a>(
// ── Right: Details panel ──────────────────────────────────────────────
let info_row = |label: &'static str, val: String| -> Element<'_, Message> {
row![
text(label).size(11).color(DIM).width(120),
text(label).size(11).style(muted_style).width(120),
text(val).size(11),
]
.spacing(8)
@@ -49,7 +48,7 @@ pub fn view_window<'a>(
&e.linetype
};
row![
text(format!(" {idx}:")).size(10).color(DIM).width(24),
text(format!(" {idx}:")).size(10).style(muted_style).width(24),
text(format!("{:+.3}", e.offset)).size(10).width(70),
text(color_str).size(10).width(90),
text(lt).size(10),
@@ -65,7 +64,7 @@ pub fn view_window<'a>(
info_row("Elements:", s.elements.len().to_string()),
text(" Off Color Ltype")
.size(10)
.color(DIM)
.style(muted_style)
.into(),
];
col_items.extend(elem_rows);
@@ -73,7 +72,7 @@ pub fn view_window<'a>(
.height(Fill)
.into()
} else {
container(text("Select a style to view details.").size(11).color(DIM))
container(text("Select a style to view details.").size(11).style(muted_style))
.padding([12, 12])
.into()
};
+76 -115
View File
@@ -2,108 +2,55 @@
use crate::app::Message;
use iced::widget::{button, column, container, row, scrollable, text, text_input, Space};
use iced::{Background, Border, Color, Element, Fill, Theme};
const TB: Color = Color {
r: 0.13,
g: 0.13,
b: 0.13,
a: 1.0,
};
const BG: Color = Color {
r: 0.15,
g: 0.15,
b: 0.15,
a: 1.0,
};
const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
const ACTIVE: Color = Color {
r: 0.20,
g: 0.40,
b: 0.70,
a: 1.0,
};
const FIELD: Color = Color {
r: 0.10,
g: 0.10,
b: 0.10,
a: 1.0,
};
const LIST: Color = Color {
r: 0.12,
g: 0.12,
b: 0.12,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, Theme};
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.20,
g: 0.42,
b: 0.72,
a: 1.0,
},
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.28,
g: 0.28,
b: 0.28,
a: 1.0,
},
(true, _) => ACCENT,
_ => Color {
r: 0.22,
g: 0.22,
b: 0.22,
a: 1.0,
},
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
(false, button::Status::Hovered | button::Status::Pressed) => {
palette.background.strong
}
(true, _) => palette.primary.base,
_ => palette.background.weak,
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into(),
},
..Default::default()
}
}
}
fn field_style(_: &Theme, _: text_input::Status) -> text_input::Style {
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.extended_palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(FIELD),
background: Background::Color(palette.background.base.color),
border: Border {
color: BORDER,
color: border,
width: 1.0,
radius: 3.0.into(),
},
icon: TEXT,
placeholder: DIM,
value: TEXT,
selection: ACCENT,
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
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)),
}
}
@@ -111,8 +58,10 @@ fn hdivider<'a>() -> Element<'a, Message> {
container(Space::new().width(Fill).height(1))
.width(Fill)
.height(1)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
@@ -122,8 +71,10 @@ fn vsep<'a>() -> Element<'a, Message> {
container(Space::new().width(1).height(Fill))
.width(1)
.height(Fill)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
@@ -156,13 +107,15 @@ pub fn view_window<'a>(
.style(btn_s(false))
.padding([4, 10]),
Space::new().width(Fill),
text(table_name).size(10).color(DIM),
text(table_name).size(10).style(muted_style),
]
.spacing(4)
.align_y(iced::Center),
)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(TB)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color
)),
..Default::default()
})
.width(Fill)
@@ -199,19 +152,22 @@ pub fn view_window<'a>(
};
button(text(label).size(10).font(iced::Font::MONOSPACE))
.on_press(Message::PlotStylePanelSelectAci(aci))
.style(move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (is_sel, st) {
(true, _) => ACTIVE,
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.26,
g: 0.26,
b: 0.26,
a: 1.0,
},
_ => Color::TRANSPARENT,
})),
text_color: TEXT,
.style(move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (is_sel, st) {
(true, _) => Some(palette.primary.strong),
(false, button::Status::Hovered | button::Status::Pressed) => {
Some(palette.background.strong)
}
_ => None,
};
button::Style {
background: pair.map(|p| Background::Color(p.color)),
text_color: pair
.map(|p| p.text)
.unwrap_or(palette.background.base.text),
..Default::default()
}
})
.padding([2, 8])
.width(Fill)
@@ -221,16 +177,19 @@ pub fn view_window<'a>(
let aci_list = container(
column![
text("ACI Color Index").size(10).color(DIM),
text("ACI Color Index").size(10).style(muted_style),
container(scrollable(column(aci_items).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(Fill)
.height(Fill)
@@ -269,12 +228,12 @@ pub fn view_window<'a>(
.map(|e| format!("{}%", e.screening))
.unwrap_or_else(|| "—".into());
let lbl = |s: &'static str| text(s).size(11).color(DIM);
let lbl = |s: &'static str| text(s).size(11).style(muted_style);
let edit_panel = container(
column![
row![
text("ACI:").size(11).color(DIM).width(100),
text("ACI:").size(11).style(muted_style).width(100),
text(format!("{selected_aci}")).size(11),
]
.spacing(8)
@@ -298,7 +257,7 @@ pub fn view_window<'a>(
.size(11)
.padding([4, 8]),
Space::new().height(8),
text("Current values:").size(10).color(DIM),
text("Current values:").size(10).style(muted_style),
text(format!(" Color: {cur_color}")).size(10),
text(format!(" Lineweight: {cur_lw}")).size(10),
text(format!(" Screening: {cur_scr}")).size(10),
@@ -318,8 +277,10 @@ pub fn view_window<'a>(
let body = row![aci_list, vsep(), edit_panel].height(Fill);
container(column![toolbar, hdivider(), body].spacing(0))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BG)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
)),
..Default::default()
})
.width(Fill)
+41 -45
View File
@@ -7,15 +7,7 @@
use crate::app::Message;
use iced::widget::{button, canvas, column, container, radio, row, text, text_input, Space};
use iced::{mouse, Background, Border, Color, Element, Length, Point, Rectangle, Size, Theme};
const BG: Color = Color { r: 0.15, g: 0.15, b: 0.15, a: 1.0 };
const WHITE: Color = Color { r: 0.92, g: 0.92, b: 0.92, a: 1.0 };
const DIM: Color = Color { r: 0.55, g: 0.55, b: 0.55, a: 1.0 };
const ACCENT: Color = Color { r: 0.30, g: 0.62, b: 0.95, a: 1.0 };
const CELL: Color = Color { r: 0.20, g: 0.20, b: 0.20, a: 1.0 };
const CELL_SEL: Color = Color { r: 0.30, g: 0.62, b: 0.95, a: 1.0 };
const GLYPH: Color = Color { r: 0.90, g: 0.90, b: 0.90, a: 1.0 };
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Size, Theme};
const CELL_PX: f32 = 44.0;
@@ -37,22 +29,23 @@ impl canvas::Program<Message> for GlyphCanvas {
&self,
_state: &(),
renderer: &iced::Renderer,
_theme: &Theme,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let glyph = theme.extended_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 {
width: 1.4,
style: canvas::Style::Solid(GLYPH),
style: canvas::Style::Solid(glyph),
..Default::default()
};
let line = |a: Point, b: Point| canvas::Path::line(a, b);
match self.mode & 0x0F {
0 => frame.fill(&canvas::Path::circle(Point::new(cx, cy), 2.4), GLYPH),
0 => frame.fill(&canvas::Path::circle(Point::new(cx, cy), 2.4), glyph),
1 => {}
2 => {
frame.stroke(&line(Point::new(cx - r, cy), Point::new(cx + r, cy)), stroke.clone());
@@ -89,39 +82,52 @@ fn cell<'a>(value: i16, selected: bool) -> Element<'a, Message> {
button(glyph)
.padding(0)
.on_press(Message::PointStyleSetMode(value))
.style(move |_: &Theme, status| {
let bg = if selected {
CELL_SEL
.style(move |theme: &Theme, status| {
let palette = theme.extended_palette();
let pair = if selected {
palette.primary.strong
} else if matches!(status, button::Status::Hovered | button::Status::Pressed) {
Color { r: 0.28, g: 0.28, b: 0.28, a: 1.0 }
palette.background.strong
} else {
CELL
palette.background.weak
};
button::Style {
background: Some(Background::Color(bg)),
background: Some(Background::Color(pair.color)),
border: Border {
color: Color { r: 0.35, g: 0.35, b: 0.35, a: 1.0 },
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
text_color: pair.text,
..Default::default()
}
})
.into()
}
fn field_style(_: &Theme, _: text_input::Status) -> text_input::Style {
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.extended_palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(Color { r: 0.1, g: 0.1, b: 0.1, a: 1.0 }),
background: Background::Color(palette.background.base.color),
border: Border {
color: Color { r: 0.3, g: 0.3, b: 0.3, a: 1.0 },
color: border,
width: 1.0,
radius: 4.0.into(),
},
icon: DIM,
placeholder: DIM,
value: WHITE,
selection: ACCENT,
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
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)),
}
}
@@ -138,7 +144,7 @@ pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'
}
let size_row = row![
text("Point Size:").size(13).color(WHITE),
text("Point Size:").size(13),
Space::new().width(10),
text_input("0", size_buf)
.on_input(Message::PointStyleSizeInput)
@@ -147,7 +153,7 @@ pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'
.size(13)
.width(110),
Space::new().width(6),
text(if relative { "%" } else { "units" }).size(12).color(DIM),
text(if relative { "%" } else { "units" }).size(12).style(muted_style),
]
.align_y(iced::Center);
@@ -171,26 +177,14 @@ pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'
]
.spacing(6);
let ok = button(text("OK").size(13).color(WHITE))
let ok = button(text("OK").size(13))
.padding([5, 22])
.on_press(Message::PointStyleOk)
.style(|_: &Theme, status| {
let bg = if matches!(status, button::Status::Hovered | button::Status::Pressed) {
Color { r: 0.32, g: 0.55, b: 0.85, a: 1.0 }
} else {
ACCENT
};
button::Style {
background: Some(Background::Color(bg)),
text_color: WHITE,
border: Border { radius: 4.0.into(), ..Default::default() },
..Default::default()
}
});
.style(button::primary);
container(
column![
text("Point Style").size(18).color(WHITE),
text("Point Style").size(18),
Space::new().height(6),
grid,
Space::new().height(12),
@@ -203,8 +197,10 @@ pub fn view_window<'a>(pdmode: i16, relative: bool, size_buf: &str) -> Element<'
.spacing(4)
.padding(20),
)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BG)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
)),
..Default::default()
})
.into()
+43 -50
View File
@@ -6,53 +6,36 @@
//! messages instead of the StyleKind machinery.
use crate::app::Message;
use crate::ui::style::style_manager::{hdivider, tb_button, vsep, BG, BORDER, DIM, LIST, TB, TEXT};
use crate::ui::style::style_manager::{
hdivider, muted_text_style, tb_button, vsep,
};
use iced::widget::{
column, container, mouse_area, row, scrollable, text, text_input, Space,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
use iced::{Background, Border, Element, Fill, Theme};
/// Inline-rename text-input id, so the rename-start handler can focus it.
pub fn rename_input_id() -> iced::widget::Id {
iced::widget::Id::new("scale-rename-input")
}
const INPUT_BG: Color = Color {
r: 0.10,
g: 0.10,
b: 0.10,
a: 1.0,
};
const ACTIVE: Color = Color {
r: 0.20,
g: 0.40,
b: 0.70,
a: 1.0,
};
const CURRENT_CHECK: Color = Color {
r: 0.30,
g: 0.82,
b: 0.36,
a: 1.0,
};
fn field_style(_: &Theme, _: text_input::Status) -> text_input::Style {
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.extended_palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(INPUT_BG),
background: Background::Color(palette.background.base.color),
border: Border {
color: BORDER,
color: border,
width: 1.0,
radius: 4.0.into(),
},
icon: TEXT,
placeholder: DIM,
value: TEXT,
selection: Color {
r: 0.20,
g: 0.46,
b: 0.80,
a: 0.45,
},
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
@@ -80,8 +63,10 @@ pub fn view_window<'a, 'b>(
.spacing(4)
.align_y(iced::Center),
)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(TB)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color
)),
..Default::default()
})
.width(Fill)
@@ -105,21 +90,24 @@ pub fn view_window<'a, 'b>(
}
let is_sel = name.as_str() == selected;
let is_cur = name.eq_ignore_ascii_case(current);
let check = crate::ui::icons::check_cell(is_cur, CURRENT_CHECK);
let check = crate::ui::icons::themed_check_cell(is_cur);
let label = row![
check,
text(name.clone()).size(11).color(TEXT).width(Fill),
text(ratio.clone()).size(10).color(DIM),
text(name.clone()).size(11).width(Fill),
text(ratio.clone()).size(10).style(muted_text_style),
]
.spacing(4)
.align_y(iced::Center);
let cell = container(label)
.padding([4, 8])
.width(Fill)
.style(move |_: &Theme| container::Style {
background: is_sel.then_some(Background::Color(ACTIVE)),
text_color: Some(TEXT),
.style(move |theme: &Theme| {
let pair = theme.extended_palette().primary.strong;
container::Style {
background: is_sel.then_some(Background::Color(pair.color)),
text_color: is_sel.then_some(pair.text),
..Default::default()
}
});
mouse_area(cell)
.on_press(Message::ScaleManagerSelect(name.clone()))
@@ -130,16 +118,19 @@ pub fn view_window<'a, 'b>(
let list_panel = container(
column![
text("Scales").size(10).color(DIM),
text("Scales").size(10).style(muted_text_style),
container(scrollable(column(rows).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(Fill)
.height(Fill)
@@ -161,7 +152,7 @@ pub fn view_window<'a, 'b>(
let field =
|label: &'static str, ph: &'static str, value: &str, on: fn(String) -> Message| {
row![
text(label).size(11).color(DIM).width(96),
text(label).size(11).style(muted_text_style).width(96),
text_input(ph, value)
.on_input(on)
.style(field_style)
@@ -175,13 +166,13 @@ pub fn view_window<'a, 'b>(
let editor = container(
column![
text("Scale").size(10).color(DIM),
text("Scale").size(10).style(muted_text_style),
field("Paper units", "1", paper_buf, Message::ScaleManagerPaperBuf),
field("Drawing units", "50", drawing_buf, Message::ScaleManagerDrawingBuf),
Space::new().height(6),
text("Double-click a scale to rename it; edit its paper : drawing ratio here. New / Copy add a scale. Changes are kept only if you click Apply before closing.")
.size(10)
.color(DIM),
.style(muted_text_style),
]
.spacing(8),
)
@@ -192,8 +183,10 @@ pub fn view_window<'a, 'b>(
let body = row![list_panel, vsep(), editor].height(Fill);
container(column![toolbar, hdivider(), body])
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BG)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
)),
..Default::default()
})
.width(Fill)
+9 -25
View File
@@ -10,7 +10,7 @@
use crate::app::{Message, StyleKind};
use iced::widget::{container, mouse_area, row, text, text_input};
use iced::{Background, Color, Element, Fill, Theme};
use iced::{Background, Element, Fill, Theme};
/// Shared id for the inline rename field, so the rename-start handler can focus
/// it the moment the row turns editable.
@@ -18,25 +18,6 @@ pub fn rename_input_id() -> iced::widget::Id {
iced::widget::Id::new("style-rename-input")
}
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const ACTIVE: Color = Color {
r: 0.20,
g: 0.40,
b: 0.70,
a: 1.0,
};
const CURRENT_CHECK: Color = Color {
r: 0.30,
g: 0.82,
b: 0.36,
a: 1.0,
};
/// One row of the style list. Renders an editable `text_input` when `name` is
/// the style being renamed (`rename_active`), otherwise a selectable row whose
/// double click starts the rename. The current style gets a green ✓.
@@ -61,16 +42,19 @@ pub fn item<'a>(
} else {
// Fixed-width ✓ column keeps every name left-aligned whether or not the
// row is current.
let check = crate::ui::icons::check_cell(is_current, CURRENT_CHECK);
let label = row![check, text(name.to_string()).size(11).color(TEXT)]
let check = crate::ui::icons::themed_check_cell(is_current);
let label = row![check, text(name.to_string()).size(11)]
.align_y(iced::Center);
let cell = container(label)
.padding([4, 8])
.width(Fill)
.style(move |_: &Theme| container::Style {
background: is_selected.then_some(Background::Color(ACTIVE)),
text_color: Some(TEXT),
.style(move |theme: &Theme| {
let pair = theme.extended_palette().primary.strong;
container::Style {
background: is_selected.then_some(Background::Color(pair.color)),
text_color: is_selected.then_some(pair.text),
..Default::default()
}
});
mouse_area(cell)
.on_press(on_select)
+43 -82
View File
@@ -10,52 +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, Color, Element, Fill, Theme};
// Shared palette — also reused by the scale manager so it matches the style
// managers exactly ([[feedback_shared_infra]]).
pub(crate) const TB: Color = Color {
r: 0.13,
g: 0.13,
b: 0.13,
a: 1.0,
};
pub(crate) const BG: Color = Color {
r: 0.15,
g: 0.15,
b: 0.15,
a: 1.0,
};
pub(crate) const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
pub(crate) const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
pub(crate) const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
pub(crate) const LIST: Color = Color {
r: 0.12,
g: 0.12,
b: 0.12,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, Theme};
/// Everything the shared frame needs. The per-manager `editor` element is the
/// only bespoke part.
@@ -103,8 +58,10 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
.spacing(4)
.align_y(iced::Center);
let toolbar = container(bar)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(TB)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.weak.color
)),
..Default::default()
})
.width(Fill)
@@ -131,16 +88,19 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
let list_panel = container(
column![
text("Styles").size(10).color(DIM),
text("Styles").size(10).style(muted_text_style),
container(scrollable(column(rows).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(Fill)
.height(Fill)
@@ -161,8 +121,10 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
let body = row![list_panel, vsep(), s.editor].height(Fill);
container(column![toolbar, hdivider(), body])
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BG)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.base.color
)),
..Default::default()
})
.width(Fill)
@@ -182,35 +144,30 @@ 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, st| Style {
background: Some(Background::Color(match (accent, st) {
(true, Status::Hovered | Status::Pressed) => Color {
r: 0.20,
g: 0.42,
b: 0.72,
a: 1.0,
},
(false, Status::Hovered | Status::Pressed) => Color {
r: 0.28,
g: 0.28,
b: 0.28,
a: 1.0,
},
(true, _) => ACCENT,
_ => Color {
r: 0.22,
g: 0.22,
b: 0.22,
a: 1.0,
},
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (accent, st) {
(true, Status::Hovered | Status::Pressed) => palette.primary.strong,
(false, Status::Hovered | Status::Pressed) => palette.background.strong,
(true, _) => palette.primary.base,
_ => palette.background.weak,
};
Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into(),
},
..Default::default()
}
}
}
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)),
}
}
@@ -218,8 +175,10 @@ pub(crate) fn hdivider<'a>() -> Element<'a, Message> {
container(Space::new().width(Fill).height(1))
.width(Fill)
.height(1)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
@@ -229,8 +188,10 @@ pub(crate) fn vsep<'a>() -> Element<'a, Message> {
container(Space::new().width(1).height(Fill))
.width(1)
.height(Fill)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
+40 -62
View File
@@ -4,63 +4,41 @@ use crate::app::Message;
use iced::widget::{
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Column,
};
use iced::{Background, Border, Color, Element, Fill, Theme};
const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
use iced::{Background, Border, Element, Fill, Theme};
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.20,
g: 0.42,
b: 0.72,
a: 1.0,
},
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.28,
g: 0.28,
b: 0.28,
a: 1.0,
},
(true, _) => ACCENT,
_ => Color {
r: 0.22,
g: 0.22,
b: 0.22,
a: 1.0,
},
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
(false, button::Status::Hovered | button::Status::Pressed) => {
palette.background.strong
}
(true, _) => palette.primary.base,
_ => palette.background.weak,
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into(),
},
..Default::default()
}
}
}
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)),
}
}
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().primary.base.color),
}
}
@@ -89,7 +67,7 @@ pub fn view_window<'a>(
// ── Right: Details panel ──────────────────────────────────────────────
let info_row = |label: &'static str, val: String| -> Element<'_, Message> {
row![
text(label).size(11).color(DIM).width(160),
text(label).size(11).style(muted_style).width(160),
text(val).size(11),
]
.spacing(8)
@@ -108,7 +86,7 @@ pub fn view_window<'a>(
field: &'static str|
-> Element<'a, Message> {
row![
text(label).size(11).color(DIM).width(150),
text(label).size(11).style(muted_style).width(150),
text_input(placeholder, value)
.on_input(move |v| Message::TableStyleCellEdit {
row,
@@ -142,14 +120,14 @@ pub fn view_window<'a>(
Message::TableColorMore(row, field),
Message::OpenColorWindow(crate::app::ColorPickTarget::Table(row, field)),
);
row![text(label).size(11).color(DIM).width(150), selector]
row![text(label).size(11).style(muted_style).width(150), selector]
.spacing(8)
.align_y(iced::Center)
.into()
};
let mut col = Column::new()
.spacing(3)
.push(text(row_label).size(11).color(ACCENT))
.push(text(row_label).size(11).style(primary_style))
.push(cell_in(
" Text style:",
"Standard",
@@ -161,7 +139,7 @@ pub fn view_window<'a>(
.push(cell_color(" Fill color:", &cell_fillcolor[r], "fillcolor"))
.push(
row![
text(" Alignment:").size(11).color(DIM).width(150),
text(" Alignment:").size(11).style(muted_style).width(150),
pick_list(
[
"TopLeft",
@@ -199,7 +177,7 @@ pub fn view_window<'a>(
.push(
text(" Borders (type / weight / color / spacing / hidden)")
.size(10)
.color(DIM),
.style(muted_style),
);
let borders: [(&'static str, &acadrust::objects::TableCellBorder); 6] = [
@@ -214,7 +192,7 @@ pub fn view_window<'a>(
let bu = b as u8;
col = col.push(
row![
text(format!(" {bname}")).size(11).color(DIM).width(28),
text(format!(" {bname}")).size(11).style(muted_style).width(28),
pick_list(
["Single", "Double"]
.iter()
@@ -282,7 +260,7 @@ pub fn view_window<'a>(
column![
info_row("Name:", s.name.clone()),
row![
text("Description:").size(11).color(DIM).width(160),
text("Description:").size(11).style(muted_style).width(160),
text_input("", description_buf)
.on_input(|v| Message::TableStyleEdit {
field: "description",
@@ -294,7 +272,7 @@ pub fn view_window<'a>(
.spacing(8)
.align_y(iced::Center),
row![
text("Flow direction:").size(11).color(DIM).width(160),
text("Flow direction:").size(11).style(muted_style).width(160),
pick_list(
["Down", "Up"]
.iter()
@@ -314,7 +292,7 @@ pub fn view_window<'a>(
.size(14)
.text_size(11),
row![
text("H Margin:").size(11).color(DIM).width(160),
text("H Margin:").size(11).style(muted_style).width(160),
text_input("1.5", hmargin_buf)
.on_input(|v| Message::TableStyleEdit {
field: "hmargin",
@@ -326,7 +304,7 @@ pub fn view_window<'a>(
.spacing(8)
.align_y(iced::Center),
row![
text("V Margin:").size(11).color(DIM).width(160),
text("V Margin:").size(11).style(muted_style).width(160),
text_input("1.5", vmargin_buf)
.on_input(|v| Message::TableStyleEdit {
field: "vmargin",
@@ -362,7 +340,7 @@ pub fn view_window<'a>(
.height(Fill)
.into()
} else {
container(text("Select a style to view details.").size(11).color(DIM))
container(text("Select a style to view details.").size(11).style(muted_style))
.padding([12, 12])
.into()
};
+67 -81
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, Color, Element, Fill, Length, Point, Rectangle, Theme};
use iced::{mouse, Background, Border, Element, Fill, Length, Point, Rectangle, Theme};
/// View-model for the Text Style editor window.
pub struct TextStyleView<'a> {
@@ -28,49 +28,6 @@ pub struct TextStyleView<'a> {
pub rename_buf: &'a str,
}
const BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
const TEXT: Color = Color {
r: 0.88,
g: 0.88,
b: 0.88,
a: 1.0,
};
const DIM: Color = Color {
r: 0.55,
g: 0.55,
b: 0.55,
a: 1.0,
};
const ACCENT: Color = Color {
r: 0.25,
g: 0.50,
b: 0.85,
a: 1.0,
};
const ACTIVE: Color = Color {
r: 0.20,
g: 0.40,
b: 0.70,
a: 1.0,
};
const FIELD: Color = Color {
r: 0.10,
g: 0.10,
b: 0.10,
a: 1.0,
};
const LIST: Color = Color {
r: 0.12,
g: 0.12,
b: 0.12,
a: 1.0,
};
const BUILTIN_FONTS: &[&str] = &[
"Standard", "ISO", "Simplex", "RomanS", "RomanD", "RomanC", "RomanT", "ItalicC", "ItalicT",
"ScriptS", "ScriptC", "GothGBT", "GothGRT", "GothITT", "GreekC", "Symbol",
@@ -78,34 +35,52 @@ const BUILTIN_FONTS: &[&str] = &[
];
fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |_: &Theme, st| button::Style {
background: Some(Background::Color(match (active, st) {
(true, _) => ACTIVE,
(false, button::Status::Hovered | button::Status::Pressed) => Color {
r: 0.26,
g: 0.26,
b: 0.26,
a: 1.0,
},
_ => Color::TRANSPARENT,
})),
text_color: TEXT,
move |theme: &Theme, st| {
let palette = theme.extended_palette();
let pair = match (active, st) {
(true, _) => Some(palette.primary.strong),
(false, button::Status::Hovered | button::Status::Pressed) => {
Some(palette.background.strong)
}
_ => None,
};
button::Style {
background: pair.map(|p| Background::Color(p.color)),
text_color: pair.map(|p| p.text).unwrap_or(palette.background.base.text),
..Default::default()
}
}
}
fn field_style(_: &Theme, _: text_input::Status) -> text_input::Style {
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.extended_palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(FIELD),
background: Background::Color(palette.background.base.color),
border: Border {
color: BORDER,
color: border,
width: 1.0,
radius: 3.0.into(),
},
icon: TEXT,
placeholder: DIM,
value: TEXT,
selection: ACCENT,
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
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)),
}
}
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().primary.base.color),
}
}
@@ -113,8 +88,10 @@ fn vsep<'a>() -> Element<'a, Message> {
container(Space::new().width(1).height(Fill))
.width(1)
.height(Fill)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(BORDER)),
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.extended_palette().background.neutral.color
)),
..Default::default()
})
.into()
@@ -143,7 +120,7 @@ impl canvas::Program<Message> for TextPreviewCanvas {
&self,
_state: &(),
renderer: &iced::Renderer,
_theme: &Theme,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
@@ -185,7 +162,7 @@ impl canvas::Program<Message> for TextPreviewCanvas {
};
let stroke = canvas::Stroke {
width: 1.4,
style: canvas::Style::Solid(TEXT),
style: canvas::Style::Solid(theme.extended_palette().background.base.text),
..Default::default()
};
for s in &strokes {
@@ -237,16 +214,19 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
let font_panel = container(
column![
text("Font File").size(10).color(DIM),
text("Font File").size(10).style(muted_style),
container(scrollable(column(font_items).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(Fill)
.height(Fill)
@@ -275,7 +255,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
field: &'static str,
) -> Element<'a, Message> {
row![
text(label).size(11).color(DIM).width(120),
text(label).size(11).style(muted_style).width(120),
text_input(ph, buf)
.on_input(move |v| Message::TextStyleEdit { field, value: v })
.style(field_style)
@@ -312,7 +292,7 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
// ── Right: Properties ─────────────────────────────────────────────────
let props_panel = container(
column![
text("Properties").size(11).color(ACCENT),
text("Properties").size(11).style(primary_style),
frow("Big Font:", "big-font file…", bigfont_buf, "bigfont"),
frow("TrueType Font:", "e.g. Arial", ttf_buf, "ttf"),
frow("Fixed Height:", "0 = variable", height_buf, "height"),
@@ -337,16 +317,19 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
.size(15)
.text_size(11),
Space::new().height(8),
text("Preview").size(10).color(DIM),
text("Preview").size(10).style(muted_style),
container(preview)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(FIELD)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.base.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into()
},
..Default::default()
}
})
.padding(8)
.width(Fill),
@@ -382,16 +365,19 @@ pub fn view_window<'a>(v: TextStyleView<'a>) -> Element<'a, Message> {
let ttf_panel = container(
column![
text("TrueType (system)").size(10).color(DIM),
text("TrueType (system)").size(10).style(muted_style),
container(scrollable(column(ttf_items).spacing(1)).height(Fill))
.style(|_: &Theme| container::Style {
background: Some(Background::Color(LIST)),
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(Fill)
.height(Fill)