diff options
author | Akshay <[email protected]> | 2021-03-28 08:28:58 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-03-28 08:28:58 +0100 |
commit | e18777e32448f465748535690666055c179d5d5f (patch) | |
tree | 4211900a8cc2f5642dac459a92fca7eac8bf36e6 /src/app.rs | |
parent | 3e249a2086e7763a366d4cad70bd3c8e7dc9181f (diff) |
add better brush drawing feedback
Diffstat (limited to 'src/app.rs')
-rw-r--r-- | src/app.rs | 107 |
1 files changed, 69 insertions, 38 deletions
@@ -1,5 +1,5 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | bitmap::{MapPoint, Pixmap}, | 2 | bitmap::{positive_angle_with_x, MapPoint, Pixmap}, |
3 | brush::Brush, | 3 | brush::Brush, |
4 | command::CommandBox, | 4 | command::CommandBox, |
5 | consts::{colors::*, FONT_PATH}, | 5 | consts::{colors::*, FONT_PATH}, |
@@ -35,7 +35,6 @@ pub enum Mode { | |||
35 | 35 | ||
36 | pub struct AppState<'ctx, 'file> { | 36 | pub struct AppState<'ctx, 'file> { |
37 | pub active_color: bool, | 37 | pub active_color: bool, |
38 | pub brush_size: u8, | ||
39 | pub brush: Brush, | 38 | pub brush: Brush, |
40 | pub canvas: Canvas<Window>, | 39 | pub canvas: Canvas<Window>, |
41 | pub command_box: CommandBox, | 40 | pub command_box: CommandBox, |
@@ -146,8 +145,9 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
146 | &mut self, | 145 | &mut self, |
147 | center: P, | 146 | center: P, |
148 | val: bool, | 147 | val: bool, |
148 | brush_size: u8, | ||
149 | ) -> Result<Vec<ModifyRecord>, ()> { | 149 | ) -> Result<Vec<ModifyRecord>, ()> { |
150 | let radius = self.brush_size as u32; | 150 | let radius = brush_size as u32; |
151 | let center = self.idx_at_coord(center).ok_or(())?; | 151 | let center = self.idx_at_coord(center).ok_or(())?; |
152 | let dither_level = self.dither_level; | 152 | let dither_level = self.dither_level; |
153 | 153 | ||
@@ -172,6 +172,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
172 | start: MapPoint, | 172 | start: MapPoint, |
173 | end: P, | 173 | end: P, |
174 | val: bool, | 174 | val: bool, |
175 | brush_size: u8, | ||
175 | ) -> Result<Vec<ModifyRecord>, ()> { | 176 | ) -> Result<Vec<ModifyRecord>, ()> { |
176 | let MapPoint { x, y } = start; | 177 | let MapPoint { x, y } = start; |
177 | let end = self.idx_at_coord(end).ok_or(())?; | 178 | let end = self.idx_at_coord(end).ok_or(())?; |
@@ -182,7 +183,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
182 | 183 | ||
183 | let mut line_modify_record = vec![]; | 184 | let mut line_modify_record = vec![]; |
184 | for point in line.into_iter().chain(sym_line) { | 185 | for point in line.into_iter().chain(sym_line) { |
185 | let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32, true); | 186 | let circle_around_point = self.pixmap.get_circle(point, brush_size as u32, true); |
186 | for c in circle_around_point | 187 | for c in circle_around_point |
187 | .into_iter() | 188 | .into_iter() |
188 | .filter(|&pt| dither::bayer(dither_level, pt)) | 189 | .filter(|&pt| dither::bayer(dither_level, pt)) |
@@ -257,15 +258,15 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
257 | ); | 258 | ); |
258 | } | 259 | } |
259 | 260 | ||
260 | pub fn increase_brush_size(&mut self) { | 261 | // pub fn increase_brush_size(&mut self) { |
261 | self.brush_size += 1; | 262 | // self.brush_size += 1; |
262 | } | 263 | // } |
263 | 264 | ||
264 | pub fn decrease_brush_size(&mut self) { | 265 | // pub fn decrease_brush_size(&mut self) { |
265 | if self.brush_size > 0 { | 266 | // if self.brush_size > 0 { |
266 | self.brush_size -= 1; | 267 | // self.brush_size -= 1; |
267 | } | 268 | // } |
268 | } | 269 | // } |
269 | 270 | ||
270 | pub fn reduce_intensity(&mut self) { | 271 | pub fn reduce_intensity(&mut self) { |
271 | if self.dither_level > 0 { | 272 | if self.dither_level > 0 { |
@@ -343,9 +344,8 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
343 | format!("---, ---") | 344 | format!("---, ---") |
344 | }; | 345 | }; |
345 | let status_text = format!( | 346 | let status_text = format!( |
346 | "[DITHER {}][BRUSH {}][SYM {}][PT {}][ACTIVE {}][KIND {}]", | 347 | "[DITHER {}][SYM {}][PT {}][ACTIVE {}][KIND {}]", |
347 | self.dither_level, | 348 | self.dither_level, |
348 | self.brush_size + 1, | ||
349 | self.symmetry, | 349 | self.symmetry, |
350 | mouse_coords, | 350 | mouse_coords, |
351 | if self.active_color { "WHT" } else { "BLK" }, | 351 | if self.active_color { "WHT" } else { "BLK" }, |
@@ -405,22 +405,51 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
405 | } | 405 | } |
406 | 406 | ||
407 | fn draw_mouse(&mut self) { | 407 | fn draw_mouse(&mut self) { |
408 | let brush_size = self.brush_size; | ||
409 | let cs = self.zoom as u32; | 408 | let cs = self.zoom as u32; |
410 | let pt = self.idx_at_coord(self.mouse); | 409 | let pt = self.idx_at_coord(self.mouse); |
411 | if let Some(center) = pt { | 410 | if matches!(self.brush, Brush::Circle { .. } | Brush::Line { .. }) { |
412 | let circle = self.pixmap.get_circle(center, brush_size as u32, false); | 411 | let size = self.brush.size().unwrap(); |
413 | for MapPoint { x, y } in circle.into_iter() { | 412 | if let Some(center) = pt { |
414 | self.canvas.set_draw_color(PINK); | 413 | let circle = self.pixmap.get_circle(center, size as u32, false); |
415 | self.canvas | 414 | for MapPoint { x, y } in circle.into_iter() { |
416 | .fill_rect(Rect::new( | 415 | self.canvas.set_draw_color(PINK); |
417 | x as i32 * cs as i32 + self.start.x(), | 416 | self.canvas |
418 | y as i32 * cs as i32 + self.start.y(), | 417 | .fill_rect(Rect::new( |
419 | cs, | 418 | x as i32 * cs as i32 + self.start.x(), |
420 | cs, | 419 | y as i32 * cs as i32 + self.start.y(), |
421 | )) | 420 | cs, |
422 | .unwrap(); | 421 | cs, |
422 | )) | ||
423 | .unwrap(); | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | match self.brush { | ||
428 | Brush::Line { start, size, .. } => { | ||
429 | let size = self.zoom as u32 * size as u32; | ||
430 | if let (Some(from), Some(to)) = (start, pt) { | ||
431 | let line = self.pixmap.get_line(from, to.into()); | ||
432 | draw_text( | ||
433 | &mut self.canvas, | ||
434 | self.ttf_context, | ||
435 | format!("{}°", positive_angle_with_x(from, to.into())), | ||
436 | PINK, | ||
437 | (self.mouse.0 as u32 + size, self.mouse.1 as u32 + size), | ||
438 | ); | ||
439 | for MapPoint { x, y } in line.into_iter() { | ||
440 | self.canvas.set_draw_color(PINK); | ||
441 | self.canvas | ||
442 | .fill_rect(Rect::new( | ||
443 | x as i32 * cs as i32 + self.start.x(), | ||
444 | y as i32 * cs as i32 + self.start.y(), | ||
445 | cs, | ||
446 | cs, | ||
447 | )) | ||
448 | .unwrap(); | ||
449 | } | ||
450 | } | ||
423 | } | 451 | } |
452 | _ => {} | ||
424 | } | 453 | } |
425 | } | 454 | } |
426 | 455 | ||
@@ -485,9 +514,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
485 | ev.push_event(Event::Quit { timestamp: 0u32 }) | 514 | ev.push_event(Event::Quit { timestamp: 0u32 }) |
486 | .expect("ohno unable to quit"); | 515 | .expect("ohno unable to quit"); |
487 | } | 516 | } |
488 | } | ||
489 | 517 | ||
490 | impl<'ctx, 'file> AppState<'ctx, 'file> { | ||
491 | pub fn init( | 518 | pub fn init( |
492 | width: u32, | 519 | width: u32, |
493 | height: u32, | 520 | height: u32, |
@@ -499,7 +526,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
499 | let video_subsystem = context.video().unwrap(); | 526 | let video_subsystem = context.video().unwrap(); |
500 | 527 | ||
501 | let window = video_subsystem | 528 | let window = video_subsystem |
502 | .window("Pixel editor", 200, 200) | 529 | .window("Pixel editor", 500, 500) |
503 | .position_centered() | 530 | .position_centered() |
504 | .resizable() | 531 | .resizable() |
505 | .opengl() | 532 | .opengl() |
@@ -517,8 +544,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
517 | let pixmap = Pixmap::new_with(width, height, data); | 544 | let pixmap = Pixmap::new_with(width, height, data); |
518 | Self { | 545 | Self { |
519 | active_color: true, | 546 | active_color: true, |
520 | brush_size: 0, | 547 | brush: Brush::new(0), |
521 | brush: Brush::new(), | ||
522 | canvas, | 548 | canvas, |
523 | command_box: CommandBox::new(), | 549 | command_box: CommandBox::new(), |
524 | context, | 550 | context, |
@@ -594,8 +620,8 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
594 | self.zoom_out(cursor); | 620 | self.zoom_out(cursor); |
595 | } | 621 | } |
596 | // brush ops | 622 | // brush ops |
597 | Keycode::Q => self.decrease_brush_size(), | 623 | Keycode::Q => self.brush.shrink(), |
598 | Keycode::E => self.increase_brush_size(), | 624 | Keycode::E => self.brush.grow(), |
599 | Keycode::Num1 => self.reduce_intensity(), | 625 | Keycode::Num1 => self.reduce_intensity(), |
600 | Keycode::Num3 => self.increase_intensity(), | 626 | Keycode::Num3 => self.increase_intensity(), |
601 | // flip color | 627 | // flip color |
@@ -650,7 +676,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
650 | }; | 676 | }; |
651 | match self.brush { | 677 | match self.brush { |
652 | Brush::Circle { size } => { | 678 | Brush::Circle { size } => { |
653 | if let Ok(o) = self.paint_point(pt, val) { | 679 | if let Ok(o) = self.paint_point(pt, val, size) { |
654 | self.current_operation.extend(o); | 680 | self.current_operation.extend(o); |
655 | } | 681 | } |
656 | } | 682 | } |
@@ -666,7 +692,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
666 | extend, | 692 | extend, |
667 | }; | 693 | }; |
668 | } else if let Ok(o) = | 694 | } else if let Ok(o) = |
669 | self.paint_line(start.unwrap(), pt, val) | 695 | self.paint_line(start.unwrap(), pt, val, size) |
670 | { | 696 | { |
671 | self.current_operation.extend(o); | 697 | self.current_operation.extend(o); |
672 | self.brush = Brush::Line { | 698 | self.brush = Brush::Line { |
@@ -705,16 +731,21 @@ impl<'ctx, 'file> AppState<'ctx, 'file> { | |||
705 | Event::MouseMotion { | 731 | Event::MouseMotion { |
706 | x, y, mousestate, .. | 732 | x, y, mousestate, .. |
707 | } => { | 733 | } => { |
734 | let size = match self.brush { | ||
735 | Brush::Circle { size } => size, | ||
736 | Brush::Line { size, .. } => size, | ||
737 | _ => continue, | ||
738 | }; | ||
708 | if mousestate.is_mouse_button_pressed(MouseButton::Left) { | 739 | if mousestate.is_mouse_button_pressed(MouseButton::Left) { |
709 | let pt = (x, y); | 740 | let pt = (x, y); |
710 | let val = self.active_color; | 741 | let val = self.active_color; |
711 | if let Ok(o) = self.paint_point(pt, val) { | 742 | if let Ok(o) = self.paint_point(pt, val, size) { |
712 | self.current_operation.extend(o); | 743 | self.current_operation.extend(o); |
713 | } | 744 | } |
714 | } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { | 745 | } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { |
715 | let pt = (x, y); | 746 | let pt = (x, y); |
716 | let val = !self.active_color; | 747 | let val = !self.active_color; |
717 | if let Ok(o) = self.paint_point(pt, val) { | 748 | if let Ok(o) = self.paint_point(pt, val, size) { |
718 | self.current_operation.extend(o); | 749 | self.current_operation.extend(o); |
719 | } | 750 | } |
720 | } | 751 | } |