From a0027a8977f982395788fcdf4cc3db0cae57d578 Mon Sep 17 00:00:00 2001 From: Panos <25664832+mechpanos@users.noreply.github.com> Date: Thu, 10 Sep 2026 08:26:20 +0300 Subject: [PATCH] Put text fill and the command-line preferences on the Display page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three settings that work, persist, and could only be reached by typing their name: TEXTFILL, CLIPROMPTLINES and COMMANDLINEFADETIME. The last two govern how much of the command window is prompt and how long its history lingers — the kind of thing people fiddle with once and then leave, which is exactly what a settings dialog is for. One fix rides along. TEXTFILL is a process-global, so changing it invalidates the text in every open drawing; the SETVAR path rebuilt only the active tab, leaving the others rendering the previous setting until an unrelated edit happened to rebuild them. Both paths now go through `invalidate_text_everywhere`, so the checkbox and the command cannot disagree. Co-Authored-By: Claude Opus 5 --- src/app/commands/styleprops.rs | 4 +- src/app/mod.rs | 6 +++ src/app/update/file.rs | 11 +++++ src/app/update/mod.rs | 23 +++++++++++ src/app/view/modal.rs | 3 ++ src/ui/window/options.rs | 75 ++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 4efc41f80..12128fa88 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -2184,9 +2184,7 @@ impl OpenCADStudio { // TEXTFILL reset the glyph atlas; re-tessellate so text picks // up the re-baked filled / hollow tiles. if name == "TEXTFILL" { - self.tabs[i] - .scene - .invalidate_text_geometry_dependencies(); + self.invalidate_text_everywhere(); } // LTSCALE scales the dash pattern baked into every wire, and // PDMODE / PDSIZE decide the point glyph built at tessellation diff --git a/src/app/mod.rs b/src/app/mod.rs index 9a6eda5f0..65c2f715b 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -2011,6 +2011,12 @@ pub enum Message { SaveTimeChanged(i32), /// Toggle keeping a `.bak` copy when overwriting a drawing (ISAVEBAK). BackupOnSaveChanged(bool), + /// Toggle filled TrueType glyphs (TEXTFILL). + TextFillChanged(bool), + /// Change how many prompt lines sit above the command window (CLIPROMPTLINES). + ClipromptLinesChanged(i32), + /// Change how long command-line history lines stay visible (COMMANDLINEFADETIME). + CommandLineFadeChanged(i32), /// Restore Model Space display/canvas appearance to defaults. RestoreModelSpaceDisplayDefaults, /// Restore Selection visual effect settings to defaults. diff --git a/src/app/update/file.rs b/src/app/update/file.rs index bc4c020cd..61921204a 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -355,6 +355,17 @@ impl OpenCADStudio { } } + /// Rebuild text geometry in every open drawing. + /// + /// `TEXTFILL` is a process-global, so a change to it invalidates the text + /// in every tab. Doing only the active one leaves the others rendering the + /// previous setting until some unrelated edit happens to rebuild them. + pub(in crate::app) fn invalidate_text_everywhere(&mut self) { + for tab in &mut self.tabs { + tab.scene.invalidate_text_geometry_dependencies(); + } + } + /// Snapshot the persisted UI preferences from live state. pub(in crate::app) fn current_settings(&self) -> crate::app::settings::UserSettings { crate::app::settings::UserSettings { diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 8f29e3ae8..9781b22f3 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -6200,6 +6200,29 @@ impl OpenCADStudio { Task::none() } + Message::TextFillChanged(filled) => { + crate::scene::text::sdf_atlas::set_textfill(filled); + self.invalidate_text_everywhere(); + self.persist_settings_if_changed(); + Task::none() + } + + Message::ClipromptLinesChanged(lines) => { + let lines = crate::app::settings::clamp_clipromptlines(lines); + self.cliprompt_lines = lines; + self.command_line.set_cliprompt_lines(lines.clamp(0, 50) as u8); + self.persist_settings_if_changed(); + Task::none() + } + + Message::CommandLineFadeChanged(ms) => { + let ms = crate::app::settings::clamp_commandline_fade_ms(ms); + self.commandline_fade_ms = ms; + self.command_line.set_commandline_fade_ms(ms.max(0) as u32); + self.persist_settings_if_changed(); + Task::none() + } + Message::PickDragRectToggled(rectangle) => { self.pick_drag_rect = rectangle; self.persist_settings_if_changed(); diff --git a/src/app/view/modal.rs b/src/app/view/modal.rs index ebf081925..50da6adfb 100644 --- a/src/app/view/modal.rs +++ b/src/app/view/modal.rs @@ -195,6 +195,9 @@ impl OpenCADStudio { crate::ui::window::options::AppPrefs { savetime_min: self.savetime_min, backup_on_save: self.backup_on_save, + textfill: crate::scene::text::sdf_atlas::textfill(), + cliprompt_lines: self.cliprompt_lines, + commandline_fade_ms: self.commandline_fade_ms, }, self.double_click_block_refedit, self.double_click_block_attedit, diff --git a/src/ui/window/options.rs b/src/ui/window/options.rs index 4b674795c..35e888006 100644 --- a/src/ui/window/options.rs +++ b/src/ui/window/options.rs @@ -42,6 +42,12 @@ pub struct AppPrefs { pub savetime_min: i32, /// ISAVEBAK: keep a `.bak` when overwriting. pub backup_on_save: bool, + /// TEXTFILL: fill TrueType glyphs rather than drawing them hollow. + pub textfill: bool, + /// CLIPROMPTLINES: prompt lines shown above the command window. + pub cliprompt_lines: i32, + /// COMMANDLINEFADETIME: how long overlay history lines stay visible, in ms. + pub commandline_fade_ms: i32, } /// The Selection-card settings that live on `UserSettings` rather than on the @@ -642,6 +648,75 @@ pub fn view_window<'a>( text(crate::t!("Changes the on-screen width in Model without affecting plotted output.")) .size(11) .width(sizing.width), + ) + .push(Space::new().height(14)) + .push( + row![ + iced::widget::checkbox(prefs.textfill) + .on_toggle(Message::TextFillChanged) + .size(15), + text(crate::t!("Fill TrueType glyphs (TEXTFILL)")).size(12), + ] + .spacing(8) + .align_y(iced::Center), + ) + .push(Space::new().height(24)) + .push(text(crate::t!("Command Line")).size(15)) + .push(Space::new().height(10)) + .push( + row![ + text(crate::t!("Prompt lines")).size(12).width(140), + slider( + 0..=50, + prefs.cliprompt_lines.clamp(0, 50), + Message::ClipromptLinesChanged, + ) + .step(1) + .width(Fill), + text(prefs.cliprompt_lines.clamp(0, 50).to_string()) + .size(11) + .width(44), + ] + .spacing(10) + .align_y(iced::Center), + ) + .push(Space::new().height(6)) + .push( + text(crate::t!( + "Temporary prompt lines shown above the command window (CLIPROMPTLINES)." + )) + .size(11) + .width(sizing.width), + ) + .push(Space::new().height(12)) + .push( + row![ + text(crate::t!("History fade time")).size(12).width(140), + slider( + 0..=60000, + prefs.commandline_fade_ms.clamp(0, 60000), + Message::CommandLineFadeChanged, + ) + .step(250) + .width(Fill), + text(if prefs.commandline_fade_ms <= 0 { + crate::t!("Off").into_owned() + } else { + format!("{:.1} s", prefs.commandline_fade_ms as f32 / 1000.0) + }) + .size(11) + .width(44), + ] + .spacing(10) + .align_y(iced::Center), + ) + .push(Space::new().height(6)) + .push( + text(crate::t!( + "How long overlay history lines stay visible; 0 skips them (COMMANDLINEFADETIME)." + )) + .size(11) + .width(sizing.width), ); let display_element = display.spacing(0).width(sizing.width);