diff --git a/Cargo.lock b/Cargo.lock index 293775d..b3d48ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,6 +599,7 @@ dependencies = [ "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "neovim-lib 0.6.0 (git+https://github.com/daa84/neovim-lib)", "rmpv 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "skia-safe 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "skulpin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index a2a3195..414805d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] skulpin = "0.3" +skia-safe = { version = "0.17", features = ["vulkan"] } derive-new = "0.5" env_logger = "0.7.1" neovim-lib = { git = "https://github.com/daa84/neovim-lib", version = "0.6" } diff --git a/src/editor.rs b/src/editor.rs index 2e42441..856862e 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use skia_safe::Color4f; -use skia_safe::colors::*; +use skulpin::skia_safe::{colors, Color4f}; use neovim_lib::{Neovim, NeovimApi}; diff --git a/src/main.rs b/src/main.rs index cfc5484..13b9e10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#![windows_subsystem = "windows"] +// #![windows_subsystem = "windows"] mod editor; mod window; @@ -17,7 +17,7 @@ use rmpv::Value; use window::ui_loop; use editor::{Colors, Editor, GridLineCell, Style}; -use skia_safe::Color4f; +use skulpin::skia_safe::Color4f; const INITIAL_WIDTH: u16 = 100; const INITIAL_HEIGHT: u16 = 50; @@ -71,9 +71,17 @@ fn handle_cursor_goto(cursor_goto_arguments: &Vec, editor: &Arc Color { - - Color::from_rgba32_u32(((packed_color as u32) << 8) + 255) +fn unpack_color(packed_color: u64) -> Color4f { + let packed_color = packed_color as u32; + let r = ((packed_color & 0xff0000) >> 16) as f32; + let g = ((packed_color & 0xff00) >> 8) as f32; + let b = (packed_color & 0xff) as f32; + Color4f { + r: r / 255.0, + g: g / 255.0, + b: b / 255.0, + a: 1.0 + } } fn handle_default_colors(default_colors_arguments: &Vec, editor: &Arc>) { diff --git a/src/window.rs b/src/window.rs index ff6aeb1..12cb3bd 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1,122 +1,205 @@ use std::sync::{Arc, Mutex}; use std::any::Any; -use druid_shell::{Application, WinHandler, WindowHandle, WinCtx, KeyEvent, WindowBuilder, RunLoop, HotKey, KeyCode}; -use druid_shell::piet::{ - Piet, PietFont, Color, FontBuilder, RenderContext, Text, TextLayoutBuilder -}; -use druid_shell::kurbo::Rect; + +use skulpin::{CoordinateSystem, CoordinateSystemHelper, RendererBuilder}; +use skulpin::skia_safe::{Canvas, Color4f, Font, FontStyle, Point, Paint, Rect, Typeface}; +use skulpin::skia_safe::paint::Style; +use skulpin::skia_safe::matrix::ScaleToFit; +use skulpin::winit::dpi::LogicalSize; +use skulpin::winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; +use skulpin::winit::event_loop::{ControlFlow, EventLoop}; +use skulpin::winit::window::WindowBuilder; + use neovim_lib::NeovimApi; use crate::editor::{DrawCommand, Editor, Colors}; -#[derive(new)] -struct WindowState { - editor: Arc>, +const FONT_NAME: &str = "Delugia Nerd Font"; +const FONT_SIZE: f32 = 14.0; +const FONT_WIDTH: f32 = 8.2; +const FONT_HEIGHT: f32 = 16.4; - #[new(default)] - pub size: (f64, f64), - #[new(default)] - pub handle: WindowHandle, - #[new(default)] - pub font: Option -} +// fn process_draw_commands(draw_commands: &Vec, default_colors: &Colors, piet: &mut Piet, font: &PietFont) { +// } -const FONT_NAME: &str = "Delugia Nerd Font"; -const FONT_SIZE: f64 = 14.0; -const FONT_WIDTH: f64 = 8.2; -const FONT_HEIGHT: f64 = 16.4; +fn draw( + editor: &Arc>, + canvas: &mut Canvas, + _coordinate_system_helper: &CoordinateSystemHelper +) { + + let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file."); + let font = Font::from_typeface(typeface, FONT_SIZE); + let paint = Paint::new(Color4f::new(0.0, 1.0, 1.0, 1.0), None); + + // let shaper = Shaper::new(None); + // if let Some((blob, _)) = shaper.shape_text_blob("This is a test ~==", font, false, 10000.0, Point::default()) { + // canvas.draw_text_blob(&blob, (50, 50), &paint); + // } + + let (draw_commands, default_colors, cursor_pos) = { + let editor = editor.lock().unwrap(); + (editor.build_draw_commands().clone(), editor.default_colors.clone(), editor.cursor_pos.clone()) + }; + + canvas.clear(default_colors.background.clone().unwrap().to_color()); + + canvas.draw_str("This is a test!", (50, 50), &font, &paint); -fn process_draw_commands(draw_commands: &Vec, default_colors: &Colors, piet: &mut Piet, font: &PietFont) { for command in draw_commands { - let x = command.col_start as f64 * FONT_WIDTH; - let y = command.row as f64 * FONT_HEIGHT + FONT_HEIGHT; + let x = command.col_start as f32 * FONT_WIDTH; + let y = command.row as f32 * FONT_HEIGHT + FONT_HEIGHT; let top = y - FONT_HEIGHT * 0.8; - let top_left = (x, top); - let width = command.text.chars().count() as f64 * FONT_WIDTH; + let width = command.text.chars().count() as f32 * FONT_WIDTH; let height = FONT_HEIGHT; - let bottom_right = (x + width, top + height); - let region = Rect::from_points(top_left, bottom_right); - piet.fill(region, &command.style.colors.background.clone().or(default_colors.background.clone()).unwrap()); + let region = Rect::new(x, top, x + width, top + height); + let background_paint = Paint::new(command.style.colors.background.unwrap_or(default_colors.background.clone().unwrap()), None); + canvas.draw_rect(region, &background_paint); - let piet_text = piet.text(); - let text_layout = piet_text.new_text_layout(&font, &command.text).build().unwrap(); - piet.draw_text(&text_layout, (x, y), &command.style.colors.foreground.clone().or(default_colors.foreground.clone()).unwrap()); + let foreground_paint = Paint::new(command.style.colors.foreground.unwrap_or(default_colors.foreground.clone().unwrap()), None); + canvas.draw_str(&command.text, (x, y), &font, &foreground_paint); } -} -impl WinHandler for WindowState { - fn connect(&mut self, handle: &WindowHandle) { - self.handle = handle.clone(); - } - - fn paint(&mut self, piet: &mut Piet, _ctx: &mut dyn WinCtx) -> bool { - let text = piet.text(); - if self.font.is_none() { - self.font = Some(text.new_font_by_name(FONT_NAME, FONT_SIZE).build().unwrap()); - } - let font = self.font.as_ref().unwrap(); - - let (draw_commands, default_colors, cursor_pos) = { - let editor = self.editor.lock().unwrap(); - (editor.build_draw_commands().clone(), editor.default_colors.clone(), editor.cursor_pos.clone()) - }; - - piet.clear(default_colors.background.clone().unwrap()); - process_draw_commands(&draw_commands, &default_colors, piet, font); - - let (cursor_grid_x, cursor_grid_y) = cursor_pos; - let cursor_x = cursor_grid_x as f64 * FONT_WIDTH; - let cursor_width = FONT_WIDTH / 8.0; - let cursor_y = cursor_grid_y as f64 * FONT_HEIGHT + FONT_HEIGHT * 0.2; - let cursor_height = FONT_HEIGHT; - let cursor = Rect::from_points((cursor_x, cursor_y), (cursor_x + cursor_width, cursor_y + cursor_height)); - piet.fill(cursor, &Color::rgb8(0xff, 0xff, 0xff)); - true - } + let (cursor_grid_x, cursor_grid_y) = cursor_pos; + let cursor_x = cursor_grid_x as f32 * FONT_WIDTH; + let cursor_width = FONT_WIDTH / 8.0; + let cursor_y = cursor_grid_y as f32 * FONT_HEIGHT + FONT_HEIGHT * 0.2; + let cursor_height = FONT_HEIGHT; + let cursor = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height); + let cursor_paint = Paint::new(default_colors.foreground.unwrap(), None); + canvas.draw_rect(cursor, &cursor_paint); +} - fn key_down(&mut self, key_event: KeyEvent, _ctx: &mut dyn WinCtx) -> bool { - let mut editor = self.editor.lock().unwrap(); - match key_event { - k_e if k_e.key_code.is_printable() => { - let incoming_text = k_e.unmod_text().unwrap_or(""); - editor.nvim.input(incoming_text).expect("Input call failed..."); - }, - k_e if (HotKey::new(None, KeyCode::Escape)).matches(k_e) => { - editor.nvim.input("").expect("Input call failed..."); +pub fn ui_loop(editor: Arc>) { + let event_loop = EventLoop::<()>::with_user_event(); + let logical_size = LogicalSize::new((100.0 * FONT_WIDTH) as f64, (50.0 * FONT_HEIGHT) as f64); + let visible_range = Rect { + left: 0.0, + right: logical_size.width as f32, + top: 0.0, + bottom: logical_size.height as f32 + }; + let scale_to_fit = ScaleToFit::Center; + + let window = WindowBuilder::new() + .with_title("Neovide") + .with_inner_size(logical_size) + .build(&event_loop) + .expect("Failed to create window"); + + let mut renderer = RendererBuilder::new() + .use_vulkan_debug_layer(true) + .coordinate_system(CoordinateSystem::Logical) + .build(&window) + .expect("Failed to create renderer"); + + // icu::init(); + + event_loop.run(move |event, _window_target, control_flow| { + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + + Event::WindowEvent { + event: WindowEvent::Resized(new_size), + .. + } => { + editor.lock().unwrap().resize( + (new_size.width as f32 / FONT_WIDTH) as u16, + (new_size.height as f32 / FONT_HEIGHT) as u16 + ) }, - k_e if (HotKey::new(None, KeyCode::Backspace)).matches(k_e) => { - editor.nvim.input("").expect("Input call failed..."); - } - _ => () - }; - true - } - fn size(&mut self, width: u32, height: u32, _ctx: &mut dyn WinCtx) { - let dpi = self.handle.get_dpi(); - let dpi_scale = dpi as f64 / 96.0; - let width_f = (width as f64) / dpi_scale; - let height_f = (height as f64) / dpi_scale; - self.size = (width_f, height_f); + Event:: WindowEvent { + event: WindowEvent::KeyboardInput { + input: KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(keycode), + .. + }, + .. + }, + .. + } => { + let possible_string = match keycode { + VirtualKeyCode::A => Some("a"), + VirtualKeyCode::B => Some("b"), + VirtualKeyCode::C => Some("c"), + VirtualKeyCode::D => Some("d"), + VirtualKeyCode::E => Some("e"), + VirtualKeyCode::F => Some("f"), + VirtualKeyCode::G => Some("g"), + VirtualKeyCode::H => Some("h"), + VirtualKeyCode::I => Some("i"), + VirtualKeyCode::J => Some("j"), + VirtualKeyCode::K => Some("k"), + VirtualKeyCode::L => Some("l"), + VirtualKeyCode::M => Some("m"), + VirtualKeyCode::N => Some("n"), + VirtualKeyCode::O => Some("o"), + VirtualKeyCode::P => Some("p"), + VirtualKeyCode::Q => Some("q"), + VirtualKeyCode::R => Some("r"), + VirtualKeyCode::S => Some("s"), + VirtualKeyCode::T => Some("t"), + VirtualKeyCode::U => Some("u"), + VirtualKeyCode::V => Some("v"), + VirtualKeyCode::W => Some("w"), + VirtualKeyCode::X => Some("x"), + VirtualKeyCode::Y => Some("y"), + VirtualKeyCode::Z => Some("z"), + VirtualKeyCode::Escape => Some(""), + VirtualKeyCode::Back => Some(""), + VirtualKeyCode::Space => Some(""), + VirtualKeyCode::Return => Some(""), + VirtualKeyCode::Up => Some(""), + VirtualKeyCode::Down => Some(""), + VirtualKeyCode::Left => Some(""), + VirtualKeyCode::Right => Some(""), + VirtualKeyCode::LShift => Some(""), + VirtualKeyCode::RShift => Some(""), + VirtualKeyCode::Key1 => Some("1"), + VirtualKeyCode::Key2 => Some("2"), + VirtualKeyCode::Key3 => Some("3"), + VirtualKeyCode::Key4 => Some("4"), + VirtualKeyCode::Key5 => Some("5"), + VirtualKeyCode::Key6 => Some("6"), + VirtualKeyCode::Key7 => Some("7"), + VirtualKeyCode::Key8 => Some("8"), + VirtualKeyCode::Key9 => Some("9"), + VirtualKeyCode::Key0 => Some("0"), + VirtualKeyCode::Insert => Some(""), + VirtualKeyCode::Home => Some(""), + VirtualKeyCode::Delete => Some(""), + VirtualKeyCode::End => Some(""), + _ => None + }; + + if let Some(string) = possible_string { + editor.lock().unwrap().nvim.input(string).expect("Input call failed..."); + } + }, - let mut editor = self.editor.lock().unwrap(); - editor.resize((width_f / FONT_WIDTH) as u16, (height_f / FONT_HEIGHT) as u16); - } + Event::EventsCleared => { + // Queue a RedrawRequested event. + window.request_redraw(); + }, - fn as_any(&mut self) -> &mut dyn Any { - self - } -} + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + } => { + if let Err(e) = renderer.draw(&window, |canvas, coordinate_system_helper| { + draw(&editor, canvas, coordinate_system_helper); + }) { + println!("Error during draw: {:?}", e); + *control_flow = ControlFlow::Exit + } + }, -pub fn ui_loop(editor: Arc>) { - let window_state = WindowState::new(editor); - - Application::init(); - let mut run_loop = RunLoop::new(); - let mut builder = WindowBuilder::new(); - builder.set_handler(Box::new(window_state)); - builder.set_title("Nvim editor"); - let window = builder.build().unwrap(); - window.show(); - run_loop.run(); + _ => {} + } + }) }