aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.rs39
-rw-r--r--src/bitmap.rs13
-rw-r--r--src/lisp/prelude.rs9
-rw-r--r--src/undo.rs2
4 files changed, 61 insertions, 2 deletions
diff --git a/src/app.rs b/src/app.rs
index 3e7ac0f..d8a6132 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -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 &centered_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)]
17pub struct MapPoint { 17pub 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)]
29pub struct UndoStack<T> { 29pub struct UndoStack<T> {
30 operations: Vec<T>, 30 pub operations: Vec<T>,
31 position: Option<u32>, 31 position: Option<u32>,
32} 32}
33 33