Skip to content

Commit

Permalink
Get paste/copy/cut working again
Browse files Browse the repository at this point in the history
This gets us back to parity with the current situation, but I'd
like to get these working without menus soon.
  • Loading branch information
cmyr committed Mar 10, 2021
1 parent 3e6c682 commit df6ec41
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 9 deletions.
48 changes: 40 additions & 8 deletions druid/src/text/input_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,37 @@ impl<T> EditSession<T> {
}

impl<T: TextStorage + EditableText> EditSession<T> {
/// Insert text *not* from the IME, replacing the current selection.
///
/// The caller is responsible for notifying the platform of the change in
/// text state, by calling [`EventCtx::invalidate_text_input`].
#[must_use]
pub fn insert_text(&mut self, data: &mut T, new_text: &str) -> ImeUpdate {
let new_cursor_pos = self.selection.min() + new_text.len();
data.edit(self.selection.range(), new_text);
self.selection = Selection::caret(new_cursor_pos);
self.scroll_to_selection_end(true);
ImeUpdate::Reset
}

/// Sets the clipboard to the contents of the current selection.
///
/// Returns `true` if the clipboard was set, and `false` if not (indicating)
/// that the selection was empty.)
pub fn set_clipboard(&self) -> bool {
if let Some(text) = self
.layout
.text()
.and_then(|txt| txt.slice(self.selection.range()))
{
if !text.is_empty() {
crate::Application::global().clipboard().put_string(text);
return true;
}
}
false
}

fn scroll_to_selection_end(&mut self, after_edit: bool) {
self.external_scroll_to = Some(after_edit);
}
Expand Down Expand Up @@ -519,10 +550,10 @@ impl<T: TextStorage + EditableText> EditSession<T> {
let to_delete =
crate::text::movement(movement, self.selection, &self.layout, true);
self.selection = to_delete;
self.insert_text(buffer, "")
self.ime_insert_text(buffer, "")
}
}
ImeAction::Delete(_) => self.insert_text(buffer, ""),
ImeAction::Delete(_) => self.ime_insert_text(buffer, ""),
ImeAction::DecomposingBackspace => {
log::warn!("Decomposing Backspace is not implemented");
self.backspace(buffer);
Expand All @@ -539,12 +570,12 @@ impl<T: TextStorage + EditableText> EditSession<T> {
if self.send_notification_on_return && !ignore_hotkey {
self.external_action = Some(action);
} else if self.accepts_newlines {
self.insert_text(buffer, &newline_type.to_string());
self.ime_insert_text(buffer, &newline_type.to_string());
}
}
ImeAction::InsertTab { ignore_hotkey } => {
if ignore_hotkey || self.accepts_tabs {
self.insert_text(buffer, "\t");
self.ime_insert_text(buffer, "\t");
} else if !ignore_hotkey {
self.external_action = Some(action);
}
Expand All @@ -554,8 +585,8 @@ impl<T: TextStorage + EditableText> EditSession<T> {
self.external_action = Some(action);
}
}
ImeAction::InsertSingleQuoteIgnoringSmartQuotes => self.insert_text(buffer, "'"),
ImeAction::InsertDoubleQuoteIgnoringSmartQuotes => self.insert_text(buffer, "\""),
ImeAction::InsertSingleQuoteIgnoringSmartQuotes => self.ime_insert_text(buffer, "'"),
ImeAction::InsertDoubleQuoteIgnoringSmartQuotes => self.ime_insert_text(buffer, "\""),
ImeAction::Cancel if self.send_notification_on_cancel => {
self.external_action = Some(action)
}
Expand All @@ -564,7 +595,9 @@ impl<T: TextStorage + EditableText> EditSession<T> {
}

/// Replace the current selection with `text`, and advance the cursor.
fn insert_text(&mut self, buffer: &mut T, text: &str) {
///
/// This should only be called from the IME.
fn ime_insert_text(&mut self, buffer: &mut T, text: &str) {
let new_cursor_pos = self.selection.min() + text.len();
buffer.edit(self.selection.range(), text);
self.external_selection_change = Some(Selection::caret(new_cursor_pos));
Expand Down Expand Up @@ -649,7 +682,6 @@ impl<T: TextStorage + EditableText> EditSession<T> {
self.selection = new_sel;
self.update_pending_invalidation(ImeUpdate::SelectionChanged);
}
//self.selection = self.selection.constrained(new_data);
self.layout.rebuild_if_needed(ctx.text(), env);
}
}
Expand Down
2 changes: 1 addition & 1 deletion druid/src/text/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl<T: TextStorage> TextLayout<T> {

/// Set the text to display.
pub fn set_text(&mut self, text: T) {
if self.text.is_none() || self.text.as_ref().unwrap().as_str() != text.as_str() {
if self.text.is_none() || !self.text.as_ref().unwrap().same(&text) {
self.text = Some(text);
self.layout = None;
}
Expand Down
28 changes: 28 additions & 0 deletions druid/src/widget/textbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,34 @@ impl<T: TextStorage + EditableText> Widget<T> for TextBox<T> {
Event::ImeStateChange => {
self.reset_cursor_blink(ctx.request_timer(CURSOR_BLINK_DURATION));
}
Event::Command(ref cmd)
if self.text().can_read() && ctx.is_focused() && cmd.is(crate::commands::COPY) =>
{
self.text().borrow().set_clipboard();
ctx.set_handled();
}
Event::Command(cmd)
if self.text().can_write() && ctx.is_focused() && cmd.is(crate::commands::CUT) =>
{
if self.text().borrow().set_clipboard() {
let inval = self.text_mut().borrow_mut().insert_text(data, "");
ctx.invalidate_text_input(Some(inval));
}
ctx.set_handled();
}
Event::Paste(ref item) if self.text().can_write() => {
if let Some(string) = item.get_string() {
let text = if self.multiline {
&string
} else {
string.lines().next().unwrap_or("")
};
if !text.is_empty() {
let inval = self.text_mut().borrow_mut().insert_text(data, text);
ctx.invalidate_text_input(Some(inval));
}
}
}
_ => (),
}
self.inner.event(ctx, event, data, env)
Expand Down

0 comments on commit df6ec41

Please sign in to comment.