summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
authorPaulb23 <p_batty@hotmail.co.uk>2021-07-09 12:42:55 +0100
committerPaulb23 <p_batty@hotmail.co.uk>2021-08-12 09:29:56 +0100
commit9ec3e7f3d7ae7f9eaf5a1de29346c5e10b3af6f9 (patch)
tree2953e06268871695e0c49b12f16372ce672bf027 /scene/gui
parent7e70f9e0b9696fab55e2d0570c6bdc8b07c14462 (diff)
Cleanup TextEdit selection methods
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/code_edit.cpp20
-rw-r--r--scene/gui/text_edit.cpp795
-rw-r--r--scene/gui/text_edit.h90
3 files changed, 464 insertions, 441 deletions
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 6528e90f30..134151dbe8 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -548,7 +548,7 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
// Overridable actions
void CodeEdit::_handle_unicode_input(const uint32_t p_unicode) {
- bool had_selection = is_selection_active();
+ bool had_selection = has_selection();
if (had_selection) {
begin_complex_operation();
delete_selection();
@@ -611,7 +611,7 @@ void CodeEdit::_backspace() {
return;
}
- if (is_selection_active()) {
+ if (has_selection()) {
delete_selection();
return;
}
@@ -718,7 +718,7 @@ void CodeEdit::do_indent() {
return;
}
- if (is_selection_active()) {
+ if (has_selection()) {
indent_lines();
return;
}
@@ -747,7 +747,7 @@ void CodeEdit::indent_lines() {
int start_line = get_caret_line();
int end_line = start_line;
- if (is_selection_active()) {
+ if (has_selection()) {
start_line = get_selection_from_line();
end_line = get_selection_to_line();
@@ -760,7 +760,7 @@ void CodeEdit::indent_lines() {
for (int i = start_line; i <= end_line; i++) {
const String line_text = get_line(i);
- if (line_text.size() == 0 && is_selection_active()) {
+ if (line_text.size() == 0 && has_selection()) {
continue;
}
@@ -777,7 +777,7 @@ void CodeEdit::indent_lines() {
}
/* Fix selection and caret being off after shifting selection right.*/
- if (is_selection_active()) {
+ if (has_selection()) {
select(start_line, get_selection_from_column() + selection_offset, get_selection_to_line(), get_selection_to_column() + selection_offset);
}
set_caret_column(get_caret_column() + selection_offset, false);
@@ -792,7 +792,7 @@ void CodeEdit::do_unindent() {
int cc = get_caret_column();
- if (is_selection_active() || cc <= 0) {
+ if (has_selection() || cc <= 0) {
unindent_lines();
return;
}
@@ -839,7 +839,7 @@ void CodeEdit::unindent_lines() {
int start_line = get_caret_line();
int end_line = start_line;
- if (is_selection_active()) {
+ if (has_selection()) {
start_line = get_selection_from_line();
end_line = get_selection_to_line();
@@ -882,7 +882,7 @@ void CodeEdit::unindent_lines() {
}
}
- if (is_selection_active()) {
+ if (has_selection()) {
/* Fix selection being off by one on the first line. */
if (first_line_edited) {
select(get_selection_from_line(), get_selection_from_column() - removed_characters, get_selection_to_line(), initial_selection_end_column);
@@ -1423,7 +1423,7 @@ void CodeEdit::fold_line(int p_line) {
}
/* Fix selection. */
- if (is_selection_active()) {
+ if (has_selection()) {
if (is_line_hidden(get_selection_from_line()) && is_line_hidden(get_selection_to_line())) {
deselect();
} else if (is_line_hidden(get_selection_from_line())) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e77c8188cc..5cd95fbbf7 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -315,30 +315,6 @@ void TextEdit::_update_scrollbars() {
updating_scrolls = false;
}
-void TextEdit::_click_selection_held() {
- // Warning: is_mouse_button_pressed(MOUSE_BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
- // and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
- // I'm unsure if there's an actual fix that doesn't have a ton of side effects.
- if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
- switch (selection.selecting_mode) {
- case SelectionMode::SELECTION_MODE_POINTER: {
- _update_selection_mode_pointer();
- } break;
- case SelectionMode::SELECTION_MODE_WORD: {
- _update_selection_mode_word();
- } break;
- case SelectionMode::SELECTION_MODE_LINE: {
- _update_selection_mode_line();
- } break;
- default: {
- break;
- }
- }
- } else {
- click_select_held->stop();
- }
-}
-
Point2 TextEdit::_get_local_mouse_pos() const {
Point2 mp = get_local_mouse_position();
if (is_layout_rtl()) {
@@ -347,96 +323,6 @@ Point2 TextEdit::_get_local_mouse_pos() const {
return mp;
}
-void TextEdit::_update_selection_mode_pointer() {
- dragging_selection = true;
- Point2 mp = _get_local_mouse_pos();
-
- int row, col;
- _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
-
- select(selection.selecting_line, selection.selecting_column, row, col);
-
- set_caret_line(row, false);
- set_caret_column(col);
- update();
-
- click_select_held->start();
-}
-
-void TextEdit::_update_selection_mode_word() {
- dragging_selection = true;
- Point2 mp = _get_local_mouse_pos();
-
- int row, col;
- _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
-
- String line = text[row];
- int caret_pos = CLAMP(col, 0, line.length());
- int beg = caret_pos;
- int end = beg;
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(row)->get_rid());
- for (int i = 0; i < words.size(); i++) {
- if (words[i].x < caret_pos && words[i].y > caret_pos) {
- beg = words[i].x;
- end = words[i].y;
- break;
- }
- }
-
- // Initial selection.
- if (!selection.active) {
- select(row, beg, row, end);
- selection.selecting_column = beg;
- 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);
- } else {
- if ((col <= selection.selected_word_origin && row == selection.selecting_line) || row < selection.selecting_line) {
- selection.selecting_column = selection.selected_word_end;
- select(row, beg, selection.selecting_line, selection.selected_word_end);
- set_caret_line(selection.from_line, false);
- set_caret_column(selection.from_column);
- } else {
- selection.selecting_column = selection.selected_word_beg;
- select(selection.selecting_line, selection.selected_word_beg, row, end);
- set_caret_line(selection.to_line, false);
- set_caret_column(selection.to_column);
- }
- }
-
- update();
-
- click_select_held->start();
-}
-
-void TextEdit::_update_selection_mode_line() {
- dragging_selection = true;
- Point2 mp = _get_local_mouse_pos();
-
- int row, col;
- _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
-
- col = 0;
- if (row < selection.selecting_line) {
- // Caret is above us.
- set_caret_line(row - 1, false);
- selection.selecting_column = text[selection.selecting_line].length();
- } else {
- // Caret is below us.
- set_caret_line(row + 1, false);
- selection.selecting_column = 0;
- col = text[row].length();
- }
- set_caret_column(0);
-
- select(selection.selecting_line, selection.selecting_column, row, col);
- update();
-
- click_select_held->start();
-}
-
void TextEdit::_update_minimap_click() {
Point2 mp = _get_local_mouse_pos();
@@ -739,7 +625,7 @@ void TextEdit::_notification(int p_what) {
}
// Get the highlighted words.
- String highlighted_text = get_selection_text();
+ String highlighted_text = get_selected_text();
// Check if highlighted words contain only whitespaces (tabs or spaces).
bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String();
@@ -1010,9 +896,9 @@ void TextEdit::_notification(int p_what) {
if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) {
int char_w = cache.font->get_char_size(' ', 0, cache.font_size).width;
if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), cache.selection_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), selection_color);
} else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, row_height), cache.selection_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, row_height), selection_color);
}
}
} else {
@@ -1124,7 +1010,7 @@ void TextEdit::_notification(int p_what) {
if (rect.position.x + rect.size.x > xmargin_end) {
rect.size.x = xmargin_end - rect.position.x;
}
- draw_rect(rect, cache.selection_color, true);
+ draw_rect(rect, selection_color, true);
}
}
@@ -1192,7 +1078,7 @@ void TextEdit::_notification(int p_what) {
}
rect.position.y = TS->shaped_text_get_ascent(rid) + cache.font->get_underline_position(cache.font_size);
rect.size.y = cache.font->get_underline_thickness(cache.font_size);
- draw_rect(rect, cache.font_selected_color);
+ draw_rect(rect, font_selected_color);
}
highlighted_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, highlighted_word_col + 1);
@@ -1237,7 +1123,7 @@ void TextEdit::_notification(int p_what) {
int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column;
if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
- current_color = cache.font_selected_color;
+ current_color = font_selected_color;
}
}
@@ -1457,7 +1343,7 @@ void TextEdit::_notification(int p_what) {
caret_start = full_text.length();
} else {
String pre_text = _base_get_text(0, 0, selection.from_line, selection.from_column);
- String post_text = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ String post_text = get_selected_text();
caret_start = pre_text.length();
caret_end = caret_start + post_text.length();
@@ -1794,7 +1680,7 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
return;
}
- if (is_selection_active() || (!p_all_to_left && !p_word)) {
+ if (has_selection() || (!p_all_to_left && !p_word)) {
backspace();
return;
}
@@ -1831,7 +1717,7 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
return;
}
- if (is_selection_active()) {
+ if (has_selection()) {
delete_selection();
return;
}
@@ -1877,19 +1763,6 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
update();
}
-void TextEdit::delete_selection() {
- if (!is_selection_active()) {
- return;
- }
-
- selection.active = false;
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- set_caret_line(selection.from_line, false, false);
- set_caret_column(selection.from_column);
- update();
-}
-
void TextEdit::_move_caret_document_start(bool p_select) {
if (p_select) {
_pre_shift_selection();
@@ -2187,7 +2060,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_get_mouse_pos(Point2i(mpos.x, mpos.y), row, col);
if (is_move_caret_on_right_click_enabled()) {
- if (is_selection_active()) {
+ if (has_selection()) {
int from_line = get_selection_from_line();
int to_line = get_selection_to_line();
int from_column = get_selection_from_column();
@@ -2198,7 +2071,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
deselect();
}
}
- if (!is_selection_active()) {
+ if (!has_selection()) {
set_caret_line(row, true, false);
set_caret_column(col);
}
@@ -2565,25 +2438,6 @@ void TextEdit::_scroll_down(real_t p_delta) {
}
}
-void TextEdit::_pre_shift_selection() {
- if (!selection.active || selection.selecting_mode == SelectionMode::SELECTION_MODE_NONE) {
- selection.selecting_line = caret.line;
- selection.selecting_column = caret.column;
- selection.active = true;
- }
-
- selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
-}
-
-void TextEdit::_post_shift_selection() {
- if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) {
- select(selection.selecting_line, selection.selecting_column, caret.line, caret.column);
- update();
- }
-
- selection.selecting_text = true;
-}
-
void TextEdit::_scroll_lines_up() {
scrolling = false;
minimap_clicked = false;
@@ -3022,30 +2876,6 @@ void TextEdit::center_viewport_to_caret() {
update();
}
-TextEdit::SelectionMode TextEdit::get_selection_mode() const {
- return selection.selecting_mode;
-}
-
-void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column) {
- selection.selecting_mode = p_mode;
- if (p_line >= 0) {
- ERR_FAIL_INDEX(p_line, text.size());
- selection.selecting_line = p_line;
- }
- if (p_column >= 0) {
- ERR_FAIL_INDEX(p_column, text[selection.selecting_line].length());
- selection.selecting_column = p_column;
- }
-}
-
-int TextEdit::get_selection_line() const {
- return selection.selecting_line;
-};
-
-int TextEdit::get_selection_column() const {
- return selection.selecting_column;
-};
-
void TextEdit::_v_scroll_input() {
scrolling = false;
minimap_clicked = false;
@@ -3374,6 +3204,10 @@ void TextEdit::_update_caches() {
caret_color = get_theme_color(SNAME("caret_color"));
caret_background_color = get_theme_color(SNAME("caret_background_color"));
+ /* Selection */
+ font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ selection_color = get_theme_color(SNAME("selection_color"));
+
cache.style_normal = get_theme_stylebox(SNAME("normal"));
cache.style_focus = get_theme_stylebox(SNAME("focus"));
cache.style_readonly = get_theme_stylebox(SNAME("read_only"));
@@ -3382,9 +3216,7 @@ void TextEdit::_update_caches() {
cache.outline_color = get_theme_color(SNAME("font_outline_color"));
cache.outline_size = get_theme_constant(SNAME("outline_size"));
cache.font_color = get_theme_color(SNAME("font_color"));
- cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
cache.font_readonly_color = get_theme_color(SNAME("font_readonly_color"));
- cache.selection_color = get_theme_color(SNAME("selection_color"));
cache.current_line_color = get_theme_color(SNAME("current_line_color"));
cache.code_folding_color = get_theme_color(SNAME("code_folding_color"), SNAME("CodeEdit"));
cache.brace_mismatch_color = get_theme_color(SNAME("brace_mismatch_color"), SNAME("CodeEdit"));
@@ -3621,6 +3453,215 @@ int TextEdit::get_caret_wrap_index() const {
return get_line_wrap_index_at_column(caret.line, caret.column);
}
+/* Selection. */
+void TextEdit::set_selecting_enabled(const bool p_enabled) {
+ selecting_enabled = p_enabled;
+
+ if (!selecting_enabled) {
+ deselect();
+ }
+
+ _ensure_menu();
+}
+
+bool TextEdit::is_selecting_enabled() const {
+ return selecting_enabled;
+}
+
+void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
+ override_selected_font_color = p_override_selected_font_color;
+}
+
+bool TextEdit::is_overriding_selected_font_color() const {
+ return override_selected_font_color;
+}
+
+void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column) {
+ selection.selecting_mode = p_mode;
+ if (p_line >= 0) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ selection.selecting_line = p_line;
+ }
+ if (p_column >= 0) {
+ ERR_FAIL_INDEX(p_column, text[selection.selecting_line].length());
+ selection.selecting_column = p_column;
+ }
+}
+
+TextEdit::SelectionMode TextEdit::get_selection_mode() const {
+ return selection.selecting_mode;
+}
+
+void TextEdit::select_all() {
+ if (!selecting_enabled) {
+ return;
+ }
+
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
+ }
+ selection.active = true;
+ selection.from_line = 0;
+ selection.from_column = 0;
+ selection.selecting_line = 0;
+ selection.selecting_column = 0;
+ selection.to_line = text.size() - 1;
+ selection.to_column = text[selection.to_line].length();
+ selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
+ selection.shiftclick_left = true;
+ set_caret_line(selection.to_line, false);
+ set_caret_column(selection.to_column, false);
+ update();
+}
+
+void TextEdit::select_word_under_caret() {
+ if (!selecting_enabled) {
+ return;
+ }
+
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
+ }
+
+ if (selection.active) {
+ /* Allow toggling selection by pressing the shortcut a second time. */
+ /* This is also usable as a general-purpose "deselect" shortcut after */
+ /* selecting anything. */
+ deselect();
+ return;
+ }
+
+ int begin = 0;
+ int end = 0;
+ const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x <= caret.column && words[i].y >= caret.column) {
+ begin = words[i].x;
+ end = words[i].y;
+ break;
+ }
+ }
+
+ select(caret.line, begin, caret.line, end);
+ /* Move the caret to the end of the word for easier editing. */
+ set_caret_column(end, false);
+}
+
+void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
+ if (!selecting_enabled) {
+ return;
+ }
+
+ if (p_from_line < 0) {
+ p_from_line = 0;
+ } else if (p_from_line >= text.size()) {
+ p_from_line = text.size() - 1;
+ }
+ if (p_from_column >= text[p_from_line].length()) {
+ p_from_column = text[p_from_line].length();
+ }
+ if (p_from_column < 0) {
+ p_from_column = 0;
+ }
+
+ if (p_to_line < 0) {
+ p_to_line = 0;
+ } else if (p_to_line >= text.size()) {
+ p_to_line = text.size() - 1;
+ }
+ if (p_to_column >= text[p_to_line].length()) {
+ p_to_column = text[p_to_line].length();
+ }
+ if (p_to_column < 0) {
+ p_to_column = 0;
+ }
+
+ selection.from_line = p_from_line;
+ selection.from_column = p_from_column;
+ selection.to_line = p_to_line;
+ selection.to_column = p_to_column;
+
+ selection.active = true;
+
+ if (selection.from_line == selection.to_line) {
+ if (selection.from_column == selection.to_column) {
+ selection.active = false;
+
+ } else if (selection.from_column > selection.to_column) {
+ selection.shiftclick_left = false;
+ SWAP(selection.from_column, selection.to_column);
+ } else {
+ selection.shiftclick_left = true;
+ }
+ } else if (selection.from_line > selection.to_line) {
+ selection.shiftclick_left = false;
+ SWAP(selection.from_line, selection.to_line);
+ SWAP(selection.from_column, selection.to_column);
+ } else {
+ selection.shiftclick_left = true;
+ }
+
+ update();
+}
+
+bool TextEdit::has_selection() const {
+ return selection.active;
+}
+
+String TextEdit::get_selected_text() const {
+ if (!selection.active) {
+ return "";
+ }
+
+ return _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+}
+
+int TextEdit::get_selection_line() const {
+ return selection.selecting_line;
+}
+
+int TextEdit::get_selection_column() const {
+ return selection.selecting_column;
+}
+
+int TextEdit::get_selection_from_line() const {
+ ERR_FAIL_COND_V(!selection.active, -1);
+ return selection.from_line;
+}
+
+int TextEdit::get_selection_from_column() const {
+ ERR_FAIL_COND_V(!selection.active, -1);
+ return selection.from_column;
+}
+
+int TextEdit::get_selection_to_line() const {
+ ERR_FAIL_COND_V(!selection.active, -1);
+ return selection.to_line;
+}
+
+int TextEdit::get_selection_to_column() const {
+ ERR_FAIL_COND_V(!selection.active, -1);
+ return selection.to_column;
+}
+
+void TextEdit::deselect() {
+ selection.active = false;
+ update();
+}
+
+void TextEdit::delete_selection() {
+ if (!has_selection()) {
+ return;
+ }
+
+ selection.active = false;
+ selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
+ _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ set_caret_line(selection.from_line, false, false);
+ set_caret_column(selection.from_column);
+ update();
+}
+
/* line wrapping. */
void TextEdit::set_line_wrapping_mode(LineWrappingMode p_wrapping_mode) {
if (line_wrapping_mode != p_wrapping_mode) {
@@ -3934,123 +3975,6 @@ Color TextEdit::get_line_background_color(int p_line) {
return text.get_line_background_color(p_line);
}
-void TextEdit::select_all() {
- if (!selecting_enabled) {
- return;
- }
-
- if (text.size() == 1 && text[0].length() == 0) {
- return;
- }
- selection.active = true;
- selection.from_line = 0;
- selection.from_column = 0;
- selection.selecting_line = 0;
- selection.selecting_column = 0;
- selection.to_line = text.size() - 1;
- selection.to_column = text[selection.to_line].length();
- selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
- selection.shiftclick_left = true;
- set_caret_line(selection.to_line, false);
- set_caret_column(selection.to_column, false);
- update();
-}
-
-void TextEdit::select_word_under_caret() {
- if (!selecting_enabled) {
- return;
- }
-
- if (text.size() == 1 && text[0].length() == 0) {
- return;
- }
-
- if (selection.active) {
- // Allow toggling selection by pressing the shortcut a second time.
- // This is also usable as a general-purpose "deselect" shortcut after
- // selecting anything.
- deselect();
- return;
- }
-
- int begin = 0;
- int end = 0;
- const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- for (int i = 0; i < words.size(); i++) {
- if (words[i].x <= caret.column && words[i].y >= caret.column) {
- begin = words[i].x;
- end = words[i].y;
- break;
- }
- }
-
- select(caret.line, begin, caret.line, end);
- // Move the caret to the end of the word for easier editing.
- set_caret_column(end, false);
-}
-
-void TextEdit::deselect() {
- selection.active = false;
- update();
-}
-
-void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
- if (!selecting_enabled) {
- return;
- }
-
- if (p_from_line < 0) {
- p_from_line = 0;
- } else if (p_from_line >= text.size()) {
- p_from_line = text.size() - 1;
- }
- if (p_from_column >= text[p_from_line].length()) {
- p_from_column = text[p_from_line].length();
- }
- if (p_from_column < 0) {
- p_from_column = 0;
- }
-
- if (p_to_line < 0) {
- p_to_line = 0;
- } else if (p_to_line >= text.size()) {
- p_to_line = text.size() - 1;
- }
- if (p_to_column >= text[p_to_line].length()) {
- p_to_column = text[p_to_line].length();
- }
- if (p_to_column < 0) {
- p_to_column = 0;
- }
-
- selection.from_line = p_from_line;
- selection.from_column = p_from_column;
- selection.to_line = p_to_line;
- selection.to_column = p_to_column;
-
- selection.active = true;
-
- if (selection.from_line == selection.to_line) {
- if (selection.from_column == selection.to_column) {
- selection.active = false;
-
- } else if (selection.from_column > selection.to_column) {
- selection.shiftclick_left = false;
- SWAP(selection.from_column, selection.to_column);
- } else {
- selection.shiftclick_left = true;
- }
- } else if (selection.from_line > selection.to_line) {
- selection.shiftclick_left = false;
- SWAP(selection.from_line, selection.to_line);
- SWAP(selection.from_column, selection.to_column);
- } else {
- selection.shiftclick_left = true;
- }
-
- update();
-}
-
void TextEdit::swap_lines(int line1, int line2) {
String tmp = get_line(line1);
String tmp2 = get_line(line2);
@@ -4058,38 +3982,6 @@ void TextEdit::swap_lines(int line1, int line2) {
set_line(line1, tmp2);
}
-bool TextEdit::is_selection_active() const {
- return selection.active;
-}
-
-int TextEdit::get_selection_from_line() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.from_line;
-}
-
-int TextEdit::get_selection_from_column() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.from_column;
-}
-
-int TextEdit::get_selection_to_line() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.to_line;
-}
-
-int TextEdit::get_selection_to_column() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.to_column;
-}
-
-String TextEdit::get_selection_text() const {
- if (!selection.active) {
- return "";
- }
-
- return _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
-}
-
String TextEdit::get_word_under_caret() const {
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
for (int i = 0; i < words.size(); i++) {
@@ -4643,14 +4535,6 @@ bool TextEdit::is_drawing_spaces() const {
return draw_spaces;
}
-void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
- override_selected_font_color = p_override_selected_font_color;
-}
-
-bool TextEdit::is_overriding_selected_font_color() const {
- return override_selected_font_color;
-}
-
void TextEdit::set_insert_mode(bool p_enabled) {
insert_mode = p_enabled;
update();
@@ -4860,7 +4744,7 @@ void TextEdit::set_line(int line, String new_text) {
if (caret.line == line) {
caret.column = MIN(caret.column, new_text.length());
}
- if (is_selection_active() && line == selection.to_line && selection.to_column > text[line].length()) {
+ if (has_selection() && line == selection.to_line && selection.to_column > text[line].length()) {
selection.to_column = text[line].length();
}
}
@@ -4871,7 +4755,7 @@ void TextEdit::insert_at(const String &p_text, int at) {
// offset cursor when located after inserted line
++caret.line;
}
- if (is_selection_active()) {
+ if (has_selection()) {
if (selection.from_line >= at) {
// offset selection when located after inserted line
++selection.from_line;
@@ -5080,18 +4964,6 @@ void TextEdit::set_virtual_keyboard_enabled(bool p_enable) {
virtual_keyboard_enabled = p_enable;
}
-void TextEdit::set_selecting_enabled(bool p_enabled) {
- selecting_enabled = p_enabled;
-
- if (!selecting_enabled) {
- deselect();
- }
-}
-
-bool TextEdit::is_selecting_enabled() const {
- return selecting_enabled;
-}
-
bool TextEdit::is_shortcut_keys_enabled() const {
return shortcut_keys_enabled;
}
@@ -5170,12 +5042,6 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(SEARCH_WHOLE_WORDS);
BIND_ENUM_CONSTANT(SEARCH_BACKWARDS);
- BIND_ENUM_CONSTANT(SELECTION_MODE_NONE);
- BIND_ENUM_CONSTANT(SELECTION_MODE_SHIFT);
- BIND_ENUM_CONSTANT(SELECTION_MODE_POINTER);
- BIND_ENUM_CONSTANT(SELECTION_MODE_WORD);
- BIND_ENUM_CONSTANT(SELECTION_MODE_LINE);
-
ClassDB::bind_method(D_METHOD("get_draw_control_chars"), &TextEdit::get_draw_control_chars);
ClassDB::bind_method(D_METHOD("set_draw_control_chars", "enable"), &TextEdit::set_draw_control_chars);
ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &TextEdit::set_text_direction);
@@ -5207,11 +5073,6 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("center_viewport_to_caret"), &TextEdit::center_viewport_to_caret);
- ClassDB::bind_method(D_METHOD("get_selection_mode"), &TextEdit::get_selection_mode);
- ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_selection_line"), &TextEdit::get_selection_line);
- ClassDB::bind_method(D_METHOD("get_selection_column"), &TextEdit::get_selection_column);
-
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
@@ -5221,22 +5082,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled);
ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &TextEdit::set_virtual_keyboard_enabled);
ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &TextEdit::is_virtual_keyboard_enabled);
- ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
- ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
-
- ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection);
- ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select);
- ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
- ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
ClassDB::bind_method(D_METHOD("is_dragging_cursor"), &TextEdit::is_dragging_cursor);
- ClassDB::bind_method(D_METHOD("is_selection_active"), &TextEdit::is_selection_active);
- ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line);
- ClassDB::bind_method(D_METHOD("get_selection_from_column"), &TextEdit::get_selection_from_column);
- ClassDB::bind_method(D_METHOD("get_selection_to_line"), &TextEdit::get_selection_to_line);
- ClassDB::bind_method(D_METHOD("get_selection_to_column"), &TextEdit::get_selection_to_column);
- ClassDB::bind_method(D_METHOD("get_selection_text"), &TextEdit::get_selection_text);
ClassDB::bind_method(D_METHOD("get_word_under_caret"), &TextEdit::get_word_under_caret);
ClassDB::bind_method(D_METHOD("search", "key", "flags", "from_line", "from_column"), &TextEdit::_search_bind);
@@ -5304,6 +5152,38 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_caret_wrap_index"), &TextEdit::get_caret_wrap_index);
+ /* Selection. */
+ BIND_ENUM_CONSTANT(SELECTION_MODE_NONE);
+ BIND_ENUM_CONSTANT(SELECTION_MODE_SHIFT);
+ BIND_ENUM_CONSTANT(SELECTION_MODE_POINTER);
+ BIND_ENUM_CONSTANT(SELECTION_MODE_WORD);
+ BIND_ENUM_CONSTANT(SELECTION_MODE_LINE);
+
+ ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("get_selection_mode"), &TextEdit::get_selection_mode);
+
+ ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
+ ClassDB::bind_method(D_METHOD("select_word_under_caret"), &TextEdit::select_word_under_caret);
+ ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select);
+
+ ClassDB::bind_method(D_METHOD("has_selection"), &TextEdit::has_selection);
+
+ ClassDB::bind_method(D_METHOD("get_selected_text"), &TextEdit::get_selected_text);
+
+ ClassDB::bind_method(D_METHOD("get_selection_line"), &TextEdit::get_selection_line);
+ ClassDB::bind_method(D_METHOD("get_selection_column"), &TextEdit::get_selection_column);
+
+ ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line);
+ ClassDB::bind_method(D_METHOD("get_selection_from_column"), &TextEdit::get_selection_from_column);
+ ClassDB::bind_method(D_METHOD("get_selection_to_line"), &TextEdit::get_selection_to_line);
+ ClassDB::bind_method(D_METHOD("get_selection_to_column"), &TextEdit::get_selection_to_column);
+
+ ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
+ ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection);
+
/* line wrapping. */
BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE);
BIND_ENUM_CONSTANT(LINE_WRAPPING_BOUNDARY);
@@ -5549,7 +5429,7 @@ void TextEdit::_handle_unicode_input(const uint32_t p_unicode) {
return;
}
- bool had_selection = is_selection_active();
+ bool had_selection = has_selection();
if (had_selection) {
begin_complex_operation();
delete_selection();
@@ -5587,7 +5467,7 @@ void TextEdit::_backspace() {
return;
}
- if (is_selection_active()) {
+ if (has_selection()) {
delete_selection();
return;
}
@@ -5611,8 +5491,8 @@ void TextEdit::_cut() {
return;
}
- if (is_selection_active()) {
- DisplayServer::get_singleton()->clipboard_set(get_selection_text());
+ if (has_selection()) {
+ DisplayServer::get_singleton()->clipboard_set(get_selected_text());
delete_selection();
cut_copy_line = "";
return;
@@ -5637,8 +5517,8 @@ void TextEdit::_cut() {
}
void TextEdit::_copy() {
- if (is_selection_active()) {
- DisplayServer::get_singleton()->clipboard_set(get_selection_text());
+ if (has_selection()) {
+ DisplayServer::get_singleton()->clipboard_set(get_selected_text());
cut_copy_line = "";
return;
}
@@ -5659,7 +5539,7 @@ void TextEdit::_paste() {
String clipboard = DisplayServer::get_singleton()->clipboard_get();
begin_complex_operation();
- if (is_selection_active()) {
+ if (has_selection()) {
delete_selection();
} else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) {
set_caret_column(0);
@@ -5697,6 +5577,139 @@ void TextEdit::_toggle_draw_caret() {
}
}
+/* Selection */
+void TextEdit::_click_selection_held() {
+ // Warning: is_mouse_button_pressed(MOUSE_BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
+ // and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
+ // I'm unsure if there's an actual fix that doesn't have a ton of side effects.
+ if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
+ switch (selection.selecting_mode) {
+ case SelectionMode::SELECTION_MODE_POINTER: {
+ _update_selection_mode_pointer();
+ } break;
+ case SelectionMode::SELECTION_MODE_WORD: {
+ _update_selection_mode_word();
+ } break;
+ case SelectionMode::SELECTION_MODE_LINE: {
+ _update_selection_mode_line();
+ } break;
+ default: {
+ break;
+ }
+ }
+ } else {
+ click_select_held->stop();
+ }
+}
+
+void TextEdit::_update_selection_mode_pointer() {
+ dragging_selection = true;
+ Point2 mp = _get_local_mouse_pos();
+
+ int line, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), line, col);
+
+ select(selection.selecting_line, selection.selecting_column, line, col);
+
+ set_caret_line(line, false);
+ set_caret_column(col);
+ update();
+
+ click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_word() {
+ dragging_selection = true;
+ Point2 mp = _get_local_mouse_pos();
+
+ int line, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), line, col);
+
+ int caret_pos = CLAMP(col, 0, text[line].length());
+ int beg = caret_pos;
+ int end = beg;
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x < caret_pos && words[i].y > caret_pos) {
+ beg = words[i].x;
+ end = words[i].y;
+ break;
+ }
+ }
+
+ /* Initial selection. */
+ if (!selection.active) {
+ select(line, beg, line, end);
+ selection.selecting_column = beg;
+ 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);
+ } else {
+ if ((col <= selection.selected_word_origin && line == selection.selecting_line) || line < selection.selecting_line) {
+ selection.selecting_column = selection.selected_word_end;
+ select(line, beg, selection.selecting_line, selection.selected_word_end);
+ set_caret_line(selection.from_line, false);
+ set_caret_column(selection.from_column);
+ } else {
+ selection.selecting_column = selection.selected_word_beg;
+ select(selection.selecting_line, selection.selected_word_beg, line, end);
+ set_caret_line(selection.to_line, false);
+ set_caret_column(selection.to_column);
+ }
+ }
+
+ update();
+
+ click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_line() {
+ dragging_selection = true;
+ Point2 mp = _get_local_mouse_pos();
+
+ int line, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), line, col);
+
+ col = 0;
+ if (line < selection.selecting_line) {
+ /* Caret is above us. */
+ set_caret_line(line - 1, false);
+ selection.selecting_column = text[selection.selecting_line].length();
+ } else {
+ /* Caret is below us. */
+ set_caret_line(line + 1, false);
+ selection.selecting_column = 0;
+ col = text[line].length();
+ }
+ set_caret_column(0);
+
+ select(selection.selecting_line, selection.selecting_column, line, col);
+ update();
+
+ click_select_held->start();
+}
+
+void TextEdit::_pre_shift_selection() {
+ if (!selection.active || selection.selecting_mode == SelectionMode::SELECTION_MODE_NONE) {
+ selection.selecting_line = caret.line;
+ selection.selecting_column = caret.column;
+ selection.active = true;
+ }
+
+ selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
+}
+
+void TextEdit::_post_shift_selection() {
+ if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) {
+ select(selection.selecting_line, selection.selecting_column, caret.line, caret.column);
+ update();
+ }
+
+ selection.selecting_text = true;
+}
+
/* Line Wrapping */
void TextEdit::_update_wrap_at_column(bool p_force) {
int new_wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding;
@@ -5752,23 +5765,25 @@ TextEdit::TextEdit() {
v_scroll->connect("scrolling", callable_mp(this, &TextEdit::_v_scroll_input));
+ /* Caret. */
caret_blink_timer = memnew(Timer);
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &TextEdit::_toggle_draw_caret));
set_caret_blink_enabled(false);
+ /* Selection. */
+ click_select_held = memnew(Timer);
+ add_child(click_select_held);
+ click_select_held->set_wait_time(0.05);
+ click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held));
+
idle_detect = memnew(Timer);
add_child(idle_detect);
idle_detect->set_one_shot(true);
idle_detect->set_wait_time(GLOBAL_GET("gui/timers/text_edit_idle_detect_sec"));
idle_detect->connect("timeout", callable_mp(this, &TextEdit::_push_current_op));
- click_select_held = memnew(Timer);
- add_child(click_select_held);
- click_select_held->set_wait_time(0.05);
- click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held));
-
undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size");
set_readonly(false);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 9eb83981eb..84ee356673 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -244,6 +244,26 @@ private:
bool shiftclick_left = false;
} selection;
+ bool selecting_enabled = true;
+
+ Color font_selected_color = Color(1, 1, 1);
+ Color selection_color = Color(1, 1, 1);
+ bool override_selected_font_color = false;
+
+ bool dragging_selection = false;
+
+ Timer *click_select_held;
+ uint64_t last_dblclk = 0;
+ Vector2 last_dblclk_pos;
+ void _click_selection_held();
+
+ void _update_selection_mode_pointer();
+ void _update_selection_mode_word();
+ void _update_selection_mode_line();
+
+ void _pre_shift_selection();
+ void _post_shift_selection();
+
/* line wrapping. */
LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE;
@@ -317,7 +337,6 @@ private:
bool first_draw = true;
bool draw_tabs = false;
bool draw_spaces = false;
- bool override_selected_font_color = false;
bool text_changed_dirty = false;
bool undo_enabled = true;
bool hiding_enabled = false;
@@ -331,11 +350,9 @@ private:
bool highlight_current_line = false;
bool insert_mode = false;
- bool select_identifiers_enabled = false;
bool smooth_scroll_enabled = false;
bool scrolling = false;
- bool dragging_selection = false;
bool dragging_minimap = false;
bool can_drag_minimap = false;
bool minimap_clicked = false;
@@ -346,11 +363,7 @@ private:
String lookup_symbol_word;
- uint64_t last_dblclk = 0;
- Vector2 last_dblclk_pos;
-
Timer *idle_detect;
- Timer *click_select_held;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
bool updating_scrolls = false;
@@ -366,8 +379,6 @@ private:
int search_result_line = 0;
int search_result_col = 0;
- bool selecting_enabled = true;
-
bool context_menu_enabled = true;
bool shortcut_keys_enabled = true;
bool virtual_keyboard_enabled = true;
@@ -394,20 +405,12 @@ private:
void _scroll_moved(double);
void _update_scrollbars();
void _v_scroll_input();
- void _click_selection_held();
-
- void _update_selection_mode_pointer();
- void _update_selection_mode_word();
- void _update_selection_mode_line();
void _update_minimap_click();
void _update_minimap_drag();
void _scroll_up(real_t p_delta);
void _scroll_down(real_t p_delta);
- void _pre_shift_selection();
- void _post_shift_selection();
-
void _scroll_lines_up();
void _scroll_lines_down();
@@ -470,9 +473,7 @@ protected:
int outline_size = 0;
Color outline_color;
Color font_color;
- Color font_selected_color;
Color font_readonly_color;
- Color selection_color;
Color code_folding_color;
Color current_line_color;
Color brace_mismatch_color;
@@ -548,6 +549,35 @@ public:
int get_caret_wrap_index() const;
+ /* Selection. */
+ void set_selecting_enabled(const bool p_enabled);
+ bool is_selecting_enabled() const;
+
+ void set_override_selected_font_color(bool p_override_selected_font_color);
+ bool is_overriding_selected_font_color() const;
+
+ void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1);
+ SelectionMode get_selection_mode() const;
+
+ void select_all();
+ void select_word_under_caret();
+ void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
+
+ bool has_selection() const;
+
+ String get_selected_text() const;
+
+ int get_selection_line() const;
+ int get_selection_column() const;
+
+ int get_selection_from_line() const;
+ int get_selection_from_column() const;
+ int get_selection_to_line() const;
+ int get_selection_to_column() const;
+
+ void deselect();
+ void delete_selection();
+
/* line wrapping. */
void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode);
LineWrappingMode get_line_wrapping_mode() const;
@@ -710,22 +740,11 @@ public:
void adjust_viewport_to_caret();
void center_viewport_to_caret();
- SelectionMode get_selection_mode() const;
- void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1);
- int get_selection_line() const;
- int get_selection_column() const;
-
void set_readonly(bool p_readonly);
bool is_readonly() const;
void clear();
- void delete_selection();
-
- void select_all();
- void select_word_under_caret();
- void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
- void deselect();
void swap_lines(int line1, int line2);
void set_search_text(const String &p_search_text);
@@ -734,12 +753,6 @@ public:
void set_highlight_all_occurrences(const bool p_enabled);
bool is_highlight_all_occurrences_enabled() const;
- bool is_selection_active() const;
- int get_selection_from_line() const;
- int get_selection_from_column() const;
- int get_selection_to_line() const;
- int get_selection_to_column() const;
- String get_selection_text() const;
String get_word_under_caret() const;
String get_word_at_pos(const Vector2 &p_pos) const;
@@ -756,8 +769,6 @@ public:
bool is_drawing_tabs() const;
void set_draw_spaces(bool p_draw);
bool is_drawing_spaces() const;
- void set_override_selected_font_color(bool p_override_selected_font_color);
- bool is_overriding_selected_font_color() const;
void set_insert_mode(bool p_enabled);
bool is_insert_mode() const;
@@ -797,9 +808,6 @@ public:
void set_context_menu_enabled(bool p_enable);
bool is_context_menu_enabled();
- void set_selecting_enabled(bool p_enabled);
- bool is_selecting_enabled() const;
-
void set_shortcut_keys_enabled(bool p_enabled);
bool is_shortcut_keys_enabled() const;