aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-14 17:15:46 +0000
committerAkshay <[email protected]>2021-03-14 17:15:46 +0000
commit9844d702a1f33ca04815166f539616a519a89cac (patch)
tree0c6f539ce9770737bf16852e78f83ba8d8420821
parent2665972d0c15fe6b2cea7ffb0c34829c9c163c56 (diff)
add basic statusline widget; text drawing support
-rw-r--r--src/app.rs108
-rw-r--r--src/consts.rs1
-rw-r--r--src/main.rs3
3 files changed, 101 insertions, 11 deletions
diff --git a/src/app.rs b/src/app.rs
index 13f8732..695d097 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -11,18 +11,27 @@ use sdl2::{
11 mouse::MouseButton, 11 mouse::MouseButton,
12 pixels::Color, 12 pixels::Color,
13 rect::{Point, Rect}, 13 rect::{Point, Rect},
14 render::Canvas, 14 render::{Canvas, Texture},
15 ttf::Sdl2TtfContext,
15 video::Window, 16 video::Window,
16 Sdl, 17 Sdl,
17}; 18};
18 19
19use crate::consts::{BLACK, GRID_COLOR, WHITE}; 20macro_rules! quick_rect(
21 ($x:expr, $y:expr, $w:expr, $h:expr) => (
22 Rect::new($x as i32, $y as i32, $w as u32, $h as u32)
23 )
24);
25
26use crate::consts::{BLACK, FONT_PATH, GRID_COLOR, WHITE};
20 27
21pub struct AppState<'ctx> { 28pub struct AppState<'ctx> {
22 active_color: bool, 29 active_color: bool,
23 brush_size: u8, 30 brush_size: u8,
24 canvas: Canvas<Window>, 31 canvas: Canvas<Window>,
25 context: &'ctx Sdl, 32 context: &'ctx Sdl,
33 ttf_context: &'ctx Sdl2TtfContext,
34 mouse: (i32, i32),
26 current_operation: Operation, 35 current_operation: Operation,
27 grid: Grid, 36 grid: Grid,
28 last_point: Option<Point>, 37 last_point: Option<Point>,
@@ -261,13 +270,58 @@ impl<'ctx> AppState<'ctx> {
261 } 270 }
262 } 271 }
263 272
273 fn draw_statusline(&mut self) {
274 let (winsize_x, winsize_y) = self.canvas.window().size();
275 let status_height: u32 = 20;
276 let status_width = winsize_x;
277 self.canvas.set_draw_color(WHITE);
278 self.canvas
279 .fill_rect(quick_rect!(
280 0,
281 winsize_y - status_height,
282 status_width,
283 status_height
284 ))
285 .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) {
302 format!("{:3}, {:3}", x, y)
303 } else {
304 format!("--, --")
305 };
306 let status_text = format!(
307 "[BRUSH {}] [SYM {:1}] {}",
308 self.brush_size + 1,
309 symmetry_symbol,
310 mouse_coords
311 );
312 draw_text(
313 &mut self.canvas,
314 self.ttf_context,
315 status_text,
316 BLACK,
317 (0, winsize_y - status_height),
318 );
319 }
320
264 fn draw(&mut self) { 321 fn draw(&mut self) {
265 let cs = self.zoom as u32; 322 let cs = self.zoom as u32;
266 let (width, height) = (self.width(), self.height()); 323 let (width, height) = (self.width(), self.height());
267 let start = self.start; 324 let start = self.start;
268 if self.grid.enabled {
269 self.draw_grid();
270 }
271 let canvas = &mut self.canvas; 325 let canvas = &mut self.canvas;
272 for (idx, val) in self.pixmap.data.iter().enumerate() { 326 for (idx, val) in self.pixmap.data.iter().enumerate() {
273 if *val { 327 if *val {
@@ -277,15 +331,19 @@ impl<'ctx> AppState<'ctx> {
277 canvas 331 canvas
278 .fill_rect(Rect::new( 332 .fill_rect(Rect::new(
279 // start drawing 1 pixel after the grid line 333 // start drawing 1 pixel after the grid line
280 x * cs as i32 + start.x() + 1, 334 x * cs as i32 + start.x(),
281 y * cs as i32 + start.y() + 1, 335 y * cs as i32 + start.y(),
282 // stop drawing 1 pixel before the grid line 336 // stop drawing 1 pixel before the grid line
283 cs - 1, 337 cs,
284 cs - 1, 338 cs,
285 )) 339 ))
286 .unwrap(); 340 .unwrap();
287 } 341 }
288 } 342 }
343 if self.grid.enabled {
344 self.draw_grid();
345 }
346 self.draw_statusline();
289 } 347 }
290 348
291 fn redraw(&mut self) { 349 fn redraw(&mut self) {
@@ -298,12 +356,18 @@ impl<'ctx> AppState<'ctx> {
298 356
299// publicly available functions on appstate 357// publicly available functions on appstate
300impl<'ctx> AppState<'ctx> { 358impl<'ctx> AppState<'ctx> {
301 pub fn init(width: u32, height: u32, context: &'ctx Sdl) -> Self { 359 pub fn init(
360 width: u32,
361 height: u32,
362 context: &'ctx Sdl,
363 ttf_context: &'ctx Sdl2TtfContext,
364 ) -> Self {
302 let video_subsystem = context.video().unwrap(); 365 let video_subsystem = context.video().unwrap();
303 366
304 let window = video_subsystem 367 let window = video_subsystem
305 .window("Pixel editor", 200, 200) 368 .window("Pixel editor", 200, 200)
306 .position_centered() 369 .position_centered()
370 .resizable()
307 .opengl() 371 .opengl()
308 .build() 372 .build()
309 .map_err(|e| e.to_string()) 373 .map_err(|e| e.to_string())
@@ -321,6 +385,8 @@ impl<'ctx> AppState<'ctx> {
321 brush_size: 0, 385 brush_size: 0,
322 canvas, 386 canvas,
323 context, 387 context,
388 ttf_context,
389 mouse: (0, 0),
324 current_operation: Vec::new(), 390 current_operation: Vec::new(),
325 grid: Grid::new(), 391 grid: Grid::new(),
326 last_point: None, 392 last_point: None,
@@ -341,6 +407,7 @@ impl<'ctx> AppState<'ctx> {
341 let mut event_pump = self.context.event_pump().unwrap(); 407 let mut event_pump = self.context.event_pump().unwrap();
342 'running: loop { 408 'running: loop {
343 let mouse = event_pump.mouse_state(); 409 let mouse = event_pump.mouse_state();
410 self.mouse = (mouse.x(), mouse.y());
344 for event in event_pump.poll_iter() { 411 for event in event_pump.poll_iter() {
345 match event { 412 match event {
346 Event::KeyDown { 413 Event::KeyDown {
@@ -449,3 +516,24 @@ impl<'ctx> AppState<'ctx> {
449 } 516 }
450 } 517 }
451} 518}
519
520fn draw_text<S: AsRef<str>>(
521 canvas: &mut Canvas<Window>,
522 ttf_context: &Sdl2TtfContext,
523 text: S,
524 color: Color,
525 (x, y): (u32, u32),
526) {
527 let text = text.as_ref();
528 let texture_creator = canvas.texture_creator();
529 let mut font = ttf_context.load_font(FONT_PATH, 17).unwrap();
530 font.set_style(sdl2::ttf::FontStyle::NORMAL);
531 font.set_hinting(sdl2::ttf::Hinting::Mono);
532 let surface = font.render(text.as_ref()).blended(color).unwrap();
533 let texture = texture_creator
534 .create_texture_from_surface(&surface)
535 .unwrap();
536 let (width, height) = font.size_of_latin1(text.as_bytes()).unwrap();
537 let area = quick_rect!(x, y, width, height);
538 canvas.copy(&texture, None, area);
539}
diff --git a/src/consts.rs b/src/consts.rs
index b5cea43..8c90693 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -4,3 +4,4 @@ pub const GRID_COLOR: Color = Color::RGB(64, 64, 64);
4pub const WHITE: Color = Color::RGB(255, 255, 255); 4pub const WHITE: Color = Color::RGB(255, 255, 255);
5pub const BLACK: Color = Color::RGB(0, 0, 0); 5pub const BLACK: Color = Color::RGB(0, 0, 0);
6 6
7pub const FONT_PATH: &'static str = "./assets/NerdInput-Regular.ttf";
diff --git a/src/main.rs b/src/main.rs
index cb39648..bd0590e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,5 +7,6 @@ use app::AppState;
7 7
8pub fn main() { 8pub fn main() {
9 let sdl_context = sdl2::init().unwrap(); 9 let sdl_context = sdl2::init().unwrap();
10 AppState::init(100, 100, &sdl_context).run(); 10 let ttf_context = sdl2::ttf::init().unwrap();
11 AppState::init(100, 100, &sdl_context, &ttf_context).run();
11} 12}