From 9c3f3625dada14cafb50d7706013bfffbd615588 Mon Sep 17 00:00:00 2001 From: Panos <25664832+mechpanos@users.noreply.github.com> Date: Thu, 10 Sep 2026 08:29:48 +0300 Subject: [PATCH] Add a User Preferences page for six command-only settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zoom direction and factor, whether TEXTEDIT ends after one object, whether continued dimensions inherit the base dimension's style, which points QDIM measures from, and which annotative objects pick up a newly set scale. All six work today; none had a control. Two of them needed their meaning worked out rather than copied. ANNOAUTOSCALE stores the mode in the magnitude and on/off in the sign, and the four modes are not documented anywhere in the app — the command prompt just says `[-4..4]`. Reading `add_annotation_scale_to_objects` gives them: 1 skips layers that are off, frozen, locked or frozen in the viewport, 2 keeps the locked ones, 3 skips only locked, 4 takes everything. The dropdown names them instead of showing bare numbers, and choosing Off negates rather than zeroing, so the mode survives being switched off and back on — which is the convention the status-bar pill already follows. The QDIM origin priority had no system variable at all; it could only be reached through a keyword inside the running command. Drawing units stay in their own dialog; this page links to it. Co-Authored-By: Claude Opus 5 --- src/app/mod.rs | 12 +++ src/app/update/mod.rs | 43 +++++++++++ src/app/view/modal.rs | 6 ++ src/ui/window/options.rs | 157 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+) diff --git a/src/app/mod.rs b/src/app/mod.rs index 65c2f715b..357a8a73e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -2017,6 +2017,18 @@ pub enum Message { ClipromptLinesChanged(i32), /// Change how long command-line history lines stay visible (COMMANDLINEFADETIME). CommandLineFadeChanged(i32), + /// Toggle reversing the mouse-wheel zoom direction (ZOOMWHEEL). + ZoomWheelReversedChanged(bool), + /// Change how far one wheel notch zooms (ZOOMFACTOR, 3..=100). + ZoomFactorChanged(i32), + /// Toggle TEXTEDIT ending after one object (TEXTEDITMODE). + TextEditModeChanged(bool), + /// Toggle continued dimensions inheriting the base style (DIMCONTINUEMODE). + DimContinueModeChanged(bool), + /// Change which points QDIM measures from (0 endpoints, 1 intersections). + QdimSnapPriorityChanged(u8), + /// Change which annotative objects pick up a new scale (ANNOAUTOSCALE). + AnnoAutoScaleChanged(i8), /// Restore Model Space display/canvas appearance to defaults. RestoreModelSpaceDisplayDefaults, /// Restore Selection visual effect settings to defaults. diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 9781b22f3..4b83b5732 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -6223,6 +6223,49 @@ impl OpenCADStudio { Task::none() } + Message::ZoomWheelReversedChanged(reversed) => { + self.zoom_wheel_reversed = reversed; + self.persist_settings_if_changed(); + Task::none() + } + + Message::ZoomFactorChanged(factor) => { + self.zoom_factor = factor.clamp(3, 100); + self.persist_settings_if_changed(); + Task::none() + } + + Message::TextEditModeChanged(single) => { + self.texteditmode = single; + self.persist_settings_if_changed(); + Task::none() + } + + Message::DimContinueModeChanged(inherit) => { + self.dimension_continue_mode = i16::from(inherit); + self.persist_settings_if_changed(); + Task::none() + } + + Message::QdimSnapPriorityChanged(priority) => { + self.quick_dimension_snap_priority = priority.min(1); + self.persist_settings_if_changed(); + Task::none() + } + + // The sign carries on/off and the magnitude the mode, so switching + // off and back on has to return to the mode that was chosen — the + // same convention the status-bar pill uses when it negates. + Message::AnnoAutoScaleChanged(mode) => { + self.annotation_auto_scale = if mode == 0 { + -self.annotation_auto_scale.abs().max(1) + } else { + mode.clamp(1, 4) + }; + 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 50da6adfb..3f650f643 100644 --- a/src/app/view/modal.rs +++ b/src/app/view/modal.rs @@ -198,6 +198,12 @@ impl OpenCADStudio { textfill: crate::scene::text::sdf_atlas::textfill(), cliprompt_lines: self.cliprompt_lines, commandline_fade_ms: self.commandline_fade_ms, + zoom_wheel_reversed: self.zoom_wheel_reversed, + zoom_factor: self.zoom_factor, + texteditmode: self.texteditmode, + dimension_continue_mode: self.dimension_continue_mode, + qdim_snap_priority: self.quick_dimension_snap_priority, + annotation_auto_scale: self.annotation_auto_scale, }, 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 35e888006..14bbb2de6 100644 --- a/src/ui/window/options.rs +++ b/src/ui/window/options.rs @@ -28,6 +28,7 @@ pub enum OptionsTab { OpenAndSave, Display, Selection, + UserPreferences, Drawing, } @@ -48,6 +49,19 @@ pub struct AppPrefs { pub cliprompt_lines: i32, /// COMMANDLINEFADETIME: how long overlay history lines stay visible, in ms. pub commandline_fade_ms: i32, + /// ZOOMWHEEL: reverse the mouse-wheel zoom direction. + pub zoom_wheel_reversed: bool, + /// ZOOMFACTOR, 3..=100. + pub zoom_factor: i32, + /// TEXTEDITMODE: TEXTEDIT keeps prompting for the next object. + pub texteditmode: bool, + /// DIMCONTINUEMODE: continued dimensions inherit the base dimension's style. + pub dimension_continue_mode: i16, + /// QDIM extension-origin priority: 0 endpoints, 1 intersections. + pub qdim_snap_priority: u8, + /// ANNOAUTOSCALE, -4..=4. The sign is on/off; the magnitude selects which + /// objects a newly added scale reaches. + pub annotation_auto_scale: i8, } /// The Selection-card settings that live on `UserSettings` rather than on the @@ -995,11 +1009,153 @@ pub fn view_window<'a>( .spacing(0) .width(sizing.width); + + // ANNOAUTOSCALE's magnitude decides which objects a newly added scale + // reaches — 1 skips layers that are off, frozen, locked or frozen in the + // viewport, 2 keeps locked ones, 3 skips only locked, 4 takes everything. + // The sign is the on/off the status-bar pill flips, so the mode survives + // being switched off and back on. + let auto_scale_options = [ + (0i8, "Off"), + (1, "Skip objects on layers that are off, frozen or locked"), + (2, "Skip objects on layers that are off or frozen"), + (3, "Skip objects on locked layers"), + (4, "All annotative objects"), + ] + .into_iter() + .map(|(value, label)| Labelled { + value, + label: crate::t!(label).into_owned(), + }) + .collect::>(); + let selected_auto_scale = auto_scale_options + .iter() + .find(|choice| choice.value == prefs.annotation_auto_scale.max(0)) + .cloned(); + + let qdim_options = [ + (0u8, "Endpoints"), + (1, "Intersections"), + ] + .into_iter() + .map(|(value, label)| Labelled { + value, + label: crate::t!(label).into_owned(), + }) + .collect::>(); + let selected_qdim = qdim_options + .iter() + .find(|choice| choice.value == prefs.qdim_snap_priority) + .cloned(); + + let user_prefs = column![ + text(crate::t!("User Preferences")).size(15), + Space::new().height(10), + text(crate::t!("Zoom")).size(15), + Space::new().height(10), + row![ + iced::widget::checkbox(prefs.zoom_wheel_reversed) + .on_toggle(Message::ZoomWheelReversedChanged) + .size(15), + text(crate::t!("Reverse mouse wheel zoom (ZOOMWHEEL)")).size(12), + ] + .spacing(8) + .align_y(iced::Center), + Space::new().height(12), + row![ + text(crate::t!("Zoom factor")).size(12).width(150), + slider(3..=100, prefs.zoom_factor.clamp(3, 100), Message::ZoomFactorChanged) + .step(1) + .width(Fill), + text(prefs.zoom_factor.clamp(3, 100).to_string()).size(11).width(44), + ] + .spacing(10) + .align_y(iced::Center), + Space::new().height(6), + text(crate::t!("How far one wheel notch zooms (ZOOMFACTOR).")) + .size(11) + .width(sizing.width), + Space::new().height(24), + text(crate::t!("Text and Dimensions")).size(15), + Space::new().height(10), + row![ + iced::widget::checkbox(prefs.texteditmode) + .on_toggle(Message::TextEditModeChanged) + .size(15), + text(crate::t!("TEXTEDIT edits one object and ends (TEXTEDITMODE)")).size(12), + ] + .spacing(8) + .align_y(iced::Center), + Space::new().height(12), + row![ + iced::widget::checkbox(prefs.dimension_continue_mode == 1) + .on_toggle(Message::DimContinueModeChanged) + .size(15), + text(crate::t!( + "Continued dimensions inherit the base dimension's layer and style (DIMCONTINUEMODE)" + )) + .size(12), + ] + .spacing(8) + .align_y(iced::Center), + Space::new().height(12), + row![ + text(crate::t!("QDIM origin priority")).size(12).width(150), + iced::widget::pick_list(selected_qdim, qdim_options, |choice| choice.label.clone()) + .on_select(|choice| Message::QdimSnapPriorityChanged(choice.value)) + .width(Fill), + ] + .spacing(10) + .align_y(iced::Center), + Space::new().height(6), + text(crate::t!( + "Which points QDIM measures from. Also settable inside the command." + )) + .size(11) + .width(sizing.width), + Space::new().height(24), + text(crate::t!("Annotation")).size(15), + Space::new().height(10), + row![ + text(crate::t!("Add scales automatically")).size(12).width(150), + iced::widget::pick_list(selected_auto_scale, auto_scale_options, |choice| { + choice.label.clone() + }) + .on_select(|choice| Message::AnnoAutoScaleChanged(choice.value)) + .width(Fill), + ] + .spacing(10) + .align_y(iced::Center), + Space::new().height(6), + text(crate::t!( + "Which annotative objects pick up a newly set annotation scale (ANNOAUTOSCALE)." + )) + .size(11) + .width(sizing.width), + Space::new().height(24), + text(crate::t!("Drawing Units")).size(15), + Space::new().height(10), + row![ + text(crate::t!("Length, angle and insertion units")) + .size(12) + .width(Fill), + button(text(crate::t!("Drawing Units…")).size(11)) + .on_press(Message::OpenDrawingUnits) + .padding([4, 10]) + .style(button::secondary), + ] + .spacing(10) + .align_y(iced::Center), + ] + .spacing(0) + .width(sizing.width); + let content: Element<'a, Message> = match active_tab { OptionsTab::General => general.into(), OptionsTab::Display => display_element.into(), OptionsTab::Selection => selection.into(), OptionsTab::OpenAndSave => open_and_save.into(), + OptionsTab::UserPreferences => user_prefs.into(), OptionsTab::Drawing => drawing.into(), }; @@ -1019,6 +1175,7 @@ pub fn view_window<'a>( tab_button(crate::t!("Open and Save"), OptionsTab::OpenAndSave), tab_button(crate::t!("Display"), OptionsTab::Display), tab_button(crate::t!("Selection"), OptionsTab::Selection), + tab_button(crate::t!("User Preferences"), OptionsTab::UserPreferences), tab_button(crate::t!("Drawing"), OptionsTab::Drawing), ] .spacing(2)