aboutsummaryrefslogtreecommitdiff
path: root/src/app.rs
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-17 12:22:40 +0000
committerAkshay <[email protected]>2021-03-17 12:22:40 +0000
commit7615546fb0157c3ec9d2f25ec9837ee0b6cb7e9a (patch)
treeb197326f7812ec20e2207b0e444f2a50569c5b74 /src/app.rs
parent83732aed1a41a713cd8790fcebae90aabe78b789 (diff)
feat: basic command mode, add text box primitives
Diffstat (limited to 'src/app.rs')
-rw-r--r--src/app.rs308
1 files changed, 211 insertions, 97 deletions
diff --git a/src/app.rs b/src/app.rs
index 5b27422..0eac084 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -23,21 +23,29 @@ use sdl2::{
23 Sdl, 23 Sdl,
24}; 24};
25 25
26#[derive(Debug, Copy, Clone, PartialEq)]
27pub enum Mode {
28 Draw,
29 Command,
30}
31
26pub struct AppState<'ctx> { 32pub struct AppState<'ctx> {
27 active_color: bool, 33 active_color: bool,
28 brush_size: u8, 34 brush_size: u8,
29 dither_level: u8,
30 canvas: Canvas<Window>, 35 canvas: Canvas<Window>,
31 context: &'ctx Sdl, 36 context: &'ctx Sdl,
32 ttf_context: &'ctx Sdl2TtfContext,
33 mouse: (i32, i32),
34 current_operation: Operation, 37 current_operation: Operation,
38 dither_level: u8,
35 grid: Grid, 39 grid: Grid,
36 last_point: Option<Point>, 40 last_point: Option<MapPoint>,
41 mode: Mode,
42 mouse: (i32, i32),
37 pixmap: Pixmap<bool>, 43 pixmap: Pixmap<bool>,
38 start: Point, 44 start: Point,
39 symmetry: Symmetry, 45 symmetry: Symmetry,
46 ttf_context: &'ctx Sdl2TtfContext,
40 undo_stack: UndoStack<Operation>, 47 undo_stack: UndoStack<Operation>,
48 command_box: CommandBox,
41 zoom: u8, 49 zoom: u8,
42} 50}
43 51
@@ -153,15 +161,15 @@ impl<'ctx> AppState<'ctx> {
153 161
154 fn paint_line<P: Into<Point>>( 162 fn paint_line<P: Into<Point>>(
155 &mut self, 163 &mut self,
156 start: P, 164 start: MapPoint,
157 end: P, 165 end: P,
158 val: bool, 166 val: bool,
159 ) -> Result<Vec<ModifyRecord>, ()> { 167 ) -> Result<Vec<ModifyRecord>, ()> {
160 let start = self.idx_at_coord(start).ok_or(())?; 168 let MapPoint { x, y } = start;
161 let end = self.idx_at_coord(end).ok_or(())?; 169 let end = self.idx_at_coord(end).ok_or(())?;
162 let dither_level = self.dither_level; 170 let dither_level = self.dither_level;
163 171
164 let line = self.pixmap.get_line(start, end); 172 let line = self.pixmap.get_line((x, y), end);
165 let sym_line = self.symmetry.apply(&line); 173 let sym_line = self.symmetry.apply(&line);
166 174
167 let mut line_modify_record = vec![]; 175 let mut line_modify_record = vec![];
@@ -239,6 +247,21 @@ impl<'ctx> AppState<'ctx> {
239 } 247 }
240 } 248 }
241 249
250 fn eval_command(&mut self) {
251 match self.command_box.text.as_str() {
252 "(save)" => {
253 let image = self.export();
254 let encoded = image.encode().unwrap();
255 let mut buffer = File::create("test.obi").unwrap();
256 eprintln!("writing to file");
257 buffer.write_all(&encoded[..]).unwrap();
258 }
259 _ => {}
260 }
261 self.command_box.clear();
262 self.mode = Mode::Draw;
263 }
264
242 fn zoom_out(&mut self, p: (i32, i32)) { 265 fn zoom_out(&mut self, p: (i32, i32)) {
243 if self.zoom > 1 { 266 if self.zoom > 1 {
244 // attempt to center around cursor 267 // attempt to center around cursor
@@ -309,6 +332,27 @@ impl<'ctx> AppState<'ctx> {
309 ); 332 );
310 } 333 }
311 334
335 fn draw_command_box(&mut self) {
336 if self.command_box.is_empty() {
337 self.mode = Mode::Draw;
338 return;
339 }
340 let (winsize_x, winsize_y) = self.canvas.window().size();
341 let cmd_height: u32 = 20;
342 let cmd_width = winsize_x;
343 self.canvas.set_draw_color(WHITE);
344 self.canvas
345 .fill_rect(rect!(0, winsize_y - cmd_height, cmd_width, cmd_height))
346 .unwrap();
347 draw_text(
348 &mut self.canvas,
349 self.ttf_context,
350 &self.command_box.text[..],
351 BLACK,
352 (0, winsize_y - cmd_height),
353 );
354 }
355
312 fn draw_mouse(&mut self) { 356 fn draw_mouse(&mut self) {
313 let brush_size = self.brush_size; 357 let brush_size = self.brush_size;
314 let cs = self.zoom as u32; 358 let cs = self.zoom as u32;
@@ -368,7 +412,11 @@ impl<'ctx> AppState<'ctx> {
368 .draw_line((line_coord, 0), (line_coord, winsize_y as i32)) 412 .draw_line((line_coord, 0), (line_coord, winsize_y as i32))
369 .unwrap(); 413 .unwrap();
370 } 414 }
371 self.draw_statusline(); 415 if self.mode == Mode::Draw {
416 self.draw_statusline();
417 } else {
418 self.draw_command_box();
419 }
372 self.draw_mouse(); 420 self.draw_mouse();
373 } 421 }
374 422
@@ -446,109 +494,175 @@ impl<'ctx> AppState<'ctx> {
446 let mouse = event_pump.mouse_state(); 494 let mouse = event_pump.mouse_state();
447 self.mouse = (mouse.x(), mouse.y()); 495 self.mouse = (mouse.x(), mouse.y());
448 for event in event_pump.poll_iter() { 496 for event in event_pump.poll_iter() {
449 match event { 497 if let Event::KeyDown {
450 Event::KeyDown { 498 keycode: Some(Keycode::Num9),
451 keycode: Some(k), .. 499 keymod,
452 } => { 500 ..
453 match k { 501 } = event
454 // pan 502 {
455 Keycode::W => self.pan((0, 10)), 503 if keymod == Mod::LSHIFTMOD || keymod == Mod::RSHIFTMOD {
456 Keycode::A => self.pan((10, 0)), 504 self.mode = Mode::Command;
457 Keycode::S => self.pan((0, -10)), 505 }
458 Keycode::D => self.pan((-10, 0)), 506 }
459 // zoom 507 match self.mode {
460 Keycode::C => { 508 Mode::Draw => {
461 let cursor = (mouse.x(), mouse.y()); 509 match event {
462 self.zoom_in(cursor); 510 Event::KeyDown {
463 } 511 keycode: Some(k), ..
464 Keycode::Z => { 512 } => {
465 let cursor = (mouse.x(), mouse.y()); 513 match k {
466 self.zoom_out(cursor); 514 // pan
467 } 515 Keycode::W => self.pan((0, 10)),
468 // brush ops 516 Keycode::A => self.pan((10, 0)),
469 Keycode::Q => self.decrease_brush_size(), 517 Keycode::S => self.pan((0, -10)),
470 Keycode::E => self.increase_brush_size(), 518 Keycode::D => self.pan((-10, 0)),
471 Keycode::Num1 => self.reduce_intensity(), 519 // zoom
472 Keycode::Num3 => self.increase_intensity(), 520 Keycode::C => {
473 // flip color 521 let cursor = (mouse.x(), mouse.y());
474 Keycode::X => self.change_active_color(), 522 self.zoom_in(cursor);
475 // toggle grid
476 Keycode::Tab => self.toggle_grid(),
477 // line drawing
478 Keycode::F => {
479 let end = (mouse.x(), mouse.y()).into();
480 if let Some(start) = self.last_point {
481 if let Ok(o) = self.paint_line(start, end, self.active_color) {
482 self.commit_operation();
483 self.current_operation =
484 o.into_iter().filter(|v| !v.old_val == v.val).collect();
485 self.commit_operation();
486 self.last_point = Some(end);
487 } 523 }
524 Keycode::Z => {
525 let cursor = (mouse.x(), mouse.y());
526 self.zoom_out(cursor);
527 }
528 // brush ops
529 Keycode::Q => self.decrease_brush_size(),
530 Keycode::E => self.increase_brush_size(),
531 Keycode::Num1 => self.reduce_intensity(),
532 Keycode::Num3 => self.increase_intensity(),
533 // flip color
534 Keycode::X => self.change_active_color(),
535 // toggle grid
536 Keycode::Tab => self.toggle_grid(),
537 // line drawing
538 Keycode::F => {
539 let end: Point = (mouse.x(), mouse.y()).into();
540 if let Some(start) = self.last_point {
541 if let Ok(o) =
542 self.paint_line(start, end, self.active_color)
543 {
544 self.commit_operation();
545 self.current_operation = o
546 .into_iter()
547 .filter(|v| !v.old_val == v.val)
548 .collect();
549 self.commit_operation();
550 self.last_point =
551 Some(self.idx_at_coord(end).unwrap().into());
552 }
553 }
554 }
555 Keycode::V => self.cycle_symmetry(),
556 // exit
557 Keycode::Escape => break 'running,
558 // undo & redo
559 Keycode::U => {
560 if let Some(op) = self.undo_stack.undo() {
561 self.apply_operation(op, OpKind::Undo);
562 }
563 }
564 // export to file
565 Keycode::N => {
566 let image = self.export();
567 let encoded = image.encode().unwrap();
568 let mut buffer = File::create("test.obi").unwrap();
569 eprintln!("writing to file");
570 buffer.write_all(&encoded[..]).unwrap();
571 }
572 Keycode::R => {
573 if let Some(op) = self.undo_stack.redo() {
574 self.apply_operation(op, OpKind::Redo);
575 }
576 }
577 _ => (),
488 } 578 }
489 } 579 }
490 Keycode::V => self.cycle_symmetry(), 580 // start of operation
491 // exit 581 Event::MouseButtonDown {
492 Keycode::Escape => break 'running, 582 x, y, mouse_btn, ..
493 // undo & redo 583 } => {
494 Keycode::U => { 584 let pt = (x, y);
495 if let Some(op) = self.undo_stack.undo() { 585 self.last_point = self.idx_at_coord(pt).map(MapPoint::from);
496 self.apply_operation(op, OpKind::Undo); 586 let val = match mouse_btn {
587 MouseButton::Right => !self.active_color,
588 _ => self.active_color,
589 };
590 if let Ok(o) = self.paint_point(pt, val) {
591 self.current_operation.extend(o);
497 } 592 }
498 } 593 }
499 Keycode::R => { 594 // click and drag
500 if let Some(op) = self.undo_stack.redo() { 595 Event::MouseMotion {
501 self.apply_operation(op, OpKind::Redo); 596 x, y, mousestate, ..
597 } => {
598 if mousestate.is_mouse_button_pressed(MouseButton::Left) {
599 let pt = (x, y);
600 let val = self.active_color;
601 if let Ok(o) = self.paint_point(pt, val) {
602 self.current_operation.extend(o);
603 }
604 } else if mousestate.is_mouse_button_pressed(MouseButton::Right) {
605 let pt = (x, y);
606 let val = !self.active_color;
607 if let Ok(o) = self.paint_point(pt, val) {
608 self.current_operation.extend(o);
609 }
502 } 610 }
503 } 611 }
504 _ => (), 612 // end of operation
613 Event::MouseButtonUp { .. } => {
614 let op = self
615 .current_operation
616 .drain(..)
617 .filter(|v| !v.old_val == v.val)
618 .collect::<Vec<_>>();
619 self.undo_stack.push(op);
620 }
621 Event::Quit { .. } => {
622 break 'running;
623 }
624 _ => {}
505 } 625 }
506 } 626 }
507 // start of operation 627 Mode::Command => {
508 Event::MouseButtonDown { 628 if let Event::KeyDown {
509 x, y, mouse_btn, .. 629 keycode, keymod, ..
510 } => { 630 } = event
511 let pt = (x, y); 631 {
512 self.last_point = Some(pt.into()); 632 let video = self.context.video().unwrap();
513 let val = match mouse_btn { 633 let clipboard = video.clipboard();
514 MouseButton::Right => !self.active_color, 634 if is_copy_event(keycode, keymod) {
515 _ => self.active_color, 635 clipboard.set_clipboard_text(&self.command_box.text);
516 }; 636 } else if is_paste_event(keycode, keymod)
517 if let Ok(o) = self.paint_point(pt, val) { 637 && clipboard.has_clipboard_text()
518 self.current_operation.extend(o); 638 {
639 self.command_box.text = clipboard.clipboard_text().unwrap();
640 }
519 } 641 }
520 } 642 if let Event::KeyDown {
521 // click and drag 643 keycode: Some(k), ..
522 Event::MouseMotion { 644 } = event
523 x, y, mousestate, .. 645 {
524 } => { 646 match k {
525 if mousestate.is_mouse_button_pressed(MouseButton::Left) { 647 Keycode::Backspace => self.command_box.backspace(),
526 let pt = (x, y); 648 Keycode::Delete => self.command_box.delete(),
527 let val = self.active_color; 649 Keycode::Left => self.command_box.backward(),
528 if let Ok(o) = self.paint_point(pt, val) { 650 Keycode::Right => self.command_box.forward(),
529 self.current_operation.extend(o); 651 Keycode::Return => self.eval_command(),
652 Keycode::Escape => {
653 self.command_box.clear();
654 self.mode = Mode::Draw;
655 }
656 _ => (),
530 } 657 }
531 } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { 658 }
532 let pt = (x, y); 659 match event {
533 let val = !self.active_color; 660 Event::TextInput { text, .. } => {
534 if let Ok(o) = self.paint_point(pt, val) { 661 self.command_box.push_str(&text[..]);
535 self.current_operation.extend(o);
536 } 662 }
663 _ => (),
537 } 664 }
538 } 665 }
539 // end of operation
540 Event::MouseButtonUp { .. } => {
541 let op = self
542 .current_operation
543 .drain(..)
544 .filter(|v| !v.old_val == v.val)
545 .collect::<Vec<_>>();
546 self.undo_stack.push(op);
547 }
548 Event::Quit { .. } => {
549 break 'running;
550 }
551 _ => {}
552 } 666 }
553 } 667 }
554 self.redraw(); 668 self.redraw();