diff options
author | Akshay <[email protected]> | 2021-05-24 17:57:41 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-05-24 17:57:41 +0100 |
commit | bfe6a86bd5b1d02988dbd9a3bb5759854d76a050 (patch) | |
tree | 2f7025562203b79bac65080bcc5f72a0d7787343 | |
parent | 02c8475c9dd8ac589054a39d5ae01b565062dbe6 (diff) |
basic primitives to repeat last paint oprepeat
-rw-r--r-- | src/app.rs | 39 | ||||
-rw-r--r-- | src/bitmap.rs | 13 | ||||
-rw-r--r-- | src/lisp/prelude.rs | 9 | ||||
-rw-r--r-- | src/undo.rs | 2 |
4 files changed, 61 insertions, 2 deletions
@@ -257,6 +257,40 @@ impl<'ctx> AppState<'ctx> { | |||
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
260 | pub fn repeat_last_paint(&mut self, target: MapPoint) { | ||
261 | self.commit_operation(); | ||
262 | if let Some(ModifyRecord::Paint(records)) = self | ||
263 | .undo_stack | ||
264 | .operations | ||
265 | .iter() | ||
266 | .rev() | ||
267 | .find(|&o| matches!(o, ModifyRecord::Paint(_))) | ||
268 | { | ||
269 | dbg!(target); | ||
270 | // find center of paint cluster | ||
271 | let centroid: MapPoint = records | ||
272 | .iter() | ||
273 | .fold(MapPoint { x: 0, y: 0 }, |acc, x| acc + x.point) | ||
274 | .reduce(records.len() as u32); | ||
275 | dbg!(centroid); | ||
276 | // re-center cluster around target | ||
277 | let centered_op = records | ||
278 | .iter() | ||
279 | .map(|x| PaintRecord { | ||
280 | point: x.point + target - centroid, | ||
281 | ..*x | ||
282 | }) | ||
283 | .collect::<Vec<_>>(); | ||
284 | let mut ud = Vec::new(); | ||
285 | for r in ¢ered_op { | ||
286 | let p = r.point; | ||
287 | let v = r.new; | ||
288 | ud.push(PaintRecord::new(p, self.pixmap.set(p, v), v)); | ||
289 | } | ||
290 | self.undo_stack.push(ModifyRecord::Paint(ud)); | ||
291 | } | ||
292 | } | ||
293 | |||
260 | pub fn zoom_in(&mut self, p: (i32, i32)) { | 294 | pub fn zoom_in(&mut self, p: (i32, i32)) { |
261 | // attempt to center around cursor | 295 | // attempt to center around cursor |
262 | if let Some(p) = self.idx_at_coord(p) { | 296 | if let Some(p) = self.idx_at_coord(p) { |
@@ -774,6 +808,11 @@ impl<'ctx> AppState<'ctx> { | |||
774 | let cursor = (mouse.x(), mouse.y()); | 808 | let cursor = (mouse.x(), mouse.y()); |
775 | self.zoom_out(cursor); | 809 | self.zoom_out(cursor); |
776 | } | 810 | } |
811 | Keycode::Period => { | ||
812 | if let Some(contact) = self.idx_at_coord(self.mouse) { | ||
813 | self.repeat_last_paint(contact.into()); | ||
814 | } | ||
815 | } | ||
777 | // brush ops | 816 | // brush ops |
778 | Keycode::Q => self.brush.shrink(), | 817 | Keycode::Q => self.brush.shrink(), |
779 | Keycode::E => self.brush.grow(), | 818 | Keycode::E => self.brush.grow(), |
diff --git a/src/bitmap.rs b/src/bitmap.rs index ff41cb8..ffc0258 100644 --- a/src/bitmap.rs +++ b/src/bitmap.rs | |||
@@ -13,7 +13,7 @@ pub struct Pixmap<T> { | |||
13 | pub data: Vec<T>, | 13 | pub data: Vec<T>, |
14 | } | 14 | } |
15 | 15 | ||
16 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] | 16 | #[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq)] |
17 | pub struct MapPoint { | 17 | pub struct MapPoint { |
18 | pub x: u32, | 18 | pub x: u32, |
19 | pub y: u32, | 19 | pub y: u32, |
@@ -111,6 +111,17 @@ impl MapPoint { | |||
111 | } | 111 | } |
112 | 112 | ||
113 | #[inline] | 113 | #[inline] |
114 | pub fn reduce(self, c: u32) -> MapPoint { | ||
115 | if c == 0 { | ||
116 | panic!("reduce MapPoint by zero") | ||
117 | } | ||
118 | MapPoint { | ||
119 | x: self.x / c, | ||
120 | y: self.y / c, | ||
121 | } | ||
122 | } | ||
123 | |||
124 | #[inline] | ||
114 | pub fn mirror_about(self, line: u32, axis: Axis) -> MapPoint { | 125 | pub fn mirror_about(self, line: u32, axis: Axis) -> MapPoint { |
115 | let MapPoint { x, y } = self; | 126 | let MapPoint { x, y } = self; |
116 | match axis { | 127 | match axis { |
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs index dddce5f..ce3f97b 100644 --- a/src/lisp/prelude.rs +++ b/src/lisp/prelude.rs | |||
@@ -536,6 +536,15 @@ pub fn new_env() -> Result<Environment, LispError> { | |||
536 | ])) | 536 | ])) |
537 | }); | 537 | }); |
538 | 538 | ||
539 | primitive!(env, Arity::Exact(0), "active-color", |_, app| { | ||
540 | Ok(LispExpr::BoolLit(app.active_color)) | ||
541 | }); | ||
542 | |||
543 | primitive!(env, Arity::Exact(1), "set-active-color!", |args, app| { | ||
544 | app.active_color = args[0].cast_bool(); | ||
545 | Ok(LispExpr::Unit) | ||
546 | }); | ||
547 | |||
539 | primitive!(env, Arity::Exact(2), "range", |args, _| { | 548 | primitive!(env, Arity::Exact(2), "range", |args, _| { |
540 | if type_match!( | 549 | if type_match!( |
541 | args, | 550 | args, |
diff --git a/src/undo.rs b/src/undo.rs index 5effd79..f6c41ce 100644 --- a/src/undo.rs +++ b/src/undo.rs | |||
@@ -27,7 +27,7 @@ pub enum OpKind { | |||
27 | 27 | ||
28 | #[derive(Debug)] | 28 | #[derive(Debug)] |
29 | pub struct UndoStack<T> { | 29 | pub struct UndoStack<T> { |
30 | operations: Vec<T>, | 30 | pub operations: Vec<T>, |
31 | position: Option<u32>, | 31 | position: Option<u32>, |
32 | } | 32 | } |
33 | 33 | ||