diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 78cc2154213..bc91fcdf04e 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -47,12 +47,11 @@ #include "scene/main/scene_tree.h" #include "scene/main/viewport.h" +// PRIVATE METHODS + Ref EditorSettings::singleton = NULL; -EditorSettings *EditorSettings::get_singleton() { - - return singleton.ptr(); -} +// Properties bool EditorSettings::_set(const StringName &p_name, const Variant &p_value, bool p_emit_signal) { @@ -195,347 +194,26 @@ void EditorSettings::_get_property_list(List *p_list) const { p_list->push_back(PropertyInfo(Variant::ARRAY, "shortcuts", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); //do not edit } -void EditorSettings::set_setting(const String &p_setting, const Variant &p_value) { - _THREAD_SAFE_METHOD_ - set(p_setting, p_value); +void EditorSettings::_add_property_info_bind(const Dictionary &p_info) { + + ERR_FAIL_COND(!p_info.has("name")); + ERR_FAIL_COND(!p_info.has("type")); + + PropertyInfo pinfo; + pinfo.name = p_info["name"]; + ERR_FAIL_COND(!props.has(pinfo.name)); + pinfo.type = Variant::Type(p_info["type"].operator int()); + ERR_FAIL_INDEX(pinfo.type, Variant::VARIANT_MAX); + + if (p_info.has("hint")) + pinfo.hint = PropertyHint(p_info["hint"].operator int()); + if (p_info.has("hint_string")) + pinfo.hint_string = p_info["hint_string"]; + + add_property_hint(pinfo); } -Variant EditorSettings::get_setting(const String &p_setting) const { - _THREAD_SAFE_METHOD_ - return get(p_setting); -} - -bool EditorSettings::has_setting(String p_var) const { - - _THREAD_SAFE_METHOD_ - - return props.has(p_var); -} - -void EditorSettings::erase(String p_var) { - - _THREAD_SAFE_METHOD_ - - props.erase(p_var); -} - -void EditorSettings::raise_order(const String &p_name) { - _THREAD_SAFE_METHOD_ - - ERR_FAIL_COND(!props.has(p_name)); - props[p_name].order = ++last_order; -} - -Variant _EDITOR_DEF(const String &p_var, const Variant &p_default) { - - if (EditorSettings::get_singleton()->has_setting(p_var)) - return EditorSettings::get_singleton()->get(p_var); - EditorSettings::get_singleton()->set(p_var, p_default); - EditorSettings::get_singleton()->set_initial_value(p_var, p_default); - - return p_default; -} - -Variant _EDITOR_GET(const String &p_var) { - - ERR_FAIL_COND_V(!EditorSettings::get_singleton()->has_setting(p_var), Variant()) - return EditorSettings::get_singleton()->get(p_var); -} - -static Dictionary _get_builtin_script_templates() { - Dictionary templates; - - //No Comments - templates["no_comments.gd"] = - "extends %BASE%\n" - "\n" - "func _ready():\n" - "%TS%pass\n"; - - //Empty - templates["empty.gd"] = - "extends %BASE%" - "\n" - "\n"; - - return templates; -} - -static void _create_script_templates(const String &p_path) { - - Dictionary templates = _get_builtin_script_templates(); - List keys; - templates.get_key_list(&keys); - FileAccess *file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM); - - DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - dir->change_dir(p_path); - for (int i = 0; i < keys.size(); i++) { - if (!dir->file_exists(keys[i])) { - Error err = file->reopen(p_path.plus_file((String)keys[i]), FileAccess::WRITE); - ERR_FAIL_COND(err != OK); - file->store_string(templates[keys[i]]); - file->close(); - } - } - - memdelete(dir); - memdelete(file); -} - -void EditorSettings::create() { - - if (singleton.ptr()) - return; //pointless - - DirAccess *dir = NULL; - Variant meta; - - String config_path; - String config_dir; - Ref extra_config = memnew(ConfigFile); - - String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); - DirAccess *d = DirAccess::create_for_path(exe_path); - bool self_contained = false; - - if (d->file_exists(exe_path + "/._sc_")) { - self_contained = true; - extra_config->load(exe_path + "/._sc_"); - } else if (d->file_exists(exe_path + "/_sc_")) { - self_contained = true; - extra_config->load(exe_path + "/_sc_"); - } - memdelete(d); - - if (self_contained) { - // editor is self contained - config_path = exe_path; - config_dir = "editor_data"; - } else { - - if (OS::get_singleton()->has_environment("APPDATA")) { - // Most likely under windows, save here - config_path = OS::get_singleton()->get_environment("APPDATA"); - config_dir = String(_MKSTR(VERSION_SHORT_NAME)).capitalize(); - } else if (OS::get_singleton()->has_environment("HOME")) { - - config_path = OS::get_singleton()->get_environment("HOME"); - config_dir = "." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower(); - } - }; - - ClassDB::register_class(); //otherwise it can't be unserialized - String config_file_path; - - if (config_path != "") { - - dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); - memdelete(dir); - goto fail; - } - - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); - if (dir->change_dir(config_dir) != OK) { - ERR_PRINT("Cannot create config directory!"); - memdelete(dir); - goto fail; - } - } - - if (dir->change_dir("templates") != OK) { - dir->make_dir("templates"); - } else { - - dir->change_dir(".."); - } - - if (dir->change_dir("text_editor_themes") != OK) { - dir->make_dir("text_editor_themes"); - } else { - dir->change_dir(".."); - } - - if (dir->change_dir("script_templates") != OK) { - dir->make_dir("script_templates"); - } else { - dir->change_dir(".."); - } - _create_script_templates(dir->get_current_dir() + "/script_templates"); - - if (dir->change_dir("tmp") != OK) { - dir->make_dir("tmp"); - } else { - - dir->change_dir(".."); - } - - if (dir->change_dir("config") != OK) { - dir->make_dir("config"); - } else { - - dir->change_dir(".."); - } - - dir->change_dir("config"); - - String pcp = ProjectSettings::get_singleton()->get_resource_path(); - if (pcp.ends_with("/")) - pcp = config_path.substr(0, pcp.size() - 1); - pcp = pcp.get_file() + "-" + pcp.md5_text(); - - if (dir->change_dir(pcp)) { - dir->make_dir(pcp); - } else { - dir->change_dir(".."); - } - - dir->change_dir(".."); - - // path at least is validated, so validate config file - - String config_file_name = "editor_settings-" + String(_MKSTR(VERSION_MAJOR)) + ".tres"; - config_file_path = config_path + "/" + config_dir + "/" + config_file_name; - - String open_path = config_file_path; - - if (!dir->file_exists(config_file_name)) { - - goto fail; - } - - memdelete(dir); - - singleton = ResourceLoader::load(open_path, "EditorSettings"); - - if (singleton.is_null()) { - WARN_PRINT("Could not open config file."); - goto fail; - } - - singleton->save_changed_setting = true; - singleton->config_file_path = config_file_path; - singleton->project_config_path = pcp; - singleton->settings_path = config_path + "/" + config_dir; - - if (OS::get_singleton()->is_stdout_verbose()) { - - print_line("EditorSettings: Load OK!"); - } - - singleton->setup_language(); - singleton->setup_network(); - singleton->load_favorites(); - singleton->list_text_editor_themes(); - - return; - } - -fail: - - // patch init projects - if (extra_config->has_section("init_projects")) { - Vector list = extra_config->get_value("init_projects", "list"); - for (int i = 0; i < list.size(); i++) { - - list[i] = exe_path + "/" + list[i]; - }; - extra_config->set_value("init_projects", "list", list); - }; - - singleton = Ref(memnew(EditorSettings)); - singleton->save_changed_setting = true; - singleton->config_file_path = config_file_path; - singleton->settings_path = config_path + "/" + config_dir; - singleton->_load_defaults(extra_config); - singleton->setup_language(); - singleton->setup_network(); - singleton->list_text_editor_themes(); -} - -String EditorSettings::get_settings_path() const { - - return settings_path; -} - -void EditorSettings::setup_language() { - - String lang = get("interface/editor/editor_language"); - if (lang == "en") - return; //none to do - - for (int i = 0; i < translations.size(); i++) { - if (translations[i]->get_locale() == lang) { - TranslationServer::get_singleton()->set_tool_translation(translations[i]); - break; - } - } -} - -void EditorSettings::setup_network() { - - List local_ip; - IP::get_singleton()->get_local_addresses(&local_ip); - String lip = "127.0.0.1"; - String hint; - String current = has_setting("network/debug/remote_host") ? get("network/debug/remote_host") : ""; - int port = has_setting("network/debug/remote_port") ? (int)get("network/debug/remote_port") : 6007; - - for (List::Element *E = local_ip.front(); E; E = E->next()) { - - String ip = E->get(); - - // link-local IPv6 addresses don't work, skipping them - if (ip.begins_with("fe80:0:0:0:")) // fe80::/64 - continue; - if (ip == current) - lip = current; //so it saves - if (hint != "") - hint += ","; - hint += ip; - } - - set("network/debug/remote_host", lip); - add_property_hint(PropertyInfo(Variant::STRING, "network/debug/remote_host", PROPERTY_HINT_ENUM, hint)); - - set("network/debug/remote_port", port); - add_property_hint(PropertyInfo(Variant::INT, "network/debug/remote_port", PROPERTY_HINT_RANGE, "1,65535,1")); -} - -void EditorSettings::save() { - - //_THREAD_SAFE_METHOD_ - - if (!singleton.ptr()) - return; - - if (singleton->config_file_path == "") { - ERR_PRINT("Cannot save EditorSettings config, no valid path"); - return; - } - - Error err = ResourceSaver::save(singleton->config_file_path, singleton); - - if (err != OK) { - ERR_PRINT("Can't Save!"); - return; - } - - if (OS::get_singleton()->is_stdout_verbose()) { - print_line("EditorSettings Save OK!"); - } -} - -void EditorSettings::destroy() { - - if (!singleton.ptr()) - return; - save(); - singleton = Ref(); -} +// Default configs void EditorSettings::_load_defaults(Ref p_extra_config) { @@ -857,235 +535,6 @@ void EditorSettings::_load_default_text_editor_theme() { _initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1)); } -void EditorSettings::notify_changes() { - - _THREAD_SAFE_METHOD_ - - SceneTree *sml = Object::cast_to(OS::get_singleton()->get_main_loop()); - - if (!sml) { - return; - } - - Node *root = sml->get_root()->get_child(0); - - if (!root) { - return; - } - root->propagate_notification(NOTIFICATION_EDITOR_SETTINGS_CHANGED); -} - -void EditorSettings::_add_property_info_bind(const Dictionary &p_info) { - - ERR_FAIL_COND(!p_info.has("name")); - ERR_FAIL_COND(!p_info.has("type")); - - PropertyInfo pinfo; - pinfo.name = p_info["name"]; - ERR_FAIL_COND(!props.has(pinfo.name)); - pinfo.type = Variant::Type(p_info["type"].operator int()); - ERR_FAIL_INDEX(pinfo.type, Variant::VARIANT_MAX); - - if (p_info.has("hint")) - pinfo.hint = PropertyHint(p_info["hint"].operator int()); - if (p_info.has("hint_string")) - pinfo.hint_string = p_info["hint_string"]; - - add_property_hint(pinfo); -} - -void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { - - _THREAD_SAFE_METHOD_ - - hints[p_hint.name] = p_hint; -} - -void EditorSettings::set_favorite_dirs(const Vector &p_favorites_dirs) { - - favorite_dirs = p_favorites_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::WRITE); - if (f) { - for (int i = 0; i < favorite_dirs.size(); i++) - f->store_line(favorite_dirs[i]); - memdelete(f); - } -} - -Vector EditorSettings::get_favorite_dirs() const { - - return favorite_dirs; -} - -void EditorSettings::set_recent_dirs(const Vector &p_recent_dirs) { - - recent_dirs = p_recent_dirs; - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::WRITE); - if (f) { - for (int i = 0; i < recent_dirs.size(); i++) - f->store_line(recent_dirs[i]); - memdelete(f); - } -} - -Vector EditorSettings::get_recent_dirs() const { - - return recent_dirs; -} - -String EditorSettings::get_project_settings_path() const { - - return get_settings_path().plus_file("config").plus_file(project_config_path); -} - -void EditorSettings::load_favorites() { - - FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::READ); - if (f) { - String line = f->get_line().strip_edges(); - while (line != "") { - favorite_dirs.push_back(line); - line = f->get_line().strip_edges(); - } - memdelete(f); - } - - f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::READ); - if (f) { - String line = f->get_line().strip_edges(); - while (line != "") { - recent_dirs.push_back(line); - line = f->get_line().strip_edges(); - } - memdelete(f); - } -} - -void EditorSettings::list_text_editor_themes() { - String themes = "Adaptive,Default"; - DirAccess *d = DirAccess::open(settings_path + "/text_editor_themes"); - if (d) { - d->list_dir_begin(); - String file = d->get_next(); - while (file != String()) { - if (file.get_extension() == "tet" && file.get_basename().to_lower() != "default" && file.get_basename().to_lower() != "adaptive") { - themes += "," + file.get_basename(); - } - file = d->get_next(); - } - d->list_dir_end(); - memdelete(d); - } - add_property_hint(PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, themes)); -} - -void EditorSettings::load_text_editor_theme() { - if (get("text_editor/theme/color_theme") == "Default" || get("text_editor/theme/color_theme") == "Adaptive") { - _load_default_text_editor_theme(); // sorry for "Settings changed" console spam - return; - } - - String theme_path = get_settings_path() + "/text_editor_themes/" + get("text_editor/theme/color_theme") + ".tet"; - - Ref cf = memnew(ConfigFile); - Error err = cf->load(theme_path); - - if (err != OK) { - return; - } - - List keys; - cf->get_section_keys("color_theme", &keys); - - for (List::Element *E = keys.front(); E; E = E->next()) { - String key = E->get(); - String val = cf->get_value("color_theme", key); - - // don't load if it's not already there! - if (has_setting("text_editor/highlighting/" + key)) { - - // make sure it is actually a color - if (val.is_valid_html_color() && key.find("color") >= 0) { - props["text_editor/highlighting/" + key].variant = Color::html(val); // change manually to prevent "Settings changed" console spam - } - } - } - emit_signal("settings_changed"); - // if it doesn't load just use what is currently loaded -} - -bool EditorSettings::import_text_editor_theme(String p_file) { - - if (!p_file.ends_with(".tet")) { - return false; - } else { - if (p_file.get_file().to_lower() == "default.tet") { - return false; - } - - DirAccess *d = DirAccess::open(settings_path + "/text_editor_themes"); - if (d) { - d->copy(p_file, settings_path + "/text_editor_themes/" + p_file.get_file()); - memdelete(d); - return true; - } - } - return false; -} - -bool EditorSettings::save_text_editor_theme() { - - String p_file = get("text_editor/theme/color_theme"); - - if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive") { - return false; - } - String theme_path = get_settings_path() + "/text_editor_themes/" + p_file + ".tet"; - return _save_text_editor_theme(theme_path); -} - -bool EditorSettings::save_text_editor_theme_as(String p_file) { - if (!p_file.ends_with(".tet")) { - p_file += ".tet"; - } - - if (p_file.get_file().to_lower() == "default.tet" || p_file.get_file().to_lower() == "adaptive.tet") { - return false; - } - if (_save_text_editor_theme(p_file)) { - - // switch to theme is saved in the theme directory - list_text_editor_themes(); - String theme_name = p_file.substr(0, p_file.length() - 4).get_file(); - - if (p_file.get_base_dir() == get_settings_path() + "/text_editor_themes") { - _initial_set("text_editor/theme/color_theme", theme_name); - load_text_editor_theme(); - } - return true; - } - return false; -} - -Vector EditorSettings::get_script_templates(const String &p_extension) { - - Vector templates; - DirAccess *d = DirAccess::open(settings_path + "/script_templates"); - if (d) { - d->list_dir_begin(); - String file = d->get_next(); - while (file != String()) { - if (file.get_extension() == p_extension) { - templates.push_back(file.get_basename()); - } - file = d->get_next(); - } - d->list_dir_end(); - memdelete(d); - } - return templates; -} - bool EditorSettings::_save_text_editor_theme(String p_file) { String theme_section = "color_theme"; Ref cf = memnew(ConfigFile); // hex is better? @@ -1127,6 +576,598 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { return false; } +static Dictionary _get_builtin_script_templates() { + Dictionary templates; + + //No Comments + templates["no_comments.gd"] = + "extends %BASE%\n" + "\n" + "func _ready():\n" + "%TS%pass\n"; + + //Empty + templates["empty.gd"] = + "extends %BASE%" + "\n" + "\n"; + + return templates; +} + +static void _create_script_templates(const String &p_path) { + + Dictionary templates = _get_builtin_script_templates(); + List keys; + templates.get_key_list(&keys); + FileAccess *file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM); + + DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + dir->change_dir(p_path); + for (int i = 0; i < keys.size(); i++) { + if (!dir->file_exists(keys[i])) { + Error err = file->reopen(p_path.plus_file((String)keys[i]), FileAccess::WRITE); + ERR_FAIL_COND(err != OK); + file->store_string(templates[keys[i]]); + file->close(); + } + } + + memdelete(dir); + memdelete(file); +} + +// PUBLIC METHODS + +EditorSettings *EditorSettings::get_singleton() { + + return singleton.ptr(); +} + +void EditorSettings::create() { + + if (singleton.ptr()) + return; //pointless + + DirAccess *dir = NULL; + Variant meta; + + String config_path; + String config_dir; + Ref extra_config = memnew(ConfigFile); + + String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); + DirAccess *d = DirAccess::create_for_path(exe_path); + bool self_contained = false; + + if (d->file_exists(exe_path + "/._sc_")) { + self_contained = true; + extra_config->load(exe_path + "/._sc_"); + } else if (d->file_exists(exe_path + "/_sc_")) { + self_contained = true; + extra_config->load(exe_path + "/_sc_"); + } + memdelete(d); + + if (self_contained) { + // editor is self contained + config_path = exe_path; + config_dir = "editor_data"; + } else { + + if (OS::get_singleton()->has_environment("APPDATA")) { + // Most likely under windows, save here + config_path = OS::get_singleton()->get_environment("APPDATA"); + config_dir = String(_MKSTR(VERSION_SHORT_NAME)).capitalize(); + } else if (OS::get_singleton()->has_environment("HOME")) { + + config_path = OS::get_singleton()->get_environment("HOME"); + config_dir = "." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower(); + } + }; + + ClassDB::register_class(); //otherwise it can't be unserialized + String config_file_path; + + if (config_path != "") { + + dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (dir->change_dir(config_path) != OK) { + ERR_PRINT("Cannot find path for config directory!"); + memdelete(dir); + goto fail; + } + + if (dir->change_dir(config_dir) != OK) { + dir->make_dir(config_dir); + if (dir->change_dir(config_dir) != OK) { + ERR_PRINT("Cannot create config directory!"); + memdelete(dir); + goto fail; + } + } + + if (dir->change_dir("templates") != OK) { + dir->make_dir("templates"); + } else { + + dir->change_dir(".."); + } + + if (dir->change_dir("text_editor_themes") != OK) { + dir->make_dir("text_editor_themes"); + } else { + dir->change_dir(".."); + } + + if (dir->change_dir("script_templates") != OK) { + dir->make_dir("script_templates"); + } else { + dir->change_dir(".."); + } + _create_script_templates(dir->get_current_dir() + "/script_templates"); + + if (dir->change_dir("tmp") != OK) { + dir->make_dir("tmp"); + } else { + + dir->change_dir(".."); + } + + if (dir->change_dir("config") != OK) { + dir->make_dir("config"); + } else { + + dir->change_dir(".."); + } + + dir->change_dir("config"); + + String pcp = ProjectSettings::get_singleton()->get_resource_path(); + if (pcp.ends_with("/")) + pcp = config_path.substr(0, pcp.size() - 1); + pcp = pcp.get_file() + "-" + pcp.md5_text(); + + if (dir->change_dir(pcp)) { + dir->make_dir(pcp); + } else { + dir->change_dir(".."); + } + + dir->change_dir(".."); + + // path at least is validated, so validate config file + + String config_file_name = "editor_settings-" + String(_MKSTR(VERSION_MAJOR)) + ".tres"; + config_file_path = config_path + "/" + config_dir + "/" + config_file_name; + + String open_path = config_file_path; + + if (!dir->file_exists(config_file_name)) { + + goto fail; + } + + memdelete(dir); + + singleton = ResourceLoader::load(open_path, "EditorSettings"); + + if (singleton.is_null()) { + WARN_PRINT("Could not open config file."); + goto fail; + } + + singleton->save_changed_setting = true; + singleton->config_file_path = config_file_path; + singleton->project_config_path = pcp; + singleton->settings_path = config_path + "/" + config_dir; + + if (OS::get_singleton()->is_stdout_verbose()) { + + print_line("EditorSettings: Load OK!"); + } + + singleton->setup_language(); + singleton->setup_network(); + singleton->load_favorites(); + singleton->list_text_editor_themes(); + + return; + } + +fail: + + // patch init projects + if (extra_config->has_section("init_projects")) { + Vector list = extra_config->get_value("init_projects", "list"); + for (int i = 0; i < list.size(); i++) { + + list[i] = exe_path + "/" + list[i]; + }; + extra_config->set_value("init_projects", "list", list); + }; + + singleton = Ref(memnew(EditorSettings)); + singleton->save_changed_setting = true; + singleton->config_file_path = config_file_path; + singleton->settings_path = config_path + "/" + config_dir; + singleton->_load_defaults(extra_config); + singleton->setup_language(); + singleton->setup_network(); + singleton->list_text_editor_themes(); +} + +void EditorSettings::setup_language() { + + String lang = get("interface/editor/editor_language"); + if (lang == "en") + return; //none to do + + for (int i = 0; i < translations.size(); i++) { + if (translations[i]->get_locale() == lang) { + TranslationServer::get_singleton()->set_tool_translation(translations[i]); + break; + } + } +} + +void EditorSettings::setup_network() { + + List local_ip; + IP::get_singleton()->get_local_addresses(&local_ip); + String lip = "127.0.0.1"; + String hint; + String current = has_setting("network/debug/remote_host") ? get("network/debug/remote_host") : ""; + int port = has_setting("network/debug/remote_port") ? (int)get("network/debug/remote_port") : 6007; + + for (List::Element *E = local_ip.front(); E; E = E->next()) { + + String ip = E->get(); + + // link-local IPv6 addresses don't work, skipping them + if (ip.begins_with("fe80:0:0:0:")) // fe80::/64 + continue; + if (ip == current) + lip = current; //so it saves + if (hint != "") + hint += ","; + hint += ip; + } + + set("network/debug/remote_host", lip); + add_property_hint(PropertyInfo(Variant::STRING, "network/debug/remote_host", PROPERTY_HINT_ENUM, hint)); + + set("network/debug/remote_port", port); + add_property_hint(PropertyInfo(Variant::INT, "network/debug/remote_port", PROPERTY_HINT_RANGE, "1,65535,1")); +} + +void EditorSettings::save() { + + //_THREAD_SAFE_METHOD_ + + if (!singleton.ptr()) + return; + + if (singleton->config_file_path == "") { + ERR_PRINT("Cannot save EditorSettings config, no valid path"); + return; + } + + Error err = ResourceSaver::save(singleton->config_file_path, singleton); + + if (err != OK) { + ERR_PRINT("Can't Save!"); + return; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("EditorSettings Save OK!"); + } +} + +void EditorSettings::destroy() { + + if (!singleton.ptr()) + return; + save(); + singleton = Ref(); +} + +void EditorSettings::set_optimize_save(bool p_optimize) { + + optimize_save = p_optimize; +} + +// Properties + +void EditorSettings::set_setting(const String &p_setting, const Variant &p_value) { + _THREAD_SAFE_METHOD_ + set(p_setting, p_value); +} + +Variant EditorSettings::get_setting(const String &p_setting) const { + _THREAD_SAFE_METHOD_ + return get(p_setting); +} + +bool EditorSettings::has_setting(const String &p_setting) const { + + _THREAD_SAFE_METHOD_ + + return props.has(p_setting); +} + +void EditorSettings::erase(const String &p_setting) { + + _THREAD_SAFE_METHOD_ + + props.erase(p_setting); +} + +void EditorSettings::raise_order(const String &p_setting) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!props.has(p_setting)); + props[p_setting].order = ++last_order; +} + +void EditorSettings::set_initial_value(const StringName &p_setting, const Variant &p_value) { + + ERR_FAIL_COND(!props.has(p_setting)); + props[p_setting].initial = p_value; +} + +Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default) { + + if (EditorSettings::get_singleton()->has_setting(p_setting)) + return EditorSettings::get_singleton()->get(p_setting); + EditorSettings::get_singleton()->set(p_setting, p_default); + EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); + + return p_default; +} + +Variant _EDITOR_GET(const String &p_setting) { + + ERR_FAIL_COND_V(!EditorSettings::get_singleton()->has_setting(p_setting), Variant()) + return EditorSettings::get_singleton()->get(p_setting); +} + +bool EditorSettings::property_can_revert(const String &p_setting) { + + if (!props.has(p_setting)) + return false; + + return props[p_setting].initial != props[p_setting].variant; +} + +Variant EditorSettings::property_get_revert(const String &p_setting) { + + if (!props.has(p_setting)) + return Variant(); + + return props[p_setting].initial; +} + +void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { + + _THREAD_SAFE_METHOD_ + + hints[p_hint.name] = p_hint; +} + +// Settings paths and saved metadata + +String EditorSettings::get_settings_path() const { + + return settings_path; +} + +String EditorSettings::get_project_settings_path() const { + + return get_settings_path().plus_file("config").plus_file(project_config_path); +} + +void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { + Ref cf = memnew(ConfigFile); + String path = get_project_settings_path().plus_file("project_metadata.cfg"); + cf->load(path); + cf->set_value(p_section, p_key, p_data); + cf->save(path); +} + +Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) { + Ref cf = memnew(ConfigFile); + String path = get_project_settings_path().plus_file("project_metadata.cfg"); + Error err = cf->load(path); + if (err != OK) { + return p_default; + } + return cf->get_value(p_section, p_key, p_default); +} + +void EditorSettings::set_favorite_dirs(const Vector &p_favorites_dirs) { + + favorite_dirs = p_favorites_dirs; + FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::WRITE); + if (f) { + for (int i = 0; i < favorite_dirs.size(); i++) + f->store_line(favorite_dirs[i]); + memdelete(f); + } +} + +Vector EditorSettings::get_favorite_dirs() const { + + return favorite_dirs; +} + +void EditorSettings::set_recent_dirs(const Vector &p_recent_dirs) { + + recent_dirs = p_recent_dirs; + FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::WRITE); + if (f) { + for (int i = 0; i < recent_dirs.size(); i++) + f->store_line(recent_dirs[i]); + memdelete(f); + } +} + +Vector EditorSettings::get_recent_dirs() const { + + return recent_dirs; +} + +void EditorSettings::load_favorites() { + + FileAccess *f = FileAccess::open(get_project_settings_path().plus_file("favorite_dirs"), FileAccess::READ); + if (f) { + String line = f->get_line().strip_edges(); + while (line != "") { + favorite_dirs.push_back(line); + line = f->get_line().strip_edges(); + } + memdelete(f); + } + + f = FileAccess::open(get_project_settings_path().plus_file("recent_dirs"), FileAccess::READ); + if (f) { + String line = f->get_line().strip_edges(); + while (line != "") { + recent_dirs.push_back(line); + line = f->get_line().strip_edges(); + } + memdelete(f); + } +} + +void EditorSettings::list_text_editor_themes() { + String themes = "Adaptive,Default"; + DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + if (d) { + d->list_dir_begin(); + String file = d->get_next(); + while (file != String()) { + if (file.get_extension() == "tet" && file.get_basename().to_lower() != "default" && file.get_basename().to_lower() != "adaptive") { + themes += "," + file.get_basename(); + } + file = d->get_next(); + } + d->list_dir_end(); + memdelete(d); + } + add_property_hint(PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, themes)); +} + +void EditorSettings::load_text_editor_theme() { + if (get("text_editor/theme/color_theme") == "Default" || get("text_editor/theme/color_theme") == "Adaptive") { + _load_default_text_editor_theme(); // sorry for "Settings changed" console spam + return; + } + + String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file((String)get("text_editor/theme/color_theme") + ".tet"); + + Ref cf = memnew(ConfigFile); + Error err = cf->load(theme_path); + + if (err != OK) { + return; + } + + List keys; + cf->get_section_keys("color_theme", &keys); + + for (List::Element *E = keys.front(); E; E = E->next()) { + String key = E->get(); + String val = cf->get_value("color_theme", key); + + // don't load if it's not already there! + if (has_setting("text_editor/highlighting/" + key)) { + + // make sure it is actually a color + if (val.is_valid_html_color() && key.find("color") >= 0) { + props["text_editor/highlighting/" + key].variant = Color::html(val); // change manually to prevent "Settings changed" console spam + } + } + } + emit_signal("settings_changed"); + // if it doesn't load just use what is currently loaded +} + +bool EditorSettings::import_text_editor_theme(String p_file) { + + if (!p_file.ends_with(".tet")) { + return false; + } else { + if (p_file.get_file().to_lower() == "default.tet") { + return false; + } + + DirAccess *d = DirAccess::open(get_settings_path().plus_file("text_editor_themes")); + if (d) { + d->copy(p_file, get_settings_path().plus_file("text_editor_themes").plus_file(p_file.get_file())); + memdelete(d); + return true; + } + } + return false; +} + +bool EditorSettings::save_text_editor_theme() { + + String p_file = get("text_editor/theme/color_theme"); + + if (p_file.get_file().to_lower() == "default" || p_file.get_file().to_lower() == "adaptive") { + return false; + } + String theme_path = get_settings_path().plus_file("text_editor_themes").plus_file(p_file + ".tet"); + return _save_text_editor_theme(theme_path); +} + +bool EditorSettings::save_text_editor_theme_as(String p_file) { + if (!p_file.ends_with(".tet")) { + p_file += ".tet"; + } + + if (p_file.get_file().to_lower() == "default.tet" || p_file.get_file().to_lower() == "adaptive.tet") { + return false; + } + if (_save_text_editor_theme(p_file)) { + + // switch to theme is saved in the theme directory + list_text_editor_themes(); + String theme_name = p_file.substr(0, p_file.length() - 4).get_file(); + + if (p_file.get_base_dir() == get_settings_path().plus_file("text_editor_themes")) { + _initial_set("text_editor/theme/color_theme", theme_name); + load_text_editor_theme(); + } + return true; + } + return false; +} + +Vector EditorSettings::get_script_templates(const String &p_extension) { + + Vector templates; + DirAccess *d = DirAccess::open(get_settings_path().plus_file("script_templates")); + if (d) { + d->list_dir_begin(); + String file = d->get_next(); + while (file != String()) { + if (file.get_extension() == p_extension) { + templates.push_back(file.get_basename()); + } + file = d->get_next(); + } + d->list_dir_end(); + memdelete(d); + } + return templates; +} + +// Shortcuts + void EditorSettings::add_shortcut(const String &p_name, Ref &p_shortcut) { shortcuts[p_name] = p_shortcut; @@ -1160,110 +1201,6 @@ void EditorSettings::get_shortcut_list(List *r_shortcuts) { } } -void EditorSettings::set_optimize_save(bool p_optimize) { - - optimize_save = p_optimize; -} - -Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) { - Ref cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); - Error err = cf->load(path); - if (err != OK) { - return p_default; - } - return cf->get_value(p_section, p_key, p_default); -} - -void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { - Ref cf = memnew(ConfigFile); - String path = get_project_settings_path().plus_file("project_metadata.cfg"); - cf->load(path); - cf->set_value(p_section, p_key, p_data); - cf->save(path); -} - -bool EditorSettings::property_can_revert(const String &p_name) { - - if (!props.has(p_name)) - return false; - - return props[p_name].initial != props[p_name].variant; -} - -Variant EditorSettings::property_get_revert(const String &p_name) { - - if (!props.has(p_name)) - return Variant(); - - return props[p_name].initial; -} - -void EditorSettings::set_initial_value(const StringName &p_name, const Variant &p_value) { - - ERR_FAIL_COND(!props.has(p_name)); - props[p_name].initial = p_value; -} - -void EditorSettings::_bind_methods() { - - ClassDB::bind_method(D_METHOD("has_setting", "name"), &EditorSettings::has_setting); - ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &EditorSettings::set_setting); - ClassDB::bind_method(D_METHOD("get_setting", "name"), &EditorSettings::get_setting); - - ClassDB::bind_method(D_METHOD("erase", "property"), &EditorSettings::erase); - ClassDB::bind_method(D_METHOD("get_settings_path"), &EditorSettings::get_settings_path); - ClassDB::bind_method(D_METHOD("get_project_settings_path"), &EditorSettings::get_project_settings_path); - - ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind); - - ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs); - ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs); - - ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs); - ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs); - - ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorSettings::property_can_revert); - ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert); - - ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &EditorSettings::set_initial_value); - - ADD_SIGNAL(MethodInfo("settings_changed")); -} - -EditorSettings::EditorSettings() { - - last_order = 0; - optimize_save = true; - save_changed_setting = true; - - EditorTranslationList *etl = _editor_translations; - - while (etl->data) { - - Vector data; - data.resize(etl->uncomp_size); - Compression::decompress(data.ptr(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); - - FileAccessMemory *fa = memnew(FileAccessMemory); - fa->open_custom(data.ptr(), data.size()); - - Ref tr = TranslationLoaderPO::load_translation(fa, NULL, "translation_" + String(etl->lang)); - - if (tr.is_valid()) { - tr->set_locale(etl->lang); - translations.push_back(tr); - } - - etl++; - } - - _load_defaults(); -} - -EditorSettings::~EditorSettings() { -} - Ref ED_GET_SHORTCUT(const String &p_path) { Ref sc = EditorSettings::get_singleton()->get_shortcut(p_path); @@ -1305,3 +1242,76 @@ Ref ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p return sc; } + +void EditorSettings::notify_changes() { + + _THREAD_SAFE_METHOD_ + + SceneTree *sml = Object::cast_to(OS::get_singleton()->get_main_loop()); + + if (!sml) { + return; + } + + Node *root = sml->get_root()->get_child(0); + + if (!root) { + return; + } + root->propagate_notification(NOTIFICATION_EDITOR_SETTINGS_CHANGED); +} + +void EditorSettings::_bind_methods() { + + ClassDB::bind_method(D_METHOD("has_setting", "name"), &EditorSettings::has_setting); + ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &EditorSettings::set_setting); + ClassDB::bind_method(D_METHOD("get_setting", "name"), &EditorSettings::get_setting); + ClassDB::bind_method(D_METHOD("erase", "property"), &EditorSettings::erase); + ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &EditorSettings::set_initial_value); + ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorSettings::property_can_revert); + ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert); + ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind); + + ClassDB::bind_method(D_METHOD("get_settings_path"), &EditorSettings::get_settings_path); + ClassDB::bind_method(D_METHOD("get_project_settings_path"), &EditorSettings::get_project_settings_path); + + ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs); + ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs); + ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs); + ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs); + + ADD_SIGNAL(MethodInfo("settings_changed")); +} + +EditorSettings::EditorSettings() { + + last_order = 0; + optimize_save = true; + save_changed_setting = true; + + EditorTranslationList *etl = _editor_translations; + + while (etl->data) { + + Vector data; + data.resize(etl->uncomp_size); + Compression::decompress(data.ptr(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + + FileAccessMemory *fa = memnew(FileAccessMemory); + fa->open_custom(data.ptr(), data.size()); + + Ref tr = TranslationLoaderPO::load_translation(fa, NULL, "translation_" + String(etl->lang)); + + if (tr.is_valid()) { + tr->set_locale(etl->lang); + translations.push_back(tr); + } + + etl++; + } + + _load_defaults(); +} + +EditorSettings::~EditorSettings() { +} diff --git a/editor/editor_settings.h b/editor/editor_settings.h index c5d2670650c..a74be6494a6 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -80,44 +80,37 @@ private: } }; - HashMap hints; - int last_order; - HashMap props; - String resource_path; - - bool _set(const StringName &p_name, const Variant &p_value, bool p_emit_signal = true); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List *p_list) const; - - void _initial_set(const StringName &p_name, const Variant &p_value); - static Ref singleton; - String config_file_path; - String settings_path; + HashMap hints; + HashMap props; + int last_order; Ref clipboard; + Vector > translations; + Map > shortcuts; - bool save_changed_setting; - - bool optimize_save; //do not save stuff that came from config but was not set from engine - - void _load_defaults(Ref p_extra_config = NULL); - void _load_default_text_editor_theme(); - - bool _save_text_editor_theme(String p_file); - + String resource_path; + String config_file_path; + String settings_path; String project_config_path; Vector favorite_dirs; Vector recent_dirs; - Vector > translations; - - Map > shortcuts; + bool save_changed_setting; + bool optimize_save; //do not save stuff that came from config but was not set from engine + bool _set(const StringName &p_name, const Variant &p_value, bool p_emit_signal = true); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _initial_set(const StringName &p_name, const Variant &p_value); + void _get_property_list(List *p_list) const; void _add_property_info_bind(const Dictionary &p_info); + void _load_defaults(Ref p_extra_config = NULL); + void _load_default_text_editor_theme(); + bool _save_text_editor_theme(String p_file); + protected: static void _bind_methods(); @@ -126,41 +119,41 @@ public: NOTIFICATION_EDITOR_SETTINGS_CHANGED = 10000 }; - void set_manually(const StringName &p_name, const Variant &p_value, bool p_emit_signal = false) { - _set(p_name, p_value, p_emit_signal); - } + static EditorSettings *get_singleton(); + + static void create(); + void setup_language(); + void setup_network(); + static void save(); + static void destroy(); + void set_optimize_save(bool p_optimize); void set_setting(const String &p_setting, const Variant &p_value); Variant get_setting(const String &p_setting) const; - - bool has_setting(String p_var) const; - static EditorSettings *get_singleton(); - void erase(String p_var); - String get_settings_path() const; - //String get_global_settings_path() const; - String get_project_settings_path() const; - - void setup_language(); - void setup_network(); - - void raise_order(const String &p_name); - static void create(); - static void save(); - static void destroy(); - - void notify_changes(); + bool has_setting(const String &p_setting) const; + void erase(const String &p_setting); + void raise_order(const String &p_setting); + void set_initial_value(const StringName &p_setting, const Variant &p_value); + void set_manually(const StringName &p_setting, const Variant &p_value, bool p_emit_signal = false) { + _set(p_setting, p_value, p_emit_signal); + } + bool property_can_revert(const String &p_setting); + Variant property_get_revert(const String &p_setting); + void add_property_hint(const PropertyInfo &p_hint); void set_resource_clipboard(const Ref &p_resource) { clipboard = p_resource; } Ref get_resource_clipboard() const { return clipboard; } - void add_property_hint(const PropertyInfo &p_hint); + String get_settings_path() const; + String get_project_settings_path() const; + + void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); + Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default); void set_favorite_dirs(const Vector &p_favorites_dirs); Vector get_favorite_dirs() const; - void set_recent_dirs(const Vector &p_recent_dirs); Vector get_recent_dirs() const; - void load_favorites(); void list_text_editor_themes(); @@ -176,15 +169,7 @@ public: Ref get_shortcut(const String &p_name) const; void get_shortcut_list(List *r_shortcuts); - void set_optimize_save(bool p_optimize); - - Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default); - void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); - - bool property_can_revert(const String &p_name); - Variant property_get_revert(const String &p_name); - - void set_initial_value(const StringName &p_name, const Variant &p_value); + void notify_changes(); EditorSettings(); ~EditorSettings(); @@ -193,10 +178,10 @@ public: //not a macro any longer #define EDITOR_DEF(m_var, m_val) _EDITOR_DEF(m_var, Variant(m_val)) -Variant _EDITOR_DEF(const String &p_var, const Variant &p_default); +Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default); #define EDITOR_GET(m_var) _EDITOR_GET(m_var) -Variant _EDITOR_GET(const String &p_var); +Variant _EDITOR_GET(const String &p_setting); #define ED_IS_SHORTCUT(p_name, p_ev) (EditorSettings::get_singleton()->is_shortcut(p_name, p_ev)) Ref ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p_keycode = 0);