Support tracking and direct distance input for grip editing
This commit is contained in:
parent
6752df6ea4
commit
62457be90e
4 changed files with 231 additions and 11 deletions
|
|
@ -281,6 +281,95 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
|||
self.refresh_properties();
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
// Direct-distance entry while a normal grip stretch is active.
|
||||
//
|
||||
// The live grip-drag path has already resolved OSNAP / OTRACK /
|
||||
// Extension / Polar / Ortho into `last_cursor_world`. A typed scalar
|
||||
// therefore means: move from the grip's original position by that
|
||||
// distance along the currently indicated direction.
|
||||
{
|
||||
let i = self.active_tab;
|
||||
|
||||
if let Some(grip) = self.tabs[i].active_grip.clone() {
|
||||
if grip.mode == GripEditMode::Stretch {
|
||||
let text =
|
||||
crate::app::expr_eval::eval_to_string(self.command_line.input.trim());
|
||||
|
||||
if let Some(dist) = crate::app::expr_eval::eval_number(text.trim()) {
|
||||
let cursor = self.tabs[i].last_cursor_world;
|
||||
|
||||
// If the cursor is following OTRACK or Extension, use the actual
|
||||
// reference ray that is currently driving the cursor. Otherwise
|
||||
// fall back to the direction from the original grip position,
|
||||
// which covers Polar / Ortho / free direct-distance entry.
|
||||
let target = if let Some((base, dir)) = self.active_distance_ray(i) {
|
||||
base + dir * dist
|
||||
} else {
|
||||
let direction = cursor - grip.origin_world;
|
||||
let len = direction.length();
|
||||
|
||||
if len <= 1e-12 {
|
||||
self.command_line.push_error(
|
||||
"Move the cursor in a direction before entering a distance.",
|
||||
);
|
||||
return self.focus_cmd_input();
|
||||
}
|
||||
|
||||
let dir = direction / len;
|
||||
grip.origin_world + dir * dist
|
||||
};
|
||||
|
||||
// The entity is already being edited live. Apply only the
|
||||
// incremental movement from its current grip position to the
|
||||
// exact typed-distance position.
|
||||
let delta = target - grip.last_world;
|
||||
|
||||
let actions: Vec<_> = grip
|
||||
.targets
|
||||
.iter()
|
||||
.map(|target_grip| {
|
||||
let apply = if target_grip.is_translate {
|
||||
GripApply::Translate(delta)
|
||||
} else {
|
||||
GripApply::Absolute(target_grip.last_world + delta)
|
||||
};
|
||||
|
||||
(
|
||||
target_grip.handle,
|
||||
target_grip.grip_id,
|
||||
apply,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (handle, grip_id, apply) in actions {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.apply_grip(handle, grip_id, apply);
|
||||
}
|
||||
|
||||
// Keep the live GripEdit state synchronized so the normal
|
||||
// grip commit path sees the exact final position.
|
||||
if let Some(active) = self.tabs[i].active_grip.as_mut() {
|
||||
active.last_world = target;
|
||||
|
||||
for target_grip in &mut active.targets {
|
||||
target_grip.last_world += delta;
|
||||
}
|
||||
}
|
||||
|
||||
self.tabs[i].last_cursor_world = target;
|
||||
self.command_line.input.clear();
|
||||
self.tabs[i].dirty = true;
|
||||
|
||||
// Reuse the existing click-move-click grip finalization:
|
||||
// undo grouping, preview restoration, grip cleanup, etc.
|
||||
return self.on_viewport_left_release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Interactive VPORTS: the entry after a bare `VPORTS` is the
|
||||
// tiled configuration. Empty input defaults to SINGLE.
|
||||
if self.awaiting_vports {
|
||||
|
|
@ -386,10 +475,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
|||
return self.feed_command(crate::command::StepInput::Enter);
|
||||
}
|
||||
|
||||
// OTRACK: while aligned to a tracking ray, a bare distance
|
||||
// places the point along the ray from the tracking point
|
||||
// (issue #69).
|
||||
if let Some((base, dir)) = self.otrack_active {
|
||||
// OTRACK and Extension both allow a bare scalar to act as a
|
||||
// distance measured along the active reference ray.
|
||||
if let Some((base, dir)) = self.active_distance_ray(i) {
|
||||
if let Some(dist) = crate::app::expr_eval::eval_number(text.trim()) {
|
||||
let pt = base + dir * dist;
|
||||
if !self.command_point_allowed(i, pt) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue