From 56d091fb6f5aaeeb01c32418517d3d01b0bcc69a Mon Sep 17 00:00:00 2001 From: Wesley Moore Date: Sat, 26 Nov 2022 20:38:41 +1000 Subject: Reduce CPU usage by waiting for an event --- src/app.rs | 642 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 327 insertions(+), 315 deletions(-) diff --git a/src/app.rs b/src/app.rs index 3e7ac0f..6f39b5e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -28,6 +28,7 @@ use std::{ }; use obi::{CompressionType, Image}; +use sdl2::mouse::MouseState; use sdl2::{ event::Event, keyboard::{Keycode, Mod}, @@ -73,6 +74,11 @@ pub struct AppState<'ctx> { pub pan_start: Point, } +enum HandleEventOutcome { + Normal, + Break, +} + // private actions on appstate impl<'ctx> AppState<'ctx> { fn pan>(&mut self, direction: P) { @@ -737,354 +743,360 @@ impl<'ctx> AppState<'ctx> { 'running: loop { let mouse = event_pump.mouse_state(); self.mouse = (mouse.x(), mouse.y()); + let event = event_pump.wait_event(); + match self.handle_event(mouse, event) { + HandleEventOutcome::Normal => {} + HandleEventOutcome::Break => break, + } for event in event_pump.poll_iter() { - if let Event::KeyDown { - keycode: Some(Keycode::Num9), - keymod, - .. - } = event - { - if keymod == Mod::LSHIFTMOD || keymod == Mod::RSHIFTMOD { - self.mode = Mode::Command; - } + match self.handle_event(mouse, event) { + HandleEventOutcome::Normal => {} + HandleEventOutcome::Break => break 'running, } - match self.mode { - Mode::Draw => { - match event { - Event::KeyDown { - keycode: Some(k), - keymod: Mod::NOMOD, - .. - } => { - match k { - // pan - Keycode::W => self.pan((0, 10)), - Keycode::A => self.pan((10, 0)), - Keycode::S => self.pan((0, -10)), - Keycode::D => self.pan((-10, 0)), - // zoom - // Keycode::C if keymod == Mod::LSHIFTMOD => { - // self.center_grid(); - // } - Keycode::C => { - let cursor = (mouse.x(), mouse.y()); - self.zoom_in(cursor); - } - Keycode::Z => { - let cursor = (mouse.x(), mouse.y()); - self.zoom_out(cursor); - } - // brush ops - Keycode::Q => self.brush.shrink(), - Keycode::E => self.brush.grow(), - Keycode::Num1 => self.reduce_intensity(), - Keycode::Num3 => self.increase_intensity(), - // flip color - Keycode::X => self.change_active_color(), - // toggle grid - Keycode::Tab => self.toggle_grid(), - // invert canvas - Keycode::I => { - self.pixmap.invert(); - self.undo_stack.push(ModifyRecord::Invert); - } - // cycle through brushes - Keycode::F => self.cycle_brush(), - // change rect select active end - Keycode::O => { - match &mut self.brush { - Brush::RectSelect(RectSelectBrush { - active_end, - .. - }) => *active_end = !*active_end, - _ => (), - }; - } - Keycode::V => self.cycle_symmetry(), - // undo - Keycode::U => { - if let Some(op) = self.undo_stack.undo() { - self.apply_operation(op, OpKind::Undo); - } - } - // redo - Keycode::R => { - if let Some(op) = self.undo_stack.redo() { - self.apply_operation(op, OpKind::Redo); - } - } - Keycode::Escape => { - match self.brush { - Brush::RectSelect(_) => self.brush = Brush::rect(), - _ => (), - } - continue; + } + self.cache(); + self.redraw(); + } + } + + #[must_use] + fn handle_event(&mut self, mouse: MouseState, event: Event) -> HandleEventOutcome { + if let Event::KeyDown { + keycode: Some(Keycode::Num9), + keymod, + .. + } = event + { + if keymod == Mod::LSHIFTMOD || keymod == Mod::RSHIFTMOD { + self.mode = Mode::Command; + } + } + match self.mode { + Mode::Draw => { + match event { + Event::KeyDown { + keycode: Some(k), + keymod: Mod::NOMOD, + .. + } => { + match k { + // pan + Keycode::W => self.pan((0, 10)), + Keycode::A => self.pan((10, 0)), + Keycode::S => self.pan((0, -10)), + Keycode::D => self.pan((-10, 0)), + // zoom + // Keycode::C if keymod == Mod::LSHIFTMOD => { + // self.center_grid(); + // } + Keycode::C => { + let cursor = (mouse.x(), mouse.y()); + self.zoom_in(cursor); + } + Keycode::Z => { + let cursor = (mouse.x(), mouse.y()); + self.zoom_out(cursor); + } + // brush ops + Keycode::Q => self.brush.shrink(), + Keycode::E => self.brush.grow(), + Keycode::Num1 => self.reduce_intensity(), + Keycode::Num3 => self.increase_intensity(), + // flip color + Keycode::X => self.change_active_color(), + // toggle grid + Keycode::Tab => self.toggle_grid(), + // invert canvas + Keycode::I => { + self.pixmap.invert(); + self.undo_stack.push(ModifyRecord::Invert); + } + // cycle through brushes + Keycode::F => self.cycle_brush(), + // change rect select active end + Keycode::O => { + match &mut self.brush { + Brush::RectSelect(RectSelectBrush { active_end, .. }) => { + *active_end = !*active_end } _ => (), + }; + } + Keycode::V => self.cycle_symmetry(), + // undo + Keycode::U => { + if let Some(op) = self.undo_stack.undo() { + self.apply_operation(op, OpKind::Undo); } } - Event::KeyDown { - keycode: Some(k), - keymod, - .. - } if self.keybinds.contains_key(&Keybind::new(k, keymod)) => { - let body = - // clone here because body can modify itself - self.keybinds.get(&Keybind::new(k, keymod)).unwrap().clone(); - self.eval_expr(&body); + // redo + Keycode::R => { + if let Some(op) = self.undo_stack.redo() { + self.apply_operation(op, OpKind::Redo); + } } - Event::KeyDown { - keycode: Some(k), .. - } if k == Keycode::LCtrl || k == Keycode::RCtrl => { - self.brush = Brush::line( - self.cache - .borrow() - .as_ref() - .map(|c| c.last_brush.size().unwrap_or(0)) - .unwrap_or(0), - true, - ); + Keycode::Escape => { + match self.brush { + Brush::RectSelect(_) => self.brush = Brush::rect(), + _ => (), + } + return HandleEventOutcome::Normal; } - Event::KeyUp { - keycode: Some(k), .. - } if k == Keycode::LCtrl || k == Keycode::RCtrl => { - self.brush = Brush::new( - self.cache - .borrow() - .as_ref() - .map(|c| c.last_brush.size().unwrap_or(0)) - .unwrap_or(0), - ); + _ => (), + } + } + Event::KeyDown { + keycode: Some(k), + keymod, + .. + } if self.keybinds.contains_key(&Keybind::new(k, keymod)) => { + let body = + // clone here because body can modify itself + self.keybinds.get(&Keybind::new(k, keymod)).unwrap().clone(); + self.eval_expr(&body); + } + Event::KeyDown { + keycode: Some(k), .. + } if k == Keycode::LCtrl || k == Keycode::RCtrl => { + self.brush = Brush::line( + self.cache + .borrow() + .as_ref() + .map(|c| c.last_brush.size().unwrap_or(0)) + .unwrap_or(0), + true, + ); + } + Event::KeyUp { + keycode: Some(k), .. + } if k == Keycode::LCtrl || k == Keycode::RCtrl => { + self.brush = Brush::new( + self.cache + .borrow() + .as_ref() + .map(|c| c.last_brush.size().unwrap_or(0)) + .unwrap_or(0), + ); + } + Event::MouseButtonDown { + x, + y, + mouse_btn: MouseButton::Middle, + .. + } => self.pan_start = Point::from((x, y)), + // start of operation + Event::MouseButtonDown { + x, y, mouse_btn, .. + } => { + let pt = (x, y); + let contact = self.idx_at_coord(pt).map(MapPoint::from); + let val = match mouse_btn { + MouseButton::Right => !self.active_color, + _ => self.active_color, + }; + match self.brush { + Brush::Circle(CircleBrush { size }) => { + if let Ok(o) = self.paint_point(pt, val, size) { + self.current_operation.extend(o); + } } - Event::MouseButtonDown { - x, - y, - mouse_btn: MouseButton::Middle, - .. - } => self.pan_start = Point::from((x, y)), - // start of operation - Event::MouseButtonDown { - x, y, mouse_btn, .. - } => { - let pt = (x, y); - let contact = self.idx_at_coord(pt).map(MapPoint::from); - let val = match mouse_btn { - MouseButton::Right => !self.active_color, - _ => self.active_color, - }; - match self.brush { - Brush::Circle(CircleBrush { size }) => { - if let Ok(o) = self.paint_point(pt, val, size) { - self.current_operation.extend(o); - } + Brush::Line(LineBrush { + size, + start, + extend, + }) => { + if let Some(s) = start { + if let Ok(o) = self.paint_line(s, pt, val, size) { + self.current_operation.extend(o); + self.brush = Brush::Line(LineBrush { + size, + start: if extend { contact } else { None }, + extend, + }); } - Brush::Line(LineBrush { + } else { + self.brush = Brush::Line(LineBrush { size, - start, + start: contact, extend, - }) => { - if let Some(s) = start { - if let Ok(o) = self.paint_line(s, pt, val, size) { - self.current_operation.extend(o); - self.brush = Brush::Line(LineBrush { - size, - start: if extend { contact } else { None }, - extend, - }); - } - } else { - self.brush = Brush::Line(LineBrush { - size, - start: contact, - extend, - }); - } - } - Brush::RectSelect(RectSelectBrush { + }); + } + } + Brush::RectSelect(RectSelectBrush { + start, + end, + active_end, + }) => { + if start.is_none() { + self.brush = Brush::RectSelect(RectSelectBrush { + start: contact, + end, + active_end, + }); + } else if end.is_none() || active_end { + self.brush = Brush::RectSelect(RectSelectBrush { start, + end: contact, + active_end, + }); + } else { + self.brush = Brush::RectSelect(RectSelectBrush { + start: contact, end, active_end, - }) => { - if start.is_none() { - self.brush = Brush::RectSelect(RectSelectBrush { - start: contact, - end, - active_end, - }); - } else if end.is_none() || active_end { - self.brush = Brush::RectSelect(RectSelectBrush { - start, - end: contact, - active_end, - }); - } else { - self.brush = Brush::RectSelect(RectSelectBrush { - start: contact, - end, - active_end, - }); - }; - } - Brush::Fill => { - if let Some(c) = contact { - // this `get` is unchecked because contact is checked - // to be within pixmap - let target = self.pixmap.get(c); - let replacement = self.active_color; - let operation = - self.pixmap.flood_fill(c, target, replacement); - for o in operation.iter() { - // this `set` is unchecked because the returned - // value of flood_fill is checked to be within pixmap - self.pixmap.set(*o, replacement); - } - self.current_operation.extend( - operation - .into_iter() - .map(|point| PaintRecord { - point, - old: target, - new: replacement, - }) - .collect::>(), - ) - } + }); + }; + } + Brush::Fill => { + if let Some(c) = contact { + // this `get` is unchecked because contact is checked + // to be within pixmap + let target = self.pixmap.get(c); + let replacement = self.active_color; + let operation = self.pixmap.flood_fill(c, target, replacement); + for o in operation.iter() { + // this `set` is unchecked because the returned + // value of flood_fill is checked to be within pixmap + self.pixmap.set(*o, replacement); } - _ => {} + self.current_operation.extend( + operation + .into_iter() + .map(|point| PaintRecord { + point, + old: target, + new: replacement, + }) + .collect::>(), + ) } } - // click and drag - Event::MouseMotion { - x, y, mousestate, .. - } => { - if mousestate.is_mouse_button_pressed(MouseButton::Left) { - match self.brush { - Brush::RectSelect(RectSelectBrush { + _ => {} + } + } + // click and drag + Event::MouseMotion { + x, y, mousestate, .. + } => { + if mousestate.is_mouse_button_pressed(MouseButton::Left) { + match self.brush { + Brush::RectSelect(RectSelectBrush { + start, + end, + active_end, + }) => { + if active_end { + self.brush = Brush::RectSelect(RectSelectBrush { start, + end: self.idx_at_coord((x, y)).map(MapPoint::from), + active_end, + }); + } else { + self.brush = Brush::RectSelect(RectSelectBrush { + start: self.idx_at_coord((x, y)).map(MapPoint::from), end, active_end, - }) => { - if active_end { - self.brush = Brush::RectSelect(RectSelectBrush { - start, - end: self - .idx_at_coord((x, y)) - .map(MapPoint::from), - active_end, - }); - } else { - self.brush = Brush::RectSelect(RectSelectBrush { - start: self - .idx_at_coord((x, y)) - .map(MapPoint::from), - end, - active_end, - }); - } - } - Brush::Circle(CircleBrush { size }) => { - let pt = (x, y); - let val = self.active_color; - if let Ok(o) = self.paint_point(pt, val, size) { - self.current_operation.extend(o); - } - } - _ => (), + }); } - } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { - match self.brush { - Brush::Circle(CircleBrush { size }) - | Brush::Line(LineBrush { size, .. }) => { - let pt = (x, y); - let val = !self.active_color; - if let Ok(o) = self.paint_point(pt, val, size) { - self.current_operation.extend(o); - } - } - _ => (), + } + Brush::Circle(CircleBrush { size }) => { + let pt = (x, y); + let val = self.active_color; + if let Ok(o) = self.paint_point(pt, val, size) { + self.current_operation.extend(o); } - } else if mousestate.is_mouse_button_pressed(MouseButton::Middle) { - let pan_end = Point::from((x, y)); - let shift = pan_end - self.pan_start; - self.start += shift; - self.pan_start = pan_end; } + _ => (), } - // end of operation - Event::MouseButtonUp { .. } => self.commit_operation(), - Event::Quit { .. } => { - break 'running; + } else if mousestate.is_mouse_button_pressed(MouseButton::Right) { + match self.brush { + Brush::Circle(CircleBrush { size }) + | Brush::Line(LineBrush { size, .. }) => { + let pt = (x, y); + let val = !self.active_color; + if let Ok(o) = self.paint_point(pt, val, size) { + self.current_operation.extend(o); + } + } + _ => (), } - _ => {} + } else if mousestate.is_mouse_button_pressed(MouseButton::Middle) { + let pan_end = Point::from((x, y)); + let shift = pan_end - self.pan_start; + self.start += shift; + self.pan_start = pan_end; } } - Mode::Command => { - if let Event::KeyDown { - keycode, keymod, .. - } = event - { - let video = self.context.video().unwrap(); - let clipboard = video.clipboard(); - if is_copy_event(keycode, keymod) { - clipboard - .set_clipboard_text(&self.command_box.text) - .unwrap(); - } else if is_paste_event(keycode, keymod) - && clipboard.has_clipboard_text() - { - self.command_box - .push_str(&clipboard.clipboard_text().unwrap()); - } + // end of operation + Event::MouseButtonUp { .. } => self.commit_operation(), + Event::Quit { .. } => { + return HandleEventOutcome::Break; + } + _ => {} + } + } + Mode::Command => { + if let Event::KeyDown { + keycode, keymod, .. + } = event + { + let video = self.context.video().unwrap(); + let clipboard = video.clipboard(); + if is_copy_event(keycode, keymod) { + clipboard + .set_clipboard_text(&self.command_box.text) + .unwrap(); + } else if is_paste_event(keycode, keymod) && clipboard.has_clipboard_text() { + self.command_box + .push_str(&clipboard.clipboard_text().unwrap()); + } + } + match event { + Event::KeyDown { + keycode: Some(k), + keymod, + .. + } => match k { + Keycode::Backspace => self.command_box.backspace(), + Keycode::Delete => self.command_box.delete(), + Keycode::Left => self.command_box.backward(), + Keycode::Right => self.command_box.forward(), + Keycode::Up => self.command_box.hist_prev(), + Keycode::Down => self.command_box.hist_next(), + Keycode::Return => self.eval_command(), + Keycode::Tab if keymod == Mod::LSHIFTMOD => { + self.command_box.complete(&self.lisp_env, true) } - match event { - Event::KeyDown { - keycode: Some(k), - keymod, - .. - } => match k { - Keycode::Backspace => self.command_box.backspace(), - Keycode::Delete => self.command_box.delete(), - Keycode::Left => self.command_box.backward(), - Keycode::Right => self.command_box.forward(), - Keycode::Up => self.command_box.hist_prev(), - Keycode::Down => self.command_box.hist_next(), - Keycode::Return => self.eval_command(), - Keycode::Tab if keymod == Mod::LSHIFTMOD => { - self.command_box.complete(&self.lisp_env, true) - } - Keycode::Tab => self.command_box.complete(&self.lisp_env, false), - Keycode::Escape => { - self.command_box.clear(); - self.message.text.clear(); - self.mode = Mode::Draw; - } - _ if keymod == Mod::LCTRLMOD => match k { - Keycode::A => self.command_box.cursor_start(), - Keycode::E => self.command_box.cursor_end(), - Keycode::F => self.command_box.forward(), - Keycode::B => self.command_box.backward(), - Keycode::K => self.command_box.delete_to_end(), - Keycode::U => self.command_box.delete_to_start(), - _ => (), - }, - // how does one handle alt keys - _ if keymod == Mod::LALTMOD => match k { - Keycode::B => self.command_box.cursor_back_word(), - Keycode::F => self.command_box.cursor_forward_word(), - _ => (), - }, - _ => (), - }, - Event::TextInput { text, .. } => { - self.command_box.push_str(&text[..]); - } - _ => (), + Keycode::Tab => self.command_box.complete(&self.lisp_env, false), + Keycode::Escape => { + self.command_box.clear(); + self.message.text.clear(); + self.mode = Mode::Draw; } + _ if keymod == Mod::LCTRLMOD => match k { + Keycode::A => self.command_box.cursor_start(), + Keycode::E => self.command_box.cursor_end(), + Keycode::F => self.command_box.forward(), + Keycode::B => self.command_box.backward(), + Keycode::K => self.command_box.delete_to_end(), + Keycode::U => self.command_box.delete_to_start(), + _ => (), + }, + // how does one handle alt keys + _ if keymod == Mod::LALTMOD => match k { + Keycode::B => self.command_box.cursor_back_word(), + Keycode::F => self.command_box.cursor_forward_word(), + _ => (), + }, + _ => (), + }, + Event::TextInput { text, .. } => { + self.command_box.push_str(&text[..]); } + _ => (), } } - self.cache(); - self.redraw(); } + HandleEventOutcome::Normal } } -- cgit v1.2.3