rework cursor to render itself
This commit is contained in:
@@ -5,8 +5,6 @@ use gpui::Hsla;
|
||||
pub struct InputColors {
|
||||
/// This is the background color applied to the range of text that is currently selected by the user.
|
||||
pub selection: Hsla,
|
||||
/// This is the color of the user's text cursor.
|
||||
pub cursor: Hsla,
|
||||
/// This is the color of the placeholder string, when one is assigned and the text field is empty.
|
||||
pub placeholder: Hsla,
|
||||
pub marked: Hsla,
|
||||
@@ -16,7 +14,6 @@ impl Default for InputColors {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
selection: gpui::hsla(0.583, 0.519, 0.31, 1.0),
|
||||
cursor: Hsla::white().opacity(0.8),
|
||||
marked: Hsla::white().opacity(0.6),
|
||||
placeholder: gpui::hsla(0., 0., 0.5, 1.0),
|
||||
}
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
use gpui::Context;
|
||||
use gpui::{Bounds, Context, Element, Hsla, IntoElement, Pixels, Point, Render};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Default interval for cursor blinking.
|
||||
pub const DEFAULT_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
|
||||
pub trait Cursor {}
|
||||
|
||||
/// Configuration for cursor blinking, to be provided to InputState.
|
||||
pub enum CursorBlinkType<'app> {
|
||||
/// The cursor will not blink.
|
||||
Disabled,
|
||||
/// The cursor will blink at some interval.
|
||||
Enabled {
|
||||
/// Provide the app so that the internal state to track cursor blinking can be created.
|
||||
app: &'app mut gpui::App,
|
||||
/// The interval to blink at. If none, the default value of 500ms is used (defined by `DEFAULT_BLINK_INTERVAL`).
|
||||
interval: Option<Duration>,
|
||||
},
|
||||
}
|
||||
|
||||
/// The state of an input's cursor blinking. While active, the cursor's visibility changes at some interval.
|
||||
/// This blinking can be temporarily paused (e.g. during typing).
|
||||
pub(super) struct CursorBlink {
|
||||
pub struct Cursor {
|
||||
interval: Duration,
|
||||
generation: usize,
|
||||
visible: bool,
|
||||
active: bool,
|
||||
paused: bool,
|
||||
color: Hsla,
|
||||
/// Tracks whether we were focused on the last update.
|
||||
was_focused: bool,
|
||||
point: Point<Pixels>,
|
||||
height: Pixels,
|
||||
}
|
||||
|
||||
impl CursorBlink {
|
||||
impl Cursor {
|
||||
/// Initializes the cursor blinking with the cursor already being visible.
|
||||
#[track_caller]
|
||||
pub fn new(interval: Duration) -> Self {
|
||||
pub fn new(interval: Option<Duration>) -> Self {
|
||||
Self {
|
||||
interval,
|
||||
interval: interval.unwrap_or_default(),
|
||||
generation: 0,
|
||||
visible: true,
|
||||
active: false,
|
||||
paused: false,
|
||||
color: Hsla::white(),
|
||||
was_focused: false,
|
||||
point: Point::default(),
|
||||
height: Pixels::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: Hsla) -> Self {
|
||||
self.color = color;
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns whether the cursor should currently be rendered.
|
||||
pub fn visible(&self) -> bool {
|
||||
self.visible
|
||||
@@ -121,4 +120,94 @@ impl CursorBlink {
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn update_input(
|
||||
&mut self,
|
||||
is_focused: bool,
|
||||
pos: Point<Pixels>,
|
||||
line_height: Pixels,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let was_focused = self.was_focused;
|
||||
self.was_focused = is_focused;
|
||||
|
||||
self.point = pos;
|
||||
self.height = line_height;
|
||||
|
||||
match (self.interval.is_zero(), is_focused, was_focused) {
|
||||
(true, _, _) => true,
|
||||
(false, true, false) => {
|
||||
self.enable(cx);
|
||||
true
|
||||
}
|
||||
(false, false, true) => {
|
||||
self.disable(cx);
|
||||
false
|
||||
}
|
||||
(false, _, _) => self.visible,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElement for Cursor {
|
||||
type Element = Self;
|
||||
fn into_element(self) -> Self::Element {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Cursor {
|
||||
type RequestLayoutState = ();
|
||||
type PrepaintState = ();
|
||||
|
||||
fn id(&self) -> Option<gpui::ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
_id: Option<&gpui::GlobalElementId>,
|
||||
_inspector_id: Option<&gpui::InspectorElementId>,
|
||||
window: &mut gpui::Window,
|
||||
cx: &mut gpui::App,
|
||||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||
let layout_id = window.request_layout(gpui::Style::default(), None, cx);
|
||||
(layout_id, ())
|
||||
}
|
||||
|
||||
fn prepaint(
|
||||
&mut self,
|
||||
_id: Option<&gpui::GlobalElementId>,
|
||||
_inspector_id: Option<&gpui::InspectorElementId>,
|
||||
_bounds: gpui::Bounds<gpui::Pixels>,
|
||||
_request_layout: &mut Self::RequestLayoutState,
|
||||
_window: &mut gpui::Window,
|
||||
_cx: &mut gpui::App,
|
||||
) -> Self::PrepaintState {
|
||||
()
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_id: Option<&gpui::GlobalElementId>,
|
||||
_inspector_id: Option<&gpui::InspectorElementId>,
|
||||
bounds: gpui::Bounds<gpui::Pixels>,
|
||||
_request_layout: &mut Self::RequestLayoutState,
|
||||
_prepaint: &mut Self::PrepaintState,
|
||||
window: &mut gpui::Window,
|
||||
_cx: &mut gpui::App,
|
||||
) {
|
||||
const CURSOR_WIDTH: f32 = 2.0;
|
||||
window.paint_quad(gpui::fill(
|
||||
Bounds::new(
|
||||
gpui::point(bounds.left(), bounds.top()) + self.point,
|
||||
gpui::size(gpui::px(CURSOR_WIDTH), self.height),
|
||||
),
|
||||
self.color,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct Input {
|
||||
pub(super) interactivity: Interactivity,
|
||||
pub(super) placeholder: Option<SharedString>,
|
||||
pub(super) colors: InputColors,
|
||||
pub(super) cursor: Option<AnyElement>,
|
||||
pub(super) cursor: Option<Entity<Cursor>>,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
@@ -145,13 +145,6 @@ impl Input {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the "cursor" color for the input element.
|
||||
/// This is the color of the user's text cursor.
|
||||
pub fn cursor_color(mut self, color: Hsla) -> Self {
|
||||
self.colors.cursor = color;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the "placeholder" color for the input element.
|
||||
/// This is the color of the placeholder string, when one is assigned and the text field is empty.
|
||||
pub fn placeholder_color(mut self, color: Hsla) -> Self {
|
||||
@@ -166,12 +159,8 @@ impl Input {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cursor<T>(mut self, entity: Entity<T>) -> Self
|
||||
where
|
||||
T: Cursor,
|
||||
Entity<T>: Into<AnyElement>,
|
||||
{
|
||||
self.cursor = Some(entity.into());
|
||||
pub fn cursor(mut self, entity: Entity<Cursor>) -> Self {
|
||||
self.cursor = Some(entity);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::input::{Input, InputColors, InputLayoutData, InputLogicalLine, InputState};
|
||||
use crate::input::{Cursor, Input, InputColors, InputLayoutData, InputLogicalLine, InputState};
|
||||
use gpui::{
|
||||
Along, App, Axis, Bounds, ContentMask, CursorStyle, DispatchPhase, Display, Element, ElementId,
|
||||
ElementInputHandler, Entity, Focusable, GlobalElementId, Hitbox, HitboxBehavior, Hsla,
|
||||
@@ -9,17 +9,18 @@ use gpui::{
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::Range;
|
||||
|
||||
const CURSOR_WIDTH: f32 = 2.0;
|
||||
const MARKED_TEXT_UNDERLINE_THICKNESS: f32 = 2.0;
|
||||
|
||||
pub struct InputLayoutState {
|
||||
text_style: TextStyle,
|
||||
#[allow(dead_code)]
|
||||
child_layout_ids: SmallVec<[LayoutId; 2]>,
|
||||
cursor_layout: Option<<Cursor as Element>::RequestLayoutState>,
|
||||
}
|
||||
|
||||
pub struct InputPrepaintState {
|
||||
hitbox: Option<Hitbox>,
|
||||
cursor_prepaint: Option<<Cursor as Element>::PrepaintState>,
|
||||
}
|
||||
|
||||
impl Element for Input {
|
||||
@@ -43,6 +44,7 @@ impl Element for Input {
|
||||
) -> (LayoutId, Self::RequestLayoutState) {
|
||||
let mut resolved_text_style = None;
|
||||
let mut child_layout_ids = SmallVec::new();
|
||||
let mut cursor_layout = None;
|
||||
|
||||
let layout_id = self.interactivity.request_layout(
|
||||
global_id,
|
||||
@@ -65,11 +67,13 @@ impl Element for Input {
|
||||
}
|
||||
}
|
||||
|
||||
child_layout_ids = self
|
||||
.cursor
|
||||
.iter_mut()
|
||||
.map(|cursor| cursor.request_layout(window, cx))
|
||||
.collect::<SmallVec<_>>();
|
||||
if let Some(cursor) = &self.cursor {
|
||||
let (layout_id, layout) = cursor.update(cx, |cursor, cx| {
|
||||
cursor.request_layout(global_id, inspector_id, window, cx)
|
||||
});
|
||||
child_layout_ids.push(layout_id);
|
||||
cursor_layout = Some(layout);
|
||||
}
|
||||
|
||||
window.request_layout(layout_style, child_layout_ids.iter().copied(), cx)
|
||||
})
|
||||
@@ -79,6 +83,7 @@ impl Element for Input {
|
||||
let layout_state = InputLayoutState {
|
||||
text_style: resolved_text_style.unwrap_or_else(|| window.text_style()),
|
||||
child_layout_ids,
|
||||
cursor_layout,
|
||||
};
|
||||
(layout_id, layout_state)
|
||||
}
|
||||
@@ -112,6 +117,7 @@ impl Element for Input {
|
||||
input.apply_layout_update(layout_data, window);
|
||||
});
|
||||
|
||||
let mut cursor_prepaint = None;
|
||||
let hitbox = self.interactivity.prepaint(
|
||||
global_id,
|
||||
inspector_id,
|
||||
@@ -125,8 +131,21 @@ impl Element for Input {
|
||||
|
||||
if style.display != Display::None {
|
||||
window.with_element_offset(scroll_offset, |window| {
|
||||
if let Some(cursor) = &mut self.cursor {
|
||||
cursor.prepaint(window, cx);
|
||||
match (&mut self.cursor, &mut layout_state.cursor_layout) {
|
||||
(Some(cursor), Some(layout)) => {
|
||||
let prepaint = cursor.update(cx, |cursor, cx| {
|
||||
cursor.prepaint(
|
||||
global_id,
|
||||
inspector_id,
|
||||
bounds,
|
||||
layout,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
cursor_prepaint = Some(prepaint);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,7 +154,10 @@ impl Element for Input {
|
||||
},
|
||||
);
|
||||
|
||||
InputPrepaintState { hitbox }
|
||||
InputPrepaintState {
|
||||
hitbox,
|
||||
cursor_prepaint,
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(
|
||||
@@ -166,10 +188,6 @@ impl Element for Input {
|
||||
let is_focused = focus_handle.is_focused(window);
|
||||
let colors = self.colors;
|
||||
|
||||
let is_cursor_visible = self.input.update(cx, |input, cx| {
|
||||
input.toggle_cursor_on_focus_change(is_focused, cx)
|
||||
});
|
||||
|
||||
let perform_paint = |style: &Style, window: &mut Window, cx: &mut App| {
|
||||
if style.display == Display::None {
|
||||
return;
|
||||
@@ -182,14 +200,39 @@ impl Element for Input {
|
||||
text_style: &text_style,
|
||||
placeholder: placeholder.as_ref(),
|
||||
colors: &colors,
|
||||
cursor_visible: is_cursor_visible,
|
||||
};
|
||||
context.process_mouse_events(&self.input, window, cx);
|
||||
window.with_content_mask(Some(ContentMask { bounds }), |window| {
|
||||
context.paint(window, cx);
|
||||
|
||||
if let Some(cursor) = &mut self.cursor {
|
||||
cursor.paint(window, cx);
|
||||
match (
|
||||
&mut self.cursor,
|
||||
&mut layout_state.cursor_layout,
|
||||
&mut prepaint_state.cursor_prepaint,
|
||||
) {
|
||||
(Some(cursor), Some(layout), Some(prepaint)) => {
|
||||
cursor.update(cx, |cursor, cx| {
|
||||
let cursor_pos = context.find_cursor_position_in_layouts();
|
||||
let visible = cursor.update_input(
|
||||
is_focused,
|
||||
cursor_pos,
|
||||
context.snapshot.line_height,
|
||||
cx,
|
||||
);
|
||||
if is_focused && visible && context.snapshot.selected_range.is_empty() {
|
||||
cursor.paint(
|
||||
global_id,
|
||||
inspector_id,
|
||||
bounds,
|
||||
layout,
|
||||
prepaint,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -253,7 +296,6 @@ struct PaintContext<'app> {
|
||||
text_style: &'app TextStyle,
|
||||
placeholder: Option<&'app SharedString>,
|
||||
colors: &'app InputColors,
|
||||
cursor_visible: bool,
|
||||
}
|
||||
|
||||
impl<'app> PaintContext<'app> {
|
||||
@@ -388,10 +430,6 @@ impl<'app> PaintContext<'app> {
|
||||
}
|
||||
|
||||
self.paint_marked_underline(window);
|
||||
|
||||
if self.is_focused && self.snapshot.selected_range.is_empty() && self.cursor_visible {
|
||||
self.paint_cursor(window);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_selection(&self, window: &mut Window) {
|
||||
@@ -557,17 +595,6 @@ impl<'app> PaintContext<'app> {
|
||||
Point::default()
|
||||
}
|
||||
|
||||
fn paint_cursor(&self, window: &mut Window) {
|
||||
let cursor_pos = self.find_cursor_position_in_layouts();
|
||||
window.paint_quad(fill(
|
||||
Bounds::new(
|
||||
point(self.bounds.left(), self.bounds.top()) + cursor_pos,
|
||||
size(px(CURSOR_WIDTH), self.snapshot.line_height),
|
||||
),
|
||||
self.colors.cursor,
|
||||
));
|
||||
}
|
||||
|
||||
fn is_line_visible(&self, line: &InputLogicalLine) -> bool {
|
||||
let line_y = line.y_offset - self.snapshot.scroll_distance;
|
||||
let line_bottom = line_y + self.snapshot.line_height * line.visual_line_count as f32;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::actions::*;
|
||||
use crate::input::{CursorBlinkType, InputLayoutStyle, InputStorage};
|
||||
use crate::input::{InputLayoutStyle, InputStorage};
|
||||
use gpui::{
|
||||
App, AppContext, ClipboardItem, Context, Entity, EntityId, EntityInputHandler, EventEmitter,
|
||||
FocusHandle, Focusable, NavigationDirection, Pixels, Point, Render, SharedString, Size,
|
||||
@@ -26,9 +26,15 @@ pub enum InputStateEvent {
|
||||
/// Emitted when a redo operation is performed.
|
||||
Redo,
|
||||
}
|
||||
|
||||
impl EventEmitter<InputStateEvent> for InputState {}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CursorTrigger {
|
||||
// TODO: cursor needs to receive this
|
||||
PauseBlinkingForUserAction,
|
||||
}
|
||||
impl EventEmitter<CursorTrigger> for InputState {}
|
||||
|
||||
/// `Input` is the state model for text input components. It handles:
|
||||
/// - Text content storage and manipulation
|
||||
/// - Selection and cursor management
|
||||
@@ -56,8 +62,6 @@ pub struct InputState {
|
||||
layout_data: InputLayoutData,
|
||||
/// A reinterpretation of `content` as wrapped lines with layout information. Regenerated when content changes or the layout changes during element painting.
|
||||
logical_lines: Vec<InputLogicalLine>,
|
||||
/// Tracks whether we were focused on the last update.
|
||||
was_focused: bool,
|
||||
|
||||
/// True while the user is in the act of highlighting a section of the text (e.g. during mouse pressed & dragging).
|
||||
is_selecting: bool,
|
||||
@@ -135,7 +139,6 @@ impl InputState {
|
||||
|
||||
layout_data: InputLayoutData::default(),
|
||||
logical_lines: Vec::new(),
|
||||
was_focused: false,
|
||||
|
||||
is_selecting: false,
|
||||
last_click_position: None,
|
||||
@@ -164,7 +167,7 @@ impl InputState {
|
||||
self.history_undo_stack.clear();
|
||||
self.history_redo_stack.clear();
|
||||
self.mark_layout_dirty();
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
cx.emit(InputStateEvent::TextChanged);
|
||||
cx.notify();
|
||||
}
|
||||
@@ -305,7 +308,7 @@ impl InputState {
|
||||
self.marked_range.take();
|
||||
self.mark_layout_dirty();
|
||||
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
cx.emit(InputStateEvent::TextChanged);
|
||||
cx.notify();
|
||||
}
|
||||
@@ -429,7 +432,7 @@ impl InputState {
|
||||
}
|
||||
|
||||
pub(super) fn up(&mut self, _: &Up, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
match self.layout_style {
|
||||
InputLayoutStyle::SingleLine => {
|
||||
// In single-line mode, up moves to start
|
||||
@@ -450,7 +453,7 @@ impl InputState {
|
||||
}
|
||||
|
||||
pub(super) fn down(&mut self, _: &Down, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
match self.layout_style {
|
||||
InputLayoutStyle::SingleLine => {
|
||||
// In single-line mode, down moves to end
|
||||
@@ -480,7 +483,7 @@ impl InputState {
|
||||
}
|
||||
|
||||
pub(super) fn select_up(&mut self, _: &SelectUp, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
match self.layout_style {
|
||||
InputLayoutStyle::SingleLine => {
|
||||
// In single-line mode, select_up selects to start
|
||||
@@ -503,7 +506,7 @@ impl InputState {
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
match self.layout_style {
|
||||
InputLayoutStyle::SingleLine => {
|
||||
// In single-line mode, select_down selects to end
|
||||
@@ -808,13 +811,6 @@ impl InputState {
|
||||
self.content.update_utf8(range, text_to_insert);
|
||||
}
|
||||
|
||||
/// Temporarily pauses blinking and leaves the cursor visible. Blinking will resume after the pre-established interval elapses from the time this is called.
|
||||
pub(super) fn pause_cursor_blink(&self, cx: &mut Context<Self>) {
|
||||
if let Some((cursor_blink, _)) = &self.cursor_blink {
|
||||
cursor_blink.update(cx, |cb, cx| cb.pause_blinking(cx));
|
||||
}
|
||||
}
|
||||
|
||||
/// Records a patch for undo. Called before making changes to content.
|
||||
/// Returns true if a new entry was created, false if grouped with previous.
|
||||
pub(super) fn push_undo_patch(&mut self, range: Range<usize>, new_text_len: usize) {
|
||||
@@ -1110,37 +1106,8 @@ impl InputState {
|
||||
logical_lines
|
||||
}
|
||||
|
||||
/// Processes a focus-flag update during window paint, returning whether the cursor should be visible in this frame.
|
||||
/// Returns false if the cursor is blinking and not currently visible.
|
||||
pub(super) fn toggle_cursor_on_focus_change(
|
||||
&mut self,
|
||||
is_focused: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
// Update cursor blink based on focus changes
|
||||
let was_focused = self.was_focused;
|
||||
self.was_focused = is_focused;
|
||||
|
||||
match &self.cursor_blink {
|
||||
None => true,
|
||||
Some((cursor_blink, _)) => match (is_focused, was_focused) {
|
||||
(true, false) => {
|
||||
cursor_blink.update(cx, |cursor, cx| cursor.enable(cx));
|
||||
cx.emit(InputStateEvent::Focus);
|
||||
true
|
||||
}
|
||||
(false, true) => {
|
||||
cursor_blink.update(cx, |cursor, cx| cursor.disable(cx));
|
||||
cx.emit(InputStateEvent::Blur);
|
||||
false
|
||||
}
|
||||
_ => cursor_blink.read(cx).visible(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn move_to(&mut self, offset: usize, cx: &mut Context<Self>) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
let offset = offset.min(self.content.len());
|
||||
self.selected_range = offset..offset;
|
||||
self.selection_direction = NavigationDirection::Forward;
|
||||
@@ -1149,7 +1116,7 @@ impl InputState {
|
||||
}
|
||||
|
||||
fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
let offset = offset.min(self.content.len());
|
||||
self.apply_selection_offset(offset);
|
||||
self.scroll_to_cursor();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::input::InputStateEvent;
|
||||
use crate::input::{CursorTrigger, InputStateEvent};
|
||||
use gpui::{
|
||||
Bounds, Context, EntityInputHandler, NavigationDirection, Pixels, Point, UTF16Selection,
|
||||
Window, point, px,
|
||||
@@ -73,7 +73,7 @@ impl EntityInputHandler for super::InputState {
|
||||
self.set_marked_range(None);
|
||||
self.mark_layout_dirty();
|
||||
|
||||
self.pause_cursor_blink(cx);
|
||||
cx.emit(CursorTrigger::PauseBlinkingForUserAction);
|
||||
cx.emit(InputStateEvent::TextChanged);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user