forked from 1b-agent/opencadstudio-upstream
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
caec8dc53b
9 files changed
+1562
-342
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));
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ pub use automation::{export_headless, serve};
|
||||
mod command_driver;
|
||||
pub(crate) mod commands;
|
||||
mod document;
|
||||
mod drafting_settings;
|
||||
pub(crate) mod expr_eval;
|
||||
mod find_replace;
|
||||
pub(crate) mod helpers;
|
||||
@@ -415,6 +416,9 @@ pub(super) struct OpenCADStudio {
|
||||
win_size: (f32, f32),
|
||||
snapper: Snapper,
|
||||
snap_popup_open: bool,
|
||||
drafting_settings_state: Option<crate::ui::window::drafting_settings::DraftingSettingsState>,
|
||||
drafting_settings_saved: Option<crate::ui::window::drafting_settings::DraftingSettingsState>,
|
||||
drafting_settings_close_confirm: bool,
|
||||
scale_popup_open: bool,
|
||||
/// True while the polar-tracking angle picker is open.
|
||||
polar_popup_open: bool,
|
||||
@@ -2619,6 +2623,29 @@ pub enum Message {
|
||||
SnapSelectAll,
|
||||
/// Disable all snap modes.
|
||||
SnapClearAll,
|
||||
// ── Drafting Settings Dialog ──────────────────────────────────────────
|
||||
DraftingSettingsTabChanged(crate::ui::window::drafting_settings::DraftingSettingsTab),
|
||||
DraftingSettingsToggleGrid,
|
||||
DraftingSettingsToggleSnap,
|
||||
DraftingSettingsToggleIsometric,
|
||||
DraftingSettingsSetIsoPlane(crate::app::settings::IsoPlane),
|
||||
DraftingSettingsResetRotation,
|
||||
DraftingSettingsTogglePolar,
|
||||
DraftingSettingsToggleOrtho,
|
||||
DraftingSettingsToggleOsnap,
|
||||
DraftingSettingsToggleOtrack,
|
||||
DraftingSettingsToggleSnapMode(crate::snap::SnapType),
|
||||
DraftingSettingsSnapSelectAll,
|
||||
DraftingSettingsSnapClearAll,
|
||||
DraftingSettingsToggle3dOsnap,
|
||||
DraftingSettingsToggleDynInput,
|
||||
DraftingSettingsToggleQuickProps,
|
||||
DraftingSettingsToggleSelCycling,
|
||||
DraftingSettingsApply,
|
||||
DraftingSettingsOk,
|
||||
DraftingSettingsClose,
|
||||
DraftingSettingsCloseDiscard,
|
||||
DraftingSettingsCloseKeep,
|
||||
/// Toggle a ribbon dropdown open/closed.
|
||||
ToggleRibbonDropdown(String),
|
||||
/// Toggle a collapsed ribbon panel's flyout open/closed (by panel title).
|
||||
@@ -3548,6 +3575,9 @@ impl OpenCADStudio {
|
||||
win_size: (1280.0, 720.0),
|
||||
snapper: Snapper::default(),
|
||||
snap_popup_open: false,
|
||||
drafting_settings_state: None,
|
||||
drafting_settings_saved: None,
|
||||
drafting_settings_close_confirm: false,
|
||||
scale_popup_open: false,
|
||||
polar_popup_open: false,
|
||||
polar_custom_input: String::new(),
|
||||
|
||||
@@ -171,6 +171,9 @@ impl OpenCADStudio {
|
||||
}
|
||||
if self.active_modal == Some(DraftingSettings) {
|
||||
self.snap_popup_open = false;
|
||||
self.drafting_settings_close_confirm = false;
|
||||
self.drafting_settings_state = None;
|
||||
self.drafting_settings_saved = None;
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if self.active_modal == Some(FileInUse) {
|
||||
@@ -4072,9 +4075,17 @@ impl OpenCADStudio {
|
||||
}
|
||||
Message::ToggleSnapPopup => {
|
||||
if self.active_modal == Some(super::ModalKind::DraftingSettings) {
|
||||
if !self.drafting_settings_close_confirm && self.drafting_settings_dirty() {
|
||||
self.drafting_settings_close_confirm = true;
|
||||
return Task::none();
|
||||
}
|
||||
self.close_active_modal();
|
||||
self.snap_popup_open = false;
|
||||
} else {
|
||||
let st = crate::ui::window::drafting_settings::DraftingSettingsState::from_app(self);
|
||||
self.drafting_settings_saved = Some(st.clone());
|
||||
self.drafting_settings_state = Some(st);
|
||||
self.drafting_settings_close_confirm = false;
|
||||
self.active_modal = Some(super::ModalKind::DraftingSettings);
|
||||
self.snap_popup_open = true;
|
||||
}
|
||||
@@ -4096,6 +4107,147 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
// ── Drafting Settings Dialog ──────────────────────────────────
|
||||
Message::DraftingSettingsTabChanged(tab) => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.active_tab = tab;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleGrid => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.grid_on = !state.grid_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleSnap => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.snap_on = !state.snap_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleIsometric => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.isometric = !state.isometric;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsSetIsoPlane(plane) => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.isometric = true;
|
||||
state.iso_plane = plane;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsResetRotation => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.snap_angle_deg = 0.0;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsTogglePolar => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.polar_on = !state.polar_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleOrtho => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.ortho_on = !state.ortho_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleOsnap => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.osnap_on = !state.osnap_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleOtrack => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.otrack_on = !state.otrack_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleSnapMode(snap_type) => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
if !state.snap_modes.remove(&snap_type) {
|
||||
state.snap_modes.insert(snap_type);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsSnapSelectAll => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
for &(snap_type, _, _) in crate::snap::ALL_SNAP_MODES {
|
||||
state.snap_modes.insert(snap_type);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsSnapClearAll => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.snap_modes.clear();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggle3dOsnap => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.osnap3d_on = !state.osnap3d_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleDynInput => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.dyn_input_on = !state.dyn_input_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleQuickProps => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.quick_props_on = !state.quick_props_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsToggleSelCycling => {
|
||||
if let Some(state) = &mut self.drafting_settings_state {
|
||||
state.selection_cycling_on = !state.selection_cycling_on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsApply => {
|
||||
self.apply_drafting_settings();
|
||||
self.drafting_settings_saved = self.drafting_settings_state.clone();
|
||||
self.persist_settings_if_changed();
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsOk => {
|
||||
self.apply_drafting_settings();
|
||||
self.drafting_settings_saved = self.drafting_settings_state.clone();
|
||||
self.drafting_settings_close_confirm = false;
|
||||
self.persist_settings_if_changed();
|
||||
self.close_active_modal();
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsClose => {
|
||||
if !self.drafting_settings_close_confirm && self.drafting_settings_dirty() {
|
||||
self.drafting_settings_close_confirm = true;
|
||||
return Task::none();
|
||||
}
|
||||
self.drafting_settings_close_confirm = false;
|
||||
self.close_active_modal();
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsCloseDiscard => {
|
||||
self.drafting_settings_close_confirm = false;
|
||||
self.close_active_modal();
|
||||
Task::none()
|
||||
}
|
||||
Message::DraftingSettingsCloseKeep => {
|
||||
self.drafting_settings_close_confirm = false;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
// ── Ribbon dropdowns ──────────────────────────────────────────
|
||||
Message::ToggleRibbonDropdown(id) => {
|
||||
if self.tabs[self.active_tab].is_start {
|
||||
@@ -6655,6 +6807,14 @@ impl OpenCADStudio {
|
||||
return Task::none();
|
||||
}
|
||||
self.shortcut_close_confirm = false;
|
||||
if self.active_modal == Some(super::ModalKind::DraftingSettings)
|
||||
&& !self.drafting_settings_close_confirm
|
||||
&& self.drafting_settings_dirty()
|
||||
{
|
||||
self.drafting_settings_close_confirm = true;
|
||||
return Task::none();
|
||||
}
|
||||
self.drafting_settings_close_confirm = false;
|
||||
let resume_open_queue = self.active_modal == Some(super::ModalKind::Recovery);
|
||||
self.close_active_modal();
|
||||
if resume_open_queue {
|
||||
|
||||
+22
-19
@@ -286,25 +286,28 @@ impl OpenCADStudio {
|
||||
)
|
||||
},
|
||||
),
|
||||
super::super::ModalKind::DraftingSettings => sized_flow(
|
||||
ex,
|
||||
520,
|
||||
560,
|
||||
|flow| {
|
||||
crate::ui::window::drafting_settings::view_window(
|
||||
&self.snapper,
|
||||
self.show_grid,
|
||||
self.snapper.grid_snap(),
|
||||
self.ortho_mode,
|
||||
self.polar_mode,
|
||||
self.snapper.otrack_enabled,
|
||||
self.isometric_drafting,
|
||||
self.iso_plane,
|
||||
self.snap_angle_deg,
|
||||
flow,
|
||||
)
|
||||
},
|
||||
),
|
||||
super::super::ModalKind::DraftingSettings => {
|
||||
let state = self.drafting_settings_state.as_ref();
|
||||
let dirty = self.drafting_settings_dirty();
|
||||
let confirm = self.drafting_settings_close_confirm;
|
||||
sized_flow(
|
||||
ex,
|
||||
700,
|
||||
480,
|
||||
|flow| {
|
||||
if let Some(state) = state {
|
||||
crate::ui::window::drafting_settings::view_window(
|
||||
state,
|
||||
dirty,
|
||||
confirm,
|
||||
flow,
|
||||
)
|
||||
} else {
|
||||
iced::widget::Space::new().into()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
super::super::ModalKind::FindReplace => automatic_flow(ex, |flow| {
|
||||
crate::ui::window::find_replace::view_window(
|
||||
&self.find_replace.search,
|
||||
|
||||
Reference in new issue
Block a user