progress toward smeared cursor

macos-click-through
keith 5 years ago
parent 2b2beb4e10
commit 59601b7d71

@ -1,63 +1,46 @@
use std::cmp::Ordering; use std::sync::{Arc, Mutex};
use skulpin::skia_safe::{Canvas, Point}; use skulpin::skia_safe::{Canvas, Paint, Point};
use skulpin::skia_safe::canvas::PointMode;
use crate::editor::Cursor; use crate::renderer::{CachingShaper, FontLookup};
use crate::editor::{Colors, Cursor, CursorShape, Editor};
const motion_percentages: [f32; 4] = [0.4, 0.5, 0.6, 0.7]; const average_motion_percentage: f32 = 0.5;
const motion_percentage_spread: f32 = 0.3;
#[derive(new, Eq, PartialEq, Clone)] const bar_width: f32 = 1.0 / 8.0;
struct Corner {
pub x: f32,
pub y: f32,
pub center_x: f32, const standard_corners: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)];
pub center_y: f32,
pub position_x: f32, #[derive(Debug, Clone)]
pub position_y: f32 pub struct Corner {
pub current_position: Point,
pub relative_position: Point,
} }
impl Corner { impl Corner {
pub fn new(position_x: f32, position_y: f32) -> Corner { pub fn new(relative_position: Point) -> Corner {
Corner { Corner {
x: 0, y: 0, current_position: Point::new(0.0, 0.0),
center_x: 0, center_y: 0, relative_position
position_x, position_y
} }
} }
pub fn remaining_distance(&self) -> f32 { pub fn update(&mut self, font_dimensions: Point, destination: Point) -> bool {
let dx = self.center_x - x; let relative_scaled_position: Point =
let dy = self.center_y - y; (self.relative_position.x * font_dimensions.x, self.relative_position.y * font_dimensions.y).into();
let corner_destination = destination + relative_scaled_position;
(dx * dx + dy * dy).sqrt() let delta = corner_destination - self.current_position;
}
pub fn update(&mut self, motion_percentage: f32) { let motion_scale = delta.dot(relative_scaled_position) / delta.length() / font_dimensions.length();
let delta_x = self.dest_x - self.x; let motion_percentage = motion_scale * motion_percentage_spread + average_motion_percentage;
let delta_y = self.dest_y - self.y;
self.x += delta_x * motion_percentage; let delta = corner_destination - self.current_position;
self.y += delta_y * motion_percentage; self.current_position += delta * motion_percentage;
}
}
impl Ord for Corner {
fn cmp(&self, other: &Self) -> Ordering {
self.remaining_distance().cmp(&other.remaining_distance())
}
}
impl PartialOrd for Corner {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Into<Point> for Corner { delta.length() > 0.001
fn into(self) -> Point {
(self.x, self.y).into()
} }
} }
@ -67,24 +50,75 @@ pub struct CursorRenderer {
impl CursorRenderer { impl CursorRenderer {
pub fn new() -> CursorRenderer { pub fn new() -> CursorRenderer {
CursorRenderer { let mut renderer = CursorRenderer {
corners: vec![Corner::new(-0.5, -0.5), Corner::new(0.5, -0.5), Corner::new(0.5, 0.5), Corner::new(-0.5, 0.5)] corners: vec![Corner::new((0.0, 0.0).into()); 4]
} };
} renderer.set_cursor_shape(CursorShape::Block);
renderer
pub fn update(&mut self, destination: (u64, u64), font_width: f32, font_height: f32) { }
let (grid_x, grid_y) = destination;
let mut center_x = grid_x as f32 * font_width + font_width / 2.0; fn set_cursor_shape(&mut self, cursor_shape: CursorShape) {
let mut center_y = grid_y as f32 * font_height + font_height / 2.0; self.corners = self.corners
.clone()
let mut corners: Vec<&mut Corner> = self.corners.iter_mut().collect(); .into_iter().enumerate()
corners.sort(); .map(|(i, corner)| {
for (&mut corner, motion_percentage) in corners.iter().zip(motion_percentages.iter()) { let (x, y) = standard_corners[i];
corner.update(motion_percentage); Corner {
} relative_position: match cursor_shape {
} CursorShape::Block => (x, y).into(),
CursorShape::Vertical => ((x + 0.5) * bar_width - 0.5, y).into(),
pub fn draw(&self, &mut canvas: Canvas, paint: &Paint) { CursorShape::Horizontal => (x, (y + 0.5) * bar_width - 0.5).into()
canvas.draw_points(PointMode::Polygon, canvas.as_slice().map(|corner| corner.into::<Point>()).as_slice(), paint); },
.. corner
}
})
.collect::<Vec<Corner>>();
}
pub fn draw(&mut self,
cursor: Cursor, default_colors: &Colors,
font_width: f32, font_height: f32,
paint: &mut Paint, editor: Arc<Mutex<Editor>>,
shaper: &mut CachingShaper, fonts_lookup: &mut FontLookup,
canvas: &mut Canvas) -> bool {
let (grid_x, grid_y) = cursor.position;
let font_dimensions: Point = (font_width, font_height).into();
let center_destination: Point = (
grid_x as f32 * (font_width * 1.5),
grid_y as f32 * (font_height * 1.5)
).into();
let mut animating = false;
for corner in self.corners.iter_mut() {
let corner_animating = corner.update(font_dimensions, center_destination);
animating = animating || corner_animating;
}
if cursor.enabled {
// Draw Background
paint.set_color(cursor.background(&default_colors).to_color());
canvas.draw_points(PointMode::Polygon, &self.corners.iter().map(|corner| corner.current_position).collect::<Vec<_>>(), &paint);
let mut position_sum: Point = (0.0, 0.0).into();
for i in 0..4 {
position_sum += self.corners[i].current_position;
}
let Point { x: cursor_x, y: cursor_y } = position_sum * (1.0 / 4.0);
// Draw foreground
if let CursorShape::Block = cursor.shape {
let (cursor_grid_y, cursor_grid_x) = cursor.position;
paint.set_color(cursor.foreground(&default_colors).to_color());
let editor = editor.lock().unwrap();
let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone()
.map(|(character, _)| character)
.unwrap_or(' ');
canvas.draw_text_blob(
shaper.shape_cached(character.to_string(), &fonts_lookup.size(1).normal),
(cursor_x, cursor_y), &paint);
}
}
animating
} }
} }

@ -5,15 +5,17 @@ use skulpin::skia_safe::{Canvas, Paint, Surface, Budgeted, Rect, Typeface, Font,
use skulpin::skia_safe::gpu::SurfaceOrigin; use skulpin::skia_safe::gpu::SurfaceOrigin;
mod caching_shaper; mod caching_shaper;
mod cursor_renderer;
use caching_shaper::CachingShaper; pub use caching_shaper::CachingShaper;
use crate::editor::{Editor, CursorShape, Style, Colors}; use cursor_renderer::CursorRenderer;
use crate::editor::{Editor, Style, Colors};
const FONT_NAME: &str = "Delugia Nerd Font"; const FONT_NAME: &str = "Delugia Nerd Font";
const FONT_SIZE: f32 = 14.0; const FONT_SIZE: f32 = 14.0;
struct Fonts { pub struct Fonts {
pub name: String, pub name: String,
pub size: f32, pub size: f32,
pub normal: Font, pub normal: Font,
@ -52,7 +54,7 @@ impl Fonts {
} }
} }
struct FontLookup { pub struct FontLookup {
pub name: String, pub name: String,
pub base_size: f32, pub base_size: f32,
pub loaded_fonts: HashMap<u16, Fonts> pub loaded_fonts: HashMap<u16, Fonts>
@ -92,7 +94,7 @@ pub struct Renderer {
pub font_width: f32, pub font_width: f32,
pub font_height: f32, pub font_height: f32,
cursor_pos: (f32, f32), cursor_renderer: CursorRenderer,
} }
impl Renderer { impl Renderer {
@ -108,9 +110,9 @@ impl Renderer {
let font_width = bounds.width(); let font_width = bounds.width();
let (_, metrics) = base_fonts.normal.metrics(); let (_, metrics) = base_fonts.normal.metrics();
let font_height = metrics.descent - metrics.ascent; let font_height = metrics.descent - metrics.ascent;
let cursor_pos = (0.0, 0.0); let cursor_renderer = CursorRenderer::new();
Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_pos } Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer }
} }
fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option<Style>, default_colors: &Colors) { fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option<Style>, default_colors: &Colors) {
@ -193,42 +195,13 @@ impl Renderer {
self.surface = Some(surface); self.surface = Some(surface);
let (cursor_grid_x, cursor_grid_y) = cursor.position; let cursor_animating = self.cursor_renderer.draw(
let target_cursor_x = cursor_grid_x as f32 * self.font_width; cursor, &default_colors,
let target_cursor_y = cursor_grid_y as f32 * self.font_height; self.font_width, self.font_height,
let (previous_cursor_x, previous_cursor_y) = self.cursor_pos; &mut self.paint, self.editor.clone(),
&mut self.shaper, &mut self.fonts_lookup,
let delta_cursor_x = target_cursor_x - previous_cursor_x; gpu_canvas);
let delta_cursor_y = target_cursor_y - previous_cursor_y;
let cursor_x = delta_cursor_x * 0.5 + previous_cursor_x;
let cursor_y = delta_cursor_y * 0.5 + previous_cursor_y;
self.cursor_pos = (cursor_x, cursor_y);
if cursor.enabled {
let cursor_width = match cursor.shape {
CursorShape::Vertical => self.font_width / 8.0,
CursorShape::Horizontal | CursorShape::Block => self.font_width
};
let cursor_height = match cursor.shape {
CursorShape::Horizontal => self.font_width / 8.0,
CursorShape::Vertical | CursorShape::Block => self.font_height
};
let cursor_region = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height);
self.paint.set_color(cursor.background(&default_colors).to_color());
gpu_canvas.draw_rect(cursor_region, &self.paint);
if let CursorShape::Block = cursor.shape {
self.paint.set_color(cursor.foreground(&default_colors).to_color());
let editor = self.editor.lock().unwrap();
let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone()
.map(|(character, _)| character)
.unwrap_or(' ');
gpu_canvas.draw_text_blob(
self.shaper.shape_cached(character.to_string(), &self.fonts_lookup.size(1).normal),
(cursor_x, cursor_y), &self.paint);
}
}
draw_commands.len() > 0 || delta_cursor_x.abs() > 0.001 || delta_cursor_y.abs() > 0.001 draw_commands.len() > 0 || cursor_animating
} }
} }

Loading…
Cancel
Save