Browse Source

Show icons for code completion options

Geequlim 6 years ago
parent
commit
10cfd87414
5 changed files with 98 additions and 35 deletions
  1. 1 0
      core/script_language.h
  2. 45 6
      editor/code_editor.cpp
  3. 1 0
      editor/code_editor.h
  4. 47 25
      scene/gui/text_edit.cpp
  5. 4 4
      scene/gui/text_edit.h

+ 1 - 0
core/script_language.h

@@ -216,6 +216,7 @@ struct ScriptCodeCompletionOption {
 	Kind kind;
 	String display;
 	String insert_text;
+	RES icon;
 
 	ScriptCodeCompletionOption() {
 		kind = KIND_PLAIN_TEXT;

+ 45 - 6
editor/code_editor.cpp

@@ -734,15 +734,54 @@ void CodeTextEditor::_complete_request() {
 	if (entries.size() == 0)
 		return;
 
-	Vector<String> options;
-	options.resize(entries.size());
-	size_t i = 0;
 	for (List<ScriptCodeCompletionOption>::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<Texture> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOption &p_option) {
+	Ref<Texture> 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() {

+ 1 - 0
editor/code_editor.h

@@ -162,6 +162,7 @@ class CodeTextEditor : public VBoxContainer {
 
 	void _update_font();
 	void _complete_request();
+	Ref<Texture> _get_completion_icon(const ScriptCodeCompletionOption &p_option);
 	void _font_resize_timeout();
 	bool _add_font_size(int p_delta);
 

+ 47 - 25
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<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) {
@@ -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<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]);
 			}
 		}
 	}
@@ -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<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();
 }

+ 4 - 4
scene/gui/text_edit.h

@@ -255,11 +255,11 @@ private:
 
 	Set<String> completion_prefixes;
 	bool completion_enabled;
-	Vector<String> completion_strings;
-	Vector<String> completion_options;
+	List<ScriptCodeCompletionOption> completion_sources;
+	Vector<ScriptCodeCompletionOption> 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<String> &p_prefixes);
-	void code_complete(const Vector<String> &p_strings, bool p_forced = false);
+	void code_complete(const List<ScriptCodeCompletionOption> &p_strings, bool p_forced = false);
 	void set_code_hint(const String &p_hint);
 	void query_code_comple();