diff options
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r-- | scene/gui/text_edit.cpp | 195 |
1 files changed, 84 insertions, 111 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index ef6bfc2e2d..ff0c723141 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -35,6 +35,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/project_settings.h" +#include "core/script_language.h" #include "scene/main/viewport.h" #ifdef TOOLS_ENABLED @@ -50,7 +51,7 @@ inline bool _is_symbol(CharType c) { static bool _is_text_char(CharType c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; + return !is_symbol(c); } static bool _is_whitespace(CharType c) { @@ -662,10 +663,8 @@ void TextEdit::_notification(int p_what) { int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci, Rect2(Point2(), size)); - float readonly_alpha = 1.0; // used to set the input text color when in read-only mode if (readonly) { cache.style_readonly->draw(ci, Rect2(Point2(), size)); - readonly_alpha = .5; draw_caret = false; } if (has_focus()) @@ -675,8 +674,7 @@ void TextEdit::_notification(int p_what) { int visible_rows = get_visible_rows() + 1; - Color color = cache.font_color; - color.a *= readonly_alpha; + Color color = readonly ? cache.font_color_readonly : cache.font_color; if (syntax_coloring) { if (cache.background_color.a > 0.01) { @@ -684,6 +682,13 @@ void TextEdit::_notification(int p_what) { } } + if (line_length_guideline) { + int x = xmargin_beg + (int)cache.font->get_char_size('0').width * line_length_guideline_col - cursor.x_ofs; + if (x > xmargin_beg && x < xmargin_end) { + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, size.height), cache.line_length_guideline_color); + } + } + int brace_open_match_line = -1; int brace_open_match_column = -1; bool brace_open_matching = false; @@ -871,10 +876,7 @@ void TextEdit::_notification(int p_what) { color_map = _get_line_syntax_highlighting(line); } // ensure we at least use the font color - Color current_color = cache.font_color; - if (readonly) { - current_color.a *= readonly_alpha; - } + Color current_color = readonly ? cache.font_color_readonly : cache.font_color; bool underlined = false; @@ -1061,10 +1063,7 @@ void TextEdit::_notification(int p_what) { if (syntax_coloring) { if (color_map.has(last_wrap_column + j)) { - current_color = color_map[last_wrap_column + j].color; - if (readonly) { - current_color.a *= readonly_alpha; - } + current_color = readonly ? cache.font_color_readonly : color_map[last_wrap_column + j].color; } color = current_color; } @@ -1178,7 +1177,7 @@ void TextEdit::_notification(int p_what) { if (brace_open_mismatch) color = cache.brace_mismatch_color; - drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); } if ((brace_close_match_line == line && brace_close_match_column == last_wrap_column + j) || @@ -1186,7 +1185,7 @@ void TextEdit::_notification(int p_what) { if (brace_close_mismatch) color = cache.brace_mismatch_color; - drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); } } @@ -1252,29 +1251,28 @@ void TextEdit::_notification(int p_what) { if (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index && block_caret && draw_caret && !insert_mode) { color = cache.caret_background_color; } else if (!syntax_coloring && block_caret) { - color = cache.font_color; - color.a *= readonly_alpha; + color = readonly ? cache.font_color_readonly : cache.font_color; } if (str[j] >= 32) { int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; - int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); + int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_color_selected : color); if (underlined) { float line_width = 1.0; #ifdef TOOLS_ENABLED line_width *= EDSCALE; #endif - draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), in_selection && override_selected_font_color ? cache.font_selected_color : color); + draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), in_selection && override_selected_font_color ? cache.font_color_selected : color); } } else if (draw_tabs && str[j] == '\t') { int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2; - cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_color_selected : color); } if (draw_spaces && str[j] == ' ') { int yofs = (get_row_height() - cache.space_icon->get_height()) / 2; - cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color); + cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_color_selected : color); } char_ofs += char_w; @@ -1349,13 +1347,6 @@ void TextEdit::_notification(int p_what) { } } - if (line_length_guideline) { - int x = xmargin_beg + cache.font->get_char_size('0').width * line_length_guideline_col - cursor.x_ofs; - if (x > xmargin_beg && x < xmargin_end) { - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, size.height), cache.line_length_guideline_color); - } - } - bool completion_below = false; if (completion_active) { // code completion box @@ -1372,7 +1363,7 @@ void TextEdit::_notification(int p_what) { if (completion_options.size() < 50) { for (int i = 0; i < completion_options.size(); i++) { - int w2 = MIN(cache.font->get_string_size(completion_options[i]).x, cmax_width); + int w2 = MIN(cache.font->get_string_size(completion_options[i].display).x, cmax_width); if (w2 > w) w = w2; } @@ -1380,6 +1371,11 @@ void TextEdit::_notification(int p_what) { w = cmax_width; } + // Add space for completion icons + const int icon_hsep = get_constant("hseparation", "ItemList"); + Size2 icon_area_size(get_row_height(), get_row_height()); + w += icon_area_size.width + icon_hsep; + int th = h + csb->get_minimum_size().y; if (cursor_pos.y + get_row_height() + th > get_size().height) { @@ -1407,7 +1403,7 @@ void TextEdit::_notification(int p_what) { } int line_from = CLAMP(completion_index - lines / 2, 0, completion_options.size() - lines); VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color); - draw_rect(Rect2(completion_rect.position, Size2(nofs, completion_rect.size.height)), cache.completion_existing_color); + draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(nofs, completion_rect.size.height)), cache.completion_existing_color); for (int i = 0; i < lines; i++) { @@ -1415,12 +1411,26 @@ void TextEdit::_notification(int p_what) { ERR_CONTINUE(l < 0 || l >= completion_options.size()); Color text_color = cache.completion_font_color; for (int j = 0; j < color_regions.size(); j++) { - if (completion_options[l].begins_with(color_regions[j].begin_key)) { + if (completion_options[l].insert_text.begins_with(color_regions[j].begin_key)) { text_color = color_regions[j].color; } } int yofs = (get_row_height() - cache.font->get_height()) / 2; - draw_string(cache.font, Point2(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent() + yofs), completion_options[l], text_color, completion_rect.size.width); + Point2 title_pos(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent() + yofs); + + //draw completion icon if it is valid + Ref<Texture> icon = completion_options[l].icon; + Rect2 icon_area(completion_rect.position.x, completion_rect.position.y + i * get_row_height(), icon_area_size.width, icon_area_size.height); + if (icon.is_valid()) { + const real_t max_scale = 0.7f; + const real_t side = max_scale * icon_area.size.width; + real_t scale = MIN(side / icon->get_width(), side / icon->get_height()); + Size2 icon_size = icon->get_size() * scale; + draw_texture_rect(icon, Rect2(icon_area.position + (icon_area.size - icon_size) / 2, icon_size)); + } + + title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep; + draw_string(cache.font, title_pos, completion_options[l].display, text_color, completion_rect.size.width); } if (scrollw) { @@ -1603,7 +1613,6 @@ void TextEdit::_consume_pair_symbol(CharType ch) { insert_text_at_cursor(ch_pair); cursor_set_column(cursor_position_to_move); - return; } void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column) { @@ -3278,28 +3287,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; - case KEY_U: { - if (!k->get_command() || k->get_shift()) { - scancode_handled = false; - break; - } else { - if (selection.active) { - int ini = selection.from_line; - int end = selection.to_line; - - for (int i = ini; i <= end; i++) { - _uncomment_line(i); - } - } else { - _uncomment_line(cursor.line); - if (cursor.column >= get_line(cursor.line).length()) { - cursor.column = MAX(0, get_line(cursor.line).length() - 1); - } - } - update(); - } - } break; - default: { scancode_handled = false; @@ -3358,24 +3345,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } -void TextEdit::_uncomment_line(int p_line) { - String line_text = get_line(p_line); - for (int i = 0; i < line_text.length(); i++) { - if (line_text[i] == '#') { - _remove_text(p_line, i, p_line, i + 1); - if (p_line == selection.to_line && selection.to_column > line_text.length() - 1) { - selection.to_column -= 1; - if (selection.to_column >= selection.from_column) { - selection.active = false; - } - } - return; - } else if (line_text[i] != '\t' && line_text[i] != ' ') { - return; - } - } -} - void TextEdit::_scroll_up(real_t p_delta) { if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta)) @@ -4078,7 +4047,7 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_ cursor.line = p_row; int n_col = get_char_pos_for_line(cursor.last_fit_x, p_row, p_wrap_index); - if (is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) { + if (n_col != 0 && is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) { Vector<String> rows = get_wrap_rows_text(p_row); int row_end_col = 0; for (int i = 0; i < p_wrap_index + 1; i++) { @@ -4169,7 +4138,7 @@ void TextEdit::_scroll_moved(double p_to_val) { int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; - for (n_line = 0; n_line < text.size(); n_line++) { + for (n_line = 0; n_line < text.size() - 1; n_line++) { if (!is_line_hidden(n_line)) { sc++; sc += times_line_wraps(n_line); @@ -4554,7 +4523,8 @@ void TextEdit::_update_caches() { cache.line_number_color = get_color("line_number_color"); cache.safe_line_number_color = get_color("safe_line_number_color"); cache.font_color = get_color("font_color"); - cache.font_selected_color = get_color("font_selected_color"); + cache.font_color_selected = get_color("font_color_selected"); + cache.font_color_readonly = get_color("font_color_readonly"); cache.keyword_color = get_color("keyword_color"); cache.function_color = get_color("function_color"); cache.member_variable_color = get_color("member_variable_color"); @@ -4682,6 +4652,8 @@ bool TextEdit::has_keyword_color(String p_keyword) const { } Color TextEdit::get_keyword_color(String p_keyword) const { + + ERR_FAIL_COND_V(!keywords.has(p_keyword), Color()); return keywords[p_keyword]; } @@ -4825,14 +4797,18 @@ void TextEdit::deselect() { void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) { - if (p_from_line >= text.size()) + 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 >= text.size()) + 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(); @@ -5402,11 +5378,7 @@ bool TextEdit::is_line_comment(int p_line) const { for (int i = 0; i < line_length - 1; i++) { if (_is_symbol(text[p_line][i]) && cri_map.has(i)) { const Text::ColorRegionInfo &cri = cri_map[i]; - if (color_regions[cri.region].begin_key == "#" || color_regions[cri.region].begin_key == "//") { - return true; - } else { - return false; - } + return color_regions[cri.region].begin_key == "#" || color_regions[cri.region].begin_key == "//"; } else if (_is_whitespace(text[p_line][i])) { continue; } else { @@ -5455,9 +5427,7 @@ bool TextEdit::is_folded(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), false); if (p_line + 1 >= text.size()) return false; - if (!is_line_hidden(p_line) && is_line_hidden(p_line + 1)) - return true; - return false; + return !is_line_hidden(p_line) && is_line_hidden(p_line + 1); } Vector<int> TextEdit::get_folded_lines() const { @@ -5611,7 +5581,7 @@ void TextEdit::undo() { TextOperation op = undo_stack_pos->get(); _do_text_op(op, true); - if (op.from_line != op.to_line || op.to_column != op.from_column + 1) + if (op.type != TextOperation::TYPE_INSERT && (op.from_line != op.to_line || op.to_column != op.from_column + 1)) select(op.from_line, op.from_column, op.to_line, op.to_column); current_op.version = op.prev_version; @@ -5935,12 +5905,12 @@ void TextEdit::_confirm_completion() { _remove_text(cursor.line, cursor.column - completion_base.length(), cursor.line, cursor.column); cursor_set_column(cursor.column - completion_base.length(), false); - insert_text_at_cursor(completion_current); + insert_text_at_cursor(completion_current.insert_text); // When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket. String line = text[cursor.line]; CharType next_char = line[cursor.column]; - CharType last_completion_char = completion_current[completion_current.length() - 1]; + CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1]; if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) { _base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); @@ -6076,39 +6046,41 @@ void TextEdit::_update_completion_candidates() { completion_base = s; Vector<float> sim_cache; bool single_quote = s.begins_with("'"); - Vector<String> completion_options_casei; + Vector<ScriptCodeCompletionOption> completion_options_casei; + + for (List<ScriptCodeCompletionOption>::Element *E = completion_sources.front(); E; E = E->next()) { + ScriptCodeCompletionOption &option = E->get(); - for (int i = 0; i < completion_strings.size(); i++) { - if (single_quote && completion_strings[i].is_quoted()) { - completion_strings.write[i] = completion_strings[i].unquote().quote("'"); + if (single_quote && option.display.is_quoted()) { + option.display = option.display.unquote().quote("'"); } - if (inquote && restore_quotes == 1 && !completion_strings[i].is_quoted()) { + if (inquote && restore_quotes == 1 && !option.display.is_quoted()) { String quote = single_quote ? "'" : "\""; - completion_strings.write[i] = completion_strings[i].quote(quote); + option.display = option.display.quote(quote); } - if (completion_strings[i].begins_with(s)) { - completion_options.push_back(completion_strings[i]); - } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) { - completion_options_casei.push_back(completion_strings[i]); + if (option.display.begins_with(s)) { + completion_options.push_back(option); + } else if (option.display.to_lower().begins_with(s.to_lower())) { + completion_options_casei.push_back(option); } } completion_options.append_array(completion_options_casei); if (completion_options.size() == 0) { - for (int i = 0; i < completion_strings.size(); i++) { - if (s.is_subsequence_of(completion_strings[i])) { - completion_options.push_back(completion_strings[i]); + for (int i = 0; i < completion_sources.size(); i++) { + if (s.is_subsequence_of(completion_sources[i].display)) { + completion_options.push_back(completion_sources[i]); } } } if (completion_options.size() == 0) { - for (int i = 0; i < completion_strings.size(); i++) { - if (s.is_subsequence_ofi(completion_strings[i])) { - completion_options.push_back(completion_strings[i]); + for (int i = 0; i < completion_sources.size(); i++) { + if (s.is_subsequence_ofi(completion_sources[i].display)) { + completion_options.push_back(completion_sources[i]); } } } @@ -6119,7 +6091,7 @@ void TextEdit::_update_completion_candidates() { return; } - if (completion_options.size() == 1 && s == completion_options[0]) { + if (completion_options.size() == 1 && s == completion_options[0].display) { // A perfect match, stop completion _cancel_completion(); return; @@ -6157,12 +6129,12 @@ void TextEdit::set_code_hint(const String &p_hint) { update(); } -void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) { +void TextEdit::code_complete(const List<ScriptCodeCompletionOption> &p_strings, bool p_forced) { - completion_strings = p_strings; + completion_sources = p_strings; completion_active = true; completion_forced = p_forced; - completion_current = ""; + completion_current = ScriptCodeCompletionOption(); completion_index = 0; _update_completion_candidates(); } @@ -6342,14 +6314,14 @@ int TextEdit::get_info_gutter_width() const { return info_gutter_width; } -void TextEdit::set_hiding_enabled(int p_enabled) { +void TextEdit::set_hiding_enabled(bool p_enabled) { if (!p_enabled) unhide_all_lines(); hiding_enabled = p_enabled; update(); } -int TextEdit::is_hiding_enabled() const { +bool TextEdit::is_hiding_enabled() const { return hiding_enabled; } @@ -6450,6 +6422,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text); ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); + ClassDB::bind_method(D_METHOD("center_viewport_to_cursor"), &TextEdit::center_viewport_to_cursor); ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true)); ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0)); |