diff --git a/src/bridge/ui_commands.rs b/src/bridge/ui_commands.rs index 3564e00..8c0259c 100644 --- a/src/bridge/ui_commands.rs +++ b/src/bridge/ui_commands.rs @@ -110,8 +110,4 @@ impl UiCommand { } } } - - pub fn is_resize(&self) -> bool { - matches!(self, UiCommand::Resize { .. }) - } } diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 07e734e..8bffdb4 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -7,8 +7,9 @@ use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::{Sender, Receiver}; use std::thread; +use std::fmt; -use log::{error, trace}; +use log::{error, warn, trace}; use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor}; use crate::redraw_scheduler::REDRAW_SCHEDULER; @@ -56,10 +57,25 @@ pub enum DrawCommand { UpdateCursor(Cursor), FontChanged(String), DefaultStyleChanged(Style), +} + +pub enum WindowCommand { TitleChanged(String), SetMouseEnabled(bool), } +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::UpdateCursor(_) => write!(formatter, "UpdateCursor"), + DrawCommand::FontChanged(_) => write!(formatter, "FontChanged"), + DrawCommand::DefaultStyleChanged(_) => write!(formatter, "DefaultStyleChanged"), + } + } +} + pub struct Editor { pub windows: HashMap, pub cursor: Cursor, @@ -67,11 +83,12 @@ pub struct Editor { pub previous_style: Option>, pub mode_list: Vec, pub current_mode: EditorMode, - pub draw_command_sender: Sender + pub draw_command_sender: Sender, + pub window_command_sender: Sender, } impl Editor { - pub fn new(draw_command_sender: Sender) -> Editor { + pub fn new(draw_command_sender: Sender, window_command_sender: Sender) -> Editor { Editor { windows: HashMap::new(), cursor: Cursor::new(), @@ -79,14 +96,15 @@ impl Editor { previous_style: None, mode_list: Vec::new(), current_mode: EditorMode::Unknown(String::from("")), - draw_command_sender + draw_command_sender, + window_command_sender } } pub fn handle_redraw_event(&mut self, event: RedrawEvent) { match event { RedrawEvent::SetTitle { title } => { - self.draw_command_sender.send(DrawCommand::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), @@ -98,10 +116,10 @@ impl Editor { } } RedrawEvent::MouseOn => { - self.draw_command_sender.send(DrawCommand::SetMouseEnabled(true)).ok(); + self.window_command_sender.send(WindowCommand::SetMouseEnabled(true)).ok(); } RedrawEvent::MouseOff => { - self.draw_command_sender.send(DrawCommand::SetMouseEnabled(false)).ok(); + self.window_command_sender.send(WindowCommand::SetMouseEnabled(false)).ok(); } RedrawEvent::BusyStart => { trace!("Cursor off"); @@ -209,7 +227,7 @@ impl Editor { } fn resize_window(&mut self, grid: u64, width: u64, height: u64) { - println!("editor resize {}", grid); + warn!("editor resize {}", grid); if let Some(window) = self.windows.get_mut(&grid) { window.resize(width, height); } else { @@ -233,7 +251,7 @@ impl Editor { width: u64, height: u64, ) { - println!("position {}", grid); + warn!("position {}", grid); if let Some(window) = self.windows.get_mut(&grid) { window.position( width, @@ -264,7 +282,7 @@ impl Editor { anchor_left: f64, anchor_top: f64, ) { - println!("floating position {}", grid); + warn!("floating position {}", grid); let parent_position = self.get_window_top_left(anchor_grid); if let Some(window) = self.windows.get_mut(&grid) { let width = window.get_width(); @@ -292,7 +310,7 @@ impl Editor { } fn set_message_position(&mut self, grid: u64, grid_top: u64) { - println!("message position {}", grid); + warn!("message position {}", grid); let parent_width = self.windows.get(&1).map(|parent| parent.get_width()).unwrap_or(1); if let Some(window) = self.windows.get_mut(&grid) { @@ -363,9 +381,9 @@ impl Editor { } } -pub fn start_editor(redraw_event_receiver: Receiver, draw_command_sender: Sender) { +pub fn start_editor(redraw_event_receiver: Receiver, draw_command_sender: Sender, window_command_sender: Sender) { thread::spawn(move || { - let mut editor = Editor::new(draw_command_sender); + let mut editor = Editor::new(draw_command_sender, window_command_sender); loop { if let Ok(redraw_event) = redraw_event_receiver.recv() { diff --git a/src/editor/window.rs b/src/editor/window.rs index c878187..edf3f48 100644 --- a/src/editor/window.rs +++ b/src/editor/window.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::sync::mpsc::Sender; +use std::fmt; use log::warn; use unicode_segmentation::UnicodeSegmentation; @@ -10,7 +11,7 @@ use super::grid::CharacterGrid; use super::style::Style; use crate::bridge::GridLineCell; -#[derive(new, Debug, Clone)] +#[derive(new, Clone)] pub enum WindowDrawCommand { Position { grid_left: f64, @@ -40,6 +41,20 @@ pub enum WindowDrawCommand { Close } +impl fmt::Debug for WindowDrawCommand { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + WindowDrawCommand::Position { .. } => write!(formatter, "Position"), + WindowDrawCommand::Cell { .. } => write!(formatter, "Cell"), + WindowDrawCommand::Scroll { .. } => write!(formatter, "Scroll"), + WindowDrawCommand::Clear => write!(formatter, "Clear"), + WindowDrawCommand::Show => write!(formatter, "Show"), + WindowDrawCommand::Hide => write!(formatter, "Hide"), + WindowDrawCommand::Close => write!(formatter, "Close"), + } + } +} + pub struct Window { grid_id: u64, grid: CharacterGrid, diff --git a/src/main.rs b/src/main.rs index 136eb86..eb2973f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -134,8 +134,9 @@ fn main() { let (redraw_event_sender, redraw_event_receiver) = channel(); let (draw_command_sender, 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); - start_window(draw_command_receiver, ui_command_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()); } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index da03896..99b1222 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use std::sync::Arc; +use std::sync::mpsc::Receiver; -use log::{trace, error}; +use log::{trace, warn, error}; use skulpin::skia_safe::{ - colors, dash_path_effect, Canvas, Paint, Rect, BlendMode + colors, dash_path_effect, Canvas, Paint, Rect, BlendMode, Color }; use skulpin::CoordinateSystemHelper; @@ -57,10 +58,11 @@ pub struct Renderer { pub font_width: f32, pub font_height: f32, pub window_regions: Vec<(u64, Rect)>, + pub draw_command_receiver: Receiver, } impl Renderer { - pub fn new() -> Renderer { + pub fn new(draw_command_receiver: Receiver) -> Renderer { let rendered_windows = HashMap::new(); let cursor_renderer = CursorRenderer::new(); let settings = SETTINGS.get::(); @@ -87,6 +89,7 @@ impl Renderer { font_width, font_height, window_regions, + draw_command_receiver, } } @@ -115,20 +118,13 @@ impl Renderer { grid_pos: (u64, u64), cell_width: u64, style: &Option>, - floating: bool, ) { self.paint.set_blend_mode(BlendMode::Src); let region = self.compute_text_region(grid_pos, cell_width); let style = style.as_ref().unwrap_or(&self.default_style); - let mut color = style.background(&self.default_style.colors); - - if floating { - color.a = color.a * self.settings.floating_opacity.min(1.0).max(0.0); - } - - self.paint.set_color(color.to_color()); + self.paint.set_color(style.background(&self.default_style.colors).to_color()); canvas.draw_rect(region, &self.paint); } @@ -152,6 +148,10 @@ impl Renderer { let region = self.compute_text_region(grid_pos, cell_width); canvas.clip_rect(region, None, Some(false)); + self.paint.set_blend_mode(BlendMode::Src); + let transparent = Color::from_argb(0, 255, 255, 255); + self.paint.set_color(transparent); + canvas.draw_rect(region, &self.paint); if style.underline || style.undercurl { let line_position = self.shaper.underline_position(); @@ -200,6 +200,7 @@ impl Renderer { } pub fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) { + warn!("{:?}", &draw_command); match draw_command { DrawCommand::Window { grid_id, @@ -212,13 +213,14 @@ impl Renderer { 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 { - println!("Created window {}", grid_id); + warn!("Created window {}", grid_id); let new_window = RenderedWindow::new( root_canvas, &self, grid_id, (grid_left as f32, grid_top as f32).into(), @@ -251,6 +253,11 @@ impl Renderer { ) { trace!("Rendering"); + let draw_commands: Vec = self.draw_command_receiver.try_iter().collect(); + for draw_command in draw_commands.into_iter() { + self.handle_draw_command(root_canvas, draw_command); + } + root_canvas.clear(self.default_style.colors.background.clone().unwrap().to_color()); coordinate_system_helper.use_logical_coordinates(root_canvas); diff --git a/src/renderer/rendered_window.rs b/src/renderer/rendered_window.rs index 92edd07..d668a25 100644 --- a/src/renderer/rendered_window.rs +++ b/src/renderer/rendered_window.rs @@ -1,6 +1,6 @@ use skulpin::skia_safe::gpu::SurfaceOrigin; use skulpin::skia_safe::{ - Budgeted, Canvas, ImageInfo, Rect, Surface, Point, image_filters::blur + Budgeted, Canvas, ImageInfo, Rect, Surface, Point, Paint, Color, image_filters::blur }; use skulpin::skia_safe::canvas::{ SaveLayerRec, @@ -40,12 +40,14 @@ fn build_window_surface( ) .expect("Could not create surface"); let canvas = surface.canvas(); + canvas.clear(renderer.default_style.colors.background.clone().unwrap().to_color()); surface } pub struct RenderedWindow { - surface: Surface, + background_surface: Surface, + foreground_surface: Surface, pub id: u64, pub hidden: bool, pub floating: bool, @@ -60,10 +62,12 @@ pub struct RenderedWindow { impl RenderedWindow { pub fn new(parent_canvas: &mut Canvas, renderer: &Renderer, id: u64, grid_position: Point, grid_width: u64, grid_height: u64) -> RenderedWindow { - let surface = build_window_surface(parent_canvas, renderer, grid_width, grid_height); + 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); RenderedWindow { - surface, + background_surface, + foreground_surface, id, hidden: false, floating: false, @@ -135,10 +139,18 @@ impl RenderedWindow { root_canvas.save_layer(&save_layer_rec); } - self.surface.draw( - root_canvas.as_mut(), - (current_pixel_position.x, current_pixel_position.y), - None); + let mut paint = Paint::default(); + + if self.floating { + let a = (settings.floating_opacity.min(1.0).max(0.0) * 255.0) as u8; + paint.set_color(Color::from_argb(a, 255, 255, 255)); + } + + let background_snapshot = self.background_surface.image_snapshot(); + root_canvas.draw_image(background_snapshot, (current_pixel_position.x, current_pixel_position.y), Some(&paint)); + + let foreground_snapshot = self.foreground_surface.image_snapshot(); + root_canvas.draw_image(foreground_snapshot, (current_pixel_position.x, current_pixel_position.y), None); if self.floating { root_canvas.restore(); @@ -168,9 +180,14 @@ impl RenderedWindow { } if grid_width != self.grid_width || grid_height != self.grid_height { - let mut old_surface = self.surface; - self.surface = build_window_surface(old_surface.canvas(), &renderer, grid_width, grid_height); - old_surface.draw(self.surface.canvas(), (0.0, 0.0), None); + let mut old_background = self.background_surface; + self.background_surface = build_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); + old_foreground.draw(self.foreground_surface.canvas(), (0.0, 0.0), None); + self.grid_width = grid_width; self.grid_height = grid_height; } @@ -180,23 +197,28 @@ impl RenderedWindow { WindowDrawCommand::Cell { text, cell_width, window_left, window_top, style } => { - let mut canvas = self.surface.canvas(); let grid_position = (window_left, window_top); - renderer.draw_background( - &mut canvas, - grid_position, - cell_width, - &style, - self.floating, - ); - renderer.draw_foreground( - &mut canvas, - &text, - grid_position, - cell_width, - &style, - ); + { + let mut background_canvas = self.background_surface.canvas(); + renderer.draw_background( + &mut background_canvas, + grid_position, + cell_width, + &style + ); + } + + { + let mut foreground_canvas = self.foreground_surface.canvas(); + renderer.draw_foreground( + &mut foreground_canvas, + &text, + grid_position, + cell_width, + &style, + ); + } }, WindowDrawCommand::Scroll { top, bot, left, right, rows, cols @@ -207,22 +229,42 @@ impl RenderedWindow { right as f32 * renderer.font_width, bot as f32 * renderer.font_height); - let snapshot = self.surface.image_snapshot(); - let canvas = self.surface.canvas(); + { + let background_snapshot = self.background_surface.image_snapshot(); + let background_canvas = self.background_surface.canvas(); + + background_canvas.save(); + 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)); - canvas.save(); - canvas.clip_rect(scrolled_region, None, Some(false)); + background_canvas.draw_image_rect(background_snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint); + + background_canvas.restore(); + } - let mut translated_region = scrolled_region.clone(); - translated_region.offset((-cols as f32 * renderer.font_width, -rows as f32 * renderer.font_height)); + { + let foreground_snapshot = self.foreground_surface.image_snapshot(); + let foreground_canvas = self.foreground_surface.canvas(); - canvas.draw_image_rect(snapshot, Some((&scrolled_region, SrcRectConstraint::Fast)), translated_region, &renderer.paint); + foreground_canvas.save(); + foreground_canvas.clip_rect(scrolled_region, None, Some(false)); - canvas.restore(); + 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); + + foreground_canvas.restore(); + } }, WindowDrawCommand::Clear => { - let canvas = self.surface.canvas(); - self.surface = build_window_surface(canvas, &renderer, self.grid_width, self.grid_height); + let background_canvas = self.background_surface.canvas(); + self.background_surface = build_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); }, WindowDrawCommand::Show => self.hidden = false, WindowDrawCommand::Hide => self.hidden = true, diff --git a/src/window.rs b/src/window.rs index 5b7c565..e14ee9c 100644 --- a/src/window.rs +++ b/src/window.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::mpsc::{Sender, Receiver}; -use log::{debug, error, info, trace}; +use log::{debug, error, warn, info, trace}; use skulpin::sdl2; use skulpin::sdl2::event::{Event, WindowEvent}; use skulpin::sdl2::keyboard::Keycode; @@ -16,7 +16,7 @@ use skulpin::{ RendererBuilder, Sdl2Window, Window, }; -use crate::editor::DrawCommand; +use crate::editor::{DrawCommand, WindowCommand}; use crate::bridge::{produce_neovim_keybinding_string, UiCommand}; use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::renderer::Renderer; @@ -111,7 +111,7 @@ pub fn window_geometry_or_default() -> (u64, u64) { } impl WindowWrapper { - pub fn new(ui_command_sender: Sender, running: Arc) -> WindowWrapper { + pub fn new(ui_command_sender: Sender, draw_command_receiver: Receiver, running: Arc) -> WindowWrapper { let context = sdl2::init().expect("Failed to initialize sdl2"); let video_subsystem = context .video() @@ -120,7 +120,7 @@ impl WindowWrapper { let (width, height) = window_geometry_or_default(); - let renderer = Renderer::new(); + let renderer = Renderer::new(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, @@ -381,7 +381,7 @@ impl WindowWrapper { REDRAW_SCHEDULER.queue_next_frame(); } - pub fn draw_frame(&mut self, draw_commands: Vec, dt: f32) -> VkResult { + pub fn draw_frame(&mut self, dt: f32) -> VkResult { let sdl_window_wrapper = Sdl2Window::new(&self.window); let new_size = sdl_window_wrapper.logical_size(); if self.previous_size != new_size { @@ -395,10 +395,6 @@ impl WindowWrapper { let renderer = &mut self.renderer; self.skulpin_renderer .draw(&sdl_window_wrapper, |canvas, coordinate_system_helper| { - for draw_command in draw_commands.into_iter() { - renderer.handle_draw_command(canvas, draw_command); - } - renderer.draw_frame(canvas, &coordinate_system_helper, dt) })?; @@ -435,8 +431,8 @@ pub fn initialize_settings() { register_nvim_setting!("fullscreen", WindowSettings::fullscreen); } -pub fn start_window(draw_command_receiver: Receiver, ui_command_sender: Sender, running: Arc) { - let mut window = WindowWrapper::new(ui_command_sender.clone(), running.clone()); +pub fn start_window(draw_command_receiver: Receiver, window_command_receiver: Receiver, ui_command_sender: Sender, running: Arc) { + let mut window = WindowWrapper::new(ui_command_sender.clone(), draw_command_receiver, running.clone()); info!("Starting window event loop"); let mut event_pump = window @@ -503,17 +499,14 @@ pub fn start_window(draw_command_receiver: Receiver, ui_command_sen 1.0 / refresh_rate }; - let mut unhandled_draw_commands = Vec::new(); - - for draw_command in draw_command_receiver.try_iter() { - match draw_command { - DrawCommand::TitleChanged(new_title) => window.handle_title_changed(new_title), - DrawCommand::SetMouseEnabled(mouse_enabled) => window.mouse_enabled = mouse_enabled, - unhandled_command => unhandled_draw_commands.push(unhandled_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, } } - match window.draw_frame(unhandled_draw_commands, dt) { + match window.draw_frame(dt) { Ok(animating) => { was_animating = animating; },