support cursor blinking

macos-click-through
Keith Simmons 5 years ago
parent 35093e6472
commit ed28b14596

@ -28,14 +28,23 @@ pub struct CursorMode {
#[new(default)] #[new(default)]
pub style_id: Option<u64>, pub style_id: Option<u64>,
#[new(default)] #[new(default)]
pub cell_percentage: Option<f32> pub cell_percentage: Option<f32>,
#[new(default)]
pub blinkwait: Option<u64>,
#[new(default)]
pub blinkon: Option<u64>,
#[new(default)]
pub blinkoff: Option<u64>,
} }
#[derive(Clone)] #[derive(Clone, PartialEq)]
pub struct Cursor { pub struct Cursor {
pub position: (u64, u64), pub position: (u64, u64),
pub shape: CursorShape, pub shape: CursorShape,
pub cell_percentage: Option<f32>, pub cell_percentage: Option<f32>,
pub blinkwait: Option<u64>,
pub blinkon: Option<u64>,
pub blinkoff: Option<u64>,
pub style: Option<Style>, pub style: Option<Style>,
pub enabled: bool, pub enabled: bool,
pub mode_list: Vec<CursorMode> pub mode_list: Vec<CursorMode>
@ -48,6 +57,9 @@ impl Cursor {
shape: CursorShape::Block, shape: CursorShape::Block,
style: None, style: None,
cell_percentage: None, cell_percentage: None,
blinkwait: None,
blinkon: None,
blinkoff: None,
enabled: true, enabled: true,
mode_list: Vec::new() mode_list: Vec::new()
} }
@ -70,7 +82,7 @@ impl Cursor {
} }
pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Style>) { pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Style>) {
if let Some(CursorMode { shape, style_id, cell_percentage }) = self.mode_list.get(mode_index as usize) { if let Some(CursorMode { shape, style_id, cell_percentage, blinkwait, blinkon, blinkoff }) = self.mode_list.get(mode_index as usize) {
if let Some(shape) = shape { if let Some(shape) = shape {
self.shape = shape.clone(); self.shape = shape.clone();
} }
@ -82,6 +94,9 @@ impl Cursor {
} }
self.cell_percentage = cell_percentage.clone(); self.cell_percentage = cell_percentage.clone();
self.blinkwait = blinkwait.clone();
self.blinkon = blinkon.clone();
self.blinkoff = blinkoff.clone();
} }
} }
} }

@ -217,6 +217,15 @@ fn parse_mode_info_set(mode_info_set_arguments: Vec<Value>) -> Result<RedrawEven
"cell_percentage" => { "cell_percentage" => {
mode_info.cell_percentage = Some(parse_u64(&value)? as f32 / 100.0); mode_info.cell_percentage = Some(parse_u64(&value)? as f32 / 100.0);
}, },
"blinkwait" => {
mode_info.blinkwait = Some(parse_u64(&value)?);
},
"blinkon" => {
mode_info.blinkon = Some(parse_u64(&value)?);
},
"blinkoff" => {
mode_info.blinkoff = Some(parse_u64(&value)?);
}
"attr_id" => { "attr_id" => {
mode_info.style_id = Some(parse_u64(&value)?); mode_info.style_id = Some(parse_u64(&value)?);
}, },

@ -1,4 +1,5 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use skulpin::skia_safe::{Canvas, Paint, Path, Point}; use skulpin::skia_safe::{Canvas, Paint, Path, Point};
@ -12,6 +13,66 @@ const DEFAULT_CELL_PERCENTAGE: f32 = 1.0 / 8.0;
const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)]; const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)];
enum BlinkState {
Waiting,
On,
Off
}
struct BlinkStatus {
state: BlinkState,
last_transition: Instant,
previous_cursor: Option<Cursor>
}
impl BlinkStatus {
pub fn new() -> BlinkStatus {
BlinkStatus {
state: BlinkState::Waiting,
last_transition: Instant::now(),
previous_cursor: None
}
}
pub fn update_status(&mut self, new_cursor: &Cursor) -> bool {
if self.previous_cursor.is_none() || new_cursor != self.previous_cursor.as_ref().unwrap() {
self.previous_cursor = Some(new_cursor.clone());
self.last_transition = Instant::now();
if new_cursor.blinkwait.is_some() && new_cursor.blinkwait != Some(0) {
self.state = BlinkState::Waiting;
} else {
self.state = BlinkState::On;
}
}
if new_cursor.blinkwait == Some(0) ||
new_cursor.blinkoff == Some(0) ||
new_cursor.blinkon == Some(0) {
return true;
}
let delay = match self.state {
BlinkState::Waiting => new_cursor.blinkwait,
BlinkState::Off => new_cursor.blinkoff,
BlinkState::On => new_cursor.blinkon
}.filter(|millis| millis > &0).map(Duration::from_millis);
if delay.map(|delay| Instant::now() - self.last_transition > delay).unwrap_or(false) {
self.state = match self.state {
BlinkState::Waiting => BlinkState::On,
BlinkState::On => BlinkState::Off,
BlinkState::Off => BlinkState::On
};
self.last_transition = Instant::now();
}
match self.state {
BlinkState::Waiting | BlinkState::Off => false,
BlinkState::On => true
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Corner { pub struct Corner {
pub current_position: Point, pub current_position: Point,
@ -59,13 +120,15 @@ impl Corner {
} }
pub struct CursorRenderer { pub struct CursorRenderer {
pub corners: Vec<Corner> pub corners: Vec<Corner>,
blink_status: BlinkStatus
} }
impl CursorRenderer { impl CursorRenderer {
pub fn new() -> CursorRenderer { pub fn new() -> CursorRenderer {
let mut renderer = CursorRenderer { let mut renderer = CursorRenderer {
corners: vec![Corner::new((0.0, 0.0).into()); 4] corners: vec![Corner::new((0.0, 0.0).into()); 4],
blink_status: BlinkStatus::new()
}; };
renderer.set_cursor_shape(&CursorShape::Block, DEFAULT_CELL_PERCENTAGE); renderer.set_cursor_shape(&CursorShape::Block, DEFAULT_CELL_PERCENTAGE);
renderer renderer
@ -100,6 +163,8 @@ impl CursorRenderer {
paint: &mut Paint, editor: Arc<Mutex<Editor>>, paint: &mut Paint, editor: Arc<Mutex<Editor>>,
shaper: &mut CachingShaper, fonts_lookup: &mut FontLookup, shaper: &mut CachingShaper, fonts_lookup: &mut FontLookup,
canvas: &mut Canvas) -> bool { canvas: &mut Canvas) -> bool {
let render = self.blink_status.update_status(&cursor);
let (grid_x, grid_y) = cursor.position; let (grid_x, grid_y) = cursor.position;
let font_dimensions: Point = (font_width, font_height).into(); let font_dimensions: Point = (font_width, font_height).into();
let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into(); let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into();
@ -116,7 +181,7 @@ impl CursorRenderer {
} }
if cursor.enabled { if cursor.enabled && render {
// Draw Background // Draw Background
paint.set_color(cursor.background(&default_colors).to_color()); paint.set_color(cursor.background(&default_colors).to_color());

Loading…
Cancel
Save