summaryrefslogtreecommitdiffstats
path: root/tests/scene/test_text_edit.h
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-04-30 17:03:04 +0200
committerRémi Verschelde <rverschelde@gmail.com>2024-04-30 17:03:04 +0200
commite19b808a7afa498921beee95ec15321ab29b735d (patch)
tree0924bc49b4ac76790316b07086338f358e763846 /tests/scene/test_text_edit.h
parentd9bf750cbf9b24103f85f43856e771fb739df4c8 (diff)
parent773a473807c75975b5820b30a4f0eccaece7cfa2 (diff)
downloadredot-engine-e19b808a7afa498921beee95ec15321ab29b735d.tar.gz
Merge pull request #86978 from kitbdev/multicaret-overhaul
Overhaul multicaret editing and selection in TextEdit
Diffstat (limited to 'tests/scene/test_text_edit.h')
-rw-r--r--tests/scene/test_text_edit.h5036
1 files changed, 4266 insertions, 770 deletions
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 8577dd7148..246d869687 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -36,6 +36,23 @@
#include "tests/test_macros.h"
namespace TestTextEdit {
+static inline Array build_array() {
+ return Array();
+}
+template <typename... Targs>
+static inline Array build_array(Variant item, Targs... Fargs) {
+ Array a = build_array(Fargs...);
+ a.push_front(item);
+ return a;
+}
+static inline Array reverse_nested(Array array) {
+ Array reversed_array = array.duplicate(true);
+ reversed_array.reverse();
+ for (int i = 0; i < reversed_array.size(); i++) {
+ ((Array)reversed_array[i]).reverse();
+ }
+ return reversed_array;
+}
TEST_CASE("[SceneTree][TextEdit] text entry") {
SceneTree::get_singleton()->get_root()->set_physics_object_picking(false);
@@ -52,12 +69,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_WATCH(text_edit, "lines_edited_from");
SIGNAL_WATCH(text_edit, "caret_changed");
- Array args1;
- args1.push_back(0);
- args1.push_back(0);
- Array lines_edited_args;
- lines_edited_args.push_back(args1);
- lines_edited_args.push_back(args1.duplicate());
+ Array lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
SUBCASE("[TextEdit] clear and set text") {
// "text_changed" should not be emitted on clear / set.
@@ -119,13 +131,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_set");
- // Clear.
+ // Can clear even if not editable.
text_edit->set_editable(false);
- Array lines_edited_clear_args;
- Array new_args = args1.duplicate();
- new_args[0] = 1;
- lines_edited_clear_args.push_back(new_args);
+ Array lines_edited_clear_args = build_array(build_array(1, 0));
text_edit->clear();
MessageQueue::get_singleton()->flush();
@@ -210,6 +219,321 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("text_changed");
}
+ SUBCASE("[TextEdit] insert text") {
+ // insert_text is 0 indexed.
+ ERR_PRINT_OFF;
+ text_edit->insert_text("test", 1, 0);
+ ERR_PRINT_ON;
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Insert text when there is no text.
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->insert_text("tes", 0, 0);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "tes");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 3);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Insert multiple lines.
+ lines_edited_args = build_array(build_array(0, 1));
+
+ text_edit->insert_text("t\ninserting text", 0, 3);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\ninserting text");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 14);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Can insert even if not editable.
+ lines_edited_args = build_array(build_array(1, 1));
+
+ text_edit->set_editable(false);
+ text_edit->insert_text("mid", 1, 2);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\ninmidserting text");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 17);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->set_editable(true);
+
+ // Undo insert.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\ninserting text");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 14);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Redo insert.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\ninmidserting text");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 17);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Insert offsets carets after the edit.
+ text_edit->add_caret(1, 1);
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 4, 1, 6, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 2));
+
+ text_edit->insert_text("\n ", 1, 2);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nin\n midserting text");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 16);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 5);
+ CHECK(text_edit->get_selection_origin_line(2) == 2);
+ CHECK(text_edit->get_selection_origin_column(2) == 3);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Insert text outside of selections.
+ text_edit->set_text("test text");
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 1, 0, 4, 0);
+ text_edit->select(0, 4, 0, 8, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->insert_text("a", 0, 4, true, false);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testa text");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 9);
+ CHECK(text_edit->get_selection_origin_line(1) == 0);
+ CHECK(text_edit->get_selection_origin_column(1) == 5);
+
+ // Insert text to beginning of selections.
+ text_edit->set_text("test text");
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 1, 0, 4, 0);
+ text_edit->select(0, 4, 0, 8, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->insert_text("a", 0, 4, false, false);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testa text");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 9);
+ CHECK(text_edit->get_selection_origin_line(1) == 0);
+ CHECK(text_edit->get_selection_origin_column(1) == 4);
+
+ // Insert text to end of selections.
+ text_edit->set_text("test text");
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 1, 0, 4, 0);
+ text_edit->select(0, 4, 0, 8, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->insert_text("a", 0, 4, true, true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testa text");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 9);
+ CHECK(text_edit->get_selection_origin_line(1) == 0);
+ CHECK(text_edit->get_selection_origin_column(1) == 5);
+
+ // Insert text inside of selections.
+ text_edit->set_text("test text");
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 1, 0, 4, 0);
+ text_edit->select(0, 4, 0, 8, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->insert_text("a", 0, 4, false, true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testa text");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ }
+
+ SUBCASE("[TextEdit] remove text") {
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 2));
+
+ text_edit->set_text("test\nremoveing text\nthird line");
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_CHECK("text_set", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+
+ // remove_text is 0 indexed.
+ ERR_PRINT_OFF;
+ text_edit->remove_text(3, 0, 3, 4);
+ ERR_PRINT_ON;
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremoveing text\nthird line");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Remove multiple lines.
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(10);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(2, 1));
+
+ text_edit->remove_text(1, 9, 2, 2);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremoveingird line");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 17);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Can remove even if not editable.
+ lines_edited_args = build_array(build_array(1, 1));
+
+ text_edit->set_editable(false);
+ text_edit->remove_text(1, 5, 1, 6);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremovingird line");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 16);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->set_editable(true);
+
+ // Undo remove.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremoveingird line");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 17);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Redo remove.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremovingird line");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 16);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Remove collapses carets and offsets carets after the edit.
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(9);
+ text_edit->add_caret(1, 10);
+ text_edit->select(1, 10, 1, 13, 1);
+ text_edit->add_caret(1, 14);
+ text_edit->add_caret(1, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+
+ text_edit->remove_text(1, 8, 1, 11);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test\nremoving line");
+ // Caret 0 was merged into the selection.
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 10);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 8);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 11);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 2);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+ }
+
SUBCASE("[TextEdit] set and get line") {
// Set / Get line is 0 indexed.
text_edit->set_line(1, "test");
@@ -225,6 +549,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_text() == "test");
CHECK(text_edit->get_line(0) == "test");
CHECK(text_edit->get_line(1) == "");
+ CHECK(text_edit->get_line_count() == 1);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
@@ -233,14 +558,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
// Setting to a longer line, caret and selections should be preserved.
text_edit->select_all();
MessageQueue::get_singleton()->flush();
- CHECK(text_edit->has_selection());
- SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_DISCARD("caret_changed");
text_edit->set_line(0, "test text");
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_line(0) == "test text");
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "test");
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("caret_changed");
@@ -299,12 +625,84 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("text_set");
-
ERR_PRINT_ON;
+
+ // Both ends of selection are adjusted and deselects.
+ text_edit->set_text("test text");
+ text_edit->select(0, 8, 0, 6);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->set_line(0, "test");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_line(0) == "test");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_column() == 4);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Multiple carets adjust to keep visual position.
+ text_edit->set_text("test text");
+ text_edit->set_caret_column(2);
+ text_edit->add_caret(0, 0);
+ text_edit->add_caret(0, 1);
+ text_edit->add_caret(0, 6);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->set_line(0, "\tset line");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_line(0) == "\tset line");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection());
+ // In the default font, these are the same positions.
+ CHECK(text_edit->get_caret_column(0) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ // The previous caret at index 2 was merged.
+ CHECK(text_edit->get_caret_column(2) == 4);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+
+ // Insert multiple lines.
+ text_edit->set_text("test text\nsecond line");
+ text_edit->set_caret_column(5);
+ text_edit->add_caret(1, 6);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 1));
+
+ text_edit->set_line(0, "multiple\nlines");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "multiple\nlines\nsecond line");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 3); // In the default font, this is the same position.
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 6);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
}
SUBCASE("[TextEdit] swap lines") {
- ((Array)lines_edited_args[1])[1] = 1;
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 1));
text_edit->set_text("testing\nswap");
MessageQueue::get_singleton()->flush();
@@ -317,15 +715,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_caret_column(text_edit->get_line(0).length());
MessageQueue::get_singleton()->flush();
SIGNAL_CHECK("caret_changed", empty_signal_args);
+ // Emitted twice for each line.
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0), build_array(1, 1), build_array(1, 1));
- ((Array)lines_edited_args[1])[1] = 0;
- Array swap_args;
- swap_args.push_back(1);
- swap_args.push_back(1);
- lines_edited_args.push_back(swap_args);
- lines_edited_args.push_back(swap_args);
-
- // Order does not matter. Should also work if not editable.
+ // Order does not matter. Works when not editable.
text_edit->set_editable(false);
text_edit->swap_lines(1, 0);
MessageQueue::get_singleton()->flush();
@@ -336,19 +729,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("text_set");
text_edit->set_editable(true);
- lines_edited_args.reverse();
-
- // Single undo/redo action
+ // Single undo/redo action.
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "testing\nswap");
- SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
- lines_edited_args.reverse();
-
text_edit->redo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "swap\ntesting");
@@ -361,36 +750,70 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
ERR_PRINT_OFF;
text_edit->swap_lines(-1, 0);
CHECK(text_edit->get_text() == "swap\ntesting");
- SIGNAL_CHECK_FALSE("lines_edited_from");
- SIGNAL_CHECK_FALSE("caret_changed");
- SIGNAL_CHECK_FALSE("text_changed");
- SIGNAL_CHECK_FALSE("text_set");
-
text_edit->swap_lines(0, -1);
CHECK(text_edit->get_text() == "swap\ntesting");
- SIGNAL_CHECK_FALSE("lines_edited_from");
- SIGNAL_CHECK_FALSE("caret_changed");
- SIGNAL_CHECK_FALSE("text_changed");
- SIGNAL_CHECK_FALSE("text_set");
-
text_edit->swap_lines(2, 0);
CHECK(text_edit->get_text() == "swap\ntesting");
+ text_edit->swap_lines(0, 2);
+ CHECK(text_edit->get_text() == "swap\ntesting");
+ MessageQueue::get_singleton()->flush();
SIGNAL_CHECK_FALSE("lines_edited_from");
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("text_set");
+ ERR_PRINT_ON;
+
+ // Carets are also swapped.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(2);
+ text_edit->select(0, 0, 0, 2);
+ text_edit->add_caret(1, 6);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 1), build_array(1, 1), build_array(0, 0), build_array(0, 0));
+
+ text_edit->swap_lines(0, 1);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testing\nswap");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 6);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+
+ // Swap non adjacent lines.
+ text_edit->insert_line_at(1, "new line");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testing\nnew line\nswap");
+ SIGNAL_DISCARD("caret_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("text_changed");
+ lines_edited_args = build_array(build_array(2, 2), build_array(2, 2), build_array(0, 0), build_array(0, 0));
text_edit->swap_lines(0, 2);
- CHECK(text_edit->get_text() == "swap\ntesting");
- SIGNAL_CHECK_FALSE("lines_edited_from");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "swap\nnew line\ntesting");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 5);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK_FALSE("caret_changed");
- SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
- ERR_PRINT_ON;
}
SUBCASE("[TextEdit] insert line at") {
- ((Array)lines_edited_args[1])[1] = 1;
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 1));
text_edit->set_text("testing\nswap");
MessageQueue::get_singleton()->flush();
@@ -407,9 +830,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_to_line() == 1);
SIGNAL_CHECK("caret_changed", empty_signal_args);
- // Insert before should move caret and selection, and works when not editable.
+ // Insert line at inserts a line before and moves caret and selection. Works when not editable.
text_edit->set_editable(false);
- lines_edited_args.remove_at(0);
+ lines_edited_args = build_array(build_array(0, 1));
text_edit->insert_line_at(0, "new");
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "new\ntesting\nswap");
@@ -417,7 +840,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_column() == text_edit->get_line(2).size() - 1);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selection_from_line() == 1);
+ CHECK(text_edit->get_selection_from_column() == 0);
CHECK(text_edit->get_selection_to_line() == 2);
+ CHECK(text_edit->get_selection_to_column() == 4);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -425,19 +850,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(true);
// Can undo/redo as single action.
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 0;
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "testing\nswap");
CHECK(text_edit->has_selection());
- SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
- ((Array)lines_edited_args[0])[0] = 0;
- ((Array)lines_edited_args[0])[1] = 1;
text_edit->redo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "new\ntesting\nswap");
@@ -454,9 +875,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_from_line() == 0);
CHECK(text_edit->get_selection_to_line() == 2);
SIGNAL_CHECK_FALSE("caret_changed");
+ lines_edited_args = build_array(build_array(2, 3));
- ((Array)lines_edited_args[0])[0] = 2;
- ((Array)lines_edited_args[0])[1] = 3;
text_edit->insert_line_at(2, "after");
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "new\ntesting\nafter\nswap");
@@ -474,24 +894,222 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
ERR_PRINT_OFF;
text_edit->insert_line_at(-1, "after");
CHECK(text_edit->get_text() == "new\ntesting\nafter\nswap");
+ text_edit->insert_line_at(4, "after");
+ CHECK(text_edit->get_text() == "new\ntesting\nafter\nswap");
+ MessageQueue::get_singleton()->flush();
SIGNAL_CHECK_FALSE("lines_edited_from");
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("text_set");
+ ERR_PRINT_ON;
- text_edit->insert_line_at(4, "after");
- CHECK(text_edit->get_text() == "new\ntesting\nafter\nswap");
+ // Can insert multiple lines.
+ text_edit->select(0, 1, 2, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(2, 4));
+
+ text_edit->insert_line_at(2, "multiple\nlines");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "new\ntesting\nmultiple\nlines\nafter\nswap");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 4);
+ CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 1);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ }
+
+ SUBCASE("[TextEdit] remove line at") {
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 5));
+ text_edit->set_text("testing\nremove line at\n\tremove\nlines\n\ntest");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testing\nremove line at\n\tremove\nlines\n\ntest");
+ SIGNAL_CHECK("text_set", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+
+ // Remove line handles multiple carets.
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(2, 7);
+ text_edit->select(2, 1, 2, 7, 1);
+ text_edit->add_caret(3, 1);
+ text_edit->add_caret(4, 5);
+ text_edit->add_caret(1, 5);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 2));
+
+ text_edit->remove_line_at(2, true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "testing\nremove line at\nlines\n\ntest");
+ CHECK(text_edit->get_caret_count() == 5);
+ CHECK_FALSE(text_edit->has_selection(0)); // Same line.
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->has_selection(1)); // Same line, clamped.
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 3); // In the default font, this is the same position.
+ CHECK_FALSE(text_edit->has_selection(2)); // Moved up.
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 1);
+ CHECK_FALSE(text_edit->has_selection(3)); // Moved up.
+ CHECK(text_edit->get_caret_line(3) == 3);
+ CHECK(text_edit->get_caret_column(3) == 0);
+ CHECK_FALSE(text_edit->has_selection(4)); // Didn't move.
+ CHECK(text_edit->get_caret_line(4) == 1);
+ CHECK(text_edit->get_caret_column(4) == 5);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+
+ // Remove first line.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(5);
+ text_edit->add_caret(4, 4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0));
+
+ text_edit->remove_line_at(0, false);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at\nlines\n\ntest");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->remove_secondary_carets();
+
+ // Remove empty line.
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 2));
+
+ text_edit->remove_line_at(2, false);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at\nlines\ntest");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Remove last line.
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(2, 1));
+
+ text_edit->remove_line_at(2, true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at\nlines");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Out of bounds.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ ERR_PRINT_OFF
+ text_edit->remove_line_at(2, true);
+ ERR_PRINT_ON
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at\nlines");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 2);
SIGNAL_CHECK_FALSE("lines_edited_from");
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("text_set");
- ERR_PRINT_ON;
+
+ // Remove regular line with move caret up and not editable.
+ text_edit->set_editable(false);
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0));
+
+ text_edit->remove_line_at(1, false);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 1); // In the default font, this is the same position.
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+ text_edit->set_editable(true);
+
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at\nlines");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "remove line at");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 1);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
+
+ // Remove only line removes line content.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(10);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->remove_line_at(0);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "");
+ CHECK(text_edit->get_line_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_set");
}
- SUBCASE("[TextEdit] insert line at caret") {
- lines_edited_args.pop_back();
- ((Array)lines_edited_args[0])[1] = 1;
+ SUBCASE("[TextEdit] insert text at caret") {
+ lines_edited_args = build_array(build_array(0, 1));
+ // Insert text at caret can insert multiple lines.
text_edit->insert_text_at_caret("testing\nswap");
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "testing\nswap");
@@ -502,11 +1120,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
+ // Text is inserted at caret.
text_edit->set_caret_line(0, false);
text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
- ((Array)lines_edited_args[0])[1] = 0;
+ lines_edited_args = build_array(build_array(0, 0));
text_edit->insert_text_at_caret("mid");
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "temidsting\nswap");
@@ -517,9 +1137,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_set");
+ // Selections are deleted then text is inserted. It also works even if not editable.
text_edit->select(0, 0, 0, text_edit->get_line(0).length());
CHECK(text_edit->has_selection());
- lines_edited_args.push_back(args1.duplicate());
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
text_edit->set_editable(false);
text_edit->insert_text_at_caret("new line");
@@ -534,12 +1155,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("text_set");
text_edit->set_editable(true);
+ // Undo restores text and selection.
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "temidsting\nswap");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
@@ -589,24 +1213,19 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_WATCH(text_edit, "lines_edited_from");
SIGNAL_WATCH(text_edit, "caret_changed");
- Array args1;
- args1.push_back(0);
- args1.push_back(0);
- Array lines_edited_args;
- lines_edited_args.push_back(args1);
- lines_edited_args.push_back(args1.duplicate());
+ Array lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
SUBCASE("[TextEdit] select all") {
+ // Select when there is no text does not select.
text_edit->select_all();
CHECK_FALSE(text_edit->has_selection());
- ERR_PRINT_OFF;
- CHECK(text_edit->get_selection_from_line() == -1);
- CHECK(text_edit->get_selection_from_column() == -1);
- CHECK(text_edit->get_selection_to_line() == -1);
- CHECK(text_edit->get_selection_to_column() == -1);
+ CHECK(text_edit->get_selection_from_line() == 0);
+ CHECK(text_edit->get_selection_from_column() == 0);
+ CHECK(text_edit->get_selection_to_line() == 0);
+ CHECK(text_edit->get_selection_to_column() == 0);
CHECK(text_edit->get_selected_text() == "");
- ERR_PRINT_ON;
+ // Select all selects all text.
text_edit->set_text("test\nselection");
SEND_GUI_ACTION("ui_text_select_all");
CHECK(text_edit->get_viewport()->is_input_handled());
@@ -618,10 +1237,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_to_line() == 1);
CHECK(text_edit->get_selection_to_column() == 9);
CHECK(text_edit->get_selection_mode() == TextEdit::SelectionMode::SELECTION_MODE_SHIFT);
+ CHECK(text_edit->is_caret_after_selection_origin());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 9);
SIGNAL_CHECK("caret_changed", empty_signal_args);
+ // Cannot select when disabled.
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
text_edit->set_selecting_enabled(false);
@@ -654,6 +1275,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Select word under caret with multiple carets.
text_edit->select_word_under_caret();
CHECK(text_edit->has_selection(0));
CHECK(text_edit->get_selected_text(0) == "test");
@@ -675,6 +1297,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_count() == 2);
+ // Select word under caret disables selection if there is already a selection.
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
@@ -703,6 +1326,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selected_text() == "test\ntest");
SIGNAL_CHECK("caret_changed", empty_signal_args);
+ // Cannot select when disabled.
text_edit->set_selecting_enabled(false);
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
@@ -714,10 +1338,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("caret_changed");
text_edit->set_selecting_enabled(true);
- text_edit->set_caret_line(1, false, true, 0, 0);
+ // Select word under caret when there is no word does not select.
+ text_edit->set_caret_line(1, false, true, -1, 0);
text_edit->set_caret_column(5, false, 0);
-
- text_edit->set_caret_line(2, false, true, 0, 1);
+ text_edit->set_caret_line(2, false, true, -1, 1);
text_edit->set_caret_column(5, false, 1);
text_edit->select_word_under_caret();
@@ -739,7 +1363,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_caret_column(0);
text_edit->set_caret_line(1);
- // First selection made by the implicit select_word_under_caret call
+ // First selection made by the implicit select_word_under_caret call.
text_edit->add_selection_for_next_occurrence();
CHECK(text_edit->get_caret_count() == 1);
CHECK(text_edit->get_selected_text(0) == "test");
@@ -780,7 +1404,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line(3) == 3);
CHECK(text_edit->get_caret_column(3) == 9);
- // A different word with a new manually added caret
+ // A different word with a new manually added caret.
text_edit->add_caret(2, 1);
text_edit->select(2, 0, 2, 4, 4);
CHECK(text_edit->get_selected_text(4) == "rand");
@@ -795,7 +1419,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line(5) == 3);
CHECK(text_edit->get_caret_column(5) == 22);
- // Make sure the previous selections are still active
+ // Make sure the previous selections are still active.
CHECK(text_edit->get_selected_text(0) == "test");
CHECK(text_edit->get_selected_text(1) == "test");
CHECK(text_edit->get_selected_text(2) == "test");
@@ -987,6 +1611,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT)
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "t");
+ CHECK(text_edit->is_caret_after_selection_origin());
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT | KeyModifierMask::ALT)
@@ -995,10 +1620,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
#endif
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "test");
+ CHECK(text_edit->is_caret_after_selection_origin());
SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT)
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "tes");
+ CHECK(text_edit->is_caret_after_selection_origin());
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT | KeyModifierMask::ALT)
@@ -1019,11 +1646,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT)
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "t");
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin());
SEND_GUI_KEY_EVENT(Key::LEFT)
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
+ // Cannot select when disabled.
text_edit->set_selecting_enabled(false);
SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT)
CHECK_FALSE(text_edit->has_selection());
@@ -1032,46 +1661,120 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] mouse drag select") {
- /* Set size for mouse input. */
+ // Set size for mouse input.
text_edit->set_size(Size2(200, 200));
text_edit->set_text("this is some text\nfor selection");
text_edit->grab_focus();
MessageQueue::get_singleton()->flush();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
+ // Click and drag to make a selection.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Add (2,0) to bring it past the center point of the grapheme and account for integer division flooring.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for s");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
- CHECK(text_edit->get_selection_from_line() == 1);
- CHECK(text_edit->get_selection_from_column() == 0);
- CHECK(text_edit->get_selection_to_line() == 1);
- CHECK(text_edit->get_selection_to_column() == 5);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 0);
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->is_caret_after_selection_origin());
+ CHECK(text_edit->is_dragging_cursor());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Releasing finishes.
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for s");
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 9).get_center() + Point2i(2, 0), MouseButtonMask::NONE, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for s");
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->is_caret_after_selection_origin());
+
+ // Clicking clears selection.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 7);
+ // Cannot select when disabled, but caret still moves.
text_edit->set_selecting_enabled(false);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 1), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 0);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
text_edit->set_selecting_enabled(true);
+
+ // Only last caret is moved when adding a selection.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 15);
+ text_edit->select(0, 11, 0, 15, 1);
+ MessageQueue::get_singleton()->flush();
+
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::ALT);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 0);
+ CHECK(text_edit->get_selection_origin_column(1) == 11);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 15);
+
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_selected_text(2) == "for s");
+ CHECK(text_edit->get_selection_origin_line(2) == 1);
+ CHECK(text_edit->get_selection_origin_column(2) == 5);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 0);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(2));
+
+ // Overlapping carets and selections merges them.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "s is some text\nfor s");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 5);
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 3);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin());
+
+ // Entering text stops selecting.
+ text_edit->insert_text_at_caret("a");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "thiaelection");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center() + Point2i(2, 0), MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
}
SUBCASE("[TextEdit] mouse word select") {
- /* Set size for mouse input. */
+ // Set size for mouse input.
text_edit->set_size(Size2(200, 200));
- text_edit->set_text("this is some text\nfor selection");
+ text_edit->set_text("this is some text\nfor selection\n");
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
- SEND_GUI_DOUBLE_CLICK(text_edit->get_pos_at_line_column(0, 2), Key::NONE);
+ // Double click to select word.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(1, 2).get_center() + Point2i(2, 0), Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
@@ -1081,9 +1784,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_to_column() == 3);
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 3);
+ CHECK(text_edit->is_caret_after_selection_origin());
SIGNAL_CHECK("caret_changed", empty_signal_args);
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
+ // Moving mouse selects entire words at a time.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 6).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "for selection");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
@@ -1093,15 +1798,116 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_selection_to_column() == 13);
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 13);
+ CHECK(text_edit->is_caret_after_selection_origin());
+ CHECK(text_edit->is_dragging_cursor());
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+
+ // Moving to a word before the initial selected word reverses selection direction and keeps the initial word selected.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "some text\nfor");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->get_selection_from_line() == 0);
+ CHECK(text_edit->get_selection_from_column() == 8);
+ CHECK(text_edit->get_selection_to_line() == 1);
+ CHECK(text_edit->get_selection_to_column() == 3);
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 8);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin());
SIGNAL_CHECK("caret_changed", empty_signal_args);
- Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
- line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Releasing finishes.
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "some text\nfor");
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 2).get_center(), MouseButtonMask::NONE, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "some text\nfor");
+ text_edit->deselect();
+
+ // Can start word select mode on an empty line.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(2, 0).get_center() + Point2i(2, 0), Key::NONE);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 0);
+
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 9).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "selection\n");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_selection_origin_line() == 2);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ // Clicking clears selection.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+
+ // Can start word select mode when not on a word.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(0, 12).get_center() + Point2i(2, 0), Key::NONE);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 12);
+
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 9).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == " text\nfor selection");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 13);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 12);
+
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "some");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 8);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 12);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 15).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+
+ // Add a new selection without affecting the old one.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::ALT);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 8).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::ALT);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "some");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 8);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 12);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "ele");
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 5);
+
+ // Shift + double click to extend selection and start word select mode.
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 8).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ text_edit->remove_secondary_carets();
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), Key::NONE | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_WORD);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == " text\nfor selection");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 13);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 12);
+
+ // Cannot select when disabled, but caret still moves to end of word.
text_edit->set_selecting_enabled(false);
- SEND_GUI_DOUBLE_CLICK(text_edit->get_pos_at_line_column(0, 2), Key::NONE);
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(1, 1).get_center() + Point2i(2, 0), Key::NONE);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 3);
@@ -1109,32 +1915,149 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] mouse line select") {
- /* Set size for mouse input. */
+ // Set size for mouse input.
text_edit->set_size(Size2(200, 200));
- text_edit->set_text("this is some text\nfor selection");
+ text_edit->set_text("this is some text\nfor selection\nwith 3 lines");
MessageQueue::get_singleton()->flush();
- SEND_GUI_DOUBLE_CLICK(text_edit->get_pos_at_line_column(0, 2), Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Triple click to select line.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(1, 2).get_center(), Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 2).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selected_text() == "for selection");
+ CHECK(text_edit->get_selected_text() == "for selection\n");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
CHECK(text_edit->get_selection_from_line() == 1);
CHECK(text_edit->get_selection_from_column() == 0);
+ CHECK(text_edit->get_selection_to_line() == 2);
+ CHECK(text_edit->get_selection_to_column() == 0);
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->is_caret_after_selection_origin());
+
+ // Moving mouse selects entire lines at a time. Selecting above reverses the selection direction.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "this is some text\nfor selection");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->get_selection_from_line() == 0);
+ CHECK(text_edit->get_selection_from_column() == 0);
CHECK(text_edit->get_selection_to_line() == 1);
CHECK(text_edit->get_selection_to_column() == 13);
- CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin());
+ CHECK(text_edit->is_dragging_cursor());
- Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
- line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Selecting to the last line puts the caret at end of the line.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(2, 10).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for selection\nwith 3 lines");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->get_selection_from_line() == 1);
+ CHECK(text_edit->get_selection_from_column() == 0);
+ CHECK(text_edit->get_selection_to_line() == 2);
+ CHECK(text_edit->get_selection_to_column() == 12);
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 12);
+ CHECK(text_edit->is_caret_after_selection_origin());
+
+ // Releasing finishes.
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(2, 10).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for selection\nwith 3 lines");
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 2).get_center(), MouseButtonMask::NONE, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for selection\nwith 3 lines");
+
+ // Clicking clears selection.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+
+ // Can start line select mode on an empty line.
+ text_edit->set_text("this is some text\n\nfor selection\nwith 4 lines");
+ MessageQueue::get_singleton()->flush();
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(1, 0).get_center() + Point2i(2, 0), Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "\n");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(2, 9).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "\nfor selection\n");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->get_caret_line() == 3);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ // Add a new selection without affecting the old one.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::ALT);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 4).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::ALT);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "\nfor selection\n");
+ CHECK(text_edit->get_caret_line(0) == 3);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "is");
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_selection_origin_line(1) == 0);
+ CHECK(text_edit->get_selection_origin_column(1) == 2);
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Selecting the last line puts caret at the end.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(3, 3).get_center(), Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(3, 3).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "with 4 lines");
+ CHECK(text_edit->get_caret_line() == 3);
+ CHECK(text_edit->get_caret_column() == 12);
+ CHECK(text_edit->get_selection_origin_line() == 3);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ // Selecting above reverses direction.
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(2, 10).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "for selection\nwith 4 lines");
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_selection_origin_line() == 3);
+ CHECK(text_edit->get_selection_origin_column() == 12);
+
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(2, 10).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Shift + triple click to extend selection and restart line select mode.
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(0, 9).get_center() + Point2i(2, 0), Key::NONE | KeyModifierMask::SHIFT);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 9).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_LINE);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "this is some text\n\nfor selection\nwith 4 lines");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_selection_origin_line() == 3);
+ CHECK(text_edit->get_selection_origin_column() == 12);
+
+ // Cannot select when disabled, but caret still moves to the start of the next line.
text_edit->set_selecting_enabled(false);
- SEND_GUI_DOUBLE_CLICK(text_edit->get_pos_at_line_column(0, 2), Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 2), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(0, 2).get_center(), Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
@@ -1142,30 +2065,47 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] mouse shift click select") {
- /* Set size for mouse input. */
+ // Set size for mouse input.
text_edit->set_size(Size2(200, 200));
text_edit->set_text("this is some text\nfor selection");
MessageQueue::get_singleton()->flush();
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ // Shift click to make a selection from the previous caret position.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 1).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selected_text() == "for s");
+ CHECK(text_edit->get_selected_text() == "or s");
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
- CHECK(text_edit->get_selection_from_line() == 1);
- CHECK(text_edit->get_selection_from_column() == 0);
- CHECK(text_edit->get_selection_to_line() == 1);
- CHECK(text_edit->get_selection_to_column() == 5);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 1);
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->is_caret_after_selection_origin());
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 9), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Shift click above to switch selection direction. Uses original selection position.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "s some text\nf");
+ CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 1);
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 6);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin());
+
+ // Clicking clears selection.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 7);
+ // Cannot select when disabled, but caret still moves.
text_edit->set_selecting_enabled(false);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
- SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 0);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
@@ -1175,89 +2115,166 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SUBCASE("[TextEdit] select and deselect") {
text_edit->set_text("this is some text\nfor selection");
MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ // Select clamps input to full text.
text_edit->select(-1, -1, 500, 500);
+ MessageQueue::get_singleton()->flush();
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "this is some text\nfor selection");
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 13);
+ CHECK(text_edit->get_selection_from_line(0) == text_edit->get_selection_origin_line(0));
+ CHECK(text_edit->get_selection_from_column(0) == text_edit->get_selection_origin_column(0));
+ CHECK(text_edit->get_selection_to_line(0) == text_edit->get_caret_line(0));
+ CHECK(text_edit->get_selection_to_column(0) == text_edit->get_caret_column(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
text_edit->deselect();
+ MessageQueue::get_singleton()->flush();
CHECK_FALSE(text_edit->has_selection());
+ SIGNAL_CHECK_FALSE("caret_changed");
+ // Select works in the other direction.
text_edit->select(500, 500, -1, -1);
+ MessageQueue::get_singleton()->flush();
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "this is some text\nfor selection");
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 13);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_selection_from_line(0) == text_edit->get_caret_line(0));
+ CHECK(text_edit->get_selection_from_column(0) == text_edit->get_caret_column(0));
+ CHECK(text_edit->get_selection_to_line(0) == text_edit->get_selection_origin_line(0));
+ CHECK(text_edit->get_selection_to_column(0) == text_edit->get_selection_origin_column(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
text_edit->deselect();
+ MessageQueue::get_singleton()->flush();
CHECK_FALSE(text_edit->has_selection());
+ SIGNAL_CHECK_FALSE("caret_changed");
+ // Select part of a line.
text_edit->select(0, 4, 0, 8);
+ MessageQueue::get_singleton()->flush();
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == " is ");
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 4);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 8);
+ CHECK(text_edit->get_selection_from_line(0) == text_edit->get_selection_origin_line(0));
+ CHECK(text_edit->get_selection_from_column(0) == text_edit->get_selection_origin_column(0));
+ CHECK(text_edit->get_selection_to_line(0) == text_edit->get_caret_line(0));
+ CHECK(text_edit->get_selection_to_column(0) == text_edit->get_caret_column(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
text_edit->deselect();
+ MessageQueue::get_singleton()->flush();
CHECK_FALSE(text_edit->has_selection());
+ SIGNAL_CHECK_FALSE("caret_changed");
+ // Select part of a line in the other direction.
text_edit->select(0, 8, 0, 4);
+ MessageQueue::get_singleton()->flush();
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == " is ");
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 8);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_from_line(0) == text_edit->get_caret_line(0));
+ CHECK(text_edit->get_selection_from_column(0) == text_edit->get_caret_column(0));
+ CHECK(text_edit->get_selection_to_line(0) == text_edit->get_selection_origin_line(0));
+ CHECK(text_edit->get_selection_to_column(0) == text_edit->get_selection_origin_column(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ // Cannot select when disabled.
text_edit->set_selecting_enabled(false);
CHECK_FALSE(text_edit->has_selection());
text_edit->select(0, 8, 0, 4);
+ MessageQueue::get_singleton()->flush();
CHECK_FALSE(text_edit->has_selection());
+ SIGNAL_CHECK_FALSE("caret_changed");
text_edit->set_selecting_enabled(true);
+ }
- text_edit->select(0, 8, 0, 4);
- CHECK(text_edit->has_selection());
- SEND_GUI_ACTION("ui_text_caret_right");
+ SUBCASE("[TextEdit] delete selection") {
+ text_edit->set_text("this is some text\nfor selection");
+ MessageQueue::get_singleton()->flush();
+
+ // Delete selection does nothing if there is no selection.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(8);
CHECK_FALSE(text_edit->has_selection());
text_edit->delete_selection();
CHECK(text_edit->get_text() == "this is some text\nfor selection");
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 8);
- text_edit->select(0, 8, 0, 4);
+ // Backspace removes selection.
+ text_edit->select(0, 4, 0, 8);
CHECK(text_edit->has_selection());
SEND_GUI_ACTION("ui_text_backspace");
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 4);
+ // Undo restores previous selection.
text_edit->undo();
- CHECK(text_edit->has_selection());
CHECK(text_edit->get_text() == "this is some text\nfor selection");
+ CHECK(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 8);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 4);
+ // Redo restores caret.
text_edit->redo();
- CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 4);
text_edit->undo();
- CHECK(text_edit->has_selection());
CHECK(text_edit->get_text() == "this is some text\nfor selection");
+ CHECK(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 8);
- text_edit->select(0, 8, 0, 4);
+ text_edit->select(0, 4, 0, 8);
CHECK(text_edit->has_selection());
+ // Delete selection removes text, deselects, and moves caret.
text_edit->delete_selection();
- CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ // Undo delete works.
text_edit->undo();
- CHECK(text_edit->has_selection());
CHECK(text_edit->get_text() == "this is some text\nfor selection");
+ CHECK(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 8);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 4);
+ // Redo delete works.
text_edit->redo();
- CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 4);
@@ -1267,19 +2284,227 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 8);
+ // Can still delete if not editable.
text_edit->set_editable(false);
text_edit->delete_selection();
text_edit->set_editable(false);
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+ // Cannot undo since it was not editable.
text_edit->undo();
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+
+ // Delete multiple adjacent selections on the same line.
+ text_edit->select(0, 0, 0, 5);
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 5, 0, 8, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+ text_edit->delete_selection();
+ CHECK(text_edit->get_text() == " text\nfor selection");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+
+ // Delete mulitline selection. Ignore non selections.
+ text_edit->remove_secondary_carets();
+ text_edit->select(1, 3, 0, 2);
+ text_edit->add_caret(1, 7);
+ text_edit->delete_selection();
+ CHECK(text_edit->get_text() == " t selection");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 6);
}
- // Add readonly test?
SUBCASE("[TextEdit] text drag") {
+ text_edit->set_size(Size2(200, 200));
+ text_edit->set_text("drag test\ndrop here ''");
+ text_edit->grab_click_focus();
+ MessageQueue::get_singleton()->flush();
+
+ // Drag and drop selected text to mouse position.
+ text_edit->select(0, 0, 0, 4);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 11).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 11).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == " test\ndrop here 'drag'");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 15);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 11);
+
+ // Undo.
+ text_edit->undo();
+ CHECK(text_edit->get_text() == "drag test\ndrop here ''");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ // Redo.
+ text_edit->redo();
+ CHECK(text_edit->get_text() == " test\ndrop here 'drag'");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 15);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 11);
+
+ // Hold control when dropping to not delete selected text.
+ text_edit->select(1, 10, 1, 16);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 12).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "'drag'");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_KEY_EVENT(Key::CMD_OR_CTRL);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ SEND_GUI_KEY_UP_EVENT(Key::CMD_OR_CTRL);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' test\ndrop here 'drag'");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 6);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+
+ // Multiple caret drags entire selection.
+ text_edit->select(0, 11, 0, 7, 0);
+ text_edit->add_caret(1, 2);
+ text_edit->select(1, 2, 1, 4, 1);
+ text_edit->add_caret(1, 12);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection(true, 1));
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 12).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "test\nop");
+ // Carets aren't removed from dragging, only dropping.
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 7);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 11);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 2);
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 12);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 9).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 9).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' \ndr heretest\nop 'drag'");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 7);
+
+ // Drop onto same selection should do effectively nothing.
+ text_edit->select(1, 3, 1, 7);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 6).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "here");
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' \ndr heretest\nop 'drag'");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 1);
+ CHECK(text_edit->get_selection_origin_column() == 3);
+
+ // Cannot drag when drag and drop selection is disabled. It becomes regular drag to select.
+ text_edit->set_drag_and_drop_selection_enabled(false);
+ text_edit->select(0, 1, 0, 5);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK_FALSE(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' \ndr heretest\nop 'drag'");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 2);
+ text_edit->set_drag_and_drop_selection_enabled(true);
+
+ // Cancel drag and drop from Escape key.
+ text_edit->select(0, 1, 0, 5);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag");
+ SEND_GUI_KEY_EVENT(Key::ESCAPE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' \ndr heretest\nop 'drag'");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 1);
+
+ // Cancel drag and drop from caret move key input.
+ text_edit->select(0, 1, 0, 5);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag");
+ SEND_GUI_KEY_EVENT(Key::RIGHT);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'drag' \ndr heretest\nop 'drag'");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 5);
+
+ // Cancel drag and drop from text key input.
+ text_edit->select(0, 1, 0, 5);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag");
+ SEND_GUI_KEY_EVENT(Key::A);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "'A' \ndr heretest\nop 'drag'");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 2);
+ }
+
+ SUBCASE("[TextEdit] text drag to another text edit") {
TextEdit *target_text_edit = memnew(TextEdit);
SceneTree::get_singleton()->get_root()->add_child(target_text_edit);
@@ -1292,27 +2517,223 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_text("drag me");
text_edit->select_all();
text_edit->grab_click_focus();
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
MessageQueue::get_singleton()->flush();
- Point2i line_0 = text_edit->get_pos_at_line_column(0, 0);
- line_0.y /= 2;
- SEND_GUI_MOUSE_BUTTON_EVENT(line_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ // Drag text between text edits.
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->is_mouse_over_selection());
- SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_pos_at_line_column(0, 7), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 7).get_center(), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->get_viewport()->gui_is_dragging());
CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag me");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
- line_0 = target_text_edit->get_pos_at_line_column(0, 0);
- line_0.y /= 2;
- line_0.x += 401; // As empty add one.
- SEND_GUI_MOUSE_MOTION_EVENT(line_0, MouseButtonMask::LEFT, Key::NONE);
+ Point2i target_line0 = target_text_edit->get_position() + Point2i(1, target_text_edit->get_line_height() / 2);
+ SEND_GUI_MOUSE_MOTION_EVENT(target_line0, MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 0);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_line0, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(target_text_edit->get_text() == "drag me");
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 7);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 0);
- SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(line_0, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ // Undo is separate per TextEdit.
+ text_edit->undo();
+ CHECK(text_edit->get_text() == "drag me");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ CHECK(target_text_edit->get_text() == "drag me");
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 7);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 0);
+
+ target_text_edit->undo();
+ CHECK(text_edit->get_text() == "drag me");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 7);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ CHECK(target_text_edit->get_text() == "");
+ CHECK_FALSE(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 0);
+
+ // Redo is also separate.
+ text_edit->redo();
+ CHECK(text_edit->get_text() == "");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ CHECK(target_text_edit->get_text() == "");
+ CHECK_FALSE(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ target_text_edit->redo();
CHECK(text_edit->get_text() == "");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
CHECK(target_text_edit->get_text() == "drag me");
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 7);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 0);
+
+ // Hold control to not remove selected text.
+ text_edit->set_text("drag test\ndrop test");
+ MessageQueue::get_singleton()->flush();
+ target_text_edit->select(0, 0, 0, 3, 0);
+ target_text_edit->add_caret(0, 5);
+ text_edit->select(0, 5, 0, 7, 0);
+ text_edit->add_caret(0, 1);
+ text_edit->select(0, 1, 0, 0, 1);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection(true, 0));
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 6).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "d\nte");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_KEY_EVENT(Key::CMD_OR_CTRL);
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ SEND_GUI_KEY_UP_EVENT(Key::CMD_OR_CTRL);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "drag test\ndrop test");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 7);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(target_text_edit->get_text() == "drag md\ntee");
+ CHECK(target_text_edit->get_caret_count() == 1);
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 1);
+ CHECK(target_text_edit->get_caret_column() == 2);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 6);
+
+ // Drop onto selected text deletes the selected text first.
+ text_edit->set_deselect_on_focus_loss_enabled(false);
+ target_text_edit->set_deselect_on_focus_loss_enabled(false);
+ text_edit->remove_secondary_carets();
+ text_edit->select(0, 5, 0, 9);
+ target_text_edit->select(0, 6, 0, 8);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection(true, 0));
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center(), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "test");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "drag \ndrop test");
+ CHECK(target_text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 5);
+ CHECK(target_text_edit->get_text() == "drag mdtest\ntee");
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 11);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 7);
+ text_edit->set_deselect_on_focus_loss_enabled(true);
+ target_text_edit->set_deselect_on_focus_loss_enabled(true);
+
+ // Can drop even when drag and drop selection is disabled.
+ target_text_edit->set_drag_and_drop_selection_enabled(false);
+ text_edit->select(0, 4, 0, 5);
+ target_text_edit->deselect();
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 4).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == " ");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 7).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "drag\ndrop test");
+ CHECK(target_text_edit->get_text() == "drag md test\ntee");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 8);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 7);
+ target_text_edit->set_drag_and_drop_selection_enabled(true);
+
+ // Cannot drop when not editable.
+ target_text_edit->set_editable(false);
+ text_edit->select(0, 1, 0, 4);
+ target_text_edit->deselect();
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "rag");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "drag\ndrop test");
+ CHECK(target_text_edit->get_text() == "drag md test\ntee");
+ CHECK(text_edit->has_selection());
+ CHECK_FALSE(target_text_edit->has_selection());
+ target_text_edit->set_editable(true);
+
+ // Can drag when not editable, but text will not be removed.
+ text_edit->set_editable(false);
+ text_edit->select(0, 0, 0, 4);
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->is_mouse_over_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 7).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ CHECK(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_viewport()->gui_get_drag_data() == "drag");
+ CHECK(text_edit->has_selection());
+ SEND_GUI_MOUSE_MOTION_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 4).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(target_text_edit->get_position() + target_text_edit->get_rect_at_line_column(0, 4).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
+ CHECK_FALSE(text_edit->get_viewport()->gui_is_dragging());
+ CHECK(text_edit->get_text() == "drag\ndrop test");
+ CHECK(target_text_edit->get_text() == "dragdrag md test\ntee");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ CHECK(target_text_edit->has_selection());
+ CHECK(target_text_edit->get_caret_line() == 0);
+ CHECK(target_text_edit->get_caret_column() == 8);
+ CHECK(target_text_edit->get_selection_origin_line() == 0);
+ CHECK(target_text_edit->get_selection_origin_column() == 4);
+ text_edit->set_editable(true);
memdelete(target_text_edit);
}
@@ -1324,44 +2745,41 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] overridable actions") {
+ DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton());
+
SIGNAL_WATCH(text_edit, "text_set");
SIGNAL_WATCH(text_edit, "text_changed");
SIGNAL_WATCH(text_edit, "lines_edited_from");
SIGNAL_WATCH(text_edit, "caret_changed");
- Array args1;
- args1.push_back(0);
- args1.push_back(0);
- Array lines_edited_args;
- lines_edited_args.push_back(args1);
+ Array lines_edited_args = build_array(build_array(0, 0));
SUBCASE("[TextEdit] backspace") {
text_edit->set_text("this is\nsome\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Cannot backspace at start of text.
text_edit->backspace();
MessageQueue::get_singleton()->flush();
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Backspace at start of line removes the line.
text_edit->set_caret_line(2);
text_edit->set_caret_column(0);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(2, 1));
- ((Array)lines_edited_args[0])[0] = 2;
- ((Array)lines_edited_args[0])[1] = 1;
text_edit->backspace();
MessageQueue::get_singleton()->flush();
-
CHECK(text_edit->get_text() == "this is\nsome");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 4);
@@ -1369,10 +2787,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[0] = 1;
+ // Backspace removes a character.
+ lines_edited_args = build_array(build_array(1, 1));
text_edit->backspace();
MessageQueue::get_singleton()->flush();
-
CHECK(text_edit->get_text() == "this is\nsom");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 3);
@@ -1380,11 +2798,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Backspace when text is selected removes the selection.
text_edit->end_complex_operation();
text_edit->select(1, 0, 1, 3);
text_edit->backspace();
MessageQueue::get_singleton()->flush();
-
CHECK(text_edit->get_text() == "this is\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
@@ -1392,11 +2810,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Cannot backspace if not editable.
text_edit->set_editable(false);
text_edit->backspace();
text_edit->set_editable(true);
MessageQueue::get_singleton()->flush();
-
CHECK(text_edit->get_text() == "this is\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
@@ -1404,6 +2822,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Undo restores text to the previous end of complex operation.
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "this is\nsom");
@@ -1412,98 +2831,736 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is\n");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // See ui_text_backspace for more backspace tests.
}
SUBCASE("[TextEdit] cut") {
+ // Cut without a selection removes the entire line.
text_edit->set_text("this is\nsome\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(6);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0));
- ERR_PRINT_OFF;
text_edit->cut();
MessageQueue::get_singleton()->flush();
- ERR_PRINT_ON; // Can't check display server content.
-
- ((Array)lines_edited_args[0])[0] = 1;
+ CHECK(DS->clipboard_get() == "this is\n");
CHECK(text_edit->get_text() == "some\n");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_caret_column() == 3); // In the default font, this is the same position.
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[0] = 0;
- ((Array)lines_edited_args[0])[1] = 1;
+ // Undo restores the cut text.
text_edit->undo();
MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\n");
CHECK(text_edit->get_text() == "this is\nsome\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 6);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
- SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 0;
+ // Redo.
text_edit->redo();
MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\n");
CHECK(text_edit->get_text() == "some\n");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_caret_column() == 3);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Cut with a selection removes just the selection.
text_edit->set_text("this is\nsome\n");
+ text_edit->select(0, 5, 0, 7);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
- ((Array)lines_edited_args[0])[0] = 0;
- text_edit->select(0, 5, 0, 7);
- ERR_PRINT_OFF;
SEND_GUI_ACTION("ui_cut");
CHECK(text_edit->get_viewport()->is_input_handled());
MessageQueue::get_singleton()->flush();
- ERR_PRINT_ON; // Can't check display server content.
+ CHECK(DS->clipboard_get() == "is");
CHECK(text_edit->get_text() == "this \nsome\n");
+ CHECK_FALSE(text_edit->get_caret_line());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 5);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Cut does not change the text if not editable. Text is still added to clipboard.
+ text_edit->set_text("this is\nsome\n");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(5);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+
text_edit->set_editable(false);
text_edit->cut();
MessageQueue::get_singleton()->flush();
text_edit->set_editable(true);
- CHECK(text_edit->get_text() == "this \nsome\n");
+ CHECK(DS->clipboard_get() == "this is\n");
+ CHECK(text_edit->get_text() == "this is\nsome\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 5);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Cut line with multiple carets.
+ text_edit->set_text("this is\nsome\n");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(3);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(0, 4);
+ text_edit->add_caret(2, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0), build_array(1, 0));
+
+ text_edit->cut();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\n\n");
+ CHECK(text_edit->get_text() == "some");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 2); // In the default font, this is the same position.
+ // The previous caret at index 1 was merged.
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 3); // In the default font, this is the same position.
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->remove_secondary_carets();
+
+ // Cut on the only line removes the contents.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->cut();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "some\n");
+ CHECK(text_edit->get_text() == "");
+ CHECK(text_edit->get_line_count() == 1);
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Cut empty line.
+ text_edit->cut();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "\n");
+ CHECK(text_edit->get_text() == "");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ // These signals are emitted even if there is no change.
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Cut multiple lines, in order.
+ text_edit->set_text("this is\nsome\ntext to\nbe\n\ncut");
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(7);
+ text_edit->add_caret(3, 0);
+ text_edit->add_caret(0, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0), build_array(3, 2), build_array(2, 1));
+
+ text_edit->cut();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\ntext to\nbe\n");
+ CHECK(text_edit->get_text() == "some\n\ncut");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->remove_secondary_carets();
+
+ // Cut multiple selections, in order. Ignores regular carets.
+ text_edit->set_text("this is\nsome\ntext to\nbe\n\ncut");
+ text_edit->add_caret(3, 0);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(2, 0);
+ text_edit->select(1, 0, 1, 2, 0);
+ text_edit->select(3, 0, 4, 0, 1);
+ text_edit->select(0, 5, 0, 3, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 1), build_array(4, 3), build_array(0, 0));
+
+ text_edit->cut();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "s \nso\nbe\n");
+ CHECK(text_edit->get_text() == "thiis\nme\ntext to\n\ncut");
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 3);
+ CHECK(text_edit->get_caret_line(3) == 2);
+ CHECK(text_edit->get_caret_column(3) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SUBCASE("[TextEdit] copy") {
- // TODO: Cannot test need display server support.
+ text_edit->set_text("this is\nsome\ntest\n\ntext");
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+
+ // Copy selected text.
+ text_edit->select(0, 0, 1, 2, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ DS->clipboard_set_primary("");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\nso");
+ CHECK(DS->clipboard_get_primary() == "");
+ CHECK(text_edit->get_text() == "this is\nsome\ntest\n\ntext");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 0);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 2);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Copy with GUI action.
+ text_edit->select(0, 0, 0, 2, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_ACTION("ui_copy");
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "th");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Can copy even if not editable.
+ text_edit->select(2, 4, 1, 2, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->set_editable(false);
+ text_edit->copy();
+ text_edit->set_editable(true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "me\ntest");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ text_edit->deselect();
+
+ // Copy full line when there is no selection.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\n");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Copy empty line.
+ text_edit->set_caret_line(3);
+ text_edit->set_caret_column(0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "\n");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ text_edit->deselect();
+
+ // Copy full line with multiple carets on that line only copies once.
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ text_edit->add_caret(1, 0);
+ text_edit->add_caret(1, 4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "some\n");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ text_edit->remove_secondary_carets();
+
+ // Copy selected text from all selections with `\n` in between, in order. Ignore regular carets.
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(4, 0);
+ text_edit->add_caret(0, 4);
+ text_edit->add_caret(1, 0);
+ text_edit->select(1, 3, 2, 4, 0);
+ text_edit->select(4, 4, 4, 0, 1);
+ text_edit->select(0, 5, 0, 4, 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == " \ne\ntest\ntext");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Copy multiple lines with multiple carets, in order.
+ text_edit->set_caret_line(3);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(4, 2);
+ text_edit->add_caret(0, 4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->copy();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "this is\n\ntext\n");
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] paste") {
- // TODO: Cannot test need display server support.
+ // Paste text from clipboard at caret.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 1));
+ DS->clipboard_set("paste");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste");
+ CHECK(text_edit->get_text() == "this is\nsopasteme\n\ntext");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 7);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste");
+ CHECK(text_edit->get_text() == "this is\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste");
+ CHECK(text_edit->get_text() == "this is\nsopasteme\n\ntext");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 7);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste on empty line. Use GUI action.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(2, 2));
+ DS->clipboard_set("paste2");
+
+ SEND_GUI_ACTION("ui_paste");
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste2");
+ CHECK(text_edit->get_text() == "this is\nsome\npaste2\ntext");
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 6);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste removes selection before pasting.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->select(0, 5, 1, 3);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0), build_array(0, 0));
+ DS->clipboard_set("paste");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste");
+ CHECK(text_edit->get_text() == "this pastee\n\ntext");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 10);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste multiple lines.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 3));
+ DS->clipboard_set("multi\n\nline\npaste");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "multi\n\nline\npaste");
+ CHECK(text_edit->get_text() == "tmulti\n\nline\npastehis is\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 3);
+ CHECK(text_edit->get_caret_column() == 5);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste full line after copying it.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 2));
+ DS->clipboard_set("");
+ text_edit->copy();
+ text_edit->set_caret_column(3);
+ CHECK(DS->clipboard_get() == "some\n");
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "some\n");
+ CHECK(text_edit->get_text() == "this is\nsome\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 2);
+ CHECK(text_edit->get_caret_column() == 3);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Do not paste as line since it wasn't copied.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1));
+ DS->clipboard_set("paste\n");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste\n");
+ CHECK(text_edit->get_text() == "thispaste\n is\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste text at each caret.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ text_edit->add_caret(3, 4);
+ text_edit->add_caret(0, 4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(2, 3), build_array(5, 6));
+ DS->clipboard_set("paste\ntest");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste\ntest");
+ CHECK(text_edit->get_text() == "thispaste\ntest is\nsopaste\ntestme\n\ntextpaste\ntest");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(0) == 3);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 6);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->remove_secondary_carets();
+
+ // Paste line per caret when the amount of lines is equal to the number of carets.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(2);
+ text_edit->add_caret(3, 4);
+ text_edit->add_caret(0, 4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1), build_array(3, 3));
+ DS->clipboard_set("paste\ntest\n1");
+
+ text_edit->paste();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "paste\ntest\n1");
+ CHECK(text_edit->get_text() == "thispaste is\nsotestme\n\ntext1");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 6);
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 9);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->remove_secondary_carets();
+
+ // Cannot paste when not editable.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ DS->clipboard_set("no paste");
+
+ text_edit->set_editable(false);
+ text_edit->paste();
+ text_edit->set_editable(true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "no paste");
+ CHECK(text_edit->get_text() == "this is\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] paste primary") {
- // TODO: Cannot test need display server support.
+ // Set size for mouse input.
+ text_edit->set_size(Size2(200, 200));
+
+ text_edit->grab_focus();
+ DS->clipboard_set("");
+ DS->clipboard_set_primary("");
+ CHECK(DS->clipboard_get_primary() == "");
+
+ // Select text with mouse to put into primary clipboard.
+ text_edit->set_text("this is\nsome\n\ntext");
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 2).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 3).get_center() + Point2i(2, 0), MouseButtonMask::LEFT, Key::NONE);
+ SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
+ CHECK(DS->clipboard_get() == "");
+ CHECK(DS->clipboard_get_primary() == "is is\nsom");
+ CHECK(text_edit->get_text() == "this is\nsome\n\ntext");
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "is is\nsom");
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 2);
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 3);
+ SIGNAL_CHECK_FALSE("text_set");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Middle click to paste at mouse.
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 4));
+
+ SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(3, 2).get_center() + Point2i(2, 0), MouseButton::MIDDLE, MouseButtonMask::MIDDLE, Key::NONE);
+ CHECK(DS->clipboard_get_primary() == "is is\nsom");
+ CHECK(text_edit->get_text() == "this is\nsome\n\nteis is\nsomxt");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 4);
+ CHECK(text_edit->get_caret_column() == 3);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste at mouse position if there is only one caret.
+ text_edit->set_text("this is\nsome\n\ntext");
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::NONE, Key::NONE);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ DS->clipboard_set_primary("paste");
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->paste_primary_clipboard();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get_primary() == "paste");
+ CHECK(text_edit->get_text() == "tpastehis is\nsome\n\ntext");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 6);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Paste at all carets if there are multiple carets.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(2, 0);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButtonMask::NONE, Key::NONE);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ DS->clipboard_set_primary("paste");
+ lines_edited_args = build_array(build_array(1, 1), build_array(2, 2));
+
+ text_edit->paste_primary_clipboard();
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get_primary() == "paste");
+ CHECK(text_edit->get_text() == "this is\npastesome\npaste\ntext");
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Cannot paste if not editable.
+ text_edit->set_text("this is\nsome\n\ntext");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(1, 3).get_center() + Point2i(2, 0), MouseButtonMask::NONE, Key::NONE);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ DS->clipboard_set("no paste");
+
+ text_edit->set_editable(false);
+ text_edit->paste_primary_clipboard();
+ text_edit->set_editable(true);
+ MessageQueue::get_singleton()->flush();
+ CHECK(DS->clipboard_get() == "no paste");
+ CHECK(text_edit->get_text() == "this is\nsome\n\ntext");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
}
SIGNAL_UNWATCH(text_edit, "text_set");
@@ -1512,60 +3569,77 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_UNWATCH(text_edit, "caret_changed");
}
- // Add undo / redo tests?
SUBCASE("[TextEdit] input") {
SIGNAL_WATCH(text_edit, "text_set");
SIGNAL_WATCH(text_edit, "text_changed");
SIGNAL_WATCH(text_edit, "lines_edited_from");
SIGNAL_WATCH(text_edit, "caret_changed");
- Array args1;
- args1.push_back(0);
- args1.push_back(0);
- Array lines_edited_args;
- lines_edited_args.push_back(args1);
+ Array lines_edited_args = build_array(build_array(0, 0));
SUBCASE("[TextEdit] ui_text_newline_above") {
text_edit->set_text("this is some test text.\nthis is some test text.");
- text_edit->select(0, 0, 0, 4);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(1, 4);
- text_edit->select(1, 0, 1, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(0);
- args2.push_back(1);
- lines_edited_args.push_front(args2);
+ // Insert new line above.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret(1, 4);
+ CHECK(text_edit->get_caret_count() == 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(2, 3));
- ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION("ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some test text.\nthis is some test text.");
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_caret_line(1);
text_edit->set_caret_column(4);
-
- text_edit->set_caret_line(3, false, true, 0, 1);
+ text_edit->set_caret_line(3, false, true, -1, 1);
text_edit->set_caret_column(4, false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
@@ -1574,31 +3648,57 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION("ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 4);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 3);
CHECK(text_edit->get_caret_column(1) == 4);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- ((Array)lines_edited_args[0])[0] = 2;
- ((Array)lines_edited_args[0])[1] = 3;
+ // Works on first line, empty lines, and only happens at caret for selections.
+ text_edit->select(1, 10, 0, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(4, 5));
SEND_GUI_ACTION("ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "\n\nthis is some test text.\n\n\nthis is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 4);
CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Insert multiple new lines above from one line.
+ text_edit->set_text("test");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 3);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(1, 2));
+
+ SEND_GUI_ACTION("ui_text_newline_above");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "\n\ntest");
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1606,34 +3706,55 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SUBCASE("[TextEdit] ui_text_newline_blank") {
text_edit->set_text("this is some test text.\nthis is some test text.");
- text_edit->select(0, 0, 0, 4);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(1, 4);
- text_edit->select(1, 0, 1, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
- SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(1);
- args2.push_back(2);
- lines_edited_args.push_front(args2);
+ // Insert new line below.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret(1, 4);
+ CHECK(text_edit->get_caret_count() == 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(2, 3));
- ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION("ui_text_newline_blank");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some test text.\nthis is some test text.");
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(0));
CHECK(text_edit->get_caret_line(1) == 3);
CHECK(text_edit->get_caret_column(1) == 0);
CHECK_FALSE(text_edit->has_selection(1));
@@ -1641,75 +3762,119 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_newline_blank");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 3);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+
+ // Insert multiple new lines below from one line.
+ text_edit->set_text("test");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 3);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 1), build_array(0, 1));
+
+ SEND_GUI_ACTION("ui_text_newline_blank");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "test\n\n");
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SUBCASE("[TextEdit] ui_text_newline") {
text_edit->set_text("this is some test text.\nthis is some test text.");
- text_edit->select(0, 0, 0, 4);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(1, 4);
- text_edit->select(1, 0, 1, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(1);
- args2.push_back(1);
- lines_edited_args.push_front(args2);
- lines_edited_args.push_front(args2.duplicate());
- ((Array)lines_edited_args[1])[1] = 2;
-
- lines_edited_args.push_back(lines_edited_args[2].duplicate());
- ((Array)lines_edited_args[3])[1] = 1;
+ // Insert new line at caret.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret(1, 4);
+ CHECK(text_edit->get_caret_count() == 2);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ // Lines edited: deletion, insert line, insert line.
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 1), build_array(2, 3));
SEND_GUI_ACTION("ui_text_newline");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "\n is some test text.\nthis\n is some test text.");
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 3);
CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some test text.\nthis is some test text.");
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\n is some test text.\nthis\n is some test text.");
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_newline");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "\n is some test text.\nthis\n is some test text.");
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 3);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -1717,255 +3882,399 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] ui_text_backspace_all_to_left") {
- text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
- text_edit->select(1, 0, 1, 4);
- text_edit->set_caret_line(1);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(3, 4);
- text_edit->select(3, 0, 3, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
- MessageQueue::get_singleton()->flush();
-
Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL);
InputMap::get_singleton()->action_add_event("ui_text_backspace_all_to_left", tmpevent);
+ text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(3);
- args2.push_back(3);
- lines_edited_args.push_front(args2);
-
- // With selection should be a normal backspace.
- ((Array)lines_edited_args[1])[0] = 1;
- ((Array)lines_edited_args[1])[1] = 1;
+ // Remove all text to the left.
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(5);
+ text_edit->add_caret(1, 2);
+ text_edit->add_caret(1, 8);
+ lines_edited_args = build_array(build_array(1, 1));
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
SEND_GUI_ACTION("ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
+ CHECK(text_edit->get_text() == "\nsome test text.\n\nthis is some test text.");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- CHECK(text_edit->get_caret_line(1) == 3);
- CHECK(text_edit->get_caret_column(1) == 0);
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 8);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[1] = 2;
- ((Array)lines_edited_args[1])[1] = 0;
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\nsome test text.\n\nthis is some test text.");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 1);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Acts as a normal backspace with selections.
+ text_edit->select(1, 5, 1, 9, 0);
+ text_edit->add_caret(3, 4);
+ text_edit->select(3, 7, 3, 4, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 3), build_array(1, 1));
- // Start of line should also be a normal backspace.
SEND_GUI_ACTION("ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "\nsome text.\n\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Acts as a normal backspace when at the start of a line.
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 2), build_array(1, 0));
+ SEND_GUI_ACTION("ui_text_backspace_all_to_left");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "some text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_caret_column(text_edit->get_line(0).length());
text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
+ CHECK(text_edit->get_text() == "some text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == text_edit->get_line(0).length());
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
- ((Array)lines_edited_args[1])[0] = 0;
+ // Remove entire line content when at the end of the line.
+ lines_edited_args = build_array(build_array(1, 1), build_array(0, 0));
SEND_GUI_ACTION("ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->remove_secondary_carets();
+
+ // Removing newline effectively happens after removing text.
+ text_edit->set_text("test\nlines");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(1, 4);
+
+ SEND_GUI_ACTION("ui_text_backspace_all_to_left");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "tests");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ text_edit->remove_secondary_carets();
+
+ // Removing newline effectively happens after removing text, reverse caret order.
+ text_edit->set_text("test\nlines");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(1, 0);
+
+ SEND_GUI_ACTION("ui_text_backspace_all_to_left");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "tests");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ text_edit->remove_secondary_carets();
InputMap::get_singleton()->action_erase_event("ui_text_backspace_all_to_left", tmpevent);
}
SUBCASE("[TextEdit] ui_text_backspace_word") {
text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
- text_edit->select(1, 0, 1, 4);
- text_edit->set_caret_line(1);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(3, 4);
- text_edit->select(3, 0, 3, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
- SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(3);
- args2.push_back(3);
- lines_edited_args.push_front(args2);
-
- // With selection should be a normal backspace.
- ((Array)lines_edited_args[1])[0] = 1;
- ((Array)lines_edited_args[1])[1] = 1;
+ // Acts as a normal backspace with selections.
+ text_edit->select(1, 8, 1, 15);
+ text_edit->add_caret(3, 6);
+ text_edit->select(3, 10, 3, 6, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 3), build_array(1, 1));
SEND_GUI_ACTION("ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "\nthis is st text.\n\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 3);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 8);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 6);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->end_complex_operation();
- ((Array)lines_edited_args[0])[1] = 2;
- ((Array)lines_edited_args[1])[1] = 0;
+ lines_edited_args = build_array(build_array(3, 2), build_array(1, 0));
// Start of line should also be a normal backspace.
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
SEND_GUI_ACTION("ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ // FIXME: Remove after GH-77101 is fixed.
+ text_edit->start_action(TextEdit::ACTION_NONE);
+
+ // Remove text to the start of the word to the left of the caret.
text_edit->set_caret_column(text_edit->get_line(0).length());
- text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
+ text_edit->set_caret_column(12, false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
-
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
- ((Array)lines_edited_args[1])[0] = 0;
+ lines_edited_args = build_array(build_array(1, 1), build_array(0, 0));
SEND_GUI_ACTION("ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test \n is some test ");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 14);
+ CHECK(text_edit->get_text() == "this is st \nthis ime t text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 11);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 9);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 16);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 14);
+ CHECK(text_edit->get_caret_column(1) == 12);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is st \nthis ime t text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 11);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 9);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- }
- SUBCASE("[TextEdit] ui_text_backspace_word same line") {
- text_edit->set_text("test test test");
- text_edit->set_caret_column(4);
- text_edit->add_caret(0, 9);
- text_edit->add_caret(0, 15);
+ // Removing newline effectively happens after removing text.
+ text_edit->set_text("test\nlines");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(1, 4);
- // For the second caret.
- Array args2;
- args2.push_back(0);
- lines_edited_args.push_front(args2);
+ SEND_GUI_ACTION("ui_text_backspace_word");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "tests");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ text_edit->remove_secondary_carets();
- // For the third caret.
- Array args3;
- args2.push_back(0);
- lines_edited_args.push_front(args2);
+ // Removing newline effectively happens after removing text, reverse caret order.
+ text_edit->set_text("test\nlines");
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(1, 0);
- CHECK(text_edit->get_caret_count() == 3);
- MessageQueue::get_singleton()->flush();
+ SEND_GUI_ACTION("ui_text_backspace_word");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "tests");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ text_edit->remove_secondary_carets();
+ }
+ SUBCASE("[TextEdit] ui_text_backspace_word same line") {
+ text_edit->set_text("test longwordtest test");
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Multiple carets on the same line is handled.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 11);
+ text_edit->add_caret(0, 15);
+ text_edit->add_caret(0, 9);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
+
SEND_GUI_ACTION("ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " st test");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 0);
CHECK(text_edit->get_caret_column(1) == 1);
- CHECK_FALSE(text_edit->has_selection(1));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- CHECK(text_edit->get_caret_line(2) == 0);
- CHECK(text_edit->get_caret_column(2) == 2);
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test longwordtest test");
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 11);
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 15);
+ CHECK_FALSE(text_edit->has_selection(3));
+ CHECK(text_edit->get_caret_line(3) == 0);
+ CHECK(text_edit->get_caret_column(3) == 9);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " st test");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 1);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1973,130 +4282,267 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SUBCASE("[TextEdit] ui_text_backspace") {
text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
- text_edit->select(1, 0, 1, 4);
- text_edit->set_caret_line(1);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(3, 4);
- text_edit->select(3, 0, 3, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
- SIGNAL_DISCARD("caret_changed");
-
- // For the second caret.
- Array args2;
- args2.push_back(3);
- args2.push_back(3);
- lines_edited_args.push_front(args2);
- // With selection should be a normal backspace.
- ((Array)lines_edited_args[1])[0] = 1;
- ((Array)lines_edited_args[1])[1] = 1;
+ // Remove selected text when there are selections.
+ text_edit->select(1, 0, 1, 4);
+ text_edit->add_caret(3, 4);
+ text_edit->select(3, 5, 3, 2, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 3), build_array(1, 1));
SEND_GUI_ACTION("ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "\n is some test text.\n\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Undo remove selection.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 3);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK(text_edit->get_selection_origin_line(1) == 3);
+ CHECK(text_edit->get_selection_origin_column(1) == 5);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo remove selection.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\n is some test text.\n\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 2);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[1] = 2;
- ((Array)lines_edited_args[1])[1] = 0;
+ // Remove the newline when at start of line.
+ text_edit->set_caret_column(0, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(3, 2), build_array(1, 0));
- // Start of line should also be a normal backspace.
SEND_GUI_ACTION("ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Undo remove newline.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "\n is some test text.\n\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo remove newline.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does not work if not editable.
text_edit->set_caret_column(text_edit->get_line(0).length());
- text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
+ text_edit->set_caret_column(15, false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == text_edit->get_line(0).length());
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
- ((Array)lines_edited_args[1])[0] = 0;
+ // FIXME: Remove after GH-77101 is fixed.
+ text_edit->start_action(TextEdit::ACTION_NONE);
+
+ // Backspace removes character to the left.
+ lines_edited_args = build_array(build_array(1, 1), build_array(0, 0));
SEND_GUI_ACTION("ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text\n is some test text");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 18);
+ CHECK(text_edit->get_text() == " is some test text\nthis some testtext.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 18);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 14);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Backspace another character without changing caret.
+ SEND_GUI_ACTION("ui_text_backspace");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == " is some test tex\nthis some testext.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 17);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 13);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Undo both backspaces.
+ lines_edited_args = build_array(build_array(1, 1), build_array(0, 0), build_array(1, 1), build_array(0, 0));
+
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 19);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 18);
+ CHECK(text_edit->get_caret_column(1) == 15);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo both backspaces.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test tex\nthis some testext.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 17);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 13);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- // Select the entire text, from right to left
- text_edit->select(0, 18, 0, 0);
+ // Backspace with multiple carets that will overlap.
+ text_edit->remove_secondary_carets();
text_edit->set_caret_line(0);
- text_edit->set_caret_column(0);
-
- text_edit->select(1, 18, 1, 0, 1);
- text_edit->set_caret_line(1, false, true, 0, 1);
- text_edit->set_caret_column(0, false, 1);
+ text_edit->set_caret_column(8);
+ text_edit->add_caret(0, 7);
+ text_edit->add_caret(0, 9);
MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0), build_array(0, 0));
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
+ SEND_GUI_ACTION("ui_text_backspace");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == " is sotest tex\nthis some testext.");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 6);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Select each line of text, from right to left. Remove selection to column 0.
+ text_edit->select(0, text_edit->get_line(0).length(), 0, 0);
+ text_edit->add_caret(1, 0);
+ text_edit->select(1, text_edit->get_line(1).length(), 1, 0, 1);
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 1), build_array(0, 0));
SEND_GUI_ACTION("ui_text_backspace");
CHECK(text_edit->get_text() == "\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Backspace at start of first line does nothing.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_ACTION("ui_text_backspace");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "\n");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 0);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_delete_all_to_right") {
@@ -2104,101 +4550,138 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
InputMap::get_singleton()->action_add_event("ui_text_delete_all_to_right", tmpevent);
text_edit->set_text("this is some test text.\nthis is some test text.\n");
- text_edit->select(0, 0, 0, 4);
- text_edit->set_caret_line(0);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(1, 4);
- text_edit->select(1, 0, 1, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
- SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(1);
- args2.push_back(1);
- lines_edited_args.push_front(args2);
+ // Remove all text to right of caret.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(18);
+ text_edit->add_caret(0, 16);
+ text_edit->add_caret(0, 20);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0));
- // With selection should be a normal delete.
SEND_GUI_ACTION("ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "this is some tes\nthis is some test text.\n");
+ CHECK(text_edit->get_caret_count() == 1);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 16);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 0);
+ // Undo.
+ lines_edited_args = build_array(build_array(0, 0));
+
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some test text.\nthis is some test text.\n");
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 18);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 16);
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 20);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- // End of line should not do anything.
- text_edit->set_caret_column(text_edit->get_line(0).length());
- text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
+ // Redo.
+ text_edit->redo();
MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is some tes\nthis is some test text.\n");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 16);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
+ // Acts as a normal delete with selections.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 8, 1, 4, 1);
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1));
SEND_GUI_ACTION("ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
+ CHECK(text_edit->get_text() == " is some tes\nthissome test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Does nothing when caret is at end of line.
+ text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_ACTION("ui_text_delete_all_to_right");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == " is some tes\nthissome test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == text_edit->get_line(0).length());
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Does not work if not editable.
text_edit->set_caret_column(0);
text_edit->set_caret_column(0, false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " is some tes\nthissome test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ // Delete entire line.
SEND_GUI_ACTION("ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_text() == "\n\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -2210,302 +4693,589 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_caret_mid_grapheme_enabled(true);
CHECK(text_edit->is_caret_mid_grapheme_enabled());
- text_edit->set_text("this ffi some test text.\n\nthis ffi some test text.\n");
- text_edit->select(0, 0, 0, 4);
- text_edit->set_caret_line(0);
- text_edit->set_caret_column(4);
-
- text_edit->add_caret(2, 4);
- text_edit->select(2, 0, 2, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
+ text_edit->set_text("this is some test text.\n\nthis is some test text.\n");
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(2);
- args2.push_back(2);
- lines_edited_args.push_front(args2);
+ // Acts as a normal delete with selections.
+ text_edit->select(0, 8, 0, 15);
+ text_edit->add_caret(2, 6);
+ text_edit->select(2, 10, 2, 6, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(2, 2));
- // With selection should be a normal delete.
SEND_GUI_ACTION("ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n\n ffi some test text.\n");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "this is st text.\n\nthis ime test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 8);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 6);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- // With selection should be a normal delete.
- ((Array)lines_edited_args[0])[0] = 3;
- ((Array)lines_edited_args[1])[0] = 1;
+ // Removes newlines when at end of line.
text_edit->set_caret_column(text_edit->get_line(0).length());
text_edit->set_caret_column(text_edit->get_line(2).length(), false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0), build_array(2, 1));
SEND_GUI_ACTION("ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
-
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == text_edit->get_line(0).length());
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
- CHECK_FALSE(text_edit->has_selection(0));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[1])[0] = 0;
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
+ // Does not work if not editable.
text_edit->set_caret_column(0);
- text_edit->set_caret_column(0, false, 1);
+ text_edit->set_caret_column(10, false, 1);
MessageQueue::get_singleton()->flush();
-
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 10);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ // FIXME: Remove after GH-77101 is fixed.
+ text_edit->start_action(TextEdit::ACTION_NONE);
+
+ // Delete to the end of the word right of the caret.
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1));
+
SEND_GUI_ACTION("ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " some test text.\n some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " is st text.\nthis ime t text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 10);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Undo.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "this is st text.\nthis ime test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 10);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is st text.\nthis ime t text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 10);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- }
- SUBCASE("[TextEdit] ui_text_delete") {
- text_edit->set_caret_mid_grapheme_enabled(true);
- CHECK(text_edit->is_caret_mid_grapheme_enabled());
+ // Delete one word with multiple carets.
+ text_edit->remove_secondary_carets();
+ text_edit->set_text("onelongword test");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(6);
+ text_edit->add_caret(0, 9);
+ text_edit->add_caret(0, 3);
+ lines_edited_args = build_array(build_array(0, 0));
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
- text_edit->set_text("this ffi some test text.\nthis ffi some test text.");
- text_edit->select(0, 0, 0, 4);
+ SEND_GUI_ACTION("ui_text_delete_word");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "one test");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 3);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Removing newline effectively happens after removing text.
+ text_edit->set_text("test\nlines");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(2);
+ text_edit->add_caret(0, 4);
+
+ SEND_GUI_ACTION("ui_text_delete_word");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "telines");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ text_edit->remove_secondary_carets();
+
+ // Removing newline effectively happens after removing text, reverse caret order.
+ text_edit->set_text("test\nlines");
text_edit->set_caret_line(0);
text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 2);
- text_edit->add_caret(1, 4);
- text_edit->select(1, 0, 1, 4, 1);
- CHECK(text_edit->get_caret_count() == 2);
+ SEND_GUI_ACTION("ui_text_delete_word");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_text() == "telines");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ text_edit->remove_secondary_carets();
+ }
+ SUBCASE("[TextEdit] ui_text_delete_word same line") {
+ text_edit->set_text("test longwordtest test");
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(1);
- args2.push_back(1);
- lines_edited_args.push_front(args2);
+ // Multiple carets on the same line is handled.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret(0, 11);
+ text_edit->add_caret(0, 15);
+ text_edit->add_caret(0, 9);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
- // With selection should be a normal delete.
- SEND_GUI_ACTION("ui_text_delete");
+ SEND_GUI_ACTION("ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " long test");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 1);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 5);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- // With selection should be a normal delete.
- lines_edited_args.remove_at(0);
- ((Array)lines_edited_args[0])[0] = 1;
- text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
- text_edit->set_caret_column(text_edit->get_line(0).length());
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0));
+
+ text_edit->undo();
MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "test longwordtest test");
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 11);
+ CHECK_FALSE(text_edit->has_selection(2));
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 15);
+ CHECK_FALSE(text_edit->has_selection(3));
+ CHECK(text_edit->get_caret_line(3) == 0);
+ CHECK(text_edit->get_caret_column(3) == 9);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " long test");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ }
+
+ SUBCASE("[TextEdit] ui_text_delete") {
+ text_edit->set_caret_mid_grapheme_enabled(true);
+ CHECK(text_edit->is_caret_mid_grapheme_enabled());
+
+ text_edit->set_text("this is some test text.\n\nthis is some test text.\n");
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Remove selected text when there are selections.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret(2, 2);
+ text_edit->select(2, 5, 2, 2, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(0, 0), build_array(2, 2));
+
SEND_GUI_ACTION("ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text. ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 20);
+ CHECK(text_edit->get_text() == " is some test text.\n\nthis some test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- // Caret should be removed due to column preservation.
- CHECK(text_edit->get_caret_count() == 1);
-
- // Lets add it back.
- text_edit->set_caret_column(0);
- text_edit->add_caret(0, 20);
+ // Undo remove selection.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 5);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
- ((Array)lines_edited_args[0])[0] = 0;
- lines_edited_args.push_back(args2);
- ((Array)lines_edited_args[1])[0] = 0;
- ((Array)lines_edited_args[1])[1] = 0;
+ // Redo remove selection.
+ text_edit->redo();
MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\n\nthis some test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- SIGNAL_DISCARD("text_set");
- SIGNAL_DISCARD("text_changed");
- SIGNAL_DISCARD("lines_edited_from");
+ // Remove newline when at end of line.
+ text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(2).length(), false, 1);
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
+ lines_edited_args = build_array(build_array(1, 0), build_array(2, 1));
- text_edit->set_editable(false);
SEND_GUI_ACTION("ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text. ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 19);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 20);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- CHECK(text_edit->get_caret_line(1) == 0);
+ // Undo remove newline.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\n\nthis some test text.\n");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 19);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 20);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo remove newline.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 19);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 20);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Does not work if not editable.
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_column(15, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ text_edit->set_editable(false);
+ SEND_GUI_ACTION("ui_text_delete");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ // FIXME: Remove after GH-77101 is fixed.
text_edit->start_action(TextEdit::EditAction::ACTION_NONE);
+ // Delete removes character to the right.
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1));
+
SEND_GUI_ACTION("ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "ffi some test text.ffi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_text() == "is some test text.\nthis some test ext.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- CHECK(text_edit->get_caret_line(1) == 0);
- CHECK(text_edit->get_caret_column(1) == 19);
+ // Delete another character without changing caret.
+ SEND_GUI_ACTION("ui_text_delete");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "s some test text.\nthis some test xt.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
- SIGNAL_CHECK("caret_changed", empty_signal_args);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- text_edit->start_action(TextEdit::EditAction::ACTION_NONE);
+ // Undo both deletes.
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1), build_array(0, 0), build_array(1, 1));
- SEND_GUI_ACTION("ui_text_delete");
- CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "fi some test text.fi some test text.");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == " is some test text.\nthis some test text.");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
- CHECK(text_edit->get_caret_line(1) == 0);
- CHECK(text_edit->get_caret_column(1) == 18);
+ // Redo both deletes.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "s some test text.\nthis some test xt.");
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
- SIGNAL_CHECK("caret_changed", empty_signal_args);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 15);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Delete at end of last line does nothing.
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(18);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_ACTION("ui_text_delete");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "s some test text.\nthis some test xt.");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 18);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_caret_word_left") {
text_edit->set_text("\nthis is some test text.\nthis is some test text.");
text_edit->set_caret_line(1);
- text_edit->set_caret_column(7);
-
- text_edit->add_caret(2, 7);
- CHECK(text_edit->get_caret_count() == 2);
+ text_edit->set_caret_column(15);
+ text_edit->add_caret(2, 10);
+ text_edit->select(1, 10, 1, 15);
+ text_edit->select(2, 15, 2, 10, 1);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // Shift should select.
+ // Deselect to start of previous word when selection is right to left.
+ // Select to start of next word when selection is left to right.
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 5);
- CHECK(text_edit->get_selected_text(0) == "is");
+ CHECK(text_edit->get_caret_count() == 2);
+
CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "me ");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 13);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 10);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
- CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 5);
- CHECK(text_edit->get_selected_text(1) == "is");
CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "some te");
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 15);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Should still move caret with selection.
- SEND_GUI_ACTION("ui_text_caret_word_left");
+ // Select to start of word with shift.
+ text_edit->deselect();
+ text_edit->set_caret_column(7);
+ text_edit->set_caret_column(16, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+#ifdef MACOS_ENABLED
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
+#else
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
+#endif
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "is");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 7);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "tes");
CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_column(1) == 13);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 16);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Normal word left.
+ // Deselect and move caret to start of next word without shift.
SEND_GUI_ACTION("ui_text_caret_word_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Moves to end of previous line when at start of line. Does nothing at start of text.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_ACTION("ui_text_caret_word_left");
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 23);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2515,249 +5285,417 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_text("\nthis is some test text.\nthis is some test text.");
text_edit->set_caret_line(1);
text_edit->set_caret_column(7);
- text_edit->select(1, 2, 1, 7);
-
- text_edit->add_caret(2, 7);
- text_edit->select(2, 2, 2, 7, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
+ text_edit->select(1, 3, 1, 7);
+ text_edit->add_caret(2, 3);
+ text_edit->select(2, 7, 2, 3, 1);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // Normal left should deselect and place at selection start.
- SEND_GUI_ACTION("ui_text_caret_left");
+ // Remove one character from selection when selection is left to right.
+ // Add one character to selection when selection is right to left.
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "s i");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 6);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 3);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 2);
- CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "is is");
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 2);
- CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 7);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // With shift should select.
- SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT);
+ // Deselect and put caret at selection start without shift.
+ SEND_GUI_ACTION("ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 1);
- CHECK(text_edit->get_selected_text(0) == "h");
- CHECK(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 3);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 1);
- CHECK(text_edit->get_selected_text(1) == "h");
- CHECK(text_edit->has_selection(1));
-
+ CHECK(text_edit->get_caret_column(1) == 2);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // All ready at select left, should only deselect.
+ // Move caret one character to the left.
SEND_GUI_ACTION("ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 1);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 2);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 1);
- CHECK_FALSE(text_edit->has_selection(1));
-
- SIGNAL_CHECK_FALSE("caret_changed");
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Normal left.
- SEND_GUI_ACTION("ui_text_caret_left");
+ // Select one character to the left with shift and no existing selection.
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "h");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 1);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 2);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "t");
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 1);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Left at col 0 should go up a line.
+ // Moves to end of previous line when at start of line. Does nothing at start of text.
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
SEND_GUI_ACTION("ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 1);
CHECK(text_edit->get_caret_column(1) == 23);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- }
- SUBCASE("[TextEdit] ui_text_caret_word_right") {
- text_edit->set_text("this is some test text\n\nthis is some test text\n");
- text_edit->set_caret_line(0);
- text_edit->set_caret_column(13);
+ // Selects to end of previous line when at start of line.
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(0);
+ text_edit->select(1, 1, 1, 0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
- text_edit->add_caret(2, 13);
- CHECK(text_edit->get_caret_count() == 2);
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "\nt");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Merge selections when they overlap.
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(4);
+ text_edit->select(1, 6, 1, 4);
+ text_edit->add_caret(1, 8);
+ text_edit->select(1, 8, 1, 6, 1);
MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ CHECK(text_edit->get_caret_count() == 2);
+ SEND_GUI_KEY_EVENT(Key::LEFT | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "s is ");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 3);
+ CHECK(text_edit->get_selection_origin_line(0) == 1);
+ CHECK(text_edit->get_selection_origin_column(0) == 8);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ }
+
+ SUBCASE("[TextEdit] ui_text_caret_word_right") {
+ text_edit->set_text("this is some test text\n\nthis is some test text");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(15);
+ text_edit->add_caret(2, 10);
+ text_edit->select(0, 10, 0, 15);
+ text_edit->select(2, 15, 2, 10, 1);
+ MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // Shift should select.
+ // Select to end of next word when selection is right to left.
+ // Deselect to end of previous word when selection is left to right.
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 17);
- CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_caret_count() == 2);
CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "me test");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 17);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 10);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == " te");
CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 17);
- CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_caret_column(1) == 12);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 15);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
+
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+
+ // Select to end of word with shift.
+ text_edit->deselect();
+ text_edit->set_caret_column(13);
+ text_edit->set_caret_column(15, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+#ifdef MACOS_ENABLED
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
+#else
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
+#endif
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 17);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 13);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+
CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "st");
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 17);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 15);
+ CHECK(text_edit->is_caret_after_selection_origin(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Should still move caret with selection.
+ // Deselect and move caret to end of next word without shift.
SEND_GUI_ACTION("ui_text_caret_word_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 22);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 22);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 22);
- CHECK_FALSE(text_edit->has_selection(1));
-
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Normal word right.
+ // Moves to start of next line when at end of line. Does nothing at end of text.
SEND_GUI_ACTION("ui_text_caret_word_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
- CHECK(text_edit->get_caret_line(1) == 3);
- CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 22);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_caret_right") {
- text_edit->set_text("this is some test text\n\nthis is some test text\n");
+ text_edit->set_text("this is some test text\n\nthis is some test text");
text_edit->set_caret_line(0);
- text_edit->set_caret_column(16);
- text_edit->select(0, 16, 0, 20);
-
- text_edit->add_caret(2, 16);
- text_edit->select(2, 16, 2, 20, 1);
- CHECK(text_edit->get_caret_count() == 2);
-
+ text_edit->set_caret_column(19);
+ text_edit->select(0, 15, 0, 19);
+ text_edit->add_caret(2, 15);
+ text_edit->select(2, 19, 2, 15, 1);
MessageQueue::get_singleton()->flush();
-
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // Normal right should deselect and place at selection start.
- SEND_GUI_ACTION("ui_text_caret_right");
+ // Remove one character from selection when selection is right to left.
+ // Add one character to selection when selection is left to right.
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 20);
- CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "st te");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 20);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 15);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "t t");
CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 20);
- CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_column(1) == 16);
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 19);
+ CHECK_FALSE(text_edit->is_caret_after_selection_origin(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // With shift should select.
- SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT);
+ // Deselect and put caret at selection end without shift.
+ SEND_GUI_ACTION("ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 21);
- CHECK(text_edit->get_selected_text(0) == "x");
- CHECK(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 20);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
- CHECK(text_edit->get_caret_column(1) == 21);
- CHECK(text_edit->get_selected_text(1) == "x");
- CHECK(text_edit->has_selection(1));
-
+ CHECK(text_edit->get_caret_column(1) == 19);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // All ready at select right, should only deselect.
+ // Move caret one character to the right.
SEND_GUI_ACTION("ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 21);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 21);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 20);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Select one character to the right with shift and no existing selection.
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "t");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 22);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 21);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "x");
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 21);
- CHECK_FALSE(text_edit->has_selection(1));
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK(text_edit->get_selection_origin_line(1) == 2);
+ CHECK(text_edit->get_selection_origin_column(1) == 20);
+ CHECK(text_edit->is_caret_after_selection_origin(1));
+
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Normal right.
+ // Moves to start of next line when at end of line. Does nothing at end of text.
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(22);
+ text_edit->set_caret_column(22, false, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
SEND_GUI_ACTION("ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 22);
+ CHECK(text_edit->get_caret_count() == 2);
CHECK_FALSE(text_edit->has_selection(0));
-
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 22);
- CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
- // Right at end col should go down a line.
- SEND_GUI_ACTION("ui_text_caret_right");
+ // Selects to start of next line when at end of line.
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(22);
+ text_edit->select(0, 21, 0, 22);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection(0));
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "t\n");
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 21);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("text_changed");
+ SIGNAL_CHECK_FALSE("lines_edited_from");
- CHECK(text_edit->get_caret_line(1) == 3);
- CHECK(text_edit->get_caret_column(1) == 0);
- CHECK_FALSE(text_edit->has_selection(1));
+ // Merge selections when they overlap.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->select(0, 4, 0, 6);
+ text_edit->add_caret(0, 8);
+ text_edit->select(0, 6, 0, 8, 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+ CHECK(text_edit->get_caret_count() == 2);
+
+ SEND_GUI_KEY_EVENT(Key::RIGHT | KeyModifierMask::SHIFT);
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == " is s");
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 4);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2775,7 +5713,6 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
-
CHECK(text_edit->is_line_wrapped(0));
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
@@ -3156,11 +6093,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- // For the second caret.
- Array args2;
- args2.push_back(1);
- args2.push_back(1);
- lines_edited_args.push_front(args2);
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1));
SEND_GUI_KEY_EVENT(Key::A);
CHECK(text_edit->get_viewport()->is_input_handled());
@@ -3171,6 +6104,27 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ // Undo reverts both carets.
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "a\na");
+ CHECK(text_edit->get_caret_column() == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", reverse_nested(lines_edited_args));
+
+ // Redo.
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_text() == "aA\naA");
+ CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+
+ // Does not work if not editable.
text_edit->set_editable(false);
SEND_GUI_KEY_EVENT(Key::A);
CHECK_FALSE(text_edit->get_viewport()->is_input_handled()); // Should this be handled?
@@ -3182,8 +6136,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- lines_edited_args.push_back(lines_edited_args[1].duplicate());
- lines_edited_args.push_front(args2.duplicate());
+ lines_edited_args = build_array(build_array(0, 0), build_array(0, 0), build_array(1, 1), build_array(1, 1));
text_edit->select(0, 0, 0, 1);
text_edit->select(1, 0, 1, 1, 1);
@@ -3220,8 +6173,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_overtype_mode_enabled(false);
CHECK_FALSE(text_edit->is_overtype_mode_enabled());
- lines_edited_args.remove_at(0);
- lines_edited_args.remove_at(1);
+ lines_edited_args = build_array(build_array(0, 0), build_array(1, 1));
SEND_GUI_KEY_EVENT(Key::TAB);
CHECK(text_edit->get_viewport()->is_input_handled());
@@ -3576,6 +6528,11 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
text_edit->set_caret_column(4);
CHECK(text_edit->get_word_under_caret() == "Lorem");
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 15);
+ CHECK(text_edit->get_word_under_caret() == "Lorem\ndolor");
+ text_edit->remove_secondary_carets();
+
// Should this work?
text_edit->set_caret_column(5);
CHECK(text_edit->get_word_under_caret() == "");
@@ -3616,18 +6573,20 @@ TEST_CASE("[SceneTree][TextEdit] multicaret") {
SIGNAL_DISCARD("caret_changed");
SUBCASE("[TextEdit] add remove caret") {
- // Overlapping
+ // Overlapping.
CHECK(text_edit->add_caret(0, 0) == -1);
MessageQueue::get_singleton()->flush();
SIGNAL_CHECK_FALSE("caret_changed");
- // Selection
- text_edit->select(0, 0, 2, 4);
+ // Select.
+ text_edit->select(2, 4, 0, 0);
+
+ // Cannot add in selection.
CHECK(text_edit->add_caret(0, 0) == -1);
CHECK(text_edit->add_caret(2, 4) == -1);
CHECK(text_edit->add_caret(1, 2) == -1);
- // Out of bounds
+ // Cannot add when out of bounds.
CHECK(text_edit->add_caret(-1, 0) == -1);
CHECK(text_edit->add_caret(5, 0) == -1);
CHECK(text_edit->add_caret(0, 100) == -1);
@@ -3670,23 +6629,276 @@ TEST_CASE("[SceneTree][TextEdit] multicaret") {
ERR_PRINT_ON;
}
- SUBCASE("[TextEdit] caret index edit order") {
- Vector<int> caret_index_get_order;
- caret_index_get_order.push_back(1);
- caret_index_get_order.push_back(0);
+ SUBCASE("[TextEdit] sort carets") {
+ Vector<int> sorted_carets = { 0, 1, 2 };
- CHECK(text_edit->add_caret(1, 0));
- CHECK(text_edit->get_caret_count() == 2);
- CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order);
+ // Ascending order.
+ text_edit->remove_secondary_carets();
+ text_edit->add_caret(0, 1);
+ text_edit->add_caret(1, 0);
+ CHECK(text_edit->get_sorted_carets() == sorted_carets);
+ // Descending order.
+ sorted_carets = { 2, 1, 0 };
text_edit->remove_secondary_carets();
text_edit->set_caret_line(1);
- CHECK(text_edit->add_caret(0, 0));
+ text_edit->add_caret(0, 1);
+ text_edit->add_caret(0, 0);
+ CHECK(text_edit->get_sorted_carets() == sorted_carets);
+
+ // Mixed order.
+ sorted_carets = { 0, 2, 1, 3 };
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(0);
+ text_edit->add_caret(1, 0);
+ text_edit->add_caret(0, 1);
+ text_edit->add_caret(1, 1);
+ CHECK(text_edit->get_sorted_carets() == sorted_carets);
+
+ // Overlapping carets.
+ sorted_carets = { 0, 1, 3, 2 };
+ text_edit->remove_secondary_carets();
+ text_edit->add_caret(0, 1);
+ text_edit->add_caret(1, 2);
+ text_edit->add_caret(0, 2);
+ text_edit->set_caret_column(1, false, 3);
+ CHECK(text_edit->get_sorted_carets() == sorted_carets);
+
+ // Sorted by selection start.
+ sorted_carets = { 1, 0 };
+ text_edit->remove_secondary_carets();
+ text_edit->select(1, 3, 1, 5);
+ text_edit->add_caret(2, 0);
+ text_edit->select(1, 0, 2, 0, 1);
+ CHECK(text_edit->get_sorted_carets() == sorted_carets);
+ }
+
+ SUBCASE("[TextEdit] merge carets") {
+ text_edit->set_text("this is some text\nfor selection");
+ MessageQueue::get_singleton()->flush();
+
+ // Don't merge carets that are not overlapping.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 6);
+ text_edit->add_caret(1, 6);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 6);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 6);
+ text_edit->remove_secondary_carets();
+
+ // Don't merge when in a multicaret edit.
+ text_edit->begin_multicaret_edit();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 4);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->is_in_mulitcaret_edit());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 4);
+
+ // Merge overlapping carets. Merge at the end of the multicaret edit.
+ text_edit->end_multicaret_edit();
+ CHECK_FALSE(text_edit->is_in_mulitcaret_edit());
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ // Don't merge selections that are not overlapping.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(1, 4);
+ text_edit->select(0, 4, 1, 2, 0);
+ text_edit->select(0, 2, 0, 3, 1);
+ text_edit->select(1, 4, 1, 8, 2);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->has_selection(2));
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Don't merge selections that are only touching.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret(1, 2);
+ text_edit->select(0, 4, 1, 2, 0);
+ text_edit->select(1, 2, 1, 5, 1);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->has_selection(1));
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Merge carets into selection.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(3);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(1, 4);
+ text_edit->add_caret(1, 8);
+ text_edit->add_caret(1, 10);
+ text_edit->select(0, 2, 1, 8, 0);
+ text_edit->merge_overlapping_carets();
CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_from_line(0) == 0);
+ CHECK(text_edit->get_selection_from_column(0) == 2);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 8);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 10);
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
- caret_index_get_order.write[0] = 0;
- caret_index_get_order.write[1] = 1;
- CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order);
+ // Merge partially overlapping selections.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(0, 3);
+ text_edit->select(0, 2, 0, 6, 0);
+ text_edit->select(0, 4, 1, 3, 1);
+ text_edit->select(1, 0, 1, 5, 2);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_from_line(0) == 0);
+ CHECK(text_edit->get_selection_from_column(0) == 2);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 5);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Merge smaller overlapping selection into a bigger one.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 2);
+ text_edit->add_caret(0, 3);
+ text_edit->select(0, 2, 0, 6, 0);
+ text_edit->select(0, 8, 1, 3, 1);
+ text_edit->select(0, 2, 1, 5, 2);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_from_line(0) == 0);
+ CHECK(text_edit->get_selection_from_column(0) == 2);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 5);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+
+ // Merge equal overlapping selections.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->add_caret(0, 2);
+ text_edit->select(0, 2, 1, 6, 0);
+ text_edit->select(0, 2, 1, 6, 1);
+ text_edit->merge_overlapping_carets();
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_from_line(0) == 0);
+ CHECK(text_edit->get_selection_from_column(0) == 2);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 6);
+ CHECK(text_edit->is_caret_after_selection_origin(0));
+ }
+
+ SUBCASE("[TextEdit] collapse carets") {
+ text_edit->set_text("this is some text\nfor selection");
+
+ // Collapse carets in range, dont affect other carets.
+ text_edit->add_caret(0, 9);
+ text_edit->add_caret(1, 0);
+ text_edit->add_caret(1, 2);
+ text_edit->add_caret(1, 6);
+ text_edit->begin_multicaret_edit();
+
+ text_edit->collapse_carets(0, 8, 1, 2);
+ CHECK(text_edit->get_caret_count() == 5);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 8);
+ CHECK(text_edit->get_caret_line(3) == 1);
+ CHECK(text_edit->get_caret_column(3) == 2);
+ CHECK(text_edit->get_caret_line(4) == 1);
+ CHECK(text_edit->get_caret_column(4) == 6);
+ CHECK_FALSE(text_edit->multicaret_edit_ignore_caret(0));
+ CHECK(text_edit->multicaret_edit_ignore_caret(1));
+ CHECK(text_edit->multicaret_edit_ignore_caret(2));
+ CHECK_FALSE(text_edit->multicaret_edit_ignore_caret(3));
+ CHECK_FALSE(text_edit->multicaret_edit_ignore_caret(4));
+
+ // Collapsed carets get merged at the end of the edit.
+ text_edit->end_multicaret_edit();
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 2);
+ CHECK(text_edit->get_caret_line(3) == 1);
+ CHECK(text_edit->get_caret_column(3) == 6);
+ text_edit->remove_secondary_carets();
+
+ // Collapse inclusive.
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(3);
+ text_edit->add_caret(1, 2);
+ text_edit->collapse_carets(0, 3, 1, 2, true);
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 3);
+ text_edit->remove_secondary_carets();
+
+ // Deselect if selection was encompassed.
+ text_edit->select(0, 5, 0, 7);
+ text_edit->collapse_carets(0, 3, 1, 2);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 3);
+
+ // Clamp only caret end of selection.
+ text_edit->select(0, 1, 0, 7);
+ text_edit->collapse_carets(0, 3, 1, 2);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 3);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 1);
+ text_edit->deselect();
+
+ // Clamp only selection origin end of selection.
+ text_edit->select(0, 7, 0, 1);
+ text_edit->collapse_carets(0, 3, 1, 2);
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 1);
+ CHECK(text_edit->get_selection_origin_line() == 0);
+ CHECK(text_edit->get_selection_origin_column() == 3);
+ text_edit->deselect();
}
SUBCASE("[TextEdit] add caret at carets") {
@@ -3694,36 +6906,320 @@ TEST_CASE("[SceneTree][TextEdit] multicaret") {
text_edit->set_caret_line(1);
text_edit->set_caret_column(9);
+ // Add caret below. Column will clamp.
text_edit->add_caret_at_carets(true);
CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 9);
CHECK(text_edit->get_caret_line(1) == 2);
CHECK(text_edit->get_caret_column(1) == 4);
+ // Cannot add below when at last line.
text_edit->add_caret_at_carets(true);
CHECK(text_edit->get_caret_count() == 2);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ // Add caret above. Column will clamp.
text_edit->add_caret_at_carets(false);
CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
CHECK(text_edit->get_caret_line(2) == 0);
CHECK(text_edit->get_caret_column(2) == 7);
+ // Cannot add above when at first line.
+ text_edit->add_caret_at_carets(false);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 7);
+
+ // Cannot add below when at the last line for selection.
+ text_edit->remove_secondary_carets();
+ text_edit->select(2, 1, 2, 4);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 2);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ // Cannot add above when at the first line for selection.
+ text_edit->select(0, 1, 0, 4);
+ text_edit->add_caret_at_carets(false);
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ // Add selection below.
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 0);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 3); // In the default font, this is the same position.
+
+ // Add selection below again.
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 0);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 0);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 3);
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_selection_origin_line(2) == 2);
+ CHECK(text_edit->get_selection_origin_column(2) == 0);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 4);
+
+ text_edit->set_text("\tthis is\nsome\n\ttest text");
+ MessageQueue::get_singleton()->flush();
+
+ // Last fit x is preserved when adding below.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(6);
+ text_edit->add_caret_at_carets(true);
+ text_edit->add_caret_at_carets(true);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 6);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 6);
+
+ // Last fit x is preserved when adding above.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(9);
+ text_edit->add_caret_at_carets(false);
+ text_edit->add_caret_at_carets(false);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 9);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 8);
+
+ // Last fit x is preserved when selection adding below.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->select(0, 8, 0, 5);
+ text_edit->add_caret_at_carets(true);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 8);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_selection_origin_line(2) == 2);
+ CHECK(text_edit->get_selection_origin_column(2) == 7);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 5);
+
+ // Last fit x is preserved when selection adding above.
text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->select(2, 9, 2, 5);
+ text_edit->add_caret_at_carets(false);
+ text_edit->add_caret_at_carets(false);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 2);
+ CHECK(text_edit->get_selection_origin_column(0) == 9);
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK_FALSE(text_edit->has_selection(1));
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_selection_origin_line(2) == 0);
+ CHECK(text_edit->get_selection_origin_column(2) == 8);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 5);
+
+ // Selections are merged when they overlap.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->select(0, 1, 0, 5);
+ text_edit->add_caret(1, 0);
+ text_edit->select(1, 1, 1, 3, 1);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 1);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK(text_edit->has_selection(2));
+ CHECK(text_edit->get_selection_origin_line(2) == 2);
+ CHECK(text_edit->get_selection_origin_column(2) == 0);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 3);
+
+ // Multiline selection.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(1);
+ text_edit->select(0, 3, 1, 1);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selection_origin_line(0) == 0);
+ CHECK(text_edit->get_selection_origin_column(0) == 3);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 1);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selection_origin_line(1) == 1);
+ CHECK(text_edit->get_selection_origin_column(1) == 3);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
+
+ text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
+ text_edit->set_size(Size2(50, 100));
+ // Line wraps: `\t,this, is\nso,me\n\t,test, ,text`.
+ CHECK(text_edit->is_line_wrapped(0));
+ MessageQueue::get_singleton()->flush();
+
+ // Add caret below on next line wrap.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
text_edit->set_caret_line(0);
text_edit->set_caret_column(4);
- text_edit->select(0, 0, 0, 4);
text_edit->add_caret_at_carets(true);
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_count() == 2);
- CHECK(text_edit->get_selection_from_line(1) == 1);
- CHECK(text_edit->get_selection_to_line(1) == 1);
- CHECK(text_edit->get_selection_from_column(1) == 0);
- CHECK(text_edit->get_selection_to_column(1) == 3);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ // Add caret below from end of line wrap.
text_edit->add_caret_at_carets(true);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK(text_edit->get_caret_line(2) == 1);
+ CHECK(text_edit->get_caret_column(2) == 1);
+
+ // Add caret below from last line and not last line wrap.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(2);
+ text_edit->set_caret_column(5);
+ text_edit->add_caret_at_carets(true);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 10);
+
+ // Cannot add caret below from last line last line wrap.
+ text_edit->add_caret_at_carets(true);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 2);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 10);
+
+ // Add caret above from not first line wrap.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(4);
+ text_edit->add_caret_at_carets(false);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
+
+ // Add caret above from first line wrap.
+ text_edit->add_caret_at_carets(false);
+ CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_caret_count() == 3);
- CHECK(text_edit->get_selection_from_line(2) == 2);
- CHECK(text_edit->get_selection_to_line(2) == 2);
- CHECK(text_edit->get_selection_from_column(2) == 0);
- CHECK(text_edit->get_selection_to_column(2) == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 8);
+
+ // Add caret above from first line and not first line wrap.
+ text_edit->add_caret_at_carets(false);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 8);
+ CHECK(text_edit->get_caret_line(3) == 0);
+ CHECK(text_edit->get_caret_column(3) == 4);
+
+ // Cannot add caret above from first line first line wrap.
+ text_edit->remove_secondary_carets();
+ text_edit->deselect();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->add_caret_at_carets(false);
+ CHECK_FALSE(text_edit->has_selection());
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
}
memdelete(text_edit);
@@ -3992,7 +7488,7 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
CHECK(text_edit->get_last_full_visible_line() == visible_lines - 1);
CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
- // Wrap
+ // Wrap.
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_total_visible_line_count() > total_visible_lines);
@@ -4242,7 +7738,7 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
CHECK(text_edit->get_caret_wrap_index() == 0);
- // Typing and undo / redo should adjust viewport
+ // Typing and undo / redo should adjust viewport.
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
text_edit->set_line_as_first_visible(5);