Fix TextEdit Shift+Click selection start position

This commit is contained in:
kit
2026-01-08 18:44:53 -05:00
parent c5e670f26e
commit 9813c834fa
3 changed files with 71 additions and 3 deletions

View File

@@ -459,7 +459,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (line != -1) {
emit_signal(SNAME("symbol_lookup"), symbol_lookup_word, line, col);
}
return;
// Don't return here to pass event to TextEdit so it can clean up the mouse pressed state.
}
}
}

View File

@@ -6191,6 +6191,11 @@ void TextEdit::set_selection_origin_column(int p_column, int p_caret) {
deselect(p_caret);
}
if (get_selection_mode() == SELECTION_MODE_NONE || get_selection_mode() == SELECTION_MODE_SHIFT) {
carets.write[p_caret].selection.word_begin_column = p_column;
carets.write[p_caret].selection.word_end_column = p_column;
}
if (selection_moved && has_selection(p_caret)) {
_selection_changed(p_caret);
}
@@ -8521,8 +8526,6 @@ void TextEdit::_pre_shift_selection(int p_caret) {
set_selection_origin_line(get_caret_line(p_caret), true, -1, p_caret);
set_selection_origin_column(get_caret_column(p_caret), p_caret);
carets.write[p_caret].selection.active = true;
carets.write[p_caret].selection.word_begin_column = get_caret_column(p_caret);
carets.write[p_caret].selection.word_end_column = get_caret_column(p_caret);
}
bool TextEdit::_selection_contains(int p_caret, int p_line, int p_column, bool p_include_edges, bool p_only_selections) const {

View File

@@ -2134,6 +2134,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
// 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_RELEASED_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() == "or s");
@@ -2143,6 +2144,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
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_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 5).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
// 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);
@@ -2154,9 +2156,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 6);
CHECK_FALSE(text_edit->is_caret_after_selection_origin());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
// 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);
SEND_GUI_MOUSE_BUTTON_RELEASED_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);
@@ -2164,13 +2168,74 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
// Cannot select when disabled, but caret still moves.
text_edit->set_selecting_enabled(false);
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 0).get_center(), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
SEND_GUI_MOUSE_BUTTON_RELEASED_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);
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 | KeyModifierMask::SHIFT);
text_edit->set_selecting_enabled(true);
// Shift click to make a selection from caret.
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 1).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
text_edit->set_caret_column(5, false);
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 13).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "is some ");
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() == 5);
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 13);
CHECK(text_edit->is_caret_after_selection_origin());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 13).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
text_edit->deselect();
// Shift click with an existing selection.
text_edit->select(1, 2, 1, 5);
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(1, 8).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "r sele");
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() == 2);
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 8);
CHECK(text_edit->is_caret_after_selection_origin());
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(1, 8).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
text_edit->deselect();
// Shift selecting after word selection mode keeps the selection on the word.
SEND_GUI_DOUBLE_CLICK(text_edit->get_rect_at_line_column(0, 6).get_center() + Point2i(2, 0), Key::NONE);
SEND_GUI_MOUSE_BUTTON_RELEASED_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() == "is");
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() == 5);
SEND_GUI_MOUSE_BUTTON_EVENT(text_edit->get_rect_at_line_column(0, 10).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "is so");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 10);
CHECK(text_edit->get_selection_origin_line() == 0);
CHECK(text_edit->get_selection_origin_column() == 5);
SEND_GUI_MOUSE_MOTION_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center(), MouseButtonMask::LEFT, Key::NONE);
CHECK(text_edit->get_selection_mode() == TextEdit::SELECTION_MODE_POINTER);
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "is is");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 2);
CHECK(text_edit->get_selection_origin_line() == 0);
CHECK(text_edit->get_selection_origin_column() == 7);
SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(text_edit->get_rect_at_line_column(0, 3).get_center() + Point2i(2, 0), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE | KeyModifierMask::SHIFT);
}
SUBCASE("[TextEdit] select and deselect") {