From ff67afaa4674173f688dd76929ec480b74c5e486 Mon Sep 17 00:00:00 2001 From: keith Date: Sat, 22 Feb 2020 15:09:42 -0800 Subject: [PATCH] refactor window event handling to be more organized --- src/window.rs | 381 +++++++++++++++++++++++++++++--------------------- 1 file changed, 222 insertions(+), 159 deletions(-) diff --git a/src/window.rs b/src/window.rs index b6df6e7..da5e14b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -4,9 +4,11 @@ use std::thread::sleep; use log::{info, trace, debug, error}; use skulpin::{LogicalSize, PhysicalSize}; use skulpin::sdl2; +use skulpin::sdl2::Sdl; +use skulpin::sdl2::video::Window; use skulpin::sdl2::event::Event; -use skulpin::sdl2::keyboard::Mod; -use skulpin::{RendererBuilder, PresentMode, CoordinateSystem, dpis}; +use skulpin::sdl2::keyboard::{Mod, Keycode}; +use skulpin::{RendererBuilder, Renderer as SkulpinRenderer, PresentMode, CoordinateSystem, dpis}; use crate::bridge::{parse_keycode, append_modifiers, BRIDGE, UiCommand}; use crate::renderer::Renderer; @@ -37,184 +39,245 @@ fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer) { } } -pub fn ui_loop() { - let sdl_context = sdl2::init().expect("Failed to initialize sdl2"); - let video_subsystem = sdl_context.video().expect("Failed to create sdl video subsystem"); - - let (width, height) = INITIAL_DIMENSIONS; - - let mut renderer = Renderer::new(); - let logical_size = LogicalSize { - width: (width as f32 * renderer.font_width) as u32, - height: (height as f32 * renderer.font_height + 1.0) as u32 - }; - - // let icon = { - // let icon_data = Asset::get("nvim.ico").expect("Failed to read icon data"); - // let icon = load_from_memory(&icon_data).expect("Failed to parse icon data"); - // let (width, height) = icon.dimensions(); - // let mut rgba = Vec::with_capacity((width * height) as usize * 4); - // for (_, _, pixel) in icon.pixels() { - // rgba.extend_from_slice(&pixel.to_rgba().0); - // } - // Icon::from_rgba(rgba, width, height).expect("Failed to create icon object") - // }; - // info!("icon created"); - #[cfg(target_os = "windows")] - windows_fix_dpi(); - sdl2::hint::set("SDL_MOUSE_FOCUS_CLICKTHROUGH", "1"); - - let mut window = video_subsystem.window("Neovide", logical_size.width, logical_size.height) - .position_centered() - .allow_highdpi() - .resizable() - .vulkan() - .build() - .expect("Failed to create window"); - info!("window created"); - - let mut skulpin_renderer = RendererBuilder::new() - .prefer_integrated_gpu() - .use_vulkan_debug_layer(true) - .present_mode_priority(vec![PresentMode::Immediate]) - .coordinate_system(CoordinateSystem::Logical) - .build(&window) - .expect("Failed to create renderer"); - info!("renderer created"); - - let mut mouse_down = false; - let mut mouse_position = LogicalSize { - width: 0, - height: 0 - }; - - let mut title = "Neovide".to_string(); - let mut previous_size = LogicalSize::new(&window).unwrap(); - let mut previous_dpis = dpis(&window).unwrap(); +struct WindowWrapper { + context: Sdl, + window: Window, + skulpin_renderer: SkulpinRenderer, + renderer: Renderer, + mouse_down: bool, + mouse_position: LogicalSize, + title: String, + previous_size: LogicalSize, + previous_dpis: (f32, f32), + ignore_text_input: bool +} - info!("Starting window event loop"); - let mut event_pump = sdl_context.event_pump().expect("Could not create sdl event pump"); - 'running: loop { - let frame_start = Instant::now(); +impl WindowWrapper { + pub fn new() -> WindowWrapper { + let context = sdl2::init().expect("Failed to initialize sdl2"); + let video_subsystem = context.video().expect("Failed to create sdl video subsystem"); + + let (width, height) = INITIAL_DIMENSIONS; + + let renderer = Renderer::new(); + let logical_size = LogicalSize { + width: (width as f32 * renderer.font_width) as u32, + height: (height as f32 * renderer.font_height + 1.0) as u32 + }; + + #[cfg(target_os = "windows")] + windows_fix_dpi(); + sdl2::hint::set("SDL_MOUSE_FOCUS_CLICKTHROUGH", "1"); + + // let icon = { + // let icon_data = Asset::get("nvim.ico").expect("Failed to read icon data"); + // let icon = load_from_memory(&icon_data).expect("Failed to parse icon data"); + // let (width, height) = icon.dimensions(); + // let mut rgba = Vec::with_capacity((width * height) as usize * 4); + // for (_, _, pixel) in icon.pixels() { + // rgba.extend_from_slice(&pixel.to_rgba().0); + // } + // Icon::from_rgba(rgba, width, height).expect("Failed to create icon object") + // }; + // info!("icon created"); + let window = video_subsystem.window("Neovide", logical_size.width, logical_size.height) + .position_centered() + .allow_highdpi() + .resizable() + .vulkan() + .build() + .expect("Failed to create window"); + info!("window created"); + + let skulpin_renderer = RendererBuilder::new() + .prefer_integrated_gpu() + .use_vulkan_debug_layer(true) + .present_mode_priority(vec![PresentMode::Immediate]) + .coordinate_system(CoordinateSystem::Logical) + .build(&window) + .expect("Failed to create renderer"); + info!("renderer created"); + + let previous_size = LogicalSize::new(&window).unwrap(); + let previous_dpis = dpis(&window).unwrap(); + + WindowWrapper { + context, window, skulpin_renderer, renderer, + mouse_down: false, + mouse_position: LogicalSize { + width: 0, + height: 0 + }, + title: String::from("Neovide"), + previous_size, + previous_dpis, + ignore_text_input: false + } + } + + pub fn synchronize_title(&mut self) { let editor_title = { EDITOR.lock().title.clone() }; - if title != editor_title { - title = editor_title; - window.set_title(&title).expect("Could not set title"); + if self.title != editor_title { + self.title = editor_title; + self.window.set_title(&self.title).expect("Could not set title"); } + } - let mut ignore_text_input = false; - for event in event_pump.poll_iter() { - match event { - Event::Quit {..} => break 'running, - Event::Window {..} => REDRAW_SCHEDULER.queue_next_frame(), - Event::KeyDown { keycode: Some(keycode), keymod: modifiers, .. } => { - trace!("KeyDown Received: {}", keycode); - if let Some((key_text, special)) = parse_keycode(keycode) { - let will_text_input = - - !modifiers.contains(Mod::LCTRLMOD) && - !modifiers.contains(Mod::RCTRLMOD) && - !modifiers.contains(Mod::LALTMOD) && - !modifiers.contains(Mod::RALTMOD) && - !modifiers.contains(Mod::LGUIMOD) && - !modifiers.contains(Mod::RGUIMOD); - if will_text_input && !special { - break; - } - - BRIDGE.queue_command(UiCommand::Keyboard(append_modifiers(modifiers, key_text, special))); - ignore_text_input = true; - } - }, - Event::TextInput { text, .. } => { - trace!("Keyboard Input Received: {}", &text); - if ignore_text_input { - ignore_text_input = false; - } else { - let text = if text == "<" { - String::from("") - } else { - text - }; - BRIDGE.queue_command(UiCommand::Keyboard(text)) - } - }, - Event::MouseMotion { x, y, .. } => { - let previous_position = mouse_position; - mouse_position = LogicalSize::from_physical_size_tuple(( - (x as f32 / renderer.font_width) as u32, - (y as f32 / renderer.font_height) as u32 - ), - &window - ).expect("Could not calculate logical mouse position"); - if mouse_down && previous_position != mouse_position { - BRIDGE.queue_command(UiCommand::Drag(mouse_position.width, mouse_position.height)); - } - }, - Event::MouseButtonDown { .. } => { - BRIDGE.queue_command(UiCommand::MouseButton { action: String::from("press"), position: (mouse_position.width, mouse_position.height) }); - mouse_down = true; - }, - Event::MouseButtonUp { .. } => { - BRIDGE.queue_command(UiCommand::MouseButton { action: String::from("release"), position: (mouse_position.width, mouse_position.height) }); - mouse_down = false; - }, - Event::MouseWheel { x, y, .. } => { - let vertical_input_type = if y > 0 { - Some("up") - } else if y < 0 { - Some("down") - } else { - None - }; - - if let Some(input_type) = vertical_input_type { - BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: (mouse_position.width, mouse_position.height) }); - } - - let horizontal_input_type = if x > 0 { - Some("right") - } else if x < 0 { - Some("left") - } else { - None - }; - - if let Some(input_type) = horizontal_input_type { - BRIDGE.queue_command(UiCommand::Scroll { direction: input_type.to_string(), position: (mouse_position.width, mouse_position.height) }); - } - }, - _ => {} + pub fn handle_key_down(&mut self, keycode: Keycode, modifiers: Mod) { + trace!("KeyDown Received: {}", keycode); + if let Some((key_text, special)) = parse_keycode(keycode) { + let will_text_input = + !modifiers.contains(Mod::LCTRLMOD) && + !modifiers.contains(Mod::RCTRLMOD) && + !modifiers.contains(Mod::LALTMOD) && + !modifiers.contains(Mod::RALTMOD) && + !modifiers.contains(Mod::LGUIMOD) && + !modifiers.contains(Mod::RGUIMOD); + if modifiers.contains(Mod::MODEMOD) || (will_text_input && !special) { + self.ignore_text_input = false; + return; } + + BRIDGE.queue_command(UiCommand::Keyboard(append_modifiers(modifiers, key_text, special))); + self.ignore_text_input = true; + } + } + + pub fn handle_text_input(&mut self, text: String) { + trace!("Keyboard Input Received: {}", &text); + if self.ignore_text_input { + self.ignore_text_input = false; + } else { + let text = if text == "<" { + String::from("") + } else { + text + }; + BRIDGE.queue_command(UiCommand::Keyboard(text)) + } + } + + pub fn handle_pointer_motion(&mut self, x: i32, y: i32) { + let previous_position = self.mouse_position; + self.mouse_position = LogicalSize::from_physical_size_tuple(( + (x as f32 / self.renderer.font_width) as u32, + (y as f32 / self.renderer.font_height) as u32 + ), + &self.window + ).expect("Could not calculate logical mouse position"); + if self.mouse_down && previous_position != self.mouse_position { + BRIDGE.queue_command(UiCommand::Drag(self.mouse_position.width, self.mouse_position.height)); + } + } + + pub fn handle_pointer_down(&mut self) { + BRIDGE.queue_command(UiCommand::MouseButton { + action: String::from("press"), + position: (self.mouse_position.width, self.mouse_position.height) + }); + self.mouse_down = true; + } + + pub fn handle_pointer_up(&mut self) { + BRIDGE.queue_command(UiCommand::MouseButton { + action: String::from("release"), + position: (self.mouse_position.width, self.mouse_position.height) + }); + self.mouse_down = false; + } + + pub fn handle_mouse_wheel(&mut self, x: i32, y: i32) { + let vertical_input_type = if y > 0 { + Some("up") + } else if y < 0 { + Some("down") + } else { + None + }; + + if let Some(input_type) = vertical_input_type { + BRIDGE.queue_command(UiCommand::Scroll { + direction: input_type.to_string(), + position: (self.mouse_position.width, self.mouse_position.height) + }); } - let new_size = LogicalSize::new(&window).unwrap(); - if previous_size != new_size { - handle_new_grid_size(new_size, &renderer); - previous_size = new_size; + let horizontal_input_type = if x > 0 { + Some("right") + } else if x < 0 { + Some("left") + } else { + None + }; + + if let Some(input_type) = horizontal_input_type { + BRIDGE.queue_command(UiCommand::Scroll { + direction: input_type.to_string(), + position: (self.mouse_position.width, self.mouse_position.height) + }); } + } - let new_dpis = dpis(&window).unwrap(); - if previous_dpis != new_dpis { - let physical_size = PhysicalSize::new(&window); - window.set_size( - (physical_size.width as f32 * new_dpis.0 / previous_dpis.0) as u32, - (physical_size.height as f32 * new_dpis.1 / previous_dpis.1) as u32).unwrap(); - previous_dpis = new_dpis; + pub fn draw_frame(&mut self) -> bool { + let new_size = LogicalSize::new(&self.window).unwrap(); + if self.previous_size != new_size { + handle_new_grid_size(new_size, &self.renderer); + self.previous_size = new_size; + } + + let new_dpis = dpis(&self.window).unwrap(); + if self.previous_dpis != new_dpis { + let physical_size = PhysicalSize::new(&self.window); + self.window.set_size( + (physical_size.width as f32 * new_dpis.0 / self.previous_dpis.0) as u32, + (physical_size.height as f32 * new_dpis.1 / self.previous_dpis.1) as u32).unwrap(); + self.previous_dpis = new_dpis; } debug!("Render Triggered"); if REDRAW_SCHEDULER.should_draw() || SETTINGS.get("no_idle").read_bool() { - if skulpin_renderer.draw(&window, |canvas, coordinate_system_helper| { + let renderer = &mut self.renderer; + if self.skulpin_renderer.draw(&self.window, |canvas, coordinate_system_helper| { if renderer.draw(canvas, coordinate_system_helper) { handle_new_grid_size(new_size, &renderer) } }).is_err() { error!("Render failed. Closing"); - break; + return false; } } + return true; + } +} + +pub fn ui_loop() { + let mut window = WindowWrapper::new(); + + info!("Starting window event loop"); + let mut event_pump = window.context.event_pump().expect("Could not create sdl event pump"); + 'running: loop { + let frame_start = Instant::now(); + + window.synchronize_title(); + + for event in event_pump.poll_iter() { + match event { + Event::Quit {..} => break 'running, + Event::Window {..} => REDRAW_SCHEDULER.queue_next_frame(), + Event::KeyDown { keycode: Some(keycode), keymod: modifiers, .. } => window.handle_key_down(keycode, modifiers), + Event::TextInput { text, .. } => window.handle_text_input(text), + Event::MouseMotion { x, y, .. } => window.handle_pointer_motion(x, y), + Event::MouseButtonDown { .. } => window.handle_pointer_down(), + Event::MouseButtonUp { .. } => window.handle_pointer_up(), + Event::MouseWheel { x, y, .. } => window.handle_mouse_wheel(x, y), + _ => {} + } + } + + if !window.draw_frame() { + break; + } let elapsed = frame_start.elapsed(); let refresh_rate = SETTINGS.get("refresh_rate").read_u16() as f32;