diff options
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r-- | scene/gui/text_edit.cpp | 194 |
1 files changed, 107 insertions, 87 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 07f1bdf8e5..2ce31ea1b3 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -42,14 +42,14 @@ #define TAB_PIXELS -static bool _is_text_char(CharType c) { +inline bool _is_symbol(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return is_symbol(c); } -static bool _is_symbol(CharType c) { +static bool _is_text_char(CharType c) { - return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' '); + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } static bool _is_whitespace(CharType c) { @@ -1695,10 +1695,9 @@ void TextEdit::indent_right() { // fix selection and cursor being off by one on the last line if (is_selection_active()) { - selection.to_column++; - selection.from_column++; + select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); } - cursor.column++; + cursor_set_column(cursor.column + 1, false); end_complex_operation(); update(); } @@ -1737,14 +1736,9 @@ void TextEdit::indent_left() { // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - if (selection.to_column > 0) - selection.to_column--; - if (selection.from_column > 0) - selection.from_column--; - } - if (cursor.column > 0) { - cursor.column--; + select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); } + cursor_set_column(cursor.column - 1, false); end_complex_operation(); update(); } @@ -1962,7 +1956,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else if (mb->is_doubleclick() && text[cursor.line].length()) { - //doubleclick select world + //doubleclick select word selection.selecting_mode = Selection::MODE_WORD; _update_selection_mode_word(); last_dblclk = OS::get_singleton()->get_ticks_msec(); @@ -1973,6 +1967,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + _reset_caret_blink_timer(); + + int row, col; + update_line_scroll_pos(); + _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); + + if (is_right_click_moving_caret()) { + if (is_selection_active()) { + + int from_line = get_selection_from_line(); + int to_line = get_selection_to_line(); + int from_column = get_selection_from_column(); + int to_column = get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + deselect(); + } + } + if (!is_selection_active()) { + cursor_set_line(row, true, false); + cursor_set_column(col); + } + } + menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); menu->popup(); @@ -2420,26 +2439,44 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { //simple unindent int cc = cursor.column; + + const int len = text[cursor.line].length(); + const String &line = text[cursor.line]; + + int left = 0; // number of whitespace chars at beginning of line + while (left < len && (line[left] == '\t' || line[left] == ' ')) + left++; + cc = MIN(cc, left); + + while (cc < indent_size && cc < left && line[cc] == ' ') + cc++; + if (cc > 0 && cc <= text[cursor.line].length()) { - if (text[cursor.line][cursor.column - 1] == '\t') { - backspace_at_cursor(); + if (text[cursor.line][cc - 1] == '\t') { + _remove_text(cursor.line, cc - 1, cursor.line, cc); + if (cursor.column >= left) + cursor_set_column(MAX(0, cursor.column - 1)); + update(); } else { - if (cursor.column - indent_size >= 0) { + int n = 0; - bool unindent = true; - for (int i = 1; i <= indent_size; i++) { - if (text[cursor.line][cursor.column - i] != ' ') { - unindent = false; - break; - } + for (int i = 1; i <= MIN(cc, indent_size); i++) { + if (line[cc - i] != ' ') { + break; } + n++; + } - if (unindent) { - _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column); - cursor_set_column(cursor.column - indent_size); - } + if (n > 0) { + _remove_text(cursor.line, cc - n, cursor.line, cc); + if (cursor.column > left - n) // inside text? + cursor_set_column(MAX(0, cursor.column - n)); + update(); } } + } else if (cc == 0 && line.length() > 0 && line[0] == '\t') { + _remove_text(cursor.line, 0, cursor.line, 1); + update(); } } else { //simple indent @@ -2544,22 +2581,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc == 0 && cursor.line > 0) { cursor_set_line(cursor.line - 1); cursor_set_column(text[cursor.line].length()); - break; - } - - while (cc > 0) { - - bool ischar = _is_text_char(text[cursor.line][cc - 1]); + } else { + while (cc > 0) { + bool ischar = _is_text_char(text[cursor.line][cc - 1]); - if (prev_char && !ischar) - break; + if (prev_char && !ischar) + break; - prev_char = ischar; - cc--; + prev_char = ischar; + cc--; + } + cursor_set_column(cc); } - cursor_set_column(cc); - } else if (cursor.column == 0) { if (cursor.line > 0) { @@ -2608,21 +2642,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) { cursor_set_line(cursor.line + 1); cursor_set_column(0); - break; - } - - while (cc < text[cursor.line].length()) { - - bool ischar = _is_text_char(text[cursor.line][cc]); + } else { + while (cc < text[cursor.line].length()) { + bool ischar = _is_text_char(text[cursor.line][cc]); - if (prev_char && !ischar) - break; - prev_char = ischar; - cc++; + if (prev_char && !ischar) + break; + prev_char = ischar; + cc++; + } + cursor_set_column(cc); } - cursor_set_column(cc); - } else if (cursor.column == text[cursor.line].length()) { if (cursor.line < text.size() - 1) { @@ -3708,6 +3739,14 @@ bool TextEdit::cursor_is_block_mode() const { return block_caret; } +void TextEdit::set_right_click_moves_caret(bool p_enable) { + right_click_moves_caret = p_enable; +} + +bool TextEdit::is_right_click_moving_caret() const { + return right_click_moves_caret; +} + void TextEdit::_v_scroll_input() { scrolling = false; } @@ -4168,11 +4207,15 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t 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 >= 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; @@ -5181,12 +5224,8 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { String s = text[row]; if (s.length() == 0) return ""; - int beg = CLAMP(col, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + int beg, end; + if (select_word(s, col, beg, end)) { bool inside_quotes = false; int qbegin = 0, qend = 0; @@ -5205,16 +5244,6 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { } } - while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) - end += 1; - return s.substr(beg, end - beg); } @@ -5231,22 +5260,8 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const { String s = text[row]; if (s.length() == 0) return Control::get_tooltip(p_pos); - int beg = CLAMP(col, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) - end += 1; + int beg, end; + if (select_word(s, col, beg, end)) { String tt = tooltip_obj->call(tooltip_func, s.substr(beg, end - beg), tooltip_ud); @@ -5457,6 +5472,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode); ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode); + ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret); + ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret); + ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly); ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly); @@ -5492,7 +5510,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); - ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden); + ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden); ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); @@ -5540,6 +5558,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret"); ADD_SIGNAL(MethodInfo("cursor_changed")); ADD_SIGNAL(MethodInfo("text_changed")); @@ -5617,6 +5636,7 @@ TextEdit::TextEdit() { caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", this, "_toggle_draw_caret"); cursor_set_blink_enabled(false); + right_click_moves_caret = true; idle_detect = memnew(Timer); add_child(idle_detect); |