mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 22:06:49 -06:00
Merge pull request #1516 from AganzeFelicite/fix/vector-marquee-anywhere-1508
M4: a drag anywhere in vector edit mode draws a marquee (#1508)
This commit is contained in:
@@ -236,7 +236,7 @@ pub struct PointerEvent {
|
||||
}
|
||||
|
||||
/// The pointer is still within [`DRAG_SLOP_PX`] of where it was pressed.
|
||||
fn within_slop(ev: &PointerEvent, start: Point) -> bool {
|
||||
pub(crate) fn within_slop(ev: &PointerEvent, start: Point) -> bool {
|
||||
(ev.p() - start).hypot() * ev.zoom.max(1e-6) < DRAG_SLOP_PX
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use super::regions::region_hit;
|
||||
use super::transform::{self, BoxHit, PointBox};
|
||||
use super::{EditPart, VHit, VTool, VectorEdit, edit, editing, hit, hit_any, local_offset, network, ops, points_of, selected_points, set_state};
|
||||
use crate::snap::Targets;
|
||||
use crate::tools::{Cursor, Gesture, Handle, PenCursor, PointerEvent, PointerKind};
|
||||
use crate::tools::{Cursor, Gesture, Handle, PenCursor, PointerEvent, PointerKind, within_slop};
|
||||
use crate::{Result, Session};
|
||||
|
||||
/// An in-progress edit-mode gesture (cheap to clone: snap targets are shared).
|
||||
@@ -67,10 +67,13 @@ pub(crate) enum VGesture {
|
||||
moved: bool,
|
||||
smooth: bool,
|
||||
},
|
||||
/// Marquee and lasso: `base` is each edited layer's selection to add to.
|
||||
/// Marquee and lasso: `base` is each edited layer's selection to add to. `leave` is a press
|
||||
/// on another layer: released without a drag, it leaves edit mode and goes to the
|
||||
/// normal tool.
|
||||
Marquee {
|
||||
start: Point,
|
||||
base: Vec<EditPart>,
|
||||
leave: Option<PointerEvent>,
|
||||
},
|
||||
Lasso {
|
||||
points: Vec<Point>,
|
||||
@@ -700,21 +703,18 @@ impl Session {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// A press on another layer (and not shift) leaves edit mode, so the normal tool
|
||||
// takes it; empty canvas only clears the points and starts a marquee (a
|
||||
// double-click or Escape leaves edit mode).
|
||||
// Every drag here marquees (#1508). A click on another layer (and not shift)
|
||||
// leaves edit mode, so the normal tool takes it; a click on empty canvas only
|
||||
// clears the points (a double-click or Escape leaves edit mode).
|
||||
let inside =
|
||||
ve.parts().iter().any(|p| doc.world_render_bounds(p.id).is_some_and(|b| b.inflate(tol * 4.0, tol * 4.0).contains(ev.p())));
|
||||
let page = self.ds()?.page;
|
||||
let other = !inside && self.hit(&doc, page, ev.p(), tol * 2.0).is_some();
|
||||
if other && !ev.shift {
|
||||
super::end(self)?;
|
||||
return Ok(false);
|
||||
}
|
||||
if !ev.shift {
|
||||
set_state(self, VectorEdit::clear_selection)?;
|
||||
}
|
||||
self.vgesture(VGesture::Marquee { start: ev.p(), base: Self::select_base(ve, ev.shift) });
|
||||
let leave = (other && !ev.shift).then(|| ev.clone());
|
||||
self.vgesture(VGesture::Marquee { start: ev.p(), base: Self::select_base(ve, ev.shift), leave });
|
||||
}
|
||||
},
|
||||
VTool::Bend => match h {
|
||||
@@ -738,7 +738,7 @@ impl Session {
|
||||
self.begin_interaction("Bend")?;
|
||||
self.vgesture(VGesture::BendSegment { seg, t });
|
||||
}
|
||||
None => self.vgesture(VGesture::Marquee { start: ev.p(), base: Self::select_base(ve, ev.shift) }),
|
||||
None => self.vgesture(VGesture::Marquee { start: ev.p(), base: Self::select_base(ve, ev.shift), leave: None }),
|
||||
},
|
||||
VTool::Pen => {
|
||||
let at = if h.is_none() && !ev.shift { self.snap_pen(ev, Some(id), &[])?.0 } else { ev.p() };
|
||||
@@ -951,7 +951,7 @@ impl Session {
|
||||
self.preview(|doc, _| edit(doc, id, |net| ops::make_smooth(net, v, d)))?;
|
||||
self.vgesture(VGesture::BendVertex { v, origin, moved: true, smooth });
|
||||
}
|
||||
VGesture::Marquee { start, base } => {
|
||||
VGesture::Marquee { start, base, .. } => {
|
||||
let r = Rect::from_points(start, ev.p());
|
||||
self.tool.overlay.marquee = Some([r.x0, r.y0, r.x1, r.y1]);
|
||||
self.select_parts(&base, |doc, id| super::vertices_in(doc, id, r), false)?;
|
||||
@@ -1068,6 +1068,11 @@ impl Session {
|
||||
VGesture::Handle { .. } | VGesture::BendSegment { .. } | VGesture::Pen { .. } | VGesture::BoxRotate { .. } => {
|
||||
self.commit_interaction()?
|
||||
}
|
||||
VGesture::Marquee { start, leave: Some(press), .. } if within_slop(ev, start) => {
|
||||
super::end(self)?;
|
||||
self.pointer(&press)?;
|
||||
return self.pointer(ev);
|
||||
}
|
||||
// The active layer moves to one with points selected when it has none.
|
||||
VGesture::Marquee { .. } | VGesture::Lasso { .. } => set_state(self, |e| {
|
||||
if e.vertices.is_empty()
|
||||
|
||||
@@ -542,6 +542,27 @@ fn selecting_points_and_segments() {
|
||||
assert_eq!(page_pos(&s, id, tl), Point::new(1.0, 0.0), "the drag is one undo step");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_marquee_starts_anywhere_on_the_canvas() {
|
||||
// #1508: a drag far from the edited shape, over another layer, marquees its points; a click
|
||||
// there still leaves edit mode and selects that layer.
|
||||
let mut s = Session::new();
|
||||
let bg = id_of(&ex(&mut s, "shape.rectangle", json!({"x": -500, "y": -500, "width": 1000, "height": 1000}))["id"]).unwrap();
|
||||
let id = square(&mut s, true);
|
||||
let (tl, tr) = (point_at(&s, id, (0.0, 0.0)), point_at(&s, id, (100.0, 0.0)));
|
||||
let bg_x = |s: &Session| s.doc().unwrap().world_transform(bg).translation().x;
|
||||
drag(&mut s, (-200.0, -200.0), (110.0, 10.0), NONE);
|
||||
let mut got = editing(&s).expect("a drag away from the shape stays in edit mode").vertices;
|
||||
got.sort_unstable();
|
||||
let mut want = vec![tl, tr];
|
||||
want.sort_unstable();
|
||||
assert_eq!(got, want, "the marquee selects the points inside it");
|
||||
assert_eq!(bg_x(&s), -500.0, "the layer under the drag stays put");
|
||||
click(&mut s, (-200.0, -200.0), NONE);
|
||||
assert!(editing(&s).is_none(), "a click away from the shape leaves edit mode");
|
||||
assert_eq!(s.selection(), vec![bg], "the click selects the layer under it");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deleting_points_vs_delete_and_heal() {
|
||||
// (key, Shift, points, segments, closed afterwards, derivation)
|
||||
|
||||
Reference in New Issue
Block a user