diff options
-rw-r--r-- | src/app.rs | 39 | ||||
-rw-r--r-- | src/lisp/eval.rs | 9 | ||||
-rw-r--r-- | src/main.rs | 32 | ||||
-rw-r--r-- | src/render.rs | 19 |
4 files changed, 56 insertions, 43 deletions
@@ -11,6 +11,7 @@ use crate::{ | |||
11 | lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList}, | 11 | lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList}, |
12 | message::Message, | 12 | message::Message, |
13 | rect, | 13 | rect, |
14 | render::Signal, | ||
14 | symmetry::Symmetry, | 15 | symmetry::Symmetry, |
15 | undo::{ModifyRecord, OpKind, PaintRecord, UndoStack}, | 16 | undo::{ModifyRecord, OpKind, PaintRecord, UndoStack}, |
16 | utils::{self, draw_text, handle_error, is_copy_event, is_paste_event, load_script}, | 17 | utils::{self, draw_text, handle_error, is_copy_event, is_paste_event, load_script}, |
@@ -24,6 +25,7 @@ use std::{ | |||
24 | fs::File, | 25 | fs::File, |
25 | io::prelude::*, | 26 | io::prelude::*, |
26 | path::{Path, PathBuf}, | 27 | path::{Path, PathBuf}, |
28 | sync::mpsc::{Receiver, Sender}, | ||
27 | }; | 29 | }; |
28 | 30 | ||
29 | use obi::{CompressionType, Image}; | 31 | use obi::{CompressionType, Image}; |
@@ -45,13 +47,11 @@ pub enum Mode { | |||
45 | Command, | 47 | Command, |
46 | } | 48 | } |
47 | 49 | ||
48 | pub struct AppState<'ctx> { | 50 | pub struct AppState { |
49 | pub active_color: bool, | 51 | pub active_color: bool, |
50 | pub brush: Brush, | 52 | pub brush: Brush, |
51 | pub canvas: Canvas<Window>, | ||
52 | pub command_box: CommandBox, | 53 | pub command_box: CommandBox, |
53 | pub cache: RefCell<Option<Cache>>, | 54 | pub cache: RefCell<Option<Cache>>, |
54 | pub context: &'ctx Sdl, | ||
55 | pub current_operation: Vec<PaintRecord>, | 55 | pub current_operation: Vec<PaintRecord>, |
56 | pub dither_level: u8, | 56 | pub dither_level: u8, |
57 | pub file_name: Option<PathBuf>, | 57 | pub file_name: Option<PathBuf>, |
@@ -60,17 +60,17 @@ pub struct AppState<'ctx> { | |||
60 | pub lisp_env: EnvList, | 60 | pub lisp_env: EnvList, |
61 | pub message: Message, | 61 | pub message: Message, |
62 | pub mode: Mode, | 62 | pub mode: Mode, |
63 | pub mouse: (i32, i32), | ||
64 | pub pixmap: Pixmap<bool>, | 63 | pub pixmap: Pixmap<bool>, |
65 | pub start: Point, | 64 | pub start: Point, |
66 | pub symmetry: Symmetry, | 65 | pub symmetry: Symmetry, |
67 | pub ttf_context: &'ctx Sdl2TtfContext, | ||
68 | pub undo_stack: UndoStack<ModifyRecord>, | 66 | pub undo_stack: UndoStack<ModifyRecord>, |
69 | pub zoom: u8, | 67 | pub zoom: u8, |
68 | pub sender: Sender<Signal>, | ||
69 | pub receiver: Receiver<Signal>, | ||
70 | } | 70 | } |
71 | 71 | ||
72 | // private actions on appstate | 72 | // private actions on appstate |
73 | impl<'ctx> AppState<'ctx> { | 73 | impl AppState { |
74 | fn pan<P: Into<Point>>(&mut self, direction: P) { | 74 | fn pan<P: Into<Point>>(&mut self, direction: P) { |
75 | self.start += direction.into(); | 75 | self.start += direction.into(); |
76 | } | 76 | } |
@@ -602,34 +602,17 @@ impl<'ctx> AppState<'ctx> { | |||
602 | pub fn init( | 602 | pub fn init( |
603 | width: u32, | 603 | width: u32, |
604 | height: u32, | 604 | height: u32, |
605 | context: &'ctx Sdl, | 605 | sender: Sender<Signal>, |
606 | ttf_context: &'ctx Sdl2TtfContext, | 606 | receiver: Receiver<Signal>, |
607 | start_data: Option<Vec<bool>>, | 607 | start_data: Option<Vec<bool>>, |
608 | file_name: Option<PathBuf>, | 608 | file_name: Option<PathBuf>, |
609 | ) -> Result<Self, AppError> { | 609 | ) -> Result<Self, AppError> { |
610 | let video_subsystem = context.video().map_err(AppError::Sdl)?; | ||
611 | |||
612 | let window = video_subsystem | ||
613 | .window("Pixel editor", 500, 500) | ||
614 | .position_centered() | ||
615 | .resizable() | ||
616 | .opengl() | ||
617 | .build() | ||
618 | .map_err(|e| AppError::Sdl(e.to_string()))?; | ||
619 | |||
620 | let canvas = window | ||
621 | .into_canvas() | ||
622 | .build() | ||
623 | .map_err(|e| AppError::Sdl(e.to_string()))?; | ||
624 | |||
625 | let data = start_data.unwrap_or_else(|| vec![false; (width * height) as usize]); | 610 | let data = start_data.unwrap_or_else(|| vec![false; (width * height) as usize]); |
626 | let pixmap = Pixmap::new_with(width, height, data); | 611 | let pixmap = Pixmap::new_with(width, height, data); |
627 | let mut app = Self { | 612 | let mut app = Self { |
628 | active_color: true, | 613 | active_color: true, |
629 | brush: Brush::new(0), | 614 | brush: Brush::new(0), |
630 | canvas, | ||
631 | command_box: CommandBox::new(), | 615 | command_box: CommandBox::new(), |
632 | context, | ||
633 | cache: RefCell::new(None), | 616 | cache: RefCell::new(None), |
634 | guides: HashMap::new(), | 617 | guides: HashMap::new(), |
635 | current_operation: Vec::new(), | 618 | current_operation: Vec::new(), |
@@ -639,13 +622,13 @@ impl<'ctx> AppState<'ctx> { | |||
639 | lisp_env: vec![prelude::new_env().map_err(AppError::Lisp)?], | 622 | lisp_env: vec![prelude::new_env().map_err(AppError::Lisp)?], |
640 | message: Message::new().text(" "), | 623 | message: Message::new().text(" "), |
641 | mode: Mode::Draw, | 624 | mode: Mode::Draw, |
642 | mouse: (0, 0), | ||
643 | pixmap, | 625 | pixmap, |
644 | start: Point::new(60, 60), | 626 | start: Point::new(60, 60), |
645 | symmetry: Default::default(), | 627 | symmetry: Default::default(), |
646 | ttf_context, | ||
647 | undo_stack: UndoStack::new(), | 628 | undo_stack: UndoStack::new(), |
648 | zoom: 5, | 629 | zoom: 5, |
630 | sender, | ||
631 | receiver, | ||
649 | }; | 632 | }; |
650 | load_script(STDLIB_PATH, &mut app).map_err(AppError::Lisp)?; | 633 | load_script(STDLIB_PATH, &mut app).map_err(AppError::Lisp)?; |
651 | std::fs::create_dir_all(RC_PATH).map_err(AppError::File)?; | 634 | std::fs::create_dir_all(RC_PATH).map_err(AppError::File)?; |
@@ -676,8 +659,6 @@ impl<'ctx> AppState<'ctx> { | |||
676 | 659 | ||
677 | let mut event_pump = self.context.event_pump().unwrap(); | 660 | let mut event_pump = self.context.event_pump().unwrap(); |
678 | 'running: loop { | 661 | 'running: loop { |
679 | let mouse = event_pump.mouse_state(); | ||
680 | self.mouse = (mouse.x(), mouse.y()); | ||
681 | for event in event_pump.poll_iter() { | 662 | for event in event_pump.poll_iter() { |
682 | if let Event::KeyDown { | 663 | if let Event::KeyDown { |
683 | keycode: Some(Keycode::Num9), | 664 | keycode: Some(Keycode::Num9), |
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index 75cb5c9..759cca0 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -14,15 +14,12 @@ use log::{error, info}; | |||
14 | 14 | ||
15 | pub type Context = Vec<String>; | 15 | pub type Context = Vec<String>; |
16 | 16 | ||
17 | pub struct Evaluator<'ctx, 'global> { | 17 | pub struct Evaluator<'global> { |
18 | pub app: &'global mut AppState<'ctx>, | 18 | pub app: &'global mut AppState, |
19 | pub context: Context, | 19 | pub context: Context, |
20 | } | 20 | } |
21 | 21 | ||
22 | impl<'ctx, 'global> Evaluator<'ctx, 'global> | 22 | impl<'global> Evaluator<'global> { |
23 | where | ||
24 | 'ctx: 'global, | ||
25 | { | ||
26 | pub fn eval(&mut self, expr: &LispExpr) -> Result<LispExpr, LispError> { | 23 | pub fn eval(&mut self, expr: &LispExpr) -> Result<LispExpr, LispError> { |
27 | match expr { | 24 | match expr { |
28 | LispExpr::Unit => Ok(expr.clone()), | 25 | LispExpr::Unit => Ok(expr.clone()), |
diff --git a/src/main.rs b/src/main.rs index 225c37c..04b0f2b 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -18,6 +18,7 @@ mod grid; | |||
18 | mod guide; | 18 | mod guide; |
19 | mod lisp; | 19 | mod lisp; |
20 | mod message; | 20 | mod message; |
21 | mod render; | ||
21 | mod symmetry; | 22 | mod symmetry; |
22 | mod undo; | 23 | mod undo; |
23 | mod utils; | 24 | mod utils; |
@@ -27,12 +28,19 @@ use { | |||
27 | app::AppState, | 28 | app::AppState, |
28 | cli::Config, | 29 | cli::Config, |
29 | error::{AppError, SdlTTFError}, | 30 | error::{AppError, SdlTTFError}, |
31 | render::Signal, | ||
30 | }; | 32 | }; |
31 | 33 | ||
34 | use std::{sync::mpsc, thread}; | ||
35 | |||
32 | use log::{error, info}; | 36 | use log::{error, info}; |
37 | use sdl2::event::Event; | ||
33 | 38 | ||
34 | pub fn error_sink() -> Result<(), AppError> { | 39 | pub fn error_sink() -> Result<(), AppError> { |
35 | let init = || { | 40 | let (render_tx, app_rx) = mpsc::channel(); |
41 | let (app_tx, render_rx) = mpsc::channel(); | ||
42 | |||
43 | let render_handle = thread::spawn(move || -> Result<(), AppError> { | ||
36 | let sdl_context = sdl2::init().map_err(AppError::Sdl)?; | 44 | let sdl_context = sdl2::init().map_err(AppError::Sdl)?; |
37 | info!("Initialized SDL context"); | 45 | info!("Initialized SDL context"); |
38 | 46 | ||
@@ -40,8 +48,18 @@ pub fn error_sink() -> Result<(), AppError> { | |||
40 | .map_err(SdlTTFError::Init) | 48 | .map_err(SdlTTFError::Init) |
41 | .map_err(AppError::SdlTTF)?; | 49 | .map_err(AppError::SdlTTF)?; |
42 | info!("Initialized SDL_ttf context"); | 50 | info!("Initialized SDL_ttf context"); |
43 | Ok((sdl_context, ttf_context)) | 51 | while let Ok(signal) = render_rx.recv() { |
44 | }; | 52 | match signal { |
53 | Signal::Quit => { | ||
54 | let ev = sdl_context.event().unwrap(); | ||
55 | ev.push_event(Event::Quit { timestamp: 0u32 }) | ||
56 | .expect("unable to quit ohno"); | ||
57 | } | ||
58 | _ => {} | ||
59 | } | ||
60 | } | ||
61 | Ok(()) | ||
62 | }); | ||
45 | 63 | ||
46 | match cli::parse_args().map_err(AppError::Cli)? { | 64 | match cli::parse_args().map_err(AppError::Cli)? { |
47 | Config::Help => { | 65 | Config::Help => { |
@@ -52,18 +70,16 @@ pub fn error_sink() -> Result<(), AppError> { | |||
52 | file_name, | 70 | file_name, |
53 | dimensions: (width, height), | 71 | dimensions: (width, height), |
54 | } => { | 72 | } => { |
55 | let (sdl_context, ttf_context) = init()?; | 73 | AppState::init(width, height, app_tx, app_rx, None, file_name)?.run(); |
56 | AppState::init(width, height, &sdl_context, &ttf_context, None, file_name)?.run(); | ||
57 | } | 74 | } |
58 | 75 | ||
59 | Config::ExistingProject { file_name } => { | 76 | Config::ExistingProject { file_name } => { |
60 | let (sdl_context, ttf_context) = init()?; | ||
61 | let image = utils::load_file(&file_name).map_err(AppError::File)?; | 77 | let image = utils::load_file(&file_name).map_err(AppError::File)?; |
62 | AppState::init( | 78 | AppState::init( |
63 | image.width(), | 79 | image.width(), |
64 | image.height(), | 80 | image.height(), |
65 | &sdl_context, | 81 | app_tx, |
66 | &ttf_context, | 82 | app_rx, |
67 | Some(image.data), | 83 | Some(image.data), |
68 | Some(file_name), | 84 | Some(file_name), |
69 | )? | 85 | )? |
diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 0000000..f642a04 --- /dev/null +++ b/src/render.rs | |||
@@ -0,0 +1,19 @@ | |||
1 | use sdl2::pixels::Color; | ||
2 | use sdl2::rect::{Point, Rect}; | ||
3 | |||
4 | pub enum Signal { | ||
5 | Redraw, | ||
6 | Request(RequestData), | ||
7 | DrawStatusline, | ||
8 | DrawCommandBox, | ||
9 | DrawBrush, | ||
10 | DrawLineToGrid, | ||
11 | DrawSymmetry, | ||
12 | DrawApp, | ||
13 | Quit, | ||
14 | } | ||
15 | |||
16 | pub enum RequestData { | ||
17 | WinSize, | ||
18 | MouseLoc, | ||
19 | } | ||