Skip to content

Commit

Permalink
Merge pull request #60438 from Paulb23/text-edit-tests
Browse files Browse the repository at this point in the history
Add TextEdit unit tests and multiple fixes.
  • Loading branch information
akien-mga committed Apr 25, 2022
2 parents bc520e4 + c1d445f commit 8c2b980
Show file tree
Hide file tree
Showing 7 changed files with 3,639 additions and 53 deletions.
4 changes: 4 additions & 0 deletions core/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1446,4 +1446,8 @@ Input::Input() {
}
}

Input::~Input() {
singleton = nullptr;
}

//////////////////////////////////////////////////////////
1 change: 1 addition & 0 deletions core/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class Input : public Object {
void set_event_dispatch_function(EventDispatchFunc p_function);

Input();
~Input();
};

VARIANT_ENUM_CAST(Input::MouseMode);
Expand Down
77 changes: 50 additions & 27 deletions scene/gui/text_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ void TextEdit::_notification(int p_what) {
}
}

if (draw_placeholder) {
if (!draw_placeholder) {
line_drawing_cache[line] = cache_entry;
}
}
Expand Down Expand Up @@ -1640,7 +1640,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
set_caret_column(col);
selection.drag_attempt = false;

if (mb->is_shift_pressed() && (caret.column != prev_col || caret.line != prev_line)) {
if (selecting_enabled && mb->is_shift_pressed() && (caret.column != prev_col || caret.line != prev_line)) {
if (!selection.active) {
selection.active = true;
selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
Expand Down Expand Up @@ -1708,15 +1708,14 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
last_dblclk = OS::get_singleton()->get_ticks_msec();
last_dblclk_pos = mb->get_position();
}

update();
}

if (is_middle_mouse_paste_enabled() && mb->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
paste_primary_clipboard();
}

if (mb->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
if (mb->get_button_index() == MouseButton::RIGHT && (context_menu_enabled || is_move_caret_on_right_click_enabled())) {
_reset_caret_blink_timer();

Point2i pos = get_line_column_at_pos(mpos);
Expand All @@ -1741,11 +1740,13 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
}

_generate_context_menu();
menu->set_position(get_screen_position() + mpos);
menu->reset_size();
menu->popup();
grab_focus();
if (context_menu_enabled) {
_generate_context_menu();
menu->set_position(get_screen_position() + mpos);
menu->reset_size();
menu->popup();
grab_focus();
}
}
} else {
if (mb->get_button_index() == MouseButton::LEFT) {
Expand Down Expand Up @@ -2314,15 +2315,7 @@ void TextEdit::_move_caret_to_line_start(bool p_select) {
}
if (caret.column == row_start_col || wi == 0) {
// Compute whitespace symbols sequence length.
int current_line_whitespace_len = 0;
while (current_line_whitespace_len < text[caret.line].length()) {
char32_t c = text[caret.line][current_line_whitespace_len];
if (c != '\t' && c != ' ') {
break;
}
current_line_whitespace_len++;
}

int current_line_whitespace_len = get_first_non_whitespace_column(caret.line);
if (get_caret_column() == current_line_whitespace_len) {
set_caret_column(0);
} else {
Expand Down Expand Up @@ -2460,6 +2453,10 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
int next_column;

if (p_all_to_right) {
if (caret.column == curline_len) {
return;
}

// Delete everything to right of caret
next_column = curline_len;
next_line = caret.line;
Expand Down Expand Up @@ -3122,6 +3119,7 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) {
++selection.to_line;
}
}
update();
}

void TextEdit::insert_text_at_caret(const String &p_text) {
Expand Down Expand Up @@ -3817,7 +3815,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_

Point2i TextEdit::get_pos_at_line_column(int p_line, int p_column) const {
Rect2i rect = get_rect_at_line_column(p_line, p_column);
return rect.position + Vector2i(0, get_line_height());
return rect.position.x == -1 ? rect.position : rect.position + Vector2i(0, get_line_height());
}

Rect2i TextEdit::get_rect_at_line_column(int p_line, int p_column) const {
Expand Down Expand Up @@ -4055,12 +4053,12 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) {
if (p_col < 0) {
p_col = 0;
}
if (p_col > get_line(caret.line).length()) {
p_col = get_line(caret.line).length();
}

bool caret_moved = caret.column != p_col;
caret.column = p_col;
if (caret.column > get_line(caret.line).length()) {
caret.column = get_line(caret.line).length();
}

caret.last_fit_x = _get_column_x_offset_for_line(caret.column, caret.line);

Expand Down Expand Up @@ -4189,13 +4187,18 @@ void TextEdit::select_word_under_caret() {
int end = 0;
const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
for (int i = 0; i < words.size(); i = i + 2) {
if ((words[i] < caret.column && words[i + 1] > caret.column) || (i == words.size() - 2 && caret.column == words[i + 1])) {
if ((words[i] <= caret.column && words[i + 1] >= caret.column) || (i == words.size() - 2 && caret.column == words[i + 1])) {
begin = words[i];
end = words[i + 1];
break;
}
}

// No word found.
if (begin == 0 && end == 0) {
return;
}

select(caret.line, begin, caret.line, end);
/* Move the caret to the end of the word for easier editing. */
set_caret_column(end, false);
Expand Down Expand Up @@ -4271,10 +4274,12 @@ String TextEdit::get_selected_text() const {
}

int TextEdit::get_selection_line() const {
ERR_FAIL_COND_V(!selection.active, -1);
return selection.selecting_line;
}

int TextEdit::get_selection_column() const {
ERR_FAIL_COND_V(!selection.active, -1);
return selection.selecting_column;
}

Expand Down Expand Up @@ -4476,9 +4481,13 @@ void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line));

int visible_rows = get_visible_line_count();
Point2i next_line = get_next_visible_line_index_offset_from(p_line, p_wrap_index, -visible_rows / 2);
Point2i next_line = get_next_visible_line_index_offset_from(p_line, p_wrap_index, (-visible_rows / 2) - 1);
int first_line = p_line - next_line.x + 1;

if (first_line < 0) {
set_v_scroll(0);
return;
}
set_v_scroll(get_scroll_pos_for_line(first_line, next_line.y));
}

Expand All @@ -4490,6 +4499,12 @@ void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
Point2i next_line = get_next_visible_line_index_offset_from(p_line, p_wrap_index, -get_visible_line_count() - 1);
int first_line = p_line - next_line.x + 1;

// Adding _get_visible_lines_offset is not 100% correct as we end up showing almost p_line + 1, however, it provides a
// better user experience. Therefore we need to special case < visible line count, else showing line 0 is impossible.
if (get_visible_line_count_in_range(0, p_line) < get_visible_line_count() + 1) {
set_v_scroll(0);
return;
}
set_v_scroll(get_scroll_pos_for_line(first_line, next_line.y) + _get_visible_lines_offset());
}

Expand Down Expand Up @@ -5899,7 +5914,7 @@ int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line) const {
int row = 0;
Vector<Vector2i> rows2 = text.get_line_wrap_ranges(p_line);
for (int i = 0; i < rows2.size(); i++) {
if ((p_char >= rows2[i].x) && (p_char < rows2[i].y)) {
if ((p_char >= rows2[i].x) && (p_char <= rows2[i].y)) {
row = i;
break;
}
Expand Down Expand Up @@ -5983,8 +5998,8 @@ void TextEdit::_update_selection_mode_word() {
selection.selected_word_beg = beg;
selection.selected_word_end = end;
selection.selected_word_origin = beg;
set_caret_line(selection.to_line, false);
set_caret_column(selection.to_column);
set_caret_line(line, false);
set_caret_column(end);
} else {
if ((col <= selection.selected_word_origin && line == selection.selecting_line) || line < selection.selecting_line) {
selection.selecting_column = selection.selected_word_end;
Expand Down Expand Up @@ -6040,6 +6055,10 @@ void TextEdit::_update_selection_mode_line() {
}

void TextEdit::_pre_shift_selection() {
if (!selecting_enabled) {
return;
}

if (!selection.active || selection.selecting_mode == SelectionMode::SELECTION_MODE_NONE) {
selection.selecting_line = caret.line;
selection.selecting_column = caret.column;
Expand All @@ -6050,6 +6069,10 @@ void TextEdit::_pre_shift_selection() {
}

void TextEdit::_post_shift_selection() {
if (!selecting_enabled) {
return;
}

if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) {
select(selection.selecting_line, selection.selecting_column, caret.line, caret.column);
update();
Expand Down
19 changes: 14 additions & 5 deletions tests/scene/test_code_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace TestCodeEdit {
TEST_CASE("[SceneTree][CodeEdit] line gutters") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

SUBCASE("[CodeEdit] breakpoints") {
SIGNAL_WATCH(code_edit, "breakpoint_toggled");
Expand Down Expand Up @@ -881,6 +882,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") {
TEST_CASE("[SceneTree][CodeEdit] delimiters") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

const Point2 OUTSIDE_DELIMETER = Point2(-1, -1);

Expand Down Expand Up @@ -1759,6 +1761,7 @@ TEST_CASE("[SceneTree][CodeEdit] delimiters") {
TEST_CASE("[SceneTree][CodeEdit] indent") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

SUBCASE("[CodeEdit] indent settings") {
code_edit->set_indent_size(10);
Expand Down Expand Up @@ -2288,6 +2291,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
TEST_CASE("[SceneTree][CodeEdit] folding") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

SUBCASE("[CodeEdit] folding settings") {
code_edit->set_line_folding_enabled(true);
Expand Down Expand Up @@ -2672,6 +2676,7 @@ TEST_CASE("[SceneTree][CodeEdit] folding") {
TEST_CASE("[SceneTree][CodeEdit] completion") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

SUBCASE("[CodeEdit] auto brace completion") {
code_edit->set_auto_brace_completion_enabled(true);
Expand Down Expand Up @@ -2991,18 +2996,18 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {

Point2 caret_pos = code_edit->get_caret_draw_pos();
caret_pos.y -= code_edit->get_line_height();
SEND_GUI_MOUSE_EVENT(code_edit, caret_pos, MouseButton::WHEEL_DOWN, MouseButton::NONE);
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_DOWN, MouseButton::NONE, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 1);

SEND_GUI_MOUSE_EVENT(code_edit, caret_pos, MouseButton::WHEEL_UP, MouseButton::NONE);
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::WHEEL_UP, MouseButton::NONE, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 0);

/* Single click selects. */
SEND_GUI_MOUSE_EVENT(code_edit, caret_pos, MouseButton::LEFT, MouseButton::MASK_LEFT);
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::LEFT, MouseButton::MASK_LEFT, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == 2);

/* Double click inserts. */
SEND_GUI_DOUBLE_CLICK(code_edit, caret_pos);
SEND_GUI_DOUBLE_CLICK(code_edit, caret_pos, Key::NONE);
CHECK(code_edit->get_code_completion_selected_index() == -1);
CHECK(code_edit->get_line(0) == "item_2");

Expand Down Expand Up @@ -3196,6 +3201,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
TEST_CASE("[SceneTree][CodeEdit] symbol lookup") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

code_edit->set_symbol_lookup_on_click_enabled(true);
CHECK(code_edit->is_symbol_lookup_on_click_enabled());
Expand All @@ -3208,7 +3214,7 @@ TEST_CASE("[SceneTree][CodeEdit] symbol lookup") {

Point2 caret_pos = code_edit->get_caret_draw_pos();
caret_pos.x += 58;
SEND_GUI_MOUSE_EVENT(code_edit, caret_pos, MouseButton::NONE, MouseButton::NONE);
SEND_GUI_MOUSE_BUTTON_EVENT(code_edit, caret_pos, MouseButton::NONE, MouseButton::NONE, Key::NONE);
CHECK(code_edit->get_text_for_symbol_lookup() == "this is s" + String::chr(0xFFFF) + "ome text");

SIGNAL_WATCH(code_edit, "symbol_validate");
Expand All @@ -3234,6 +3240,7 @@ TEST_CASE("[SceneTree][CodeEdit] symbol lookup") {
TEST_CASE("[SceneTree][CodeEdit] line length guidelines") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

TypedArray<int> guide_lines;

Expand All @@ -3254,6 +3261,7 @@ TEST_CASE("[SceneTree][CodeEdit] line length guidelines") {
TEST_CASE("[SceneTree][CodeEdit] Backspace delete") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

/* Backspace with selection on first line. */
code_edit->set_text("");
Expand Down Expand Up @@ -3301,6 +3309,7 @@ TEST_CASE("[SceneTree][CodeEdit] Backspace delete") {
TEST_CASE("[SceneTree][CodeEdit] New Line") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
code_edit->grab_focus();

/* Add a new line. */
code_edit->set_text("");
Expand Down
Loading

0 comments on commit 8c2b980

Please sign in to comment.