diff options
Diffstat (limited to 'src/app.rs')
-rw-r--r-- | src/app.rs | 176 |
1 files changed, 130 insertions, 46 deletions
@@ -1,6 +1,6 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | bitmap::{positive_angle_with_x, Axis, MapPoint, Pixmap}, | 2 | bitmap::{positive_angle_with_x, abs_difference, Axis, MapPoint, Pixmap}, |
3 | brush::{Brush, CircleBrush, LineBrush}, | 3 | brush::{Brush, CircleBrush, LineBrush, RectSelectBrush}, |
4 | cache::Cache, | 4 | cache::Cache, |
5 | command::CommandBox, | 5 | command::CommandBox, |
6 | consts::{colors::*, ANGLE, FONT_PATH, RC_PATH, STDLIB_PATH}, | 6 | consts::{colors::*, ANGLE, FONT_PATH, RC_PATH, STDLIB_PATH}, |
@@ -152,6 +152,7 @@ impl<'ctx> AppState<'ctx> { | |||
152 | Brush::Circle(_) => Brush::line(0, false), | 152 | Brush::Circle(_) => Brush::line(0, false), |
153 | Brush::Line(LineBrush { extend: false, .. }) => Brush::line(0, true), | 153 | Brush::Line(LineBrush { extend: false, .. }) => Brush::line(0, true), |
154 | Brush::Line(LineBrush { extend: true, .. }) => Brush::Fill, | 154 | Brush::Line(LineBrush { extend: true, .. }) => Brush::Fill, |
155 | Brush::Fill => Brush::rect(), | ||
155 | _ => Brush::new(0), | 156 | _ => Brush::new(0), |
156 | } | 157 | } |
157 | } | 158 | } |
@@ -444,34 +445,54 @@ impl<'ctx> AppState<'ctx> { | |||
444 | } | 445 | } |
445 | } | 446 | } |
446 | } | 447 | } |
447 | if let Brush::Line(LineBrush { start, size, .. }) = self.brush { | 448 | match self.brush { |
448 | let size = self.zoom as u32 * (size as u32 + 5); | 449 | Brush::Line(LineBrush { start, size, .. }) => { |
449 | if let (Some(from), Some(to)) = (start, pt) { | 450 | let size = self.zoom as u32 * (size as u32 + 5); |
450 | let line = self.pixmap.get_line(from, to.into()); | 451 | if let (Some(from), Some(to)) = (start, pt) { |
451 | let angle = positive_angle_with_x(from, to.into()); | 452 | let line = self.pixmap.get_line(from, to.into()); |
453 | let angle = positive_angle_with_x(from, to.into()); | ||
454 | draw_text( | ||
455 | &mut self.canvas, | ||
456 | self.ttf_context, | ||
457 | format!( | ||
458 | "{:.width$}°", | ||
459 | angle, | ||
460 | width = if (angle - ANGLE).abs() < 1e-3 { 3 } else { 0 } | ||
461 | ), | ||
462 | PINK, | ||
463 | (self.mouse.0 + size as i32, self.mouse.1 + size as i32), | ||
464 | ); | ||
465 | for MapPoint { x, y } in line.into_iter() { | ||
466 | self.canvas.set_draw_color(PINK); | ||
467 | self.canvas | ||
468 | .fill_rect(Rect::new( | ||
469 | x as i32 * cs as i32 + self.start.x(), | ||
470 | y as i32 * cs as i32 + self.start.y(), | ||
471 | cs, | ||
472 | cs, | ||
473 | )) | ||
474 | .unwrap(); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | Brush::RectSelect(RectSelectBrush { start: Some(s), end: Some(e), active_end }) => { | ||
479 | self.canvas.set_draw_color(PINK); | ||
480 | let (width, height) = (abs_difference(s.x, e.x), abs_difference(s.y, e.y)); | ||
481 | let MapPoint{x: start_x, y: start_y} = utils::rect_coords(s, e).0; | ||
482 | let start_loc_x = self.start.x() + (start_x * cs) as i32; | ||
483 | let start_loc_y = self.start.y() + (start_y * cs) as i32; | ||
452 | draw_text( | 484 | draw_text( |
453 | &mut self.canvas, | 485 | &mut self.canvas, |
454 | self.ttf_context, | 486 | self.ttf_context, |
455 | format!( | 487 | format!("{}x{}", width, height), |
456 | "{:.width$}°", | ||
457 | angle, | ||
458 | width = if (angle - ANGLE).abs() < 1e-3 { 3 } else { 0 } | ||
459 | ), | ||
460 | PINK, | 488 | PINK, |
461 | (self.mouse.0 + size as i32, self.mouse.1 + size as i32), | 489 | (start_loc_x, start_loc_y - 20), |
462 | ); | 490 | ); |
463 | for MapPoint { x, y } in line.into_iter() { | 491 | self.canvas.draw_rect( |
464 | self.canvas.set_draw_color(PINK); | 492 | rect!(start_loc_x, start_loc_y, width * cs, height * cs) |
465 | self.canvas | 493 | ).unwrap(); |
466 | .fill_rect(Rect::new( | ||
467 | x as i32 * cs as i32 + self.start.x(), | ||
468 | y as i32 * cs as i32 + self.start.y(), | ||
469 | cs, | ||
470 | cs, | ||
471 | )) | ||
472 | .unwrap(); | ||
473 | } | ||
474 | } | 494 | } |
495 | _ => () | ||
475 | } | 496 | } |
476 | } | 497 | } |
477 | 498 | ||
@@ -699,27 +720,37 @@ impl<'ctx> AppState<'ctx> { | |||
699 | self.pixmap.invert(); | 720 | self.pixmap.invert(); |
700 | self.undo_stack.push(ModifyRecord::Invert); | 721 | self.undo_stack.push(ModifyRecord::Invert); |
701 | } | 722 | } |
723 | // cycle through brushes | ||
702 | Keycode::F => self.cycle_brush(), | 724 | Keycode::F => self.cycle_brush(), |
703 | // bucket fill tool | 725 | // change rect select active end |
726 | Keycode::O => { | ||
727 | match &mut self.brush { | ||
728 | Brush::RectSelect(RectSelectBrush { | ||
729 | active_end, | ||
730 | .. | ||
731 | }) => *active_end = !*active_end, | ||
732 | _ => (), | ||
733 | }; | ||
734 | } | ||
704 | Keycode::V => self.cycle_symmetry(), | 735 | Keycode::V => self.cycle_symmetry(), |
705 | // undo & redo | 736 | // undo |
706 | Keycode::U => { | 737 | Keycode::U => { |
707 | if let Some(op) = self.undo_stack.undo() { | 738 | if let Some(op) = self.undo_stack.undo() { |
708 | self.apply_operation(op, OpKind::Undo); | 739 | self.apply_operation(op, OpKind::Undo); |
709 | } | 740 | } |
710 | } | 741 | } |
742 | // redo | ||
711 | Keycode::R => { | 743 | Keycode::R => { |
712 | if let Some(op) = self.undo_stack.redo() { | 744 | if let Some(op) = self.undo_stack.redo() { |
713 | self.apply_operation(op, OpKind::Redo); | 745 | self.apply_operation(op, OpKind::Redo); |
714 | } | 746 | } |
715 | } | 747 | } |
716 | // export to file | 748 | Keycode::Escape => { |
717 | Keycode::N => { | 749 | match self.brush { |
718 | let image = self.export(); | 750 | Brush::RectSelect(_) => self.brush = Brush::rect(), |
719 | let encoded = image.encode().unwrap(); | 751 | _ => () |
720 | let mut buffer = File::create("test.obi").unwrap(); | 752 | } |
721 | eprintln!("writing to file"); | 753 | continue; |
722 | buffer.write_all(&encoded[..]).unwrap(); | ||
723 | } | 754 | } |
724 | _ if keymod == Mod::LCTRLMOD || keymod == Mod::RCTRLMOD => { | 755 | _ if keymod == Mod::LCTRLMOD || keymod == Mod::RCTRLMOD => { |
725 | self.brush = Brush::line( | 756 | self.brush = Brush::line( |
@@ -783,6 +814,37 @@ impl<'ctx> AppState<'ctx> { | |||
783 | }); | 814 | }); |
784 | } | 815 | } |
785 | } | 816 | } |
817 | Brush::RectSelect(RectSelectBrush { | ||
818 | start, | ||
819 | end, | ||
820 | active_end, | ||
821 | }) => { | ||
822 | if start.is_none() { | ||
823 | self.brush = Brush::RectSelect(RectSelectBrush { | ||
824 | start: contact, | ||
825 | end, | ||
826 | active_end, | ||
827 | }); | ||
828 | } else if end.is_none() { | ||
829 | self.brush = Brush::RectSelect(RectSelectBrush { | ||
830 | start, | ||
831 | end: contact, | ||
832 | active_end, | ||
833 | }); | ||
834 | } else if active_end { | ||
835 | self.brush = Brush::RectSelect(RectSelectBrush { | ||
836 | start, | ||
837 | end: contact, | ||
838 | active_end, | ||
839 | }); | ||
840 | } else { | ||
841 | self.brush = Brush::RectSelect(RectSelectBrush { | ||
842 | start: contact, | ||
843 | end, | ||
844 | active_end, | ||
845 | }); | ||
846 | }; | ||
847 | } | ||
786 | Brush::Fill => { | 848 | Brush::Fill => { |
787 | if let Some(c) = contact { | 849 | if let Some(c) = contact { |
788 | // this `get` is unchecked because contact is checked | 850 | // this `get` is unchecked because contact is checked |
@@ -815,22 +877,44 @@ impl<'ctx> AppState<'ctx> { | |||
815 | Event::MouseMotion { | 877 | Event::MouseMotion { |
816 | x, y, mousestate, .. | 878 | x, y, mousestate, .. |
817 | } => { | 879 | } => { |
818 | let size = match self.brush { | ||
819 | Brush::Circle(CircleBrush { size }) => size, | ||
820 | Brush::Line(LineBrush { size, .. }) => size, | ||
821 | _ => continue, | ||
822 | }; | ||
823 | if mousestate.is_mouse_button_pressed(MouseButton::Left) { | 880 | if mousestate.is_mouse_button_pressed(MouseButton::Left) { |
824 | let pt = (x, y); | 881 | match self.brush { |
825 | let val = self.active_color; | 882 | Brush::RectSelect(RectSelectBrush{start, end, active_end}) => { |
826 | if let Ok(o) = self.paint_point(pt, val, size) { | 883 | if active_end { |
827 | self.current_operation.extend(o); | 884 | self.brush = Brush::RectSelect(RectSelectBrush{ |
885 | start, | ||
886 | end: self.idx_at_coord((x, y)).map(MapPoint::from), | ||
887 | active_end | ||
888 | }); | ||
889 | } else { | ||
890 | self.brush = Brush::RectSelect(RectSelectBrush{ | ||
891 | start: self.idx_at_coord((x, y)).map(MapPoint::from), | ||
892 | end, | ||
893 | active_end | ||
894 | }); | ||
895 | } | ||
896 | }, | ||
897 | Brush::Circle(CircleBrush { size }) | ||
898 | | Brush::Line(LineBrush { size, .. }) => { | ||
899 | let pt = (x, y); | ||
900 | let val = self.active_color; | ||
901 | if let Ok(o) = self.paint_point(pt, val, size) { | ||
902 | self.current_operation.extend(o); | ||
903 | } | ||
904 | }, | ||
905 | _ => () | ||
828 | } | 906 | } |
829 | } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { | 907 | } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { |
830 | let pt = (x, y); | 908 | match self.brush { |
831 | let val = !self.active_color; | 909 | Brush::Circle(CircleBrush { size }) |
832 | if let Ok(o) = self.paint_point(pt, val, size) { | 910 | | Brush::Line(LineBrush { size, .. }) => { |
833 | self.current_operation.extend(o); | 911 | let pt = (x, y); |
912 | let val = !self.active_color; | ||
913 | if let Ok(o) = self.paint_point(pt, val, size) { | ||
914 | self.current_operation.extend(o); | ||
915 | } | ||
916 | }, | ||
917 | _ => () | ||
834 | } | 918 | } |
835 | } | 919 | } |
836 | } | 920 | } |