forked from 1b-agent/opencadstudio-upstream
feat(area): support multi-object selection
This commit is contained in:
1 parent
48332ee807
commit
5662e07303
8 files changed
+427
-100
No files matched your search
@@ -1,9 +1,19 @@
|
||||
use super::{Message, OpenCADStudio};
|
||||
use crate::command::{CmdResult, StepInput};
|
||||
use crate::command::{CmdResult, SelectionEntity, StepInput};
|
||||
use acadrust::Handle;
|
||||
use iced::Task;
|
||||
|
||||
impl OpenCADStudio {
|
||||
fn refresh_area_preview(&mut self, i: usize) {
|
||||
let regions = self.tabs[i]
|
||||
.active_cmd
|
||||
.as_ref()
|
||||
.and_then(|command| command.area_preview_regions());
|
||||
if let Some(regions) = regions {
|
||||
self.tabs[i].scene.set_area_preview_regions(®ions);
|
||||
}
|
||||
}
|
||||
|
||||
/// Point supplied by a bare Enter before LINE/PLINE's first click. Prefer
|
||||
/// the current endpoint of the most recently created path drawable in the
|
||||
/// active space. A loaded drawing has no runtime anchor, so recover its
|
||||
@@ -258,6 +268,31 @@ impl OpenCADStudio {
|
||||
self.reset_tracking_after_point();
|
||||
self.push_ucs_to_cmd(i);
|
||||
}
|
||||
if let StepInput::SelectionComplete(handles) = &input {
|
||||
let entities = {
|
||||
let scene = &self.tabs[i].scene;
|
||||
handles
|
||||
.iter()
|
||||
.filter_map(|handle| {
|
||||
scene.document.get_entity(*handle).cloned().map(|entity| {
|
||||
let surface_area = scene
|
||||
.meshes
|
||||
.get(handle)
|
||||
.or_else(|| scene.block_meshes.get(handle))
|
||||
.map(|mesh| mesh.metrics.surface_area);
|
||||
SelectionEntity {
|
||||
handle: *handle,
|
||||
entity,
|
||||
surface_area,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
if let Some(command) = self.tabs[i].active_cmd.as_mut() {
|
||||
command.inject_selection_entities(entities);
|
||||
}
|
||||
}
|
||||
let ctrl = self.ctrl_down;
|
||||
let shift = self.shift_down;
|
||||
let result: Option<CmdResult> = {
|
||||
@@ -399,14 +434,7 @@ impl OpenCADStudio {
|
||||
.into_iter()
|
||||
.map(|(h, _)| h)
|
||||
.collect();
|
||||
let result = self.tabs[i]
|
||||
.active_cmd
|
||||
.as_mut()
|
||||
.map(|cmd| cmd.on_selection_complete(handles));
|
||||
Some(match result {
|
||||
Some(r) => self.apply_cmd_result(r),
|
||||
None => Task::none(),
|
||||
})
|
||||
Some(self.feed_command(StepInput::SelectionComplete(handles)))
|
||||
}
|
||||
|
||||
pub(super) fn feed_active_cmd(&mut self, token: &str) {
|
||||
@@ -557,6 +585,7 @@ impl OpenCADStudio {
|
||||
// and typed digits land in it rather than the command line,
|
||||
// instead of waiting for the next cursor move to resync.
|
||||
self.sync_dyn_fields();
|
||||
self.refresh_area_preview(i);
|
||||
}
|
||||
CmdResult::Preview(wire) => {
|
||||
self.tabs[i].scene.set_preview_wires(vec![wire]);
|
||||
@@ -1792,11 +1821,33 @@ impl OpenCADStudio {
|
||||
CmdResult::ReportMeasurement(msg) => {
|
||||
self.tabs[i].snap_result = None;
|
||||
self.tabs[i].scene.clear_preview_wire();
|
||||
self.refresh_area_preview(i);
|
||||
self.command_line.push_output(&msg);
|
||||
if let Some(prompt) = self.tabs[i].active_cmd.as_ref().map(|c| c.prompt()) {
|
||||
self.command_line.push_info(&prompt);
|
||||
}
|
||||
}
|
||||
CmdResult::ReportMeasurementAndDeselect(msg) => {
|
||||
self.tabs[i].snap_result = None;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.clear_preview_wire();
|
||||
self.refresh_area_preview(i);
|
||||
self.refresh_properties();
|
||||
self.command_line.push_output(&msg);
|
||||
if let Some(prompt) = self.tabs[i].active_cmd.as_ref().map(|c| c.prompt()) {
|
||||
self.command_line.push_info(&prompt);
|
||||
}
|
||||
}
|
||||
CmdResult::DeselectAndContinue => {
|
||||
self.tabs[i].snap_result = None;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.clear_preview_wire();
|
||||
self.refresh_area_preview(i);
|
||||
self.refresh_properties();
|
||||
if let Some(prompt) = self.tabs[i].active_cmd.as_ref().map(|c| c.prompt()) {
|
||||
self.command_line.push_info(&prompt);
|
||||
}
|
||||
}
|
||||
CmdResult::AlignSelected {
|
||||
handles,
|
||||
src1,
|
||||
|
||||
+14
-10
@@ -2417,6 +2417,11 @@ impl OpenCADStudio {
|
||||
.as_ref()
|
||||
.map(|c| c.is_selection_gathering())
|
||||
.unwrap_or(false);
|
||||
let selection_pick_add = self.pick_add
|
||||
|| self.tabs[i]
|
||||
.active_cmd
|
||||
.as_ref()
|
||||
.is_some_and(|command| command.selection_forces_add());
|
||||
// A committed window corner must stay free of the Ortho/Polar
|
||||
// lock too, so the picked rectangle isn't flattened (#291).
|
||||
let is_window_corner = self.tabs[i]
|
||||
@@ -3011,7 +3016,7 @@ impl OpenCADStudio {
|
||||
self.tabs[i].scene.deselect_entity(*h);
|
||||
}
|
||||
} else {
|
||||
if !self.pick_add && !handles.is_empty() {
|
||||
if !selection_pick_add && !handles.is_empty() {
|
||||
self.tabs[i].scene.deselect_all();
|
||||
}
|
||||
for h in &handles {
|
||||
@@ -3142,7 +3147,7 @@ impl OpenCADStudio {
|
||||
// PICKADD 0 (#226): a plain marquee REPLACES
|
||||
// the selection (empty results still leave it
|
||||
// alone, matching the box rule).
|
||||
if !self.pick_add && !handles.is_empty() {
|
||||
if !selection_pick_add && !handles.is_empty() {
|
||||
self.tabs[i].scene.deselect_all();
|
||||
}
|
||||
for h in &handles {
|
||||
@@ -3271,7 +3276,7 @@ impl OpenCADStudio {
|
||||
// REPLACES the selection instead and
|
||||
// Shift+click toggles membership.
|
||||
if self.shift_down {
|
||||
if !self.pick_add
|
||||
if !selection_pick_add
|
||||
&& !self.tabs[i].scene.selected.contains(&handle)
|
||||
{
|
||||
self.tabs[i].scene.select_entity(handle, false);
|
||||
@@ -3280,7 +3285,9 @@ impl OpenCADStudio {
|
||||
self.tabs[i].scene.deselect_entity(handle);
|
||||
}
|
||||
} else {
|
||||
self.tabs[i].scene.select_entity(handle, !self.pick_add);
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.select_entity(handle, !selection_pick_add);
|
||||
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
||||
}
|
||||
self.refresh_properties();
|
||||
@@ -3294,7 +3301,7 @@ impl OpenCADStudio {
|
||||
// selection.
|
||||
// PICKADD 0 (#226): OS convention — the
|
||||
// empty click also drops the selection.
|
||||
if !self.pick_add && !self.shift_down {
|
||||
if !selection_pick_add && !self.shift_down {
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.refresh_properties();
|
||||
}
|
||||
@@ -3413,7 +3420,7 @@ impl OpenCADStudio {
|
||||
self.tabs[i].scene.deselect_entity(*h);
|
||||
}
|
||||
} else {
|
||||
if !self.pick_add && !handles.is_empty() {
|
||||
if !selection_pick_add && !handles.is_empty() {
|
||||
self.tabs[i].scene.deselect_all();
|
||||
}
|
||||
for h in &handles {
|
||||
@@ -3447,10 +3454,7 @@ impl OpenCADStudio {
|
||||
.into_iter()
|
||||
.map(|(h, _)| h)
|
||||
.collect();
|
||||
if let Some(cmd) = self.tabs[i].active_cmd.as_mut() {
|
||||
let result = cmd.on_selection_complete(handles);
|
||||
return self.apply_cmd_result(result);
|
||||
}
|
||||
return self.feed_command(crate::command::StepInput::SelectionComplete(handles));
|
||||
}
|
||||
|
||||
// ── Double-click in Model Space: DDEDIT for Text/MText ────
|
||||
|
||||
Reference in new issue
Block a user