aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs39
-rw-r--r--src/lisp/eval.rs9
-rw-r--r--src/main.rs32
-rw-r--r--src/render.rs19
4 files changed, 56 insertions, 43 deletions
diff --git a/src/app.rs b/src/app.rs
index 23458f4..99c0bb5 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -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
29use obi::{CompressionType, Image}; 31use obi::{CompressionType, Image};
@@ -45,13 +47,11 @@ pub enum Mode {
45 Command, 47 Command,
46} 48}
47 49
48pub struct AppState<'ctx> { 50pub 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
73impl<'ctx> AppState<'ctx> { 73impl 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
15pub type Context = Vec<String>; 15pub type Context = Vec<String>;
16 16
17pub struct Evaluator<'ctx, 'global> { 17pub 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
22impl<'ctx, 'global> Evaluator<'ctx, 'global> 22impl<'global> Evaluator<'global> {
23where
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;
18mod guide; 18mod guide;
19mod lisp; 19mod lisp;
20mod message; 20mod message;
21mod render;
21mod symmetry; 22mod symmetry;
22mod undo; 23mod undo;
23mod utils; 24mod 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
34use std::{sync::mpsc, thread};
35
32use log::{error, info}; 36use log::{error, info};
37use sdl2::event::Event;
33 38
34pub fn error_sink() -> Result<(), AppError> { 39pub 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 @@
1use sdl2::pixels::Color;
2use sdl2::rect::{Point, Rect};
3
4pub enum Signal {
5 Redraw,
6 Request(RequestData),
7 DrawStatusline,
8 DrawCommandBox,
9 DrawBrush,
10 DrawLineToGrid,
11 DrawSymmetry,
12 DrawApp,
13 Quit,
14}
15
16pub enum RequestData {
17 WinSize,
18 MouseLoc,
19}