diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app.rs | 120 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/undo.rs | 4 |
3 files changed, 51 insertions, 74 deletions
@@ -1,4 +1,9 @@ | |||
1 | use crate::undo::{ModifyRecord, OpKind, Operation, UndoStack}; | 1 | use crate::{ |
2 | bitmap::{MapPoint, Pixmap}, | ||
3 | undo::{ModifyRecord, OpKind, Operation, UndoStack}, | ||
4 | }; | ||
5 | |||
6 | use std::convert::{From, TryFrom}; | ||
2 | 7 | ||
3 | use sdl2::{ | 8 | use sdl2::{ |
4 | event::Event, | 9 | event::Event, |
@@ -15,9 +20,7 @@ use crate::consts::{BLACK, GRID_COLOR, WHITE}; | |||
15 | 20 | ||
16 | pub struct AppState<'ctx> { | 21 | pub struct AppState<'ctx> { |
17 | start: Point, | 22 | start: Point, |
18 | width: u32, | 23 | pixmap: Pixmap<bool>, |
19 | height: u32, | ||
20 | data: Vec<bool>, | ||
21 | zoom: u8, | 24 | zoom: u8, |
22 | brush_size: u8, | 25 | brush_size: u8, |
23 | grid: Grid, | 26 | grid: Grid, |
@@ -49,11 +52,19 @@ impl<'ctx> AppState<'ctx> { | |||
49 | self.start += direction.into(); | 52 | self.start += direction.into(); |
50 | } | 53 | } |
51 | 54 | ||
55 | fn width(&self) -> u32 { | ||
56 | self.pixmap.width | ||
57 | } | ||
58 | |||
59 | fn height(&self) -> u32 { | ||
60 | self.pixmap.height | ||
61 | } | ||
62 | |||
52 | fn bounds(&self) -> (Point, Point) { | 63 | fn bounds(&self) -> (Point, Point) { |
53 | let x_min = self.start.x(); | 64 | let x_min = self.start.x(); |
54 | let y_min = self.start.y(); | 65 | let y_min = self.start.y(); |
55 | let x_max = self.start.x() + (self.width * self.zoom as u32) as i32; | 66 | let x_max = self.start.x() + (self.width() * self.zoom as u32) as i32; |
56 | let y_max = self.start.y() + (self.height * self.zoom as u32) as i32; | 67 | let y_max = self.start.y() + (self.height() * self.zoom as u32) as i32; |
57 | return ( | 68 | return ( |
58 | Point::new(x_min, y_min), | 69 | Point::new(x_min, y_min), |
59 | Point::new(x_max as i32, y_max as i32), | 70 | Point::new(x_max as i32, y_max as i32), |
@@ -83,34 +94,6 @@ impl<'ctx> AppState<'ctx> { | |||
83 | p.x() < maxi.x() && p.y() < maxi.y() && p.x() >= mini.x() && p.y() >= mini.y() | 94 | p.x() < maxi.x() && p.y() < maxi.y() && p.x() >= mini.x() && p.y() >= mini.y() |
84 | } | 95 | } |
85 | 96 | ||
86 | fn within_grid<P: Into<Point>>(&self, p: P) -> bool { | ||
87 | let p = p.into(); | ||
88 | let (x, y) = (p.x(), p.y()); | ||
89 | x >= 0 && x < self.width as i32 && y >= 0 && y < self.height as i32 | ||
90 | } | ||
91 | |||
92 | fn set_at<P: Into<Point>>(&mut self, p: P, val: bool) -> Result<ModifyRecord, ()> { | ||
93 | let p: Point = p.into(); | ||
94 | if let Some((x, y)) = self.idx_at_coord(p) { | ||
95 | let old_val = self.data[(y * self.width + x) as usize]; | ||
96 | self.data[(y * self.width + x) as usize] = val; | ||
97 | return Ok(ModifyRecord::new((x as i32, y as i32), old_val, val)); | ||
98 | } | ||
99 | return Err(()); | ||
100 | } | ||
101 | |||
102 | fn set_with_absolute<P: Into<Point>>(&mut self, p: P, val: bool) -> Result<ModifyRecord, ()> { | ||
103 | let p: Point = p.into(); | ||
104 | let (x, y) = (p.x(), p.y()); | ||
105 | if self.within_grid(p) { | ||
106 | let idx = y as u32 * self.width + x as u32; | ||
107 | let old_val = self.data[idx as usize]; | ||
108 | self.data[idx as usize] = val; | ||
109 | return Ok(ModifyRecord::new((x as i32, y as i32), old_val, val)); | ||
110 | } | ||
111 | return Err(()); | ||
112 | } | ||
113 | |||
114 | fn toggle_grid(&mut self) { | 97 | fn toggle_grid(&mut self) { |
115 | self.grid.enabled = !self.grid.enabled; | 98 | self.grid.enabled = !self.grid.enabled; |
116 | } | 99 | } |
@@ -122,7 +105,14 @@ impl<'ctx> AppState<'ctx> { | |||
122 | ) -> Result<Vec<ModifyRecord>, ()> { | 105 | ) -> Result<Vec<ModifyRecord>, ()> { |
123 | let radius = self.brush_size; | 106 | let radius = self.brush_size; |
124 | if radius == 1 { | 107 | if radius == 1 { |
125 | return Ok(self.set_at(center, val).map(|x| vec![x])?); | 108 | let center_point: Point = center.into(); |
109 | return Ok(if let Some(pt) = self.idx_at_coord(center_point) { | ||
110 | let old_val = self.pixmap.set(pt, val); | ||
111 | Ok(ModifyRecord::new(pt, old_val, val)) | ||
112 | } else { | ||
113 | Err(()) | ||
114 | } | ||
115 | .map(|x| vec![x])?); | ||
126 | } else { | 116 | } else { |
127 | if let Some(center_on_grid) = self.idx_at_coord(center) { | 117 | if let Some(center_on_grid) = self.idx_at_coord(center) { |
128 | // center_on_grid is now a coordinate on the drawing grid | 118 | // center_on_grid is now a coordinate on the drawing grid |
@@ -158,16 +148,10 @@ impl<'ctx> AppState<'ctx> { | |||
158 | } | 148 | } |
159 | } | 149 | } |
160 | } | 150 | } |
161 | dbg!(&circle); | 151 | for circumference_pt in circle { |
162 | for (x, y) in circle { | 152 | if let Ok(mp) = MapPoint::try_from(circumference_pt) { |
163 | if self.within_grid((x as i32, y as i32)) { | 153 | let old_val = self.pixmap.set(mp, val); |
164 | let idx = y as u32 * self.width + x as u32; | 154 | old_vals.push(ModifyRecord::new((mp.x, mp.y), old_val, val)); |
165 | old_vals.push(ModifyRecord::new( | ||
166 | (x as i32, y as i32), | ||
167 | self.data[idx as usize], | ||
168 | val, | ||
169 | )); | ||
170 | self.data[idx as usize] = val; | ||
171 | } | 155 | } |
172 | } | 156 | } |
173 | return Ok(old_vals); | 157 | return Ok(old_vals); |
@@ -176,27 +160,20 @@ impl<'ctx> AppState<'ctx> { | |||
176 | return Err(()); | 160 | return Err(()); |
177 | } | 161 | } |
178 | 162 | ||
179 | fn draw_line<P: Into<Point>>(&mut self, to: P) { | 163 | fn apply_operation(&mut self, op: Operation, op_kind: OpKind) { |
180 | let to = to.into(); | ||
181 | let from = self.last_point.unwrap_or(to.into()); | ||
182 | } | ||
183 | |||
184 | fn apply_operation(&mut self, op: Operation, op_kind: OpKind) -> Result<(), ()> { | ||
185 | for ModifyRecord { | 164 | for ModifyRecord { |
186 | point, | 165 | point, |
187 | old_val, | 166 | old_val, |
188 | val, | 167 | val, |
189 | } in op.into_iter() | 168 | } in op.into_iter() |
190 | { | 169 | { |
191 | self.set_with_absolute( | 170 | if self.pixmap.is_inside(point) { |
192 | point, | ||
193 | match op_kind { | 171 | match op_kind { |
194 | OpKind::Undo => old_val, | 172 | OpKind::Undo => self.pixmap.set(point, old_val), |
195 | OpKind::Redo => val, | 173 | OpKind::Redo => self.pixmap.set(point, val), |
196 | }, | 174 | }; |
197 | )?; | 175 | } |
198 | } | 176 | } |
199 | Ok(()) | ||
200 | } | 177 | } |
201 | 178 | ||
202 | fn zoom_in(&mut self, p: (i32, i32)) { | 179 | fn zoom_in(&mut self, p: (i32, i32)) { |
@@ -237,17 +214,18 @@ impl<'ctx> AppState<'ctx> { | |||
237 | 214 | ||
238 | fn draw_grid(&mut self) { | 215 | fn draw_grid(&mut self) { |
239 | let cs = self.zoom as u32; | 216 | let cs = self.zoom as u32; |
217 | let (width, height) = (self.width(), self.height()); | ||
240 | let canvas = &mut self.canvas; | 218 | let canvas = &mut self.canvas; |
241 | canvas.set_draw_color(self.grid.color); | 219 | canvas.set_draw_color(self.grid.color); |
242 | for i in 0..=self.width { | 220 | for i in 0..=width { |
243 | let x = (i * cs) as i32; | 221 | let x = (i * cs) as i32; |
244 | let y = (self.height * cs) as i32; | 222 | let y = (height * cs) as i32; |
245 | let start = self.start + Point::new(x, 0); | 223 | let start = self.start + Point::new(x, 0); |
246 | let end = self.start + Point::new(x, y); | 224 | let end = self.start + Point::new(x, y); |
247 | canvas.draw_line(start, end).unwrap(); | 225 | canvas.draw_line(start, end).unwrap(); |
248 | } | 226 | } |
249 | for j in 0..=self.height { | 227 | for j in 0..=height { |
250 | let x = (self.width * cs) as i32; | 228 | let x = (width * cs) as i32; |
251 | let y = (j * cs) as i32; | 229 | let y = (j * cs) as i32; |
252 | let start = self.start + Point::new(0, y); | 230 | let start = self.start + Point::new(0, y); |
253 | let end = self.start + Point::new(x, y); | 231 | let end = self.start + Point::new(x, y); |
@@ -257,20 +235,22 @@ impl<'ctx> AppState<'ctx> { | |||
257 | 235 | ||
258 | fn draw(&mut self) { | 236 | fn draw(&mut self) { |
259 | let cs = self.zoom as u32; | 237 | let cs = self.zoom as u32; |
238 | let (width, height) = (self.width(), self.height()); | ||
239 | let start = self.start; | ||
260 | if self.grid.enabled { | 240 | if self.grid.enabled { |
261 | self.draw_grid(); | 241 | self.draw_grid(); |
262 | } | 242 | } |
263 | let canvas = &mut self.canvas; | 243 | let canvas = &mut self.canvas; |
264 | for (idx, val) in self.data.iter().enumerate() { | 244 | for (idx, val) in self.pixmap.data.iter().enumerate() { |
265 | if *val { | 245 | if *val { |
266 | let idx = idx as i32; | 246 | let idx = idx as i32; |
267 | let (x, y) = (idx % self.width as i32, idx / self.height as i32); | 247 | let (x, y) = (idx % width as i32, idx / height as i32); |
268 | canvas.set_draw_color(WHITE); | 248 | canvas.set_draw_color(WHITE); |
269 | canvas | 249 | canvas |
270 | .fill_rect(Rect::new( | 250 | .fill_rect(Rect::new( |
271 | // start drawing 1 pixel after the grid line | 251 | // start drawing 1 pixel after the grid line |
272 | x * cs as i32 + self.start.x() + 1, | 252 | x * cs as i32 + start.x() + 1, |
273 | y * cs as i32 + self.start.y() + 1, | 253 | y * cs as i32 + start.y() + 1, |
274 | // stop drawing 1 pixel before the grid line | 254 | // stop drawing 1 pixel before the grid line |
275 | cs - 1, | 255 | cs - 1, |
276 | cs - 1, | 256 | cs - 1, |
@@ -312,14 +292,12 @@ impl<'ctx> AppState<'ctx> { | |||
312 | .map_err(|e| e.to_string()) | 292 | .map_err(|e| e.to_string()) |
313 | .unwrap(); | 293 | .unwrap(); |
314 | 294 | ||
315 | let data = vec![false; (width * height) as usize]; | 295 | let pixmap = Pixmap::new_with(width, height, false); |
316 | Self { | 296 | Self { |
317 | start: Point::new(60, 60), | 297 | start: Point::new(60, 60), |
318 | width, | ||
319 | height, | ||
320 | data, | ||
321 | zoom: 5, | 298 | zoom: 5, |
322 | brush_size: 1, | 299 | brush_size: 1, |
300 | pixmap, | ||
323 | grid: Grid::new(), | 301 | grid: Grid::new(), |
324 | canvas, | 302 | canvas, |
325 | context, | 303 | context, |
@@ -425,14 +403,12 @@ impl<'ctx> AppState<'ctx> { | |||
425 | } | 403 | } |
426 | // end of operation | 404 | // end of operation |
427 | Event::MouseButtonUp { .. } => self.modify(|e| { | 405 | Event::MouseButtonUp { .. } => self.modify(|e| { |
428 | dbg!(&e.current_operation.len()); | ||
429 | let op = e | 406 | let op = e |
430 | .current_operation | 407 | .current_operation |
431 | .drain(..) | 408 | .drain(..) |
432 | .filter(|v| !v.old_val == v.val) | 409 | .filter(|v| !v.old_val == v.val) |
433 | .collect::<Vec<_>>(); | 410 | .collect::<Vec<_>>(); |
434 | e.undo_stack.push(op); | 411 | e.undo_stack.push(op); |
435 | dbg!(&e.undo_stack); | ||
436 | }), | 412 | }), |
437 | Event::Quit { .. } => { | 413 | Event::Quit { .. } => { |
438 | break 'running; | 414 | break 'running; |
diff --git a/src/main.rs b/src/main.rs index bf89508..cb39648 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | mod app; | 1 | mod app; |
2 | mod bitmap; | ||
2 | mod consts; | 3 | mod consts; |
3 | mod undo; | 4 | mod undo; |
4 | 5 | ||
diff --git a/src/undo.rs b/src/undo.rs index 2249fe7..b590312 100644 --- a/src/undo.rs +++ b/src/undo.rs | |||
@@ -1,12 +1,12 @@ | |||
1 | #[derive(Copy, Clone, Debug)] | 1 | #[derive(Copy, Clone, Debug)] |
2 | pub struct ModifyRecord { | 2 | pub struct ModifyRecord { |
3 | pub point: (i32, i32), | 3 | pub point: (u32, u32), |
4 | pub old_val: bool, | 4 | pub old_val: bool, |
5 | pub val: bool, | 5 | pub val: bool, |
6 | } | 6 | } |
7 | 7 | ||
8 | impl ModifyRecord { | 8 | impl ModifyRecord { |
9 | pub fn new(point: (i32, i32), old_val: bool, val: bool) -> Self { | 9 | pub fn new(point: (u32, u32), old_val: bool, val: bool) -> Self { |
10 | ModifyRecord { | 10 | ModifyRecord { |
11 | point, | 11 | point, |
12 | old_val, | 12 | old_val, |