From 10cfd87414f1e39a31c2ac13ead61cbca9353afd Mon Sep 17 00:00:00 2001 From: Geequlim Date: Thu, 13 Jun 2019 17:32:03 +0800 Subject: [PATCH] Show icons for code completion options --- core/script_language.h | 1 + editor/code_editor.cpp | 51 +++++++++++++++++++++++++---- editor/code_editor.h | 1 + scene/gui/text_edit.cpp | 72 +++++++++++++++++++++++++++-------------- scene/gui/text_edit.h | 8 ++--- 5 files changed, 98 insertions(+), 35 deletions(-) diff --git a/core/script_language.h b/core/script_language.h index cb103646ed1..87f103bb33d 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -216,6 +216,7 @@ struct ScriptCodeCompletionOption { Kind kind; String display; String insert_text; + RES icon; ScriptCodeCompletionOption() { kind = KIND_PLAIN_TEXT; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index d5aae7b562f..00d026baa40 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -734,15 +734,54 @@ void CodeTextEditor::_complete_request() { if (entries.size() == 0) return; - Vector options; - options.resize(entries.size()); - size_t i = 0; for (List::Element *E = entries.front(); E; E = E->next()) { - options.write[i] = E->get().insert_text; - i++; + E->get().icon = _get_completion_icon(E->get()); } + text_editor->code_complete(entries, forced); +} - text_editor->code_complete(options, forced); +Ref CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOption &p_option) { + Ref tex; + switch (p_option.kind) { + case ScriptCodeCompletionOption::KIND_CLASS: { + if (has_icon(p_option.display, "EditorIcons")) { + tex = get_icon(p_option.display, "EditorIcons"); + } else { + tex = get_icon("Object", "EditorIcons"); + } + } break; + case ScriptCodeCompletionOption::KIND_ENUM: + tex = get_icon("Enum", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_FILE_PATH: + tex = get_icon("File", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_NODE_PATH: + tex = get_icon("NodePath", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_VARIABLE: + tex = get_icon("Variant", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_CONSTANT: + tex = get_icon("MemberConstant", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_MEMBER: + tex = get_icon("MemberProperty", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_SIGNAL: + tex = get_icon("MemberSignal", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_FUNCTION: + tex = get_icon("MemberMethod", "EditorIcons"); + break; + case ScriptCodeCompletionOption::KIND_PLAIN_TEXT: + tex = get_icon("CubeMesh", "EditorIcons"); + break; + default: + tex = get_icon("String", "EditorIcons"); + break; + } + return tex; } void CodeTextEditor::_font_resize_timeout() { diff --git a/editor/code_editor.h b/editor/code_editor.h index 2653a8cecce..5af1f531a99 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -162,6 +162,7 @@ class CodeTextEditor : public VBoxContainer { void _update_font(); void _complete_request(); + Ref _get_completion_icon(const ScriptCodeCompletionOption &p_option); void _font_resize_timeout(); bool _add_font_size(int p_delta); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index a6e3d644f69..9242e7997af 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 @@ -1362,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; } @@ -1370,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) { @@ -1405,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 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) { @@ -5925,12 +5945,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); @@ -6066,39 +6086,41 @@ void TextEdit::_update_completion_candidates() { completion_base = s; Vector sim_cache; bool single_quote = s.begins_with("'"); - Vector completion_options_casei; + Vector completion_options_casei; - 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("'"); + for (List::Element *E = completion_sources.front(); E; E = E->next()) { + ScriptCodeCompletionOption &option = E->get(); + + 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]); } } } @@ -6109,7 +6131,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; @@ -6147,12 +6169,12 @@ void TextEdit::set_code_hint(const String &p_hint) { update(); } -void TextEdit::code_complete(const Vector &p_strings, bool p_forced) { +void TextEdit::code_complete(const List &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(); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 30956ccb23e..9fb8e03288c 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -255,11 +255,11 @@ private: Set completion_prefixes; bool completion_enabled; - Vector completion_strings; - Vector completion_options; + List completion_sources; + Vector completion_options; bool completion_active; bool completion_forced; - String completion_current; + ScriptCodeCompletionOption completion_current; String completion_base; int completion_index; Rect2i completion_rect; @@ -704,7 +704,7 @@ public: void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata); void set_completion(bool p_enabled, const Vector &p_prefixes); - void code_complete(const Vector &p_strings, bool p_forced = false); + void code_complete(const List &p_strings, bool p_forced = false); void set_code_hint(const String &p_hint); void query_code_comple();