refactor grid_renderer out of renderer and clean up window draw command handling

macos-click-through
Keith Simmons 3 years ago
parent c52a6e356a
commit 3bba418c1c

@ -2,8 +2,8 @@ use log::error;
use skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect}; use skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect};
use super::CursorSettings; use super::CursorSettings;
use crate::editor::{Colors, Cursor}; use crate::editor::Cursor;
use crate::renderer::animation_utils::*; use crate::renderer::{animation_utils::*, grid_renderer::GridRenderer};
use crate::settings::*; use crate::settings::*;
pub trait CursorVfx { pub trait CursorVfx {
@ -11,7 +11,7 @@ pub trait CursorVfx {
&mut self, &mut self,
settings: &CursorSettings, settings: &CursorSettings,
current_cursor_destination: Point, current_cursor_destination: Point,
font_size: (u64, u64), cursor_dimensions: Point,
dt: f32, dt: f32,
) -> bool; ) -> bool;
fn restart(&mut self, position: Point); fn restart(&mut self, position: Point);
@ -19,9 +19,8 @@ pub trait CursorVfx {
&self, &self,
settings: &CursorSettings, settings: &CursorSettings,
canvas: &mut Canvas, canvas: &mut Canvas,
grid_renderer: &mut GridRenderer,
cursor: &Cursor, cursor: &Cursor,
colors: &Colors,
font_size: (u64, u64),
); );
} }
@ -111,7 +110,7 @@ impl CursorVfx for PointHighlight {
&mut self, &mut self,
_settings: &CursorSettings, _settings: &CursorSettings,
_current_cursor_destination: Point, _current_cursor_destination: Point,
_font_size: (u64, u64), _cursor_dimensions: Point,
dt: f32, dt: f32,
) -> bool { ) -> bool {
self.t = (self.t + dt * 5.0).min(1.0); // TODO - speed config self.t = (self.t + dt * 5.0).min(1.0); // TODO - speed config
@ -127,9 +126,8 @@ impl CursorVfx for PointHighlight {
&self, &self,
settings: &CursorSettings, settings: &CursorSettings,
canvas: &mut Canvas, canvas: &mut Canvas,
grid_renderer: &mut GridRenderer,
cursor: &Cursor, cursor: &Cursor,
colors: &Colors,
font_size: (u64, u64),
) { ) {
if (self.t - 1.0).abs() < std::f32::EPSILON { if (self.t - 1.0).abs() < std::f32::EPSILON {
return; return;
@ -138,13 +136,15 @@ impl CursorVfx for PointHighlight {
let mut paint = Paint::new(skia_safe::colors::WHITE, None); let mut paint = Paint::new(skia_safe::colors::WHITE, None);
paint.set_blend_mode(BlendMode::SrcOver); paint.set_blend_mode(BlendMode::SrcOver);
let colors = &grid_renderer.default_style.colors;
let base_color: Color = cursor.background(colors).to_color(); let base_color: Color = cursor.background(colors).to_color();
let alpha = ease(ease_in_quad, settings.vfx_opacity, 0.0, self.t) as u8; let alpha = ease(ease_in_quad, settings.vfx_opacity, 0.0, self.t) as u8;
let color = Color::from_argb(alpha, base_color.r(), base_color.g(), base_color.b()); let color = Color::from_argb(alpha, base_color.r(), base_color.g(), base_color.b());
paint.set_color(color); paint.set_color(color);
let size = 3 * font_size.1; let cursor_height = grid_renderer.font_dimensions.height;
let size = 3 * cursor_height;
let radius = self.t * size as f32; let radius = self.t * size as f32;
let hr = radius * 0.5; let hr = radius * 0.5;
let rect = Rect::from_xywh( let rect = Rect::from_xywh(
@ -160,12 +160,12 @@ impl CursorVfx for PointHighlight {
} }
HighlightMode::Ripple => { HighlightMode::Ripple => {
paint.set_style(Style::Stroke); paint.set_style(Style::Stroke);
paint.set_stroke_width(font_size.1 as f32 * 0.2); paint.set_stroke_width(cursor_height as f32 * 0.2);
canvas.draw_oval(&rect, &paint); canvas.draw_oval(&rect, &paint);
} }
HighlightMode::Wireframe => { HighlightMode::Wireframe => {
paint.set_style(Style::Stroke); paint.set_style(Style::Stroke);
paint.set_stroke_width(font_size.1 as f32 * 0.2); paint.set_stroke_width(cursor_height as f32 * 0.2);
canvas.draw_rect(&rect, &paint); canvas.draw_rect(&rect, &paint);
} }
} }
@ -218,7 +218,7 @@ impl CursorVfx for ParticleTrail {
&mut self, &mut self,
settings: &CursorSettings, settings: &CursorSettings,
current_cursor_dest: Point, current_cursor_dest: Point,
font_size: (u64, u64), cursor_dimensions: Point,
dt: f32, dt: f32,
) -> bool { ) -> bool {
// Update lifetimes and remove dead particles // Update lifetimes and remove dead particles
@ -246,7 +246,7 @@ impl CursorVfx for ParticleTrail {
let travel_distance = travel.length(); let travel_distance = travel.length();
// Increase amount of particles when cursor travels further // Increase amount of particles when cursor travels further
let particle_count = ((travel_distance / font_size.0 as f32).powf(1.5) let particle_count = ((travel_distance / cursor_dimensions.y as f32).powf(1.5)
* settings.vfx_particle_density * settings.vfx_particle_density
* 0.01) as usize; * 0.01) as usize;
@ -259,7 +259,7 @@ impl CursorVfx for ParticleTrail {
TrailMode::Railgun => { TrailMode::Railgun => {
let phase = t / std::f32::consts::PI let phase = t / std::f32::consts::PI
* settings.vfx_particle_phase * settings.vfx_particle_phase
* (travel_distance / font_size.0 as f32); * (travel_distance / cursor_dimensions.y as f32);
Point::new(phase.sin(), phase.cos()) * 2.0 * settings.vfx_particle_speed Point::new(phase.sin(), phase.cos()) * 2.0 * settings.vfx_particle_speed
} }
TrailMode::Torpedo => { TrailMode::Torpedo => {
@ -282,7 +282,7 @@ impl CursorVfx for ParticleTrail {
TrailMode::PixieDust | TrailMode::Torpedo => { TrailMode::PixieDust | TrailMode::Torpedo => {
prev_p prev_p
+ travel * self.rng.next_f32() + travel * self.rng.next_f32()
+ Point::new(0.0, font_size.1 as f32 * 0.5) + Point::new(0.0, cursor_dimensions.y as f32 * 0.5)
} }
}; };
@ -316,19 +316,20 @@ impl CursorVfx for ParticleTrail {
&self, &self,
settings: &CursorSettings, settings: &CursorSettings,
canvas: &mut Canvas, canvas: &mut Canvas,
grid_renderer: &mut GridRenderer,
cursor: &Cursor, cursor: &Cursor,
colors: &Colors,
font_size: (u64, u64),
) { ) {
let mut paint = Paint::new(skia_safe::colors::WHITE, None); let mut paint = Paint::new(skia_safe::colors::WHITE, None);
let font_dimensions = grid_renderer.font_dimensions;
match self.trail_mode { match self.trail_mode {
TrailMode::Torpedo | TrailMode::Railgun => { TrailMode::Torpedo | TrailMode::Railgun => {
paint.set_style(Style::Stroke); paint.set_style(Style::Stroke);
paint.set_stroke_width(font_size.1 as f32 * 0.2); paint.set_stroke_width(font_dimensions.height as f32 * 0.2);
} }
_ => {} _ => {}
} }
let colors = &grid_renderer.default_style.colors;
let base_color: Color = cursor.background(colors).to_color(); let base_color: Color = cursor.background(colors).to_color();
paint.set_blend_mode(BlendMode::SrcOver); paint.set_blend_mode(BlendMode::SrcOver);
@ -340,8 +341,10 @@ impl CursorVfx for ParticleTrail {
paint.set_color(color); paint.set_color(color);
let radius = match self.trail_mode { let radius = match self.trail_mode {
TrailMode::Torpedo | TrailMode::Railgun => font_size.0 as f32 * 0.5 * lifetime, TrailMode::Torpedo | TrailMode::Railgun => {
TrailMode::PixieDust => font_size.0 as f32 * 0.2, font_dimensions.width as f32 * 0.5 * lifetime
}
TrailMode::PixieDust => font_dimensions.width as f32 * 0.2,
}; };
let hr = radius * 0.5; let hr = radius * 0.5;

@ -6,12 +6,11 @@ use std::collections::HashMap;
// use neovide_derive::SettingGroup; // use neovide_derive::SettingGroup;
use skia_safe::{Canvas, Paint, Path, Point}; use skia_safe::{Canvas, Paint, Path, Point};
use super::RenderedWindow; use super::{GridRenderer, RenderedWindow};
use crate::bridge::EditorMode; use crate::bridge::EditorMode;
use crate::editor::{Colors, Cursor, CursorShape}; use crate::editor::{Cursor, CursorShape};
use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::renderer::animation_utils::*; use crate::renderer::animation_utils::*;
use crate::renderer::CachingShaper;
use crate::settings::{FromValue, SETTINGS}; use crate::settings::{FromValue, SETTINGS};
use blink::*; use blink::*;
@ -257,10 +256,8 @@ impl CursorRenderer {
pub fn draw( pub fn draw(
&mut self, &mut self,
default_colors: &Colors, grid_renderer: &mut GridRenderer,
(font_width, font_height): (u64, u64),
current_mode: &EditorMode, current_mode: &EditorMode,
shaper: &mut CachingShaper,
canvas: &mut Canvas, canvas: &mut Canvas,
dt: f32, dt: f32,
) { ) {
@ -277,19 +274,23 @@ impl CursorRenderer {
let character = self.cursor.character.clone(); let character = self.cursor.character.clone();
let font_width = match (self.cursor.double_width, &self.cursor.shape) { let mut cursor_width = grid_renderer.font_dimensions.width;
(true, CursorShape::Block) => font_width * 2, if self.cursor.double_width && self.cursor.shape == CursorShape::Block {
_ => font_width, cursor_width *= 2;
}; }
let font_dimensions: Point = (font_width as f32, font_height as f32).into(); let cursor_dimensions: Point = (
cursor_width as f32,
grid_renderer.font_dimensions.height as f32,
)
.into();
let in_insert_mode = matches!(current_mode, EditorMode::Insert); let in_insert_mode = matches!(current_mode, EditorMode::Insert);
let changed_to_from_cmdline = !matches!(self.previous_editor_mode, EditorMode::CmdLine) let changed_to_from_cmdline = !matches!(self.previous_editor_mode, EditorMode::CmdLine)
^ matches!(current_mode, EditorMode::CmdLine); ^ matches!(current_mode, EditorMode::CmdLine);
let center_destination = self.destination + font_dimensions * 0.5; let center_destination = self.destination + cursor_dimensions * 0.5;
let new_cursor = Some(self.cursor.shape.clone()); let new_cursor = Some(self.cursor.shape.clone());
if self.previous_cursor_shape != new_cursor { if self.previous_cursor_shape != new_cursor {
@ -315,7 +316,7 @@ impl CursorRenderer {
let corner_animating = corner.update( let corner_animating = corner.update(
&settings, &settings,
font_dimensions, cursor_dimensions,
center_destination, center_destination,
dt, dt,
immediate_movement, immediate_movement,
@ -325,7 +326,7 @@ impl CursorRenderer {
} }
let vfx_animating = if let Some(vfx) = self.cursor_vfx.as_mut() { let vfx_animating = if let Some(vfx) = self.cursor_vfx.as_mut() {
vfx.update(&settings, center_destination, (font_width, font_height), dt) vfx.update(&settings, center_destination, cursor_dimensions, dt)
} else { } else {
false false
}; };
@ -341,7 +342,11 @@ impl CursorRenderer {
if self.cursor.enabled && render { if self.cursor.enabled && render {
// Draw Background // Draw Background
paint.set_color(self.cursor.background(default_colors).to_color()); let background_color = self
.cursor
.background(&grid_renderer.default_style.colors)
.to_color();
paint.set_color(background_color);
// The cursor is made up of four points, so I create a path with each of the four // The cursor is made up of four points, so I create a path with each of the four
// corners. // corners.
@ -356,13 +361,19 @@ impl CursorRenderer {
canvas.draw_path(&path, &paint); canvas.draw_path(&path, &paint);
// Draw foreground // Draw foreground
paint.set_color(self.cursor.foreground(default_colors).to_color()); let foreground_color = self
.cursor
.foreground(&grid_renderer.default_style.colors)
.to_color();
paint.set_color(foreground_color);
canvas.save(); canvas.save();
canvas.clip_path(&path, None, Some(false)); canvas.clip_path(&path, None, Some(false));
let y_adjustment = shaper.y_adjustment(); let y_adjustment = grid_renderer.shaper.y_adjustment();
let blobs = &shaper.shape_cached(&[character], false, false); let blobs = &grid_renderer
.shaper
.shape_cached(&[character], false, false);
for blob in blobs.iter() { for blob in blobs.iter() {
canvas.draw_text_blob( canvas.draw_text_blob(
@ -375,13 +386,7 @@ impl CursorRenderer {
canvas.restore(); canvas.restore();
if let Some(vfx) = self.cursor_vfx.as_ref() { if let Some(vfx) = self.cursor_vfx.as_ref() {
vfx.render( vfx.render(&settings, canvas, grid_renderer, &self.cursor);
&settings,
canvas,
&self.cursor,
default_colors,
(font_width, font_height),
);
} }
} }
} }

@ -0,0 +1,185 @@
use std::sync::Arc;
use glutin::dpi::PhysicalSize;
use log::trace;
use skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect, HSV};
use super::{CachingShaper, RendererSettings};
use crate::editor::{Colors, Style};
use crate::settings::*;
use crate::utils::Dimensions;
pub struct GridRenderer {
pub shaper: CachingShaper,
pub paint: Paint,
pub default_style: Arc<Style>,
pub font_dimensions: Dimensions,
pub scale_factor: f64,
pub is_ready: bool,
}
impl GridRenderer {
pub fn new(scale_factor: f64) -> Self {
let mut shaper = CachingShaper::new(scale_factor as f32);
let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false);
let default_style = Arc::new(Style::new(Colors::new(
Some(colors::WHITE),
Some(colors::BLACK),
Some(colors::GREY),
)));
let font_dimensions: Dimensions = shaper.font_base_dimensions().into();
GridRenderer {
shaper,
paint,
default_style,
font_dimensions,
scale_factor,
is_ready: false,
}
}
/// Convert PhysicalSize to grid size
pub fn convert_physical_to_grid(&self, physical: PhysicalSize<u32>) -> Dimensions {
Dimensions::from(physical) / self.font_dimensions
}
/// Convert grid size to PhysicalSize
pub fn convert_grid_to_physical(&self, grid: Dimensions) -> PhysicalSize<u32> {
(grid * self.font_dimensions).into()
}
pub fn handle_scale_factor_update(&mut self, scale_factor: f64) {
self.shaper.update_scale_factor(scale_factor as f32);
self.update_font_dimensions();
}
pub fn update_font(&mut self, guifont_setting: &str) {
self.shaper.update_font(guifont_setting);
self.update_font_dimensions();
}
fn update_font_dimensions(&mut self) {
self.font_dimensions = self.shaper.font_base_dimensions().into();
self.is_ready = true;
trace!("Updated font dimensions: {:?}", self.font_dimensions,);
}
fn compute_text_region(&self, grid_position: (u64, u64), cell_width: u64) -> Rect {
let (x, y) = grid_position * self.font_dimensions;
let width = cell_width * self.font_dimensions.width;
let height = self.font_dimensions.height;
Rect::new(x as f32, y as f32, (x + width) as f32, (y + height) as f32)
}
pub fn get_default_background(&self) -> Color {
self.default_style.colors.background.unwrap().to_color()
}
pub fn draw_background(
&mut self,
canvas: &mut Canvas,
grid_position: (u64, u64),
cell_width: u64,
style: &Option<Arc<Style>>,
) {
self.paint.set_blend_mode(BlendMode::Src);
let region = self.compute_text_region(grid_position, cell_width);
let style = style.as_ref().unwrap_or(&self.default_style);
if SETTINGS.get::<RendererSettings>().debug_renderer {
let random_hsv: HSV = (rand::random::<f32>() * 360.0, 0.3, 0.3).into();
let random_color = random_hsv.to_color(255);
self.paint.set_color(random_color);
} else {
self.paint
.set_color(style.background(&self.default_style.colors).to_color());
}
canvas.draw_rect(region, &self.paint);
}
pub fn draw_foreground(
&mut self,
canvas: &mut Canvas,
cells: &[String],
grid_position: (u64, u64),
cell_width: u64,
style: &Option<Arc<Style>>,
) {
let (x, y) = grid_position * self.font_dimensions;
let width = cell_width * self.font_dimensions.width;
let style = style.as_ref().unwrap_or(&self.default_style);
canvas.save();
let region = self.compute_text_region(grid_position, cell_width);
canvas.clip_rect(region, None, Some(false));
if style.underline || style.undercurl {
let line_position = self.shaper.underline_position();
let stroke_width = self.shaper.current_size() / 10.0;
self.paint
.set_color(style.special(&self.default_style.colors).to_color());
self.paint.set_stroke_width(stroke_width);
if style.undercurl {
self.paint.set_path_effect(dash_path_effect::new(
&[stroke_width * 2.0, stroke_width * 2.0],
0.0,
));
} else {
self.paint.set_path_effect(None);
}
canvas.draw_line(
(
x as f32,
(y - line_position + self.font_dimensions.height) as f32,
),
(
(x + width) as f32,
(y - line_position + self.font_dimensions.height) as f32,
),
&self.paint,
);
}
let y_adjustment = self.shaper.y_adjustment();
if SETTINGS.get::<RendererSettings>().debug_renderer {
let random_hsv: HSV = (rand::random::<f32>() * 360.0, 1.0, 1.0).into();
let random_color = random_hsv.to_color(255);
self.paint.set_color(random_color);
} else {
self.paint
.set_color(style.foreground(&self.default_style.colors).to_color());
}
self.paint.set_anti_alias(false);
for blob in self
.shaper
.shape_cached(cells, style.bold, style.italic)
.iter()
{
canvas.draw_text_blob(blob, (x as f32, (y + y_adjustment) as f32), &self.paint);
}
if style.strikethrough {
let line_position = region.center_y();
self.paint
.set_color(style.special(&self.default_style.colors).to_color());
canvas.draw_line(
(x as f32, line_position),
((x + width) as f32, line_position),
&self.paint,
);
}
canvas.restore();
}
}

@ -1,22 +1,22 @@
pub mod animation_utils; pub mod animation_utils;
pub mod cursor_renderer; pub mod cursor_renderer;
mod fonts; mod fonts;
pub mod grid_renderer;
mod rendered_window; mod rendered_window;
use std::collections::HashMap; use std::collections::{hash_map::Entry, HashMap};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use std::sync::Arc; use std::sync::Arc;
use glutin::dpi::PhysicalSize; use log::error;
use log::{error, trace}; use skia_safe::Canvas;
use skia_safe::{colors, dash_path_effect, BlendMode, Canvas, Color, Paint, Rect, HSV};
use crate::bridge::EditorMode; use crate::bridge::EditorMode;
use crate::editor::{Colors, DrawCommand, Style, WindowDrawCommand}; use crate::editor::{DrawCommand, WindowDrawCommand};
use crate::settings::*; use crate::settings::*;
use crate::utils::Dimensions;
use cursor_renderer::CursorRenderer; use cursor_renderer::CursorRenderer;
pub use fonts::caching_shaper::CachingShaper; pub use fonts::caching_shaper::CachingShaper;
pub use grid_renderer::GridRenderer;
pub use rendered_window::{RenderedWindow, WindowDrawDetails}; pub use rendered_window::{RenderedWindow, WindowDrawDetails};
#[derive(SettingGroup, Clone)] #[derive(SettingGroup, Clone)]
@ -41,238 +41,35 @@ impl Default for RendererSettings {
} }
pub struct Renderer { pub struct Renderer {
rendered_windows: HashMap<u64, RenderedWindow>,
cursor_renderer: CursorRenderer, cursor_renderer: CursorRenderer,
pub grid_renderer: GridRenderer,
current_mode: EditorMode, current_mode: EditorMode,
pub paint: Paint,
pub shaper: CachingShaper, rendered_windows: HashMap<u64, RenderedWindow>,
pub default_style: Arc<Style>,
pub font_dimensions: Dimensions,
pub window_regions: Vec<WindowDrawDetails>, pub window_regions: Vec<WindowDrawDetails>,
pub batched_draw_command_receiver: Receiver<Vec<DrawCommand>>, pub batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
pub is_ready: bool,
} }
impl Renderer { impl Renderer {
pub fn new( pub fn new(
batched_draw_command_receiver: Receiver<Vec<DrawCommand>>, batched_draw_command_receiver: Receiver<Vec<DrawCommand>>,
scale_factor: f64, scale_factor: f64,
) -> Renderer { ) -> Self {
let rendered_windows = HashMap::new();
let cursor_renderer = CursorRenderer::new(); let cursor_renderer = CursorRenderer::new();
let grid_renderer = GridRenderer::new(scale_factor);
let current_mode = EditorMode::Unknown(String::from("")); let current_mode = EditorMode::Unknown(String::from(""));
let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false); let rendered_windows = HashMap::new();
let mut shaper = CachingShaper::new(scale_factor as f32);
let font_dimensions: Dimensions = shaper.font_base_dimensions().into();
let default_style = Arc::new(Style::new(Colors::new(
Some(colors::WHITE),
Some(colors::BLACK),
Some(colors::GREY),
)));
let window_regions = Vec::new(); let window_regions = Vec::new();
Renderer { Renderer {
rendered_windows, rendered_windows,
cursor_renderer, cursor_renderer,
grid_renderer,
current_mode, current_mode,
paint,
shaper,
default_style,
font_dimensions,
window_regions, window_regions,
batched_draw_command_receiver, batched_draw_command_receiver,
is_ready: false,
}
}
/// Convert PhysicalSize to grid size
pub fn convert_physical_to_grid(&self, physical: PhysicalSize<u32>) -> Dimensions {
Dimensions::from(physical) / self.font_dimensions
}
/// Convert grid size to PhysicalSize
pub fn convert_grid_to_physical(&self, grid: Dimensions) -> PhysicalSize<u32> {
(grid * self.font_dimensions).into()
}
pub fn handle_scale_factor_update(&mut self, scale_factor: f64) {
self.shaper.update_scale_factor(scale_factor as f32);
self.update_font_dimensions();
}
fn update_font(&mut self, guifont_setting: &str) {
self.shaper.update_font(guifont_setting);
self.update_font_dimensions();
}
fn update_font_dimensions(&mut self) {
self.font_dimensions = self.shaper.font_base_dimensions().into();
self.is_ready = true;
trace!("Updated font dimensions: {:?}", self.font_dimensions,);
}
fn compute_text_region(&self, grid_position: (u64, u64), cell_width: u64) -> Rect {
let (x, y) = grid_position * self.font_dimensions;
let width = cell_width * self.font_dimensions.width;
let height = self.font_dimensions.height;
Rect::new(x as f32, y as f32, (x + width) as f32, (y + height) as f32)
}
fn get_default_background(&self) -> Color {
self.default_style.colors.background.unwrap().to_color()
}
fn draw_background(
&mut self,
canvas: &mut Canvas,
grid_position: (u64, u64),
cell_width: u64,
style: &Option<Arc<Style>>,
) {
self.paint.set_blend_mode(BlendMode::Src);
let region = self.compute_text_region(grid_position, cell_width);
let style = style.as_ref().unwrap_or(&self.default_style);
if SETTINGS.get::<RendererSettings>().debug_renderer {
let random_hsv: HSV = (rand::random::<f32>() * 360.0, 0.3, 0.3).into();
let random_color = random_hsv.to_color(255);
self.paint.set_color(random_color);
} else {
self.paint
.set_color(style.background(&self.default_style.colors).to_color());
}
canvas.draw_rect(region, &self.paint);
}
fn draw_foreground(
&mut self,
canvas: &mut Canvas,
cells: &[String],
grid_position: (u64, u64),
cell_width: u64,
style: &Option<Arc<Style>>,
) {
let (x, y) = grid_position * self.font_dimensions;
let width = cell_width * self.font_dimensions.width;
let style = style.as_ref().unwrap_or(&self.default_style);
canvas.save();
let region = self.compute_text_region(grid_position, cell_width);
canvas.clip_rect(region, None, Some(false));
if style.underline || style.undercurl {
let line_position = self.shaper.underline_position();
let stroke_width = self.shaper.current_size() / 10.0;
self.paint
.set_color(style.special(&self.default_style.colors).to_color());
self.paint.set_stroke_width(stroke_width);
if style.undercurl {
self.paint.set_path_effect(dash_path_effect::new(
&[stroke_width * 2.0, stroke_width * 2.0],
0.0,
));
} else {
self.paint.set_path_effect(None);
}
canvas.draw_line(
(
x as f32,
(y - line_position + self.font_dimensions.height) as f32,
),
(
(x + width) as f32,
(y - line_position + self.font_dimensions.height) as f32,
),
&self.paint,
);
}
let y_adjustment = self.shaper.y_adjustment();
if SETTINGS.get::<RendererSettings>().debug_renderer {
let random_hsv: HSV = (rand::random::<f32>() * 360.0, 1.0, 1.0).into();
let random_color = random_hsv.to_color(255);
self.paint.set_color(random_color);
} else {
self.paint
.set_color(style.foreground(&self.default_style.colors).to_color());
}
self.paint.set_anti_alias(false);
for blob in self
.shaper
.shape_cached(cells, style.bold, style.italic)
.iter()
{
canvas.draw_text_blob(blob, (x as f32, (y + y_adjustment) as f32), &self.paint);
}
if style.strikethrough {
let line_position = region.center_y();
self.paint
.set_color(style.special(&self.default_style.colors).to_color());
canvas.draw_line(
(x as f32, line_position),
((x + width) as f32, line_position),
&self.paint,
);
}
canvas.restore();
}
fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) {
match draw_command {
DrawCommand::Window {
grid_id,
command: WindowDrawCommand::Close,
} => {
self.rendered_windows.remove(&grid_id);
}
DrawCommand::Window { grid_id, command } => {
if let Some(rendered_window) = self.rendered_windows.remove(&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_position: (grid_left, grid_top),
grid_size: (width, height),
..
} = command
{
let new_window = RenderedWindow::new(
root_canvas,
self,
grid_id,
(grid_left as f32, grid_top as f32).into(),
(width, height).into(),
);
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) => {
self.update_font(&new_font);
}
DrawCommand::DefaultStyleChanged(new_style) => {
self.default_style = Arc::new(new_style);
}
DrawCommand::ModeChanged(new_mode) => {
self.current_mode = new_mode;
}
_ => {}
} }
} }
@ -297,17 +94,18 @@ impl Renderer {
self.handle_draw_command(root_canvas, draw_command); self.handle_draw_command(root_canvas, draw_command);
} }
root_canvas.clear(self.default_style.colors.background.unwrap().to_color()); let default_background = self.grid_renderer.get_default_background();
let font_dimensions = self.grid_renderer.font_dimensions;
root_canvas.clear(default_background);
root_canvas.save(); root_canvas.save();
root_canvas.reset_matrix(); root_canvas.reset_matrix();
if let Some(root_window) = self.rendered_windows.get(&1) { if let Some(root_window) = self.rendered_windows.get(&1) {
let clip_rect = root_window.pixel_region(self.font_dimensions); let clip_rect = root_window.pixel_region(font_dimensions);
root_canvas.clip_rect(&clip_rect, None, Some(false)); root_canvas.clip_rect(&clip_rect, None, Some(false));
} }
let default_background = self.get_default_background();
let windows: Vec<&mut RenderedWindow> = { let windows: Vec<&mut RenderedWindow> = {
let (mut root_windows, mut floating_windows): ( let (mut root_windows, mut floating_windows): (
Vec<&mut RenderedWindow>, Vec<&mut RenderedWindow>,
@ -335,7 +133,6 @@ impl Renderer {
}; };
let settings = SETTINGS.get::<RendererSettings>(); let settings = SETTINGS.get::<RendererSettings>();
let font_dimensions = self.font_dimensions;
self.window_regions = windows self.window_regions = windows
.into_iter() .into_iter()
.map(|window| { .map(|window| {
@ -353,17 +150,63 @@ impl Renderer {
self.cursor_renderer self.cursor_renderer
.update_cursor_destination(font_dimensions.into(), windows); .update_cursor_destination(font_dimensions.into(), windows);
self.cursor_renderer.draw( self.cursor_renderer
&self.default_style.colors, .draw(&mut self.grid_renderer, &self.current_mode, root_canvas, dt);
font_dimensions.into(),
&self.current_mode,
&mut self.shaper,
root_canvas,
dt,
);
root_canvas.restore(); root_canvas.restore();
font_changed font_changed
} }
fn handle_draw_command(&mut self, root_canvas: &mut Canvas, draw_command: DrawCommand) {
match draw_command {
DrawCommand::Window {
grid_id,
command: WindowDrawCommand::Close,
} => {
self.rendered_windows.remove(&grid_id);
}
DrawCommand::Window { grid_id, command } => {
match self.rendered_windows.entry(grid_id) {
Entry::Occupied(mut occupied_entry) => {
let rendered_window = occupied_entry.get_mut();
rendered_window
.handle_window_draw_command(&mut self.grid_renderer, command);
}
Entry::Vacant(vacant_entry) => {
if let WindowDrawCommand::Position {
grid_position: (grid_left, grid_top),
grid_size: (width, height),
..
} = command
{
let new_window = RenderedWindow::new(
root_canvas,
&self.grid_renderer,
grid_id,
(grid_left as f32, grid_top as f32).into(),
(width, height).into(),
);
vacant_entry.insert(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) => {
self.grid_renderer.update_font(&new_font);
}
DrawCommand::DefaultStyleChanged(new_style) => {
self.grid_renderer.default_style = Arc::new(new_style);
}
DrawCommand::ModeChanged(new_mode) => {
self.current_mode = new_mode;
}
_ => {}
}
}
} }

@ -8,7 +8,7 @@ use skia_safe::{
}; };
use super::animation_utils::*; use super::animation_utils::*;
use super::{Renderer, RendererSettings}; use super::{GridRenderer, RendererSettings};
use crate::editor::WindowDrawCommand; use crate::editor::WindowDrawCommand;
use crate::redraw_scheduler::REDRAW_SCHEDULER; use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::utils::Dimensions; use crate::utils::Dimensions;
@ -40,14 +40,16 @@ fn build_window_surface(parent_canvas: &mut Canvas, pixel_size: (i32, i32)) -> S
fn build_window_surface_with_grid_size( fn build_window_surface_with_grid_size(
parent_canvas: &mut Canvas, parent_canvas: &mut Canvas,
renderer: &Renderer, grid_renderer: &GridRenderer,
grid_size: Dimensions, grid_size: Dimensions,
) -> Surface { ) -> Surface {
let mut surface = let mut surface = build_window_surface(
build_window_surface(parent_canvas, (grid_size * renderer.font_dimensions).into()); parent_canvas,
(grid_size * grid_renderer.font_dimensions).into(),
);
let canvas = surface.canvas(); let canvas = surface.canvas();
canvas.clear(renderer.get_default_background()); canvas.clear(grid_renderer.get_default_background());
surface surface
} }
@ -64,11 +66,11 @@ pub struct LocatedSurface {
impl LocatedSurface { impl LocatedSurface {
fn new( fn new(
parent_canvas: &mut Canvas, parent_canvas: &mut Canvas,
renderer: &Renderer, grid_renderer: &GridRenderer,
grid_size: Dimensions, grid_size: Dimensions,
top_line: u64, top_line: u64,
) -> LocatedSurface { ) -> LocatedSurface {
let surface = build_window_surface_with_grid_size(parent_canvas, renderer, grid_size); let surface = build_window_surface_with_grid_size(parent_canvas, grid_renderer, grid_size);
LocatedSurface { surface, top_line } LocatedSurface { surface, top_line }
} }
@ -113,12 +115,12 @@ pub struct WindowDrawDetails {
impl RenderedWindow { impl RenderedWindow {
pub fn new( pub fn new(
parent_canvas: &mut Canvas, parent_canvas: &mut Canvas,
renderer: &Renderer, grid_renderer: &GridRenderer,
id: u64, id: u64,
grid_position: Point, grid_position: Point,
grid_size: Dimensions, grid_size: Dimensions,
) -> RenderedWindow { ) -> RenderedWindow {
let current_surface = LocatedSurface::new(parent_canvas, renderer, grid_size, 0); let current_surface = LocatedSurface::new(parent_canvas, grid_renderer, grid_size, 0);
RenderedWindow { RenderedWindow {
snapshots: VecDeque::new(), snapshots: VecDeque::new(),
@ -279,10 +281,10 @@ impl RenderedWindow {
} }
pub fn handle_window_draw_command( pub fn handle_window_draw_command(
mut self, &mut self,
renderer: &mut Renderer, grid_renderer: &mut GridRenderer,
draw_command: WindowDrawCommand, draw_command: WindowDrawCommand,
) -> Self { ) {
match draw_command { match draw_command {
WindowDrawCommand::Position { WindowDrawCommand::Position {
grid_position: (grid_left, grid_top), grid_position: (grid_left, grid_top),
@ -308,19 +310,19 @@ impl RenderedWindow {
} }
if self.grid_size != new_grid_size { if self.grid_size != new_grid_size {
let mut old_surface = self.current_surface.surface; let mut new_surface = build_window_surface_with_grid_size(
self.current_surface.surface = build_window_surface_with_grid_size( self.current_surface.surface.canvas(),
old_surface.canvas(), grid_renderer,
renderer,
new_grid_size, new_grid_size,
); );
old_surface.draw( self.current_surface.surface.draw(
self.current_surface.surface.canvas(), new_surface.canvas(),
(0.0, 0.0), (0.0, 0.0),
SamplingOptions::default(), SamplingOptions::default(),
None, None,
); );
self.current_surface.surface = new_surface;
self.grid_size = new_grid_size; self.grid_size = new_grid_size;
} }
@ -344,8 +346,8 @@ impl RenderedWindow {
let canvas = self.current_surface.surface.canvas(); let canvas = self.current_surface.surface.canvas();
canvas.save(); canvas.save();
renderer.draw_background(canvas, grid_position, width, &style); grid_renderer.draw_background(canvas, grid_position, width, &style);
renderer.draw_foreground(canvas, &cells, grid_position, width, &style); grid_renderer.draw_foreground(canvas, &cells, grid_position, width, &style);
canvas.restore(); canvas.restore();
} }
WindowDrawCommand::Scroll { WindowDrawCommand::Scroll {
@ -359,7 +361,7 @@ impl RenderedWindow {
let Dimensions { let Dimensions {
width: font_width, width: font_width,
height: font_height, height: font_height,
} = renderer.font_dimensions; } = grid_renderer.font_dimensions;
let scrolled_region = Rect::new( let scrolled_region = Rect::new(
(left * font_width) as f32, (left * font_width) as f32,
(top * font_height) as f32, (top * font_height) as f32,
@ -383,7 +385,7 @@ impl RenderedWindow {
snapshot, snapshot,
Some((&scrolled_region, SrcRectConstraint::Fast)), Some((&scrolled_region, SrcRectConstraint::Fast)),
translated_region, translated_region,
&renderer.paint, &grid_renderer.paint,
); );
canvas.restore(); canvas.restore();
@ -391,7 +393,7 @@ impl RenderedWindow {
WindowDrawCommand::Clear => { WindowDrawCommand::Clear => {
self.current_surface.surface = build_window_surface_with_grid_size( self.current_surface.surface = build_window_surface_with_grid_size(
self.current_surface.surface.canvas(), self.current_surface.surface.canvas(),
renderer, grid_renderer,
self.grid_size, self.grid_size,
); );
@ -424,7 +426,5 @@ impl RenderedWindow {
} }
_ => {} _ => {}
}; };
self
} }
} }

@ -22,6 +22,9 @@ macro_rules! impl_from_tuple_to_dimensions {
}; };
} }
impl_from_tuple_to_dimensions!(u64);
impl_from_tuple_to_dimensions!(f32);
macro_rules! impl_from_dimensions_to_tuple { macro_rules! impl_from_dimensions_to_tuple {
($type:ty) => { ($type:ty) => {
impl From<Dimensions> for ($type, $type) { impl From<Dimensions> for ($type, $type) {
@ -32,9 +35,6 @@ macro_rules! impl_from_dimensions_to_tuple {
}; };
} }
impl_from_tuple_to_dimensions!(u64);
impl_from_tuple_to_dimensions!(f32);
impl_from_dimensions_to_tuple!(u64); impl_from_dimensions_to_tuple!(u64);
impl_from_dimensions_to_tuple!(u32); impl_from_dimensions_to_tuple!(u32);
impl_from_dimensions_to_tuple!(i32); impl_from_dimensions_to_tuple!(i32);

@ -171,13 +171,13 @@ impl GlutinWindowWrapper {
} }
// Wait until fonts are loaded, so we can set proper window size. // Wait until fonts are loaded, so we can set proper window size.
if !self.renderer.is_ready { if !self.renderer.grid_renderer.is_ready {
return; return;
} }
if self.saved_grid_size.is_none() && !window.is_maximized() { if self.saved_grid_size.is_none() && !window.is_maximized() {
let size = SETTINGS.get::<CmdLineSettings>().geometry; let size = SETTINGS.get::<CmdLineSettings>().geometry;
window.set_inner_size(self.renderer.convert_grid_to_physical(size)); window.set_inner_size(self.renderer.grid_renderer.convert_grid_to_physical(size));
self.saved_grid_size = Some(size); self.saved_grid_size = Some(size);
// Font change at startup is ignored, so grid size (and startup screen) could be preserved. // Font change at startup is ignored, so grid size (and startup screen) could be preserved.
font_changed = false; font_changed = false;
@ -193,7 +193,10 @@ impl GlutinWindowWrapper {
} }
fn handle_new_grid_size(&mut self, new_size: PhysicalSize<u32>) { fn handle_new_grid_size(&mut self, new_size: PhysicalSize<u32>) {
let grid_size = self.renderer.convert_physical_to_grid(new_size); let grid_size = self
.renderer
.grid_renderer
.convert_physical_to_grid(new_size);
if self.saved_grid_size == Some(grid_size) { if self.saved_grid_size == Some(grid_size) {
trace!("Grid matched saved size, skip update."); trace!("Grid matched saved size, skip update.");
return; return;
@ -208,7 +211,9 @@ impl GlutinWindowWrapper {
} }
fn handle_scale_factor_update(&mut self, scale_factor: f64) { fn handle_scale_factor_update(&mut self, scale_factor: f64) {
self.renderer.handle_scale_factor_update(scale_factor); self.renderer
.grid_renderer
.handle_scale_factor_update(scale_factor);
} }
} }
@ -265,7 +270,7 @@ pub fn create_window(
log::info!( log::info!(
"window created (scale_factor: {:.4}, font_dimensions: {:?})", "window created (scale_factor: {:.4}, font_dimensions: {:?})",
scale_factor, scale_factor,
renderer.font_dimensions, renderer.grid_renderer.font_dimensions,
); );
let mut window_wrapper = GlutinWindowWrapper { let mut window_wrapper = GlutinWindowWrapper {

@ -113,18 +113,26 @@ impl MouseManager {
let global_bounds = relevant_window_details let global_bounds = relevant_window_details
.map(|details| details.region) .map(|details| details.region)
.unwrap_or_else(|| Rect::from_wh(size.width as f32, size.height as f32)); .unwrap_or_else(|| Rect::from_wh(size.width as f32, size.height as f32));
let clamped_position = let clamped_position = clamp_position(
clamp_position(position, global_bounds, renderer.font_dimensions.into()); position,
global_bounds,
renderer.grid_renderer.font_dimensions.into(),
);
self.position = to_grid_coords(clamped_position, renderer.font_dimensions.into()); self.position = to_grid_coords(
clamped_position,
renderer.grid_renderer.font_dimensions.into(),
);
if let Some(relevant_window_details) = relevant_window_details { if let Some(relevant_window_details) = relevant_window_details {
let relative_position = PhysicalPosition::new( let relative_position = PhysicalPosition::new(
clamped_position.x - relevant_window_details.region.left, clamped_position.x - relevant_window_details.region.left,
clamped_position.y - relevant_window_details.region.top, clamped_position.y - relevant_window_details.region.top,
); );
self.relative_position = self.relative_position = to_grid_coords(
to_grid_coords(relative_position, renderer.font_dimensions.into()); relative_position,
renderer.grid_renderer.font_dimensions.into(),
);
let previous_position = self.drag_position; let previous_position = self.drag_position;
// Until https://github.com/neovim/neovim/pull/12667 is merged, we have to special // Until https://github.com/neovim/neovim/pull/12667 is merged, we have to special
@ -288,7 +296,7 @@ impl MouseManager {
}, },
.. ..
} => self.handle_pixel_scroll( } => self.handle_pixel_scroll(
renderer.font_dimensions.into(), renderer.grid_renderer.font_dimensions.into(),
(delta.x as f32, delta.y as f32), (delta.x as f32, delta.y as f32),
), ),
Event::WindowEvent { Event::WindowEvent {

Loading…
Cancel
Save