add accepts_input flag as a way to track an input field's disabled state

This commit is contained in:
temportalflux
2026-07-11 09:31:07 -04:00
parent b5acea4809
commit dd61395440
3 changed files with 39 additions and 8 deletions
@@ -9,7 +9,6 @@ pub use state::*;
pub use storage::*;
/* TODO list
- disabled input/area
- remove gpuikit based input
- auto-scroll when cursor moves
- cursor blinking
@@ -21,6 +21,7 @@ pub fn editable_text(id: impl Into<ElementId>) -> EditableTextElement {
supports_multiline: true,
init_storage: InitStorage::default(),
placeholder: None,
accepts_input: true,
};
this.interactivity.element_id = Some(id.into());
@@ -40,7 +41,6 @@ pub fn text_area(id: impl Into<ElementId>) -> EditableTextElement {
editable_text(id).multiline(true)
}
// TODO: Disabled flag/state?
pub struct EditableTextElement {
interactivity: Interactivity,
// Populated on first render with an entity stored/attached to the view.
@@ -50,6 +50,7 @@ pub struct EditableTextElement {
init_storage: InitStorage,
supports_multiline: bool,
placeholder: Option<SharedString>,
accepts_input: bool,
}
impl EditableTextElement {
@@ -78,6 +79,12 @@ impl EditableTextElement {
self.init_storage = InitStorage::new_typed(move |_cx| storage.clone());
self
}
/// Configures whether the element can accept input (effectively is the element currently enabled).
pub fn accepts_input(mut self, enabled: bool) -> Self {
self.accepts_input = enabled;
self
}
}
impl InteractiveElement for EditableTextElement {
@@ -193,6 +200,7 @@ impl Element for EditableTextElement {
let placeholder = self.placeholder.clone();
let placeholder_color = Hsla::white().opacity(0.5); // TODO: as an element param
let supports_multiline = self.supports_multiline;
let accepts_input = self.accepts_input;
let layout_id = self.interactivity().request_layout(
global_id,
inspector_id,
@@ -317,6 +325,7 @@ impl Element for EditableTextElement {
let layout_data = TextInputLayoutData {
supports_multiline,
accepts_input,
wrap_width,
size: Some(size),
last_seen_storage_version,
@@ -552,6 +561,7 @@ impl Element for EditableTextElement {
window.set_cursor_style(CursorStyle::IBeam, hitbox);
}
let accepts_input = self.accepts_input;
let inner_bounds = prepaint.inner_bounds;
let to_local_position = -(bounds.origin + prepaint.scroll_offset);
let perform_paint = |style: &Style, window: &mut Window, cx: &mut App| {
@@ -559,9 +569,11 @@ impl Element for EditableTextElement {
return;
}
// NOTE: Skip when disabled
let ime_handler = ElementInputHandler::new(inner_bounds, request_layout.state.clone());
window.handle_input(&prepaint.focus_handle, ime_handler, cx);
if accepts_input {
let ime_handler =
ElementInputHandler::new(inner_bounds, request_layout.state.clone());
window.handle_input(&prepaint.focus_handle, ime_handler, cx);
}
window.on_mouse_event({
let state = request_layout.state.clone();
@@ -38,6 +38,7 @@ pub struct EditableTextState {
#[derive(Default)]
pub(super) struct TextInputLayoutData {
pub supports_multiline: bool,
pub accepts_input: bool,
/// The last known width at which the lines were wrapped.
pub wrap_width: Option<Pixels>,
/// The last known size of the text, as generated during layout.
@@ -277,6 +278,10 @@ impl EditableTextState {
boundary: TextBoundary,
cx: &mut Context<Self>,
) {
if !self.layout_data.accepts_input {
return;
}
let range = self.selected_range();
let range = match range.is_empty() {
false => range,
@@ -555,13 +560,20 @@ impl<'app> EditableTextActionHandler<Context<'app, Self>> for EditableTextState
}
fn insert_enter(&mut self, _: &Enter, window: &mut Window, cx: &mut Context<'app, Self>) {
if self.layout_data.supports_multiline {
// TODO: Why is the cursor appearing at the start of the entire field instead of on the new line?
self.replace_text_in_range(None, "\n", window, cx);
if !self.layout_data.supports_multiline {
return;
}
if !self.layout_data.accepts_input {
return;
}
// TODO: Why is the cursor appearing at the start of the entire field instead of on the new line?
self.replace_text_in_range(None, "\n", window, cx);
}
fn insert_tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<'app, Self>) {
if !self.layout_data.accepts_input {
return;
}
self.replace_text_in_range(None, "\t", window, cx);
}
@@ -741,6 +753,10 @@ impl<'app> EditableTextActionHandler<Context<'app, Self>> for EditableTextState
}
fn cut(&mut self, _: &Cut, _w: &mut Window, cx: &mut Context<'app, Self>) {
if !self.layout_data.accepts_input {
return;
}
if !self.selected_range.is_empty() {
// Cut selected text
let slice = &self.storage.content_utf8()[self.selected_range.clone()];
@@ -789,6 +805,10 @@ impl<'app> EditableTextActionHandler<Context<'app, Self>> for EditableTextState
}
fn paste(&mut self, _: &Paste, _w: &mut Window, cx: &mut Context<'app, Self>) {
if !self.layout_data.accepts_input {
return;
}
let Some(text) = cx.read_from_clipboard().and_then(|item| item.text()) else {
return;
};