1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-28 07:55:03 +03:00

Add separate animation_fps config for easing

and adjust animation scheduling to avoid excessive scheduling
if the time we compute is later than an already scheduled time
This commit is contained in:
Wez Furlong 2022-02-07 23:02:52 -07:00
parent 39babc1f1e
commit 0826fb060c
3 changed files with 67 additions and 31 deletions

View File

@ -433,6 +433,9 @@ pub struct Config {
#[serde(default = "linear_ease")]
pub cursor_blink_ease_out: EasingFunction,
#[serde(default = "default_anim_fps")]
pub animation_fps: u8,
#[serde(default)]
pub force_reverse_video_cursor: bool,
@ -1164,6 +1167,10 @@ fn default_mux_env_remove() -> Vec<String> {
]
}
fn default_anim_fps() -> u8 {
10
}
fn default_max_fps() -> u8 {
60
}

View File

@ -8,6 +8,7 @@ pub struct ColorEase {
out_duration: f32,
out_function: EasingFunction,
start: Option<Instant>,
last_render: Instant,
}
impl ColorEase {
@ -24,6 +25,7 @@ impl ColorEase {
out_duration: Duration::from_millis(out_duration_ms).as_secs_f32(),
out_function,
start,
last_render: Instant::now(),
}
}
@ -35,7 +37,7 @@ impl ColorEase {
self.start.replace(start);
}
pub fn intensity_continuous(&mut self) -> f32 {
pub fn intensity_continuous(&mut self) -> (f32, Instant) {
match self.intensity_one_shot() {
Some(intensity) => intensity,
None => {
@ -46,7 +48,7 @@ impl ColorEase {
}
}
pub fn intensity_one_shot(&mut self) -> Option<f32> {
pub fn intensity_one_shot(&mut self) -> Option<(f32, Instant)> {
let start = self.start?;
let elapsed = start.elapsed().as_secs_f32();
@ -64,9 +66,37 @@ impl ColorEase {
}
};
if intensity.is_none() {
self.start.take();
match intensity {
Some(i) => {
let now = Instant::now();
let fps = config::configuration().animation_fps as u64;
let next = match fps {
1 if elapsed < self.in_duration => {
start + Duration::from_secs_f32(self.in_duration)
}
1 => {
start
+ Duration::from_secs_f32(self.in_duration)
+ Duration::from_secs_f32(self.out_duration)
}
_ => {
let frame_interval = 1000 / fps as u64;
let elapsed = (elapsed * 1000.).ceil() as u64;
let remain = elapsed % frame_interval;
if remain != 0 {
now + Duration::from_millis(remain)
} else {
now + Duration::from_millis(frame_interval)
}
}
};
self.last_render = now;
Some((i, next))
}
None => {
self.start.take();
None
}
}
intensity
}
}

View File

@ -30,7 +30,7 @@ use mux::tab::{PositionedPane, PositionedSplit, SplitDirection};
use smol::Timer;
use std::ops::Range;
use std::rc::Rc;
use std::time::{Duration, Instant};
use std::time::Instant;
use termwiz::cell::{unicode_column_width, Blink};
use termwiz::cellcluster::CellCluster;
use termwiz::surface::{CursorShape, CursorVisibility};
@ -302,18 +302,24 @@ impl super::TermWindow {
// invalidate the viewport when the next frame is due
if self.focused.is_some() {
if let Some(next_due) = *self.has_animation.borrow() {
if Some(next_due) != *self.scheduled_animation.borrow() {
self.scheduled_animation.borrow_mut().replace(next_due);
let window = self.window.clone().take().unwrap();
promise::spawn::spawn(async move {
Timer::at(next_due).await;
let win = window.clone();
window.notify(TermWindowNotif::Apply(Box::new(move |tw| {
tw.scheduled_animation.borrow_mut().take();
win.invalidate();
})));
})
.detach();
let prior = self.scheduled_animation.borrow_mut().take();
match prior {
Some(prior) if prior <= next_due => {
// Already due before that time
}
_ => {
self.scheduled_animation.borrow_mut().replace(next_due);
let window = self.window.clone().take().unwrap();
promise::spawn::spawn(async move {
Timer::at(next_due).await;
let win = window.clone();
window.notify(TermWindowNotif::Apply(Box::new(move |tw| {
tw.scheduled_animation.borrow_mut().take();
win.invalidate();
})));
})
.detach();
}
}
}
}
@ -357,10 +363,8 @@ impl super::TermWindow {
None => {
per_pane.bell_start.take();
}
Some(intensity) => {
self.update_next_frame_time(Some(
Instant::now() + Duration::from_millis(1000 / config.max_fps as u64),
));
Some((intensity, next)) => {
self.update_next_frame_time(Some(next));
return Some(intensity);
}
}
@ -1608,7 +1612,7 @@ impl super::TermWindow {
};
if let Some((blink_rate, mut colorease)) = blink_rate {
if blink_rate != 0 {
let intensity = colorease.intensity_continuous();
let (intensity, next) = colorease.intensity_continuous();
let (r1, g1, b1, a) = bg.tuple();
let (r, g, b, _a) = fg.tuple();
@ -1619,10 +1623,7 @@ impl super::TermWindow {
a,
);
self.update_next_frame_time(Some(
Instant::now()
+ Duration::from_millis(1000 / self.config.max_fps as u64),
));
self.update_next_frame_time(Some(next));
}
}
@ -2518,7 +2519,7 @@ impl super::TermWindow {
if blinking {
let mut color_ease = self.cursor_blink_state.borrow_mut();
color_ease.update_start(self.prev_cursor.last_cursor_movement());
let intensity = color_ease.intensity_continuous();
let (intensity, next) = color_ease.intensity_continuous();
// Invert the intensity: we want to start with a visible
// cursor whenever the cursor moves, then fade out, then back.
@ -2547,9 +2548,7 @@ impl super::TermWindow {
);
}
self.update_next_frame_time(Some(
Instant::now() + Duration::from_millis(1000 / self.config.max_fps as u64),
));
self.update_next_frame_time(Some(next));
}
ComputeCellFgBgResult {