mostly working

macos-click-through
keith 4 years ago
parent 15d02a0417
commit 8b87f92f5f

@ -700,7 +700,7 @@ fn parse_win_external_pos(win_external_pos_arguments: Vec<Value>) -> Result<Redr
let [grid, _window] = extract_values(win_external_pos_arguments, [Value::Nil, Value::Nil])?;
Ok(RedrawEvent::WindowExternalPosition {
grid: parse_u64(grid)?
grid: parse_u64(grid)?,
})
}

@ -4,12 +4,12 @@ pub mod layouts;
mod events;
mod ui_commands;
use std::process::{Stdio, Command};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::mpsc::{Sender, Receiver};
use std::env;
use std::path::Path;
use std::process::{Command, Stdio};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use std::thread;
#[cfg(windows)]
@ -108,10 +108,16 @@ pub fn create_nvim_command() -> Command {
cmd
}
pub fn start_bridge(ui_command_sender: Sender<UiCommand>, ui_command_receiver: Receiver<UiCommand>, redraw_event_sender: Sender<RedrawEvent>, running: Arc<AtomicBool>) {
pub fn start_bridge(
ui_command_sender: Sender<UiCommand>,
ui_command_receiver: Receiver<UiCommand>,
redraw_event_sender: Sender<RedrawEvent>,
running: Arc<AtomicBool>,
) {
thread::spawn(move || {
let (width, height) = window_geometry_or_default();
let mut session = Session::new_child_cmd(&mut create_nvim_command()).unwrap_or_explained_panic("Could not locate or start neovim process");
let mut session = Session::new_child_cmd(&mut create_nvim_command())
.unwrap_or_explained_panic("Could not locate or start neovim process");
let notification_receiver = session.start_event_loop_channel();
let mut nvim = Neovim::new(session);
@ -126,7 +132,8 @@ pub fn start_bridge(ui_command_sender: Sender<UiCommand>, ui_command_receiver: R
std::process::exit(0);
};
nvim.set_var("neovide", Value::Boolean(true)).unwrap_or_explained_panic("Could not communicate with neovim process");
nvim.set_var("neovide", Value::Boolean(true))
.unwrap_or_explained_panic("Could not communicate with neovim process");
if let Err(command_error) = nvim.command("runtime! ginit.vim") {
nvim.command(&format!(
"echomsg \"error encountered in ginit.vim {:?}\"",
@ -200,61 +207,58 @@ pub fn start_bridge(ui_command_sender: Sender<UiCommand>, ui_command_receiver: R
SETTINGS.setup_changed_listeners(&mut nvim);
let notification_running = running.clone();
thread::spawn(move || {
loop {
if !notification_running.load(Ordering::Relaxed) {
break;
}
thread::spawn(move || loop {
if !notification_running.load(Ordering::Relaxed) {
break;
}
match notification_receiver.recv() {
Ok((event_name, arguments)) =>
match event_name.as_ref() {
"redraw" => {
for events in arguments {
let parsed_events = parse_redraw_event(events)
.unwrap_or_explained_panic("Could not parse event from neovim");
for parsed_event in parsed_events {
redraw_event_sender.send(parsed_event).ok();
}
}
}
"setting_changed" => {
SETTINGS.handle_changed_notification(arguments);
}
#[cfg(windows)]
"neovide.register_right_click" => {
ui_command_sender.send(UiCommand::RegisterRightClick).ok();
}
#[cfg(windows)]
"neovide.unregister_right_click" => {
ui_command_sender.send(UiCommand::UnregisterRightClick).ok();
match notification_receiver.recv() {
Ok((event_name, arguments)) => match event_name.as_ref() {
"redraw" => {
for events in arguments {
let parsed_events = parse_redraw_event(events)
.unwrap_or_explained_panic("Could not parse event from neovim");
for parsed_event in parsed_events {
redraw_event_sender.send(parsed_event).ok();
}
_ => {}
},
Err(error) => {
notification_running.store(false, Ordering::Relaxed);
break;
}
}
"setting_changed" => {
SETTINGS.handle_changed_notification(arguments);
}
#[cfg(windows)]
"neovide.register_right_click" => {
ui_command_sender.send(UiCommand::RegisterRightClick).ok();
}
#[cfg(windows)]
"neovide.unregister_right_click" => {
ui_command_sender.send(UiCommand::UnregisterRightClick).ok();
}
_ => {}
},
Err(error) => {
error!("Notification channel closed: {}", error);
notification_running.store(false, Ordering::Relaxed);
break;
}
}
});
let ui_command_running = running.clone();
thread::spawn(move || {
loop {
if !ui_command_running.load(Ordering::Relaxed) {
break;
}
thread::spawn(move || loop {
if !ui_command_running.load(Ordering::Relaxed) {
break;
}
match ui_command_receiver.recv() {
Ok(ui_command) => {
ui_command.execute(&mut nvim);
},
Err(error) => {
ui_command_running.store(false, Ordering::Relaxed);
break;
}
match ui_command_receiver.recv() {
Ok(ui_command) => {
ui_command.execute(&mut nvim);
}
Err(error) => {
error!("Ui command channel closed: {}", error);
ui_command_running.store(false, Ordering::Relaxed);
break;
}
}
});

@ -52,23 +52,44 @@ impl UiCommand {
grid_id,
position: (grid_x, grid_y),
} => {
nvim.input_mouse("left", &action, "", grid_id as i64, grid_y as i64, grid_x as i64)
.expect("Mouse Input Failed");
nvim.input_mouse(
"left",
&action,
"",
grid_id as i64,
grid_y as i64,
grid_x as i64,
)
.expect("Mouse Input Failed");
}
UiCommand::Scroll {
direction,
grid_id,
position: (grid_x, grid_y),
} => {
nvim.input_mouse("wheel", &direction, "", grid_id as i64, grid_y as i64, grid_x as i64)
.expect("Mouse Scroll Failed");
nvim.input_mouse(
"wheel",
&direction,
"",
grid_id as i64,
grid_y as i64,
grid_x as i64,
)
.expect("Mouse Scroll Failed");
}
UiCommand::Drag {
grid_id,
position: (grid_x, grid_y)
position: (grid_x, grid_y),
} => {
nvim.input_mouse("left", "drag", "", grid_id as i64, grid_y as i64, grid_x as i64)
.expect("Mouse Drag Failed");
nvim.input_mouse(
"left",
"drag",
"",
grid_id as i64,
grid_y as i64,
grid_x as i64,
)
.expect("Mouse Drag Failed");
}
UiCommand::FocusLost => nvim
.command("if exists('#FocusLost') | doautocmd <nomodeline> FocusLost | endif")

@ -0,0 +1,31 @@
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
use super::DrawCommand;
pub struct DrawCommandBatcher {
window_draw_command_sender: Sender<DrawCommand>,
window_draw_command_receiver: Receiver<DrawCommand>,
batched_draw_command_sender: Sender<Vec<DrawCommand>>,
}
impl DrawCommandBatcher {
pub fn new(batched_draw_command_sender: Sender<Vec<DrawCommand>>) -> DrawCommandBatcher {
let (sender, receiver) = channel();
DrawCommandBatcher {
window_draw_command_sender: sender,
window_draw_command_receiver: receiver,
batched_draw_command_sender,
}
}
pub fn queue(&self, draw_command: DrawCommand) -> Result<(), SendError<DrawCommand>> {
self.window_draw_command_sender.send(draw_command)
}
pub fn send_batch(&self) -> Result<(), SendError<Vec<DrawCommand>>> {
let batch = self.window_draw_command_receiver.try_iter().collect();
self.batched_draw_command_sender.send(batch)
}
}

@ -71,7 +71,10 @@ impl CharacterGrid {
pub fn row(&self, row_index: u64) -> Option<&[GridCell]> {
if row_index < self.height {
Some(&self.characters[(row_index * self.width) as usize..((row_index + 1) * self.width) as usize])
Some(
&self.characters
[(row_index * self.width) as usize..((row_index + 1) * self.width) as usize],
)
} else {
None
}
@ -230,7 +233,6 @@ mod tests {
(thread_rng().gen::<u64>() % 500) + 1,
(thread_rng().gen::<u64>() % 500) + 1,
);
let new_area = (width * height) as usize;
let grid_cell = Some((
"foo".to_string(),
@ -243,6 +245,18 @@ mod tests {
assert_eq!(character_grid.width, width);
assert_eq!(character_grid.height, height);
assert_eq!(character_grid.characters, vec![grid_cell.clone(); new_area]);
let (original_width, original_height) = context.size;
for x in 0..original_width.min(width) {
for y in 0..original_height.min(height) {
assert_eq!(character_grid.get_cell(x, y).unwrap(), &grid_cell);
}
}
for x in original_width..width {
for y in original_height..height {
assert_eq!(character_grid.get_cell(x, y).unwrap(), &None);
}
}
}
}

@ -1,19 +1,21 @@
mod cursor;
mod draw_command_batcher;
mod grid;
mod style;
mod window;
use std::collections::HashMap;
use std::fmt;
use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use std::sync::mpsc::{Sender, Receiver};
use std::thread;
use std::fmt;
use log::{error, warn, trace};
use log::{error, trace, warn};
use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor};
use crate::redraw_scheduler::REDRAW_SCHEDULER;
pub use cursor::{Cursor, CursorMode, CursorShape};
pub use draw_command_batcher::DrawCommandBatcher;
pub use grid::CharacterGrid;
pub use style::{Colors, Style};
pub use window::*;
@ -26,24 +28,18 @@ pub struct AnchorInfo {
}
impl WindowAnchor {
fn modified_top_left(&self, grid_left: f64, grid_top: f64, width: u64, height: u64) -> (f64, f64) {
fn modified_top_left(
&self,
grid_left: f64,
grid_top: f64,
width: u64,
height: u64,
) -> (f64, f64) {
match self {
WindowAnchor::NorthWest => (
grid_left,
grid_top,
),
WindowAnchor::NorthEast => (
grid_left - width as f64,
grid_top,
),
WindowAnchor::SouthWest => (
grid_left,
grid_top - height as f64,
),
WindowAnchor::SouthEast => (
grid_left - width as f64,
grid_top - height as f64,
),
WindowAnchor::NorthWest => (grid_left, grid_top),
WindowAnchor::NorthEast => (grid_left - width as f64, grid_top),
WindowAnchor::SouthWest => (grid_left, grid_top - height as f64),
WindowAnchor::SouthEast => (grid_left - width as f64, grid_top - height as f64),
}
}
}
@ -52,7 +48,7 @@ pub enum DrawCommand {
CloseWindow(u64),
Window {
grid_id: u64,
command: WindowDrawCommand
command: WindowDrawCommand,
},
UpdateCursor(Cursor),
FontChanged(String),
@ -68,7 +64,9 @@ impl fmt::Debug for DrawCommand {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DrawCommand::CloseWindow(_) => write!(formatter, "CloseWindow"),
DrawCommand::Window { grid_id, command } => write!(formatter, "Window {} {:?}", grid_id, command),
DrawCommand::Window { grid_id, command } => {
write!(formatter, "Window {} {:?}", grid_id, command)
}
DrawCommand::UpdateCursor(_) => write!(formatter, "UpdateCursor"),
DrawCommand::FontChanged(_) => write!(formatter, "FontChanged"),
DrawCommand::DefaultStyleChanged(_) => write!(formatter, "DefaultStyleChanged"),
@ -82,28 +80,33 @@ pub struct Editor {
pub defined_styles: HashMap<u64, Arc<Style>>,
pub mode_list: Vec<CursorMode>,
pub current_mode: EditorMode,
pub draw_command_sender: Sender<DrawCommand>,
pub draw_command_batcher: Arc<DrawCommandBatcher>,
pub window_command_sender: Sender<WindowCommand>,
}
impl Editor {
pub fn new(draw_command_sender: Sender<DrawCommand>, window_command_sender: Sender<WindowCommand>) -> Editor {
pub fn new(
batched_draw_command_sender: Sender<Vec<DrawCommand>>,
window_command_sender: Sender<WindowCommand>,
) -> Editor {
Editor {
windows: HashMap::new(),
cursor: Cursor::new(),
defined_styles: HashMap::new(),
mode_list: Vec::new(),
current_mode: EditorMode::Unknown(String::from("")),
draw_command_sender,
window_command_sender
draw_command_batcher: Arc::new(DrawCommandBatcher::new(batched_draw_command_sender)),
window_command_sender,
}
}
pub fn handle_redraw_event(&mut self, event: RedrawEvent) {
match event {
RedrawEvent::SetTitle { title } => {
self.window_command_sender.send(WindowCommand::TitleChanged(title)).ok();
},
self.window_command_sender
.send(WindowCommand::TitleChanged(title))
.ok();
}
RedrawEvent::ModeInfoSet { cursor_modes } => self.mode_list = cursor_modes,
RedrawEvent::OptionSet { gui_option } => self.set_option(gui_option),
RedrawEvent::ModeChange { mode, mode_index } => {
@ -113,10 +116,14 @@ impl Editor {
}
}
RedrawEvent::MouseOn => {
self.window_command_sender.send(WindowCommand::SetMouseEnabled(true)).ok();
self.window_command_sender
.send(WindowCommand::SetMouseEnabled(true))
.ok();
}
RedrawEvent::MouseOff => {
self.window_command_sender.send(WindowCommand::SetMouseEnabled(false)).ok();
self.window_command_sender
.send(WindowCommand::SetMouseEnabled(false))
.ok();
}
RedrawEvent::BusyStart => {
trace!("Cursor off");
@ -129,17 +136,22 @@ impl Editor {
RedrawEvent::Flush => {
trace!("Image flushed");
self.send_cursor_info();
self.draw_command_batcher.send_batch().ok();
REDRAW_SCHEDULER.queue_next_frame();
}
RedrawEvent::DefaultColorsSet { colors } => {
self.draw_command_sender.send(DrawCommand::DefaultStyleChanged(Style::new(colors))).ok();
self.draw_command_batcher
.queue(DrawCommand::DefaultStyleChanged(Style::new(colors)))
.ok();
}
RedrawEvent::HighlightAttributesDefine { id, style } => {
self.defined_styles.insert(id, Arc::new(style));
}
RedrawEvent::CursorGoto { grid, column: left, row: top } => {
self.set_cursor_position(grid, left, top)
}
RedrawEvent::CursorGoto {
grid,
column: left,
row: top,
} => self.set_cursor_position(grid, left, top),
RedrawEvent::Resize {
grid,
width,
@ -154,19 +166,12 @@ impl Editor {
cells,
} => {
let defined_styles = &self.defined_styles;
self.windows.get_mut(&grid).map(|window| {
window.draw_grid_line(
row,
column_start,
cells,
defined_styles
)
});
}
RedrawEvent::Clear { grid } => {
self.windows
.get_mut(&grid)
.map(|window| window.clear());
.map(|window| window.draw_grid_line(row, column_start, cells, defined_styles));
}
RedrawEvent::Clear { grid } => {
self.windows.get_mut(&grid).map(|window| window.clear());
}
RedrawEvent::Destroy { grid } => self.close_window(grid),
RedrawEvent::Scroll {
@ -196,13 +201,9 @@ impl Editor {
anchor_column: anchor_left,
anchor_row: anchor_top,
..
} => {
self.set_window_float_position(grid, anchor_grid, anchor, anchor_left, anchor_top)
}
} => self.set_window_float_position(grid, anchor_grid, anchor, anchor_left, anchor_top),
RedrawEvent::WindowHide { grid } => {
self.windows
.get(&grid)
.map(|window| window.hide());
self.windows.get(&grid).map(|window| window.hide());
}
RedrawEvent::WindowClose { grid } => self.close_window(grid),
RedrawEvent::MessageSetPosition { grid, row, .. } => {
@ -215,7 +216,9 @@ impl Editor {
fn close_window(&mut self, grid: u64) {
if let Some(window) = self.windows.remove(&grid) {
window.close();
self.draw_command_sender.send(DrawCommand::CloseWindow(grid)).ok();
self.draw_command_batcher
.queue(DrawCommand::CloseWindow(grid))
.ok();
}
}
@ -231,7 +234,8 @@ impl Editor {
None,
0.0,
0.0,
self.draw_command_sender.clone());
self.draw_command_batcher.clone(),
);
self.windows.insert(grid, window);
}
}
@ -246,12 +250,7 @@ impl Editor {
) {
warn!("position {}", grid);
if let Some(window) = self.windows.get_mut(&grid) {
window.position(
width,
height,
None,
start_left as f64,
start_top as f64);
window.position(width, height, None, start_left as f64, start_top as f64);
window.show();
} else {
let new_window = Window::new(
@ -261,7 +260,7 @@ impl Editor {
None,
start_left as f64,
start_top as f64,
self.draw_command_sender.clone()
self.draw_command_batcher.clone(),
);
self.windows.insert(grid, new_window);
}
@ -280,9 +279,8 @@ impl Editor {
if let Some(window) = self.windows.get_mut(&grid) {
let width = window.get_width();
let height = window.get_height();
let (mut modified_left, mut modified_top) = anchor_type.modified_top_left(
anchor_left, anchor_top,
width, height);
let (mut modified_left, mut modified_top) =
anchor_type.modified_top_left(anchor_left, anchor_top, width, height);
if let Some((parent_left, parent_top)) = parent_position {
modified_left = parent_left + modified_left;
@ -290,12 +288,17 @@ impl Editor {
}
window.position(
width, height,
width,
height,
Some(AnchorInfo {
anchor_grid_id: anchor_grid,
anchor_type, anchor_left, anchor_top
anchor_type,
anchor_left,
anchor_top,
}),
modified_left, modified_top);
modified_left,
modified_top,
);
window.show();
} else {
error!("Attempted to float window that does not exist.");
@ -304,14 +307,20 @@ impl Editor {
fn set_message_position(&mut self, grid: u64, grid_top: u64) {
warn!("message position {}", grid);
let parent_width = self.windows.get(&1).map(|parent| parent.get_width()).unwrap_or(1);
let parent_width = self
.windows
.get(&1)
.map(|parent| parent.get_width())
.unwrap_or(1);
if let Some(window) = self.windows.get_mut(&grid) {
window.position(
parent_width, window.get_height(),
parent_width,
window.get_height(),
None,
0.0,
grid_top as f64);
grid_top as f64,
);
window.show();
} else {
let new_window = Window::new(
@ -321,7 +330,7 @@ impl Editor {
None,
0.0,
grid_top as f64,
self.draw_command_sender.clone()
self.draw_command_batcher.clone(),
);
self.windows.insert(grid, new_window);
}
@ -336,11 +345,18 @@ impl Editor {
let (parent_anchor_left, parent_anchor_top) =
self.get_window_top_left(anchor_info.anchor_grid_id)?;
let (anchor_modified_left, anchor_modified_top) = anchor_info.anchor_type.modified_top_left(
anchor_info.anchor_left, anchor_info.anchor_top,
window.get_width(), window.get_height());
let (anchor_modified_left, anchor_modified_top) =
anchor_info.anchor_type.modified_top_left(
anchor_info.anchor_left,
anchor_info.anchor_top,
window.get_width(),
window.get_height(),
);
Some((parent_anchor_left + anchor_modified_left, parent_anchor_top + anchor_modified_top))
Some((
parent_anchor_left + anchor_modified_left,
parent_anchor_top + anchor_modified_top,
))
}
None => Some(window.get_grid_position()),
}
@ -355,10 +371,12 @@ impl Editor {
let (grid_left, grid_top) = self.cursor.grid_position;
match self.get_window_top_left(self.cursor.parent_window_id) {
Some((window_left, window_top)) => {
self.cursor.position = (window_left + grid_left as f64, window_top + grid_top as f64);
self.cursor.position =
(window_left + grid_left as f64, window_top + grid_top as f64);
if let Some(window) = self.windows.get(&self.cursor.parent_window_id) {
let (character, double_width) = window.get_cursor_character(grid_left, grid_top);
let (character, double_width) =
window.get_cursor_character(grid_left, grid_top);
self.cursor.character = character;
self.cursor.double_width = double_width;
}
@ -369,20 +387,28 @@ impl Editor {
self.cursor.character = " ".to_string();
}
}
self.draw_command_sender.send(DrawCommand::UpdateCursor(self.cursor.clone())).ok();
self.draw_command_batcher
.queue(DrawCommand::UpdateCursor(self.cursor.clone()))
.ok();
}
fn set_option(&mut self, gui_option: GuiOption) {
trace!("Option set {:?}", &gui_option);
if let GuiOption::GuiFont(guifont) = gui_option {
self.draw_command_sender.send(DrawCommand::FontChanged(guifont)).ok();
self.draw_command_batcher
.queue(DrawCommand::FontChanged(guifont))
.ok();
}
}
}
pub fn start_editor(redraw_event_receiver: Receiver<RedrawEvent>, draw_command_sender: Sender<DrawCommand>, window_command_sender: Sender<WindowCommand>) {
pub fn start_editor(
redraw_event_receiver: Receiver<RedrawEvent>,
batched_draw_command_sender: Sender<Vec<DrawCommand>>,
window_command_sender: Sender<WindowCommand>,
) {
thread::spawn(move || {
let mut editor = Editor::new(draw_command_sender, window_command_sender);
let mut editor = Editor::new(batched_draw_command_sender, window_command_sender);
loop {
if let Ok(redraw_event) = redraw_event_receiver.recv() {

@ -1,14 +1,13 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::fmt;
use std::sync::Arc;
use log::warn;
use unicode_segmentation::UnicodeSegmentation;
use super::{DrawCommand, AnchorInfo};
use super::grid::CharacterGrid;
use super::style::Style;
use super::{AnchorInfo, DrawCommand, DrawCommandBatcher};
use crate::bridge::GridLineCell;
#[derive(new, Clone)]
@ -18,7 +17,7 @@ pub enum WindowDrawCommand {
grid_top: f64,
width: u64,
height: u64,
floating: bool
floating: bool,
},
Cell {
text: String,
@ -38,7 +37,7 @@ pub enum WindowDrawCommand {
Clear,
Show,
Hide,
Close
Close,
}
impl fmt::Debug for WindowDrawCommand {
@ -64,7 +63,7 @@ pub struct Window {
grid_left: f64,
grid_top: f64,
draw_command_sender: Sender<DrawCommand>
draw_command_batcher: Arc<DrawCommandBatcher>,
}
impl Window {
@ -75,7 +74,7 @@ impl Window {
anchor_info: Option<AnchorInfo>,
grid_left: f64,
grid_top: f64,
draw_command_sender: Sender<DrawCommand>
draw_command_batcher: Arc<DrawCommandBatcher>,
) -> Window {
let window = Window {
grid_id,
@ -83,17 +82,19 @@ impl Window {
anchor_info,
grid_left,
grid_top,
draw_command_sender
draw_command_batcher,
};
window.send_updated_position();
window
}
fn send_command(&self, command: WindowDrawCommand) {
self.draw_command_sender.send(DrawCommand::Window {
grid_id: self.grid_id,
command
}).ok();
self.draw_command_batcher
.queue(DrawCommand::Window {
grid_id: self.grid_id,
command,
})
.ok();
}
fn send_updated_position(&self) {
@ -132,7 +133,14 @@ impl Window {
(self.grid_left, self.grid_top)
}
pub fn position(&mut self, width: u64, height: u64, anchor_info: Option<AnchorInfo>, grid_left: f64, grid_top: f64) {
pub fn position(
&mut self,
width: u64,
height: u64,
anchor_info: Option<AnchorInfo>,
grid_left: f64,
grid_top: f64,
) {
self.grid.resize(width, height);
self.anchor_info = anchor_info;
self.grid_left = grid_left;
@ -156,12 +164,8 @@ impl Window {
// Get the defined style from the style list
let style = match cell.highlight_id {
Some(0) => None,
Some(style_id) => {
defined_styles.get(&style_id).cloned()
},
None => {
previous_style.clone()
},
Some(style_id) => defined_styles.get(&style_id).cloned(),
None => previous_style.clone(),
};
// Compute text
@ -185,16 +189,14 @@ impl Window {
*column_pos += text.graphemes(true).count() as u64;
}
if let Some(style) = style {
*previous_style = Some(style);
}
*previous_style = style;
}
fn send_draw_command(
&mut self,
row_index: u64,
line_start: u64,
current_start: u64
current_start: u64,
) -> Option<u64> {
let row = self.grid.row(row_index).unwrap();
@ -217,7 +219,6 @@ impl Window {
}
}
let mut draw_command_end_index = current_start;
for possible_end_index in draw_command_start_index..self.grid.width {
if let Some((_, possible_end_style)) = &row[possible_end_index as usize] {
@ -242,7 +243,7 @@ impl Window {
cell_width: draw_command_end_index - draw_command_start_index + 1,
window_left: draw_command_start_index,
window_top: row_index,
style: style.clone()
style: style.clone(),
});
Some(draw_command_end_index + 1)
@ -253,7 +254,7 @@ impl Window {
row: u64,
column_start: u64,
cells: Vec<GridLineCell>,
defined_styles: &HashMap<u64, Arc<Style>>
defined_styles: &HashMap<u64, Arc<Style>>,
) {
let mut previous_style = None;
if row < self.grid.height {
@ -297,7 +298,12 @@ impl Window {
};
self.send_command(WindowDrawCommand::Scroll {
top, bot, left, right, rows, cols
top,
bot,
left,
right,
rows,
cols,
});
// Scrolls must not only translate the rendered texture, but also must move the grid data

@ -18,10 +18,10 @@ extern crate rust_embed;
#[macro_use]
extern crate lazy_static;
use std::sync::Arc;
use std::process;
use std::sync::atomic::AtomicBool;
use std::sync::mpsc::channel;
use std::process;
use std::sync::Arc;
use window::window_geometry;
@ -132,11 +132,25 @@ fn main() {
let running = Arc::new(AtomicBool::new(true));
let (redraw_event_sender, redraw_event_receiver) = channel();
let (draw_command_sender, draw_command_receiver) = channel();
let (batched_draw_command_sender, batched_draw_command_receiver) = channel();
let (ui_command_sender, ui_command_receiver) = channel();
let (window_command_sender, window_command_receiver) = channel();
start_bridge(ui_command_sender.clone(), ui_command_receiver, redraw_event_sender, running.clone());
start_editor(redraw_event_receiver, draw_command_sender, window_command_sender);
start_window(draw_command_receiver, window_command_receiver, ui_command_sender, running.clone());
start_bridge(
ui_command_sender.clone(),
ui_command_receiver,
redraw_event_sender,
running.clone(),
);
start_editor(
redraw_event_receiver,
batched_draw_command_sender,
window_command_sender,
);
start_window(
batched_draw_command_receiver,
window_command_receiver,
ui_command_sender,
running.clone(),
);
}

@ -2,8 +2,8 @@ use log::error;
use skulpin::skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect};
use super::CursorSettings;
use crate::renderer::animation_utils::*;
use crate::editor::{Colors, Cursor};
use crate::renderer::animation_utils::*;
use crate::settings::*;
pub trait CursorVfx {

@ -5,8 +5,8 @@ use skulpin::skia_safe::{Canvas, Paint, Path, Point};
use crate::editor::{Colors, Cursor, CursorShape};
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::renderer::CachingShaper;
use crate::renderer::animation_utils::*;
use crate::renderer::CachingShaper;
use crate::settings::*;
use blink::*;
@ -265,8 +265,8 @@ impl CursorRenderer {
let in_insert_mode = false;
// {
// let editor = EDITOR.lock();
// matches!(editor.current_mode, EditorMode::Insert)
// let editor = EDITOR.lock();
// matches!(editor.current_mode, EditorMode::Insert)
// };
let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into();
@ -277,7 +277,9 @@ impl CursorRenderer {
self.previous_cursor_shape = new_cursor.clone();
self.set_cursor_shape(
&new_cursor.unwrap(),
self.cursor.cell_percentage.unwrap_or(DEFAULT_CELL_PERCENTAGE),
self.cursor
.cell_percentage
.unwrap_or(DEFAULT_CELL_PERCENTAGE),
);
if let Some(vfx) = self.cursor_vfx.as_mut() {

@ -1,28 +1,25 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::Receiver;
use std::sync::Arc;
use log::{trace, warn, error};
use skulpin::skia_safe::{
colors, dash_path_effect, Canvas, Paint, Rect, BlendMode, Color
};
use log::{error, trace, warn};
use skulpin::skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect};
use skulpin::CoordinateSystemHelper;
pub mod animation_utils;
mod caching_shaper;
mod rendered_window;
pub mod cursor_renderer;
pub mod font_options;
pub mod animation_utils;
mod rendered_window;
pub use caching_shaper::CachingShaper;
pub use font_options::*;
use crate::editor::{Style, Colors, DrawCommand, WindowDrawCommand};
use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand};
use crate::settings::*;
use cursor_renderer::CursorRenderer;
use rendered_window::RenderedWindow;
// ----------------------------------------------------------------------------
#[derive(Clone)]
@ -39,14 +36,19 @@ pub fn initialize_settings() {
floating_blur: true,
});
register_nvim_setting!("window_animation_length", RendererSettings::animation_length);
register_nvim_setting!("floating_window_opacity", RendererSettings::floating_opacity);
register_nvim_setting!(
"window_animation_length",
RendererSettings::animation_length
);
register_nvim_setting!(
"floating_window_opacity",
RendererSettings::floating_opacity
);
register_nvim_setting!("floating_window_blur", RendererSettings::floating_opacity);
}
// ----------------------------------------------------------------------------
pub struct Renderer {
rendered_windows: HashMap<u64, RenderedWindow>,
cursor_renderer: CursorRenderer,
@ -58,11 +60,11 @@ pub struct Renderer {
pub font_width: f32,
pub font_height: f32,
pub window_regions: Vec<(u64, Rect)>,
pub draw_command_receiver: Receiver<DrawCommand>,
pub batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
}
impl Renderer {
pub fn new(draw_command_receiver: Receiver<DrawCommand>) -> Renderer {
pub fn new(batched_draw_command_receiver: Receiver<Vec<DrawCommand>>) -> Renderer {
let rendered_windows = HashMap::new();
let cursor_renderer = CursorRenderer::new();
let settings = SETTINGS.get::<RendererSettings>();
@ -89,7 +91,7 @@ impl Renderer {
font_width,
font_height,
window_regions,
draw_command_receiver,
batched_draw_command_receiver,
}
}
@ -124,7 +126,8 @@ impl Renderer {
let region = self.compute_text_region(grid_pos, cell_width);
let style = style.as_ref().unwrap_or(&self.default_style);
self.paint.set_color(style.background(&self.default_style.colors).to_color());
self.paint
.set_color(style.background(&self.default_style.colors).to_color());
canvas.draw_rect(region, &self.paint);
}
@ -205,44 +208,49 @@ impl Renderer {
match draw_command {
DrawCommand::Window {
grid_id,
command: WindowDrawCommand::Close
command: WindowDrawCommand::Close,
} => {
self.rendered_windows.remove(&grid_id);
},
DrawCommand::Window {
grid_id,
command
} => {
}
DrawCommand::Window { grid_id, command } => {
if let Some(rendered_window) = self.rendered_windows.remove(&grid_id) {
warn!("Window positioned {}", grid_id);
let rendered_window = rendered_window.handle_window_draw_command(self, command);
self.rendered_windows.insert(grid_id, rendered_window);
} else if let WindowDrawCommand::Position {
grid_left, grid_top,
width, height, ..
} = command {
grid_left,
grid_top,
width,
height,
..
} = command
{
warn!("Created window {}", grid_id);
let new_window = RenderedWindow::new(
root_canvas, &self, grid_id,
root_canvas,
&self,
grid_id,
(grid_left as f32, grid_top as f32).into(),
width, height);
width,
height,
);
self.rendered_windows.insert(grid_id, new_window);
} else {
error!("WindowDrawCommand sent for uninitialized grid {}", grid_id);
}
},
}
DrawCommand::UpdateCursor(new_cursor) => {
self.cursor_renderer.update_cursor(new_cursor);
},
}
DrawCommand::FontChanged(new_font) => {
if self.update_font(&new_font) {
// Resize all the grids
}
},
}
DrawCommand::DefaultStyleChanged(new_style) => {
self.default_style = Arc::new(new_style);
},
_ => { }
}
_ => {}
}
}
@ -255,7 +263,12 @@ impl Renderer {
trace!("Rendering");
let mut font_changed = false;
let draw_commands: Vec<DrawCommand> = self.draw_command_receiver.try_iter().collect();
let draw_commands: Vec<DrawCommand> = self
.batched_draw_command_receiver
.try_iter() // Iterator of Vec of DrawCommand
.map(|batch| batch.into_iter()) // Iterator of Iterator of DrawCommand
.flatten() // Iterator of DrawCommand
.collect(); // Vec of DrawCommand
for draw_command in draw_commands.into_iter() {
if let DrawCommand::FontChanged(_) = draw_command {
font_changed = true;
@ -263,20 +276,36 @@ impl Renderer {
self.handle_draw_command(root_canvas, draw_command);
}
root_canvas.clear(self.default_style.colors.background.clone().unwrap().to_color());
root_canvas.clear(
self.default_style
.colors
.background
.clone()
.unwrap()
.to_color(),
);
coordinate_system_helper.use_logical_coordinates(root_canvas);
let windows: Vec<&mut RenderedWindow> = {
let (mut root_windows, mut floating_windows): (Vec<&mut RenderedWindow>, Vec<&mut RenderedWindow>) = self.rendered_windows
let (mut root_windows, mut floating_windows): (
Vec<&mut RenderedWindow>,
Vec<&mut RenderedWindow>,
) = self
.rendered_windows
.values_mut()
.filter(|window| !window.hidden)
.partition(|window| !window.floating);
root_windows.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
floating_windows.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
root_windows
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
floating_windows
.sort_by(|window_a, window_b| window_a.id.partial_cmp(&window_b.id).unwrap());
root_windows.into_iter().chain(floating_windows.into_iter()).collect()
root_windows
.into_iter()
.chain(floating_windows.into_iter())
.collect()
};
let settings = &self.settings;

@ -1,14 +1,11 @@
use skulpin::skia_safe::canvas::{SaveLayerRec, SrcRectConstraint};
use skulpin::skia_safe::gpu::SurfaceOrigin;
use skulpin::skia_safe::{
Budgeted, Canvas, ImageInfo, Rect, Surface, Point, Paint, Color, BlendMode, image_filters::blur
};
use skulpin::skia_safe::canvas::{
SaveLayerRec,
SrcRectConstraint
image_filters::blur, BlendMode, Budgeted, Canvas, Color, ImageInfo, Paint, Point, Rect, Surface,
};
use super::{Renderer, RendererSettings};
use super::animation_utils::*;
use super::{Renderer, RendererSettings};
use crate::editor::WindowDrawCommand;
use crate::redraw_scheduler::REDRAW_SCHEDULER;
@ -18,7 +15,10 @@ fn build_window_surface(
grid_width: u64,
grid_height: u64,
) -> Surface {
let dimensions = ((grid_width as f32 * renderer.font_width) as i32, (grid_height as f32 * renderer.font_height) as i32);
let dimensions = (
(grid_width as f32 * renderer.font_width) as i32,
(grid_height as f32 * renderer.font_height) as i32,
);
let mut context = parent_canvas.gpu_context().unwrap();
let budgeted = Budgeted::Yes;
let parent_image_info = parent_canvas.image_info();
@ -39,9 +39,26 @@ fn build_window_surface(
None,
)
.expect("Could not create surface");
let canvas = surface.canvas();
surface
}
canvas.clear(renderer.default_style.colors.background.clone().unwrap().to_color());
fn build_background_window_surface(
parent_canvas: &mut Canvas,
renderer: &Renderer,
grid_width: u64,
grid_height: u64,
) -> Surface {
let mut surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height);
let canvas = surface.canvas();
canvas.clear(
renderer
.default_style
.colors
.background
.clone()
.unwrap()
.to_color(),
);
surface
}
@ -52,18 +69,28 @@ pub struct RenderedWindow {
pub hidden: bool,
pub floating: bool,
grid_width: u64, grid_height: u64,
grid_width: u64,
grid_height: u64,
grid_start_position: Point,
grid_current_position: Point,
grid_destination: Point,
t: f32
t: f32,
}
impl RenderedWindow {
pub fn new(parent_canvas: &mut Canvas, renderer: &Renderer, id: u64, grid_position: Point, grid_width: u64, grid_height: u64) -> RenderedWindow {
let background_surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height);
let foreground_surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height);
pub fn new(
parent_canvas: &mut Canvas,
renderer: &Renderer,
id: u64,
grid_position: Point,
grid_width: u64,
grid_height: u64,
) -> RenderedWindow {
let background_surface =
build_background_window_surface(parent_canvas, renderer, grid_width, grid_height);
let foreground_surface =
build_window_surface(parent_canvas, renderer, grid_width, grid_height);
RenderedWindow {
background_surface,
@ -78,15 +105,11 @@ impl RenderedWindow {
grid_start_position: grid_position,
grid_current_position: grid_position,
grid_destination: grid_position,
t: 2.0 // 2.0 is out of the 0.0 to 1.0 range and stops animation
t: 2.0, // 2.0 is out of the 0.0 to 1.0 range and stops animation
}
}
pub fn update(
&mut self,
settings: &RendererSettings,
dt: f32
) -> bool {
pub fn update(&mut self, settings: &RendererSettings, dt: f32) -> bool {
if (self.t - 1.0).abs() < std::f32::EPSILON {
return false;
}
@ -114,9 +137,12 @@ impl RenderedWindow {
settings: &RendererSettings,
font_width: f32,
font_height: f32,
dt: f32
) -> (u64, Rect) {
let current_pixel_position = Point::new(self.grid_current_position.x * font_width, self.grid_current_position.y * font_height);
dt: f32,
) -> (u64, Rect) {
let current_pixel_position = Point::new(
self.grid_current_position.x * font_width,
self.grid_current_position.y * font_height,
);
let image_width = (self.grid_width as f32 * font_width) as i32;
let image_height = (self.grid_height as f32 * font_height) as i32;
@ -132,9 +158,7 @@ impl RenderedWindow {
if self.floating && settings.floating_blur {
let blur = blur((2.0, 2.0), None, None, None).unwrap();
let save_layer_rec = SaveLayerRec::default()
.backdrop(&blur)
.bounds(&region);
let save_layer_rec = SaveLayerRec::default().backdrop(&blur).bounds(&region);
root_canvas.save_layer(&save_layer_rec);
}
@ -146,12 +170,20 @@ impl RenderedWindow {
paint.set_color(Color::from_argb(a, 255, 255, 255));
}
self.background_surface.draw(root_canvas.as_mut(), (current_pixel_position.x, current_pixel_position.y), Some(&paint));
self.background_surface.draw(
root_canvas.as_mut(),
(current_pixel_position.x, current_pixel_position.y),
Some(&paint),
);
let mut paint = Paint::default();
paint.set_blend_mode(BlendMode::SrcOver);
self.foreground_surface.draw(root_canvas.as_mut(), (current_pixel_position.x, current_pixel_position.y), Some(&paint));
self.foreground_surface.draw(
root_canvas.as_mut(),
(current_pixel_position.x, current_pixel_position.y),
Some(&paint),
);
if self.floating {
root_canvas.restore();
@ -161,21 +193,31 @@ impl RenderedWindow {
let window_position = current_pixel_position.clone();
(self.id, Rect::from_point_and_size(window_position, (image_width as f32, image_height as f32)))
(
self.id,
Rect::from_point_and_size(window_position, (image_width as f32, image_height as f32)),
)
}
pub fn handle_window_draw_command(mut self, renderer: &mut Renderer, draw_command: WindowDrawCommand) -> Self {
pub fn handle_window_draw_command(
mut self,
renderer: &mut Renderer,
draw_command: WindowDrawCommand,
) -> Self {
match draw_command {
WindowDrawCommand::Position {
grid_left, grid_top,
grid_left,
grid_top,
width: grid_width,
height: grid_height,
floating
floating,
} => {
let new_destination: Point = (grid_left as f32, grid_top as f32).into();
if self.grid_destination != new_destination {
if self.grid_start_position.x.abs() > f32::EPSILON || self.grid_start_position.y.abs() > f32::EPSILON {
if self.grid_start_position.x.abs() > f32::EPSILON
|| self.grid_start_position.y.abs() > f32::EPSILON
{
self.t = 0.0; // Reset animation as we have a new destination.
self.grid_start_position = self.grid_current_position;
self.grid_destination = new_destination;
@ -191,13 +233,23 @@ impl RenderedWindow {
if grid_width != self.grid_width || grid_height != self.grid_height {
{
let mut old_background = self.background_surface;
self.background_surface = build_window_surface(old_background.canvas(), &renderer, grid_width, grid_height);
self.background_surface = build_background_window_surface(
old_background.canvas(),
&renderer,
grid_width,
grid_height,
);
old_background.draw(self.background_surface.canvas(), (0.0, 0.0), None);
}
{
let mut old_foreground = self.foreground_surface;
self.foreground_surface = build_window_surface(old_foreground.canvas(), &renderer, grid_width, grid_height);
self.foreground_surface = build_window_surface(
old_foreground.canvas(),
&renderer,
grid_width,
grid_height,
);
old_foreground.draw(self.foreground_surface.canvas(), (0.0, 0.0), None);
}
@ -213,9 +265,13 @@ impl RenderedWindow {
self.grid_start_position = new_destination;
self.grid_destination = new_destination;
}
},
}
WindowDrawCommand::Cell {
text, cell_width, window_left, window_top, style
text,
cell_width,
window_left,
window_top,
style,
} => {
let grid_position = (window_left, window_top);
@ -225,7 +281,7 @@ impl RenderedWindow {
&mut background_canvas,
grid_position,
cell_width,
&style
&style,
);
}
@ -239,15 +295,21 @@ impl RenderedWindow {
&style,
);
}
},
}
WindowDrawCommand::Scroll {
top, bot, left, right, rows, cols
top,
bot,
left,
right,
rows,
cols,
} => {
let scrolled_region = Rect::new(
left as f32 * renderer.font_width,
top as f32 * renderer.font_height,
right as f32 * renderer.font_width,
bot as f32 * renderer.font_height);
bot as f32 * renderer.font_height,
);
{
let background_snapshot = self.background_surface.image_snapshot();
@ -257,9 +319,17 @@ impl RenderedWindow {
background_canvas.clip_rect(scrolled_region, None, Some(false));
let mut translated_region = scrolled_region.clone();
translated_region.offset((-cols as f32 * renderer.font_width, -rows as f32 * renderer.font_height));
background_canvas.draw_image_rect(background_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint);
translated_region.offset((
-cols as f32 * renderer.font_width,
-rows as f32 * renderer.font_height,
));
background_canvas.draw_image_rect(
background_snapshot,
Some((&scrolled_region, SrcRectConstraint::Fast)),
translated_region,
&renderer.paint,
);
background_canvas.restore();
}
@ -272,20 +342,38 @@ impl RenderedWindow {
foreground_canvas.clip_rect(scrolled_region, None, Some(false));
let mut translated_region = scrolled_region.clone();
translated_region.offset((-cols as f32 * renderer.font_width, -rows as f32 * renderer.font_height));
foreground_canvas.draw_image_rect(foreground_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint);
translated_region.offset((
-cols as f32 * renderer.font_width,
-rows as f32 * renderer.font_height,
));
foreground_canvas.draw_image_rect(
foreground_snapshot,
Some((&scrolled_region, SrcRectConstraint::Fast)),
translated_region,
&renderer.paint,
);
foreground_canvas.restore();
}
},
}
WindowDrawCommand::Clear => {
let background_canvas = self.background_surface.canvas();
self.background_surface = build_window_surface(background_canvas, &renderer, self.grid_width, self.grid_height);
self.background_surface = build_background_window_surface(
background_canvas,
&renderer,
self.grid_width,
self.grid_height,
);
let foreground_canvas = self.foreground_surface.canvas();
self.foreground_surface = build_window_surface(foreground_canvas, &renderer, self.grid_width, self.grid_height);
},
self.foreground_surface = build_window_surface(
foreground_canvas,
&renderer,
self.grid_width,
self.grid_height,
);
}
WindowDrawCommand::Show => {
if self.hidden {
self.hidden = false;
@ -293,7 +381,7 @@ impl RenderedWindow {
self.grid_start_position = self.grid_destination;
self.grid_destination = self.grid_destination;
}
},
}
WindowDrawCommand::Hide => self.hidden = true,
_ => {}
};

@ -170,11 +170,10 @@ impl Settings {
),
name
);
nvim.command(&vimscript)
.unwrap_or_explained_panic(&format!(
"Could not setup setting notifier for {}",
name
));
nvim.command(&vimscript).unwrap_or_explained_panic(&format!(
"Could not setup setting notifier for {}",
name
));
}
}
@ -191,31 +190,11 @@ impl Settings {
#[cfg(test)]
mod tests {
use neovim_lib::{Neovim, NeovimApi, Session, UiAttachOptions};
use super::*;
use crate::bridge::create_nvim_command;
use async_trait::async_trait;
use nvim_rs::create::tokio as create;
use nvim_rs::{compat::tokio::Compat, Handler, Neovim};
#[derive(Clone)]
pub struct NeovimHandler();
#[async_trait]
impl Handler for NeovimHandler {
type Writer = Compat<ChildStdin>;
async fn handle_notify(
&self,
_event_name: String,
_arguments: Vec<Value>,
_neovim: Neovim<Compat<ChildStdin>>,
) {
}
}
use tokio;
#[test]
fn test_set_setting_handlers() {
@ -288,8 +267,8 @@ mod tests {
assert_eq!(v2, r2);
}
#[tokio::test]
async fn test_read_initial_values() {
#[test]
fn test_read_initial_values() {
let settings = Settings::new();
let v1: String = "foo".to_string();
@ -298,12 +277,12 @@ mod tests {
let v4: String = format!("neovide_{}", v1);
let v5: String = format!("neovide_{}", v2);
let (nvim, _, _) = create::new_child_cmd(&mut create_nvim_command(), NeovimHandler())
.await
.unwrap_or_explained_panic("Could not locate or start the neovim process");
let mut session = Session::new_child_cmd(&mut create_nvim_command())
.unwrap_or_explained_panic("Could not locate or start neovim process");
session.start_event_loop_channel();
let mut nvim = Neovim::new(session);
nvim.set_var(&v4, Value::from(v2.clone())).await.ok();
println!("v4 set");
nvim.set_var(&v4, Value::from(v2.clone())).unwrap();
fn noop_update(_v: Value) {}
@ -327,10 +306,10 @@ mod tests {
settings.readers.force_unlock_write();
}
settings.read_initial_values(&nvim).await;
settings.read_initial_values(&mut nvim);
let rt1 = nvim.get_var(&v4).await.unwrap();
let rt2 = nvim.get_var(&v5).await.unwrap();
let rt1 = nvim.get_var(&v4).unwrap();
let rt2 = nvim.get_var(&v5).unwrap();
let r1 = rt1.as_str().unwrap();
let r2 = rt2.as_str().unwrap();

@ -1,28 +1,28 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Receiver, Sender};
use std::sync::Arc;
use std::thread::sleep;
use std::time::{Duration, Instant};
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
use std::sync::mpsc::{Sender, Receiver};
use log::{debug, error, warn, info, trace};
use log::{debug, error, info, trace, warn};
use skulpin::ash::prelude::VkResult;
use skulpin::sdl2;
use skulpin::sdl2::event::{Event, WindowEvent};
use skulpin::sdl2::keyboard::Keycode;
use skulpin::sdl2::video::FullscreenType;
use skulpin::sdl2::Sdl;
use skulpin::ash::prelude::VkResult;
use skulpin::{
CoordinateSystem, LogicalSize, PhysicalSize, PresentMode, Renderer as SkulpinRenderer,
RendererBuilder, Sdl2Window, Window,
};
use crate::editor::{DrawCommand, WindowCommand};
use crate::bridge::{produce_neovim_keybinding_string, UiCommand};
use crate::editor::{DrawCommand, WindowCommand};
use crate::error_handling::ResultPanicExplanation;
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::renderer::Renderer;
use crate::settings::*;
use crate::INITIAL_DIMENSIONS;
use crate::error_handling::ResultPanicExplanation;
#[derive(RustEmbed)]
#[folder = "assets/"]
@ -37,15 +37,21 @@ fn windows_fix_dpi() {
}
}
fn handle_new_grid_size(new_size: LogicalSize, renderer: &Renderer, ui_command_sender: &Sender<UiCommand>) {
fn handle_new_grid_size(
new_size: LogicalSize,
renderer: &Renderer,
ui_command_sender: &Sender<UiCommand>,
) {
if new_size.width > 0 && new_size.height > 0 {
let new_width = ((new_size.width + 1) as f32 / renderer.font_width) as u32;
let new_height = ((new_size.height + 1) as f32 / renderer.font_height) as u32;
// Add 1 here to make sure resizing doesn't change the grid size on startup
ui_command_sender.send(UiCommand::Resize {
width: new_width,
height: new_height,
}).ok();
ui_command_sender
.send(UiCommand::Resize {
width: new_width,
height: new_height,
})
.ok();
}
}
@ -65,7 +71,7 @@ struct WindowWrapper {
cached_size: (u32, u32),
cached_position: (i32, i32),
ui_command_sender: Sender<UiCommand>,
running: Arc<AtomicBool>
running: Arc<AtomicBool>,
}
pub fn window_geometry() -> Result<(u64, u64), String> {
@ -111,7 +117,11 @@ pub fn window_geometry_or_default() -> (u64, u64) {
}
impl WindowWrapper {
pub fn new(ui_command_sender: Sender<UiCommand>, draw_command_receiver: Receiver<DrawCommand>, running: Arc<AtomicBool>) -> WindowWrapper {
pub fn new(
ui_command_sender: Sender<UiCommand>,
batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
running: Arc<AtomicBool>,
) -> WindowWrapper {
let context = sdl2::init().expect("Failed to initialize sdl2");
let video_subsystem = context
.video()
@ -120,7 +130,7 @@ impl WindowWrapper {
let (width, height) = window_geometry_or_default();
let renderer = Renderer::new(draw_command_receiver);
let renderer = Renderer::new(batched_draw_command_receiver);
let logical_size = LogicalSize {
width: (width as f32 * renderer.font_width) as u32,
height: (height as f32 * renderer.font_height + 1.0) as u32,
@ -172,7 +182,7 @@ impl WindowWrapper {
cached_size: (0, 0),
cached_position: (0, 0),
ui_command_sender,
running
running,
}
}
@ -270,28 +280,36 @@ impl WindowWrapper {
if let Some(keybinding_string) = produce_neovim_keybinding_string(keycode, text, modifiers)
{
self.ui_command_sender.send(UiCommand::Keyboard(keybinding_string)).unwrap_or_explained_panic(
"Could not send UI command from the window system to the neovim process.",
);
self.ui_command_sender
.send(UiCommand::Keyboard(keybinding_string))
.unwrap_or_explained_panic(
"Could not send UI command from the window system to the neovim process.",
);
}
}
pub fn handle_pointer_motion(&mut self, x: i32, y: i32) {
let previous_position = self.mouse_position;
let sdl_window_wrapper = Sdl2Window::new(&self.window);
let logical_position = PhysicalSize::new(x as u32, y as u32)
.to_logical(sdl_window_wrapper.scale_factor());
let logical_position =
PhysicalSize::new(x as u32, y as u32).to_logical(sdl_window_wrapper.scale_factor());
let mut top_window_position = (0.0, 0.0);
let mut top_grid_position = None;
for (grid_id, window_region) in self.renderer.window_regions.iter() {
if logical_position.width >= window_region.left as u32 && logical_position.width < window_region.right as u32 &&
logical_position.height >= window_region.top as u32 && logical_position.height < window_region.bottom as u32 {
if logical_position.width >= window_region.left as u32
&& logical_position.width < window_region.right as u32
&& logical_position.height >= window_region.top as u32
&& logical_position.height < window_region.bottom as u32
{
top_window_position = (window_region.left, window_region.top);
top_grid_position = Some((
grid_id,
LogicalSize::new(logical_position.width - window_region.left as u32, logical_position.height - window_region.top as u32)
LogicalSize::new(
logical_position.width - window_region.left as u32,
logical_position.height - window_region.top as u32,
),
));
}
}
@ -300,40 +318,48 @@ impl WindowWrapper {
self.grid_id_under_mouse = *grid_id;
self.mouse_position = LogicalSize::new(
(grid_position.width as f32 / self.renderer.font_width) as u32,
(grid_position.height as f32 / self.renderer.font_height) as u32
(grid_position.height as f32 / self.renderer.font_height) as u32,
);
if self.mouse_enabled && self.mouse_down && previous_position != self.mouse_position {
let (window_left, window_top) = top_window_position;
let adjusted_drag_left = self.mouse_position.width + (window_left / self.renderer.font_width) as u32;
let adjusted_drag_top = self.mouse_position.height + (window_top / self.renderer.font_height) as u32;
self.ui_command_sender.send(UiCommand::Drag {
grid_id: self.grid_id_under_mouse,
position: (adjusted_drag_left, adjusted_drag_top),
}).ok();
let adjusted_drag_left =
self.mouse_position.width + (window_left / self.renderer.font_width) as u32;
let adjusted_drag_top =
self.mouse_position.height + (window_top / self.renderer.font_height) as u32;
self.ui_command_sender
.send(UiCommand::Drag {
grid_id: self.grid_id_under_mouse,
position: (adjusted_drag_left, adjusted_drag_top),
})
.ok();
}
}
}
pub fn handle_pointer_down(&mut self) {
if self.mouse_enabled {
self.ui_command_sender.send(UiCommand::MouseButton {
action: String::from("press"),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
}).ok();
self.ui_command_sender
.send(UiCommand::MouseButton {
action: String::from("press"),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
})
.ok();
}
self.mouse_down = true;
}
pub fn handle_pointer_up(&mut self) {
if self.mouse_enabled {
self.ui_command_sender.send(UiCommand::MouseButton {
action: String::from("release"),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
}).ok();
self.ui_command_sender
.send(UiCommand::MouseButton {
action: String::from("release"),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
})
.ok();
}
self.mouse_down = false;
}
@ -350,11 +376,13 @@ impl WindowWrapper {
};
if let Some(input_type) = vertical_input_type {
self.ui_command_sender.send(UiCommand::Scroll {
direction: input_type.to_string(),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
}).ok();
self.ui_command_sender
.send(UiCommand::Scroll {
direction: input_type.to_string(),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
})
.ok();
}
let horizontal_input_type = match y {
@ -364,11 +392,13 @@ impl WindowWrapper {
};
if let Some(input_type) = horizontal_input_type {
self.ui_command_sender.send(UiCommand::Scroll {
direction: input_type.to_string(),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
}).ok();
self.ui_command_sender
.send(UiCommand::Scroll {
direction: input_type.to_string(),
grid_id: self.grid_id_under_mouse,
position: (self.mouse_position.width, self.mouse_position.height),
})
.ok();
}
}
@ -396,12 +426,14 @@ impl WindowWrapper {
if REDRAW_SCHEDULER.should_draw() || SETTINGS.get::<WindowSettings>().no_idle {
let renderer = &mut self.renderer;
self.skulpin_renderer
.draw(&sdl_window_wrapper, |canvas, coordinate_system_helper| {
self.skulpin_renderer.draw(
&sdl_window_wrapper,
|canvas, coordinate_system_helper| {
if renderer.draw_frame(canvas, &coordinate_system_helper, dt) {
handle_new_grid_size(current_size, &renderer, &ui_command_sender);
}
})?;
},
)?;
Ok(true)
} else {
@ -436,8 +468,17 @@ pub fn initialize_settings() {
register_nvim_setting!("fullscreen", WindowSettings::fullscreen);
}
pub fn start_window(draw_command_receiver: Receiver<DrawCommand>, window_command_receiver: Receiver<WindowCommand>, ui_command_sender: Sender<UiCommand>, running: Arc<AtomicBool>) {
let mut window = WindowWrapper::new(ui_command_sender.clone(), draw_command_receiver, running.clone());
pub fn start_window(
batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
window_command_receiver: Receiver<WindowCommand>,
ui_command_sender: Sender<UiCommand>,
running: Arc<AtomicBool>,
) {
let mut window = WindowWrapper::new(
ui_command_sender.clone(),
batched_draw_command_receiver,
running.clone(),
);
info!("Starting window event loop");
let mut event_pump = window
@ -507,14 +548,16 @@ pub fn start_window(draw_command_receiver: Receiver<DrawCommand>, window_command
for window_command in window_command_receiver.try_iter() {
match window_command {
WindowCommand::TitleChanged(new_title) => window.handle_title_changed(new_title),
WindowCommand::SetMouseEnabled(mouse_enabled) => window.mouse_enabled = mouse_enabled,
WindowCommand::SetMouseEnabled(mouse_enabled) => {
window.mouse_enabled = mouse_enabled
}
}
}
match window.draw_frame(dt) {
Ok(animating) => {
was_animating = animating;
},
}
Err(error) => {
error!("Render failed: {}", error);
break;

Loading…
Cancel
Save