From f013596760da0631bc6efb4c5ab527bf1553c1de Mon Sep 17 00:00:00 2001 From: "Andrii Doroshenko (Xrayez)" Date: Thu, 22 Aug 2019 18:59:43 +0300 Subject: Allow to define and load script templates per project Previously it was only possible to create custom script templates per editor instance which could lead to certain name collisions, but now one can create such templates per project tailored for specific use cases. The default path to search for custom script templates is defined in project settings via `editor/script_templates_search_path` setting as `res://script_templates` path, yet this can be configured per project. Templates have at most two origins now: 1. Project-specific, defined in `ProjectSettings`, for instance: - res://script_templates/ 2. Editor script templates, for instance: - %APPDATA%/Godot/script_templates/ As script templates can have the same name over different paths, the override mechanism was also added, enabling project-specific templates over the editor ones. --- core/project_settings.cpp | 3 + editor/editor_settings.cpp | 13 ++++- editor/editor_settings.h | 3 +- editor/script_create_dialog.cpp | 118 ++++++++++++++++++++++++++++++++++++---- editor/script_create_dialog.h | 19 ++++++- 5 files changed, 141 insertions(+), 15 deletions(-) diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 0a673fb638..eb88143db3 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -1019,6 +1019,9 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("editor/search_in_file_extensions", extensions); custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::POOL_STRING_ARRAY, "editor/search_in_file_extensions"); + GLOBAL_DEF("editor/script_templates_search_path", "res://script_templates"); + custom_prop_info["editor/script_templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script_templates_search_path", PROPERTY_HINT_DIR); + action = Dictionary(); action["deadzone"] = Variant(0.5f); events = Array(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 61668d55be..db353c0dfc 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1209,6 +1209,11 @@ String EditorSettings::get_script_templates_dir() const { return get_settings_dir().plus_file("script_templates"); } +String EditorSettings::get_project_script_templates_dir() const { + + return ProjectSettings::get_singleton()->get("editor/script_templates_search_path"); +} + // Cache directory String EditorSettings::get_cache_dir() const { @@ -1429,10 +1434,14 @@ bool EditorSettings::is_default_text_editor_theme() { return _is_default_text_editor_theme(p_file.get_file().to_lower()); } -Vector EditorSettings::get_script_templates(const String &p_extension) { +Vector EditorSettings::get_script_templates(const String &p_extension, const String &p_custom_path) { Vector templates; - DirAccess *d = DirAccess::open(get_script_templates_dir()); + String template_dir = get_script_templates_dir(); + if (!p_custom_path.empty()) { + template_dir = p_custom_path; + } + DirAccess *d = DirAccess::open(template_dir); if (d) { d->list_dir_begin(); String file = d->get_next(); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 890850629e..0738185e95 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -166,6 +166,7 @@ public: String get_project_settings_dir() const; String get_text_editor_themes_dir() const; String get_script_templates_dir() const; + String get_project_script_templates_dir() const; String get_cache_dir() const; String get_feature_profiles_dir() const; @@ -187,7 +188,7 @@ public: bool save_text_editor_theme_as(String p_file); bool is_default_text_editor_theme(); - Vector get_script_templates(const String &p_extension); + Vector get_script_templates(const String &p_extension, const String &p_custom_path = String()); String get_editor_layouts_config() const; void add_shortcut(const String &p_name, Ref &p_shortcut); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 7d0f40fe91..ffb3f5feab 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -34,6 +34,7 @@ #include "core/os/file_access.h" #include "core/project_settings.h" #include "core/script_language.h" +#include "core/string_builder.h" #include "editor/create_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -238,16 +239,22 @@ void ScriptCreateDialog::_parent_name_changed(const String &p_parent) { void ScriptCreateDialog::_template_changed(int p_template) { - String selected_template = p_template == 0 ? "" : template_menu->get_item_text(template_menu->get_selected()); + String selected_template = p_template == 0 ? "" : template_menu->get_item_text(p_template); EditorSettings::get_singleton()->set_project_metadata("script_setup", "last_selected_template", selected_template); if (p_template == 0) { //default script_template = ""; return; } - String ext = ScriptServer::get_language(language_menu->get_selected())->get_extension(); - String name = template_list[p_template - 1] + "." + ext; - script_template = EditorSettings::get_singleton()->get_script_templates_dir().plus_file(name); + int selected_id = template_menu->get_selected_id(); + + for (int i = 0; i < template_list.size(); i++) { + const ScriptTemplateInfo &sinfo = template_list[i]; + if (sinfo.id == selected_id) { + script_template = sinfo.dir.plus_file(sinfo.name + "." + sinfo.extension); + break; + } + } } void ScriptCreateDialog::ok_pressed() { @@ -368,23 +375,77 @@ void ScriptCreateDialog::_lang_changed(int l) { bool use_templates = language->is_using_templates(); template_menu->set_disabled(!use_templates); template_menu->clear(); - if (use_templates) { - template_list = EditorSettings::get_singleton()->get_script_templates(language->get_extension()); + if (use_templates) { + _update_script_templates(language->get_extension()); String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); String last_template = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_template", ""); template_menu->add_item(TTR("Default")); + + ScriptTemplateInfo *templates = template_list.ptrw(); + + Vector origin_names; + origin_names.push_back(TTR("Project")); + origin_names.push_back(TTR("Editor")); + int cur_origin = -1; + + // Populate script template items previously sorted and now grouped by origin for (int i = 0; i < template_list.size(); i++) { - String s = template_list[i].capitalize(); - template_menu->add_item(s); - if (language_menu->get_item_text(language_menu->get_selected()) == last_lang && last_template == s) { - template_menu->select(i + 1); + + if (int(templates[i].origin) != cur_origin) { + template_menu->add_separator(); + + String origin_name = origin_names[templates[i].origin]; + + int last_index = template_menu->get_item_count() - 1; + template_menu->set_item_text(last_index, origin_name); + + cur_origin = templates[i].origin; } + String item_name = templates[i].name.capitalize(); + template_menu->add_item(item_name); + + int new_id = template_menu->get_item_count() - 1; + templates[i].id = new_id; } - } else { + // Disable overridden + for (Map >::Element *E = template_overrides.front(); E; E = E->next()) { + const Vector &overrides = E->get(); + + if (overrides.size() == 1) { + continue; // doesn't override anything + } + const ScriptTemplateInfo &extended = template_list[overrides[0]]; + + StringBuilder override_info; + override_info += TTR("Overrides"); + override_info += ": "; + + for (int i = 1; i < overrides.size(); i++) { + const ScriptTemplateInfo &overridden = template_list[overrides[i]]; + + int disable_index = template_menu->get_item_index(overridden.id); + template_menu->set_item_disabled(disable_index, true); + override_info += origin_names[overridden.origin]; + if (i < overrides.size() - 1) { + override_info += ", "; + } + } + template_menu->set_item_icon(extended.id, get_icon("Override", "EditorIcons")); + template_menu->get_popup()->set_item_tooltip(extended.id, override_info.as_string()); + } + // Reselect last selected template + for (int i = 0; i < template_menu->get_item_count(); i++) { + const String &ti = template_menu->get_item_text(i); + if (language_menu->get_item_text(language_menu->get_selected()) == last_lang && last_template == ti) { + template_menu->select(i); + break; + } + } + } else { template_menu->add_item(TTR("N/A")); script_template = ""; } @@ -396,6 +457,41 @@ void ScriptCreateDialog::_lang_changed(int l) { _update_dialog(); } +void ScriptCreateDialog::_update_script_templates(const String &p_extension) { + + template_list.clear(); + template_overrides.clear(); + + Vector dirs; + + // Ordered from local to global for correct override mechanism + dirs.push_back(EditorSettings::get_singleton()->get_project_script_templates_dir()); + dirs.push_back(EditorSettings::get_singleton()->get_script_templates_dir()); + + for (int i = 0; i < dirs.size(); i++) { + + Vector list = EditorSettings::get_singleton()->get_script_templates(p_extension, dirs[i]); + + for (int j = 0; j < list.size(); j++) { + ScriptTemplateInfo sinfo; + sinfo.origin = ScriptOrigin(i); + sinfo.dir = dirs[i]; + sinfo.name = list[j]; + sinfo.extension = p_extension; + template_list.push_back(sinfo); + + if (!template_overrides.has(sinfo.name)) { + Vector overrides; + overrides.push_back(template_list.size() - 1); // first one + template_overrides.insert(sinfo.name, overrides); + } else { + Vector &overrides = template_overrides[sinfo.name]; + overrides.push_back(template_list.size() - 1); + } + } + } +} + void ScriptCreateDialog::_built_in_pressed() { if (internal->is_pressed()) { diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 202846fd3c..31cf2478cf 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -78,8 +78,25 @@ class ScriptCreateDialog : public ConfirmationDialog { int current_language; int default_language; bool re_check_path; + + enum ScriptOrigin { + SCRIPT_ORIGIN_PROJECT, + SCRIPT_ORIGIN_EDITOR, + }; + struct ScriptTemplateInfo { + int id; + ScriptOrigin origin; + String dir; + String name; + String extension; + }; + String script_template; - Vector template_list; + Vector template_list; + Map > template_overrides; // name : indices + + void _update_script_templates(const String &p_extension); + String base_type; void _path_hbox_sorted(); -- cgit v1.2.3