blink_manager.rs

  1use gpui::Context;
  2use settings::SettingsStore;
  3use std::time::Duration;
  4use ui::App;
  5
  6pub struct BlinkManager {
  7    blink_interval: Duration,
  8    blink_epoch: usize,
  9    /// Whether the blinking is paused.
 10    blinking_paused: bool,
 11    /// Whether the cursor should be visibly rendered or not.
 12    visible: bool,
 13    /// Whether the blinking currently enabled.
 14    enabled: bool,
 15    /// Whether the blinking is enabled in the settings.
 16    blink_enabled_in_settings: fn(&App) -> bool,
 17}
 18
 19impl BlinkManager {
 20    pub fn new(
 21        blink_interval: Duration,
 22        blink_enabled_in_settings: fn(&App) -> bool,
 23        cx: &mut Context<Self>,
 24    ) -> Self {
 25        // Make sure we blink the cursors if the setting is re-enabled
 26        cx.observe_global::<SettingsStore>(move |this, cx| {
 27            this.blink_cursors(this.blink_epoch, cx)
 28        })
 29        .detach();
 30
 31        Self {
 32            blink_interval,
 33            blink_epoch: 0,
 34            blinking_paused: false,
 35            visible: true,
 36            enabled: false,
 37            blink_enabled_in_settings,
 38        }
 39    }
 40
 41    fn next_blink_epoch(&mut self) -> usize {
 42        self.blink_epoch += 1;
 43        self.blink_epoch
 44    }
 45
 46    pub fn pause_blinking(&mut self, cx: &mut Context<Self>) {
 47        self.show_cursor(cx);
 48
 49        let epoch = self.next_blink_epoch();
 50        let interval = Duration::from_millis(500);
 51        cx.spawn(async move |this, cx| {
 52            cx.background_executor().timer(interval).await;
 53            this.update(cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
 54        })
 55        .detach();
 56    }
 57
 58    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut Context<Self>) {
 59        if epoch == self.blink_epoch {
 60            self.blinking_paused = false;
 61            self.blink_cursors(epoch, cx);
 62        }
 63    }
 64
 65    fn blink_cursors(&mut self, epoch: usize, cx: &mut Context<Self>) {
 66        if (self.blink_enabled_in_settings)(cx) {
 67            if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
 68                self.visible = !self.visible;
 69                cx.notify();
 70
 71                let epoch = self.next_blink_epoch();
 72                let interval = self.blink_interval;
 73                cx.spawn(async move |this, cx| {
 74                    cx.background_executor().timer(interval).await;
 75                    if let Some(this) = this.upgrade() {
 76                        this.update(cx, |this, cx| this.blink_cursors(epoch, cx));
 77                    }
 78                })
 79                .detach();
 80            }
 81        } else {
 82            self.show_cursor(cx);
 83        }
 84    }
 85
 86    pub fn show_cursor(&mut self, cx: &mut Context<BlinkManager>) {
 87        if !self.visible {
 88            self.visible = true;
 89            cx.notify();
 90        }
 91    }
 92
 93    /// Enable the blinking of the cursor.
 94    pub fn enable(&mut self, cx: &mut Context<Self>) {
 95        if self.enabled {
 96            return;
 97        }
 98
 99        self.enabled = true;
100        // Set cursors as invisible and start blinking: this causes cursors
101        // to be visible during the next render.
102        self.visible = false;
103        self.blink_cursors(self.blink_epoch, cx);
104    }
105
106    /// Disable the blinking of the cursor.
107    pub fn disable(&mut self, _cx: &mut Context<Self>) {
108        self.visible = false;
109        self.enabled = false;
110    }
111
112    pub fn visible(&self) -> bool {
113        self.visible
114    }
115}