Skip to content

Commit 7faf926

Browse files
committed
Implement arbitrary point deletion
1 parent 06933c5 commit 7faf926

File tree

4 files changed

+80
-27
lines changed

4 files changed

+80
-27
lines changed

splinetoy/src/edit_session.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ impl EditSession {
3232
self.path.update_for_drag(handle)
3333
}
3434

35-
pub fn remove_last_segment(&mut self) {
36-
self.selection = self.path.remove_last_segment()
35+
pub fn delete(&mut self) {
36+
if let Some(selected) = self.selection.take() {
37+
self.selection = self.path.delete(selected);
38+
}
3739
}
3840

3941
pub fn close(&mut self) {

splinetoy/src/editor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ impl Widget<EditSession> for Editor {
9595
Event::MouseUp(m) => self.send_mouse(ctx, TaggedEvent::Up(m.clone()), data),
9696
Event::MouseMove(m) => self.send_mouse(ctx, TaggedEvent::Moved(m.clone()), data),
9797
Event::MouseDown(m) => self.send_mouse(ctx, TaggedEvent::Down(m.clone()), data),
98-
Event::KeyDown(key) if key.key == KbKey::Backspace => {
99-
data.remove_last_segment();
98+
Event::KeyDown(k) => {
99+
self.tool.key_down(k, ctx, data);
100100
}
101-
Event::KeyDown(key) if key.key == KbKey::Escape => {
102-
data.close();
101+
Event::KeyUp(k) => {
102+
self.tool.key_up(k, ctx, data);
103103
}
104104
Event::Command(cmd) if cmd.is(commands::SAVE_FILE) => {
105105
if let Some(file_info) = cmd.get_unchecked(commands::SAVE_FILE) {

splinetoy/src/path.rs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -197,30 +197,54 @@ impl Path {
197197
self.solver.spline_to(None, None, p3, smooth);
198198
}
199199

200-
pub fn remove_last_segment(&mut self) -> Option<PointId> {
201-
Arc::make_mut(&mut self.points).pop();
202-
while self
203-
.points()
204-
.last()
205-
.map(|pt| pt.type_.is_control())
206-
.unwrap_or(false)
207-
{
208-
Arc::make_mut(&mut self.points).pop();
200+
pub fn delete(&mut self, id: PointId) -> Option<PointId> {
201+
let pos = self.idx_for_point(id).unwrap();
202+
let pt = self.points[pos];
203+
if pt.is_control() {
204+
self.points_mut().remove(pos);
205+
if self.points.get(pos).map(|pt| pt.is_control()) == Some(true) {
206+
self.points_mut().remove(pos);
207+
} else {
208+
// if the other point in this segment isn't after us, it must be before:
209+
self.points_mut().remove(pos - 1);
210+
}
211+
let (el, _) = self.element_containing_idx_mut(pos);
212+
if let Element::SplineTo(_, _, point, smooth) = el {
213+
*el = Element::LineTo(*point, *smooth);
214+
}
215+
} else {
216+
let element_idx = self.idx_for_element_containing_point(pos);
217+
let removed = self.solver.elements_mut().remove(element_idx);
218+
if element_idx == 0 {
219+
if let Some(el) = self.solver.elements_mut().get_mut(0) {
220+
*el = Element::MoveTo(el.endpoint());
221+
}
222+
}
223+
self.points_mut().remove(pos);
224+
if matches!(removed, Element::SplineTo(..)) {
225+
self.points_mut().remove(pos - 1);
226+
self.points_mut().remove(pos - 2);
227+
}
228+
// if removing the first point, and it is followed by a splineto,
229+
// remove the control points
230+
if self.points.get(0).map(|pt| pt.is_control()) == Some(true) {
231+
self.points_mut().remove(0);
232+
self.points_mut().remove(0);
233+
}
209234
}
210-
self.solver.elements_mut().pop();
211-
self.trailing = None;
212235
self.after_change();
236+
// select the last point on delete?
213237
self.points().last().map(|pt| pt.id)
214238
}
215239

216-
pub fn close(&mut self) {
217-
if !self.closed && self.points.len() > 2 {
218-
let first = self.points.first().cloned().unwrap();
219-
self.spline_to(first.point, true);
220-
self.closed = true;
221-
self.solver.close();
222-
}
223-
}
240+
//pub fn close(&mut self) {
241+
//if !self.closed && self.points.len() > 2 {
242+
//let first = self.points.first().cloned().unwrap();
243+
//self.spline_to(first.point, true);
244+
//self.closed = true;
245+
//self.solver.close();
246+
//}
247+
//}
224248

225249
pub fn update_for_drag(&mut self, handle: Point) {
226250
assert!(!self.points.is_empty());
@@ -301,6 +325,19 @@ impl Path {
301325
unreachable!();
302326
}
303327

328+
fn idx_for_element_containing_point(&self, idx: usize) -> usize {
329+
let mut dist_to_pt = idx;
330+
for (i, element) in self.solver.elements().iter().enumerate() {
331+
match element {
332+
Element::MoveTo(..) | Element::LineTo(..) if dist_to_pt == 0 => return i,
333+
Element::SplineTo(..) if (0..=2).contains(&dist_to_pt) => return i,
334+
Element::LineTo(..) | Element::MoveTo(..) => dist_to_pt -= 1,
335+
Element::SplineTo(..) => dist_to_pt = dist_to_pt.saturating_sub(3),
336+
}
337+
}
338+
unreachable!();
339+
}
340+
304341
pub fn maybe_convert_line_to_spline(&mut self, click: Point, max_dist: f64) {
305342
let mut best = (f64::MAX, 0);
306343
let spline = self.solver.solve();
@@ -331,7 +368,8 @@ impl Path {
331368
let p1 = prev_point.lerp(pt.point, 1.0 / 3.0);
332369
let p2 = prev_point.lerp(pt.point, 2.0 / 3.0);
333370
self.points_mut().insert(i, SplinePoint::control(p1, true));
334-
self.points_mut().insert(i + 1, SplinePoint::control(p2, true));
371+
self.points_mut()
372+
.insert(i + 1, SplinePoint::control(p2, true));
335373
break;
336374
}
337375
segs_seen += 1;

splinetoy/src/select.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use druid::{EventCtx, MouseEvent};
1+
use druid::{EventCtx, KbKey, KeyEvent, MouseEvent};
22

33
use crate::mouse::{Drag, Mouse, MouseDelegate, TaggedEvent};
44
use crate::tools::{EditType, Tool, ToolId};
@@ -34,6 +34,19 @@ pub struct Select {
3434
}
3535

3636
impl Tool for Select {
37+
fn key_down(
38+
&mut self,
39+
key: &KeyEvent,
40+
ctx: &mut EventCtx,
41+
data: &mut EditSession,
42+
) -> Option<EditType> {
43+
if key.key == KbKey::Backspace {
44+
data.delete();
45+
ctx.set_handled();
46+
}
47+
None
48+
}
49+
3750
fn mouse_event(
3851
&mut self,
3952
event: TaggedEvent,

0 commit comments

Comments
 (0)