aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs128
-rw-r--r--src/consts.rs14
-rw-r--r--src/main.rs1
3 files changed, 76 insertions, 67 deletions
diff --git a/src/app.rs b/src/app.rs
index 695d097..03389fb 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,9 +1,11 @@
1use crate::{ 1use crate::{
2 bitmap::{Axis, MapPoint, Pixmap}, 2 bitmap::{MapPoint, Pixmap},
3 consts::{colors::*, FONT_PATH},
4 symmetry::Symmetry,
3 undo::{ModifyRecord, OpKind, Operation, UndoStack}, 5 undo::{ModifyRecord, OpKind, Operation, UndoStack},
4}; 6};
5 7
6use std::convert::From; 8use std::convert::{From, TryFrom};
7 9
8use sdl2::{ 10use sdl2::{
9 event::Event, 11 event::Event,
@@ -11,7 +13,7 @@ use sdl2::{
11 mouse::MouseButton, 13 mouse::MouseButton,
12 pixels::Color, 14 pixels::Color,
13 rect::{Point, Rect}, 15 rect::{Point, Rect},
14 render::{Canvas, Texture}, 16 render::Canvas,
15 ttf::Sdl2TtfContext, 17 ttf::Sdl2TtfContext,
16 video::Window, 18 video::Window,
17 Sdl, 19 Sdl,
@@ -23,8 +25,6 @@ macro_rules! quick_rect(
23 ) 25 )
24); 26);
25 27
26use crate::consts::{BLACK, FONT_PATH, GRID_COLOR, WHITE};
27
28pub struct AppState<'ctx> { 28pub struct AppState<'ctx> {
29 active_color: bool, 29 active_color: bool,
30 brush_size: u8, 30 brush_size: u8,
@@ -47,12 +47,6 @@ struct Grid {
47 color: Color, 47 color: Color,
48} 48}
49 49
50#[derive(Debug, Default, Copy, Clone)]
51struct Symmetry {
52 x: Option<u32>,
53 y: Option<u32>,
54}
55
56impl Grid { 50impl Grid {
57 fn new() -> Self { 51 fn new() -> Self {
58 Self { 52 Self {
@@ -133,25 +127,6 @@ impl<'ctx> AppState<'ctx> {
133 } 127 }
134 } 128 }
135 129
136 fn apply_symmetry(&self, figure: &[MapPoint]) -> Vec<MapPoint> {
137 let Symmetry { x, y } = self.symmetry;
138 match (x, y) {
139 (None, None) => vec![],
140 (Some(line), None) => self.pixmap.mirror_figure(figure, line, Axis::X),
141 (None, Some(line)) => self.pixmap.mirror_figure(figure, line, Axis::Y),
142 (Some(x), Some(y)) => {
143 let along_x = self.pixmap.mirror_figure(figure, x, Axis::X);
144 let along_y = self.pixmap.mirror_figure(figure, y, Axis::Y);
145 let reflected = self.pixmap.reflect_figure(figure, (x, y).into());
146 along_x
147 .into_iter()
148 .chain(along_y)
149 .chain(reflected)
150 .collect()
151 }
152 }
153 }
154
155 fn paint_point<P: Into<Point>>( 130 fn paint_point<P: Into<Point>>(
156 &mut self, 131 &mut self,
157 center: P, 132 center: P,
@@ -159,9 +134,12 @@ impl<'ctx> AppState<'ctx> {
159 ) -> Result<Vec<ModifyRecord>, ()> { 134 ) -> Result<Vec<ModifyRecord>, ()> {
160 let radius = self.brush_size as u32; 135 let radius = self.brush_size as u32;
161 let center = self.idx_at_coord(center).ok_or(())?; 136 let center = self.idx_at_coord(center).ok_or(())?;
137
138 let circle = self.pixmap.get_circle(center, radius, true);
139 let sym_circle = self.symmetry.apply(&circle);
140
162 let mut modify_record = vec![]; 141 let mut modify_record = vec![];
163 let circle = self.pixmap.get_circle(center, radius); 142
164 let sym_circle = self.apply_symmetry(&circle);
165 for point in circle.into_iter().chain(sym_circle) { 143 for point in circle.into_iter().chain(sym_circle) {
166 let old_val = self.pixmap.set(point, val); 144 let old_val = self.pixmap.set(point, val);
167 modify_record.push(ModifyRecord::new(point, old_val, val)); 145 modify_record.push(ModifyRecord::new(point, old_val, val));
@@ -169,15 +147,21 @@ impl<'ctx> AppState<'ctx> {
169 Ok(modify_record) 147 Ok(modify_record)
170 } 148 }
171 149
172 fn paint_line<P: Into<Point>>(&mut self, start: P, end: P) -> Result<Vec<ModifyRecord>, ()> { 150 fn paint_line<P: Into<Point>>(
151 &mut self,
152 start: P,
153 end: P,
154 val: bool,
155 ) -> Result<Vec<ModifyRecord>, ()> {
173 let start = self.idx_at_coord(start).ok_or(())?; 156 let start = self.idx_at_coord(start).ok_or(())?;
174 let end = self.idx_at_coord(end).ok_or(())?; 157 let end = self.idx_at_coord(end).ok_or(())?;
158
175 let line = self.pixmap.get_line(start, end); 159 let line = self.pixmap.get_line(start, end);
176 let sym_line = self.apply_symmetry(&line); 160 let sym_line = self.symmetry.apply(&line);
161
177 let mut line_modify_record = vec![]; 162 let mut line_modify_record = vec![];
178 let val = self.active_color;
179 for point in line.into_iter().chain(sym_line) { 163 for point in line.into_iter().chain(sym_line) {
180 let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32); 164 let circle_around_point = self.pixmap.get_circle(point, self.brush_size as u32, true);
181 for c in circle_around_point { 165 for c in circle_around_point {
182 let old_val = self.pixmap.set(c, val); 166 let old_val = self.pixmap.set(c, val);
183 line_modify_record.push(ModifyRecord::new(c, old_val, val)); 167 line_modify_record.push(ModifyRecord::new(c, old_val, val));
@@ -283,30 +267,15 @@ impl<'ctx> AppState<'ctx> {
283 status_height 267 status_height
284 )) 268 ))
285 .unwrap(); 269 .unwrap();
286 let symmetry_symbol = match self.symmetry {
287 Symmetry { x: None, y: None } => "",
288 Symmetry {
289 x: Some(_),
290 y: None,
291 } => "-",
292 Symmetry {
293 x: None,
294 y: Some(_),
295 } => "|",
296 Symmetry {
297 x: Some(_),
298 y: Some(_),
299 } => "+",
300 };
301 let mouse_coords = if let Some((x, y)) = self.idx_at_coord(self.mouse) { 270 let mouse_coords = if let Some((x, y)) = self.idx_at_coord(self.mouse) {
302 format!("{:3}, {:3}", x, y) 271 format!("{:3}, {:3}", x, y)
303 } else { 272 } else {
304 format!("--, --") 273 format!("---, ---")
305 }; 274 };
306 let status_text = format!( 275 let status_text = format!(
307 "[BRUSH {}] [SYM {:1}] {}", 276 "[BRUSH {}] [SYM {}] {}",
308 self.brush_size + 1, 277 self.brush_size + 1,
309 symmetry_symbol, 278 self.symmetry,
310 mouse_coords 279 mouse_coords
311 ); 280 );
312 draw_text( 281 draw_text(
@@ -318,32 +287,67 @@ impl<'ctx> AppState<'ctx> {
318 ); 287 );
319 } 288 }
320 289
290 fn draw_mouse(&mut self) {
291 let brush_size = self.brush_size;
292 let cs = self.zoom as u32;
293 let pt = self.idx_at_coord(self.mouse);
294 if let Some(center) = pt {
295 let circle = self.pixmap.get_circle(center, brush_size as u32, false);
296 for MapPoint { x, y } in circle.into_iter() {
297 self.canvas.set_draw_color(GREY);
298 self.canvas
299 .fill_rect(Rect::new(
300 x as i32 * cs as i32 + self.start.x(),
301 y as i32 * cs as i32 + self.start.y(),
302 cs,
303 cs,
304 ))
305 .unwrap();
306 }
307 }
308 }
309
321 fn draw(&mut self) { 310 fn draw(&mut self) {
322 let cs = self.zoom as u32; 311 let cs = self.zoom as u32;
323 let (width, height) = (self.width(), self.height()); 312 let (width, height) = (self.width(), self.height());
324 let start = self.start; 313 let start = self.start;
325 let canvas = &mut self.canvas; 314 let grid_enabled = self.grid.enabled;
315 let (winsize_x, winsize_y) = self.canvas.window().size();
316 let Symmetry { x: sym_x, y: sym_y } = self.symmetry;
326 for (idx, val) in self.pixmap.data.iter().enumerate() { 317 for (idx, val) in self.pixmap.data.iter().enumerate() {
327 if *val { 318 if *val {
328 let idx = idx as i32; 319 let idx = idx as i32;
329 let (x, y) = (idx % width as i32, idx / height as i32); 320 let (x, y) = (idx % width as i32, idx / height as i32);
330 canvas.set_draw_color(WHITE); 321 self.canvas.set_draw_color(WHITE);
331 canvas 322 self.canvas
332 .fill_rect(Rect::new( 323 .fill_rect(Rect::new(
333 // start drawing 1 pixel after the grid line
334 x * cs as i32 + start.x(), 324 x * cs as i32 + start.x(),
335 y * cs as i32 + start.y(), 325 y * cs as i32 + start.y(),
336 // stop drawing 1 pixel before the grid line
337 cs, 326 cs,
338 cs, 327 cs,
339 )) 328 ))
340 .unwrap(); 329 .unwrap();
341 } 330 }
342 } 331 }
343 if self.grid.enabled { 332 if grid_enabled {
344 self.draw_grid(); 333 self.draw_grid();
345 } 334 }
335 if let Some(line) = sym_x {
336 self.canvas.set_draw_color(CYAN);
337 let line_coord = (line * cs) as i32 + self.start.y() + (cs / 2) as i32;
338 self.canvas
339 .draw_line((0, line_coord), (winsize_x as i32, line_coord))
340 .unwrap();
341 }
342 if let Some(line) = sym_y {
343 self.canvas.set_draw_color(CYAN);
344 let line_coord = (line * cs) as i32 + self.start.x() + (cs / 2) as i32;
345 self.canvas
346 .draw_line((line_coord, 0), (line_coord, winsize_y as i32))
347 .unwrap();
348 }
346 self.draw_statusline(); 349 self.draw_statusline();
350 self.draw_mouse();
347 } 351 }
348 352
349 fn redraw(&mut self) { 353 fn redraw(&mut self) {
@@ -439,7 +443,7 @@ impl<'ctx> AppState<'ctx> {
439 Keycode::F => { 443 Keycode::F => {
440 let end = (mouse.x(), mouse.y()).into(); 444 let end = (mouse.x(), mouse.y()).into();
441 if let Some(start) = self.last_point { 445 if let Some(start) = self.last_point {
442 if let Ok(o) = self.paint_line(start, end) { 446 if let Ok(o) = self.paint_line(start, end, self.active_color) {
443 self.commit_operation(); 447 self.commit_operation();
444 self.current_operation = 448 self.current_operation =
445 o.into_iter().filter(|v| !v.old_val == v.val).collect(); 449 o.into_iter().filter(|v| !v.old_val == v.val).collect();
@@ -535,5 +539,5 @@ fn draw_text<S: AsRef<str>>(
535 .unwrap(); 539 .unwrap();
536 let (width, height) = font.size_of_latin1(text.as_bytes()).unwrap(); 540 let (width, height) = font.size_of_latin1(text.as_bytes()).unwrap();
537 let area = quick_rect!(x, y, width, height); 541 let area = quick_rect!(x, y, width, height);
538 canvas.copy(&texture, None, area); 542 canvas.copy(&texture, None, area).unwrap();
539} 543}
diff --git a/src/consts.rs b/src/consts.rs
index 8c90693..2f7576e 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -1,7 +1,11 @@
1use sdl2::pixels::Color; 1pub mod colors {
2 2 use sdl2::pixels::Color;
3pub const GRID_COLOR: Color = Color::RGB(64, 64, 64); 3 pub const GRID_COLOR: Color = Color::RGB(64, 64, 64);
4pub const WHITE: Color = Color::RGB(255, 255, 255); 4 pub const WHITE: Color = Color::RGB(255, 255, 255);
5pub const BLACK: Color = Color::RGB(0, 0, 0); 5 pub const BLACK: Color = Color::RGB(0, 0, 0);
6 pub const GREY: Color = Color::RGB(127, 127, 127);
7 pub const CYAN: Color = Color::RGB(121, 255, 225);
8 pub const PINK: Color = Color::RGB(255, 50, 153);
9}
6 10
7pub const FONT_PATH: &'static str = "./assets/NerdInput-Regular.ttf"; 11pub const FONT_PATH: &'static str = "./assets/NerdInput-Regular.ttf";
diff --git a/src/main.rs b/src/main.rs
index bd0590e..1aaa954 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
1mod app; 1mod app;
2mod bitmap; 2mod bitmap;
3mod consts; 3mod consts;
4mod symmetry;
4mod undo; 5mod undo;
5 6
6use app::AppState; 7use app::AppState;