add read-only mode for input
This commit is contained in:
@@ -105,6 +105,8 @@ pub struct InputState {
|
||||
redo_stack: Vec<HistoryEntry>,
|
||||
/// Consecutive edits within this interval merge into one undo entry.
|
||||
group_interval: Duration,
|
||||
/// When set, user edits are refused, focus, movement, selection and copy stay.
|
||||
read_only: bool,
|
||||
/// The shaped line and element bounds, recorded during each paint,
|
||||
/// and shared with hit-testing and the IME geometry conversions.
|
||||
layout: Rc<RefCell<Option<InputLayout>>>,
|
||||
@@ -135,6 +137,7 @@ impl InputState {
|
||||
undo_stack: Vec::new(),
|
||||
redo_stack: Vec::new(),
|
||||
group_interval: DEFAULT_GROUP_INTERVAL,
|
||||
read_only: false,
|
||||
layout: Rc::new(RefCell::new(None)),
|
||||
}
|
||||
}
|
||||
@@ -212,6 +215,19 @@ impl InputState {
|
||||
self.group_interval = interval;
|
||||
}
|
||||
|
||||
/// Sets whether user edits are refused.
|
||||
pub fn set_read_only(&mut self, read_only: bool, cx: &mut Context<Self>) {
|
||||
if self.read_only != read_only {
|
||||
self.read_only = read_only;
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether user edits are refused.
|
||||
pub fn is_read_only(&self) -> bool {
|
||||
self.read_only
|
||||
}
|
||||
|
||||
/// Records `old_text` at `range` being replaced by `new_len` bytes.
|
||||
fn push_history(&mut self, range: Range<usize>, old_text: String, new_len: usize) {
|
||||
self.redo_stack.clear();
|
||||
@@ -262,6 +278,10 @@ impl InputState {
|
||||
|
||||
/// Reverts the most recent edit group (`cmd-z`).
|
||||
fn undo(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if self.read_only {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(entry) = self.undo_stack.pop() else {
|
||||
return;
|
||||
};
|
||||
@@ -277,6 +297,10 @@ impl InputState {
|
||||
|
||||
/// Reapplies the most recently undone edit group (`cmd-shift-z`).
|
||||
fn redo(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if self.read_only {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(entry) = self.redo_stack.pop() else {
|
||||
return;
|
||||
};
|
||||
@@ -331,6 +355,10 @@ impl InputState {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.read_only {
|
||||
return;
|
||||
}
|
||||
|
||||
if range.is_empty() && text.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -571,7 +599,8 @@ impl InputState {
|
||||
|
||||
self.paint_text(origin, line_height, window, cx);
|
||||
|
||||
if focused && self.selection().is_empty() {
|
||||
// A caret promises that typing lands there; in read-only it does not.
|
||||
if focused && !self.read_only && self.selection().is_empty() {
|
||||
self.paint_caret(
|
||||
origin,
|
||||
caret_x,
|
||||
@@ -640,7 +669,11 @@ impl InputState {
|
||||
|
||||
let index = self.index_at_x(event.position.x);
|
||||
|
||||
if event.click_count == 2 {
|
||||
if event.click_count >= 3 {
|
||||
// A single-line field is one line: triple-click selects all of it.
|
||||
let len = self.text.len();
|
||||
self.select_range(0..len, window, cx);
|
||||
} else if event.click_count == 2 {
|
||||
let start = previous_word_start(&self.text, index);
|
||||
let end = next_word_end(&self.text, index);
|
||||
self.select_range(start..end, window, cx);
|
||||
@@ -748,7 +781,8 @@ impl InputState {
|
||||
}
|
||||
}
|
||||
"x" if command => {
|
||||
if self.copy_selection(window, cx) {
|
||||
// Read-only refuses cut entirely, clipboard included.
|
||||
if !self.read_only && self.copy_selection(window, cx) {
|
||||
self.delete_selection(window, cx);
|
||||
cx.stop_propagation();
|
||||
}
|
||||
@@ -774,6 +808,10 @@ impl InputState {
|
||||
cx.emit(InputStateEvent::Submitted);
|
||||
cx.stop_propagation();
|
||||
}
|
||||
"escape" => {
|
||||
window.blur(cx);
|
||||
cx.stop_propagation();
|
||||
}
|
||||
"tab" => {}
|
||||
_ => {
|
||||
if let Some(text) = &keystroke.key_char
|
||||
@@ -850,6 +888,10 @@ impl EntityInputHandler for InputState {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if self.read_only {
|
||||
return;
|
||||
}
|
||||
|
||||
let range = range_utf16.map_or_else(
|
||||
|| self.selection(),
|
||||
|range| utf16_range_to_utf8(&self.text, range),
|
||||
|
||||
Reference in New Issue
Block a user