feat(edit): STRETCH crossing window selects objects implicitly (#338)

Bare STRETCH used to need a separate object-selection round before the
crossing window. Now the window itself picks the objects: with no prior
selection the command emits StretchWindow, the host gathers entities
whose world AABB touches the window (locked layers excluded) and
restarts at the base-point step. Over-selection is harmless since only
points inside the window move. The noun-verb flow (select first, then
STRETCH) is unchanged.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Fable 5 committed 2026-07-21 22:35:35 +03:00
1 parent 5383c64d5d
commit dc10c5dfba
4 files changed
+94 -15

No files matched your search

+43
View File
@@ -1404,6 +1404,49 @@ impl OpenCADStudio {
self.restore_pre_cmd_tangent();
return self.on_quick_print_handles(handles);
}
CmdResult::StretchWindow { win_min, win_max } => {
// Implicit STRETCH selection (#338): the crossing window drawn
// with no prior selection picks the objects itself. Entities
// whose world AABB touches the window are handed back to the
// command at the base-point step — over-selection is harmless,
// since only points INSIDE the window move anyway.
let mut handles: Vec<Handle> = Vec::new();
{
let scene = &self.tabs[i].scene;
let mut seen: rustc_hash::FxHashSet<Handle> = rustc_hash::FxHashSet::default();
for w in scene.entity_wires().iter() {
let Some(h) = crate::scene::Scene::handle_from_wire_name(&w.name) else {
continue;
};
if !seen.insert(h) || scene.is_layer_locked(h) {
continue;
}
let [ax, ay, bx, by] = w.aabb;
if ax as f64 <= win_max.x
&& bx as f64 >= win_min.x
&& ay as f64 <= win_max.y
&& by as f64 >= win_min.y
{
handles.push(h);
}
}
}
if handles.is_empty() {
self.command_line
.push_output("STRETCH: nothing crosses the window.");
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.tabs[i].scene.clear_preview_wire();
self.restore_pre_cmd_tangent();
} else {
use crate::command::CadCommand;
use crate::modules::draw::modify::stretch::StretchCommand;
let wires = self.tabs[i].scene.wire_models_for(&handles);
let cmd = StretchCommand::with_window(handles, wires, win_min, win_max);
self.command_line.push_info(&CadCommand::prompt(&cmd));
self.tabs[i].active_cmd = Some(Box::new(cmd));
}
}
CmdResult::StretchEntities {
handles,
win_min,