aboutsummaryrefslogtreecommitdiff
path: root/src/app.rs
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-28 05:21:41 +0100
committerAkshay <[email protected]>2021-03-28 05:21:41 +0100
commitb06d33b66e70453451bc5eb5ade9164defea4849 (patch)
tree3fa736dccaf1a29df34d71d86e6d67aa693bfd55 /src/app.rs
parentbbfca639547fcd08e51181b70e449e71281d1d9b (diff)
implement flood fill; new fill brush
Diffstat (limited to 'src/app.rs')
-rw-r--r--src/app.rs139
1 files changed, 89 insertions, 50 deletions
diff --git a/src/app.rs b/src/app.rs
index 09f52f9..7bca6ba 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,9 +1,10 @@
1use crate::{ 1use crate::{
2 bitmap::{MapPoint, Pixmap}, 2 bitmap::{MapPoint, Pixmap},
3 brush::Brush,
3 command::CommandBox, 4 command::CommandBox,
4 consts::{colors::*, FONT_PATH}, 5 consts::{colors::*, FONT_PATH},
5 dither, 6 dither,
6 lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList, Environment}, 7 lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList},
7 message::Message, 8 message::Message,
8 rect, 9 rect,
9 symmetry::Symmetry, 10 symmetry::Symmetry,
@@ -11,12 +12,7 @@ use crate::{
11 utils::{draw_text, is_copy_event, is_paste_event}, 12 utils::{draw_text, is_copy_event, is_paste_event},
12}; 13};
13 14
14use std::{ 15use std::{convert::From, fs::File, io::prelude::*, path::Path};
15 convert::From,
16 fs::File,
17 io::prelude::*,
18 path::{Path, PathBuf},
19};
20 16
21use obi::Image; 17use obi::Image;
22use sdl2::{ 18use sdl2::{
@@ -40,6 +36,7 @@ pub enum Mode {
40pub struct AppState<'ctx, 'file> { 36pub struct AppState<'ctx, 'file> {
41 pub active_color: bool, 37 pub active_color: bool,
42 pub brush_size: u8, 38 pub brush_size: u8,
39 pub brush: Brush,
43 pub canvas: Canvas<Window>, 40 pub canvas: Canvas<Window>,
44 pub command_box: CommandBox, 41 pub command_box: CommandBox,
45 pub context: &'ctx Sdl, 42 pub context: &'ctx Sdl,
@@ -204,7 +201,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
204 val, 201 val,
205 } in op.into_iter() 202 } in op.into_iter()
206 { 203 {
207 if self.pixmap.is_inside(point) { 204 if self.pixmap.contains(point) {
208 match op_kind { 205 match op_kind {
209 OpKind::Undo => self.pixmap.set(point, old_val), 206 OpKind::Undo => self.pixmap.set(point, old_val),
210 OpKind::Redo => self.pixmap.set(point, val), 207 OpKind::Redo => self.pixmap.set(point, val),
@@ -346,12 +343,13 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
346 format!("---, ---") 343 format!("---, ---")
347 }; 344 };
348 let status_text = format!( 345 let status_text = format!(
349 "[DITHER {}][BRUSH {}][SYM {}][PT {}][ACTIVE {}]", 346 "[DITHER {}][BRUSH {}][SYM {}][PT {}][ACTIVE {}][KIND {}]",
350 self.dither_level, 347 self.dither_level,
351 self.brush_size + 1, 348 self.brush_size + 1,
352 self.symmetry, 349 self.symmetry,
353 mouse_coords, 350 mouse_coords,
354 if self.active_color { "WHT" } else { "BLK" } 351 if self.active_color { "WHT" } else { "BLK" },
352 self.brush
355 ); 353 );
356 draw_text( 354 draw_text(
357 &mut self.canvas, 355 &mut self.canvas,
@@ -426,13 +424,31 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
426 } 424 }
427 } 425 }
428 426
427 fn draw_symmetry(&mut self) {
428 let (winsize_x, winsize_y) = self.canvas.window().size();
429 let cs = self.zoom as u32;
430 let Symmetry { x: sym_x, y: sym_y } = self.symmetry;
431 if let Some(line) = sym_x {
432 self.canvas.set_draw_color(CYAN);
433 let line_coord = (line * cs) as i32 + self.start.y() + (cs / 2) as i32;
434 self.canvas
435 .draw_line((0, line_coord), (winsize_x as i32, line_coord))
436 .unwrap();
437 }
438 if let Some(line) = sym_y {
439 self.canvas.set_draw_color(CYAN);
440 let line_coord = (line * cs) as i32 + self.start.x() + (cs / 2) as i32;
441 self.canvas
442 .draw_line((line_coord, 0), (line_coord, winsize_y as i32))
443 .unwrap();
444 }
445 }
446
429 fn draw(&mut self) { 447 fn draw(&mut self) {
430 let cs = self.zoom as u32; 448 let cs = self.zoom as u32;
431 let (width, height) = (self.width(), self.height()); 449 let (width, height) = (self.width(), self.height());
432 let start = self.start; 450 let start = self.start;
433 let grid_enabled = self.grid.enabled; 451 let grid_enabled = self.grid.enabled;
434 let (winsize_x, winsize_y) = self.canvas.window().size();
435 let Symmetry { x: sym_x, y: sym_y } = self.symmetry;
436 for (idx, val) in self.pixmap.data.iter().enumerate() { 452 for (idx, val) in self.pixmap.data.iter().enumerate() {
437 if *val { 453 if *val {
438 let idx = idx as i32; 454 let idx = idx as i32;
@@ -451,20 +467,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
451 if grid_enabled { 467 if grid_enabled {
452 self.draw_grid(); 468 self.draw_grid();
453 } 469 }
454 if let Some(line) = sym_x { 470 self.draw_symmetry();
455 self.canvas.set_draw_color(CYAN);
456 let line_coord = (line * cs) as i32 + self.start.y() + (cs / 2) as i32;
457 self.canvas
458 .draw_line((0, line_coord), (winsize_x as i32, line_coord))
459 .unwrap();
460 }
461 if let Some(line) = sym_y {
462 self.canvas.set_draw_color(CYAN);
463 let line_coord = (line * cs) as i32 + self.start.x() + (cs / 2) as i32;
464 self.canvas
465 .draw_line((line_coord, 0), (line_coord, winsize_y as i32))
466 .unwrap();
467 }
468 self.draw_statusline(); 471 self.draw_statusline();
469 self.draw_command_box(); 472 self.draw_command_box();
470 self.draw_mouse(); 473 self.draw_mouse();
@@ -515,6 +518,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
515 Self { 518 Self {
516 active_color: true, 519 active_color: true,
517 brush_size: 0, 520 brush_size: 0,
521 brush: Brush::new(),
518 canvas, 522 canvas,
519 command_box: CommandBox::new(), 523 command_box: CommandBox::new(),
520 context, 524 context,
@@ -602,22 +606,14 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
602 Keycode::I => self.pixmap.invert(), 606 Keycode::I => self.pixmap.invert(),
603 // line drawing 607 // line drawing
604 Keycode::F => { 608 Keycode::F => {
605 let end: Point = (mouse.x(), mouse.y()).into(); 609 if matches!(self.brush, Brush::Line { extend: false, .. }) {
606 if let Some(start) = self.last_point { 610 self.brush = Brush::line(0, true);
607 if let Ok(o) = 611 } else {
608 self.paint_line(start, end, self.active_color) 612 self.brush = Brush::line(0, false);
609 {
610 self.commit_operation();
611 self.current_operation = o
612 .into_iter()
613 .filter(|v| !v.old_val == v.val)
614 .collect();
615 self.commit_operation();
616 self.last_point =
617 Some(self.idx_at_coord(end).unwrap().into());
618 }
619 } 613 }
620 } 614 }
615 // bucket fill tool
616 Keycode::B => self.brush = Brush::Fill,
621 Keycode::V => self.cycle_symmetry(), 617 Keycode::V => self.cycle_symmetry(),
622 // undo & redo 618 // undo & redo
623 Keycode::U => { 619 Keycode::U => {
@@ -646,13 +642,63 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
646 x, y, mouse_btn, .. 642 x, y, mouse_btn, ..
647 } => { 643 } => {
648 let pt = (x, y); 644 let pt = (x, y);
645 let contact = self.idx_at_coord(pt).map(MapPoint::from);
649 self.last_point = self.idx_at_coord(pt).map(MapPoint::from); 646 self.last_point = self.idx_at_coord(pt).map(MapPoint::from);
650 let val = match mouse_btn { 647 let val = match mouse_btn {
651 MouseButton::Right => !self.active_color, 648 MouseButton::Right => !self.active_color,
652 _ => self.active_color, 649 _ => self.active_color,
653 }; 650 };
654 if let Ok(o) = self.paint_point(pt, val) { 651 match self.brush {
655 self.current_operation.extend(o); 652 Brush::Circle { size } => {
653 if let Ok(o) = self.paint_point(pt, val) {
654 self.current_operation.extend(o);
655 }
656 }
657 Brush::Line {
658 size,
659 start,
660 extend,
661 } => {
662 if start.is_none() {
663 self.brush = Brush::Line {
664 size,
665 start: contact,
666 extend,
667 };
668 } else if let Ok(o) =
669 self.paint_line(start.unwrap(), pt, val)
670 {
671 self.current_operation.extend(o);
672 self.brush = Brush::Line {
673 size,
674 start: if extend { contact } else { None },
675 extend,
676 };
677 }
678 }
679 Brush::Fill => {
680 if let Some(c) = contact {
681 let target = self.pixmap.get(c);
682 let mut operation = vec![];
683 self.pixmap.flood_fill(
684 c,
685 target,
686 self.active_color,
687 &mut operation,
688 );
689 self.current_operation.extend(
690 operation
691 .into_iter()
692 .map(|point| ModifyRecord {
693 point,
694 old_val: target,
695 val: self.active_color,
696 })
697 .collect::<Vec<ModifyRecord>>(),
698 )
699 }
700 }
701 _ => {}
656 } 702 }
657 } 703 }
658 // click and drag 704 // click and drag
@@ -674,14 +720,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
674 } 720 }
675 } 721 }
676 // end of operation 722 // end of operation
677 Event::MouseButtonUp { .. } => { 723 Event::MouseButtonUp { .. } => self.commit_operation(),
678 let op = self
679 .current_operation
680 .drain(..)
681 .filter(|v| !v.old_val == v.val)
682 .collect::<Vec<_>>();
683 self.undo_stack.push(op);
684 }
685 Event::Quit { .. } => { 724 Event::Quit { .. } => {
686 break 'running; 725 break 'running;
687 } 726 }