Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ Copies the selected text to the clipboard and removes it from the editable area.
### paste()
Pastes the text content of the clipboard at the cursor position. This function takes effect regardless of the `read-only` and `enabled` properties.

### undo()
Undoes the last text operation. This function takes effect regardless of the `read-only` and `enabled` properties.

### redo()
Redoes the last undone text operation. This function takes effect regardless of the `read-only` and `enabled` properties.

## Callbacks

### edited(string)
Expand Down
24 changes: 24 additions & 0 deletions internal/compiler/widgets/common/textedit-base.slint
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,35 @@ export component TextEditBase inherits Rectangle {
text-input.paste();
}

public function undo() {
text-input.undo();
}

public function redo() {
text-input.redo();
}

forward-focus: text-input;

ContextMenuArea {
enabled: root.enabled;
Menu {
if !root.read-only && root.enabled: MenuItem {
title: @tr("Undo");
activated => {
text-input.undo();
}
}

if !root.read-only && root.enabled: MenuItem {
title: @tr("Redo");
activated => {
text-input.redo();
}
}

if !root.read-only && root.enabled: MenuSeparator { }

MenuItem {
title: @tr("Cut");
enabled: !root.read-only && root.enabled;
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/widgets/cosmic/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ export component TextEdit {
base.paste();
}

public function undo() {
base.undo();
}

public function redo() {
base.redo();
}

forward-focus: base;
horizontal-stretch: 1;
vertical-stretch: 1;
Expand Down
22 changes: 22 additions & 0 deletions internal/compiler/widgets/cupertino/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ export component TextEdit {
text-input.paste();
}

public function undo() {
text-input.undo();
}

public function redo() {
text-input.redo();
}

forward-focus: text-input;
horizontal-stretch: 1;
vertical-stretch: 1;
Expand Down Expand Up @@ -146,21 +154,35 @@ export component TextEdit {
}

ContextMenuArea {
enabled: root.enabled;
Menu {
if !root.read-only && root.enabled: MenuItem {
title: @tr("Undo");
activated => { text-input.undo(); }
}
if !root.read-only && root.enabled: MenuItem {
title: @tr("Redo");
activated => { text-input.redo(); }
}
if !root.read-only && root.enabled: MenuSeparator { }
MenuItem {
title: @tr("Cut");
enabled: !root.read-only && root.enabled;
activated => { text-input.cut(); }
}
MenuItem {
title: @tr("Copy");
enabled: !root.text.is-empty;
activated => { text-input.copy(); }
}
MenuItem {
title: @tr("Paste");
enabled: !root.read-only && root.enabled;
activated => { text-input.paste(); }
}
MenuItem {
title: @tr("Select All");
enabled: !root.text.is-empty;
activated => { text-input.select-all(); }
}
}
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/widgets/fluent/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ export component TextEdit {
base.paste();
}

public function undo() {
base.undo();
}

public function redo() {
base.redo();
}

forward-focus: base;
horizontal-stretch: 1;
vertical-stretch: 1;
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/widgets/material/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ export component TextEdit {
base.paste();
}

public function undo() {
base.undo();
}

public function redo() {
base.redo();
}

forward-focus: base;
horizontal-stretch: 1;
vertical-stretch: 1;
Expand Down
8 changes: 8 additions & 0 deletions internal/compiler/widgets/qt/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export component TextEdit {
base.paste();
}

public function undo() {
base.undo();
}

public function redo() {
base.redo();
}

forward-focus: base;
horizontal-stretch: 1;
vertical-stretch: 1;
Expand Down
74 changes: 69 additions & 5 deletions tests/cases/widgets/textedit.slint
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export component TestCase inherits Window {
public function select_all() {
edit.select_all();
}
public function undo() {
edit.undo();
}
public function redo() {
edit.redo();
}
}

/*
Expand All @@ -41,6 +47,18 @@ use std::cell::RefCell;
use std::rc::Rc;
use slint::SharedString;

// Opens the context menu with the menu key and activates the `n`th entry,
// counting from 1 and skipping separators the way the menu's arrow keys do.
// Activating a disabled entry leaves the menu open, so this closes it.
fn menu_activate(instance: &TestCase, n: usize) {
slint_testing::send_keyboard_string_sequence(instance, &SharedString::from(slint::platform::Key::Menu));
for _ in 0..n {
slint_testing::send_keyboard_string_sequence(instance, &SharedString::from(slint::platform::Key::DownArrow));
}
slint_testing::send_keyboard_string_sequence(instance, "\n");
slint_testing::send_keyboard_string_sequence(instance, &SharedString::from(slint::platform::Key::Escape));
}

fn ctrl_key(instance: &TestCase, key: &str) {
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
slint_testing::send_keyboard_string_sequence(instance, key);
Expand Down Expand Up @@ -99,11 +117,8 @@ slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slin
slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::UpArrow));
slint_testing::send_keyboard_string_sequence(&instance, "\n");
assert_eq!(instance.get_text(), "Hello👋");
// copy
slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::Menu));
slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::DownArrow));
slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::DownArrow));
slint_testing::send_keyboard_string_sequence(&instance, "\n");
// copy: Undo, Redo and a separator come first, so Copy is the fourth entry the arrow keys reach
menu_activate(&instance, 4);
assert_eq!(instance.get_text(), "Hello👋");

slint_testing::send_keyboard_string_sequence(&instance, "Xxx");
Expand Down Expand Up @@ -143,6 +158,55 @@ assert_eq!(instance.get_font_italic(), true);
instance.invoke_select_all();
instance.invoke_cut();
assert_eq!(instance.get_text(), "");

// undo and redo, through the public functions
instance.set_enabled(true);
slint_testing::send_keyboard_string_sequence(&instance, "abc");
assert_eq!(instance.get_text(), "abc");
instance.invoke_undo();
assert_eq!(instance.get_text(), "");
instance.invoke_redo();
assert_eq!(instance.get_text(), "abc");

// and through the first two entries of the context menu
menu_activate(&instance, 1);
assert_eq!(instance.get_text(), "");
menu_activate(&instance, 2);
assert_eq!(instance.get_text(), "abc");

// neither the menu nor Ctrl+Z reaches a read-only or a disabled TextEdit
instance.invoke_select_all();
instance.invoke_cut();
assert_eq!(instance.get_text(), "");
// the menu above took the keyboard focus away from the TextEdit, so click it back
slint_testing::send_mouse_click(&instance, 25., 25.);
instance.set_read_only(true);
ctrl_key(&instance, "z");
assert_eq!(instance.get_text(), "");
// read-only hides Undo and Redo, so the first entry is Cut, which read-only disables
menu_activate(&instance, 1);
assert_eq!(instance.get_text(), "");
instance.set_read_only(false);
slint_testing::send_mouse_click(&instance, 25., 25.);
instance.set_enabled(false);
ctrl_key(&instance, "z");
assert_eq!(instance.get_text(), "");
instance.set_enabled(true);

// with neither in the way, the same shortcut undoes the cut
ctrl_key(&instance, "z");
assert_eq!(instance.get_text(), "abc");

// with Undo and Redo hidden, a read-only menu lists Cut, Copy, Paste and Select All,
// so its fourth entry selects the text instead of copying it
slint_testing::send_mouse_click(&instance, 25., 25.);
// the undo above left the whole text selected, so collapse the selection first
slint_testing::send_keyboard_string_sequence(&instance, &SharedString::from(slint::platform::Key::Home));
instance.set_read_only(true);
menu_activate(&instance, 4);
instance.invoke_cut();
Comment thread
0x6e marked this conversation as resolved.
assert_eq!(instance.get_text(), "");
Comment thread
0x6e marked this conversation as resolved.
instance.set_read_only(false);
```

*/
Loading