Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show icons for code completion options #29744

Merged
merged 1 commit into from
Jul 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ struct ScriptCodeCompletionOption {
Kind kind;
String display;
String insert_text;
RES icon;

ScriptCodeCompletionOption() {
kind = KIND_PLAIN_TEXT;
Expand Down
51 changes: 45 additions & 6 deletions editor/code_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
1 change: 1 addition & 0 deletions editor/code_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
72 changes: 47 additions & 25 deletions scene/gui/text_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1362,14 +1363,19 @@ 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;
}
} else {
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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]);
}
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down
8 changes: 4 additions & 4 deletions scene/gui/text_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,11 @@ class TextEdit : public Control {

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;
Expand Down Expand Up @@ -704,7 +704,7 @@ class TextEdit : public Control {
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();

Expand Down