Fix OFFSET distance clicks and source picking (#618)

Squash of PR #618 by @PedroGuille.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
PedroGuille 2026-10-11 14:39:55 -03:00 committed by GitHub
parent a181bbd609
commit 40aa4fbf49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 8 deletions

View File

@ -1937,6 +1937,7 @@ enum OffsetAsk {
struct OffsetM {
dist: Option<f64>,
distance_first: Option<Vec2>,
through: bool,
picked: Option<Handle>,
ask: Option<OffsetAsk>,
@ -1949,7 +1950,17 @@ struct OffsetM {
impl OffsetM {
fn new(s: &Session) -> Self {
let _ = s;
OffsetM { dist: None, through: false, picked: None, ask: None, multiple: false, undo: Vec::new() }
OffsetM { dist: None, distance_first: None, through: false, picked: None, ask: None, multiple: false, undo: Vec::new() }
}
fn set_distance(&mut self, s: &mut Session, distance: f64) -> Result<()> {
if !(distance.is_finite() && distance > 0.0) {
return Err(EngineError::Other("Requires a positive distance.".into()));
}
s.doc_mut()?.header.set_f64("OFFSETDIST", distance);
self.dist = Some(distance);
self.distance_first = None;
Ok(())
}
}
@ -1993,6 +2004,12 @@ impl Interactive for OffsetM {
None => {}
}
let last = s.doc().map(|d| d.header.f64("OFFSETDIST", -1.0)).unwrap_or(-1.0);
if self.dist.is_none()
&& !self.through
&& let Some(base) = self.distance_first
{
return Prompt::new("Specify second point", Accept::POINT).base(base);
}
match (self.dist.is_some() || self.through, self.picked) {
(false, _) => Prompt::new("Specify offset distance", Accept::POINT_OR_NUMBER).kw(&["Through", "Erase", "Layer"]).default(if last < 0.0 {
"Through".to_string()
@ -2037,14 +2054,26 @@ impl Interactive for OffsetM {
if self.dist.is_none() && !self.through {
match i {
Input::Text(t) => {
let d = number(&t).filter(|d| *d > 0.0).ok_or_else(|| EngineError::Other("Requires a positive distance.".into()))?;
self.dist = Some(d);
s.doc_mut()?.header.set_f64("OFFSETDIST", d);
let d = number(&t).ok_or_else(|| EngineError::Other("Requires a positive distance.".into()))?;
self.set_distance(s, d)?;
}
Input::Point(p) => {
if !p.is_finite() {
return Err(EngineError::Other("Invalid point.".into()));
}
match self.distance_first {
Some(base) => self.set_distance(s, base.dist(p))?,
None => self.distance_first = Some(p),
}
}
Input::Keyword(k) if k == "Through" => {
self.through = true;
self.distance_first = None;
}
Input::Keyword(k) if k == "Through" => self.through = true,
Input::Keyword(k) if k == "Erase" => self.ask = Some(OffsetAsk::Erase),
Input::Keyword(k) if k == "Layer" => self.ask = Some(OffsetAsk::Layer),
Input::Enter => {
self.distance_first = None;
let last = s.doc()?.header.f64("OFFSETDIST", -1.0);
if last > 0.0 {
self.dist = Some(last);
@ -2138,6 +2167,11 @@ impl Interactive for OffsetM {
}
}
fn preview(&self, s: &Session, c: Vec2) -> Vec<EntityKind> {
if let Some(base) = self.distance_first
&& c.is_finite()
{
return vec![line(base, c)];
}
let (Some(h), Ok(d)) = (self.picked, s.doc()) else { return Vec::new() };
let Some(e) = d.entity(h) else { return Vec::new() };
let dist = match self.dist {

View File

@ -533,7 +533,7 @@ fn draw_tracking(p: &egui::Painter, xf: &Xf, acquired: &[snap::tracking::Acquire
/// `Session::snap_cursor`: object snaps, acquiring tracking points, grid, tracking paths, ortho).
fn effective_point(app: &mut CadApp, raw: Vec2, xf: &Xf, ctx: &egui::Context) -> Vec2 {
let prompt = app.session.current_prompt();
let wants_point = prompt.as_ref().is_some_and(|p| p.accept.point && !p.accept.select);
let wants_point = prompt.as_ref().is_some_and(cadcraft_engine::pointmod::accepts);
let base = prompt.as_ref().and_then(|p| p.base);
let deferred = prompt.as_ref().is_some_and(|p| p.deferred);
app.canvas.snap = None;
@ -1106,7 +1106,7 @@ fn override_cursor(app: &mut CadApp, raw: Vec2, xf: &Xf) {
let ap = app.session.settings.aperture / xf.scale;
let cycle = snap_cycle(app, raw, ap);
let prompt = app.session.current_prompt();
let wants_point = prompt.as_ref().is_some_and(|p| p.accept.point && !p.accept.select);
let wants_point = prompt.as_ref().is_some_and(cadcraft_engine::pointmod::accepts);
if (over.is_none() && cycle.is_none()) || !wants_point || app.session.pending_window.is_some() {
return;
}

View File

@ -44,7 +44,7 @@ pub fn dyn_frame(app: &CadApp) -> Option<crate::dyninput::Frame> {
if !st.dynmode || app.session.pending_window.is_some() {
return None;
}
let p = app.session.current_prompt().filter(|p| p.accept.point && !p.accept.select)?;
let p = app.session.current_prompt().filter(cadcraft_engine::pointmod::accepts)?;
Some(crate::dyninput::Frame { base: p.base, cartesian: st.dynpi_cartesian, absolute: st.dynpi_absolute })
}