forked from 1b-agent/opencadstudio-upstream
feat(ui): modernize DSETTINGS dialog with tabbed layout and action controls
- Redesign drafting settings window to landscape 700x480 proportions while preserving interactive resizing - Add 7-tab navigation: Snap and Grid, Polar Tracking, Object Snap, 3D Object Snap, Dynamic Input, Quick Properties, and Selection Cycling - Distribute existing drafting modes, snap options, and isometric tools into their respective tabs - Implement OK, Apply, and Close action buttons with unsaved changes confirmation guard
This commit is contained in:
1 parent
ddeddeca31
commit
a0d784502a
5 files changed
+1024
-118
No files matched your search
@@ -0,0 +1,170 @@
|
||||
use super::OpenCADStudio;
|
||||
use crate::ui::window::drafting_settings::{DraftingSettingsState, DraftingSettingsTab};
|
||||
|
||||
impl DraftingSettingsState {
|
||||
pub(crate) fn from_app(app: &OpenCADStudio) -> Self {
|
||||
Self {
|
||||
active_tab: DraftingSettingsTab::SnapAndGrid,
|
||||
snap_on: app.snapper.grid_snap(),
|
||||
grid_on: app.show_grid,
|
||||
isometric: app.isometric_drafting,
|
||||
iso_plane: app.iso_plane,
|
||||
snap_angle_deg: app.snap_angle_deg,
|
||||
polar_on: app.polar_mode,
|
||||
ortho_on: app.ortho_mode,
|
||||
polar_increment_deg: app.polar_increment_deg,
|
||||
osnap_on: app.snapper.snap_enabled,
|
||||
otrack_on: app.snapper.otrack_enabled,
|
||||
snap_modes: app.snapper.enabled.clone(),
|
||||
osnap3d_on: false,
|
||||
dyn_input_on: app.dyn_input,
|
||||
quick_props_on: app.quick_properties,
|
||||
selection_cycling_on: app.selection_cycling,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenCADStudio {
|
||||
pub(super) fn drafting_settings_dirty(&self) -> bool {
|
||||
match (&self.drafting_settings_state, &self.drafting_settings_saved) {
|
||||
(Some(curr), Some(saved)) => curr.is_dirty(saved),
|
||||
(Some(_), None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn apply_drafting_settings(&mut self) {
|
||||
if let Some(state) = &self.drafting_settings_state {
|
||||
self.show_grid = state.grid_on;
|
||||
self.snapper.grid_snap_on = state.snap_on;
|
||||
self.isometric_drafting = state.isometric;
|
||||
self.iso_plane = state.iso_plane;
|
||||
self.snap_angle_deg = state.snap_angle_deg;
|
||||
self.polar_mode = state.polar_on;
|
||||
self.ortho_mode = state.ortho_on;
|
||||
self.polar_increment_deg = state.polar_increment_deg;
|
||||
self.snapper.snap_enabled = state.osnap_on;
|
||||
self.snapper.otrack_enabled = state.otrack_on;
|
||||
self.snapper.enabled = state.snap_modes.clone();
|
||||
self.dyn_input = state.dyn_input_on;
|
||||
self.quick_properties = state.quick_props_on;
|
||||
self.selection_cycling = state.selection_cycling_on;
|
||||
self.sync_vport_display(self.active_tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_drafting_settings_tab_switching_not_dirty() {
|
||||
let state1 = DraftingSettingsState {
|
||||
active_tab: DraftingSettingsTab::SnapAndGrid,
|
||||
snap_on: false,
|
||||
grid_on: true,
|
||||
isometric: false,
|
||||
iso_plane: crate::app::settings::IsoPlane::Left,
|
||||
snap_angle_deg: 0.0,
|
||||
polar_on: false,
|
||||
ortho_on: false,
|
||||
polar_increment_deg: 15.0,
|
||||
osnap_on: true,
|
||||
otrack_on: false,
|
||||
snap_modes: rustc_hash::FxHashSet::default(),
|
||||
osnap3d_on: false,
|
||||
dyn_input_on: false,
|
||||
quick_props_on: false,
|
||||
selection_cycling_on: false,
|
||||
};
|
||||
let mut state2 = state1.clone();
|
||||
assert!(!state2.is_dirty(&state1));
|
||||
|
||||
// Switching tabs should NOT mark it dirty
|
||||
state2.active_tab = DraftingSettingsTab::ObjectSnap;
|
||||
assert!(!state2.is_dirty(&state1));
|
||||
|
||||
// Toggling a setting should mark it dirty
|
||||
state2.grid_on = false;
|
||||
assert!(state2.is_dirty(&state1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drafting_settings_dirty_toggles() {
|
||||
let base = DraftingSettingsState {
|
||||
active_tab: DraftingSettingsTab::SnapAndGrid,
|
||||
snap_on: false,
|
||||
grid_on: true,
|
||||
isometric: false,
|
||||
iso_plane: crate::app::settings::IsoPlane::Left,
|
||||
snap_angle_deg: 0.0,
|
||||
polar_on: false,
|
||||
ortho_on: false,
|
||||
polar_increment_deg: 15.0,
|
||||
osnap_on: true,
|
||||
otrack_on: false,
|
||||
snap_modes: rustc_hash::FxHashSet::default(),
|
||||
osnap3d_on: false,
|
||||
dyn_input_on: false,
|
||||
quick_props_on: false,
|
||||
selection_cycling_on: false,
|
||||
};
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.snap_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.isometric = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.iso_plane = crate::app::settings::IsoPlane::Top;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.snap_angle_deg = 45.0;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.polar_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.ortho_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.polar_increment_deg = 30.0;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.osnap_on = false;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.otrack_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.snap_modes.insert(crate::snap::SnapType::Endpoint);
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.osnap3d_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.dyn_input_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.quick_props_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
|
||||
let mut modded = base.clone();
|
||||
modded.selection_cycling_on = true;
|
||||
assert!(modded.is_dirty(&base));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user