mouse support, terminal handling, and underlines

macos-click-through
Keith Simmons 5 years ago
parent 7033a05d26
commit 1bfe5bde03

@ -31,6 +31,28 @@ pub struct Style {
pub blend: u8 pub blend: u8
} }
impl Style {
pub fn foreground(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
} else {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
}
}
pub fn background(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
} else {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
}
}
pub fn special(&self, default_colors: &Colors) -> Color4f {
self.colors.special.clone().unwrap_or(default_colors.special.clone().unwrap())
}
}
#[derive(new, Debug, Clone, PartialEq)] #[derive(new, Debug, Clone, PartialEq)]
pub struct ModeInfo { pub struct ModeInfo {
#[new(default)] #[new(default)]
@ -73,6 +95,7 @@ pub struct Editor {
pub cursor_pos: (u64, u64), pub cursor_pos: (u64, u64),
pub cursor_type: CursorType, pub cursor_type: CursorType,
pub cursor_style: Option<Style>, pub cursor_style: Option<Style>,
pub cursor_enabled: bool,
pub size: (u64, u64), pub size: (u64, u64),
pub default_colors: Colors, pub default_colors: Colors,
pub defined_styles: HashMap<u64, Style>, pub defined_styles: HashMap<u64, Style>,
@ -88,6 +111,7 @@ impl Editor {
cursor_pos: (0, 0), cursor_pos: (0, 0),
cursor_type: CursorType::Block, cursor_type: CursorType::Block,
cursor_style: None, cursor_style: None,
cursor_enabled: true,
size: (width, height), size: (width, height),
default_colors: Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)), default_colors: Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)),
defined_styles: HashMap::new(), defined_styles: HashMap::new(),
@ -98,6 +122,22 @@ impl Editor {
editor editor
} }
pub fn cursor_foreground(&self) -> Color4f {
if let Some(cursor_style) = &self.cursor_style {
cursor_style.colors.foreground.clone().unwrap_or(self.default_colors.background.clone().unwrap())
} else {
self.default_colors.background.clone().unwrap()
}
}
pub fn cursor_background(&self) -> Color4f {
if let Some(cursor_style) = &self.cursor_style {
cursor_style.colors.background.clone().unwrap_or(self.default_colors.foreground.clone().unwrap())
} else {
self.default_colors.foreground.clone().unwrap()
}
}
pub fn build_draw_commands(&self) -> Vec<DrawCommand> { pub fn build_draw_commands(&self) -> Vec<DrawCommand> {
self.grid.iter().enumerate().map(|(row_index, row)| { self.grid.iter().enumerate().map(|(row_index, row)| {
let mut draw_commands = Vec::new(); let mut draw_commands = Vec::new();
@ -147,6 +187,8 @@ impl Editor {
match event { match event {
RedrawEvent::ModeInfoSet { mode_list } => self.set_mode_list(mode_list), RedrawEvent::ModeInfoSet { mode_list } => self.set_mode_list(mode_list),
RedrawEvent::ModeChange { mode_index } => self.change_mode(mode_index), RedrawEvent::ModeChange { mode_index } => self.change_mode(mode_index),
RedrawEvent::BusyStart => self.set_cursor_enabled(false),
RedrawEvent::BusyStop => self.set_cursor_enabled(true),
RedrawEvent::Resize { width, height, .. } => self.resize(width, height), RedrawEvent::Resize { width, height, .. } => self.resize(width, height),
RedrawEvent::DefaultColorsSet { foreground, background, special } => self.set_default_colors(foreground, background, special), RedrawEvent::DefaultColorsSet { foreground, background, special } => self.set_default_colors(foreground, background, special),
RedrawEvent::HighlightAttributesDefine { id, style } => self.define_style(id, style), RedrawEvent::HighlightAttributesDefine { id, style } => self.define_style(id, style),
@ -175,6 +217,10 @@ impl Editor {
} }
} }
pub fn set_cursor_enabled(&mut self, cursor_enabled: bool) {
self.cursor_enabled = cursor_enabled;
}
pub fn resize(&mut self, new_width: u64, new_height: u64) { pub fn resize(&mut self, new_width: u64, new_height: u64) {
self.nvim.ui_try_resize(new_width as i64, new_height as i64).expect("Resize failed"); self.nvim.ui_try_resize(new_width as i64, new_height as i64).expect("Resize failed");
self.size = (new_width, new_height); self.size = (new_width, new_height);

@ -47,6 +47,8 @@ pub struct GridLineCell {
pub enum RedrawEvent { pub enum RedrawEvent {
ModeInfoSet { mode_list: Vec<ModeInfo> }, ModeInfoSet { mode_list: Vec<ModeInfo> },
ModeChange { mode_index: u64 }, ModeChange { mode_index: u64 },
BusyStart,
BusyStop,
Resize { grid: u64, width: u64, height: u64 }, Resize { grid: u64, width: u64, height: u64 },
DefaultColorsSet { foreground: Color4f, background: Color4f, special: Color4f }, DefaultColorsSet { foreground: Color4f, background: Color4f, special: Color4f },
HighlightAttributesDefine { id: u64, style: Style }, HighlightAttributesDefine { id: u64, style: Style },
@ -173,6 +175,9 @@ fn parse_hl_attr_define(hl_attr_define_arguments: Vec<Value>) -> Result<RedrawEv
("foreground", Value::Integer(packed_color)) => style.colors.foreground = Some(unpack_color(packed_color.as_u64().unwrap())), ("foreground", Value::Integer(packed_color)) => style.colors.foreground = Some(unpack_color(packed_color.as_u64().unwrap())),
("background", Value::Integer(packed_color)) => style.colors.background = Some(unpack_color(packed_color.as_u64().unwrap())), ("background", Value::Integer(packed_color)) => style.colors.background = Some(unpack_color(packed_color.as_u64().unwrap())),
("special", Value::Integer(packed_color)) => style.colors.special = Some(unpack_color(packed_color.as_u64().unwrap())), ("special", Value::Integer(packed_color)) => style.colors.special = Some(unpack_color(packed_color.as_u64().unwrap())),
("reverse", Value::Boolean(reverse)) => style.reverse = *reverse,
("underline", Value::Boolean(underline)) => style.underline = *underline,
("undercurl", Value::Boolean(undercurl)) => style.undercurl = *undercurl,
_ => println!("Ignored style attribute: {}", name) _ => println!("Ignored style attribute: {}", name)
} }
} else { } else {
@ -256,8 +261,8 @@ pub fn parse_redraw_event(event_value: Value) -> Result<Vec<RedrawEvent>> {
"mode_info_set" => Some(parse_mode_info_set(event_parameters)?), "mode_info_set" => Some(parse_mode_info_set(event_parameters)?),
"option_set" => None, // Ignore option set for now "option_set" => None, // Ignore option set for now
"mode_change" => Some(parse_mode_change(event_parameters)?), "mode_change" => Some(parse_mode_change(event_parameters)?),
"busy_start" => None, // Ignore busy start for now "busy_start" => Some(RedrawEvent::BusyStart),
"busy_stop" => None, // Ignore busy stop for now "busy_stop" => Some(RedrawEvent::BusyStop),
"default_colors_set" => Some(parse_default_colors(event_parameters)?), "default_colors_set" => Some(parse_default_colors(event_parameters)?),
"hl_attr_define" => Some(parse_hl_attr_define(event_parameters)?), "hl_attr_define" => Some(parse_hl_attr_define(event_parameters)?),
"grid_line" => Some(parse_grid_line(event_parameters)?), "grid_line" => Some(parse_grid_line(event_parameters)?),

@ -1,4 +1,4 @@
// #![windows_subsystem = "windows"] #![windows_subsystem = "windows"]
mod editor; mod editor;
mod events; mod events;
@ -8,7 +8,8 @@ mod keybindings;
#[macro_use] #[macro_use]
extern crate derive_new; extern crate derive_new;
use std::process::{Command, Stdio}; use std::panic;
use std::process::{Command, Stdio, exit};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
@ -46,8 +47,13 @@ fn set_windows_creation_flags(cmd: &mut Command) {
fn main() { fn main() {
env_logger::from_env(LoggerEnv::default().default_filter_or("warn")).init(); env_logger::from_env(LoggerEnv::default().default_filter_or("warn")).init();
panic::set_hook(Box::new(|_| {
exit(1);
}));
let mut cmd = Command::new("nvim"); let mut cmd = Command::new("nvim");
cmd.arg("--embed") cmd.arg("--embed")
.args(std::env::args().skip(1))
.stderr(Stdio::inherit()); .stderr(Stdio::inherit());
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]

@ -7,7 +7,7 @@ use skulpin::skia_safe::paint::Style;
use skulpin::skia_safe::matrix::ScaleToFit; use skulpin::skia_safe::matrix::ScaleToFit;
use skulpin::skia_safe::icu; use skulpin::skia_safe::icu;
use skulpin::winit::dpi::{LogicalSize, LogicalPosition}; use skulpin::winit::dpi::{LogicalSize, LogicalPosition};
use skulpin::winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; use skulpin::winit::event::{ElementState, Event, MouseScrollDelta, KeyboardInput, VirtualKeyCode, WindowEvent};
use skulpin::winit::event_loop::{ControlFlow, EventLoop}; use skulpin::winit::event_loop::{ControlFlow, EventLoop};
use skulpin::winit::window::WindowBuilder; use skulpin::winit::window::WindowBuilder;
@ -24,17 +24,21 @@ fn draw(
canvas: &mut Canvas, canvas: &mut Canvas,
cursor_pos: &mut (f32, f32), cursor_pos: &mut (f32, f32),
shaper: &Shaper, shaper: &Shaper,
paint: &mut Paint,
font: &Font, font: &Font,
font_width: f32, font_width: f32,
font_height: f32 font_height: f32
) { ) {
let (draw_commands, default_colors, cursor_grid_pos, cursor_type) = { let (draw_commands, default_colors, cursor_grid_pos, cursor_type, cursor_foreground, cursor_background, cursor_enabled) = {
let editor = editor.lock().unwrap(); let editor = editor.lock().unwrap();
( (
editor.build_draw_commands().clone(), editor.build_draw_commands().clone(),
editor.default_colors.clone(), editor.default_colors.clone(),
editor.cursor_pos.clone(), editor.cursor_pos.clone(),
editor.cursor_type.clone() editor.cursor_type.clone(),
editor.cursor_foreground(),
editor.cursor_background(),
editor.cursor_enabled
) )
}; };
@ -47,16 +51,27 @@ fn draw(
let width = command.text.chars().count() as f32 * font_width; let width = command.text.chars().count() as f32 * font_width;
let height = font_height; let height = font_height;
let region = Rect::new(x, top, x + width, top + 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); paint.set_color(command.style.background(&default_colors).to_color());
canvas.draw_rect(region, &background_paint); canvas.draw_rect(region, &paint);
let mut foreground_paint = Paint::new(command.style.colors.foreground.unwrap_or(default_colors.foreground.clone().unwrap()), None); if command.style.underline || command.style.undercurl {
let text = command.text.trim_end(); let (_, metrics) = font.metrics();
if text.len() > 0 { let width = command.text.chars().count() as f32 * font_width;
if let Some((blob, _)) = shaper.shape_text_blob(&text, font, false, 10000.0, Point::default()) { let underline_position = metrics.underline_position().unwrap();
canvas.draw_text_blob(&blob, (x, top), &foreground_paint);
} paint.set_color(command.style.special(&default_colors).to_color());
canvas.draw_line((x, y + underline_position), (x + width, y + underline_position), &paint);
} }
paint.set_color(command.style.foreground(&default_colors).to_color());
let text = command.text.trim_end();
canvas.draw_str(text, (x, y), &font, &paint);
// if text.len() > 0 {
// if let Some((blob, _)) = shaper.shape_text_blob(&text, font, false, 10000.0, Point::default()) {
// canvas.draw_text_blob(&blob, (x, top), &paint);
// }
// }
} }
let (cursor_grid_x, cursor_grid_y) = cursor_grid_pos; let (cursor_grid_x, cursor_grid_y) = cursor_grid_pos;
@ -68,38 +83,39 @@ fn draw(
let cursor_y = (target_cursor_y - *previous_cursor_y) * 0.5 + *previous_cursor_y; let cursor_y = (target_cursor_y - *previous_cursor_y) * 0.5 + *previous_cursor_y;
*cursor_pos = (cursor_x, cursor_y); *cursor_pos = (cursor_x, cursor_y);
let cursor_width = match cursor_type { if cursor_enabled {
CursorType::Vertical => font_width / 8.0, let cursor_width = match cursor_type {
CursorType::Horizontal | CursorType::Block => font_width CursorType::Vertical => font_width / 8.0,
}; CursorType::Horizontal | CursorType::Block => font_width
let cursor_height = match cursor_type { };
CursorType::Horizontal => font_width / 8.0, let cursor_height = match cursor_type {
CursorType::Vertical | CursorType::Block => font_height CursorType::Horizontal => font_width / 8.0,
}; CursorType::Vertical | CursorType::Block => 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); let cursor = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height);
canvas.draw_rect(cursor, &cursor_paint); paint.set_color(cursor_background.to_color());
canvas.draw_rect(cursor, &paint);
if let CursorType::Block = cursor_type {
let text_paint = Paint::new(default_colors.background.unwrap(), None); if let CursorType::Block = cursor_type {
let editor = editor.lock().unwrap(); paint.set_color(cursor_foreground.to_color());
let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone() let editor = editor.lock().unwrap();
.map(|(character, _)| character) let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone()
.unwrap_or(' '); .map(|(character, _)| character)
let text_y = cursor_y + font_height - font_height * 0.2; .unwrap_or(' ');
canvas.draw_str(character.to_string(), (cursor_x, text_y), &font, &text_paint); let text_y = cursor_y + font_height - font_height * 0.2;
canvas.draw_str(character.to_string(), (cursor_x, text_y), &font, &paint);
}
} }
} }
pub fn ui_loop(editor: Arc<Mutex<Editor>>) { pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
let shaper = Shaper::new(None); let shaper = Shaper::new(None);
let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file."); let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file.");
let font = Font::from_typeface(typeface, FONT_SIZE); let font = Font::from_typeface(typeface, FONT_SIZE);
let paint = Paint::new(colors::WHITE, None); let mut paint = Paint::new(colors::WHITE, None);
let (_, bounds) = font.measure_str("0", Some(&paint)); let (width, bounds) = font.measure_str("0", Some(&paint));
let font_width = bounds.width(); let font_width = width;
let font_height = bounds.height() * 1.68; let font_height = bounds.height() * 1.68;
let event_loop = EventLoop::<()>::with_user_event(); let event_loop = EventLoop::<()>::with_user_event();
@ -118,6 +134,8 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
.expect("Failed to create renderer"); .expect("Failed to create renderer");
let mut cursor_pos = (0.0, 0.0); let mut cursor_pos = (0.0, 0.0);
let mut mouse_down = false;
let mut mouse_pos = (0, 0);
icu::init(); icu::init();
@ -152,8 +170,59 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
} }
}, },
Event::WindowEvent {
event: WindowEvent::CursorMoved {
position,
..
},
..
} => {
let grid_x = (position.x as f32 / font_width) as i64;
let grid_y = (position.y as f32 / font_height) as i64;
mouse_pos = (grid_x, grid_y);
if mouse_down {
editor.lock().unwrap().nvim.input_mouse("left", "drag", "", 0, grid_y, grid_x);
}
}
Event::WindowEvent {
event: WindowEvent::MouseInput {
state,
..
},
..
} => {
let input_type = match state {
ElementState::Pressed => {
mouse_down = true;
"press"
},
ElementState::Released => {
mouse_down = false;
"release"
}
};
let (grid_x, grid_y) = mouse_pos;
editor.lock().unwrap().nvim.input_mouse("left", input_type, "", 0, grid_y, grid_x);
}
Event::WindowEvent {
event: WindowEvent::MouseWheel {
delta: MouseScrollDelta::LineDelta(delta, _),
..
},
..
} => {
let input_type = if delta > 0.0 {
"up"
} else {
"down"
};
let (grid_x, grid_y) = mouse_pos;
editor.lock().unwrap().nvim.input_mouse("wheel", input_type, "", 0, grid_y, grid_x);
}
Event::EventsCleared => { Event::EventsCleared => {
// Queue a RedrawRequested event.
window.request_redraw(); window.request_redraw();
}, },
@ -162,7 +231,7 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>) {
.. ..
} => { } => {
if let Err(e) = renderer.draw(&window, |canvas, _coordinate_system_helper| { if let Err(e) = renderer.draw(&window, |canvas, _coordinate_system_helper| {
draw(&editor, canvas, &mut cursor_pos, &shaper, &font, font_width, font_height); draw(&editor, canvas, &mut cursor_pos, &shaper, &mut paint, &font, font_width, font_height);
}) { }) {
println!("Error during draw: {:?}", e); println!("Error during draw: {:?}", e);
*control_flow = ControlFlow::Exit *control_flow = ControlFlow::Exit

Loading…
Cancel
Save