Fix TextEdit caret movement at start of wrapped lines
This commit is contained in:
parent
96be44c0ec
commit
93a81dd7aa
2 changed files with 64 additions and 19 deletions
|
@ -4328,25 +4328,12 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
|
||||||
return Point2i(text[row].length(), row);
|
return Point2i(text[row].length(), row);
|
||||||
}
|
}
|
||||||
|
|
||||||
int col = 0;
|
|
||||||
int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding);
|
int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding);
|
||||||
colx += first_visible_col;
|
colx += first_visible_col;
|
||||||
if (!editable) {
|
if (!editable) {
|
||||||
colx -= theme_cache.style_readonly->get_offset().x / 2;
|
colx -= theme_cache.style_readonly->get_offset().x / 2;
|
||||||
colx += theme_cache.style_normal->get_offset().x / 2;
|
colx += theme_cache.style_normal->get_offset().x / 2;
|
||||||
}
|
}
|
||||||
col = _get_char_pos_for_line(colx, row, wrap_index);
|
|
||||||
if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && wrap_index < get_line_wrap_count(row)) {
|
|
||||||
// Move back one if we are at the end of the row.
|
|
||||||
Vector<String> rows2 = get_line_wrapped_text(row);
|
|
||||||
int row_end_col = 0;
|
|
||||||
for (int i = 0; i < wrap_index + 1; i++) {
|
|
||||||
row_end_col += rows2[i].length();
|
|
||||||
}
|
|
||||||
if (col >= row_end_col) {
|
|
||||||
col -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index);
|
RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index);
|
||||||
float wrap_indent = (text.is_indent_wrapped_lines() && wrap_index > 0) ? get_indent_level(row) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0;
|
float wrap_indent = (text.is_indent_wrapped_lines() && wrap_index > 0) ? get_indent_level(row) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0;
|
||||||
|
@ -4355,7 +4342,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
|
||||||
} else {
|
} else {
|
||||||
colx -= wrap_indent;
|
colx -= wrap_indent;
|
||||||
}
|
}
|
||||||
col = TS->shaped_text_hit_test_position(text_rid, colx);
|
int col = TS->shaped_text_hit_test_position(text_rid, colx);
|
||||||
if (!caret_mid_grapheme_enabled) {
|
if (!caret_mid_grapheme_enabled) {
|
||||||
col = TS->shaped_text_closest_character_pos(text_rid, col);
|
col = TS->shaped_text_closest_character_pos(text_rid, col);
|
||||||
}
|
}
|
||||||
|
@ -7531,7 +7518,7 @@ int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line, int p_column
|
||||||
int row = 0;
|
int row = 0;
|
||||||
Vector<Vector2i> rows2 = text.get_line_wrap_ranges(p_line);
|
Vector<Vector2i> rows2 = text.get_line_wrap_ranges(p_line);
|
||||||
for (int i = 0; i < rows2.size(); i++) {
|
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 || (i == rows2.size() - 1 && p_char == rows2[i].y))) {
|
||||||
row = i;
|
row = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1763,6 +1763,28 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
CHECK_FALSE(text_edit->has_selection());
|
CHECK_FALSE(text_edit->has_selection());
|
||||||
CHECK(text_edit->get_caret_line() == 0);
|
CHECK(text_edit->get_caret_line() == 0);
|
||||||
CHECK(text_edit->get_caret_column() == 4);
|
CHECK(text_edit->get_caret_column() == 4);
|
||||||
|
|
||||||
|
// Wrapped lines.
|
||||||
|
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
|
||||||
|
text_edit->set_text("this is some text\nfor selection");
|
||||||
|
text_edit->set_size(Size2(110, 100));
|
||||||
|
MessageQueue::get_singleton()->flush();
|
||||||
|
|
||||||
|
// Line 0 wraps: 'this is ', 'some text'.
|
||||||
|
// Line 1 wraps: 'for ', 'selection'.
|
||||||
|
CHECK(text_edit->is_line_wrapped(0));
|
||||||
|
|
||||||
|
// Select to the first character of a wrapped line.
|
||||||
|
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 11).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
|
||||||
|
SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 8).get_center(), MouseButtonMask::LEFT, Key::NONE);
|
||||||
|
CHECK(text_edit->has_selection());
|
||||||
|
CHECK(text_edit->get_selected_text() == "so");
|
||||||
|
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
|
||||||
|
CHECK(text_edit->get_selection_origin_line() == 0);
|
||||||
|
CHECK(text_edit->get_selection_origin_column() == 10);
|
||||||
|
CHECK(text_edit->get_caret_line() == 0);
|
||||||
|
CHECK(text_edit->get_caret_column() == 8);
|
||||||
|
CHECK(text_edit->is_dragging_cursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("[TextEdit] mouse word select") {
|
SUBCASE("[TextEdit] mouse word select") {
|
||||||
|
@ -5713,6 +5735,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
CHECK(text_edit->get_caret_count() == 2);
|
CHECK(text_edit->get_caret_count() == 2);
|
||||||
|
|
||||||
MessageQueue::get_singleton()->flush();
|
MessageQueue::get_singleton()->flush();
|
||||||
|
// Lines 0 and 4 are wrapped into 2 parts: 'this is ' and 'some'.
|
||||||
CHECK(text_edit->is_line_wrapped(0));
|
CHECK(text_edit->is_line_wrapped(0));
|
||||||
SIGNAL_DISCARD("text_set");
|
SIGNAL_DISCARD("text_set");
|
||||||
SIGNAL_DISCARD("text_changed");
|
SIGNAL_DISCARD("text_changed");
|
||||||
|
@ -5762,9 +5785,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
||||||
SIGNAL_CHECK_FALSE("text_changed");
|
SIGNAL_CHECK_FALSE("text_changed");
|
||||||
SIGNAL_CHECK_FALSE("lines_edited_from");
|
SIGNAL_CHECK_FALSE("lines_edited_from");
|
||||||
text_edit->set_caret_column(12, false);
|
|
||||||
|
|
||||||
// Normal up over wrapped line to line 0.
|
// Normal up over wrapped line to line 0.
|
||||||
|
text_edit->set_caret_column(12, false);
|
||||||
SEND_GUI_ACTION("ui_text_caret_up");
|
SEND_GUI_ACTION("ui_text_caret_up");
|
||||||
CHECK(text_edit->get_viewport()->is_input_handled());
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
CHECK(text_edit->get_caret_line() == 0);
|
CHECK(text_edit->get_caret_line() == 0);
|
||||||
|
@ -5777,6 +5800,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
||||||
SIGNAL_CHECK_FALSE("text_changed");
|
SIGNAL_CHECK_FALSE("text_changed");
|
||||||
SIGNAL_CHECK_FALSE("lines_edited_from");
|
SIGNAL_CHECK_FALSE("lines_edited_from");
|
||||||
|
|
||||||
|
// Normal up from column 0 to a wrapped line.
|
||||||
|
text_edit->remove_secondary_carets();
|
||||||
|
text_edit->set_caret_line(5);
|
||||||
|
text_edit->set_caret_column(0);
|
||||||
|
SEND_GUI_ACTION("ui_text_caret_up");
|
||||||
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
|
CHECK(text_edit->get_caret_line() == 4);
|
||||||
|
CHECK(text_edit->get_caret_column() == 8);
|
||||||
|
CHECK_FALSE(text_edit->has_selection(0));
|
||||||
|
|
||||||
|
// Normal up to column 0 of a wrapped line.
|
||||||
|
SEND_GUI_ACTION("ui_text_caret_up");
|
||||||
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
|
CHECK(text_edit->get_caret_line() == 4);
|
||||||
|
CHECK(text_edit->get_caret_column() == 0);
|
||||||
|
CHECK_FALSE(text_edit->has_selection(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("[TextEdit] ui_text_caret_down") {
|
SUBCASE("[TextEdit] ui_text_caret_down") {
|
||||||
|
@ -5792,6 +5832,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
|
|
||||||
MessageQueue::get_singleton()->flush();
|
MessageQueue::get_singleton()->flush();
|
||||||
|
|
||||||
|
// Lines 3 and 7 are wrapped into 2 parts: 'this is ' and 'some'.
|
||||||
CHECK(text_edit->is_line_wrapped(3));
|
CHECK(text_edit->is_line_wrapped(3));
|
||||||
SIGNAL_DISCARD("text_set");
|
SIGNAL_DISCARD("text_set");
|
||||||
SIGNAL_DISCARD("text_changed");
|
SIGNAL_DISCARD("text_changed");
|
||||||
|
@ -5841,9 +5882,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
||||||
SIGNAL_CHECK_FALSE("text_changed");
|
SIGNAL_CHECK_FALSE("text_changed");
|
||||||
SIGNAL_CHECK_FALSE("lines_edited_from");
|
SIGNAL_CHECK_FALSE("lines_edited_from");
|
||||||
text_edit->set_caret_column(7, false);
|
|
||||||
|
|
||||||
// Normal down over wrapped line to last wrapped line.
|
// Normal down over wrapped line to last wrapped line.
|
||||||
|
text_edit->set_caret_column(7, false);
|
||||||
SEND_GUI_ACTION("ui_text_caret_down");
|
SEND_GUI_ACTION("ui_text_caret_down");
|
||||||
CHECK(text_edit->get_viewport()->is_input_handled());
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
CHECK(text_edit->get_caret_line() == 3);
|
CHECK(text_edit->get_caret_line() == 3);
|
||||||
|
@ -5856,6 +5897,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
|
||||||
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
SIGNAL_CHECK("caret_changed", empty_signal_args);
|
||||||
SIGNAL_CHECK_FALSE("text_changed");
|
SIGNAL_CHECK_FALSE("text_changed");
|
||||||
SIGNAL_CHECK_FALSE("lines_edited_from");
|
SIGNAL_CHECK_FALSE("lines_edited_from");
|
||||||
|
|
||||||
|
// Normal down to column 0 of a wrapped line.
|
||||||
|
text_edit->remove_secondary_carets();
|
||||||
|
text_edit->set_caret_line(3);
|
||||||
|
text_edit->set_caret_column(0);
|
||||||
|
SEND_GUI_ACTION("ui_text_caret_down");
|
||||||
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
|
CHECK(text_edit->get_caret_line() == 3);
|
||||||
|
CHECK(text_edit->get_caret_column() == 8);
|
||||||
|
CHECK_FALSE(text_edit->has_selection(0));
|
||||||
|
|
||||||
|
// Normal down out of visual column 0 of a wrapped line moves to start of next line.
|
||||||
|
SEND_GUI_ACTION("ui_text_caret_down");
|
||||||
|
CHECK(text_edit->get_viewport()->is_input_handled());
|
||||||
|
CHECK(text_edit->get_caret_line() == 4);
|
||||||
|
CHECK(text_edit->get_caret_column() == 0);
|
||||||
|
CHECK_FALSE(text_edit->has_selection(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("[TextEdit] ui_text_caret_document_start") {
|
SUBCASE("[TextEdit] ui_text_caret_document_start") {
|
||||||
|
@ -7162,7 +7220,7 @@ TEST_CASE("[SceneTree][TextEdit] multicaret") {
|
||||||
CHECK(text_edit->get_caret_line(0) == 2);
|
CHECK(text_edit->get_caret_line(0) == 2);
|
||||||
CHECK(text_edit->get_caret_column(0) == 5);
|
CHECK(text_edit->get_caret_column(0) == 5);
|
||||||
CHECK(text_edit->get_caret_line(1) == 2);
|
CHECK(text_edit->get_caret_line(1) == 2);
|
||||||
CHECK(text_edit->get_caret_column(1) == 10);
|
CHECK(text_edit->get_caret_column(1) == 6);
|
||||||
|
|
||||||
// Cannot add caret below from last line last line wrap.
|
// Cannot add caret below from last line last line wrap.
|
||||||
text_edit->add_caret_at_carets(true);
|
text_edit->add_caret_at_carets(true);
|
||||||
|
@ -7171,7 +7229,7 @@ TEST_CASE("[SceneTree][TextEdit] multicaret") {
|
||||||
CHECK(text_edit->get_caret_line(0) == 2);
|
CHECK(text_edit->get_caret_line(0) == 2);
|
||||||
CHECK(text_edit->get_caret_column(0) == 5);
|
CHECK(text_edit->get_caret_column(0) == 5);
|
||||||
CHECK(text_edit->get_caret_line(1) == 2);
|
CHECK(text_edit->get_caret_line(1) == 2);
|
||||||
CHECK(text_edit->get_caret_column(1) == 10);
|
CHECK(text_edit->get_caret_column(1) == 6);
|
||||||
|
|
||||||
// Add caret above from not first line wrap.
|
// Add caret above from not first line wrap.
|
||||||
text_edit->remove_secondary_carets();
|
text_edit->remove_secondary_carets();
|
||||||
|
|
Loading…
Reference in a new issue