forked from 1b-agent/opencadstudio-upstream
fix(properties): scope asym-scale opt-out per tab
props_asym_scale was app-global keyed by raw handle values, but fresh documents restart numbering at seed 1, leaking one tab's unchecked Uniform box into another tab reusing the value. The set moves to DocumentTab; all uses tab-scoped. Also removes a dead destructure left in overlay.rs. Test: asym_scale_opt_out_does_not_leak_across_tabs with handle-reuse premise assert (RED first). Full suite: 2025 passed / 0 failed / 25 ignored, zero warnings.
This commit is contained in:
1 parent
6ad3183b3d
commit
d1da26feb6
5 files changed
+50
-10
No files matched your search
@@ -206,6 +206,12 @@ pub(super) struct DocumentTab {
|
||||
pub(super) dyn_active: usize,
|
||||
pub(super) history: HistoryState,
|
||||
pub(super) active_layer: String,
|
||||
/// Block references whose properties panel shows per-axis Scale X/Y/Z even
|
||||
/// though the three factors are currently equal — the user unchecked the
|
||||
/// "Uniform scale" box for them (#427). Per-tab: fresh documents restart
|
||||
/// handle numbering, so an app-global set keyed by raw handle leaks one
|
||||
/// tab's opt-out into another tab reusing the value (#47).
|
||||
pub(super) props_asym_scale: std::collections::HashSet<u64>,
|
||||
/// Node graph shown by the command line's graph button.
|
||||
pub(super) graph: crate::ui::node_graph::Graph,
|
||||
/// Currently active UCS. `None` means WCS (identity transform).
|
||||
@@ -649,6 +655,7 @@ impl DocumentTab {
|
||||
dyn_active: 0,
|
||||
history: HistoryState::default(),
|
||||
active_layer: "0".to_string(),
|
||||
props_asym_scale: std::collections::HashSet::new(),
|
||||
graph: Default::default(),
|
||||
active_ucs: None,
|
||||
sketch_session: None,
|
||||
|
||||
@@ -419,10 +419,6 @@ pub(super) struct OpenCADStudio {
|
||||
discussions: Vec<crate::discussions::DiscussionEntry>,
|
||||
/// True while the boot-time Discussions refresh is still in flight.
|
||||
discussions_loading: bool,
|
||||
/// Block references whose properties panel shows per-axis Scale X/Y/Z even
|
||||
/// though the three factors are currently equal — the user unchecked the
|
||||
/// "Uniform scale" box for them (#427). Keyed by entity handle.
|
||||
props_asym_scale: std::collections::HashSet<u64>,
|
||||
/// Collapsed Properties-panel section titles. This belongs to the app,
|
||||
/// rather than an individual document tab, so the same view preference is
|
||||
/// used by every currently open drawing/project.
|
||||
@@ -4110,7 +4106,6 @@ impl OpenCADStudio {
|
||||
videos_loading: false,
|
||||
discussions: Vec::new(),
|
||||
discussions_loading: false,
|
||||
props_asym_scale: std::collections::HashSet::new(),
|
||||
collapsed_property_sections: rustc_hash::FxHashSet::default(),
|
||||
start_section: StartSection::default(),
|
||||
start_action_w: std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)),
|
||||
|
||||
+40
-1
@@ -463,7 +463,7 @@ impl OpenCADStudio {
|
||||
if let codec::EntityType::Insert(ins) = entity {
|
||||
let eq = (ins.x_scale() - ins.y_scale()).abs() < 1e-12
|
||||
&& (ins.x_scale() - ins.z_scale()).abs() < 1e-12;
|
||||
let uniform = eq && !self.props_asym_scale.contains(&handle.value());
|
||||
let uniform = eq && !self.tabs[i].props_asym_scale.contains(&handle.value());
|
||||
for section in sections.iter_mut() {
|
||||
let Some(xi) = section.props.iter().position(|p| p.field == "x_scale")
|
||||
else {
|
||||
@@ -4373,6 +4373,45 @@ fn apply_insert_unit_scale(ins: &mut codec::entities::Insert, ratio: f64) -> boo
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod asym_scale_tests {
|
||||
// #47: the uniform-scale opt-out must be per-tab. Fresh documents restart
|
||||
// handle numbering (seed 1), so two tabs hand out identical handles — an
|
||||
// app-global set leaks one tab's opt-out into the other.
|
||||
use crate::app::OpenCADStudio;
|
||||
|
||||
fn tab_with_insert(app: &mut OpenCADStudio) -> (usize, codec::Handle) {
|
||||
app.tab_counter += 1;
|
||||
let n = app.tab_counter;
|
||||
app.tabs
|
||||
.push(crate::app::document::DocumentTab::new_drawing(n));
|
||||
let idx = app.tabs.len() - 1;
|
||||
app.active_tab = idx;
|
||||
let ins =
|
||||
codec::entities::Insert::new("B", codec::types::Vector3::ZERO);
|
||||
let h = app
|
||||
.commit_entity_handle(codec::EntityType::Insert(ins))
|
||||
.expect("insert commits");
|
||||
(idx, h)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asym_scale_opt_out_does_not_leak_across_tabs() {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
let (a, ha) = tab_with_insert(&mut app);
|
||||
let (b, hb) = tab_with_insert(&mut app);
|
||||
assert_eq!(
|
||||
ha, hb,
|
||||
"premise: identically built fresh docs reuse handle values"
|
||||
);
|
||||
app.tabs[a].props_asym_scale.insert(ha.value());
|
||||
assert!(
|
||||
!app.tabs[b].props_asym_scale.contains(&hb.value()),
|
||||
"tab B must not see tab A's opt-out"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod insert_unit_scale_tests {
|
||||
use super::{apply_insert_unit_scale, format_unit_factor, insert_unit_scale, insunits_to_mm};
|
||||
|
||||
@@ -6895,11 +6895,11 @@ impl OpenCADStudio {
|
||||
};
|
||||
let Some((sx, sy, sz)) = scales else { return };
|
||||
let eq = (sx - sy).abs() < 1e-12 && (sx - sz).abs() < 1e-12;
|
||||
let checked = eq && !app.props_asym_scale.contains(&handle.value());
|
||||
let checked = eq && !app.tabs[i].props_asym_scale.contains(&handle.value());
|
||||
if checked {
|
||||
app.props_asym_scale.insert(handle.value());
|
||||
app.tabs[i].props_asym_scale.insert(handle.value());
|
||||
} else {
|
||||
app.props_asym_scale.remove(&handle.value());
|
||||
app.tabs[i].props_asym_scale.remove(&handle.value());
|
||||
if let Some(codec::EntityType::Insert(ins)) =
|
||||
app.tabs[i].scene.document.get_entity_mut(handle)
|
||||
{
|
||||
|
||||
@@ -2961,7 +2961,6 @@ fn draw_axes(
|
||||
axes: (Vec3, Vec3, Vec3),
|
||||
bg_luminance: f32,
|
||||
) {
|
||||
let (ax, ay, az) = axes;
|
||||
let axis_stroke = |r: f32, g: f32, b: f32| canvas::Stroke {
|
||||
width: 1.5,
|
||||
style: canvas::Style::Solid(Color { r, g, b, a: 0.85 }),
|
||||
|
||||
Reference in new issue
Block a user