skulpin working! really fast

macos-click-through
keith 5 years ago
parent 9fe0adcb38
commit 568ca834a2

1
Cargo.lock generated

@ -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)",
]

@ -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" }

@ -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};

@ -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<Value>, editor: &Arc<Mutex<Edi
}
}
fn unpack_color(packed_color: u64) -> 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<Value>, editor: &Arc<Mutex<Editor>>) {

@ -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 neovim_lib::NeovimApi;
use crate::editor::{DrawCommand, Editor, Colors};
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;
#[derive(new)]
struct WindowState {
editor: Arc<Mutex<Editor>>,
use neovim_lib::NeovimApi;
#[new(default)]
pub size: (f64, f64),
#[new(default)]
pub handle: WindowHandle,
#[new(default)]
pub font: Option<PietFont>
}
use crate::editor::{DrawCommand, Editor, Colors};
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;
const FONT_SIZE: f32 = 14.0;
const FONT_WIDTH: f32 = 8.2;
const FONT_HEIGHT: f32 = 16.4;
fn process_draw_commands(draw_commands: &Vec<DrawCommand>, 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 top = y - FONT_HEIGHT * 0.8;
let top_left = (x, top);
let width = command.text.chars().count() as f64 * 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());
// fn process_draw_commands(draw_commands: &Vec<DrawCommand>, default_colors: &Colors, piet: &mut Piet, font: &PietFont) {
// }
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());
}
}
fn draw(
editor: &Arc<Mutex<Editor>>,
canvas: &mut Canvas,
_coordinate_system_helper: &CoordinateSystemHelper
) {
impl WinHandler for WindowState {
fn connect(&mut self, handle: &WindowHandle) {
self.handle = handle.clone();
}
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);
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 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 = self.editor.lock().unwrap();
let editor = 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);
canvas.clear(default_colors.background.clone().unwrap().to_color());
canvas.draw_str("This is a test!", (50, 50), &font, &paint);
for command in draw_commands {
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 width = command.text.chars().count() as f32 * FONT_WIDTH;
let height = FONT_HEIGHT;
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 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);
}
let (cursor_grid_x, cursor_grid_y) = cursor_pos;
let cursor_x = cursor_grid_x as f64 * FONT_WIDTH;
let cursor_x = cursor_grid_x as f32 * 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_y = cursor_grid_y as f32 * 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 = 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...");
pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
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::Escape)).matches(k_e) => {
editor.nvim.input("<Esc>").expect("Input call failed...");
Event:: WindowEvent {
event: WindowEvent::KeyboardInput {
input: KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(keycode),
..
},
k_e if (HotKey::new(None, KeyCode::Backspace)).matches(k_e) => {
editor.nvim.input("<BS>").expect("Input call failed...");
}
_ => ()
..
},
..
} => {
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("<ESC>"),
VirtualKeyCode::Back => Some("<BS>"),
VirtualKeyCode::Space => Some("<Space>"),
VirtualKeyCode::Return => Some("<Enter>"),
VirtualKeyCode::Up => Some("<Up>"),
VirtualKeyCode::Down => Some("<Down>"),
VirtualKeyCode::Left => Some("<Left>"),
VirtualKeyCode::Right => Some("<Right>"),
VirtualKeyCode::LShift => Some("<S>"),
VirtualKeyCode::RShift => Some("<S>"),
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("<Insert>"),
VirtualKeyCode::Home => Some("<Home>"),
VirtualKeyCode::Delete => Some("<Delete>"),
VirtualKeyCode::End => Some("<End>"),
_ => None
};
true
if let Some(string) = possible_string {
editor.lock().unwrap().nvim.input(string).expect("Input call failed...");
}
},
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::EventsCleared => {
// Queue a RedrawRequested event.
window.request_redraw();
},
let mut editor = self.editor.lock().unwrap();
editor.resize((width_f / FONT_WIDTH) as u16, (height_f / FONT_HEIGHT) as u16);
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
}
},
fn as_any(&mut self) -> &mut dyn Any {
self
}
_ => {}
}
pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
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();
})
}

Loading…
Cancel
Save