feat(options): command line text colour and a fonts folder

Display gets a command line text colour (blank keeps the theme's); it
covers history, prompts and the input, while errors stay red. Files
lists the fonts folder that text resolution searches, so .shx files can
be added by hand; opening it creates it first.

Discussions #1493, #1372

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-07 08:50:12 +03:00
1 parent 1c37c90c75
commit 7a8ec02003
29 files changed
+144 -15

No files matched your search

+45 -14
View File
@@ -801,12 +801,18 @@ impl CommandLine {
.on_input(Message::CommandInput)
.on_submit(Message::CommandSubmit);
}
let input = input.size(11).padding(Padding {
top: 4.0,
right: 30.0,
bottom: 4.0,
left: 6.0,
});
let input = input
.size(11)
.padding(Padding {
top: 4.0,
right: 30.0,
bottom: 4.0,
left: 6.0,
})
.style(|theme: &Theme, status| text_input::Style {
value: text_color(theme),
..text_input::default(theme, status)
});
// Autocomplete suggestions panel, shown above the input row
// when the user has typed a prefix that matches at least one
// command. Each row is a button — clicking it dispatches the
@@ -1159,18 +1165,43 @@ fn header_btn_style(theme: &Theme, status: button::Status) -> button::Style {
}
}
/// The user's command-line text colour, packed `0x01RRGGBB`; 0 keeps the
/// theme's. Global because the history highlighter takes a plain `fn`.
static TEXT_COLOR: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
pub fn set_text_color(rgb: Option<[u8; 3]>) {
let packed = rgb.map_or(0, |[r, g, b]| 1 << 24 | u32::from_be_bytes([0, r, g, b]));
TEXT_COLOR.store(packed, std::sync::atomic::Ordering::Relaxed);
}
fn user_text_color() -> Option<Color> {
match TEXT_COLOR.load(std::sync::atomic::Ordering::Relaxed) {
0 => None,
packed => {
let [_, r, g, b] = packed.to_be_bytes();
Some(Color::from_rgb8(r, g, b))
}
}
}
fn text_color(theme: &Theme) -> Color {
user_text_color().unwrap_or(theme.palette().background.base.text)
}
fn history_color(theme: &Theme, kind: &EntryKind) -> Color {
let palette = theme.palette();
match kind {
EntryKind::Command => palette.background.base.text,
EntryKind::Output => palette.background.base.text.scale_alpha(0.72),
EntryKind::Command => text_color(theme),
EntryKind::Output => text_color(theme).scale_alpha(0.72),
EntryKind::Error => palette.danger.base.color,
EntryKind::Info => accessible_accent_threshold(
palette.primary.base.color,
palette.background.base.color,
palette.background.base.text,
4.5,
),
EntryKind::Info => user_text_color().unwrap_or_else(|| {
accessible_accent_threshold(
palette.primary.base.color,
palette.background.base.color,
palette.background.base.text,
4.5,
)
}),
}
}
+37
View File
@@ -97,6 +97,9 @@ pub struct Folders {
pub plot_styles: Option<String>,
pub plugins: Option<String>,
pub autosave: Option<String>,
/// Where `.shx` / `.ttf` fonts dropped in by the user (or downloaded for
/// a drawing) are found.
pub fonts: Option<String>,
}
/// Values read from the current drawing's header rather than from preferences.
@@ -217,6 +220,8 @@ pub fn view_window<'a>(
crosshair_color_input: &'a str,
snap_marker_color: Option<[u8; 3]>,
snap_marker_color_input: &'a str,
command_text_color: Option<[u8; 3]>,
command_text_color_input: &'a str,
lineweight_display_scale: i32,
model_space: &'a crate::app::config::ModelSpaceThemeConfig,
model_bg_input: &'a str,
@@ -526,6 +531,24 @@ pub fn view_window<'a>(
..Default::default()
});
let command_rgb = command_text_color.unwrap_or([220, 220, 220]);
let command_swatch = container(Space::new())
.width(28)
.height(22)
.style(move |theme: &Theme| container::Style {
background: Some(Background::Color(iced::Color::from_rgb8(
command_rgb[0],
command_rgb[1],
command_rgb[2],
))),
border: Border {
color: theme.palette().background.strong.color,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
});
let snap_rgb = snap_marker_color.unwrap_or([255, 230, 26]);
let snap_swatch = container(Space::new())
.width(28)
@@ -803,6 +826,18 @@ pub fn view_window<'a>(
.spacing(10)
.align_y(iced::Center),
)
.push(Space::new().height(10))
.push(
row![
text(crate::t!("Command line text color")).size(12).width(140),
command_swatch,
text_input(crate::t!("#RRGGBB or blank").as_ref(), command_text_color_input)
.on_input(Message::CommandTextColorChanged)
.width(150),
]
.spacing(10)
.align_y(iced::Center),
)
.push(Space::new().height(6))
.push(
text(crate::t!("Leave the color blank to keep automatic viewport contrast."))
@@ -1700,6 +1735,8 @@ pub fn view_window<'a>(
folder_row(crate::t!("Plugins"), folders.plugins.clone()),
Space::new().height(12),
folder_row(crate::t!("Autosave files"), folders.autosave.clone()),
Space::new().height(12),
folder_row(crate::t!("Fonts"), folders.fonts.clone()),
Space::new().height(16),
text(crate::t!("Default template for new drawings")).size(12),
Space::new().height(4),