summaryrefslogtreecommitdiff
path: root/alacritty/src/display/bell.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/display/bell.rs')
-rw-r--r--alacritty/src/display/bell.rs122
1 files changed, 122 insertions, 0 deletions
diff --git a/alacritty/src/display/bell.rs b/alacritty/src/display/bell.rs
new file mode 100644
index 00000000..1aee3ba6
--- /dev/null
+++ b/alacritty/src/display/bell.rs
@@ -0,0 +1,122 @@
+use std::time::{Duration, Instant};
+
+use crate::config::bell::{BellAnimation, BellConfig};
+
+pub struct VisualBell {
+ /// Visual bell animation.
+ animation: BellAnimation,
+
+ /// Visual bell duration.
+ duration: Duration,
+
+ /// The last time the visual bell rang, if at all.
+ start_time: Option<Instant>,
+}
+
+impl VisualBell {
+ /// Ring the visual bell, and return its intensity.
+ pub fn ring(&mut self) -> f64 {
+ let now = Instant::now();
+ self.start_time = Some(now);
+ self.intensity_at_instant(now)
+ }
+
+ /// Get the currently intensity of the visual bell. The bell's intensity
+ /// ramps down from 1.0 to 0.0 at a rate determined by the bell's duration.
+ pub fn intensity(&self) -> f64 {
+ self.intensity_at_instant(Instant::now())
+ }
+
+ /// Check whether or not the visual bell has completed "ringing".
+ pub fn completed(&mut self) -> bool {
+ match self.start_time {
+ Some(earlier) => {
+ if Instant::now().duration_since(earlier) >= self.duration {
+ self.start_time = None;
+ }
+ false
+ },
+ None => true,
+ }
+ }
+
+ /// Get the intensity of the visual bell at a particular instant. The bell's
+ /// intensity ramps down from 1.0 to 0.0 at a rate determined by the bell's
+ /// duration.
+ pub fn intensity_at_instant(&self, instant: Instant) -> f64 {
+ // If `duration` is zero, then the VisualBell is disabled; therefore,
+ // its `intensity` is zero.
+ if self.duration == Duration::from_secs(0) {
+ return 0.0;
+ }
+
+ match self.start_time {
+ // Similarly, if `start_time` is `None`, then the VisualBell has not
+ // been "rung"; therefore, its `intensity` is zero.
+ None => 0.0,
+
+ Some(earlier) => {
+ // Finally, if the `instant` at which we wish to compute the
+ // VisualBell's `intensity` occurred before the VisualBell was
+ // "rung", then its `intensity` is also zero.
+ if instant < earlier {
+ return 0.0;
+ }
+
+ let elapsed = instant.duration_since(earlier);
+ let elapsed_f =
+ elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9f64;
+ let duration_f = self.duration.as_secs() as f64
+ + f64::from(self.duration.subsec_nanos()) / 1e9f64;
+
+ // Otherwise, we compute a value `time` from 0.0 to 1.0
+ // inclusive that represents the ratio of `elapsed` time to the
+ // `duration` of the VisualBell.
+ let time = (elapsed_f / duration_f).min(1.0);
+
+ // We use this to compute the inverse `intensity` of the
+ // VisualBell. When `time` is 0.0, `inverse_intensity` is 0.0,
+ // and when `time` is 1.0, `inverse_intensity` is 1.0.
+ let inverse_intensity = match self.animation {
+ BellAnimation::Ease | BellAnimation::EaseOut => {
+ cubic_bezier(0.25, 0.1, 0.25, 1.0, time)
+ },
+ BellAnimation::EaseOutSine => cubic_bezier(0.39, 0.575, 0.565, 1.0, time),
+ BellAnimation::EaseOutQuad => cubic_bezier(0.25, 0.46, 0.45, 0.94, time),
+ BellAnimation::EaseOutCubic => cubic_bezier(0.215, 0.61, 0.355, 1.0, time),
+ BellAnimation::EaseOutQuart => cubic_bezier(0.165, 0.84, 0.44, 1.0, time),
+ BellAnimation::EaseOutQuint => cubic_bezier(0.23, 1.0, 0.32, 1.0, time),
+ BellAnimation::EaseOutExpo => cubic_bezier(0.19, 1.0, 0.22, 1.0, time),
+ BellAnimation::EaseOutCirc => cubic_bezier(0.075, 0.82, 0.165, 1.0, time),
+ BellAnimation::Linear => time,
+ };
+
+ // Since we want the `intensity` of the VisualBell to decay over
+ // `time`, we subtract the `inverse_intensity` from 1.0.
+ 1.0 - inverse_intensity
+ },
+ }
+ }
+
+ pub fn update_config(&mut self, bell_config: &BellConfig) {
+ self.animation = bell_config.animation;
+ self.duration = bell_config.duration();
+ }
+}
+
+impl From<&BellConfig> for VisualBell {
+ fn from(bell_config: &BellConfig) -> VisualBell {
+ VisualBell {
+ animation: bell_config.animation,
+ duration: bell_config.duration(),
+ start_time: None,
+ }
+ }
+}
+
+fn cubic_bezier(p0: f64, p1: f64, p2: f64, p3: f64, x: f64) -> f64 {
+ (1.0 - x).powi(3) * p0
+ + 3.0 * (1.0 - x).powi(2) * x * p1
+ + 3.0 * (1.0 - x) * x.powi(2) * p2
+ + x.powi(3) * p3
+}