diff options
Diffstat (limited to 'src/app.rs')
-rw-r--r-- | src/app.rs | 115 |
1 files changed, 53 insertions, 62 deletions
@@ -103,61 +103,30 @@ impl<'ctx> AppState<'ctx> { | |||
103 | center: P, | 103 | center: P, |
104 | val: bool, | 104 | val: bool, |
105 | ) -> Result<Vec<ModifyRecord>, ()> { | 105 | ) -> Result<Vec<ModifyRecord>, ()> { |
106 | let radius = self.brush_size; | 106 | let radius = self.brush_size as u32; |
107 | if radius == 1 { | 107 | let center = self.idx_at_coord(center).ok_or(())?; |
108 | let center_point: Point = center.into(); | 108 | let mut circle_modify_record = vec![]; |
109 | return Ok(if let Some(pt) = self.idx_at_coord(center_point) { | 109 | for point in self.pixmap.get_circle(center, radius) { |
110 | let old_val = self.pixmap.set(pt, val); | 110 | let old_val = self.pixmap.set(point, val); |
111 | Ok(ModifyRecord::new(pt, old_val, val)) | 111 | circle_modify_record.push(ModifyRecord::new(point, old_val, val)); |
112 | } else { | 112 | } |
113 | Err(()) | 113 | Ok(circle_modify_record) |
114 | } | 114 | } |
115 | .map(|x| vec![x])?); | 115 | |
116 | } else { | 116 | fn paint_line<P: Into<Point>>(&mut self, start: P, end: P) -> Result<Vec<ModifyRecord>, ()> { |
117 | if let Some(center_on_grid) = self.idx_at_coord(center) { | 117 | let start = self.idx_at_coord(start).ok_or(())?; |
118 | // center_on_grid is now a coordinate on the drawing grid | 118 | let end = self.idx_at_coord(end).ok_or(())?; |
119 | let (x0, y0) = (center_on_grid.0 as i64, center_on_grid.1 as i64); | 119 | let line_coords = self.pixmap.get_line(start, end); |
120 | let (mut dx, mut dy, mut err) = (radius as i64, 0i64, 1 - radius as i64); | 120 | let mut line_modify_record = vec![]; |
121 | let mut circle = vec![]; | 121 | let val = self.active_color; |
122 | let mut old_vals = vec![]; | 122 | for point in line_coords { |
123 | while dx >= dy { | 123 | let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32); |
124 | circle.push((x0 + dx, y0 + dy)); | 124 | for c in circle_around_point { |
125 | circle.push((x0 - dx, y0 + dy)); | 125 | let old_val = self.pixmap.set(c, val); |
126 | circle.push((x0 + dx, y0 - dy)); | 126 | line_modify_record.push(ModifyRecord::new(c, old_val, val)); |
127 | circle.push((x0 - dx, y0 - dy)); | ||
128 | circle.push((x0 + dy, y0 + dx)); | ||
129 | circle.push((x0 - dy, y0 + dx)); | ||
130 | circle.push((x0 + dy, y0 - dx)); | ||
131 | circle.push((x0 - dy, y0 - dx)); | ||
132 | dy = dy + 1; | ||
133 | if err < 0 { | ||
134 | err = err + 2 * dy + 1; | ||
135 | } else { | ||
136 | dx -= 1; | ||
137 | err += 2 * (dy - dx) + 1; | ||
138 | } | ||
139 | } | ||
140 | // circle's insides | ||
141 | for x in 0..radius as i64 { | ||
142 | for y in 0..radius as i64 { | ||
143 | if x.pow(2) + y.pow(2) < (radius as i64).pow(2) { | ||
144 | circle.push((x0 + x, y0 + y)); | ||
145 | circle.push((x0 - x, y0 + y)); | ||
146 | circle.push((x0 + x, y0 - y)); | ||
147 | circle.push((x0 - x, y0 - y)); | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | for circumference_pt in circle { | ||
152 | if let Ok(mp) = MapPoint::try_from(circumference_pt) { | ||
153 | let old_val = self.pixmap.set(mp, val); | ||
154 | old_vals.push(ModifyRecord::new((mp.x, mp.y), old_val, val)); | ||
155 | } | ||
156 | } | ||
157 | return Ok(old_vals); | ||
158 | } | 127 | } |
159 | } | 128 | } |
160 | return Err(()); | 129 | Ok(line_modify_record) |
161 | } | 130 | } |
162 | 131 | ||
163 | fn apply_operation(&mut self, op: Operation, op_kind: OpKind) { | 132 | fn apply_operation(&mut self, op: Operation, op_kind: OpKind) { |
@@ -176,6 +145,17 @@ impl<'ctx> AppState<'ctx> { | |||
176 | } | 145 | } |
177 | } | 146 | } |
178 | 147 | ||
148 | fn commit_operation(&mut self) { | ||
149 | if !self.current_operation.is_empty() { | ||
150 | let op = self | ||
151 | .current_operation | ||
152 | .drain(..) | ||
153 | .filter(|v| !v.old_val == v.val) | ||
154 | .collect::<Vec<_>>(); | ||
155 | self.undo_stack.push(op); | ||
156 | } | ||
157 | } | ||
158 | |||
179 | fn zoom_in(&mut self, p: (i32, i32)) { | 159 | fn zoom_in(&mut self, p: (i32, i32)) { |
180 | // attempt to center around cursor | 160 | // attempt to center around cursor |
181 | if let Some(p) = self.idx_at_coord(p) { | 161 | if let Some(p) = self.idx_at_coord(p) { |
@@ -192,8 +172,8 @@ impl<'ctx> AppState<'ctx> { | |||
192 | self.brush_size += 1; | 172 | self.brush_size += 1; |
193 | } | 173 | } |
194 | 174 | ||
195 | fn descrease_brush_size(&mut self) { | 175 | fn decrease_brush_size(&mut self) { |
196 | if self.brush_size > 1 { | 176 | if self.brush_size > 0 { |
197 | self.brush_size -= 1; | 177 | self.brush_size -= 1; |
198 | } | 178 | } |
199 | } | 179 | } |
@@ -296,7 +276,7 @@ impl<'ctx> AppState<'ctx> { | |||
296 | Self { | 276 | Self { |
297 | start: Point::new(60, 60), | 277 | start: Point::new(60, 60), |
298 | zoom: 5, | 278 | zoom: 5, |
299 | brush_size: 1, | 279 | brush_size: 0, |
300 | pixmap, | 280 | pixmap, |
301 | grid: Grid::new(), | 281 | grid: Grid::new(), |
302 | canvas, | 282 | canvas, |
@@ -339,12 +319,25 @@ impl<'ctx> AppState<'ctx> { | |||
339 | self.modify(|e| e.zoom_out(cursor)); | 319 | self.modify(|e| e.zoom_out(cursor)); |
340 | } | 320 | } |
341 | // brush ops | 321 | // brush ops |
342 | Keycode::Q => self.modify(|e| e.descrease_brush_size()), | 322 | Keycode::Q => self.decrease_brush_size(), |
343 | Keycode::E => self.modify(|e| e.increase_brush_size()), | 323 | Keycode::E => self.increase_brush_size(), |
344 | // flip color | 324 | // flip color |
345 | Keycode::X => self.modify(|e| e.change_active_color()), | 325 | Keycode::X => self.modify(|e| e.change_active_color()), |
346 | // toggle grid | 326 | // toggle grid |
347 | Keycode::Tab => self.modify(|e| e.toggle_grid()), | 327 | Keycode::Tab => self.modify(|e| e.toggle_grid()), |
328 | // line drawing | ||
329 | Keycode::F => self.modify(|e| { | ||
330 | let end = (mouse.x(), mouse.y()).into(); | ||
331 | if let Some(start) = e.last_point { | ||
332 | if let Ok(o) = e.paint_line(start, end) { | ||
333 | e.commit_operation(); | ||
334 | e.current_operation = | ||
335 | o.into_iter().filter(|v| !v.old_val == v.val).collect(); | ||
336 | e.commit_operation(); | ||
337 | e.last_point = Some(end); | ||
338 | } | ||
339 | } | ||
340 | }), | ||
348 | // exit | 341 | // exit |
349 | Keycode::Escape => break 'running, | 342 | Keycode::Escape => break 'running, |
350 | // undo & redo | 343 | // undo & redo |
@@ -381,9 +374,7 @@ impl<'ctx> AppState<'ctx> { | |||
381 | Event::MouseMotion { | 374 | Event::MouseMotion { |
382 | x, y, mousestate, .. | 375 | x, y, mousestate, .. |
383 | } => { | 376 | } => { |
384 | let is_left = mousestate.is_mouse_button_pressed(MouseButton::Left); | 377 | if mousestate.is_mouse_button_pressed(MouseButton::Left) { |
385 | let is_right = mousestate.is_mouse_button_pressed(MouseButton::Right); | ||
386 | if is_left { | ||
387 | self.modify(|e| { | 378 | self.modify(|e| { |
388 | let pt = (x, y); | 379 | let pt = (x, y); |
389 | let val = e.active_color; | 380 | let val = e.active_color; |
@@ -391,7 +382,7 @@ impl<'ctx> AppState<'ctx> { | |||
391 | e.current_operation.extend(o); | 382 | e.current_operation.extend(o); |
392 | } | 383 | } |
393 | }); | 384 | }); |
394 | } else if is_right { | 385 | } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { |
395 | self.modify(|e| { | 386 | self.modify(|e| { |
396 | let pt = (x, y); | 387 | let pt = (x, y); |
397 | let val = !e.active_color; | 388 | let val = !e.active_color; |