summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/create_dialog.cpp66
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/editor_data.cpp45
-rw-r--r--editor/editor_data.h8
-rw-r--r--editor/editor_file_dialog.cpp6
-rw-r--r--editor/editor_file_system.cpp29
-rw-r--r--editor/editor_file_system.h5
-rw-r--r--editor/editor_help.cpp39
-rw-r--r--editor/editor_inspector.cpp5
-rw-r--r--editor/editor_log.cpp32
-rw-r--r--editor/editor_log.h9
-rw-r--r--editor/editor_node.cpp32
-rw-r--r--editor/editor_node.h5
-rw-r--r--editor/editor_plugin.cpp6
-rw-r--r--editor/editor_plugin.h5
-rw-r--r--editor/editor_plugin_settings.cpp36
-rw-r--r--editor/editor_plugin_settings.h9
-rw-r--r--editor/editor_properties.cpp35
-rw-r--r--editor/editor_properties.h3
-rw-r--r--editor/editor_properties_array_dict.cpp61
-rw-r--r--editor/editor_properties_array_dict.h4
-rw-r--r--editor/editor_settings.cpp24
-rw-r--r--editor/editor_themes.cpp20
-rw-r--r--editor/export_template_manager.cpp22
-rw-r--r--editor/export_template_manager.h2
-rw-r--r--editor/filesystem_dock.cpp190
-rw-r--r--editor/filesystem_dock.h23
-rw-r--r--editor/find_in_files.cpp257
-rw-r--r--editor/find_in_files.h24
-rw-r--r--editor/groups_editor.cpp6
-rw-r--r--editor/import/resource_importer_texture.cpp15
-rw-r--r--editor/import/resource_importer_wav.cpp24
-rw-r--r--editor/import_dock.cpp3
-rw-r--r--editor/import_dock.h10
-rw-r--r--editor/inspector_dock.cpp18
-rw-r--r--editor/inspector_dock.h5
-rw-r--r--editor/plugin_config_dialog.cpp230
-rw-r--r--editor/plugin_config_dialog.h71
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp176
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h41
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp185
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h41
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp293
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h45
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp302
-rw-r--r--editor/plugins/animation_state_machine_editor.h44
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp1477
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h198
-rw-r--r--editor/plugins/animation_tree_player_editor_plugin.cpp1446
-rw-r--r--editor/plugins/animation_tree_player_editor_plugin.h187
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp44
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp64
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp4
-rw-r--r--editor/plugins/particles_2d_editor_plugin.cpp15
-rw-r--r--editor/plugins/particles_editor_plugin.cpp17
-rw-r--r--editor/plugins/script_editor_plugin.cpp52
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp164
-rw-r--r--editor/plugins/spatial_editor_plugin.h19
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp23
-rw-r--r--editor/plugins/texture_region_editor_plugin.h1
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp10
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp54
-rw-r--r--editor/plugins/tile_set_editor_plugin.h7
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp3
-rw-r--r--editor/project_export.cpp15
-rw-r--r--editor/project_export.h20
-rw-r--r--editor/project_manager.cpp35
-rw-r--r--editor/project_manager.h6
-rw-r--r--editor/project_settings_editor.cpp26
-rw-r--r--editor/project_settings_editor.h3
-rw-r--r--editor/property_editor.cpp18
-rw-r--r--editor/quick_open.cpp3
-rw-r--r--editor/scene_tree_dock.cpp191
-rw-r--r--editor/scene_tree_dock.h5
-rw-r--r--editor/script_editor_debugger.cpp32
-rw-r--r--editor/script_editor_debugger.h2
-rw-r--r--editor/settings_config_dialog.cpp34
-rw-r--r--editor/settings_config_dialog.h2
-rw-r--r--editor/spatial_editor_gizmos.cpp66
-rw-r--r--editor/spatial_editor_gizmos.h15
83 files changed, 4085 insertions, 2693 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 29275947a4..9d4333bc29 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -745,7 +745,7 @@ bool CodeTextEditor::_add_font_size(int p_delta) {
if (font.is_valid()) {
int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE);
- zoom_nb->set_text(itos(100 * new_size / 14) + "%");
+ zoom_nb->set_text(itos(100 * new_size / (14 * EDSCALE)) + "%");
if (new_size != font->get_size()) {
EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE);
@@ -1341,7 +1341,7 @@ CodeTextEditor::CodeTextEditor() {
font_resize_val = 0;
font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
- zoom_nb->set_text(itos(100 * font_size / 14) + "%");
+ zoom_nb->set_text(itos(100 * font_size / (14 * EDSCALE)) + "%");
font_resize_timer = memnew(Timer);
add_child(font_resize_timer);
font_resize_timer->set_one_shot(true);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 3e0c1f2d53..8433f4ff7b 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -86,7 +86,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) {
memdelete(f);
}
- _update_favorite_list();
+ _save_and_update_favorite_list();
// Restore valid window bounds or pop up at default size.
if (EditorSettings::get_singleton()->has_setting("interface/dialogs/create_new_node_bounds")) {
@@ -157,6 +157,18 @@ Ref<Texture> CreateDialog::_get_editor_icon(const String &p_type) const {
return get_icon(p_type, "EditorIcons");
}
+ if (ScriptServer::is_global_class(p_type)) {
+ String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_type);
+ RES icon;
+ if (FileAccess::exists(icon_path)) {
+ icon = ResourceLoader::load(icon_path);
+ }
+ if (!icon.is_valid()) {
+ icon = get_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons");
+ }
+ return icon;
+ }
+
const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
const Vector<EditorData::CustomType> &ct = E->value();
@@ -180,7 +192,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
return;
bool cpp_type = ClassDB::class_exists(p_type);
- EditorData &ed = EditorNode::get_singleton()->get_editor_data();
+ EditorData &ed = EditorNode::get_editor_data();
if (p_type == base_type)
return;
@@ -262,13 +274,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
const String &description = EditorHelp::get_doc_data()->class_list[p_type].brief_description;
item->set_tooltip(0, description);
- if (cpp_type && has_icon(p_type, "EditorIcons")) {
-
- item->set_icon(0, get_icon(p_type, "EditorIcons"));
- } else if (!cpp_type && has_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons")) {
-
- item->set_icon(0, get_icon(ScriptServer::get_global_class_base(p_type), "EditorIcons"));
- }
+ item->set_icon(0, _get_editor_icon(p_type));
p_types[p_type] = item;
}
@@ -287,7 +293,7 @@ void CreateDialog::_update_search() {
HashMap<String, TreeItem *> types;
TreeItem *root = search_options->create_item();
- EditorData &ed = EditorNode::get_singleton()->get_editor_data();
+ EditorData &ed = EditorNode::get_editor_data();
root->set_text(0, base_type);
if (has_icon(base_type, "EditorIcons")) {
@@ -330,7 +336,7 @@ void CreateDialog::_update_search() {
break;
}
- type = ClassDB::get_parent_class(type);
+ type = cpp_type ? ClassDB::get_parent_class(type) : ed.script_class_get_base(type);
}
if (found)
@@ -425,6 +431,8 @@ void CreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", this, "_confirmed");
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
favorite->set_icon(get_icon("Favorites", "EditorIcons"));
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -488,16 +496,8 @@ Object *CreateDialog::instance_selected() {
custom = md;
if (custom != String()) {
-
if (ScriptServer::is_global_class(custom)) {
- RES script = ResourceLoader::load(ScriptServer::get_global_class_path(custom));
- ERR_FAIL_COND_V(!script.is_valid(), NULL);
-
- Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(custom));
- ERR_FAIL_COND_V(!obj, NULL);
-
- obj->set_script(script.get_ref_ptr());
- return obj;
+ return EditorNode::get_editor_data().script_class_instance(custom);
}
return EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom);
} else {
@@ -543,8 +543,7 @@ void CreateDialog::_favorite_toggled() {
favorite->set_pressed(false);
}
- _save_favorite_list();
- _update_favorite_list();
+ _save_and_update_favorite_list();
}
void CreateDialog::_save_favorite_list() {
@@ -554,8 +553,11 @@ void CreateDialog::_save_favorite_list() {
if (f) {
for (int i = 0; i < favorite_list.size(); i++) {
-
- f->store_line(favorite_list[i]);
+ String l = favorite_list[i];
+ String name = l.split(" ")[0];
+ if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name)))
+ continue;
+ f->store_line(l);
}
memdelete(f);
}
@@ -566,11 +568,15 @@ void CreateDialog::_update_favorite_list() {
favorites->clear();
TreeItem *root = favorites->create_item();
for (int i = 0; i < favorite_list.size(); i++) {
- TreeItem *ti = favorites->create_item(root);
String l = favorite_list[i];
+ String name = l.split(" ")[0];
+ if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name)))
+ continue;
+ TreeItem *ti = favorites->create_item(root);
ti->set_text(0, l);
ti->set_icon(0, _get_editor_icon(l));
}
+ emit_signal("favorites_updated");
}
void CreateDialog::_history_selected() {
@@ -579,7 +585,7 @@ void CreateDialog::_history_selected() {
if (!item)
return;
- search_box->set_text(item->get_text(0));
+ search_box->set_text(item->get_text(0).get_slicec(' ', 0));
_update_search();
}
@@ -589,7 +595,7 @@ void CreateDialog::_favorite_selected() {
if (!item)
return;
- search_box->set_text(item->get_text(0));
+ search_box->set_text(item->get_text(0).get_slicec(' ', 0));
_update_search();
}
@@ -673,6 +679,10 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
}
+ _save_and_update_favorite_list();
+}
+
+void CreateDialog::_save_and_update_favorite_list() {
_save_favorite_list();
_update_favorite_list();
}
@@ -688,12 +698,14 @@ void CreateDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_favorite_selected"), &CreateDialog::_favorite_selected);
ClassDB::bind_method(D_METHOD("_history_activated"), &CreateDialog::_history_activated);
ClassDB::bind_method(D_METHOD("_favorite_activated"), &CreateDialog::_favorite_activated);
+ ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list);
ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw);
ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw);
ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw);
ADD_SIGNAL(MethodInfo("create"));
+ ADD_SIGNAL(MethodInfo("favorites_updated"));
}
CreateDialog::CreateDialog() {
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index f8eec231a4..6df9eebc8c 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -90,6 +90,8 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ void _save_and_update_favorite_list();
+
public:
Object *instance_selected();
String get_selected_type();
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index f4ef11eb36..69c120bb3c 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -888,11 +888,56 @@ StringName EditorData::script_class_get_base(const String &p_class) {
return script->get_language()->get_global_class_name(base_script->get_path());
}
+Object *EditorData::script_class_instance(const String &p_class) {
+ if (ScriptServer::is_global_class(p_class)) {
+ Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(p_class));
+ if (obj) {
+ RES script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class));
+ if (script.is_valid())
+ obj->set_script(script.get_ref_ptr());
+
+ RES icon = ResourceLoader::load(script_class_get_icon_path(p_class));
+ if (icon.is_valid())
+ obj->set_meta("_editor_icon", icon);
+
+ return obj;
+ }
+ }
+ return NULL;
+}
+
+void EditorData::script_class_save_icon_paths() {
+ List<StringName> keys;
+ _script_class_icon_paths.get_key_list(&keys);
+
+ Dictionary d;
+ for (List<StringName>::Element *E = keys.front(); E; E = E->next()) {
+ d[E->get()] = _script_class_icon_paths[E->get()];
+ }
+
+ ProjectSettings::get_singleton()->set("_global_script_class_icons", d);
+ ProjectSettings::get_singleton()->save();
+}
+
+void EditorData::script_class_load_icon_paths() {
+ script_class_clear_icon_paths();
+
+ Dictionary d = ProjectSettings::get_singleton()->get("_global_script_class_icons");
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ String key = E->get().operator String();
+ _script_class_icon_paths[key] = d[key];
+ }
+}
+
EditorData::EditorData() {
current_edited_scene = -1;
//load_imported_scenes_from_globals();
+ script_class_load_icon_paths();
}
///////////
diff --git a/editor/editor_data.h b/editor/editor_data.h
index fac6635cd2..285769aa78 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -146,6 +146,8 @@ private:
bool _find_updated_instances(Node *p_root, Node *p_node, Set<String> &checked_paths);
+ HashMap<StringName, String> _script_class_icon_paths;
+
public:
EditorPlugin *get_editor(Object *p_object);
EditorPlugin *get_subeditor(Object *p_object);
@@ -213,6 +215,12 @@ public:
bool script_class_is_parent(const String &p_class, const String &p_inherits);
StringName script_class_get_base(const String &p_class);
+ Object *script_class_instance(const String &p_class);
+ String script_class_get_icon_path(const String &p_class) const { return _script_class_icon_paths.has(p_class) ? _script_class_icon_paths[p_class] : String(); }
+ void script_class_set_icon_path(const String &p_class, const String &p_icon_path) { _script_class_icon_paths[p_class] = p_icon_path; }
+ void script_class_clear_icon_paths() { _script_class_icon_paths.clear(); }
+ void script_class_save_icon_paths();
+ void script_class_load_icon_paths();
EditorData();
};
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 7d56c4985a..d240f4ed25 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -558,7 +558,9 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p
}
if (single_item_selected) {
item_menu->add_separator();
- item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ Dictionary item_meta = item_list->get_item_metadata(p_item);
+ String item_text = item_meta["dir"] ? TTR("Open In File Manager") : TTR("Show In File Manager");
+ item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER);
}
if (item_menu->get_item_count() > 0) {
@@ -582,7 +584,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) {
}
item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5);
item_menu->add_separator();
- item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
item_menu->set_position(item_list->get_global_position() + p_pos);
item_menu->popup();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d8ab41fa05..9562a8c63c 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -133,6 +133,10 @@ String EditorFileSystemDirectory::get_file_script_class_extends(int p_idx) const
return files[p_idx]->script_class_extends;
}
+String EditorFileSystemDirectory::get_file_script_class_icon_path(int p_idx) const {
+ return files[p_idx]->script_class_icon_path;
+}
+
StringName EditorFileSystemDirectory::get_file_type(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, files.size(), "");
@@ -233,6 +237,7 @@ void EditorFileSystem::_scan_filesystem() {
fc.import_valid = split[4].to_int64() != 0;
fc.script_class_name = split[5].get_slice("<>", 0);
fc.script_class_extends = split[5].get_slice("<>", 1);
+ fc.script_class_icon_path = split[5].get_slice("<>", 2);
String deps = split[6].strip_edges();
if (deps.length()) {
@@ -721,6 +726,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
fi->import_valid = fc->import_valid;
fi->script_class_name = fc->script_class_name;
fi->script_class_extends = fc->script_class_extends;
+ fi->script_class_icon_path = fc->script_class_icon_path;
if (fc->type == String()) {
fi->type = ResourceLoader::get_resource_type(path);
@@ -731,7 +737,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
} else {
fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path);
- fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
+ fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
fi->modified_time = 0;
fi->import_modified_time = 0;
fi->import_valid = ResourceLoader::is_import_valid(path);
@@ -753,10 +759,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
fi->import_valid = true;
fi->script_class_name = fc->script_class_name;
fi->script_class_extends = fc->script_class_extends;
+ fi->script_class_icon_path = fc->script_class_icon_path;
} else {
//new or modified time
fi->type = ResourceLoader::get_resource_type(path);
- fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
+ fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
fi->deps = _get_dependencies(path);
fi->modified_time = mt;
fi->import_modified_time = 0;
@@ -855,7 +862,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
fi->modified_time = FileAccess::get_modified_time(path);
fi->import_modified_time = 0;
fi->type = ResourceLoader::get_resource_type(path);
- fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
+ fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
fi->import_valid = ResourceLoader::is_import_valid(path);
{
@@ -1110,7 +1117,7 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir,
for (int i = 0; i < p_dir->files.size(); i++) {
- String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends;
+ String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path;
s += "::";
for (int j = 0; j < p_dir->files[i]->deps.size(); j++) {
@@ -1316,19 +1323,22 @@ Vector<String> EditorFileSystem::_get_dependencies(const String &p_path) {
return ret;
}
-String EditorFileSystem::_get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const {
+String EditorFileSystem::_get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
if (ScriptServer::get_language(i)->handles_global_class_type(p_type)) {
String global_name;
String extends;
+ String icon_path;
- global_name = ScriptServer::get_language(i)->get_global_class_name(p_path, &extends);
+ global_name = ScriptServer::get_language(i)->get_global_class_name(p_path, &extends, &icon_path);
*r_extends = extends;
+ *r_icon_path = icon_path;
return global_name;
}
}
*r_extends = String();
+ *r_icon_path = String();
return String();
}
@@ -1346,8 +1356,8 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
lang = ScriptServer::get_language(j)->get_name();
}
}
-
ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i));
+ EditorNode::get_editor_data().script_class_set_icon_path(files[i]->script_class_name, files[i]->script_class_icon_path);
}
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
_scan_script_classes(p_dir->get_subdir(i));
@@ -1366,6 +1376,8 @@ void EditorFileSystem::update_script_classes() {
}
ScriptServer::save_global_classes();
+ EditorNode::get_editor_data().script_class_save_icon_paths();
+ emit_signal("script_classes_updated");
}
void EditorFileSystem::_queue_update_script_classes() {
@@ -1437,7 +1449,7 @@ void EditorFileSystem::update_file(const String &p_file) {
}
fs->files[cpos]->type = type;
- fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends);
+ fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path);
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
fs->files[cpos]->deps = _get_dependencies(p_file);
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
@@ -1704,6 +1716,7 @@ void EditorFileSystem::_bind_methods() {
ADD_SIGNAL(MethodInfo("filesystem_changed"));
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources")));
+ ADD_SIGNAL(MethodInfo("script_classes_updated"));
}
void EditorFileSystem::_update_extensions() {
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 1aa35f4782..75ca79932f 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -60,6 +60,7 @@ class EditorFileSystemDirectory : public Object {
bool verified; //used for checking changes
String script_class_name;
String script_class_extends;
+ String script_class_icon_path;
};
struct FileInfoSort {
@@ -90,6 +91,7 @@ public:
bool get_file_import_is_valid(int p_idx) const;
String get_file_script_class_name(int p_idx) const; //used for scripts
String get_file_script_class_extends(int p_idx) const; //used for scripts
+ String get_file_script_class_icon_path(int p_idx) const; //used for scripts
EditorFileSystemDirectory *get_parent();
@@ -163,6 +165,7 @@ class EditorFileSystem : public Node {
bool import_valid;
String script_class_name;
String script_class_extends;
+ String script_class_icon_path;
};
HashMap<String, FileCache> file_cache;
@@ -225,7 +228,7 @@ class EditorFileSystem : public Node {
volatile bool update_script_classes_queued;
void _queue_update_script_classes();
- String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const;
+ String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
protected:
void _notification(int p_what);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index b7a5f67870..65c41ef579 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -253,7 +253,8 @@ void EditorHelpSearch::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
//_update_icons
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
connect("confirmed", this, "_confirmed");
_update_search();
@@ -267,7 +268,8 @@ void EditorHelpSearch::_notification(int p_what) {
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
//_update_icons
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
} else if (p_what == NOTIFICATION_PROCESS) {
if (search.is_valid()) {
@@ -381,7 +383,8 @@ void EditorHelpIndex::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
//_update_icons
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
_update_class_list();
connect("confirmed", this, "_tree_item_selected");
@@ -392,7 +395,8 @@ void EditorHelpIndex::_notification(int p_what) {
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
//_update_icons
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
}
}
@@ -541,6 +545,7 @@ void EditorHelp::_class_desc_select(const String &p_select) {
String class_name;
if (select.find(".") != -1) {
class_name = select.get_slice(".", 0);
+ select = select.get_slice(".", 1);
} else {
class_name = "@GlobalScope";
}
@@ -713,16 +718,22 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
if (p_class == edited_class)
return OK; //already there
+ edited_class = p_class;
+ _update_doc();
+ return OK;
+}
+
+void EditorHelp::_update_doc() {
+
scroll_locked = true;
class_desc->clear();
method_line.clear();
section_line.clear();
- edited_class = p_class;
_init_colors();
- DocData::ClassDoc cd = doc->class_list[p_class]; //make a copy, so we can sort without worrying
+ DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying
Ref<Font> doc_font = get_font("doc", "EditorFonts");
Ref<Font> doc_title_font = get_font("doc_title", "EditorFonts");
@@ -734,7 +745,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_color(title_color);
class_desc->add_text(TTR("Class:") + " ");
class_desc->push_color(headline_color);
- _add_text(p_class);
+ _add_text(edited_class);
class_desc->pop();
class_desc->pop();
class_desc->pop();
@@ -1453,8 +1464,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
}
scroll_locked = false;
-
- return OK;
}
void EditorHelp::_request_help(const String &p_string) {
@@ -1751,9 +1760,6 @@ void EditorHelp::_add_text(const String &p_bbcode) {
_add_text_to_rt(p_bbcode, class_desc);
}
-void EditorHelp::_update_doc() {
-}
-
void EditorHelp::generate_doc() {
doc = memnew(DocData);
@@ -1775,7 +1781,8 @@ void EditorHelp::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ class_desc->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
+ _update_doc();
} break;
@@ -1856,7 +1863,7 @@ EditorHelp::EditorHelp() {
class_desc = memnew(RichTextLabel);
add_child(class_desc);
class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
- class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ class_desc->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
class_desc->connect("meta_clicked", this, "_class_desc_select");
class_desc->connect("gui_input", this, "_class_desc_input");
@@ -1922,7 +1929,7 @@ void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ rich_text->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
} break;
default: break;
@@ -1941,7 +1948,7 @@ EditorHelpBit::EditorHelpBit() {
add_child(rich_text);
//rich_text->set_anchors_and_margins_preset(Control::PRESET_WIDE);
rich_text->connect("meta_clicked", this, "_meta_clicked");
- rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ rich_text->add_color_override("selection_color", EditorSettings::get_singleton()->get("text_editor/theme/selection_color"));
rich_text->set_override_selected_font_color(false);
set_custom_minimum_size(Size2(0, 70 * EDSCALE));
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 99a2b2aa67..852e1930d2 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1533,9 +1533,10 @@ void EditorInspector::update_tree() {
if (capitalize_paths)
path_name = path_name.capitalize();
+
Color c = sscolor;
c.a /= level;
- section->setup(path_name, acc_path, object, c, use_folding);
+ section->setup(acc_path, path_name, object, c, use_folding);
item_path[acc_path] = section->get_vbox();
}
@@ -2221,7 +2222,7 @@ EditorInspector::EditorInspector() {
show_categories = false;
hide_script = true;
use_doc_hints = false;
- capitalize_paths = false;
+ capitalize_paths = true;
use_filter = false;
autoclear = false;
changing = 0;
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 158eedfb0f..b3ec717d85 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -54,7 +54,11 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f
self->emit_signal("show_request");
*/
- self->add_message(err_str, true);
+ if (p_type == ERR_HANDLER_WARNING) {
+ self->add_message(err_str, MSG_TYPE_WARNING);
+ } else {
+ self->add_message(err_str, MSG_TYPE_ERROR);
+ }
}
void EditorLog::_notification(int p_what) {
@@ -95,22 +99,32 @@ void EditorLog::clear() {
_clear_request();
}
-void EditorLog::add_message(const String &p_msg, bool p_error) {
+void EditorLog::add_message(const String &p_msg, MessageType p_type) {
log->add_newline();
- if (p_error) {
- log->push_color(get_color("error_color", "Editor"));
- Ref<Texture> icon = get_icon("Error", "EditorIcons");
- log->add_image(icon);
- log->add_text(" ");
- tool_button->set_icon(icon);
+ bool restore = p_type != MSG_TYPE_STD;
+ switch (p_type) {
+ case MSG_TYPE_ERROR: {
+ log->push_color(get_color("error_color", "Editor"));
+ Ref<Texture> icon = get_icon("Error", "EditorIcons");
+ log->add_image(icon);
+ log->add_text(" ");
+ tool_button->set_icon(icon);
+ } break;
+ case MSG_TYPE_WARNING: {
+ log->push_color(get_color("warning_color", "Editor"));
+ Ref<Texture> icon = get_icon("Warning", "EditorIcons");
+ log->add_image(icon);
+ log->add_text(" ");
+ tool_button->set_icon(icon);
+ } break;
}
log->add_text(p_msg);
//button->set_text(p_msg);
- if (p_error)
+ if (restore)
log->pop();
}
diff --git a/editor/editor_log.h b/editor/editor_log.h
index f9bc82de7d..8d0310d914 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -42,6 +42,7 @@
#include "scene/gui/panel_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h"
+
class EditorLog : public VBoxContainer {
GDCLASS(EditorLog, VBoxContainer);
@@ -68,7 +69,13 @@ protected:
void _notification(int p_what);
public:
- void add_message(const String &p_msg, bool p_error = false);
+ enum MessageType {
+ MSG_TYPE_STD,
+ MSG_TYPE_ERROR,
+ MSG_TYPE_WARNING
+ };
+
+ void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
void set_tool_button(ToolButton *p_tool_button);
void deinit();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 81b7a66361..975c7f8345 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -74,6 +74,7 @@
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/animation_state_machine_editor.h"
#include "editor/plugins/animation_tree_editor_plugin.h"
+#include "editor/plugins/animation_tree_player_editor_plugin.h"
#include "editor/plugins/asset_library_editor_plugin.h"
#include "editor/plugins/audio_stream_editor_plugin.h"
#include "editor/plugins/baked_lightmap_editor_plugin.h"
@@ -411,6 +412,18 @@ void EditorNode::_notification(int p_what) {
}
}
+void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) {
+ Ref<Script> script = Object::cast_to<Script>(p_script);
+ if (script.is_null())
+ return;
+ if (p_activate_name.length()) {
+ set_addon_plugin_enabled(p_activate_name, true);
+ }
+ project_settings->update_plugins();
+ project_settings->hide();
+ push_item(script.operator->());
+}
+
void EditorNode::_fs_changed() {
for (Set<FileDialog *>::Element *E = file_dialogs.front(); E; E = E->next()) {
@@ -2547,6 +2560,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled)
EditorPlugin *ep = memnew(EditorPlugin);
ep->set_script(script.get_ref_ptr());
+ ep->set_dir_cache(p_addon);
plugin_addons[p_addon] = ep;
add_editor_plugin(ep);
@@ -4548,6 +4562,8 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_resources_reimported"), &EditorNode::_resources_reimported);
ClassDB::bind_method(D_METHOD("_bottom_panel_raise_toggled"), &EditorNode::_bottom_panel_raise_toggled);
+ ClassDB::bind_method(D_METHOD("_on_plugin_ready"), &EditorNode::_on_plugin_ready);
+
ClassDB::bind_method(D_METHOD("_video_driver_selected"), &EditorNode::_video_driver_selected);
ADD_SIGNAL(MethodInfo("play_pressed"));
@@ -4566,7 +4582,7 @@ static Node *_resource_get_edited_scene() {
void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error) {
EditorNode *en = (EditorNode *)p_this;
- en->log->add_message(p_string, p_error);
+ en->log->add_message(p_string, p_error ? EditorLog::MSG_TYPE_ERROR : EditorLog::MSG_TYPE_STD);
}
EditorNode::EditorNode() {
@@ -4776,7 +4792,7 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
EDITOR_DEF("interface/inspector/horizontal_vector3_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
- EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial");
+ EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial,Script");
EDITOR_DEF("run/auto_save/save_before_running", true);
theme_base = memnew(Control);
@@ -5134,6 +5150,10 @@ EditorNode::EditorNode() {
p->connect("id_pressed", this, "_menu_option");
p->add_item(TTR("Export"), FILE_EXPORT_PROJECT);
+ plugin_config_dialog = memnew(PluginConfigDialog);
+ plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready");
+ gui_base->add_child(plugin_config_dialog);
+
tool_menu = memnew(PopupMenu);
tool_menu->set_name("Tools");
tool_menu->connect("index_pressed", this, "_tool_menu_option");
@@ -5409,7 +5429,7 @@ EditorNode::EditorNode() {
}
filesystem_dock = memnew(FileSystemDock(this));
- filesystem_dock->set_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
+ filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")));
if (use_single_dock_column) {
dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(filesystem_dock);
@@ -5448,6 +5468,7 @@ EditorNode::EditorNode() {
bottom_panel->add_child(bottom_panel_vb);
bottom_panel_hb = memnew(HBoxContainer);
+ bottom_panel_hb->set_custom_minimum_size(Size2(0, 24)); // Adjust for the height of the "Expand Bottom Dock" icon.
bottom_panel_vb->add_child(bottom_panel_hb);
bottom_panel_hb_editors = memnew(HBoxContainer);
@@ -5569,16 +5590,13 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(ShaderEditorPlugin(this)));
add_editor_plugin(memnew(VisualShaderEditorPlugin(this)));
- add_editor_plugin(memnew(AnimationNodeBlendTreeEditorPlugin(this)));
- add_editor_plugin(memnew(AnimationNodeBlendSpace1DEditorPlugin(this)));
- add_editor_plugin(memnew(AnimationNodeBlendSpace2DEditorPlugin(this)));
- add_editor_plugin(memnew(AnimationNodeStateMachineEditorPlugin(this)));
add_editor_plugin(memnew(CameraEditorPlugin(this)));
add_editor_plugin(memnew(ThemeEditorPlugin(this)));
add_editor_plugin(memnew(MultiMeshEditorPlugin(this)));
add_editor_plugin(memnew(MeshInstanceEditorPlugin(this)));
add_editor_plugin(memnew(AnimationTreeEditorPlugin(this)));
+ add_editor_plugin(memnew(AnimationTreePlayerEditorPlugin(this)));
add_editor_plugin(memnew(MeshLibraryEditorPlugin(this)));
add_editor_plugin(memnew(StyleBoxEditorPlugin(this)));
add_editor_plugin(memnew(SpriteEditorPlugin(this)));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 85aa37ec7e..5a17ab6ca0 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -56,6 +56,7 @@
#include "editor/inspector_dock.h"
#include "editor/node_dock.h"
#include "editor/pane_drag.h"
+#include "editor/plugin_config_dialog.h"
#include "editor/progress_dialog.h"
#include "editor/project_export.h"
#include "editor/project_settings_editor.h"
@@ -257,6 +258,8 @@ private:
ToolButton *search_button;
TextureProgress *audio_vu;
+ PluginConfigDialog *plugin_config_dialog;
+
RichTextLabel *load_errors;
AcceptDialog *load_error_dialog;
@@ -416,6 +419,8 @@ private:
void _tool_menu_option(int p_idx);
void _update_debug_options();
+ void _on_plugin_ready(Object *p_script, const String &p_activate_name);
+
void _fs_changed();
void _resources_reimported(const Vector<String> &p_resources);
void _sources_changed(bool p_exist);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index a926401558..137e710c5c 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -309,6 +309,12 @@ void EditorPlugin::remove_autoload_singleton(const String &p_name) {
EditorNode::get_singleton()->get_project_settings()->get_autoload_settings()->autoload_remove(p_name);
}
+Ref<ConfigFile> EditorPlugin::get_config() {
+ Ref<ConfigFile> cf = memnew(ConfigFile);
+ cf->load(_dir_cache.plus_file("plugin.cfg"));
+ return cf;
+}
+
ToolButton *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const String &p_title) {
ERR_FAIL_NULL_V(p_control, NULL);
return EditorNode::get_singleton()->add_bottom_panel_item(p_title, p_control);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index c417f487dc..903b82937f 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -114,6 +114,7 @@ class EditorPlugin : public Node {
bool force_draw_over_forwarding_enabled;
String last_main_screen_name;
+ String _dir_cache;
protected:
static void _bind_methods();
@@ -221,6 +222,10 @@ public:
void add_autoload_singleton(const String &p_name, const String &p_path);
void remove_autoload_singleton(const String &p_name);
+ void set_dir_cache(const String &p_dir) { _dir_cache = p_dir; }
+ String get_dir_cache() { return _dir_cache; }
+ Ref<ConfigFile> get_config();
+
EditorPlugin();
virtual ~EditorPlugin();
};
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index ea1e0fe99e..68f8ed6d94 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -41,6 +41,9 @@ void EditorPluginSettings::_notification(int p_what) {
if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) {
update_plugins();
+ } else if (p_what == Node::NOTIFICATION_READY) {
+ plugin_config_dialog->connect("plugin_ready", EditorNode::get_singleton(), "_on_plugin_ready");
+ plugin_list->connect("button_pressed", this, "_cell_button_pressed");
}
}
@@ -124,6 +127,7 @@ void EditorPluginSettings::update_plugins() {
item->set_range_config(3, 0, 1, 1);
item->set_text(3, "Inactive,Active");
item->set_editable(3, true);
+ item->add_button(4, get_icon("Edit", "EditorIcons"), BUTTON_PLUGIN_EDIT, false, TTR("Edit Plugin"));
if (EditorNode::get_singleton()->is_addon_plugin_enabled(d)) {
item->set_custom_color(3, get_color("success_color", "Editor"));
@@ -164,17 +168,44 @@ void EditorPluginSettings::_plugin_activity_changed() {
ti->set_custom_color(3, get_color("disabled_font_color", "Editor"));
}
+void EditorPluginSettings::_create_clicked() {
+ plugin_config_dialog->config("");
+ plugin_config_dialog->popup_centered();
+}
+
+void EditorPluginSettings::_cell_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item)
+ return;
+ if (p_id == BUTTON_PLUGIN_EDIT) {
+ if (p_column == 4) {
+ String dir = item->get_metadata(0);
+ plugin_config_dialog->config("res://addons/" + dir + "/plugin.cfg");
+ plugin_config_dialog->popup_centered();
+ }
+ }
+}
+
void EditorPluginSettings::_bind_methods() {
ClassDB::bind_method("update_plugins", &EditorPluginSettings::update_plugins);
+ ClassDB::bind_method("_create_clicked", &EditorPluginSettings::_create_clicked);
ClassDB::bind_method("_plugin_activity_changed", &EditorPluginSettings::_plugin_activity_changed);
+ ClassDB::bind_method("_cell_button_pressed", &EditorPluginSettings::_cell_button_pressed);
}
EditorPluginSettings::EditorPluginSettings() {
+ plugin_config_dialog = memnew(PluginConfigDialog);
+ plugin_config_dialog->config("");
+ add_child(plugin_config_dialog);
+
HBoxContainer *title_hb = memnew(HBoxContainer);
title_hb->add_child(memnew(Label(TTR("Installed Plugins:"))));
title_hb->add_spacer();
+ create_plugin = memnew(Button(TTR("Create")));
+ create_plugin->connect("pressed", this, "_create_clicked");
+ title_hb->add_child(create_plugin);
update_list = memnew(Button(TTR("Update")));
update_list->connect("pressed", this, "update_plugins");
title_hb->add_child(update_list);
@@ -182,19 +213,22 @@ EditorPluginSettings::EditorPluginSettings() {
plugin_list = memnew(Tree);
plugin_list->set_v_size_flags(SIZE_EXPAND_FILL);
- plugin_list->set_columns(4);
+ plugin_list->set_columns(5);
plugin_list->set_column_titles_visible(true);
plugin_list->set_column_title(0, TTR("Name:"));
plugin_list->set_column_title(1, TTR("Version:"));
plugin_list->set_column_title(2, TTR("Author:"));
plugin_list->set_column_title(3, TTR("Status:"));
+ plugin_list->set_column_title(4, TTR("Edit:"));
plugin_list->set_column_expand(0, true);
plugin_list->set_column_expand(1, false);
plugin_list->set_column_expand(2, false);
plugin_list->set_column_expand(3, false);
+ plugin_list->set_column_expand(4, false);
plugin_list->set_column_min_width(1, 100 * EDSCALE);
plugin_list->set_column_min_width(2, 250 * EDSCALE);
plugin_list->set_column_min_width(3, 80 * EDSCALE);
+ plugin_list->set_column_min_width(4, 40 * EDSCALE);
plugin_list->set_hide_root(true);
plugin_list->connect("item_edited", this, "_plugin_activity_changed");
diff --git a/editor/editor_plugin_settings.h b/editor/editor_plugin_settings.h
index aacbd05dd4..194fac6b92 100644
--- a/editor/editor_plugin_settings.h
+++ b/editor/editor_plugin_settings.h
@@ -31,6 +31,7 @@
#ifndef EDITORPLUGINSETTINGS_H
#define EDITORPLUGINSETTINGS_H
+#include "editor/plugin_config_dialog.h"
#include "editor_data.h"
#include "property_editor.h"
#include "scene/gui/dialogs.h"
@@ -40,11 +41,19 @@ class EditorPluginSettings : public VBoxContainer {
GDCLASS(EditorPluginSettings, VBoxContainer);
+ enum {
+ BUTTON_PLUGIN_EDIT
+ };
+
+ PluginConfigDialog *plugin_config_dialog;
+ Button *create_plugin;
Button *update_list;
Tree *plugin_list;
bool updating;
void _plugin_activity_changed();
+ void _create_clicked();
+ void _cell_button_pressed(Object *p_item, int p_column, int p_id);
protected:
void _notification(int p_what);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 83a3662f21..5f1e7273e5 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -46,6 +46,17 @@ EditorPropertyNil::EditorPropertyNil() {
}
///////////////////// TEXT /////////////////////////
+
+void EditorPropertyText::_text_entered(const String &p_string) {
+ if (updating)
+ return;
+
+ if (text->has_focus()) {
+ text->release_focus();
+ _text_changed(p_string);
+ }
+}
+
void EditorPropertyText::_text_changed(const String &p_string) {
if (updating)
return;
@@ -61,9 +72,14 @@ void EditorPropertyText::update_property() {
updating = false;
}
+void EditorPropertyText::set_placeholder(const String &p_string) {
+ text->set_placeholder(p_string);
+}
+
void EditorPropertyText::_bind_methods() {
ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed);
+ ClassDB::bind_method(D_METHOD("_text_entered", "txt"), &EditorPropertyText::_text_entered);
}
EditorPropertyText::EditorPropertyText() {
@@ -71,6 +87,8 @@ EditorPropertyText::EditorPropertyText() {
add_child(text);
add_focusable(text);
text->connect("text_changed", this, "_text_changed");
+ text->connect("text_entered", this, "_text_entered");
+
updating = false;
}
@@ -82,7 +100,6 @@ void EditorPropertyMultilineText::_big_text_changed() {
}
void EditorPropertyMultilineText::_text_changed() {
-
emit_signal("property_changed", get_edited_property(), text->get_text(), true);
}
@@ -1721,12 +1738,18 @@ EditorPropertyTransform::EditorPropertyTransform() {
void EditorPropertyColor::_color_changed(const Color &p_color) {
- emit_signal("property_changed", get_edited_property(), p_color);
+ emit_signal("property_changed", get_edited_property(), p_color, true);
+}
+
+void EditorPropertyColor::_popup_closed() {
+
+ emit_signal("property_changed", get_edited_property(), picker->get_pick_color(), false);
}
void EditorPropertyColor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_color_changed"), &EditorPropertyColor::_color_changed);
+ ClassDB::bind_method(D_METHOD("_popup_closed"), &EditorPropertyColor::_popup_closed);
}
void EditorPropertyColor::update_property() {
@@ -1744,6 +1767,7 @@ EditorPropertyColor::EditorPropertyColor() {
add_child(picker);
picker->set_flat(true);
picker->connect("color_changed", this, "_color_changed");
+ picker->connect("popup_closed", this, "_popup_closed");
}
////////////// NODE PATH //////////////////////
@@ -2038,7 +2062,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
ERR_BREAK(!resp);
if (get_edited_object() && base_type != String() && base_type == "Script") {
//make visual script the right type
- res->call("set_instance_base_type", get_edited_object()->get_class());
+ resp->call("set_instance_base_type", get_edited_object()->get_class());
}
res = Ref<Resource>(resp);
@@ -2240,7 +2264,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) {
void EditorPropertyResource::_open_editor_pressed() {
RES res = get_edited_object()->get(get_edited_property());
if (res.is_valid()) {
- EditorNode::get_singleton()->edit_resource(res.ptr());
+ EditorNode::get_singleton()->edit_item(res.ptr());
}
}
@@ -2763,6 +2787,9 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
} else {
EditorPropertyText *editor = memnew(EditorPropertyText);
+ if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
+ editor->set_placeholder(p_hint_text);
+ }
add_property_editor(p_path, editor);
}
} break;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index ccd73d2539..5726ccfa41 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -54,12 +54,14 @@ class EditorPropertyText : public EditorProperty {
bool updating;
void _text_changed(const String &p_string);
+ void _text_entered(const String &p_string);
protected:
static void _bind_methods();
public:
virtual void update_property();
+ void set_placeholder(const String &p_string);
EditorPropertyText();
};
@@ -475,6 +477,7 @@ class EditorPropertyColor : public EditorProperty {
GDCLASS(EditorPropertyColor, EditorProperty)
ColorPickerButton *picker;
void _color_changed(const Color &p_color);
+ void _popup_closed();
protected:
static void _bind_methods();
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 2bd28170e7..23dbb026dd 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -125,13 +125,13 @@ EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() {
///////////////////// ARRAY ///////////////////////////
-void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value) {
+void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value, bool changing) {
if (p_prop.begins_with("indices")) {
int idx = p_prop.get_slice("/", 1).to_int();
Variant array = object->get_array();
array.set(idx, p_value);
- emit_signal("property_changed", get_edited_property(), array);
+ emit_signal("property_changed", get_edited_property(), array, true);
if (array.get_type() == Variant::ARRAY) {
array = array.call("duplicate"); //dupe, so undo/redo works better
@@ -210,8 +210,8 @@ void EditorPropertyArray::update_property() {
default: {}
}
- if (!array.is_array()) {
- edit->set_text(arrtype + "[" + Variant::get_type_name(array.get_type()) + "]");
+ if (array.get_type() == Variant::NIL) {
+ edit->set_text(String("(Nil) ") + arrtype);
edit->set_pressed(false);
if (vbox) {
memdelete(vbox);
@@ -219,7 +219,7 @@ void EditorPropertyArray::update_property() {
return;
}
- edit->set_text(arrtype + "[" + itos(array.call("size")) + "]");
+ edit->set_text(arrtype + "(size " + itos(array.call("size")) + ")");
#ifdef TOOLS_ENABLED
@@ -544,7 +544,7 @@ void EditorPropertyArray::_bind_methods() {
ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed);
ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed);
ClassDB::bind_method("_length_changed", &EditorPropertyArray::_length_changed);
- ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed);
+ ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed, DEFVAL(false));
ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type);
ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu);
}
@@ -579,7 +579,7 @@ EditorPropertyArray::EditorPropertyArray() {
///////////////////// DICTIONARY ///////////////////////////
-void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value) {
+void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value, bool changing) {
if (p_prop == "new_item_key") {
@@ -593,7 +593,7 @@ void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p
Variant key = dict.get_key_at_index(idx);
dict[key] = p_value;
- emit_signal("property_changed", get_edited_property(), dict);
+ emit_signal("property_changed", get_edited_property(), dict, true);
dict = dict.duplicate(); //dupe, so undo/redo works better
object->set_dict(dict);
@@ -613,7 +613,13 @@ void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
void EditorPropertyDictionary::_add_key_value() {
+ // Do not allow nil as valid key. I experienced errors with this
+ if (object->get_new_item_key().get_type() == Variant::NIL) {
+ return;
+ }
+
Dictionary dict = object->get_dict();
+
dict[object->get_new_item_key()] = object->get_new_item_value();
object->set_new_item_key(Variant());
object->set_new_item_value(Variant());
@@ -663,9 +669,20 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) {
void EditorPropertyDictionary::update_property() {
- Dictionary dict = get_edited_object()->get(get_edited_property());
+ Variant updated_val = get_edited_object()->get(get_edited_property());
+
+ if (updated_val.get_type() == Variant::NIL) {
+ edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property.
+ edit->set_pressed(false);
+ if (vbox) {
+ memdelete(vbox);
+ }
+ return;
+ }
+
+ Dictionary dict = updated_val;
- edit->set_text("Dict[" + itos(dict.size()) + "]");
+ edit->set_text("Dictionary (size " + itos(dict.size()) + ")");
#ifdef TOOLS_ENABLED
@@ -695,9 +712,9 @@ void EditorPropertyDictionary::update_property() {
page->set_h_size_flags(SIZE_EXPAND_FILL);
page->connect("value_changed", this, "_page_changed");
} else {
- //bye bye children of the box
- while (vbox->get_child_count() > 1) {
- memdelete(vbox->get_child(1));
+ // Queue childs for deletion, delete immediately might cause errors.
+ for (size_t i = 1; i < vbox->get_child_count(); i++) {
+ vbox->get_child(i)->queue_delete();
}
}
@@ -941,10 +958,10 @@ void EditorPropertyDictionary::update_property() {
prop->update_property();
if (i == amount + 1) {
- Button *add_item = memnew(Button);
- add_item->set_text(TTR("Add Key/Value Pair"));
- add_vbox->add_child(add_item);
- add_item->connect("pressed", this, "_add_key_value");
+ Button *butt_add_item = memnew(Button);
+ butt_add_item->set_text(TTR("Add Key/Value Pair"));
+ butt_add_item->connect("pressed", this, "_add_key_value");
+ add_vbox->add_child(butt_add_item);
}
}
@@ -965,8 +982,16 @@ void EditorPropertyDictionary::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
}
}
+
void EditorPropertyDictionary::_edit_pressed() {
+ Variant prop_val = get_edited_object()->get(get_edited_property());
+ if (prop_val.get_type() == Variant::NIL) {
+ Variant::CallError ce;
+ prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce);
+ get_edited_object()->set(get_edited_property(), prop_val);
+ }
+
get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
update_property();
}
@@ -981,7 +1006,7 @@ void EditorPropertyDictionary::_page_changed(double p_page) {
void EditorPropertyDictionary::_bind_methods() {
ClassDB::bind_method("_edit_pressed", &EditorPropertyDictionary::_edit_pressed);
ClassDB::bind_method("_page_changed", &EditorPropertyDictionary::_page_changed);
- ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed);
+ ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed, DEFVAL(false));
ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type);
ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu);
ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value);
diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h
index 75c67d280d..a8ddb02e9d 100644
--- a/editor/editor_properties_array_dict.h
+++ b/editor/editor_properties_array_dict.h
@@ -67,7 +67,7 @@ class EditorPropertyArray : public EditorProperty {
void _page_changed(double p_page);
void _length_changed(double p_page);
void _edit_pressed();
- void _property_changed(const String &p_prop, Variant p_value);
+ void _property_changed(const String &p_prop, Variant p_value, bool changing = false);
void _change_type(Object *p_button, int p_index);
void _change_type_menu(int p_index);
@@ -99,7 +99,7 @@ class EditorPropertyDictionary : public EditorProperty {
void _page_changed(double p_page);
void _edit_pressed();
- void _property_changed(const String &p_prop, Variant p_value);
+ void _property_changed(const String &p_prop, Variant p_value, bool changing = false);
void _change_type(Object *p_button, int p_index);
void _change_type_menu(int p_index);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 02e121b5f1..85186440ab 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -357,6 +357,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom");
_initial_set("text_editor/theme/line_spacing", 4);
+ _initial_set("text_editor/theme/selection_color", Color::html("40808080"));
_load_default_text_editor_theme();
@@ -396,7 +397,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/cursor/block_caret", false);
_initial_set("text_editor/cursor/caret_blink", true);
- _initial_set("text_editor/cursor/caret_blink_speed", 0.65);
+ _initial_set("text_editor/cursor/caret_blink_speed", 0.5);
hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.01");
_initial_set("text_editor/cursor/right_click_moves_caret", true);
@@ -473,6 +474,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["editors/3d/freelook/freelook_modifier_speed_factor"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_modifier_speed_factor", PROPERTY_HINT_RANGE, "0.0, 10.0, 0.1");
_initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);
+ _initial_set("editors/2d/grid_color", Color(1.0, 1.0, 1.0, 0.07));
_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8));
_initial_set("editors/2d/bone_width", 5);
_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
@@ -511,6 +513,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("filesystem/file_dialog/thumbnail_size", 64);
hints["filesystem/file_dialog/thumbnail_size"] = PropertyInfo(Variant::INT, "filesystem/file_dialog/thumbnail_size", PROPERTY_HINT_RANGE, "32,128,16");
+ _initial_set("docks/filesystem/disable_split", false);
+ _initial_set("docks/filesystem/split_mode_minimum_height", 600);
_initial_set("docks/filesystem/display_mode", 0);
hints["docks/filesystem/display_mode"] = PropertyInfo(Variant::INT, "docks/filesystem/display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List");
_initial_set("docks/filesystem/thumbnail_size", 64);
@@ -755,7 +759,7 @@ void EditorSettings::create() {
}
if (dir->change_dir(data_dir) != OK) {
- dir->make_dir(data_dir);
+ dir->make_dir_recursive(data_dir);
if (dir->change_dir(data_dir) != OK) {
ERR_PRINT("Cannot create data directory!");
memdelete(dir);
@@ -771,14 +775,8 @@ void EditorSettings::create() {
// Validate/create cache dir
- if (dir->change_dir(cache_path) != OK) {
- ERR_PRINT("Cannot find path for cache directory!");
- memdelete(dir);
- goto fail;
- }
-
if (dir->change_dir(cache_dir) != OK) {
- dir->make_dir(cache_dir);
+ dir->make_dir_recursive(cache_dir);
if (dir->change_dir(cache_dir) != OK) {
ERR_PRINT("Cannot create cache directory!");
memdelete(dir);
@@ -788,14 +786,8 @@ void EditorSettings::create() {
// Validate/create config dir and subdirectories
- 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);
+ dir->make_dir_recursive(config_dir);
if (dir->change_dir(config_dir) != OK) {
ERR_PRINT("Cannot create config directory!");
memdelete(dir);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 0a22026591..50d71f1c98 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -173,9 +173,9 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const Color error_color = p_theme->get_color("error_color", "Editor");
const Color success_color = p_theme->get_color("success_color", "Editor");
const Color warning_color = p_theme->get_color("warning_color", "Editor");
- dark_icon_color_dictionary[Color::html("#ff5d5d")] = error_color;
+ dark_icon_color_dictionary[Color::html("#ff0000")] = error_color;
dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color;
- dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color;
+ dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color;
List<String> exceptions;
exceptions.push_back("EditorPivot");
@@ -365,13 +365,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("mono_color", "Editor", mono_color);
Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2;
- Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.2;
+ Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.0;
Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7;
Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5);
if (!dark_theme) {
// yellow on white themes is a P.I.T.A.
- warning_color = accent_color.linear_interpolate(Color(1, 0.8, 0), 0.9);
+ warning_color = accent_color.linear_interpolate(Color(0.9, 0.7, 0), 0.9);
warning_color = warning_color.linear_interpolate(mono_color, 0.2);
success_color = success_color.linear_interpolate(mono_color, 0.2);
error_color = error_color.linear_interpolate(mono_color, 0.2);
@@ -381,12 +381,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("error_color", "Editor", error_color);
theme->set_color("property_color", "Editor", property_color);
- // 2d grid color
- const Color grid_minor_color = mono_color * Color(1.0, 1.0, 1.0, 0.07);
- const Color grid_major_color = Color(font_color_disabled.r, font_color_disabled.g, font_color_disabled.b, 0.15);
- theme->set_color("grid_major_color", "Editor", grid_major_color);
- theme->set_color("grid_minor_color", "Editor", grid_minor_color);
-
const int thumb_size = EDITOR_DEF("filesystem/file_dialog/thumbnail_size", 64);
theme->set_constant("scale", "Editor", EDSCALE);
theme->set_constant("thumb_size", "Editor", thumb_size);
@@ -828,6 +822,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("cursor_color", "LineEdit", font_color);
theme->set_color("selection_color", "LineEdit", font_color_selection);
+ theme->set_color("clear_button_color", "LineEdit", font_color);
+ theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
// TextEdit
theme->set_stylebox("normal", "TextEdit", style_widget);
@@ -969,8 +965,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// GraphEdit
theme->set_stylebox("bg", "GraphEdit", style_tree_bg);
- theme->set_color("grid_major", "GraphEdit", grid_major_color);
- theme->set_color("grid_minor", "GraphEdit", grid_minor_color);
+ theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15));
+ theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07));
theme->set_color("activity", "GraphEdit", accent_color);
theme->set_icon("minus", "GraphEdit", theme->get_icon("ZoomLess", "EditorIcons"));
theme->set_icon("more", "GraphEdit", theme->get_icon("ZoomMore", "EditorIcons"));
diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp
index 931785333f..6c9d1568fa 100644
--- a/editor/export_template_manager.cpp
+++ b/editor/export_template_manager.cpp
@@ -178,7 +178,7 @@ void ExportTemplateManager::_uninstall_template_confirm() {
_update_template_list();
}
-void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) {
+bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) {
FileAccess *fa = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&fa);
@@ -187,7 +187,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (!pkg) {
EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip."));
- return;
+ return false;
}
int ret = unzGoToFirstFile(pkg);
@@ -221,7 +221,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (data_str.get_slice_count(".") < 3) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str));
unzClose(pkg);
- return;
+ return false;
}
version = data_str;
@@ -237,7 +237,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (version == String()) {
EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates."));
unzClose(pkg);
- return;
+ return false;
}
String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version);
@@ -247,7 +247,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
if (err != OK) {
EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path);
unzClose(pkg);
- return;
+ return false;
}
memdelete(d);
@@ -310,6 +310,8 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_
unzClose(pkg);
_update_template_list();
+
+ return true;
}
void ExportTemplateManager::popup_manager() {
@@ -401,7 +403,15 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int
String path = download_templates->get_download_file();
template_list_state->set_text(TTR("Download Complete."));
template_downloader->hide();
- _install_from_file(path, false);
+ int ret = _install_from_file(path, false);
+ if (ret) {
+ Error err = OS::get_singleton()->move_to_trash(path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + path + "\n");
+ }
+ } else {
+ WARN_PRINTS(vformat(TTR("Templates installation failed. The problematic templates archives can be found at '%s'."), path));
+ }
}
} break;
}
diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h
index 54a645c69f..bd43fe5dc5 100644
--- a/editor/export_template_manager.h
+++ b/editor/export_template_manager.h
@@ -70,7 +70,7 @@ class ExportTemplateManager : public ConfirmationDialog {
void _uninstall_template_confirm();
virtual void ok_pressed();
- void _install_from_file(const String &p_file, bool p_use_progress = true);
+ bool _install_from_file(const String &p_file, bool p_use_progress = true);
void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data);
void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 1718badbfa..ec1153a015 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -139,41 +139,56 @@ void FileSystemDock::_update_tree(bool keep_collapse_state, bool p_uncollapse_ro
updating_tree = false;
}
-void FileSystemDock::_notification(int p_what) {
+void FileSystemDock::_update_display_mode() {
- switch (p_what) {
+ bool disable_split = bool(EditorSettings::get_singleton()->get("docks/filesystem/disable_split"));
+ bool compact_mode = get_size().height < int(EditorSettings::get_singleton()->get("docks/filesystem/split_mode_minimum_height"));
+ DisplayMode new_mode;
+ if (disable_split || compact_mode) {
+ new_mode = file_list_view ? DISPLAY_FILE_LIST_ONLY : DISPLAY_TREE_ONLY;
+ } else {
+ new_mode = DISPLAY_SPLIT;
+ }
- case NOTIFICATION_RESIZED: {
+ if (new_mode != display_mode) {
+ switch (new_mode) {
+ case DISPLAY_TREE_ONLY:
+ tree->show();
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ _update_tree(true);
- bool new_mode = get_size().height < get_viewport_rect().size.height / 2;
+ file_list_vb->hide();
+ break;
- if (new_mode != low_height_mode) {
+ case DISPLAY_FILE_LIST_ONLY:
+ tree->hide();
+ button_tree->show();
- low_height_mode = new_mode;
+ file_list_vb->show();
+ _update_files(true);
+ break;
- if (low_height_mode) {
+ case DISPLAY_SPLIT:
+ tree->show();
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ button_tree->hide();
+ tree->ensure_cursor_is_visible();
+ _update_tree(true);
- tree->hide();
- tree->set_v_size_flags(SIZE_EXPAND_FILL);
- button_tree->show();
- } else {
+ file_list_vb->show();
+ _update_files(true);
+ break;
+ }
+ display_mode = new_mode;
+ }
+}
- tree->set_v_size_flags(SIZE_FILL);
- button_tree->hide();
- if (!tree->is_visible()) {
- tree->show();
- button_favorite->show();
- _update_tree(true);
- }
- tree->ensure_cursor_is_visible();
+void FileSystemDock::_notification(int p_what) {
- if (!file_list_vb->is_visible()) {
- file_list_vb->show();
- _update_files(true);
- }
- }
- }
+ switch (p_what) {
+ case NOTIFICATION_RESIZED: {
+ _update_display_mode();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -190,13 +205,14 @@ void FileSystemDock::_notification(int p_what) {
//button_instance->set_icon(get_icon("Add", ei));
//button_open->set_icon(get_icon("Folder", ei));
button_tree->set_icon(get_icon("Filesystem", ei));
- _update_file_display_toggle_button();
- button_display_mode->connect("pressed", this, "_change_file_display");
+ _update_file_list_display_mode_button();
+ button_file_list_display_mode->connect("pressed", this, "_change_file_display");
//file_options->set_icon( get_icon("Tools","ei"));
files->connect("item_activated", this, "_select_file");
button_hist_next->connect("pressed", this, "_fw_history");
button_hist_prev->connect("pressed", this, "_bw_history");
- search_box->add_icon_override("right_icon", get_icon("Search", ei));
+ search_box->set_right_icon(get_icon("Search", ei));
+ search_box->set_clear_button_enabled(true);
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
@@ -207,6 +223,8 @@ void FileSystemDock::_notification(int p_what) {
button_tree->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED);
current_path->connect("text_entered", this, "navigate_to_path");
+ _update_display_mode();
+
if (EditorFileSystem::get_singleton()->is_scanning()) {
_set_scanning_mode();
} else {
@@ -240,28 +258,29 @@ void FileSystemDock::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
-
+ // Update icons
String ei = "EditorIcons";
- int new_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"));
-
- //_update_icons
-
button_reload->set_icon(get_icon("Reload", ei));
button_favorite->set_icon(get_icon("Favorites", ei));
button_tree->set_icon(get_icon("Filesystem", ei));
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
- search_box->add_icon_override("right_icon", get_icon("Search", ei));
+ search_box->set_right_icon(get_icon("Search", ei));
+ search_box->set_clear_button_enabled(true);
- if (new_mode != display_mode) {
- set_display_mode(new_mode);
+ // Change size mode
+ int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode"));
+ if (new_file_list_mode != file_list_display_mode) {
+ set_file_list_display_mode(new_file_list_mode);
} else {
- _update_file_display_toggle_button();
+ _update_file_list_display_mode_button();
_update_files(true);
}
- _update_tree(true);
+ // Change full tree mode
+ _update_display_mode();
+
} break;
}
}
@@ -287,7 +306,7 @@ void FileSystemDock::_dir_selected() {
current_path->set_text(path);
_push_to_history();
- if (!low_height_mode) {
+ if (display_mode == DISPLAY_SPLIT) {
_update_files(false);
}
}
@@ -358,7 +377,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
current_path->set_text(path);
_push_to_history();
- if (!low_height_mode) {
+ if (display_mode == DISPLAY_SPLIT) {
_update_tree(true);
_update_files(false);
} else {
@@ -388,24 +407,24 @@ void FileSystemDock::_thumbnail_done(const String &p_path, const Ref<Texture> &p
}
}
-void FileSystemDock::_update_file_display_toggle_button() {
+void FileSystemDock::_update_file_list_display_mode_button() {
- if (button_display_mode->is_pressed()) {
- display_mode = DISPLAY_LIST;
- button_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
- button_display_mode->set_tooltip(TTR("View items as a grid of thumbnails."));
+ if (button_file_list_display_mode->is_pressed()) {
+ file_list_display_mode = FILE_LIST_DISPLAY_LIST;
+ button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
+ button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails."));
} else {
- display_mode = DISPLAY_THUMBNAILS;
- button_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
- button_display_mode->set_tooltip(TTR("View items as a list."));
+ file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
+ button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
+ button_file_list_display_mode->set_tooltip(TTR("View items as a list."));
}
}
void FileSystemDock::_change_file_display() {
- _update_file_display_toggle_button();
+ _update_file_list_display_mode_button();
- EditorSettings::get_singleton()->set("docks/filesystem/display_mode", display_mode);
+ EditorSettings::get_singleton()->set("docks/filesystem/display_mode", file_list_display_mode);
_update_files(true);
}
@@ -470,8 +489,8 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
bool always_show_folders = EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders");
- bool use_thumbnails = (display_mode == DISPLAY_THUMBNAILS);
- bool use_folders = search_box->get_text().length() == 0 && (low_height_mode || always_show_folders);
+ bool use_thumbnails = (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS);
+ bool use_folders = search_box->get_text().length() == 0 && ((display_mode == DISPLAY_FILE_LIST_ONLY || display_mode == DISPLAY_TREE_ONLY) || always_show_folders);
if (use_thumbnails) {
@@ -615,24 +634,28 @@ void FileSystemDock::_select_file(int p_idx) {
}
}
-void FileSystemDock::_go_to_tree() {
+void FileSystemDock::_go_to_file_list() {
- if (low_height_mode) {
- tree->show();
- button_favorite->show();
- file_list_vb->hide();
+ if (display_mode == DISPLAY_TREE_ONLY) {
+ file_list_view = true;
+ _update_display_mode();
+ } else {
+ bool collapsed = tree->get_selected()->is_collapsed();
+ tree->get_selected()->set_collapsed(!collapsed);
+ _update_files(false);
}
+}
+void FileSystemDock::_go_to_tree() {
- _update_tree(true);
+ file_list_view = false;
tree->grab_focus();
+ _update_display_mode();
tree->ensure_cursor_is_visible();
- //button_open->hide();
- //file_options->hide();
}
void FileSystemDock::_preview_invalidated(const String &p_path) {
- if (display_mode == DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) {
+ if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) {
for (int i = 0; i < files->get_item_count(); i++) {
@@ -1408,25 +1431,7 @@ void FileSystemDock::_resource_created() const {
RES current_res = RES(r);
- editor->save_resource_as(current_res);
-}
-
-void FileSystemDock::_go_to_file_list() {
-
- if (low_height_mode) {
- tree->hide();
- file_list_vb->show();
- button_favorite->hide();
- } else {
- bool collapsed = tree->get_selected()->is_collapsed();
- tree->get_selected()->set_collapsed(!collapsed);
- }
-
- //file_options->show();
-
- _update_files(false);
-
- //emit_signal("open",path);
+ editor->save_resource_as(current_res, path);
}
void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) {
@@ -1448,7 +1453,7 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) {
}
folder_options->add_separator();
folder_options->add_item(TTR("New Folder..."), FOLDER_NEW_FOLDER);
- folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER);
+ folder_options->add_item(TTR("Open In File Manager"), FOLDER_SHOW_IN_EXPLORER);
}
folder_options->set_position(tree->get_global_position() + p_pos);
folder_options->popup();
@@ -1472,7 +1477,7 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) {
void FileSystemDock::focus_on_filter() {
- if (low_height_mode && tree->is_visible()) {
+ if (display_mode == DISPLAY_FILE_LIST_ONLY && tree->is_visible()) {
// Tree mode, switch to files list with search box
tree->hide();
file_list_vb->show();
@@ -1482,12 +1487,12 @@ void FileSystemDock::focus_on_filter() {
search_box->grab_focus();
}
-void FileSystemDock::set_display_mode(int p_mode) {
+void FileSystemDock::set_file_list_display_mode(int p_mode) {
- if (p_mode == display_mode)
+ if (p_mode == file_list_display_mode)
return;
- button_display_mode->set_pressed(p_mode == DISPLAY_LIST);
+ button_file_list_display_mode->set_pressed(p_mode == FILE_LIST_DISPLAY_LIST);
_change_file_display();
}
@@ -1757,7 +1762,10 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
- file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
+
+ String fpath = files->get_item_metadata(p_item);
+ String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager");
+ file_options->add_item(item_text, FILE_SHOW_IN_EXPLORER);
file_options->set_position(files->get_global_position() + p_pos);
file_options->popup();
@@ -2025,9 +2033,9 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
search_box->connect("text_changed", this, "_search_changed");
path_hb->add_child(search_box);
- button_display_mode = memnew(ToolButton);
- button_display_mode->set_toggle_mode(true);
- path_hb->add_child(button_display_mode);
+ button_file_list_display_mode = memnew(ToolButton);
+ button_file_list_display_mode->set_toggle_mode(true);
+ path_hb->add_child(button_file_list_display_mode);
files = memnew(ItemList);
files->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -2123,8 +2131,8 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
history_max_size = 20;
history.push_back("res://");
- low_height_mode = false;
- display_mode = DISPLAY_THUMBNAILS;
+ display_mode = DISPLAY_SPLIT;
+ file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
}
FileSystemDock::~FileSystemDock() {
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 6a0c73d52e..fbbe87fc16 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -60,12 +60,18 @@ class FileSystemDock : public VBoxContainer {
GDCLASS(FileSystemDock, VBoxContainer);
public:
- enum DisplayMode {
- DISPLAY_THUMBNAILS,
- DISPLAY_LIST
+ enum FileListDisplayMode {
+ FILE_LIST_DISPLAY_THUMBNAILS,
+ FILE_LIST_DISPLAY_LIST
};
private:
+ enum DisplayMode {
+ DISPLAY_TREE_ONLY,
+ DISPLAY_FILE_LIST_ONLY,
+ DISPLAY_SPLIT,
+ };
+
enum FileMenu {
FILE_OPEN,
FILE_INSTANCE,
@@ -106,7 +112,7 @@ private:
Button *button_reload;
Button *button_favorite;
Button *button_tree;
- Button *button_display_mode;
+ Button *button_file_list_display_mode;
Button *button_hist_next;
Button *button_hist_prev;
Button *button_show;
@@ -115,8 +121,9 @@ private:
TextureRect *search_icon;
HBoxContainer *path_hb;
- bool low_height_mode;
+ FileListDisplayMode file_list_display_mode;
DisplayMode display_mode;
+ bool file_list_view;
PopupMenu *file_options;
PopupMenu *folder_options;
@@ -172,7 +179,7 @@ private:
void _files_gui_input(Ref<InputEvent> p_event);
void _update_files(bool p_keep_selection);
- void _update_file_display_toggle_button();
+ void _update_file_list_display_mode_button();
void _change_file_display();
void _fs_changed();
@@ -245,6 +252,8 @@ private:
void _preview_invalidated(const String &p_path);
void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
+ void _update_display_mode();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -258,7 +267,7 @@ public:
void fix_dependencies(const String &p_for_file);
- void set_display_mode(int p_mode);
+ void set_file_list_display_mode(int p_mode);
int get_split_offset() { return split_box->get_split_offset(); }
void set_split_offset(int p_offset) { split_box->set_split_offset(p_offset); }
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 2be1f1644e..ef7409fd43 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -37,10 +37,10 @@
#include "scene/gui/check_box.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/grid_container.h"
-#include "scene/gui/item_list.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/progress_bar.h"
+#include "scene/gui/tree.h"
#define ROOT_PREFIX "res://"
@@ -58,6 +58,34 @@ static bool is_text_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
+static bool find_next(const String &line, String pattern, int from, bool match_case, bool whole_words, int &out_begin, int &out_end) {
+
+ int end = from;
+
+ while (true) {
+ int begin = match_case ? line.find(pattern, end) : line.findn(pattern, end);
+
+ if (begin == -1)
+ return false;
+
+ end = begin + pattern.length();
+ out_begin = begin;
+ out_end = end;
+
+ if (whole_words) {
+ if (begin > 0 && is_text_char(line[begin - 1])) {
+ continue;
+ }
+ if (end < line.size() && is_text_char(line[end])) {
+ continue;
+ }
+ }
+
+ return true;
+ }
+}
+
+//--------------------------------------------------------------------------------
FindInFiles::FindInFiles() {
_root_prefix = ROOT_PREFIX;
_extension_filter.insert("gd");
@@ -246,24 +274,7 @@ void FindInFiles::_scan_file(String fpath) {
String line = f->get_line();
- // Find all occurrences in the current line
- while (true) {
- begin = _match_case ? line.find(_pattern, end) : line.findn(_pattern, end);
-
- if (begin == -1)
- break;
-
- end = begin + _pattern.length();
-
- if (_whole_words) {
- if (begin > 0 && is_text_char(line[begin - 1])) {
- continue;
- }
- if (end < line.size() && is_text_char(line[end])) {
- continue;
- }
- }
-
+ while (find_next(line, _pattern, end, _match_case, _whole_words, begin, end)) {
emit_signal(SIGNAL_RESULT_FOUND, fpath, line_number, begin, end, line);
}
}
@@ -567,14 +578,18 @@ FindInFilesPanel::FindInFilesPanel() {
vbc->add_child(hbc);
}
- // In the future, this should be replaced by a more specific list container,
- // which can highlight text regions and change opacity for enabled/disabled states
- _results_display = memnew(ItemList);
+ _results_display = memnew(Tree);
_results_display->add_font_override("font", get_font("source", "EditorFonts"));
_results_display->set_v_size_flags(SIZE_EXPAND_FILL);
_results_display->connect("item_selected", this, "_on_result_selected");
+ _results_display->connect("item_edited", this, "_on_item_edited");
+ _results_display->set_hide_root(true);
+ _results_display->set_select_mode(Tree::SELECT_ROW);
+ _results_display->create_item(); // Root
vbc->add_child(_results_display);
+ _with_replace = false;
+
{
_replace_container = memnew(HBoxContainer);
@@ -600,12 +615,33 @@ FindInFilesPanel::FindInFilesPanel() {
void FindInFilesPanel::set_with_replace(bool with_replace) {
+ _with_replace = with_replace;
_replace_container->set_visible(with_replace);
+
+ if (with_replace) {
+ // Results show checkboxes on their left so they can be opted out
+ _results_display->set_columns(2);
+ _results_display->set_column_expand(0, false);
+ _results_display->set_column_min_width(0, 48 * EDSCALE);
+
+ } else {
+ // Results are single-cell items
+ _results_display->set_column_expand(0, true);
+ _results_display->set_columns(1);
+ }
+}
+
+void FindInFilesPanel::clear() {
+ _file_items.clear();
+ _result_items.clear();
+ _results_display->clear();
+ _results_display->create_item(); // Root
}
void FindInFilesPanel::start_search() {
- _results_display->clear();
+ clear();
+
_status_label->set_text(TTR("Searching..."));
_search_text_label->set_text(_finder->get_search_text());
@@ -636,9 +672,90 @@ void FindInFilesPanel::_notification(int p_what) {
void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin, int end, String text) {
- int i = _results_display->get_item_count();
- _results_display->add_item(fpath + ": " + String::num(line_number) + ": " + text.replace("\t", " "));
- _results_display->set_item_metadata(i, varray(fpath, line_number, begin, end));
+ TreeItem *file_item;
+ Map<String, TreeItem *>::Element *E = _file_items.find(fpath);
+
+ if (E == NULL) {
+ file_item = _results_display->create_item();
+ file_item->set_text(0, fpath);
+ file_item->set_metadata(0, fpath);
+
+ // The width of this column is restrained to checkboxes, but that doesn't make sense for the parent items,
+ // so we override their width so they can expand to full width
+ file_item->set_expand_right(0, true);
+
+ _file_items[fpath] = file_item;
+
+ } else {
+ file_item = E->value();
+ }
+
+ int text_index = _with_replace ? 1 : 0;
+
+ TreeItem *item = _results_display->create_item(file_item);
+
+ // Do this first because it resets properties of the cell...
+ item->set_cell_mode(text_index, TreeItem::CELL_MODE_CUSTOM);
+
+ String item_text = String::num_int64(line_number) + ": " + text.replace("\t", " ");
+
+ item->set_text(text_index, item_text);
+ item->set_custom_draw(text_index, this, "_draw_result_text");
+
+ Ref<Font> font = _results_display->get_font("font");
+
+ float raw_text_width = font->get_string_size(text).x;
+ float item_text_width = font->get_string_size(item_text).x;
+
+ Result r;
+ r.line_number = line_number;
+ r.begin = begin;
+ r.end = end;
+ r.draw_begin = (item_text_width - raw_text_width) + font->get_string_size(text.left(r.begin)).x;
+ r.draw_width = font->get_string_size(text.substr(r.begin, r.end - r.begin + 1)).x;
+ _result_items[item] = r;
+
+ if (_with_replace) {
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_checked(0, true);
+ item->set_editable(0, true);
+ }
+}
+
+void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) {
+
+ TreeItem *item = Object::cast_to<TreeItem>(item_obj);
+ if (!item)
+ return;
+
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+ if (!E)
+ return;
+ Result r = E->value();
+
+ Rect2 match_rect = rect;
+ match_rect.position.x += r.draw_begin;
+ match_rect.size.x = r.draw_width;
+ match_rect.position.y += 1 * EDSCALE;
+ match_rect.size.y -= 2 * EDSCALE;
+
+ _results_display->draw_rect(match_rect, Color(0, 0, 0, 0.5));
+ // Text is drawn by Tree already
+}
+
+void FindInFilesPanel::_on_item_edited() {
+
+ TreeItem *item = _results_display->get_selected();
+
+ if (item->is_checked(0)) {
+ item->set_custom_color(1, _results_display->get_color("font_color"));
+
+ } else {
+ // Grey out
+ Color color = _results_display->get_color("font_color");
+ color.a /= 2.0;
+ item->set_custom_color(1, color);
+ }
}
void FindInFilesPanel::_on_finished() {
@@ -653,10 +770,19 @@ void FindInFilesPanel::_on_cancel_button_clicked() {
stop_search();
}
-void FindInFilesPanel::_on_result_selected(int i) {
+void FindInFilesPanel::_on_result_selected() {
+
+ TreeItem *item = _results_display->get_selected();
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+
+ if (E == NULL)
+ return;
+ Result r = E->value();
+
+ TreeItem *file_item = item->get_parent();
+ String fpath = file_item->get_metadata(0);
- Array meta = _results_display->get_item_metadata(i);
- emit_signal(SIGNAL_RESULT_SELECTED, meta[0], meta[1], meta[2], meta[3]);
+ emit_signal(SIGNAL_RESULT_SELECTED, fpath, r.line_number, r.begin, r.end);
}
void FindInFilesPanel::_on_replace_text_changed(String text) {
@@ -668,39 +794,33 @@ void FindInFilesPanel::_on_replace_all_clicked() {
String replace_text = get_replace_text();
ERR_FAIL_COND(replace_text.empty());
- String last_fpath;
- PoolIntArray locations;
PoolStringArray modified_files;
- for (int i = 0; i < _results_display->get_item_count(); ++i) {
+ for (Map<String, TreeItem *>::Element *E = _file_items.front(); E; E = E->next()) {
- Array meta = _results_display->get_item_metadata(i);
+ TreeItem *file_item = E->value();
+ String fpath = file_item->get_metadata(0);
- String fpath = meta[0];
+ Vector<Result> locations;
+ for (TreeItem *item = file_item->get_children(); item; item = item->get_next()) {
- // Results are sorted by file, so we can batch replaces
- if (fpath != last_fpath) {
- if (locations.size() != 0) {
- apply_replaces_in_file(last_fpath, locations, replace_text);
- modified_files.append(last_fpath);
- locations.resize(0);
- }
- }
+ if (!item->is_checked(0))
+ continue;
- locations.append(meta[1]); // line_number
- locations.append(meta[2]); // begin
- locations.append(meta[3]); // end
-
- last_fpath = fpath;
- }
+ Map<TreeItem *, Result>::Element *E = _result_items.find(item);
+ ERR_FAIL_COND(E == NULL);
+ locations.push_back(E->value());
+ }
- if (locations.size() != 0) {
- apply_replaces_in_file(last_fpath, locations, replace_text);
- modified_files.append(last_fpath);
+ if (locations.size() != 0) {
+ // Results are sorted by file, so we can batch replaces
+ apply_replaces_in_file(fpath, locations, replace_text);
+ modified_files.append(fpath);
+ }
}
// Hide replace bar so we can't trigger the action twice without doing a new search
- set_with_replace(false);
+ _replace_container->hide();
emit_signal(SIGNAL_FILES_MODIFIED, modified_files);
}
@@ -740,11 +860,7 @@ private:
Vector<char> _line_buffer;
};
-void FindInFilesPanel::apply_replaces_in_file(String fpath, PoolIntArray locations, String text) {
-
- ERR_FAIL_COND(locations.size() % 3 != 0);
-
- //print_line(String("Replacing {0} occurrences in {1}").format(varray(fpath, locations.size() / 3)));
+void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text) {
// If the file is already open, I assume the editor will reload it.
// If there are unsaved changes, the user will be asked on focus,
@@ -759,21 +875,34 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, PoolIntArray locatio
ConservativeGetLine conservative;
String line = conservative.get_line(f);
+ String search_text = _finder->get_search_text();
+
+ int offset = 0;
- PoolIntArray::Read locations_read = locations.read();
- for (int i = 0; i < locations.size(); i += 3) {
+ for (int i = 0; i < locations.size(); ++i) {
- int repl_line_number = locations_read[i];
- int repl_begin = locations_read[i + 1];
- int repl_end = locations_read[i + 2];
+ int repl_line_number = locations[i].line_number;
while (current_line < repl_line_number) {
buffer += line;
line = conservative.get_line(f);
++current_line;
+ offset = 0;
+ }
+
+ int repl_begin = locations[i].begin + offset;
+ int repl_end = locations[i].end + offset;
+
+ int _;
+ if (!find_next(line, search_text, repl_begin, _finder->is_match_case(), _finder->is_whole_words(), _, _)) {
+ // Make sure the replace is still valid in case the file was tampered with.
+ print_line(String("Occurrence no longer matches, replace will be ignored in {0}: line {1}, col {2}").format(varray(fpath, repl_line_number, repl_begin)));
+ continue;
}
- line = line.left(repl_begin) + text + line.right(repl_end);
+ line = line.left(repl_begin) + new_text + line.right(repl_end);
+ // keep an offset in case there are successive replaces in the same line
+ offset += new_text.length() - (repl_end - repl_begin);
}
buffer += line;
@@ -811,11 +940,13 @@ void FindInFilesPanel::set_progress_visible(bool visible) {
void FindInFilesPanel::_bind_methods() {
ClassDB::bind_method("_on_result_found", &FindInFilesPanel::_on_result_found);
+ ClassDB::bind_method("_on_item_edited", &FindInFilesPanel::_on_item_edited);
ClassDB::bind_method("_on_finished", &FindInFilesPanel::_on_finished);
ClassDB::bind_method("_on_cancel_button_clicked", &FindInFilesPanel::_on_cancel_button_clicked);
ClassDB::bind_method("_on_result_selected", &FindInFilesPanel::_on_result_selected);
ClassDB::bind_method("_on_replace_text_changed", &FindInFilesPanel::_on_replace_text_changed);
ClassDB::bind_method("_on_replace_all_clicked", &FindInFilesPanel::_on_replace_all_clicked);
+ ClassDB::bind_method("_draw_result_text", &FindInFilesPanel::draw_result_text);
ADD_SIGNAL(MethodInfo(SIGNAL_RESULT_SELECTED,
PropertyInfo(Variant::STRING, "path"),
diff --git a/editor/find_in_files.h b/editor/find_in_files.h
index d57184960b..75ea1c3161 100644
--- a/editor/find_in_files.h
+++ b/editor/find_in_files.h
@@ -131,7 +131,8 @@ private:
};
class Button;
-class ItemList;
+class Tree;
+class TreeItem;
class ProgressBar;
// Display search results
@@ -159,22 +160,37 @@ private:
void _on_result_found(String fpath, int line_number, int begin, int end, String text);
void _on_finished();
void _on_cancel_button_clicked();
- void _on_result_selected(int i);
+ void _on_result_selected();
+ void _on_item_edited();
void _on_replace_text_changed(String text);
void _on_replace_all_clicked();
- void apply_replaces_in_file(String fpath, PoolIntArray locations, String text);
+ struct Result {
+ int line_number;
+ int begin;
+ int end;
+ float draw_begin;
+ float draw_width;
+ };
+ void apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text);
void update_replace_buttons();
String get_replace_text();
+
+ void draw_result_text(Object *item_obj, Rect2 rect);
+
void set_progress_visible(bool visible);
+ void clear();
FindInFiles *_finder;
Label *_search_text_label;
- ItemList *_results_display;
+ Tree *_results_display;
Label *_status_label;
Button *_cancel_button;
ProgressBar *_progress_bar;
+ Map<String, TreeItem *> _file_items;
+ Map<TreeItem *, Result> _result_items;
+ bool _with_replace;
HBoxContainer *_replace_container;
LineEdit *_replace_line_edit;
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index 2bfd2eb5c3..0efd14e932 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -287,8 +287,10 @@ void GroupDialog::_notification(int p_what) {
add_button->set_icon(get_icon("Forward", "EditorIcons"));
remove_button->set_icon(get_icon("Back", "EditorIcons"));
- add_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
- remove_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ add_filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ add_filter->set_clear_button_enabled(true);
+ remove_filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ remove_filter->set_clear_button_enabled(true);
} break;
}
}
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 17a9394b51..a2d54e0048 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -198,6 +198,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options,
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/invert_color"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "stream"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "detect_3d"), p_preset == PRESET_DETECT));
@@ -354,6 +355,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
int srgb = p_options["flags/srgb"];
bool fix_alpha_border = p_options["process/fix_alpha_border"];
bool premult_alpha = p_options["process/premult_alpha"];
+ bool invert_color = p_options["process/invert_color"];
bool stream = p_options["stream"];
int size_limit = p_options["size_limit"];
bool force_rgbe = int(p_options["compress/hdr_mode"]) == 1;
@@ -409,6 +411,19 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
image->premultiply_alpha();
}
+ if (invert_color) {
+ int height = image->get_height();
+ int width = image->get_width();
+
+ image->lock();
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ image->set_pixel(i, j, image->get_pixel(i, j).inverted());
+ }
+ }
+ image->unlock();
+ }
+
bool detect_3d = p_options["detect_3d"];
bool detect_srgb = srgb == 2;
bool detect_normal = normal == 0;
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 41f5a892eb..9e99dcc5c8 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -157,15 +157,18 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
//Consider revision for engine version 3.0
compression_code = file->get_16();
if (compression_code != 1 && compression_code != 3) {
- ERR_PRINT("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead.");
- break;
+ file->close();
+ memdelete(file);
+ ERR_EXPLAIN("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead.");
+ ERR_FAIL_V(ERR_INVALID_DATA);
}
format_channels = file->get_16();
if (format_channels != 1 && format_channels != 2) {
-
- ERR_PRINT("Format not supported for WAVE file (not stereo or mono)");
- break;
+ file->close();
+ memdelete(file);
+ ERR_EXPLAIN("Format not supported for WAVE file (not stereo or mono).");
+ ERR_FAIL_V(ERR_INVALID_DATA);
}
format_freq = file->get_32(); //sampling rate
@@ -174,10 +177,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
file->get_16(); // block align (unused)
format_bits = file->get_16(); // bits per sample
- if (format_bits % 8) {
-
- ERR_PRINT("Strange number of bits in sample (not 8,16,24,32)");
- break;
+ if (format_bits % 8 || format_bits == 0) {
+ file->close();
+ memdelete(file);
+ ERR_EXPLAIN("Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32).");
+ ERR_FAIL_V(ERR_INVALID_DATA);
}
/* Don't need anything else, continue */
@@ -185,7 +189,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
}
if (chunkID[0] == 'd' && chunkID[1] == 'a' && chunkID[2] == 't' && chunkID[3] == 'a' && !data_found) {
- /* IS FORMAT CHUNK */
+ /* IS DATA CHUNK */
data_found = true;
if (!format_found) {
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index f91802b352..31eb193461 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -420,10 +420,9 @@ ImportDock::ImportDock() {
preset->get_popup()->connect("index_pressed", this, "_preset_selected");
hb->add_child(preset);
- import_opts = memnew(PropertyEditor);
+ import_opts = memnew(EditorInspector);
add_child(import_opts);
import_opts->set_v_size_flags(SIZE_EXPAND_FILL);
- import_opts->hide_top_label();
hb = memnew(HBoxContainer);
add_child(hb);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index a7a7eda8d8..41c7298d9a 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -31,10 +31,12 @@
#ifndef IMPORTDOCK_H
#define IMPORTDOCK_H
-#include "editor_file_system.h"
-#include "io/resource_import.h"
-#include "property_editor.h"
+#include "core/io/config_file.h"
+#include "core/io/resource_import.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/popup_menu.h"
@@ -45,7 +47,7 @@ class ImportDock : public VBoxContainer {
Label *imported;
OptionButton *import_as;
MenuButton *preset;
- PropertyEditor *import_opts;
+ EditorInspector *import_opts;
List<PropertyInfo> properties;
Map<StringName, Variant> property_values;
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index e65b743bfa..0335053162 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -36,6 +36,16 @@
void InspectorDock::_menu_option(int p_option) {
switch (p_option) {
+ case RESOURCE_MAKE_BUILT_IN: {
+ _unref_resource();
+ } break;
+ case RESOURCE_COPY: {
+ _copy_resource();
+ } break;
+ case RESOURCE_EDIT_CLIPBOARD: {
+ _paste_resource();
+ } break;
+
case RESOURCE_SAVE: {
_save_resource(false);
} break;
@@ -400,10 +410,11 @@ void InspectorDock::update(Object *p_object) {
p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS);
p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS);
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Paste Resource")), RESOURCE_PASTE);
+
+ p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource Clipboard")), RESOURCE_EDIT_CLIPBOARD);
if (is_resource) {
p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY);
- p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_UNREF);
+ p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_MAKE_BUILT_IN);
}
if (is_resource || is_node) {
@@ -529,7 +540,8 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
search = memnew(LineEdit);
search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search->set_placeholder(TTR("Filter properties"));
- search->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search->set_right_icon(get_icon("Search", "EditorIcons"));
+ search->set_clear_button_enabled(true);
add_child(search);
warning = memnew(Button);
diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h
index f347056158..97ef6899dc 100644
--- a/editor/inspector_dock.h
+++ b/editor/inspector_dock.h
@@ -51,13 +51,12 @@ class InspectorDock : public VBoxContainer {
GDCLASS(InspectorDock, VBoxContainer);
enum MenuOptions {
- RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
RESOURCE_SAVE_AS,
- RESOURCE_UNREF,
+ RESOURCE_MAKE_BUILT_IN,
RESOURCE_COPY,
- RESOURCE_PASTE,
+ RESOURCE_EDIT_CLIPBOARD,
OBJECT_COPY_PARAMS,
OBJECT_PASTE_PARAMS,
OBJECT_UNIQUE_RESOURCES,
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
new file mode 100644
index 0000000000..418936ac9f
--- /dev/null
+++ b/editor/plugin_config_dialog.cpp
@@ -0,0 +1,230 @@
+/*************************************************************************/
+/* plugin_config_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "plugin_config_dialog.h"
+#include "core/io/config_file.h"
+#include "core/os/dir_access.h"
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "modules/gdscript/gdscript.h"
+#include "scene/gui/grid_container.h"
+
+void PluginConfigDialog::_clear_fields() {
+ name_edit->set_text("");
+ subfolder_edit->set_text("");
+ desc_edit->set_text("");
+ author_edit->set_text("");
+ version_edit->set_text("");
+ script_edit->set_text("");
+}
+
+void PluginConfigDialog::_on_confirmed() {
+
+ String path = "res://addons/" + subfolder_edit->get_text();
+
+ if (!_edit_mode) {
+ DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (!d || d->make_dir_recursive(path) != OK)
+ return;
+ }
+
+ Ref<ConfigFile> cf = memnew(ConfigFile);
+ cf->set_value("plugin", "name", name_edit->get_text());
+ cf->set_value("plugin", "description", desc_edit->get_text());
+ cf->set_value("plugin", "author", author_edit->get_text());
+ cf->set_value("plugin", "version", version_edit->get_text());
+ cf->set_value("plugin", "script", script_edit->get_text());
+
+ cf->save(path.plus_file("plugin.cfg"));
+
+ if (!_edit_mode) {
+ String type = script_option_edit->get_item_text(script_option_edit->get_selected());
+
+ Ref<Script> script;
+
+ if (type == GDScriptLanguage::get_singleton()->get_name()) {
+ Ref<GDScript> gdscript = memnew(GDScript);
+ gdscript->set_source_code(
+ "tool\n"
+ "extends EditorPlugin\n"
+ "\n"
+ "func _enter_tree():\n"
+ "\tpass");
+ String script_path = path.plus_file(script_edit->get_text());
+ gdscript->set_path(script_path);
+ ResourceSaver::save(script_path, gdscript);
+ script = gdscript;
+ }
+ //TODO: other languages
+
+ emit_signal("plugin_ready", script.operator->(), active_edit->is_pressed() ? name_edit->get_text() : "");
+ } else {
+ EditorNode::get_singleton()->get_project_settings()->update_plugins();
+ }
+ _clear_fields();
+}
+
+void PluginConfigDialog::_on_cancelled() {
+ _clear_fields();
+}
+
+void PluginConfigDialog::_on_required_text_changed(const String &p_text) {
+ String ext = script_option_edit->get_item_metadata(script_option_edit->get_selected());
+ get_ok()->set_disabled(script_edit->get_text().get_basename().empty() || script_edit->get_text().get_extension() != ext || name_edit->get_text().empty());
+}
+
+void PluginConfigDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ connect("confirmed", this, "_on_confirmed");
+ get_cancel()->connect("pressed", this, "_on_cancelled");
+ } break;
+ }
+}
+
+void PluginConfigDialog::config(const String &p_config_path) {
+ if (p_config_path.length()) {
+ Ref<ConfigFile> cf = memnew(ConfigFile);
+ print_line(p_config_path);
+ cf->load(p_config_path);
+
+ name_edit->set_text(cf->get_value("plugin", "name", ""));
+ subfolder_edit->set_text(p_config_path.get_base_dir().get_basename().get_file());
+ desc_edit->set_text(cf->get_value("plugin", "description", ""));
+ author_edit->set_text(cf->get_value("plugin", "author", ""));
+ version_edit->set_text(cf->get_value("plugin", "version", ""));
+ script_edit->set_text(cf->get_value("plugin", "script", ""));
+
+ _edit_mode = true;
+ active_edit->hide();
+ Object::cast_to<Label>(active_edit->get_parent()->get_child(active_edit->get_index() - 1))->hide();
+ subfolder_edit->hide();
+ Object::cast_to<Label>(subfolder_edit->get_parent()->get_child(subfolder_edit->get_index() - 1))->hide();
+ set_title(TTR("Edit a Plugin"));
+ } else {
+ _clear_fields();
+ _edit_mode = false;
+ active_edit->show();
+ Object::cast_to<Label>(active_edit->get_parent()->get_child(active_edit->get_index() - 1))->show();
+ subfolder_edit->show();
+ Object::cast_to<Label>(subfolder_edit->get_parent()->get_child(subfolder_edit->get_index() - 1))->show();
+ set_title(TTR("Create a Plugin"));
+ }
+ get_ok()->set_disabled(!_edit_mode);
+ get_ok()->set_text(_edit_mode ? TTR("Update") : TTR("Create"));
+}
+
+void PluginConfigDialog::_bind_methods() {
+ ClassDB::bind_method("_on_required_text_changed", &PluginConfigDialog::_on_required_text_changed);
+ ClassDB::bind_method("_on_confirmed", &PluginConfigDialog::_on_confirmed);
+ ClassDB::bind_method("_on_cancelled", &PluginConfigDialog::_on_cancelled);
+ ADD_SIGNAL(MethodInfo("plugin_ready", PropertyInfo(Variant::STRING, "script_path", PROPERTY_HINT_NONE, ""), PropertyInfo(Variant::STRING, "activate_name")));
+}
+
+PluginConfigDialog::PluginConfigDialog() {
+ get_ok()->set_disabled(true);
+ set_hide_on_ok(true);
+
+ GridContainer *grid = memnew(GridContainer);
+ grid->set_columns(2);
+ add_child(grid);
+
+ Label *name_lb = memnew(Label);
+ name_lb->set_text(TTR("Plugin Name:"));
+ grid->add_child(name_lb);
+
+ name_edit = memnew(LineEdit);
+ name_edit->connect("text_changed", this, "_on_required_text_changed");
+ name_edit->set_placeholder("MyPlugin");
+ grid->add_child(name_edit);
+
+ Label *subfolder_lb = memnew(Label);
+ subfolder_lb->set_text(TTR("Subfolder:"));
+ grid->add_child(subfolder_lb);
+
+ subfolder_edit = memnew(LineEdit);
+ subfolder_edit->set_placeholder("\"my_plugin\" -> res://addons/my_plugin");
+ grid->add_child(subfolder_edit);
+
+ Label *desc_lb = memnew(Label);
+ desc_lb->set_text(TTR("Description:"));
+ grid->add_child(desc_lb);
+
+ desc_edit = memnew(TextEdit);
+ desc_edit->set_custom_minimum_size(Size2(400.0f, 50.0f));
+ grid->add_child(desc_edit);
+
+ Label *author_lb = memnew(Label);
+ author_lb->set_text(TTR("Author:"));
+ grid->add_child(author_lb);
+
+ author_edit = memnew(LineEdit);
+ author_edit->set_placeholder("Godette");
+ grid->add_child(author_edit);
+
+ Label *version_lb = memnew(Label);
+ version_lb->set_text(TTR("Version:"));
+ grid->add_child(version_lb);
+
+ version_edit = memnew(LineEdit);
+ version_edit->set_placeholder("1.0");
+ grid->add_child(version_edit);
+
+ Label *script_option_lb = memnew(Label);
+ script_option_lb->set_text(TTR("Language:"));
+ grid->add_child(script_option_lb);
+
+ script_option_edit = memnew(OptionButton);
+ script_option_edit->add_item(GDScriptLanguage::get_singleton()->get_name());
+ script_option_edit->set_item_metadata(0, GDScriptLanguage::get_singleton()->get_extension());
+ script_option_edit->select(0);
+ //TODO: add other languages
+ grid->add_child(script_option_edit);
+
+ Label *script_lb = memnew(Label);
+ script_lb->set_text(TTR("Script Name:"));
+ grid->add_child(script_lb);
+
+ script_edit = memnew(LineEdit);
+ script_edit->connect("text_changed", this, "_on_required_text_changed");
+ script_edit->set_placeholder("\"plugin.gd\" -> res://addons/my_plugin/plugin.gd");
+ grid->add_child(script_edit);
+
+ Label *active_lb = memnew(Label);
+ active_lb->set_text(TTR("Activate now?"));
+ grid->add_child(active_lb);
+
+ active_edit = memnew(CheckBox);
+ active_edit->set_pressed(true);
+ grid->add_child(active_edit);
+}
+
+PluginConfigDialog::~PluginConfigDialog() {
+}
diff --git a/editor/plugin_config_dialog.h b/editor/plugin_config_dialog.h
new file mode 100644
index 0000000000..2d321a479d
--- /dev/null
+++ b/editor/plugin_config_dialog.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* plugin_config_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PLUGIN_CONFIG_DIALOG_H
+#define PLUGIN_CONFIG_DIALOG_H
+
+#include "scene/gui/check_box.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/text_edit.h"
+
+class PluginConfigDialog : public ConfirmationDialog {
+
+ GDCLASS(PluginConfigDialog, ConfirmationDialog);
+
+ LineEdit *name_edit;
+ LineEdit *subfolder_edit;
+ TextEdit *desc_edit;
+ LineEdit *author_edit;
+ LineEdit *version_edit;
+ OptionButton *script_option_edit;
+ LineEdit *script_edit;
+ CheckBox *active_edit;
+
+ bool _edit_mode;
+
+ void _clear_fields();
+ void _on_confirmed();
+ void _on_cancelled();
+ void _on_required_text_changed(const String &p_text);
+
+protected:
+ virtual void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void config(const String &p_plugin_dir_name);
+
+ PluginConfigDialog();
+ ~PluginConfigDialog();
+};
+
+#endif // PLUGIN_CONFIG_DIALOG_H
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 2e128db883..1106464edf 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -3,41 +3,11 @@
#include "os/keyboard.h"
#include "scene/animation/animation_blend_tree.h"
-void AnimationNodeBlendSpace1DEditorPlugin::edit(Object *p_object) {
- anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace1D>(p_object));
+StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
+ StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position";
+ return path;
}
-bool AnimationNodeBlendSpace1DEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("AnimationNodeBlendSpace1D");
-}
-
-void AnimationNodeBlendSpace1DEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- button->show();
- editor->make_bottom_panel_item_visible(anim_tree_editor);
- anim_tree_editor->set_process(true);
- } else {
- if (anim_tree_editor->is_visible_in_tree()) {
- editor->hide_bottom_panel();
- }
-
- button->hide();
- anim_tree_editor->set_process(false);
- }
-}
-
-AnimationNodeBlendSpace1DEditorPlugin::AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- anim_tree_editor = memnew(AnimationNodeBlendSpace1DEditor);
- anim_tree_editor->set_custom_minimum_size(Size2(0, 150 * EDSCALE));
-
- button = editor->add_bottom_panel_item(TTR("BlendSpace1D"), anim_tree_editor);
- button->hide();
-}
-
-AnimationNodeBlendSpace1DEditorPlugin::~AnimationNodeBlendSpace1DEditorPlugin() {
-}
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
@@ -62,7 +32,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = blend_space->get_tree();
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp->has_node(gp->get_animation_player())) {
@@ -85,10 +55,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
continue;
int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name));
+ menu->add_item(vformat("Add %s", name),idx);
menu->set_item_metadata(idx, E->get());
}
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
+ menu->add_separator();
+ menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
+
menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
@@ -158,7 +136,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
- blend_space->set_blend_pos(blend_pos);
+ AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
blend_space_draw->update();
}
@@ -181,7 +159,8 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
- blend_space->set_blend_pos(blend_pos);
+ AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
+
blend_space_draw->update();
}
}
@@ -277,7 +256,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
color.a *= 0.5;
}
- float point = blend_space->get_blend_pos();
+ float point = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
+
+
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s.width;
@@ -299,12 +280,6 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
updating = true;
- if (blend_space->get_parent().is_valid()) {
- goto_parent_hb->show();
- } else {
- goto_parent_hb->hide();
- }
-
max_value->set_value(blend_space->get_max_space());
min_value->set_value(blend_space->get_min_space());
@@ -355,15 +330,47 @@ void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
blend_space_draw->update();
}
+void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
+
+ file_loaded = ResourceLoader::load(p_file);
+ if (file_loaded.is_valid()) {
+ _add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ }
+}
+
void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
- String type = menu->get_item_metadata(p_index);
+ Ref<AnimationRootNode> node;
+ if (p_index == MENU_LOAD_FILE) {
+
+ open_file->clear_filters();
+ List<String> filters;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
+ for (List<String>::Element *E = filters.front(); E; E = E->next()) {
+ open_file->add_filter("*." + E->get());
+ }
+ open_file->popup_centered_ratio();
+ return;
+ } else if (p_index == MENU_LOAD_FILE_CONFIRM) {
+ node = file_loaded;
+ file_loaded.unref();
+ } else if (p_index == MENU_PASTE) {
+
+ node = EditorSettings::get_singleton()->get_resource_clipboard();
+ } else {
+ String type = menu->get_item_metadata(p_index);
- Object *obj = ClassDB::instance(type);
- ERR_FAIL_COND(!obj);
- AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ Object *obj = ClassDB::instance(type);
+ ERR_FAIL_COND(!obj);
+ AnimationNode *an = Object::cast_to<AnimationNode>(obj);
+ ERR_FAIL_COND(!an);
- Ref<AnimationNode> node(an);
+ node = Ref<AnimationNode>(an);
+ }
+
+ if (!node.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
+ return;
+ }
updating = true;
undo_redo->create_action("Add Node Point");
@@ -438,7 +445,7 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
- if (EditorNode::get_singleton()->item_has_editor(an.ptr())) {
+ if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
open_editor->show();
} else {
open_editor->hide();
@@ -490,17 +497,11 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() {
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
ERR_FAIL_COND(an.is_null());
- EditorNode::get_singleton()->edit_item(an.ptr());
+ AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
}
}
-void AnimationNodeBlendSpace1DEditor::_goto_parent() {
- EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr());
-}
-void AnimationNodeBlendSpace1DEditor::_removed_from_graph() {
- EditorNode::get_singleton()->edit_item(NULL);
-}
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
@@ -513,18 +514,16 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
open_editor->set_icon(get_icon("Edit", "EditorIcons"));
- goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
+
}
if (p_what == NOTIFICATION_PROCESS) {
String error;
- if (!blend_space->get_tree()) {
- error = TTR("BlendSpace1D does not belong to an AnimationTree node.");
- } else if (!blend_space->get_tree()->is_active()) {
+ if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (blend_space->get_tree()->is_state_invalid()) {
- error = blend_space->get_tree()->get_invalid_state_reason();
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
}
if (error != error_label->get_text()) {
@@ -536,6 +535,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
}
}
}
+
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+ set_process(is_visible_in_tree());
+ }
}
void AnimationNodeBlendSpace1DEditor::_bind_methods() {
@@ -556,28 +559,26 @@ void AnimationNodeBlendSpace1DEditor::_bind_methods() {
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);
ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor);
- ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace1DEditor::_goto_parent);
- ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace1DEditor::_removed_from_graph);
+ ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace1DEditor::_file_opened);
+
+
+
}
-void AnimationNodeBlendSpace1DEditor::edit(AnimationNodeBlendSpace1D *p_blend_space) {
+bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {
- if (blend_space.is_valid()) {
- blend_space->disconnect("removed_from_graph", this, "_removed_from_graph");
- }
+ Ref<AnimationNodeBlendSpace1D> b1d=p_node;
+ return b1d.is_valid();
+}
- if (p_blend_space) {
- blend_space = Ref<AnimationNodeBlendSpace1D>(p_blend_space);
- } else {
- blend_space.unref();
- }
+void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
- if (blend_space.is_null()) {
- hide();
- } else {
- blend_space->connect("removed_from_graph", this, "_removed_from_graph");
+
+ blend_space=p_node;
+
+ if (!blend_space.is_null()) {
_update_space();
}
}
@@ -594,14 +595,6 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
- goto_parent_hb = memnew(HBoxContainer);
- top_hb->add_child(goto_parent_hb);
-
- goto_parent = memnew(ToolButton);
- goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
- goto_parent_hb->add_child(goto_parent);
- goto_parent_hb->add_child(memnew(VSeparator));
- goto_parent_hb->hide();
tool_blend = memnew(ToolButton);
tool_blend->set_toggle_mode(true);
@@ -726,13 +719,20 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
menu = memnew(PopupMenu);
add_child(menu);
- menu->connect("index_pressed", this, "_add_menu_type");
+ menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", this, "_add_animation_type");
+ open_file = memnew(EditorFileDialog);
+ add_child(open_file);
+ open_file->set_title(TTR("Open Animation Node"));
+ open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->connect("file_selected", this, "_file_opened");
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
selected_point = -1;
dragging_selected = false;
dragging_selected_attempt = false;
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 52139626e6..f040f6dcab 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -9,10 +9,11 @@
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+#include "editor/plugins/animation_tree_editor_plugin.h"
-class AnimationNodeBlendSpace1DEditor : public VBoxContainer {
+class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
- GDCLASS(AnimationNodeBlendSpace1DEditor, VBoxContainer)
+ GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin)
Ref<AnimationNodeBlendSpace1D> blend_space;
@@ -81,7 +82,17 @@ class AnimationNodeBlendSpace1DEditor : public VBoxContainer {
void _goto_parent();
- void _removed_from_graph();
+ EditorFileDialog *open_file;
+ Ref<AnimationNode> file_loaded;
+ void _file_opened(const String &p_file);
+
+ enum {
+ MENU_LOAD_FILE = 1000,
+ MENU_PASTE = 1001,
+ MENU_LOAD_FILE_CONFIRM = 1002
+ };
+
+ StringName get_blend_position_path() const;
protected:
void _notification(int p_what);
@@ -89,29 +100,9 @@ protected:
public:
static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; }
- void edit(AnimationNodeBlendSpace1D *p_blend_space);
+ virtual bool can_edit(const Ref<AnimationNode> &p_node);
+ virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeBlendSpace1DEditor();
};
-class AnimationNodeBlendSpace1DEditorPlugin : public EditorPlugin {
-
- GDCLASS(AnimationNodeBlendSpace1DEditorPlugin, EditorPlugin)
-
- AnimationNodeBlendSpace1DEditor *anim_tree_editor;
- EditorNode *editor;
- Button *button;
-
-public:
- virtual String get_name() const { return "BlendSpace1D"; }
-
- bool has_main_screen() const { return false; }
-
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node);
- ~AnimationNodeBlendSpace1DEditorPlugin();
-};
-
#endif // ANIMATION_BLEND_SPACE_1D_EDITOR_H
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 27df60f87a..e008971e5c 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -11,27 +11,26 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
-void AnimationNodeBlendSpace2DEditor::edit(AnimationNodeBlendSpace2D *p_blend_space) {
+bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) {
- if (blend_space.is_valid()) {
- blend_space->disconnect("removed_from_graph", this, "_removed_from_graph");
- }
+ Ref<AnimationNodeBlendSpace2D> bs2d=p_node;
+ return bs2d.is_valid();
+}
- if (p_blend_space) {
- blend_space = Ref<AnimationNodeBlendSpace2D>(p_blend_space);
- } else {
- blend_space.unref();
- }
+void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
- if (blend_space.is_null()) {
- hide();
- } else {
- blend_space->connect("removed_from_graph", this, "_removed_from_graph");
+ blend_space = p_node;
+ if (!blend_space.is_null()) {
_update_space();
}
}
+StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
+ StringName path = AnimationTreeEditor::get_singleton()->get_base_path()+"blend_position";
+ return path;
+}
+
void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
@@ -54,7 +53,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = blend_space->get_tree();
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp && gp->has_node(gp->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
@@ -74,10 +73,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (name == "Animation")
continue; // nope
int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name));
+ menu->add_item(vformat("Add %s", name),idx);
menu->set_item_metadata(idx, E->get());
}
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
+ menu->add_separator();
+ menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
+
+
menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size());
@@ -203,7 +211,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
blend_pos += blend_space->get_min_space();
- blend_space->set_blend_position(blend_pos);
+ AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
+
blend_space_draw->update();
}
@@ -237,21 +246,54 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
blend_pos += blend_space->get_min_space();
- blend_space->set_blend_position(blend_pos);
+ AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(),blend_pos);
+
blend_space_draw->update();
}
}
+void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
+
+ file_loaded = ResourceLoader::load(p_file);
+ if (file_loaded.is_valid()) {
+ _add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ }
+}
+
void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
- String type = menu->get_item_metadata(p_index);
+ Ref<AnimationRootNode> node;
+ if (p_index == MENU_LOAD_FILE) {
+
+ open_file->clear_filters();
+ List<String> filters;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
+ for (List<String>::Element *E = filters.front(); E; E = E->next()) {
+ open_file->add_filter("*." + E->get());
+ }
+ open_file->popup_centered_ratio();
+ return;
+ } else if (p_index == MENU_LOAD_FILE_CONFIRM) {
+ node = file_loaded;
+ file_loaded.unref();
+ } else if (p_index == MENU_PASTE) {
+
+ node = EditorSettings::get_singleton()->get_resource_clipboard();
+ } else {
+ String type = menu->get_item_metadata(p_index);
+
+ Object *obj = ClassDB::instance(type);
+ ERR_FAIL_COND(!obj);
+ AnimationNode *an = Object::cast_to<AnimationNode>(obj);
+ ERR_FAIL_COND(!an);
- Object *obj = ClassDB::instance(type);
- ERR_FAIL_COND(!obj);
- AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ node = Ref<AnimationNode>(an);
+ }
- Ref<AnimationNode> node(an);
+ if (!node.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
+ return;
+ }
updating = true;
undo_redo->create_action("Add Node Point");
@@ -288,7 +330,7 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
- if (EditorNode::get_singleton()->item_has_editor(an.ptr())) {
+ if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
open_editor->show();
} else {
open_editor->hide();
@@ -490,13 +532,15 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
color.a *= 0.5;
}
- Vector2 point = blend_space->get_blend_position();
+ Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
+ Vector2 point = blend_pos;
+
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s;
point.y = s.height - point.y;
if (blend_space->get_triangle_count()) {
- Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_position());
+ Vector2 closest = blend_space->get_closest_point(blend_pos);
closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
closest *= s;
closest.y = s.height - closest.y;
@@ -527,12 +571,6 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
updating = true;
- if (blend_space->get_parent().is_valid()) {
- goto_parent_hb->show();
- } else {
- goto_parent_hb->hide();
- }
-
if (blend_space->get_auto_triangles()) {
tool_triangle->hide();
} else {
@@ -685,7 +723,6 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
open_editor->set_icon(get_icon("Edit", "EditorIcons"));
- goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons"));
}
@@ -693,12 +730,12 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
String error;
- if (!blend_space->get_tree()) {
+ if (!AnimationTreeEditor::get_singleton()->get_tree()) {
error = TTR("BlendSpace2D does not belong to an AnimationTree node.");
- } else if (!blend_space->get_tree()->is_active()) {
+ } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (blend_space->get_tree()->is_state_invalid()) {
- error = blend_space->get_tree()->get_invalid_state_reason();
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
} else if (blend_space->get_triangle_count() == 0) {
error = TTR("No triangles exist, so no blending can take place.");
}
@@ -712,22 +749,22 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
}
}
}
+
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+ set_process(is_visible_in_tree());
+ }
}
+
void AnimationNodeBlendSpace2DEditor::_open_editor() {
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
- ERR_FAIL_COND(!an.is_valid());
- EditorNode::get_singleton()->edit_item(an.ptr());
+ ERR_FAIL_COND(an.is_null());
+ AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
}
}
-void AnimationNodeBlendSpace2DEditor::_goto_parent() {
-
- EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr());
-}
-
void AnimationNodeBlendSpace2DEditor::_removed_from_graph() {
EditorNode::get_singleton()->edit_item(NULL);
}
@@ -761,11 +798,13 @@ void AnimationNodeBlendSpace2DEditor::_bind_methods() {
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos);
ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor);
- ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace2DEditor::_goto_parent);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph);
ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled);
+
+ ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace2DEditor::_file_opened);
+
}
AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL;
@@ -781,14 +820,6 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
Ref<ButtonGroup> bg;
bg.instance();
- goto_parent_hb = memnew(HBoxContainer);
- top_hb->add_child(goto_parent_hb);
- goto_parent = memnew(ToolButton);
- goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
- goto_parent_hb->add_child(goto_parent);
- goto_parent_hb->add_child(memnew(VSeparator));
- goto_parent_hb->hide();
-
tool_blend = memnew(ToolButton);
tool_blend->set_toggle_mode(true);
tool_blend->set_button_group(bg);
@@ -968,13 +999,20 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
menu = memnew(PopupMenu);
add_child(menu);
- menu->connect("index_pressed", this, "_add_menu_type");
+ menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("animations");
animations_menu->connect("index_pressed", this, "_add_animation_type");
+ open_file = memnew(EditorFileDialog);
+ add_child(open_file);
+ open_file->set_title(TTR("Open Animation Node"));
+ open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->connect("file_selected", this, "_file_opened");
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
selected_point = -1;
selected_triangle = -1;
@@ -982,42 +1020,3 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
dragging_selected_attempt = false;
}
-void AnimationNodeBlendSpace2DEditorPlugin::edit(Object *p_object) {
-
- anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace2D>(p_object));
-}
-
-bool AnimationNodeBlendSpace2DEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("AnimationNodeBlendSpace2D");
-}
-
-void AnimationNodeBlendSpace2DEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- //editor->hide_animation_player_editors();
- //editor->animation_panel_make_visible(true);
- button->show();
- editor->make_bottom_panel_item_visible(anim_tree_editor);
- anim_tree_editor->set_process(true);
- } else {
-
- if (anim_tree_editor->is_visible_in_tree())
- editor->hide_bottom_panel();
- button->hide();
- anim_tree_editor->set_process(false);
- }
-}
-
-AnimationNodeBlendSpace2DEditorPlugin::AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- anim_tree_editor = memnew(AnimationNodeBlendSpace2DEditor);
- anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
-
- button = editor->add_bottom_panel_item(TTR("BlendSpace2D"), anim_tree_editor);
- button->hide();
-}
-
-AnimationNodeBlendSpace2DEditorPlugin::~AnimationNodeBlendSpace2DEditorPlugin() {
-}
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index a0e497804e..ae684985f3 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -9,18 +9,17 @@
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+#include "editor/plugins/animation_tree_editor_plugin.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-class AnimationNodeBlendSpace2DEditor : public VBoxContainer {
+class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
- GDCLASS(AnimationNodeBlendSpace2DEditor, VBoxContainer);
+ GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
- HBoxContainer *goto_parent_hb;
- ToolButton *goto_parent;
PanelContainer *panel;
ToolButton *tool_blend;
@@ -93,38 +92,32 @@ class AnimationNodeBlendSpace2DEditor : public VBoxContainer {
void _edit_point_pos(double);
void _open_editor();
- void _goto_parent();
-
void _removed_from_graph();
void _auto_triangles_toggled();
+ StringName get_blend_position_path() const;
+
+ EditorFileDialog *open_file;
+ Ref<AnimationNode> file_loaded;
+ void _file_opened(const String &p_file);
+
+ enum {
+ MENU_LOAD_FILE = 1000,
+ MENU_PASTE = 1001,
+ MENU_LOAD_FILE_CONFIRM = 1002
+ };
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; }
- void edit(AnimationNodeBlendSpace2D *p_blend_space);
+ virtual bool can_edit(const Ref<AnimationNode> &p_node);
+ virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeBlendSpace2DEditor();
};
-class AnimationNodeBlendSpace2DEditorPlugin : public EditorPlugin {
- GDCLASS(AnimationNodeBlendSpace2DEditorPlugin, EditorPlugin);
-
- AnimationNodeBlendSpace2DEditor *anim_tree_editor;
- EditorNode *editor;
- Button *button;
-
-public:
- virtual String get_name() const { return "BlendSpace2D"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node);
- ~AnimationNodeBlendSpace2DEditorPlugin();
-};
#endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index c00ad451fa..42e32b9788 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -2,6 +2,7 @@
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
+#include "editor/editor_inspector.h"
#include "os/input.h"
#include "os/keyboard.h"
#include "scene/animation/animation_player.h"
@@ -9,27 +10,6 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
-void AnimationNodeBlendTreeEditor::edit(AnimationNodeBlendTree *p_blend_tree) {
-
- if (blend_tree.is_valid()) {
- blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph");
- }
-
- if (p_blend_tree) {
- blend_tree = Ref<AnimationNodeBlendTree>(p_blend_tree);
- } else {
- blend_tree.unref();
- }
-
- if (blend_tree.is_null()) {
- hide();
- } else {
- blend_tree->connect("removed_from_graph", this, "_removed_from_graph");
-
- _update_graph();
- }
-}
-
void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) {
for (int i = 0; i < add_options.size(); i++) {
@@ -58,10 +38,19 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
void AnimationNodeBlendTreeEditor::_update_options_menu() {
+ print_line("update options");
add_node->get_popup()->clear();
for (int i = 0; i < add_options.size(); i++) {
- add_node->get_popup()->add_item(add_options[i].name);
+ add_node->get_popup()->add_item(add_options[i].name, i);
}
+
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ add_node->get_popup()->add_separator();
+ add_node->get_popup()->add_item(TTR("Paste"), MENU_PASTE);
+ }
+ add_node->get_popup()->add_separator();
+ add_node->get_popup()->add_item(TTR("Load.."), MENU_LOAD_FILE);
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@@ -69,18 +58,28 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
return Size2(10, 200);
}
+void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value) {
+
+ AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree();
+ updating = true;
+ undo_redo->create_action("Parameter Changed: " + String(p_property), UndoRedo::MERGE_ENDS);
+ undo_redo->add_do_property(tree, p_property, p_value);
+ undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+ updating = false;
+}
+
void AnimationNodeBlendTreeEditor::_update_graph() {
if (updating)
return;
+ visible_properties.clear();
+
graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE);
- if (blend_tree->get_parent().is_valid()) {
- goto_parent->show();
- } else {
- goto_parent->hide();
- }
graph->clear_connections();
//erase all nodes
for (int i = 0; i < graph->get_child_count(); i++) {
@@ -107,7 +106,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED);
}
- node->set_offset(agnode->get_position() * EDSCALE);
+ node->set_offset(blend_tree->get_node_position(E->get()) * EDSCALE);
node->set_title(agnode->get_caption());
node->set_name(E->get());
@@ -133,9 +132,28 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color());
}
- node->connect("dragged", this, "_node_dragged", varray(agnode));
+ List<PropertyInfo> pinfo;
+ agnode->get_parameter_list(&pinfo);
+ for (List<PropertyInfo>::Element *F = pinfo.front(); F; F = F->next()) {
+
+ if (!(F->get().usage & PROPERTY_USAGE_EDITOR)) {
+ continue;
+ }
+ String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E->get()) + "/" + F->get().name;
+ EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F->get().type, base_path, F->get().hint, F->get().hint_string, F->get().usage);
+ if (prop) {
+ prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
+ prop->update_property();
+ prop->set_name_split_ratio(0);
+ prop->connect("property_changed", this, "_property_changed");
+ node->add_child(prop);
+ visible_properties.push_back(prop);
+ }
+ }
+
+ node->connect("dragged", this, "_node_dragged", varray(E->get()));
- if (EditorNode::get_singleton()->item_has_editor(agnode.ptr())) {
+ if (AnimationTreeEditor::get_singleton()->can_edit(agnode)) {
node->add_child(memnew(HSeparator));
Button *open_in_editor = memnew(Button);
open_in_editor->set_text(TTR("Open Editor"));
@@ -169,7 +187,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
ProgressBar *pb = memnew(ProgressBar);
- AnimationTree *player = anim->get_tree();
+ AnimationTree *player = AnimationTreeEditor::get_singleton()->get_tree();
if (player->has_node(player->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player()));
if (ap) {
@@ -194,6 +212,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED);
}
+ /* should be no longer necesary, as the boolean works
Ref<AnimationNodeOneShot> oneshot = agnode;
if (oneshot.is_valid()) {
@@ -209,7 +228,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
play_stop->add_child(stop);
play_stop->add_spacer();
node->add_child(play_stop);
- }
+ } */
}
List<AnimationNodeBlendTree::NodeConnection> connections;
@@ -225,16 +244,44 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
}
}
-void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
+void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) {
- ERR_FAIL_INDEX(p_idx, add_options.size());
+ file_loaded = ResourceLoader::load(p_file);
+ if (file_loaded.is_valid()) {
+ _add_node(MENU_LOAD_FILE_CONFIRM);
+ }
+}
+
+void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
Ref<AnimationNode> anode;
- if (add_options[p_idx].type != String()) {
+ String base_name;
+
+ if (p_idx == MENU_LOAD_FILE) {
+
+ open_file->clear_filters();
+ List<String> filters;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &filters);
+ for (List<String>::Element *E = filters.front(); E; E = E->next()) {
+ open_file->add_filter("*." + E->get());
+ }
+ open_file->popup_centered_ratio();
+ return;
+ } else if (p_idx == MENU_LOAD_FILE_CONFIRM) {
+ anode = file_loaded;
+ file_loaded.unref();
+ base_name = anode->get_class();
+ } else if (p_idx == MENU_PASTE) {
+
+ anode = EditorSettings::get_singleton()->get_resource_clipboard();
+ ERR_FAIL_COND(!anode.is_valid());
+ base_name = anode->get_class();
+ } else if (add_options[p_idx].type != String()) {
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type));
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
+ base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
String base_type = add_options[p_idx].script->get_instance_base_type();
@@ -242,13 +289,16 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
ERR_FAIL_COND(!an);
anode = Ref<AnimationNode>(an);
anode->set_script(add_options[p_idx].script.get_ref_ptr());
+ base_name = add_options[p_idx].name;
}
+ Ref<AnimationNodeOutput> out = anode;
+ if (out.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree."));
+ return;
+ }
Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5;
- anode->set_position(instance_pos / EDSCALE);
-
- String base_name = add_options[p_idx].name;
int base = 1;
String name = base_name;
while (blend_tree->has_node(name)) {
@@ -257,19 +307,19 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
}
undo_redo->create_action("Add Node to BlendTree");
- undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode);
+ undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
}
-void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node) {
+void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) {
updating = true;
undo_redo->create_action("Node Moved");
- undo_redo->add_do_method(p_node.ptr(), "set_position", p_to / EDSCALE);
- undo_redo->add_undo_method(p_node.ptr(), "set_position", p_from / EDSCALE);
+ undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
+ undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -342,20 +392,6 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
-void AnimationNodeBlendTreeEditor::_oneshot_start(const StringName &p_name) {
-
- Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name);
- ERR_FAIL_COND(!os.is_valid());
- os->start();
-}
-
-void AnimationNodeBlendTreeEditor::_oneshot_stop(const StringName &p_name) {
-
- Ref<AnimationNodeOneShot> os = blend_tree->get_node(p_name);
- ERR_FAIL_COND(!os.is_valid());
- os->stop();
-}
-
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
@@ -373,13 +409,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) {
Ref<AnimationNode> an = blend_tree->get_node(p_which);
ERR_FAIL_COND(!an.is_valid())
- EditorNode::get_singleton()->edit_item(an.ptr());
-}
-
-void AnimationNodeBlendTreeEditor::_open_parent() {
- if (blend_tree->get_parent().is_valid()) {
- EditorNode::get_singleton()->edit_item(blend_tree->get_parent().ptr());
- }
+ AnimationTreeEditor::get_singleton()->enter_editor(p_which);
}
void AnimationNodeBlendTreeEditor::_filter_toggled() {
@@ -417,14 +447,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
if (updating || _filter_edit != anode)
return false;
- NodePath player_path = anode->get_tree()->get_animation_player();
+ NodePath player_path = AnimationTreeEditor::get_singleton()->get_tree()->get_animation_player();
- if (!anode->get_tree()->has_node(player_path)) {
+ if (!AnimationTreeEditor::get_singleton()->get_tree()->has_node(player_path)) {
EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names."));
return false;
}
- AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_tree()->get_node(player_path));
+ AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_tree()->get_node(player_path));
if (!player) {
EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names."));
return false;
@@ -593,8 +623,6 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
-
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
}
@@ -603,12 +631,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
String error;
- if (!blend_tree->get_tree()) {
- error = TTR("BlendTree does not belong to an AnimationTree node.");
- } else if (!blend_tree->get_tree()->is_active()) {
+ if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (blend_tree->get_tree()->is_state_invalid()) {
- error = blend_tree->get_tree()->get_invalid_state_reason();
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
}
if (error != error_label->get_text()) {
@@ -624,13 +650,13 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
blend_tree->get_node_connections(&conns);
for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = conns.front(); E; E = E->next()) {
float activity = 0;
- if (blend_tree->get_tree() && !blend_tree->get_tree()->is_state_invalid()) {
+ if (AnimationTreeEditor::get_singleton()->get_tree() && !AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
activity = blend_tree->get_connection_activity(E->get().input_node, E->get().input_index);
}
graph->set_connection_activity(E->get().output_node, 0, E->get().input_node, E->get().input_index, activity);
}
- AnimationTree *graph_player = blend_tree->get_tree();
+ AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree();
AnimationPlayer *player = NULL;
if (graph_player->has_node(graph_player->get_animation_player())) {
player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player()));
@@ -650,6 +676,14 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
}
}
+
+ for (int i = 0; i < visible_properties.size(); i++) {
+ visible_properties[i]->update_property();
+ }
+ }
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ set_process(is_visible_in_tree());
}
}
@@ -664,9 +698,9 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
void AnimationNodeBlendTreeEditor::_node_changed(ObjectID p_node) {
AnimationNode *an = Object::cast_to<AnimationNode>(ObjectDB::get_instance(p_node));
- if (an && an->get_parent() == blend_tree) {
- _update_graph();
- }
+ //if (an && an->get_parent() == blend_tree) {
+ _update_graph();
+ //}
}
void AnimationNodeBlendTreeEditor::_bind_methods() {
@@ -680,17 +714,17 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_disconnection_request", &AnimationNodeBlendTreeEditor::_disconnection_request);
ClassDB::bind_method("_node_selected", &AnimationNodeBlendTreeEditor::_node_selected);
ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor);
- ClassDB::bind_method("_open_parent", &AnimationNodeBlendTreeEditor::_open_parent);
ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed);
ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request);
ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited);
ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled);
- ClassDB::bind_method("_oneshot_start", &AnimationNodeBlendTreeEditor::_oneshot_start);
- ClassDB::bind_method("_oneshot_stop", &AnimationNodeBlendTreeEditor::_oneshot_stop);
ClassDB::bind_method("_node_changed", &AnimationNodeBlendTreeEditor::_node_changed);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph);
+ ClassDB::bind_method("_property_changed", &AnimationNodeBlendTreeEditor::_property_changed);
+ ClassDB::bind_method("_file_opened", &AnimationNodeBlendTreeEditor::_file_opened);
+ ClassDB::bind_method("_update_options_menu", &AnimationNodeBlendTreeEditor::_update_options_menu);
ClassDB::bind_method("_anim_selected", &AnimationNodeBlendTreeEditor::_anim_selected);
}
@@ -708,7 +742,9 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1)
- ERR_FAIL_COND(new_name == prev_name);
+ if (new_name == prev_name) {
+ return; //nothing to do
+ }
String base_name = new_name;
int base = 1;
@@ -718,22 +754,61 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
name = base_name + " " + itos(base);
}
+ String base_path = AnimationTreeEditor::get_singleton()->get_base_path();
+
updating = true;
undo_redo->create_action("Node Renamed");
undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
+ undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name);
+ undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
updating = false;
gn->set_name(new_name);
gn->set_size(gn->get_minimum_size());
+
+ //change editors accordingly
+ for (int i = 0; i < visible_properties.size(); i++) {
+ String pname = visible_properties[i]->get_edited_property().operator String();
+ if (pname.begins_with(base_path + prev_name)) {
+ String new_name = pname.replace_first(base_path + prev_name, base_path + name);
+ visible_properties[i]->set_object_and_property(visible_properties[i]->get_edited_object(), new_name);
+ }
+ }
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
_node_renamed(le->call("get_text"), p_node);
}
+bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
+ Ref<AnimationNodeBlendTree> bt = p_node;
+ return bt.is_valid();
+}
+
+void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
+
+ if (blend_tree.is_valid()) {
+ blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph");
+ }
+
+ if (p_node.is_valid()) {
+ blend_tree = p_node;
+ } else {
+ blend_tree.unref();
+ }
+
+ if (blend_tree.is_null()) {
+ hide();
+ } else {
+ blend_tree->connect("removed_from_graph", this, "_removed_from_graph");
+
+ _update_graph();
+ }
+}
+
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
@@ -757,13 +832,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->get_zoom_hbox()->add_child(add_node);
add_node->set_text(TTR("Add Node.."));
graph->get_zoom_hbox()->move_child(add_node, 0);
- add_node->get_popup()->connect("index_pressed", this, "_add_node");
-
- goto_parent = memnew(Button);
- graph->get_zoom_hbox()->add_child(goto_parent);
- graph->get_zoom_hbox()->move_child(goto_parent, 0);
- goto_parent->hide();
- goto_parent->connect("pressed", this, "_open_parent");
+ add_node->get_popup()->connect("id_pressed", this, "_add_node");
+ add_node->connect("about_to_show", this, "_update_options_menu");
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot"));
@@ -804,45 +874,10 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
filters->set_hide_root(true);
filters->connect("item_edited", this, "_filter_edited");
+ open_file = memnew(EditorFileDialog);
+ add_child(open_file);
+ open_file->set_title(TTR("Open Animation Node"));
+ open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->connect("file_selected", this, "_file_opened");
undo_redo = EditorNode::get_singleton()->get_undo_redo();
}
-
-void AnimationNodeBlendTreeEditorPlugin::edit(Object *p_object) {
-
- anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendTree>(p_object));
-}
-
-bool AnimationNodeBlendTreeEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("AnimationNodeBlendTree");
-}
-
-void AnimationNodeBlendTreeEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- //editor->hide_animation_player_editors();
- //editor->animation_panel_make_visible(true);
- button->show();
- editor->make_bottom_panel_item_visible(anim_tree_editor);
- anim_tree_editor->set_process(true);
- } else {
-
- if (anim_tree_editor->is_visible_in_tree())
- editor->hide_bottom_panel();
- button->hide();
- anim_tree_editor->set_process(false);
- }
-}
-
-AnimationNodeBlendTreeEditorPlugin::AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- anim_tree_editor = memnew(AnimationNodeBlendTreeEditor);
- anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
-
- button = editor->add_bottom_panel_item(TTR("BlendTree"), anim_tree_editor);
- button->hide();
-}
-
-AnimationNodeBlendTreeEditorPlugin::~AnimationNodeBlendTreeEditorPlugin() {
-}
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index deba3b2b0e..35ecc32979 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -3,6 +3,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
@@ -13,14 +14,13 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
-class AnimationNodeBlendTreeEditor : public VBoxContainer {
+class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
- GDCLASS(AnimationNodeBlendTreeEditor, VBoxContainer);
+ GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
GraphEdit *graph;
MenuButton *add_node;
- Button *goto_parent;
PanelContainer *error_panel;
Label *error_label;
@@ -32,6 +32,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
CheckBox *filter_enabled;
Map<StringName, ProgressBar *> animations;
+ Vector<EditorProperty *> visible_properties;
void _update_graph();
@@ -52,7 +53,7 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
static AnimationNodeBlendTreeEditor *singleton;
- void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, Ref<AnimationNode> p_node);
+ void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node);
@@ -64,11 +65,8 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
void _scroll_changed(const Vector2 &p_scroll);
void _node_selected(Object *p_node);
void _open_in_editor(const String &p_which);
- void _open_parent();
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
- void _oneshot_start(const StringName &p_name);
- void _oneshot_stop(const StringName &p_name);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
@@ -78,8 +76,19 @@ class AnimationNodeBlendTreeEditor : public VBoxContainer {
void _node_changed(ObjectID p_node);
+ void _property_changed(const StringName &p_property, const Variant &p_value);
void _removed_from_graph();
+ EditorFileDialog *open_file;
+ Ref<AnimationNode> file_loaded;
+ void _file_opened(const String &p_file);
+
+ enum {
+ MENU_LOAD_FILE = 1000,
+ MENU_PASTE = 1001,
+ MENU_LOAD_FILE_CONFIRM = 1002
+ };
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -91,27 +100,11 @@ public:
void remove_custom_type(const Ref<Script> &p_script);
virtual Size2 get_minimum_size() const;
- void edit(AnimationNodeBlendTree *p_blend_tree);
- AnimationNodeBlendTreeEditor();
-};
-class AnimationNodeBlendTreeEditorPlugin : public EditorPlugin {
+ virtual bool can_edit(const Ref<AnimationNode> &p_node);
+ virtual void edit(const Ref<AnimationNode> &p_node);
- GDCLASS(AnimationNodeBlendTreeEditorPlugin, EditorPlugin);
-
- AnimationNodeBlendTreeEditor *anim_tree_editor;
- EditorNode *editor;
- Button *button;
-
-public:
- virtual String get_name() const { return "BlendTree"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- AnimationNodeBlendTreeEditorPlugin(EditorNode *p_node);
- ~AnimationNodeBlendTreeEditorPlugin();
+ AnimationNodeBlendTreeEditor();
};
#endif // ANIMATION_BLEND_TREE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index ee450333c8..3a65cb9b38 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -11,22 +11,17 @@
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
-void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_machine) {
+bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
- if (state_machine.is_valid()) {
- state_machine->disconnect("removed_from_graph", this, "_removed_from_graph");
- }
+ Ref<AnimationNodeStateMachine> ansm = p_node;
+ return ansm.is_valid();
+}
- if (p_state_machine) {
- state_machine = Ref<AnimationNodeStateMachine>(p_state_machine);
- } else {
- state_machine.unref();
- }
+void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
- if (state_machine.is_null()) {
- hide();
- } else {
- state_machine->connect("removed_from_graph", this, "_removed_from_graph");
+ state_machine = p_node;
+
+ if (state_machine.is_valid()) {
selected_transition_from = StringName();
selected_transition_to = StringName();
@@ -38,6 +33,10 @@ void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_ma
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
+ Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+ if (playback.is_null())
+ return;
+
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
@@ -59,7 +58,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = state_machine->get_tree();
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
ERR_FAIL_COND(!gp);
if (gp && gp->has_node(gp->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
@@ -79,9 +78,17 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (name == "Animation")
continue; // nope
int idx = menu->get_item_count();
- menu->add_item(vformat("Add %s", name));
+ menu->add_item(vformat("Add %s", name), idx);
menu->set_item_metadata(idx, E->get());
}
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
+ menu->add_separator();
+ menu->add_item(TTR("Load.."), MENU_LOAD_FILE);
menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position()));
menu->popup();
@@ -98,18 +105,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].play.has_point(mb->get_position())) { //edit name
- if (play_mode->get_selected() == 1 || !state_machine->is_playing()) {
+ if (play_mode->get_selected() == 1 || !playback->is_playing()) {
//start
- state_machine->start(node_rects[i].node_name);
+ playback->start(node_rects[i].node_name);
} else {
//travel
- if (!state_machine->travel(node_rects[i].node_name)) {
-
- state_machine->start(node_rects[i].node_name);
- //removing this due to usability..
- //error_time = 5;
- //error_text = vformat(TTR("No path found from '%s' to '%s'."), state_machine->get_current_node(), node_rects[i].node_name);
- }
+ playback->travel(node_rects[i].node_name);
}
state_machine_draw->update();
return;
@@ -196,8 +197,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
undo_redo->create_action("Move Node");
- undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE);
- undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position());
+ undo_redo->add_do_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE);
+ undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node));
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
@@ -293,7 +294,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
snap_y = StringName();
{
//snap
- Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE;
+ Vector2 cpos = state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE;
List<StringName> nodes;
state_machine->get_node_list(&nodes);
@@ -303,7 +304,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
if (E->get() == selected_node)
continue;
- Vector2 npos = state_machine->get_node(E->get())->get_position();
+ Vector2 npos = state_machine->get_node_position(E->get());
float d_x = ABS(npos.x - cpos.x);
if (d_x < MIN(5, best_d_x)) {
@@ -372,19 +373,58 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
}
+void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) {
+
+ file_loaded = ResourceLoader::load(p_file);
+ if (file_loaded.is_valid()) {
+ _add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ }
+}
+
void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
- String type = menu->get_item_metadata(p_index);
+ String base_name;
+ Ref<AnimationRootNode> node;
- Object *obj = ClassDB::instance(type);
- ERR_FAIL_COND(!obj);
- AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ if (p_index == MENU_LOAD_FILE) {
- Ref<AnimationNode> node(an);
- node->set_position(add_node_pos);
+ open_file->clear_filters();
+ List<String> filters;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
+ for (List<String>::Element *E = filters.front(); E; E = E->next()) {
+ open_file->add_filter("*." + E->get());
+ }
+ open_file->popup_centered_ratio();
+ return;
+ } else if (p_index == MENU_LOAD_FILE_CONFIRM) {
+ node = file_loaded;
+ file_loaded.unref();
+ } else if (p_index == MENU_PASTE) {
+
+ node = EditorSettings::get_singleton()->get_resource_clipboard();
+
+ } else {
+ String type = menu->get_item_metadata(p_index);
+
+ Object *obj = ClassDB::instance(type);
+ ERR_FAIL_COND(!obj);
+ AnimationNode *an = Object::cast_to<AnimationNode>(obj);
+ ERR_FAIL_COND(!an);
+
+ node = Ref<AnimationNode>(an);
+ base_name = type.replace_first("AnimationNode", "");
+ }
+
+ if (!node.is_valid()) {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
+ return;
+ }
+
+ if (base_name == String()) {
+
+ base_name = node->get_class().replace_first("AnimationNode", "");
+ }
- String base_name = type.replace_first("AnimationNode", "");
int base = 1;
String name = base_name;
while (state_machine->has_node(name)) {
@@ -394,7 +434,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
updating = true;
undo_redo->create_action("Add Node");
- undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node);
+ undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@@ -419,11 +459,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
name = base_name + " " + itos(base);
}
- anim->set_position(add_node_pos);
-
updating = true;
undo_redo->create_action("Add Node");
- undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim);
+ undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
@@ -502,6 +540,8 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Ve
void AnimationNodeStateMachineEditor::_state_machine_draw() {
+ Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+
Ref<StyleBox> style = get_stylebox("frame", "GraphNode");
Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode");
@@ -515,10 +555,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
linecolor.a *= 0.3;
Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode");
- bool playing = state_machine->is_playing();
- StringName current = state_machine->get_current_node();
- StringName blend_from = state_machine->get_blend_from_node();
- Vector<StringName> travel_path = state_machine->get_travel_path();
+ bool playing = false;
+ StringName current;
+ StringName blend_from;
+ Vector<StringName> travel_path;
+
+ if (playback.is_valid()) {
+ playing = playback->is_playing();
+ current = playback->get_current_node();
+ blend_from = playback->get_blend_from_node();
+ travel_path = playback->get_travel_path();
+ }
if (state_machine_draw->has_focus()) {
state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false);
@@ -534,13 +581,13 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//snap lines
if (dragging_selected) {
- Vector2 from = (state_machine->get_node(selected_node)->get_position() * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE;
+ Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE;
if (snap_x != StringName()) {
- Vector2 to = (state_machine->get_node(snap_x)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
+ Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
state_machine_draw->draw_line(from, to, linecolor, 2);
}
if (snap_y != StringName()) {
- Vector2 to = (state_machine->get_node(snap_y)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
+ Vector2 to = (state_machine->get_node_position(snap_y) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
state_machine_draw->draw_line(from, to, linecolor, 2);
}
}
@@ -563,7 +610,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
Vector2 offset;
- offset += anode->get_position() * EDSCALE;
+ offset += state_machine->get_node_position(E->get()) * EDSCALE;
if (selected_node == E->get() && dragging_selected) {
offset += drag_ofs;
}
@@ -588,10 +635,10 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
//draw conecting line for potential new transition
if (connecting) {
- Vector2 from = (state_machine->get_node(connecting_from)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
+ Vector2 from = (state_machine->get_node_position(connecting_from) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
Vector2 to;
if (connecting_to_node != StringName()) {
- to = (state_machine->get_node(connecting_to_node)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
+ to = (state_machine->get_node_position(connecting_to_node) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
} else {
to = connecting_to;
}
@@ -617,15 +664,17 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
TransitionLine tl;
tl.from_node = state_machine->get_transition_from(i);
Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2();
- tl.from = (state_machine->get_node(tl.from_node)->get_position() * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
+ tl.from = (state_machine->get_node_position(tl.from_node) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
tl.to_node = state_machine->get_transition_to(i);
Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2();
- tl.to = (state_machine->get_node(tl.to_node)->get_position() * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
+ tl.to = (state_machine->get_node_position(tl.to_node) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
tl.disabled = tr->is_disabled();
tl.auto_advance = tr->has_auto_advance();
+ tl.advance_condition_name = tr->get_advance_condition_name();
+ tl.advance_condition_state = false;
tl.mode = tr->get_switch_mode();
tl.width = tr_bidi_offset;
@@ -665,7 +714,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
}
- _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, tl.auto_advance);
+
+ bool auto_advance = tl.auto_advance;
+ StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name);
+ if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(fullpath))) {
+ tl.advance_condition_state = true;
+ auto_advance = true;
+ }
+ _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, auto_advance);
transition_lines.push_back(tl);
}
@@ -675,7 +731,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
String name = node_rects[i].node_name;
Ref<AnimationNode> anode = state_machine->get_node(name);
- bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr());
+ bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
Ref<StyleBox> sb = name == selected_node ? style_selected : style;
int strsize = font->get_string_size(name).width;
@@ -757,12 +813,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
- if (!state_machine->is_playing())
+ Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+
+ if (!playback.is_valid() || !playback->is_playing())
return;
int idx = -1;
for (int i = 0; node_rects.size(); i++) {
- if (node_rects[i].node_name == state_machine->get_current_node()) {
+ if (node_rects[i].node_name == playback->get_current_node()) {
idx = i;
break;
}
@@ -785,9 +843,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
}
to.y = from.y;
- float len = MAX(0.0001, state_machine->get_current_length());
+ float len = MAX(0.0001, playback->get_current_length());
- float pos = CLAMP(state_machine->get_current_play_pos(), 0, len);
+ float pos = CLAMP(playback->get_current_play_pos(), 0, len);
float c = pos / len;
Color fg = get_color("font_color", "Label");
Color bg = fg;
@@ -807,12 +865,6 @@ void AnimationNodeStateMachineEditor::_update_graph() {
updating = true;
- if (state_machine->get_parent().is_valid()) {
- goto_parent_hbox->show();
- } else {
- goto_parent_hbox->hide();
- }
-
state_machine_draw->update();
updating = false;
@@ -824,7 +876,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
error_label->add_color_override("font_color", get_color("error_color", "Editor"));
panel->add_style_override("panel", get_stylebox("bg", "Tree"));
- goto_parent->set_icon(get_icon("MoveUp", "EditorIcons"));
tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons"));
@@ -856,19 +907,21 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
String error;
+ Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+
if (error_time > 0) {
error = error_text;
error_time -= get_process_delta_time();
- } else if (!state_machine->get_tree()) {
- error = TTR("StateMachine does not belong to an AnimationTree node.");
- } else if (!state_machine->get_tree()->is_active()) {
+ } else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
- } else if (state_machine->get_tree()->is_state_invalid()) {
- error = state_machine->get_tree()->get_invalid_state_reason();
- } else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
+ } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
+ error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
+ /*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) {
error = TTR("Start and end nodes are needed for a sub-transition.");
- }
+ }*/
+ } else if (playback.is_null()) {
+ error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
}
if (error != error_label->get_text()) {
@@ -904,14 +957,38 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
break;
}
+ if (transition_lines[i].advance_condition_name != state_machine->get_transition(tidx)->get_advance_condition_name()) {
+ state_machine_draw->update();
+ break;
+ }
+
if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) {
state_machine_draw->update();
break;
}
+
+ bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name)));
+
+ if (transition_lines[i].advance_condition_state != acstate) {
+ state_machine_draw->update();
+ break;
+ }
}
bool same_travel_path = true;
- Vector<StringName> tp = state_machine->get_travel_path();
+ Vector<StringName> tp;
+ bool is_playing = false;
+ StringName current_node;
+ StringName blend_from_node;
+ float play_pos = 0;
+
+ if (playback.is_valid()) {
+ tp = playback->get_travel_path();
+ is_playing = playback->is_playing();
+ current_node = playback->get_current_node();
+ blend_from_node = playback->get_blend_from_node();
+ play_pos = playback->get_current_play_pos();
+ }
{
@@ -928,37 +1005,32 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
//update if travel state changed
- if (!same_travel_path || last_active != state_machine->is_playing() || last_current_node != state_machine->get_current_node() || last_blend_from_node != state_machine->get_blend_from_node()) {
+ if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
state_machine_draw->update();
last_travel_path = tp;
- last_current_node = state_machine->get_current_node();
- last_active = state_machine->is_playing();
- last_blend_from_node = state_machine->get_blend_from_node();
+ last_current_node = current_node;
+ last_active = is_playing;
+ last_blend_from_node = blend_from_node;
state_machine_play_pos->update();
}
- if (last_play_pos != state_machine->get_current_play_pos()) {
+ if (last_play_pos != play_pos) {
- last_play_pos = state_machine->get_current_play_pos();
+ last_play_pos = play_pos;
state_machine_play_pos->update();
}
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
over_node = StringName();
+ set_process(is_visible_in_tree());
}
}
void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) {
- Ref<AnimationNode> an = state_machine->get_node(p_name);
- ERR_FAIL_COND(!an.is_valid());
- EditorNode::get_singleton()->edit_item(an.ptr());
-}
-
-void AnimationNodeStateMachineEditor::_goto_parent() {
- EditorNode::get_singleton()->edit_item(state_machine->get_parent().ptr());
+ AnimationTreeEditor::get_singleton()->enter_editor(p_name);
}
void AnimationNodeStateMachineEditor::_removed_from_graph() {
@@ -1114,7 +1186,6 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_name_edited", &AnimationNodeStateMachineEditor::_name_edited);
- ClassDB::bind_method("_goto_parent", &AnimationNodeStateMachineEditor::_goto_parent);
ClassDB::bind_method("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph);
ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor);
@@ -1124,6 +1195,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected);
ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected);
ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode);
+ ClassDB::bind_method("_file_opened", &AnimationNodeStateMachineEditor::_file_opened);
}
AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL;
@@ -1136,13 +1208,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
HBoxContainer *top_hb = memnew(HBoxContainer);
add_child(top_hb);
- goto_parent_hbox = memnew(HBoxContainer);
- goto_parent = memnew(ToolButton);
- goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED);
- goto_parent_hbox->add_child(goto_parent);
- goto_parent_hbox->add_child(memnew(VSeparator));
- top_hb->add_child(goto_parent_hbox);
-
Ref<ButtonGroup> bg;
bg.instance();
@@ -1248,7 +1313,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
menu = memnew(PopupMenu);
add_child(menu);
- menu->connect("index_pressed", this, "_add_menu_type");
+ menu->connect("id_pressed", this, "_add_menu_type");
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
@@ -1261,6 +1326,13 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
name_edit->connect("text_entered", this, "_name_edited");
name_edit->set_as_toplevel(true);
+ open_file = memnew(EditorFileDialog);
+ add_child(open_file);
+ open_file->set_title(TTR("Open Animation Node"));
+ open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ open_file->connect("file_selected", this, "_file_opened");
+ undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
over_text = false;
over_node_what = -1;
@@ -1271,43 +1343,3 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
error_time = 0;
}
-
-void AnimationNodeStateMachineEditorPlugin::edit(Object *p_object) {
-
- anim_tree_editor->edit(Object::cast_to<AnimationNodeStateMachine>(p_object));
-}
-
-bool AnimationNodeStateMachineEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_class("AnimationNodeStateMachine");
-}
-
-void AnimationNodeStateMachineEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- //editor->hide_animation_player_editors();
- //editor->animation_panel_make_visible(true);
- button->show();
- editor->make_bottom_panel_item_visible(anim_tree_editor);
- anim_tree_editor->set_process(true);
- } else {
-
- if (anim_tree_editor->is_visible_in_tree())
- editor->hide_bottom_panel();
- button->hide();
- anim_tree_editor->set_process(false);
- }
-}
-
-AnimationNodeStateMachineEditorPlugin::AnimationNodeStateMachineEditorPlugin(EditorNode *p_node) {
-
- editor = p_node;
- anim_tree_editor = memnew(AnimationNodeStateMachineEditor);
- anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
-
- button = editor->add_bottom_panel_item(TTR("StateMachine"), anim_tree_editor);
- button->hide();
-}
-
-AnimationNodeStateMachineEditorPlugin::~AnimationNodeStateMachineEditorPlugin() {
-}
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index efd3de7415..49d08607cf 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -3,6 +3,7 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/property_editor.h"
#include "scene/animation/animation_node_state_machine.h"
#include "scene/gui/button.h"
@@ -10,9 +11,9 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
-class AnimationNodeStateMachineEditor : public VBoxContainer {
+class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
- GDCLASS(AnimationNodeStateMachineEditor, VBoxContainer);
+ GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
@@ -29,9 +30,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
OptionButton *transition_mode;
OptionButton *play_mode;
- HBoxContainer *goto_parent_hbox;
- ToolButton *goto_parent;
-
PanelContainer *panel;
StringName selected_node;
@@ -79,8 +77,6 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
- void _goto_parent();
-
void _removed_from_graph();
struct NodeRect {
@@ -99,6 +95,8 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
Vector2 from;
Vector2 to;
AnimationNodeStateMachineTransition::SwitchMode mode;
+ StringName advance_condition_name;
+ bool advance_condition_state;
bool disabled;
bool auto_advance;
float width;
@@ -135,33 +133,25 @@ class AnimationNodeStateMachineEditor : public VBoxContainer {
float error_time;
String error_text;
+ EditorFileDialog *open_file;
+ Ref<AnimationNode> file_loaded;
+ void _file_opened(const String &p_file);
+
+ enum {
+ MENU_LOAD_FILE = 1000,
+ MENU_PASTE = 1001,
+ MENU_LOAD_FILE_CONFIRM = 1002
+ };
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeStateMachineEditor *get_singleton() { return singleton; }
- void edit(AnimationNodeStateMachine *p_state_machine);
+ virtual bool can_edit(const Ref<AnimationNode> &p_node);
+ virtual void edit(const Ref<AnimationNode> &p_node);
AnimationNodeStateMachineEditor();
};
-class AnimationNodeStateMachineEditorPlugin : public EditorPlugin {
-
- GDCLASS(AnimationNodeStateMachineEditorPlugin, EditorPlugin);
-
- AnimationNodeStateMachineEditor *anim_tree_editor;
- EditorNode *editor;
- Button *button;
-
-public:
- virtual String get_name() const { return "StateMachine"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
-
- AnimationNodeStateMachineEditorPlugin(EditorNode *p_node);
- ~AnimationNodeStateMachineEditorPlugin();
-};
-
#endif // ANIMATION_STATE_MACHINE_EDITOR_H
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index 25582ae0b9..19921ef54f 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -1,1418 +1,247 @@
-/*************************************************************************/
-/* animation_tree_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
#include "animation_tree_editor_plugin.h"
+#include "animation_blend_space_1d_editor.h"
+#include "animation_blend_space_2d_editor.h"
+#include "animation_blend_tree_editor_plugin.h"
+#include "animation_state_machine_editor.h"
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
+#include "math/delaunay.h"
#include "os/input.h"
#include "os/keyboard.h"
+#include "scene/animation/animation_blend_tree.h"
+#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/main/viewport.h"
+#include "scene/scene_string_names.h"
-void AnimationTreeEditor::edit(AnimationTreePlayer *p_anim_tree) {
+void AnimationTreeEditor::edit(AnimationTree *p_tree) {
- anim_tree = p_anim_tree;
+ if (tree == p_tree)
+ return;
- if (!anim_tree) {
- hide();
- } else {
- order.clear();
- p_anim_tree->get_node_list(&order);
- /*
- for(List<StringName>::Element* E=order.front();E;E=E->next()) {
+ tree = p_tree;
- if (E->get() >= (int)last_id)
- last_id=E->get()+1;
- }*/
- play_button->set_pressed(p_anim_tree->is_active());
- //read the orders
+ Vector<String> path;
+ if (tree->has_meta("_tree_edit_path")) {
+ path = tree->get_meta("_tree_edit_path");
+ edit_path(path);
+ } else {
+ current_root = 0;
}
}
-Size2 AnimationTreeEditor::_get_maximum_size() {
-
- Size2 max;
-
- for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
+void AnimationTreeEditor::_path_button_pressed(int p_path) {
- Point2 pos = anim_tree->node_get_position(E->get());
-
- if (click_type == CLICK_NODE && click_node == E->get()) {
+ Ref<AnimationNode> node = tree->get_tree_root();
+ if (node.is_null())
+ return;
- pos += click_motion - click_pos;
+ edited_path.clear();
+ if (p_path >= 0) {
+ for (int i = 0; i <= p_path; i++) {
+ Ref<AnimationNode> child = node->get_child_by_name(button_path[i]);
+ ERR_BREAK(child.is_null());
+ node = child;
+ edited_path.push_back(button_path[i]);
}
- pos += get_node_size(E->get());
- if (pos.x > max.x)
- max.x = pos.x;
- if (pos.y > max.y)
- max.y = pos.y;
}
- return max;
-}
-
-const char *AnimationTreeEditor::_node_type_names[] = { "Output", "Animation", "OneShot", "Mix", "Blend2", "Blend3", "Blend4", "TimeScale", "TimeSeek", "Transition" };
-
-Size2 AnimationTreeEditor::get_node_size(const StringName &p_node) const {
-
- AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
-
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- Ref<Font> font = get_font("font", "PopupMenu");
-
- Size2 size = style->get_minimum_size();
-
- int count = 2; // title and name
- int inputs = anim_tree->node_get_input_count(p_node);
- count += inputs ? inputs : 1;
- String name = p_node;
-
- float name_w = font->get_string_size(name).width;
- float type_w = font->get_string_size(String(_node_type_names[type])).width;
- float max_w = MAX(name_w, type_w);
-
- switch (type) {
- case AnimationTreePlayer::NODE_TIMESEEK:
- case AnimationTreePlayer::NODE_OUTPUT: {
- } break;
- case AnimationTreePlayer::NODE_ANIMATION:
- case AnimationTreePlayer::NODE_ONESHOT:
- case AnimationTreePlayer::NODE_MIX:
- case AnimationTreePlayer::NODE_BLEND2:
- case AnimationTreePlayer::NODE_BLEND3:
- case AnimationTreePlayer::NODE_BLEND4:
- case AnimationTreePlayer::NODE_TIMESCALE:
- case AnimationTreePlayer::NODE_TRANSITION: {
-
- size.height += font->get_height();
- } break;
- case AnimationTreePlayer::NODE_MAX: {
+ for (int i = 0; i < editors.size(); i++) {
+ if (editors[i]->can_edit(node)) {
+ editors[i]->edit(node);
+ editors[i]->show();
+ } else {
+ editors[i]->edit(Ref<AnimationNode>());
+ editors[i]->hide();
}
}
-
- size.x += max_w + 20;
- size.y += count * (font->get_height() + get_constant("vseparation", "PopupMenu"));
-
- return size;
}
-void AnimationTreeEditor::_edit_dialog_changede(String) {
-
- edit_dialog->hide();
-}
-
-void AnimationTreeEditor::_edit_dialog_changeds(String s) {
-
- _edit_dialog_changed();
-}
-
-void AnimationTreeEditor::_edit_dialog_changedf(float) {
-
- _edit_dialog_changed();
-}
-
-void AnimationTreeEditor::_edit_dialog_changed() {
-
- if (updating_edit)
- return;
-
- if (renaming_edit) {
-
- if (anim_tree->node_rename(edited_node, edit_line[0]->get_text()) == OK) {
- for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
-
- if (E->get() == edited_node)
- E->get() = edit_line[0]->get_text();
- }
- edited_node = edit_line[0]->get_text();
- }
- update();
- return;
+void AnimationTreeEditor::_update_path() {
+ while (path_hb->get_child_count()) {
+ memdelete(path_hb->get_child(0));
}
- AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
-
- switch (type) {
-
- case AnimationTreePlayer::NODE_TIMESCALE:
- anim_tree->timescale_node_set_scale(edited_node, edit_line[0]->get_text().to_double());
- break;
- case AnimationTreePlayer::NODE_ONESHOT:
- anim_tree->oneshot_node_set_fadein_time(edited_node, edit_line[0]->get_text().to_double());
- anim_tree->oneshot_node_set_fadeout_time(edited_node, edit_line[1]->get_text().to_double());
- anim_tree->oneshot_node_set_autorestart_delay(edited_node, edit_line[2]->get_text().to_double());
- anim_tree->oneshot_node_set_autorestart_random_delay(edited_node, edit_line[3]->get_text().to_double());
- anim_tree->oneshot_node_set_autorestart(edited_node, edit_check->is_pressed());
- anim_tree->oneshot_node_set_mix_mode(edited_node, edit_option->get_selected());
-
- break;
-
- case AnimationTreePlayer::NODE_MIX:
-
- anim_tree->mix_node_set_amount(edited_node, edit_scroll[0]->get_value());
- break;
- case AnimationTreePlayer::NODE_BLEND2:
- anim_tree->blend2_node_set_amount(edited_node, edit_scroll[0]->get_value());
-
- break;
-
- case AnimationTreePlayer::NODE_BLEND3:
- anim_tree->blend3_node_set_amount(edited_node, edit_scroll[0]->get_value());
-
- break;
- case AnimationTreePlayer::NODE_BLEND4:
-
- anim_tree->blend4_node_set_amount(edited_node, Point2(edit_scroll[0]->get_value(), edit_scroll[1]->get_value()));
-
- break;
-
- case AnimationTreePlayer::NODE_TRANSITION: {
- anim_tree->transition_node_set_xfade_time(edited_node, edit_line[0]->get_text().to_double());
- if (anim_tree->transition_node_get_current(edited_node) != edit_option->get_selected())
- anim_tree->transition_node_set_current(edited_node, edit_option->get_selected());
- } break;
- default: {}
- }
-}
-
-void AnimationTreeEditor::_edit_dialog_animation_changed() {
-
- Ref<Animation> anim = property_editor->get_variant().operator RefPtr();
- anim_tree->animation_node_set_animation(edited_node, anim);
- update();
-}
-
-void AnimationTreeEditor::_edit_dialog_edit_animation() {
-
- if (Engine::get_singleton()->is_editor_hint()) {
- get_tree()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr());
- };
-};
-
-void AnimationTreeEditor::_edit_oneshot_start() {
-
- anim_tree->oneshot_node_start(edited_node);
-}
-
-void AnimationTreeEditor::_play_toggled() {
-
- anim_tree->set_active(play_button->is_pressed());
-}
-
-void AnimationTreeEditor::_master_anim_menu_item(int p_item) {
-
- if (p_item == 0)
- _edit_filters();
- else {
-
- String str = master_anim_popup->get_item_text(p_item);
- anim_tree->animation_node_set_master_animation(edited_node, str);
+ Ref<ButtonGroup> group;
+ group.instance();
+
+ Button *b = memnew(Button);
+ b->set_text("root");
+ b->set_toggle_mode(true);
+ b->set_button_group(group);
+ b->set_pressed(true);
+ b->set_focus_mode(FOCUS_NONE);
+ b->connect("pressed", this, "_path_button_pressed", varray(-1));
+ path_hb->add_child(b);
+ for (int i = 0; i < button_path.size(); i++) {
+ b = memnew(Button);
+ b->set_text(button_path[i]);
+ b->set_toggle_mode(true);
+ b->set_button_group(group);
+ path_hb->add_child(b);
+ b->set_pressed(true);
+ b->set_focus_mode(FOCUS_NONE);
+ b->connect("pressed", this, "_path_button_pressed", varray(i));
}
- update();
}
-void AnimationTreeEditor::_popup_edit_dialog() {
-
- updating_edit = true;
-
- for (int i = 0; i < 2; i++)
- edit_scroll[i]->hide();
-
- for (int i = 0; i < 4; i++) {
-
- edit_line[i]->hide();
- edit_label[i]->hide();
- }
-
- edit_option->hide();
- edit_button->hide();
- filter_button->hide();
- edit_check->hide();
-
- Point2 pos = anim_tree->node_get_position(edited_node) - Point2(h_scroll->get_value(), v_scroll->get_value());
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- Size2 size = get_node_size(edited_node);
- Point2 popup_pos(pos.x + style->get_margin(MARGIN_LEFT), pos.y + size.y - style->get_margin(MARGIN_BOTTOM));
- popup_pos += get_global_position();
-
- if (renaming_edit) {
-
- edit_label[0]->set_text(TTR("New name:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_line[0]->set_begin(Point2(15, 25));
- edit_line[0]->set_text(edited_node);
- edit_line[0]->show();
- edit_dialog->set_size(Size2(150, 50));
-
- } else {
-
- AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
-
- switch (type) {
-
- case AnimationTreePlayer::NODE_ANIMATION:
-
- if (anim_tree->get_master_player() != NodePath() && anim_tree->has_node(anim_tree->get_master_player()) && Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player()))) {
-
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player()));
- master_anim_popup->clear();
- master_anim_popup->add_item(TTR("Edit Filters"));
- master_anim_popup->add_separator();
- List<StringName> sn;
- ap->get_animation_list(&sn);
- sn.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = sn.front(); E; E = E->next()) {
- master_anim_popup->add_item(E->get());
- }
-
- master_anim_popup->set_position(popup_pos);
- master_anim_popup->popup();
- } else {
- property_editor->edit(this, "", Variant::OBJECT, anim_tree->animation_node_get_animation(edited_node), PROPERTY_HINT_RESOURCE_TYPE, "Animation");
- property_editor->set_position(popup_pos);
- property_editor->popup();
- updating_edit = false;
- }
- return;
- case AnimationTreePlayer::NODE_TIMESCALE:
- edit_label[0]->set_text(TTR("Scale:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_line[0]->set_begin(Point2(15, 25));
- edit_line[0]->set_text(rtos(anim_tree->timescale_node_get_scale(edited_node)));
- edit_line[0]->show();
- edit_dialog->set_size(Size2(150, 50));
- break;
- case AnimationTreePlayer::NODE_ONESHOT:
- edit_label[0]->set_text(TTR("Fade In (s):"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_line[0]->set_begin(Point2(15, 25));
- edit_line[0]->set_text(rtos(anim_tree->oneshot_node_get_fadein_time(edited_node)));
- edit_line[0]->show();
- edit_label[1]->set_text(TTR("Fade Out (s):"));
- edit_label[1]->set_position(Point2(5, 55));
- edit_label[1]->show();
- edit_line[1]->set_begin(Point2(15, 75));
- edit_line[1]->set_text(rtos(anim_tree->oneshot_node_get_fadeout_time(edited_node)));
- edit_line[1]->show();
-
- edit_option->clear();
- edit_option->add_item(TTR("Blend"), 0);
- edit_option->add_item(TTR("Mix"), 1);
- edit_option->set_begin(Point2(15, 105));
-
- edit_option->select(anim_tree->oneshot_node_get_mix_mode(edited_node));
- edit_option->show();
-
- edit_check->set_text(TTR("Auto Restart:"));
- edit_check->set_begin(Point2(15, 125));
- edit_check->set_pressed(anim_tree->oneshot_node_has_autorestart(edited_node));
- edit_check->show();
-
- edit_label[2]->set_text(TTR("Restart (s):"));
- edit_label[2]->set_position(Point2(5, 145));
- edit_label[2]->show();
- edit_line[2]->set_begin(Point2(15, 165));
- edit_line[2]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_delay(edited_node)));
- edit_line[2]->show();
- edit_label[3]->set_text(TTR("Random Restart (s):"));
- edit_label[3]->set_position(Point2(5, 195));
- edit_label[3]->show();
- edit_line[3]->set_begin(Point2(15, 215));
- edit_line[3]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_random_delay(edited_node)));
- edit_line[3]->show();
-
- filter_button->set_begin(Point2(10, 245));
- filter_button->show();
-
- edit_button->set_begin(Point2(10, 268));
- edit_button->set_text(TTR("Start!"));
-
- edit_button->show();
+void AnimationTreeEditor::edit_path(const Vector<String> &p_path) {
- edit_dialog->set_size(Size2(180, 293));
+ button_path.clear();
- break;
+ Ref<AnimationNode> node = tree->get_tree_root();
- case AnimationTreePlayer::NODE_MIX:
+ if (node.is_valid()) {
+ current_root = node->get_instance_id();
- edit_label[0]->set_text(TTR("Amount:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_scroll[0]->set_min(0);
- edit_scroll[0]->set_max(1);
- edit_scroll[0]->set_step(0.01);
- edit_scroll[0]->set_value(anim_tree->mix_node_get_amount(edited_node));
- edit_scroll[0]->set_begin(Point2(15, 25));
- edit_scroll[0]->show();
- edit_dialog->set_size(Size2(150, 50));
+ for (int i = 0; i < p_path.size(); i++) {
- break;
- case AnimationTreePlayer::NODE_BLEND2:
- edit_label[0]->set_text(TTR("Blend:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_scroll[0]->set_min(0);
- edit_scroll[0]->set_max(1);
- edit_scroll[0]->set_step(0.01);
- edit_scroll[0]->set_value(anim_tree->blend2_node_get_amount(edited_node));
- edit_scroll[0]->set_begin(Point2(15, 25));
- edit_scroll[0]->show();
- filter_button->set_begin(Point2(10, 47));
- filter_button->show();
- edit_dialog->set_size(Size2(150, 74));
-
- break;
-
- case AnimationTreePlayer::NODE_BLEND3:
- edit_label[0]->set_text(TTR("Blend:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_scroll[0]->set_min(-1);
- edit_scroll[0]->set_max(1);
- edit_scroll[0]->set_step(0.01);
- edit_scroll[0]->set_value(anim_tree->blend3_node_get_amount(edited_node));
- edit_scroll[0]->set_begin(Point2(15, 25));
- edit_scroll[0]->show();
- edit_dialog->set_size(Size2(150, 50));
-
- break;
- case AnimationTreePlayer::NODE_BLEND4:
-
- edit_label[0]->set_text(TTR("Blend 0:"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_scroll[0]->set_min(0);
- edit_scroll[0]->set_max(1);
- edit_scroll[0]->set_step(0.01);
- edit_scroll[0]->set_value(anim_tree->blend4_node_get_amount(edited_node).x);
- edit_scroll[0]->set_begin(Point2(15, 25));
- edit_scroll[0]->show();
- edit_label[1]->set_text(TTR("Blend 1:"));
- edit_label[1]->set_position(Point2(5, 55));
- edit_label[1]->show();
- edit_scroll[1]->set_min(0);
- edit_scroll[1]->set_max(1);
- edit_scroll[1]->set_step(0.01);
- edit_scroll[1]->set_value(anim_tree->blend4_node_get_amount(edited_node).y);
- edit_scroll[1]->set_begin(Point2(15, 75));
- edit_scroll[1]->show();
- edit_dialog->set_size(Size2(150, 100));
-
- break;
-
- case AnimationTreePlayer::NODE_TRANSITION: {
-
- edit_label[0]->set_text(TTR("X-Fade Time (s):"));
- edit_label[0]->set_position(Point2(5, 5));
- edit_label[0]->show();
- edit_line[0]->set_begin(Point2(15, 25));
- edit_line[0]->set_text(rtos(anim_tree->transition_node_get_xfade_time(edited_node)));
- edit_line[0]->show();
-
- edit_label[1]->set_text(TTR("Current:"));
- edit_label[1]->set_position(Point2(5, 55));
- edit_label[1]->show();
- edit_option->set_begin(Point2(15, 75));
-
- edit_option->clear();
-
- for (int i = 0; i < anim_tree->transition_node_get_input_count(edited_node); i++) {
- edit_option->add_item(itos(i), i);
- }
-
- edit_option->select(anim_tree->transition_node_get_current(edited_node));
- edit_option->show();
- edit_dialog->set_size(Size2(150, 100));
-
- } break;
- default: {}
+ Ref<AnimationNode> child = node->get_child_by_name(p_path[i]);
+ ERR_BREAK(child.is_null());
+ node = child;
+ button_path.push_back(p_path[i]);
}
- }
-
- edit_dialog->set_position(popup_pos);
- edit_dialog->popup();
-
- updating_edit = false;
-}
-
-void AnimationTreeEditor::_draw_node(const StringName &p_node) {
-
- RID ci = get_canvas_item();
- AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
-
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- Ref<Font> font = get_font("font", "PopupMenu");
- Color font_color = get_color("font_color", "PopupMenu");
- Color font_color_title = get_color("font_color_hover", "PopupMenu");
- font_color_title.a *= 0.8;
- Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons");
-
- Size2 size = get_node_size(p_node);
- Point2 pos = anim_tree->node_get_position(p_node);
- if (click_type == CLICK_NODE && click_node == p_node) {
-
- pos += click_motion - click_pos;
- if (pos.x < 5)
- pos.x = 5;
- if (pos.y < 5)
- pos.y = 5;
- }
-
- pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
- style->draw(ci, Rect2(pos, size));
-
- float w = size.width - style->get_minimum_size().width;
- float h = font->get_height() + get_constant("vseparation", "PopupMenu");
-
- Point2 ofs = style->get_offset() + pos;
- Point2 ascofs(0, font->get_ascent());
-
- Color bx = font_color_title;
- bx.a *= 0.1;
- draw_rect(Rect2(ofs, Size2(size.width - style->get_minimum_size().width, font->get_height())), bx);
- font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, String(_node_type_names[type]), font_color_title);
-
- ofs.y += h;
- font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, p_node, font_color);
- ofs.y += h;
-
- int count = 2; // title and name
- int inputs = anim_tree->node_get_input_count(p_node);
- count += inputs ? inputs : 1;
-
- float icon_h_ofs = Math::floor((font->get_height() - slot_icon->get_height()) / 2.0) + 1;
-
- if (type != AnimationTreePlayer::NODE_OUTPUT)
- slot_icon->draw(ci, ofs + Point2(w, icon_h_ofs)); //output
-
- if (inputs) {
- for (int i = 0; i < inputs; i++) {
-
- slot_icon->draw(ci, ofs + Point2(-slot_icon->get_width(), icon_h_ofs));
- String text;
- switch (type) {
-
- case AnimationTreePlayer::NODE_TIMESCALE:
- case AnimationTreePlayer::NODE_TIMESEEK: text = "in"; break;
- case AnimationTreePlayer::NODE_OUTPUT: text = "out"; break;
- case AnimationTreePlayer::NODE_ANIMATION: break;
- case AnimationTreePlayer::NODE_ONESHOT: text = (i == 0 ? "in" : "add"); break;
- case AnimationTreePlayer::NODE_BLEND2:
- case AnimationTreePlayer::NODE_MIX: text = (i == 0 ? "a" : "b"); break;
- case AnimationTreePlayer::NODE_BLEND3:
- switch (i) {
- case 0: text = "b-"; break;
- case 1: text = "a"; break;
- case 2: text = "b+"; break;
- }
- break;
-
- case AnimationTreePlayer::NODE_BLEND4:
- switch (i) {
- case 0: text = "a0"; break;
- case 1: text = "b0"; break;
- case 2: text = "a1"; break;
- case 3: text = "b1"; break;
- }
- break;
-
- case AnimationTreePlayer::NODE_TRANSITION:
- text = itos(i);
- if (anim_tree->transition_node_has_input_auto_advance(p_node, i))
- text += "->";
-
- break;
- default: {}
+ for (int i = 0; i < editors.size(); i++) {
+ if (editors[i]->can_edit(node)) {
+ editors[i]->edit(node);
+ editors[i]->show();
+ } else {
+ editors[i]->edit(Ref<AnimationNode>());
+ editors[i]->hide();
}
- font->draw(ci, ofs + ascofs + Point2(3, 0), text, font_color);
-
- ofs.y += h;
}
} else {
- ofs.y += h;
+ current_root = 0;
}
- Ref<StyleBox> pg_bg = get_stylebox("bg", "ProgressBar");
- Ref<StyleBox> pg_fill = get_stylebox("fill", "ProgressBar");
- Rect2 pg_rect(ofs, Size2(w, h));
-
- bool editable = true;
- switch (type) {
- case AnimationTreePlayer::NODE_ANIMATION: {
-
- Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
- String text;
- if (anim_tree->animation_node_get_master_animation(p_node) != "")
- text = anim_tree->animation_node_get_master_animation(p_node);
- else if (anim.is_null())
- text = "load...";
- else
- text = anim->get_name();
-
- font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, text, font_color_title);
+ edited_path = button_path;
- } break;
- case AnimationTreePlayer::NODE_ONESHOT:
- case AnimationTreePlayer::NODE_MIX:
- case AnimationTreePlayer::NODE_BLEND2:
- case AnimationTreePlayer::NODE_BLEND3:
- case AnimationTreePlayer::NODE_BLEND4:
- case AnimationTreePlayer::NODE_TIMESCALE:
- case AnimationTreePlayer::NODE_TRANSITION: {
-
- font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit...", font_color_title);
- } break;
- default: editable = false;
- }
-
- if (editable) {
-
- Ref<Texture> arrow = get_icon("GuiDropdown", "EditorIcons");
- Point2 arrow_ofs(w - arrow->get_width(), Math::floor((h - arrow->get_height()) / 2));
- arrow->draw(ci, ofs + arrow_ofs);
- }
+ _update_path();
}
-AnimationTreeEditor::ClickType AnimationTreeEditor::_locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const {
-
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- Ref<Font> font = get_font("font", "PopupMenu");
-
- float h = (font->get_height() + get_constant("vseparation", "PopupMenu"));
-
- for (const List<StringName>::Element *E = order.back(); E; E = E->prev()) {
-
- StringName node = E->get();
-
- AnimationTreePlayer::NodeType type = anim_tree->node_get_type(node);
-
- Point2 pos = anim_tree->node_get_position(node);
- Size2 size = get_node_size(node);
-
- pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
-
- if (!Rect2(pos, size).has_point(p_click))
- continue;
-
- if (p_node_id)
- *p_node_id = node;
-
- pos = p_click - pos;
-
- float y = pos.y - style->get_offset().height;
-
- if (y < 2 * h)
- return CLICK_NODE;
- y -= 2 * h;
-
- int inputs = anim_tree->node_get_input_count(node);
- int count = MAX(inputs, 1);
-
- if (inputs == 0 || (pos.x > size.width / 2 && type != AnimationTreePlayer::NODE_OUTPUT)) {
-
- if (y < count * h) {
-
- if (p_slot_index)
- *p_slot_index = 0;
- return CLICK_OUTPUT_SLOT;
- }
- }
-
- for (int i = 0; i < count; i++) {
-
- if (y < h) {
- if (p_slot_index)
- *p_slot_index = i;
- return CLICK_INPUT_SLOT;
- }
- y -= h;
- }
-
- bool has_parameters = type != AnimationTreePlayer::NODE_OUTPUT && type != AnimationTreePlayer::NODE_TIMESEEK;
- return has_parameters ? CLICK_PARAMETER : CLICK_NODE;
- }
-
- return CLICK_NONE;
-}
-
-Point2 AnimationTreeEditor::_get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot) {
-
- Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
- Ref<Font> font = get_font("font", "PopupMenu");
- Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons");
-
- Size2 size = get_node_size(p_node_id);
- Point2 pos = anim_tree->node_get_position(p_node_id);
-
- if (click_type == CLICK_NODE && click_node == p_node_id) {
-
- pos += click_motion - click_pos;
- if (pos.x < 5)
- pos.x = 5;
- if (pos.y < 5)
- pos.y = 5;
- }
-
- pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
-
- float w = size.width - style->get_minimum_size().width;
- float h = font->get_height() + get_constant("vseparation", "PopupMenu");
-
- pos += style->get_offset();
-
- pos.y += h * 2;
-
- pos.y += h * p_slot;
-
- pos += Point2(-slot_icon->get_width() / 2.0, h / 2.0).floor();
-
- if (!p_input) {
- pos.x += w + slot_icon->get_width();
- }
-
- return pos;
+Vector<String> AnimationTreeEditor::get_edited_path() const {
+ return button_path;
}
-void AnimationTreeEditor::_gui_input(Ref<InputEvent> p_event) {
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
-
- if (mb->is_pressed()) {
+void AnimationTreeEditor::enter_editor(const String &p_path) {
- if (mb->get_button_index() == 1) {
- click_pos = Point2(mb->get_position().x, mb->get_position().y);
- click_motion = click_pos;
- click_type = _locate_click(click_pos, &click_node, &click_slot);
- if (click_type != CLICK_NONE) {
-
- order.erase(click_node);
- order.push_back(click_node);
- update();
- }
-
- switch (click_type) {
- case CLICK_INPUT_SLOT: {
- click_pos = _get_slot_pos(click_node, true, click_slot);
- } break;
- case CLICK_OUTPUT_SLOT: {
- click_pos = _get_slot_pos(click_node, false, click_slot);
- } break;
- case CLICK_PARAMETER: {
-
- edited_node = click_node;
- renaming_edit = false;
- _popup_edit_dialog();
- //open editor
- //_node_edit_property(click_node);
- } break;
- default: {}
- }
- }
- if (mb->get_button_index() == 2) {
-
- if (click_type != CLICK_NONE) {
- click_type = CLICK_NONE;
- update();
- } else {
- // try to disconnect/remove
-
- Point2 rclick_pos = Point2(mb->get_position().x, mb->get_position().y);
- rclick_type = _locate_click(rclick_pos, &rclick_node, &rclick_slot);
- if (rclick_type == CLICK_INPUT_SLOT || rclick_type == CLICK_OUTPUT_SLOT) {
-
- node_popup->clear();
- node_popup->set_size(Size2(1, 1));
- node_popup->add_item(TTR("Disconnect"), NODE_DISCONNECT);
- if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) {
- node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
- if (rclick_type == CLICK_INPUT_SLOT) {
- if (anim_tree->transition_node_has_input_auto_advance(rclick_node, rclick_slot))
- node_popup->add_item(TTR("Clear Auto-Advance"), NODE_CLEAR_AUTOADVANCE);
- else
- node_popup->add_item(TTR("Set Auto-Advance"), NODE_SET_AUTOADVANCE);
- node_popup->add_item(TTR("Delete Input"), NODE_DELETE_INPUT);
- }
- }
-
- node_popup->set_position(rclick_pos + get_global_position());
- node_popup->popup();
- }
-
- if (rclick_type == CLICK_NODE) {
- node_popup->clear();
- node_popup->set_size(Size2(1, 1));
- node_popup->add_item(TTR("Rename"), NODE_RENAME);
- node_popup->add_item(TTR("Remove"), NODE_ERASE);
- if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION)
- node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
- node_popup->set_position(rclick_pos + get_global_position());
- node_popup->popup();
- }
- }
- }
- } else {
-
- if (mb->get_button_index() == 1 && click_type != CLICK_NONE) {
-
- switch (click_type) {
- case CLICK_INPUT_SLOT:
- case CLICK_OUTPUT_SLOT: {
-
- Point2 dst_click_pos = Point2(mb->get_position().x, mb->get_position().y);
- StringName id;
- int slot;
- ClickType dst_click_type = _locate_click(dst_click_pos, &id, &slot);
-
- if (dst_click_type == CLICK_INPUT_SLOT && click_type == CLICK_OUTPUT_SLOT) {
-
- anim_tree->connect_nodes(click_node, id, slot);
- }
- if (click_type == CLICK_INPUT_SLOT && dst_click_type == CLICK_OUTPUT_SLOT) {
-
- anim_tree->connect_nodes(id, click_node, click_slot);
- }
-
- } break;
- case CLICK_NODE: {
- Point2 new_pos = anim_tree->node_get_position(click_node) + (click_motion - click_pos);
- if (new_pos.x < 5)
- new_pos.x = 5;
- if (new_pos.y < 5)
- new_pos.y = 5;
- anim_tree->node_set_position(click_node, new_pos);
-
- } break;
- default: {}
- }
-
- click_type = CLICK_NONE;
- update();
- }
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
-
- if (mm->get_button_mask() & 1 && click_type != CLICK_NONE) {
-
- click_motion = Point2(mm->get_position().x, mm->get_position().y);
- update();
- }
- if ((mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE))) {
-
- h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
- v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
- update();
- }
- }
+ Vector<String> path = edited_path;
+ path.push_back(p_path);
+ edit_path(path);
}
-void AnimationTreeEditor::_draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color) {
-
- static const int steps = 20;
-
- Rect2 r;
- r.position = p_from;
- r.expand_to(p_to);
- Vector2 sign = Vector2((p_from.x < p_to.x) ? 1 : -1, (p_from.y < p_to.y) ? 1 : -1);
- bool flip = sign.x * sign.y < 0;
-
- Vector2 prev;
- for (int i = 0; i <= steps; i++) {
-
- float d = i / float(steps);
- float c = -Math::cos(d * Math_PI) * 0.5 + 0.5;
- if (flip)
- c = 1.0 - c;
- Vector2 p = r.position + Vector2(d * r.size.width, c * r.size.height);
-
- if (i > 0) {
-
- draw_line(prev, p, p_color, 2);
- }
-
- prev = p;
- }
+void AnimationTreeEditor::_about_to_show_root() {
}
void AnimationTreeEditor::_notification(int p_what) {
+ if (p_what == NOTIFICATION_PROCESS) {
+ ObjectID root = 0;
+ if (tree && tree->get_tree_root().is_valid()) {
+ root = tree->get_tree_root()->get_instance_id();
+ }
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- play_button->set_icon(get_icon("Play", "EditorIcons"));
- add_menu->set_icon(get_icon("Add", "EditorIcons"));
- } break;
- case NOTIFICATION_DRAW: {
-
- _update_scrollbars();
- //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1));
- get_stylebox("bg", "Tree")->draw(get_canvas_item(), Rect2(Point2(), get_size()));
-
- for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
-
- _draw_node(E->get());
- }
-
- if (click_type == CLICK_INPUT_SLOT || click_type == CLICK_OUTPUT_SLOT) {
-
- _draw_cos_line(click_pos, click_motion, Color(0.5, 1, 0.5, 0.8));
- }
-
- List<AnimationTreePlayer::Connection> connections;
- anim_tree->get_connection_list(&connections);
-
- for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
-
- const AnimationTreePlayer::Connection &c = E->get();
- Point2 source = _get_slot_pos(c.src_node, false, 0);
- Point2 dest = _get_slot_pos(c.dst_node, true, c.dst_input);
- Color col = Color(1, 1, 0.5, 0.8);
- /*
- if (click_type==CLICK_NODE && click_node==c.src_node) {
-
- source+=click_motion-click_pos;
- }
-
- if (click_type==CLICK_NODE && click_node==c.dst_node) {
-
- dest+=click_motion-click_pos;
- }*/
-
- _draw_cos_line(source, dest, col);
- }
-
- switch (anim_tree->get_last_error()) {
-
- case AnimationTreePlayer::CONNECT_OK: {
-
- Ref<Font> f = get_font("font", "Label");
- f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is valid."), Color(0, 1, 0.6, 0.8));
- } break;
- default: {
-
- Ref<Font> f = get_font("font", "Label");
- f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is invalid."), Color(1, 0.6, 0.0, 0.8));
- } break;
- }
-
- } break;
+ if (root != current_root) {
+ edit_path(Vector<String>());
+ }
}
}
-void AnimationTreeEditor::_update_scrollbars() {
-
- Size2 size = get_size();
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
-
- v_scroll->set_begin(Point2(size.width - vmin.width, 0));
- v_scroll->set_end(Point2(size.width, size.height));
-
- h_scroll->set_begin(Point2(0, size.height - hmin.height));
- h_scroll->set_end(Point2(size.width - vmin.width, size.height));
-
- Size2 min = _get_maximum_size();
-
- if (min.height < size.height - hmin.height) {
-
- v_scroll->hide();
- offset.y = 0;
- } else {
-
- v_scroll->show();
- v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - hmin.height);
- offset.y = v_scroll->get_value();
- }
-
- if (min.width < size.width - vmin.width) {
-
- h_scroll->hide();
- offset.x = 0;
- } else {
-
- h_scroll->show();
- h_scroll->set_max(min.width);
- h_scroll->set_page(size.width - vmin.width);
- offset.x = h_scroll->get_value();
- }
+void AnimationTreeEditor::_bind_methods() {
+ ClassDB::bind_method("_path_button_pressed", &AnimationTreeEditor::_path_button_pressed);
}
-void AnimationTreeEditor::_scroll_moved(float) {
+AnimationTreeEditor *AnimationTreeEditor::singleton = NULL;
- offset.x = h_scroll->get_value();
- offset.y = v_scroll->get_value();
- update();
+void AnimationTreeEditor::add_plugin(AnimationTreeNodeEditorPlugin *p_editor) {
+ ERR_FAIL_COND(p_editor->get_parent());
+ editor_base->add_child(p_editor);
+ editors.push_back(p_editor);
+ p_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+ p_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ p_editor->hide();
}
-void AnimationTreeEditor::_node_menu_item(int p_item) {
-
- switch (p_item) {
-
- case NODE_DISCONNECT: {
-
- if (rclick_type == CLICK_INPUT_SLOT) {
-
- anim_tree->disconnect_nodes(rclick_node, rclick_slot);
- update();
- }
-
- if (rclick_type == CLICK_OUTPUT_SLOT) {
-
- List<AnimationTreePlayer::Connection> connections;
- anim_tree->get_connection_list(&connections);
-
- for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
-
- const AnimationTreePlayer::Connection &c = E->get();
- if (c.dst_node == rclick_node) {
-
- anim_tree->disconnect_nodes(c.dst_node, c.dst_input);
- }
- }
- update();
- }
-
- } break;
- case NODE_RENAME: {
-
- renaming_edit = true;
- edited_node = rclick_node;
- _popup_edit_dialog();
-
- } break;
- case NODE_ADD_INPUT: {
-
- anim_tree->transition_node_set_input_count(rclick_node, anim_tree->transition_node_get_input_count(rclick_node) + 1);
- update();
- } break;
- case NODE_DELETE_INPUT: {
-
- anim_tree->transition_node_delete_input(rclick_node, rclick_slot);
- update();
- } break;
- case NODE_SET_AUTOADVANCE: {
-
- anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, true);
- update();
-
- } break;
- case NODE_CLEAR_AUTOADVANCE: {
-
- anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, false);
- update();
-
- } break;
-
- case NODE_ERASE: {
-
- if (rclick_node == "out")
- break;
- order.erase(rclick_node);
- anim_tree->remove_node(rclick_node);
- update();
- } break;
- }
+void AnimationTreeEditor::remove_plugin(AnimationTreeNodeEditorPlugin *p_editor) {
+ ERR_FAIL_COND(p_editor->get_parent() != editor_base);
+ editor_base->remove_child(p_editor);
+ editors.erase(p_editor);
}
-StringName AnimationTreeEditor::_add_node(int p_item) {
-
- static const char *bname[] = {
- "out",
- "anim",
- "oneshot",
- "mix",
- "blend2",
- "blend3",
- "blend4",
- "scale",
- "seek",
- "transition"
- };
-
- String name;
- int idx = 1;
-
- while (true) {
-
- name = bname[p_item];
- if (idx > 1)
- name += " " + itos(idx);
- if (anim_tree->node_exists(name))
- idx++;
- else
- break;
+String AnimationTreeEditor::get_base_path() {
+ String path = SceneStringNames::get_singleton()->parameters_base_path;
+ for (int i = 0; i < edited_path.size(); i++) {
+ path += edited_path[i] + "/";
}
-
- anim_tree->add_node((AnimationTreePlayer::NodeType)p_item, name);
- anim_tree->node_set_position(name, Point2(last_x, last_y));
- order.push_back(name);
- last_x += 10;
- last_y += 10;
- last_x = last_x % (int)get_size().width;
- last_y = last_y % (int)get_size().height;
- update();
-
- return name;
-};
-
-void AnimationTreeEditor::_file_dialog_selected(String p_path) {
-
- switch (file_op) {
-
- case MENU_IMPORT_ANIMATIONS: {
- Vector<String> files = file_dialog->get_selected_files();
-
- for (int i = 0; i < files.size(); i++) {
-
- StringName node = _add_node(AnimationTreePlayer::NODE_ANIMATION);
-
- RES anim = ResourceLoader::load(files[i]);
- anim_tree->animation_node_set_animation(node, anim);
- //anim_tree->node_set_name(node, files[i].get_file());
- };
- } break;
-
- default:
- break;
- };
-};
-
-void AnimationTreeEditor::_add_menu_item(int p_item) {
-
- if (p_item == MENU_GRAPH_CLEAR) {
-
- //clear
- } else if (p_item == MENU_IMPORT_ANIMATIONS) {
-
- file_op = MENU_IMPORT_ANIMATIONS;
- file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- file_dialog->popup_centered_ratio();
-
- } else {
-
- _add_node(p_item);
- }
-}
-
-Size2 AnimationTreeEditor::get_minimum_size() const {
-
- return Size2(10, 200);
+ return path;
}
-void AnimationTreeEditor::_find_paths_for_filter(const StringName &p_node, Set<String> &paths) {
-
- ERR_FAIL_COND(!anim_tree->node_exists(p_node));
-
- for (int i = 0; i < anim_tree->node_get_input_count(p_node); i++) {
-
- StringName port = anim_tree->node_get_input_source(p_node, i);
- if (port == StringName())
- continue;
- _find_paths_for_filter(port, paths);
- }
-
- if (anim_tree->node_get_type(p_node) == AnimationTreePlayer::NODE_ANIMATION) {
-
- Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
- if (anim.is_valid()) {
-
- for (int i = 0; i < anim->get_track_count(); i++) {
- paths.insert(anim->track_get_path(i));
- }
+bool AnimationTreeEditor::can_edit(const Ref<AnimationNode> &p_node) const {
+ for (int i = 0; i < editors.size(); i++) {
+ if (editors[i]->can_edit(p_node)) {
+ return true;
}
}
+ return false;
}
-void AnimationTreeEditor::_filter_edited() {
-
- TreeItem *ed = filter->get_edited();
- if (!ed)
- return;
+Vector<String> AnimationTreeEditor::get_animation_list() {
- if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
- anim_tree->oneshot_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
- } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
- anim_tree->blend2_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
- } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
- anim_tree->animation_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
+ if (!singleton->is_visible()) {
+ return Vector<String>();
}
-}
-
-void AnimationTreeEditor::_edit_filters() {
-
- filter_dialog->popup_centered_ratio();
- filter->clear();
-
- Set<String> npb;
- _find_paths_for_filter(edited_node, npb);
-
- TreeItem *root = filter->create_item();
- filter->set_hide_root(true);
- Map<String, TreeItem *> pm;
-
- Node *base = anim_tree->get_node(anim_tree->get_base_path());
-
- for (Set<String>::Element *E = npb.front(); E; E = E->next()) {
-
- TreeItem *parent = root;
- String descr = E->get();
- if (base) {
- NodePath np = E->get();
- if (np.get_subname_count() == 1) {
- Node *n = base->get_node(np);
- Skeleton *s = Object::cast_to<Skeleton>(n);
- if (s) {
+ AnimationTree *tree = singleton->tree;
+ if (!tree || !tree->has_node(tree->get_animation_player()))
+ return Vector<String>();
- String skelbase = E->get().substr(0, E->get().find(":"));
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
- int bidx = s->find_bone(np.get_subname(0));
+ if (!ap)
+ return Vector<String>();
- if (bidx != -1) {
- int bparent = s->get_bone_parent(bidx);
- //
- if (bparent != -1) {
-
- String bpn = skelbase + ":" + s->get_bone_name(bparent);
- if (pm.has(bpn)) {
- parent = pm[bpn];
- descr = np.get_subname(0);
- }
- } else {
-
- if (pm.has(skelbase)) {
- parent = pm[skelbase];
- }
- }
- }
- }
- }
- }
-
- TreeItem *it = filter->create_item(parent);
- it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- it->set_text(0, descr);
- it->set_metadata(0, NodePath(E->get()));
- it->set_editable(0, true);
- if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
- it->set_checked(0, anim_tree->oneshot_node_is_path_filtered(edited_node, E->get()));
- } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
- it->set_checked(0, anim_tree->blend2_node_is_path_filtered(edited_node, E->get()));
- } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
- it->set_checked(0, anim_tree->animation_node_is_path_filtered(edited_node, E->get()));
- }
- pm[E->get()] = it;
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ Vector<String> ret;
+ for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
+ ret.push_back(E->get());
}
-}
-
-void AnimationTreeEditor::_bind_methods() {
- ClassDB::bind_method("_add_menu_item", &AnimationTreeEditor::_add_menu_item);
- ClassDB::bind_method("_node_menu_item", &AnimationTreeEditor::_node_menu_item);
- ClassDB::bind_method("_gui_input", &AnimationTreeEditor::_gui_input);
- //ClassDB::bind_method( "_node_param_changed", &AnimationTreeEditor::_node_param_changed );
- ClassDB::bind_method("_scroll_moved", &AnimationTreeEditor::_scroll_moved);
- ClassDB::bind_method("_edit_dialog_changeds", &AnimationTreeEditor::_edit_dialog_changeds);
- ClassDB::bind_method("_edit_dialog_changede", &AnimationTreeEditor::_edit_dialog_changede);
- ClassDB::bind_method("_edit_dialog_changedf", &AnimationTreeEditor::_edit_dialog_changedf);
- ClassDB::bind_method("_edit_dialog_changed", &AnimationTreeEditor::_edit_dialog_changed);
- ClassDB::bind_method("_edit_dialog_animation_changed", &AnimationTreeEditor::_edit_dialog_animation_changed);
- ClassDB::bind_method("_edit_dialog_edit_animation", &AnimationTreeEditor::_edit_dialog_edit_animation);
- ClassDB::bind_method("_play_toggled", &AnimationTreeEditor::_play_toggled);
- ClassDB::bind_method("_edit_oneshot_start", &AnimationTreeEditor::_edit_oneshot_start);
- ClassDB::bind_method("_file_dialog_selected", &AnimationTreeEditor::_file_dialog_selected);
- ClassDB::bind_method("_master_anim_menu_item", &AnimationTreeEditor::_master_anim_menu_item);
- ClassDB::bind_method("_edit_filters", &AnimationTreeEditor::_edit_filters);
- ClassDB::bind_method("_filter_edited", &AnimationTreeEditor::_filter_edited);
+ return ret;
}
AnimationTreeEditor::AnimationTreeEditor() {
- set_focus_mode(FOCUS_ALL);
-
- PopupMenu *p;
- List<PropertyInfo> defaults;
-
- add_menu = memnew(MenuButton);
- //add_menu->set_
- add_menu->set_position(Point2(0, 0));
- add_menu->set_size(Point2(25, 15));
- add_child(add_menu);
-
- p = add_menu->get_popup();
- p->add_item(TTR("Animation Node"), AnimationTreePlayer::NODE_ANIMATION);
- p->add_item(TTR("OneShot Node"), AnimationTreePlayer::NODE_ONESHOT);
- p->add_item(TTR("Mix Node"), AnimationTreePlayer::NODE_MIX);
- p->add_item(TTR("Blend2 Node"), AnimationTreePlayer::NODE_BLEND2);
- p->add_item(TTR("Blend3 Node"), AnimationTreePlayer::NODE_BLEND3);
- p->add_item(TTR("Blend4 Node"), AnimationTreePlayer::NODE_BLEND4);
- p->add_item(TTR("TimeScale Node"), AnimationTreePlayer::NODE_TIMESCALE);
- p->add_item(TTR("TimeSeek Node"), AnimationTreePlayer::NODE_TIMESEEK);
- p->add_item(TTR("Transition Node"), AnimationTreePlayer::NODE_TRANSITION);
- p->add_separator();
- p->add_item(TTR("Import Animations..."), MENU_IMPORT_ANIMATIONS); // wtf
- p->add_separator();
- p->add_item(TTR("Clear"), MENU_GRAPH_CLEAR);
-
- p->connect("id_pressed", this, "_add_menu_item");
-
- play_button = memnew(Button);
- play_button->set_position(Point2(25, 0));
- play_button->set_size(Point2(25, 15));
- add_child(play_button);
- play_button->set_toggle_mode(true);
- play_button->connect("pressed", this, "_play_toggled");
-
- last_x = 50;
- last_y = 50;
-
- property_editor = memnew(CustomPropertyEditor);
- add_child(property_editor);
- property_editor->connect("variant_changed", this, "_edit_dialog_animation_changed");
- property_editor->connect("resource_edit_request", this, "_edit_dialog_edit_animation");
-
- h_scroll = memnew(HScrollBar);
- v_scroll = memnew(VScrollBar);
-
- add_child(h_scroll);
- add_child(v_scroll);
-
- h_scroll->connect("value_changed", this, "_scroll_moved");
- v_scroll->connect("value_changed", this, "_scroll_moved");
-
- node_popup = memnew(PopupMenu);
- add_child(node_popup);
- node_popup->set_as_toplevel(true);
-
- master_anim_popup = memnew(PopupMenu);
- add_child(master_anim_popup);
- master_anim_popup->connect("id_pressed", this, "_master_anim_menu_item");
-
- node_popup->connect("id_pressed", this, "_node_menu_item");
-
- updating_edit = false;
-
- edit_dialog = memnew(PopupPanel);
- //edit_dialog->get_ok()->hide();
- //edit_dialog->get_cancel()->hide();
- add_child(edit_dialog);
-
- edit_option = memnew(OptionButton);
- edit_option->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- edit_option->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(edit_option);
- edit_option->connect("item_selected", this, "_edit_dialog_changedf");
- edit_option->hide();
-
- for (int i = 0; i < 2; i++) {
- edit_scroll[i] = memnew(HSlider);
- edit_scroll[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- edit_scroll[i]->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(edit_scroll[i]);
- edit_scroll[i]->hide();
- edit_scroll[i]->connect("value_changed", this, "_edit_dialog_changedf");
- }
- for (int i = 0; i < 4; i++) {
- edit_line[i] = memnew(LineEdit);
- edit_line[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- edit_line[i]->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(edit_line[i]);
- edit_line[i]->hide();
- edit_line[i]->connect("text_changed", this, "_edit_dialog_changeds");
- edit_line[i]->connect("text_entered", this, "_edit_dialog_changede");
- edit_label[i] = memnew(Label);
- edit_dialog->add_child(edit_label[i]);
- edit_label[i]->hide();
- }
-
- edit_button = memnew(Button);
- edit_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- edit_button->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(edit_button);
- edit_button->hide();
- edit_button->connect("pressed", this, "_edit_oneshot_start");
-
- edit_check = memnew(CheckButton);
- edit_check->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- edit_check->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(edit_check);
- edit_check->hide();
- edit_check->connect("pressed", this, "_edit_dialog_changed");
-
- file_dialog = memnew(EditorFileDialog);
- file_dialog->set_enable_multiple_selection(true);
- file_dialog->set_current_dir(ProjectSettings::get_singleton()->get_resource_path());
- add_child(file_dialog);
- file_dialog->connect("file_selected", this, "_file_dialog_selected");
-
- filter_dialog = memnew(AcceptDialog);
- filter_dialog->set_title(TTR("Edit Node Filters"));
- add_child(filter_dialog);
-
- filter = memnew(Tree);
- filter_dialog->add_child(filter);
- //filter_dialog->set_child_rect(filter);
- filter->connect("item_edited", this, "_filter_edited");
+ AnimationNodeAnimation::get_editable_animation_list = get_animation_list;
+ path_edit = memnew(ScrollContainer);
+ add_child(path_edit);
+ path_edit->set_enable_h_scroll(true);
+ path_edit->set_enable_v_scroll(false);
+ path_hb = memnew(HBoxContainer);
+ path_edit->add_child(path_hb);
- filter_button = memnew(Button);
- filter_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- filter_button->set_margin(MARGIN_RIGHT, -10);
- edit_dialog->add_child(filter_button);
- filter_button->hide();
- filter_button->set_text(TTR("Filters..."));
- filter_button->connect("pressed", this, "_edit_filters");
+ current_root = 0;
+ singleton = this;
+ editor_base = memnew(PanelContainer);
+ editor_base->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(editor_base);
- set_clip_contents(true);
+ add_plugin(memnew(AnimationNodeBlendTreeEditor));
+ add_plugin(memnew(AnimationNodeBlendSpace1DEditor));
+ add_plugin(memnew(AnimationNodeBlendSpace2DEditor));
+ add_plugin(memnew(AnimationNodeStateMachineEditor));
}
void AnimationTreeEditorPlugin::edit(Object *p_object) {
- anim_tree_editor->edit(Object::cast_to<AnimationTreePlayer>(p_object));
+ anim_tree_editor->edit(Object::cast_to<AnimationTree>(p_object));
}
bool AnimationTreeEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("AnimationTreePlayer");
+ return p_object->is_class("AnimationTree");
}
void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
@@ -1422,13 +251,13 @@ void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
//editor->animation_panel_make_visible(true);
button->show();
editor->make_bottom_panel_item_visible(anim_tree_editor);
- anim_tree_editor->set_physics_process(true);
+ anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree())
editor->hide_bottom_panel();
button->hide();
- anim_tree_editor->set_physics_process(false);
+ anim_tree_editor->set_process(false);
}
}
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index aeb5b1744f..b12054bb62 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -1,167 +1,65 @@
-/*************************************************************************/
-/* animation_tree_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
#ifndef ANIMATION_TREE_EDITOR_PLUGIN_H
#define ANIMATION_TREE_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/property_editor.h"
-#include "scene/animation/animation_tree_player.h"
+#include "scene/animation/animation_tree.h"
#include "scene/gui/button.h"
+#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-
-class AnimationTreeEditor : public Control {
-
- GDCLASS(AnimationTreeEditor, Control);
-
- static const char *_node_type_names[];
-
- enum ClickType {
- CLICK_NONE,
- CLICK_NAME,
- CLICK_NODE,
- CLICK_INPUT_SLOT,
- CLICK_OUTPUT_SLOT,
- CLICK_PARAMETER
- };
-
- enum {
-
- MENU_GRAPH_CLEAR = 100,
- MENU_IMPORT_ANIMATIONS = 101,
- NODE_DISCONNECT,
- NODE_RENAME,
- NODE_ERASE,
- NODE_ADD_INPUT,
- NODE_DELETE_INPUT,
- NODE_SET_AUTOADVANCE,
- NODE_CLEAR_AUTOADVANCE
- };
-
- bool renaming_edit;
- StringName edited_node;
- bool updating_edit;
- Popup *edit_dialog;
- HSlider *edit_scroll[2];
- LineEdit *edit_line[4];
- OptionButton *edit_option;
- Label *edit_label[4];
- Button *edit_button;
- Button *filter_button;
- CheckButton *edit_check;
- EditorFileDialog *file_dialog;
- int file_op;
-
- void _popup_edit_dialog();
-
- void _setup_edit_dialog(const StringName &p_node);
- PopupMenu *master_anim_popup;
- PopupMenu *node_popup;
- PopupMenu *add_popup;
- HScrollBar *h_scroll;
- VScrollBar *v_scroll;
- MenuButton *add_menu;
-
- CustomPropertyEditor *property_editor;
-
- AnimationTreePlayer *anim_tree;
- List<StringName> order;
- Set<StringName> active_nodes;
-
- int last_x, last_y;
-
- Point2 offset;
- ClickType click_type;
- Point2 click_pos;
- StringName click_node;
- int click_slot;
- Point2 click_motion;
- ClickType rclick_type;
- StringName rclick_node;
- int rclick_slot;
-
- Button *play_button;
-
- Size2 _get_maximum_size();
- Size2 get_node_size(const StringName &p_node) const;
- void _draw_node(const StringName &p_node);
-
- AcceptDialog *filter_dialog;
- Tree *filter;
-
- void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color);
- void _update_scrollbars();
- void _scroll_moved(float);
- void _play_toggled();
- /*
- void _node_param_changed();
- void _node_add_callback();
- void _node_add(VisualServer::AnimationTreeNodeType p_type);
- void _node_edit_property(const StringName& p_node);
-*/
-
- void _master_anim_menu_item(int p_item);
- void _node_menu_item(int p_item);
- void _add_menu_item(int p_item);
-
- void _filter_edited();
- void _find_paths_for_filter(const StringName &p_node, Set<String> &paths);
- void _edit_filters();
-
- void _edit_oneshot_start();
- void _edit_dialog_animation_changed();
- void _edit_dialog_edit_animation();
- void _edit_dialog_changeds(String);
- void _edit_dialog_changede(String);
- void _edit_dialog_changedf(float);
- void _edit_dialog_changed();
- void _dialog_changed() const;
- ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const;
- Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot);
-
- StringName _add_node(int p_item);
- void _file_dialog_selected(String p_path);
+
+class AnimationTreeNodeEditorPlugin : public VBoxContainer {
+ GDCLASS(AnimationTreeNodeEditorPlugin, VBoxContainer)
+public:
+ virtual bool can_edit(const Ref<AnimationNode> &p_node) = 0;
+ virtual void edit(const Ref<AnimationNode> &p_node) = 0;
+};
+
+class AnimationTreeEditor : public VBoxContainer {
+
+ GDCLASS(AnimationTreeEditor, VBoxContainer);
+
+ ScrollContainer *path_edit;
+ HBoxContainer *path_hb;
+
+ AnimationTree *tree;
+ PanelContainer *editor_base;
+
+ Vector<String> button_path;
+ Vector<String> edited_path;
+ Vector<AnimationTreeNodeEditorPlugin *> editors;
+
+ void _update_path();
+ void _about_to_show_root();
+ ObjectID current_root;
+
+ void _path_button_pressed(int p_path);
+
+ static Vector<String> get_animation_list();
protected:
void _notification(int p_what);
- void _gui_input(Ref<InputEvent> p_event);
static void _bind_methods();
+ static AnimationTreeEditor *singleton;
+
public:
- virtual Size2 get_minimum_size() const;
- void edit(AnimationTreePlayer *p_anim_tree);
+ AnimationTree *get_tree() { return tree; }
+ void add_plugin(AnimationTreeNodeEditorPlugin *p_editor);
+ void remove_plugin(AnimationTreeNodeEditorPlugin *p_editor);
+
+ String get_base_path();
+
+ bool can_edit(const Ref<AnimationNode> &p_node) const;
+
+ void edit_path(const Vector<String> &p_path);
+ Vector<String> get_edited_path() const;
+
+ void enter_editor(const String &p_path = "");
+ static AnimationTreeEditor *get_singleton() { return singleton; }
+ void edit(AnimationTree *p_tree);
AnimationTreeEditor();
};
@@ -174,7 +72,7 @@ class AnimationTreeEditorPlugin : public EditorPlugin {
Button *button;
public:
- virtual String get_name() const { return "AnimTree"; }
+ virtual String get_name() const { return "AnimationTree"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
diff --git a/editor/plugins/animation_tree_player_editor_plugin.cpp b/editor/plugins/animation_tree_player_editor_plugin.cpp
new file mode 100644
index 0000000000..36d10ab99e
--- /dev/null
+++ b/editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -0,0 +1,1446 @@
+/*************************************************************************/
+/* animation_tree_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "animation_tree_player_editor_plugin.h"
+
+#include "core/io/resource_loader.h"
+#include "core/project_settings.h"
+#include "os/input.h"
+#include "os/keyboard.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/panel.h"
+#include "scene/main/viewport.h"
+
+void AnimationTreePlayerEditor::edit(AnimationTreePlayer *p_anim_tree) {
+
+ anim_tree = p_anim_tree;
+
+ if (!anim_tree) {
+ hide();
+ } else {
+ order.clear();
+ p_anim_tree->get_node_list(&order);
+ /*
+ for(List<StringName>::Element* E=order.front();E;E=E->next()) {
+
+ if (E->get() >= (int)last_id)
+ last_id=E->get()+1;
+ }*/
+ play_button->set_pressed(p_anim_tree->is_active());
+ //read the orders
+ }
+}
+
+Size2 AnimationTreePlayerEditor::_get_maximum_size() {
+
+ Size2 max;
+
+ for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
+
+ Point2 pos = anim_tree->node_get_position(E->get());
+
+ if (click_type == CLICK_NODE && click_node == E->get()) {
+
+ pos += click_motion - click_pos;
+ }
+ pos += get_node_size(E->get());
+ if (pos.x > max.x)
+ max.x = pos.x;
+ if (pos.y > max.y)
+ max.y = pos.y;
+ }
+
+ return max;
+}
+
+const char *AnimationTreePlayerEditor::_node_type_names[] = { "Output", "Animation", "OneShot", "Mix", "Blend2", "Blend3", "Blend4", "TimeScale", "TimeSeek", "Transition" };
+
+Size2 AnimationTreePlayerEditor::get_node_size(const StringName &p_node) const {
+
+ AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
+
+ Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Ref<Font> font = get_font("font", "PopupMenu");
+
+ Size2 size = style->get_minimum_size();
+
+ int count = 2; // title and name
+ int inputs = anim_tree->node_get_input_count(p_node);
+ count += inputs ? inputs : 1;
+ String name = p_node;
+
+ float name_w = font->get_string_size(name).width;
+ float type_w = font->get_string_size(String(_node_type_names[type])).width;
+ float max_w = MAX(name_w, type_w);
+
+ switch (type) {
+ case AnimationTreePlayer::NODE_TIMESEEK:
+ case AnimationTreePlayer::NODE_OUTPUT: {
+ } break;
+ case AnimationTreePlayer::NODE_ANIMATION:
+ case AnimationTreePlayer::NODE_ONESHOT:
+ case AnimationTreePlayer::NODE_MIX:
+ case AnimationTreePlayer::NODE_BLEND2:
+ case AnimationTreePlayer::NODE_BLEND3:
+ case AnimationTreePlayer::NODE_BLEND4:
+ case AnimationTreePlayer::NODE_TIMESCALE:
+ case AnimationTreePlayer::NODE_TRANSITION: {
+
+ size.height += font->get_height();
+ } break;
+ case AnimationTreePlayer::NODE_MAX: {
+ }
+ }
+
+ size.x += max_w + 20;
+ size.y += count * (font->get_height() + get_constant("vseparation", "PopupMenu"));
+
+ return size;
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_changede(String) {
+
+ edit_dialog->hide();
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_changeds(String s) {
+
+ _edit_dialog_changed();
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_changedf(float) {
+
+ _edit_dialog_changed();
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_changed() {
+
+ if (updating_edit)
+ return;
+
+ if (renaming_edit) {
+
+ if (anim_tree->node_rename(edited_node, edit_line[0]->get_text()) == OK) {
+ for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
+
+ if (E->get() == edited_node)
+ E->get() = edit_line[0]->get_text();
+ }
+ edited_node = edit_line[0]->get_text();
+ }
+ update();
+ return;
+ }
+
+ AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
+
+ switch (type) {
+
+ case AnimationTreePlayer::NODE_TIMESCALE:
+ anim_tree->timescale_node_set_scale(edited_node, edit_line[0]->get_text().to_double());
+ break;
+ case AnimationTreePlayer::NODE_ONESHOT:
+ anim_tree->oneshot_node_set_fadein_time(edited_node, edit_line[0]->get_text().to_double());
+ anim_tree->oneshot_node_set_fadeout_time(edited_node, edit_line[1]->get_text().to_double());
+ anim_tree->oneshot_node_set_autorestart_delay(edited_node, edit_line[2]->get_text().to_double());
+ anim_tree->oneshot_node_set_autorestart_random_delay(edited_node, edit_line[3]->get_text().to_double());
+ anim_tree->oneshot_node_set_autorestart(edited_node, edit_check->is_pressed());
+ anim_tree->oneshot_node_set_mix_mode(edited_node, edit_option->get_selected());
+
+ break;
+
+ case AnimationTreePlayer::NODE_MIX:
+
+ anim_tree->mix_node_set_amount(edited_node, edit_scroll[0]->get_value());
+ break;
+ case AnimationTreePlayer::NODE_BLEND2:
+ anim_tree->blend2_node_set_amount(edited_node, edit_scroll[0]->get_value());
+
+ break;
+
+ case AnimationTreePlayer::NODE_BLEND3:
+ anim_tree->blend3_node_set_amount(edited_node, edit_scroll[0]->get_value());
+
+ break;
+ case AnimationTreePlayer::NODE_BLEND4:
+
+ anim_tree->blend4_node_set_amount(edited_node, Point2(edit_scroll[0]->get_value(), edit_scroll[1]->get_value()));
+
+ break;
+
+ case AnimationTreePlayer::NODE_TRANSITION: {
+ anim_tree->transition_node_set_xfade_time(edited_node, edit_line[0]->get_text().to_double());
+ if (anim_tree->transition_node_get_current(edited_node) != edit_option->get_selected())
+ anim_tree->transition_node_set_current(edited_node, edit_option->get_selected());
+ } break;
+ default: {}
+ }
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_animation_changed() {
+
+ Ref<Animation> anim = property_editor->get_variant().operator RefPtr();
+ anim_tree->animation_node_set_animation(edited_node, anim);
+ update();
+}
+
+void AnimationTreePlayerEditor::_edit_dialog_edit_animation() {
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ get_tree()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr());
+ };
+};
+
+void AnimationTreePlayerEditor::_edit_oneshot_start() {
+
+ anim_tree->oneshot_node_start(edited_node);
+}
+
+void AnimationTreePlayerEditor::_play_toggled() {
+
+ anim_tree->set_active(play_button->is_pressed());
+}
+
+void AnimationTreePlayerEditor::_master_anim_menu_item(int p_item) {
+
+ if (p_item == 0)
+ _edit_filters();
+ else {
+
+ String str = master_anim_popup->get_item_text(p_item);
+ anim_tree->animation_node_set_master_animation(edited_node, str);
+ }
+ update();
+}
+
+void AnimationTreePlayerEditor::_popup_edit_dialog() {
+
+ updating_edit = true;
+
+ for (int i = 0; i < 2; i++)
+ edit_scroll[i]->hide();
+
+ for (int i = 0; i < 4; i++) {
+
+ edit_line[i]->hide();
+ edit_label[i]->hide();
+ }
+
+ edit_option->hide();
+ edit_button->hide();
+ filter_button->hide();
+ edit_check->hide();
+
+ Point2 pos = anim_tree->node_get_position(edited_node) - Point2(h_scroll->get_value(), v_scroll->get_value());
+ Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Size2 size = get_node_size(edited_node);
+ Point2 popup_pos(pos.x + style->get_margin(MARGIN_LEFT), pos.y + size.y - style->get_margin(MARGIN_BOTTOM));
+ popup_pos += get_global_position();
+
+ if (renaming_edit) {
+
+ edit_label[0]->set_text(TTR("New name:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_line[0]->set_begin(Point2(15, 25));
+ edit_line[0]->set_text(edited_node);
+ edit_line[0]->show();
+ edit_dialog->set_size(Size2(150, 50));
+
+ } else {
+
+ AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
+
+ switch (type) {
+
+ case AnimationTreePlayer::NODE_ANIMATION:
+
+ if (anim_tree->get_master_player() != NodePath() && anim_tree->has_node(anim_tree->get_master_player()) && Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player()))) {
+
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player()));
+ master_anim_popup->clear();
+ master_anim_popup->add_item(TTR("Edit Filters"));
+ master_anim_popup->add_separator();
+ List<StringName> sn;
+ ap->get_animation_list(&sn);
+ sn.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = sn.front(); E; E = E->next()) {
+ master_anim_popup->add_item(E->get());
+ }
+
+ master_anim_popup->set_position(popup_pos);
+ master_anim_popup->popup();
+ } else {
+ property_editor->edit(this, "", Variant::OBJECT, anim_tree->animation_node_get_animation(edited_node), PROPERTY_HINT_RESOURCE_TYPE, "Animation");
+ property_editor->set_position(popup_pos);
+ property_editor->popup();
+ updating_edit = false;
+ }
+ return;
+ case AnimationTreePlayer::NODE_TIMESCALE:
+ edit_label[0]->set_text(TTR("Scale:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_line[0]->set_begin(Point2(15, 25));
+ edit_line[0]->set_text(rtos(anim_tree->timescale_node_get_scale(edited_node)));
+ edit_line[0]->show();
+ edit_dialog->set_size(Size2(150, 50));
+ break;
+ case AnimationTreePlayer::NODE_ONESHOT:
+ edit_label[0]->set_text(TTR("Fade In (s):"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_line[0]->set_begin(Point2(15, 25));
+ edit_line[0]->set_text(rtos(anim_tree->oneshot_node_get_fadein_time(edited_node)));
+ edit_line[0]->show();
+ edit_label[1]->set_text(TTR("Fade Out (s):"));
+ edit_label[1]->set_position(Point2(5, 55));
+ edit_label[1]->show();
+ edit_line[1]->set_begin(Point2(15, 75));
+ edit_line[1]->set_text(rtos(anim_tree->oneshot_node_get_fadeout_time(edited_node)));
+ edit_line[1]->show();
+
+ edit_option->clear();
+ edit_option->add_item(TTR("Blend"), 0);
+ edit_option->add_item(TTR("Mix"), 1);
+ edit_option->set_begin(Point2(15, 105));
+
+ edit_option->select(anim_tree->oneshot_node_get_mix_mode(edited_node));
+ edit_option->show();
+
+ edit_check->set_text(TTR("Auto Restart:"));
+ edit_check->set_begin(Point2(15, 125));
+ edit_check->set_pressed(anim_tree->oneshot_node_has_autorestart(edited_node));
+ edit_check->show();
+
+ edit_label[2]->set_text(TTR("Restart (s):"));
+ edit_label[2]->set_position(Point2(5, 145));
+ edit_label[2]->show();
+ edit_line[2]->set_begin(Point2(15, 165));
+ edit_line[2]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_delay(edited_node)));
+ edit_line[2]->show();
+ edit_label[3]->set_text(TTR("Random Restart (s):"));
+ edit_label[3]->set_position(Point2(5, 195));
+ edit_label[3]->show();
+ edit_line[3]->set_begin(Point2(15, 215));
+ edit_line[3]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_random_delay(edited_node)));
+ edit_line[3]->show();
+
+ filter_button->set_begin(Point2(10, 245));
+ filter_button->show();
+
+ edit_button->set_begin(Point2(10, 268));
+ edit_button->set_text(TTR("Start!"));
+
+ edit_button->show();
+
+ edit_dialog->set_size(Size2(180, 293));
+
+ break;
+
+ case AnimationTreePlayer::NODE_MIX:
+
+ edit_label[0]->set_text(TTR("Amount:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_scroll[0]->set_min(0);
+ edit_scroll[0]->set_max(1);
+ edit_scroll[0]->set_step(0.01);
+ edit_scroll[0]->set_value(anim_tree->mix_node_get_amount(edited_node));
+ edit_scroll[0]->set_begin(Point2(15, 25));
+ edit_scroll[0]->show();
+ edit_dialog->set_size(Size2(150, 50));
+
+ break;
+ case AnimationTreePlayer::NODE_BLEND2:
+ edit_label[0]->set_text(TTR("Blend:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_scroll[0]->set_min(0);
+ edit_scroll[0]->set_max(1);
+ edit_scroll[0]->set_step(0.01);
+ edit_scroll[0]->set_value(anim_tree->blend2_node_get_amount(edited_node));
+ edit_scroll[0]->set_begin(Point2(15, 25));
+ edit_scroll[0]->show();
+ filter_button->set_begin(Point2(10, 47));
+ filter_button->show();
+ edit_dialog->set_size(Size2(150, 74));
+
+ break;
+
+ case AnimationTreePlayer::NODE_BLEND3:
+ edit_label[0]->set_text(TTR("Blend:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_scroll[0]->set_min(-1);
+ edit_scroll[0]->set_max(1);
+ edit_scroll[0]->set_step(0.01);
+ edit_scroll[0]->set_value(anim_tree->blend3_node_get_amount(edited_node));
+ edit_scroll[0]->set_begin(Point2(15, 25));
+ edit_scroll[0]->show();
+ edit_dialog->set_size(Size2(150, 50));
+
+ break;
+ case AnimationTreePlayer::NODE_BLEND4:
+
+ edit_label[0]->set_text(TTR("Blend 0:"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_scroll[0]->set_min(0);
+ edit_scroll[0]->set_max(1);
+ edit_scroll[0]->set_step(0.01);
+ edit_scroll[0]->set_value(anim_tree->blend4_node_get_amount(edited_node).x);
+ edit_scroll[0]->set_begin(Point2(15, 25));
+ edit_scroll[0]->show();
+ edit_label[1]->set_text(TTR("Blend 1:"));
+ edit_label[1]->set_position(Point2(5, 55));
+ edit_label[1]->show();
+ edit_scroll[1]->set_min(0);
+ edit_scroll[1]->set_max(1);
+ edit_scroll[1]->set_step(0.01);
+ edit_scroll[1]->set_value(anim_tree->blend4_node_get_amount(edited_node).y);
+ edit_scroll[1]->set_begin(Point2(15, 75));
+ edit_scroll[1]->show();
+ edit_dialog->set_size(Size2(150, 100));
+
+ break;
+
+ case AnimationTreePlayer::NODE_TRANSITION: {
+
+ edit_label[0]->set_text(TTR("X-Fade Time (s):"));
+ edit_label[0]->set_position(Point2(5, 5));
+ edit_label[0]->show();
+ edit_line[0]->set_begin(Point2(15, 25));
+ edit_line[0]->set_text(rtos(anim_tree->transition_node_get_xfade_time(edited_node)));
+ edit_line[0]->show();
+
+ edit_label[1]->set_text(TTR("Current:"));
+ edit_label[1]->set_position(Point2(5, 55));
+ edit_label[1]->show();
+ edit_option->set_begin(Point2(15, 75));
+
+ edit_option->clear();
+
+ for (int i = 0; i < anim_tree->transition_node_get_input_count(edited_node); i++) {
+ edit_option->add_item(itos(i), i);
+ }
+
+ edit_option->select(anim_tree->transition_node_get_current(edited_node));
+ edit_option->show();
+ edit_dialog->set_size(Size2(150, 100));
+
+ } break;
+ default: {}
+ }
+ }
+
+ edit_dialog->set_position(popup_pos);
+ edit_dialog->popup();
+
+ updating_edit = false;
+}
+
+void AnimationTreePlayerEditor::_draw_node(const StringName &p_node) {
+
+ RID ci = get_canvas_item();
+ AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
+
+ Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Ref<Font> font = get_font("font", "PopupMenu");
+ Color font_color = get_color("font_color", "PopupMenu");
+ Color font_color_title = get_color("font_color_hover", "PopupMenu");
+ font_color_title.a *= 0.8;
+ Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons");
+
+ Size2 size = get_node_size(p_node);
+ Point2 pos = anim_tree->node_get_position(p_node);
+ if (click_type == CLICK_NODE && click_node == p_node) {
+
+ pos += click_motion - click_pos;
+ if (pos.x < 5)
+ pos.x = 5;
+ if (pos.y < 5)
+ pos.y = 5;
+ }
+
+ pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
+
+ style->draw(ci, Rect2(pos, size));
+
+ float w = size.width - style->get_minimum_size().width;
+ float h = font->get_height() + get_constant("vseparation", "PopupMenu");
+
+ Point2 ofs = style->get_offset() + pos;
+ Point2 ascofs(0, font->get_ascent());
+
+ Color bx = font_color_title;
+ bx.a *= 0.1;
+ draw_rect(Rect2(ofs, Size2(size.width - style->get_minimum_size().width, font->get_height())), bx);
+ font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, String(_node_type_names[type]), font_color_title);
+
+ ofs.y += h;
+ font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, p_node, font_color);
+ ofs.y += h;
+
+ int count = 2; // title and name
+ int inputs = anim_tree->node_get_input_count(p_node);
+ count += inputs ? inputs : 1;
+
+ float icon_h_ofs = Math::floor((font->get_height() - slot_icon->get_height()) / 2.0) + 1;
+
+ if (type != AnimationTreePlayer::NODE_OUTPUT)
+ slot_icon->draw(ci, ofs + Point2(w, icon_h_ofs)); //output
+
+ if (inputs) {
+ for (int i = 0; i < inputs; i++) {
+
+ slot_icon->draw(ci, ofs + Point2(-slot_icon->get_width(), icon_h_ofs));
+ String text;
+ switch (type) {
+
+ case AnimationTreePlayer::NODE_TIMESCALE:
+ case AnimationTreePlayer::NODE_TIMESEEK: text = "in"; break;
+ case AnimationTreePlayer::NODE_OUTPUT: text = "out"; break;
+ case AnimationTreePlayer::NODE_ANIMATION: break;
+ case AnimationTreePlayer::NODE_ONESHOT: text = (i == 0 ? "in" : "add"); break;
+ case AnimationTreePlayer::NODE_BLEND2:
+ case AnimationTreePlayer::NODE_MIX: text = (i == 0 ? "a" : "b"); break;
+ case AnimationTreePlayer::NODE_BLEND3:
+ switch (i) {
+ case 0: text = "b-"; break;
+ case 1: text = "a"; break;
+ case 2: text = "b+"; break;
+ }
+ break;
+
+ case AnimationTreePlayer::NODE_BLEND4:
+ switch (i) {
+ case 0: text = "a0"; break;
+ case 1: text = "b0"; break;
+ case 2: text = "a1"; break;
+ case 3: text = "b1"; break;
+ }
+ break;
+
+ case AnimationTreePlayer::NODE_TRANSITION:
+ text = itos(i);
+ if (anim_tree->transition_node_has_input_auto_advance(p_node, i))
+ text += "->";
+
+ break;
+ default: {}
+ }
+ font->draw(ci, ofs + ascofs + Point2(3, 0), text, font_color);
+
+ ofs.y += h;
+ }
+ } else {
+ ofs.y += h;
+ }
+
+ Ref<StyleBox> pg_bg = get_stylebox("bg", "ProgressBar");
+ Ref<StyleBox> pg_fill = get_stylebox("fill", "ProgressBar");
+ Rect2 pg_rect(ofs, Size2(w, h));
+
+ bool editable = true;
+ switch (type) {
+ case AnimationTreePlayer::NODE_ANIMATION: {
+
+ Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
+ String text;
+ if (anim_tree->animation_node_get_master_animation(p_node) != "")
+ text = anim_tree->animation_node_get_master_animation(p_node);
+ else if (anim.is_null())
+ text = "load...";
+ else
+ text = anim->get_name();
+
+ font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, text, font_color_title);
+
+ } break;
+ case AnimationTreePlayer::NODE_ONESHOT:
+ case AnimationTreePlayer::NODE_MIX:
+ case AnimationTreePlayer::NODE_BLEND2:
+ case AnimationTreePlayer::NODE_BLEND3:
+ case AnimationTreePlayer::NODE_BLEND4:
+ case AnimationTreePlayer::NODE_TIMESCALE:
+ case AnimationTreePlayer::NODE_TRANSITION: {
+
+ font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit...", font_color_title);
+ } break;
+ default: editable = false;
+ }
+
+ if (editable) {
+
+ Ref<Texture> arrow = get_icon("GuiDropdown", "EditorIcons");
+ Point2 arrow_ofs(w - arrow->get_width(), Math::floor((h - arrow->get_height()) / 2));
+ arrow->draw(ci, ofs + arrow_ofs);
+ }
+}
+
+AnimationTreePlayerEditor::ClickType AnimationTreePlayerEditor::_locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const {
+
+ Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Ref<Font> font = get_font("font", "PopupMenu");
+
+ float h = (font->get_height() + get_constant("vseparation", "PopupMenu"));
+
+ for (const List<StringName>::Element *E = order.back(); E; E = E->prev()) {
+
+ StringName node = E->get();
+
+ AnimationTreePlayer::NodeType type = anim_tree->node_get_type(node);
+
+ Point2 pos = anim_tree->node_get_position(node);
+ Size2 size = get_node_size(node);
+
+ pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
+
+ if (!Rect2(pos, size).has_point(p_click))
+ continue;
+
+ if (p_node_id)
+ *p_node_id = node;
+
+ pos = p_click - pos;
+
+ float y = pos.y - style->get_offset().height;
+
+ if (y < 2 * h)
+ return CLICK_NODE;
+ y -= 2 * h;
+
+ int inputs = anim_tree->node_get_input_count(node);
+ int count = MAX(inputs, 1);
+
+ if (inputs == 0 || (pos.x > size.width / 2 && type != AnimationTreePlayer::NODE_OUTPUT)) {
+
+ if (y < count * h) {
+
+ if (p_slot_index)
+ *p_slot_index = 0;
+ return CLICK_OUTPUT_SLOT;
+ }
+ }
+
+ for (int i = 0; i < count; i++) {
+
+ if (y < h) {
+ if (p_slot_index)
+ *p_slot_index = i;
+ return CLICK_INPUT_SLOT;
+ }
+ y -= h;
+ }
+
+ bool has_parameters = type != AnimationTreePlayer::NODE_OUTPUT && type != AnimationTreePlayer::NODE_TIMESEEK;
+ return has_parameters ? CLICK_PARAMETER : CLICK_NODE;
+ }
+
+ return CLICK_NONE;
+}
+
+Point2 AnimationTreePlayerEditor::_get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot) {
+
+ Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
+ Ref<Font> font = get_font("font", "PopupMenu");
+ Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons");
+
+ Size2 size = get_node_size(p_node_id);
+ Point2 pos = anim_tree->node_get_position(p_node_id);
+
+ if (click_type == CLICK_NODE && click_node == p_node_id) {
+
+ pos += click_motion - click_pos;
+ if (pos.x < 5)
+ pos.x = 5;
+ if (pos.y < 5)
+ pos.y = 5;
+ }
+
+ pos -= Point2(h_scroll->get_value(), v_scroll->get_value());
+
+ float w = size.width - style->get_minimum_size().width;
+ float h = font->get_height() + get_constant("vseparation", "PopupMenu");
+
+ pos += style->get_offset();
+
+ pos.y += h * 2;
+
+ pos.y += h * p_slot;
+
+ pos += Point2(-slot_icon->get_width() / 2.0, h / 2.0).floor();
+
+ if (!p_input) {
+ pos.x += w + slot_icon->get_width();
+ }
+
+ return pos;
+}
+
+void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) {
+
+ Ref<InputEventMouseButton> mb = p_event;
+
+ if (mb.is_valid()) {
+
+ if (mb->is_pressed()) {
+
+ if (mb->get_button_index() == 1) {
+ click_pos = Point2(mb->get_position().x, mb->get_position().y);
+ click_motion = click_pos;
+ click_type = _locate_click(click_pos, &click_node, &click_slot);
+ if (click_type != CLICK_NONE) {
+
+ order.erase(click_node);
+ order.push_back(click_node);
+ update();
+ }
+
+ switch (click_type) {
+ case CLICK_INPUT_SLOT: {
+ click_pos = _get_slot_pos(click_node, true, click_slot);
+ } break;
+ case CLICK_OUTPUT_SLOT: {
+ click_pos = _get_slot_pos(click_node, false, click_slot);
+ } break;
+ case CLICK_PARAMETER: {
+
+ edited_node = click_node;
+ renaming_edit = false;
+ _popup_edit_dialog();
+ //open editor
+ //_node_edit_property(click_node);
+ } break;
+ default: {}
+ }
+ }
+ if (mb->get_button_index() == 2) {
+
+ if (click_type != CLICK_NONE) {
+ click_type = CLICK_NONE;
+ update();
+ } else {
+ // try to disconnect/remove
+
+ Point2 rclick_pos = Point2(mb->get_position().x, mb->get_position().y);
+ rclick_type = _locate_click(rclick_pos, &rclick_node, &rclick_slot);
+ if (rclick_type == CLICK_INPUT_SLOT || rclick_type == CLICK_OUTPUT_SLOT) {
+
+ node_popup->clear();
+ node_popup->set_size(Size2(1, 1));
+ node_popup->add_item(TTR("Disconnect"), NODE_DISCONNECT);
+ if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) {
+ node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
+ if (rclick_type == CLICK_INPUT_SLOT) {
+ if (anim_tree->transition_node_has_input_auto_advance(rclick_node, rclick_slot))
+ node_popup->add_item(TTR("Clear Auto-Advance"), NODE_CLEAR_AUTOADVANCE);
+ else
+ node_popup->add_item(TTR("Set Auto-Advance"), NODE_SET_AUTOADVANCE);
+ node_popup->add_item(TTR("Delete Input"), NODE_DELETE_INPUT);
+ }
+ }
+
+ node_popup->set_position(rclick_pos + get_global_position());
+ node_popup->popup();
+ }
+
+ if (rclick_type == CLICK_NODE) {
+ node_popup->clear();
+ node_popup->set_size(Size2(1, 1));
+ node_popup->add_item(TTR("Rename"), NODE_RENAME);
+ node_popup->add_item(TTR("Remove"), NODE_ERASE);
+ if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION)
+ node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
+ node_popup->set_position(rclick_pos + get_global_position());
+ node_popup->popup();
+ }
+ }
+ }
+ } else {
+
+ if (mb->get_button_index() == 1 && click_type != CLICK_NONE) {
+
+ switch (click_type) {
+ case CLICK_INPUT_SLOT:
+ case CLICK_OUTPUT_SLOT: {
+
+ Point2 dst_click_pos = Point2(mb->get_position().x, mb->get_position().y);
+ StringName id;
+ int slot;
+ ClickType dst_click_type = _locate_click(dst_click_pos, &id, &slot);
+
+ if (dst_click_type == CLICK_INPUT_SLOT && click_type == CLICK_OUTPUT_SLOT) {
+
+ anim_tree->connect_nodes(click_node, id, slot);
+ }
+ if (click_type == CLICK_INPUT_SLOT && dst_click_type == CLICK_OUTPUT_SLOT) {
+
+ anim_tree->connect_nodes(id, click_node, click_slot);
+ }
+
+ } break;
+ case CLICK_NODE: {
+ Point2 new_pos = anim_tree->node_get_position(click_node) + (click_motion - click_pos);
+ if (new_pos.x < 5)
+ new_pos.x = 5;
+ if (new_pos.y < 5)
+ new_pos.y = 5;
+ anim_tree->node_set_position(click_node, new_pos);
+
+ } break;
+ default: {}
+ }
+
+ click_type = CLICK_NONE;
+ update();
+ }
+ }
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+
+ if (mm->get_button_mask() & 1 && click_type != CLICK_NONE) {
+
+ click_motion = Point2(mm->get_position().x, mm->get_position().y);
+ update();
+ }
+ if ((mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE))) {
+
+ h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
+ v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
+ update();
+ }
+ }
+}
+
+void AnimationTreePlayerEditor::_draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color) {
+
+ static const int steps = 20;
+
+ Rect2 r;
+ r.position = p_from;
+ r.expand_to(p_to);
+ Vector2 sign = Vector2((p_from.x < p_to.x) ? 1 : -1, (p_from.y < p_to.y) ? 1 : -1);
+ bool flip = sign.x * sign.y < 0;
+
+ Vector2 prev;
+ for (int i = 0; i <= steps; i++) {
+
+ float d = i / float(steps);
+ float c = -Math::cos(d * Math_PI) * 0.5 + 0.5;
+ if (flip)
+ c = 1.0 - c;
+ Vector2 p = r.position + Vector2(d * r.size.width, c * r.size.height);
+
+ if (i > 0) {
+
+ draw_line(prev, p, p_color, 2);
+ }
+
+ prev = p;
+ }
+}
+
+void AnimationTreePlayerEditor::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ play_button->set_icon(get_icon("Play", "EditorIcons"));
+ add_menu->set_icon(get_icon("Add", "EditorIcons"));
+ } break;
+ case NOTIFICATION_DRAW: {
+
+ _update_scrollbars();
+ //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1));
+ get_stylebox("bg", "Tree")->draw(get_canvas_item(), Rect2(Point2(), get_size()));
+
+ for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
+
+ _draw_node(E->get());
+ }
+
+ if (click_type == CLICK_INPUT_SLOT || click_type == CLICK_OUTPUT_SLOT) {
+
+ _draw_cos_line(click_pos, click_motion, Color(0.5, 1, 0.5, 0.8));
+ }
+
+ List<AnimationTreePlayer::Connection> connections;
+ anim_tree->get_connection_list(&connections);
+
+ for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
+
+ const AnimationTreePlayer::Connection &c = E->get();
+ Point2 source = _get_slot_pos(c.src_node, false, 0);
+ Point2 dest = _get_slot_pos(c.dst_node, true, c.dst_input);
+ Color col = Color(1, 1, 0.5, 0.8);
+ /*
+ if (click_type==CLICK_NODE && click_node==c.src_node) {
+
+ source+=click_motion-click_pos;
+ }
+
+ if (click_type==CLICK_NODE && click_node==c.dst_node) {
+
+ dest+=click_motion-click_pos;
+ }*/
+
+ _draw_cos_line(source, dest, col);
+ }
+
+ switch (anim_tree->get_last_error()) {
+
+ case AnimationTreePlayer::CONNECT_OK: {
+
+ Ref<Font> f = get_font("font", "Label");
+ f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is valid."), Color(0, 1, 0.6, 0.8));
+ } break;
+ default: {
+
+ Ref<Font> f = get_font("font", "Label");
+ f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is invalid."), Color(1, 0.6, 0.0, 0.8));
+ } break;
+ }
+
+ } break;
+ }
+}
+
+void AnimationTreePlayerEditor::_update_scrollbars() {
+
+ Size2 size = get_size();
+ Size2 hmin = h_scroll->get_combined_minimum_size();
+ Size2 vmin = v_scroll->get_combined_minimum_size();
+
+ v_scroll->set_begin(Point2(size.width - vmin.width, 0));
+ v_scroll->set_end(Point2(size.width, size.height));
+
+ h_scroll->set_begin(Point2(0, size.height - hmin.height));
+ h_scroll->set_end(Point2(size.width - vmin.width, size.height));
+
+ Size2 min = _get_maximum_size();
+
+ if (min.height < size.height - hmin.height) {
+
+ v_scroll->hide();
+ offset.y = 0;
+ } else {
+
+ v_scroll->show();
+ v_scroll->set_max(min.height);
+ v_scroll->set_page(size.height - hmin.height);
+ offset.y = v_scroll->get_value();
+ }
+
+ if (min.width < size.width - vmin.width) {
+
+ h_scroll->hide();
+ offset.x = 0;
+ } else {
+
+ h_scroll->show();
+ h_scroll->set_max(min.width);
+ h_scroll->set_page(size.width - vmin.width);
+ offset.x = h_scroll->get_value();
+ }
+}
+
+void AnimationTreePlayerEditor::_scroll_moved(float) {
+
+ offset.x = h_scroll->get_value();
+ offset.y = v_scroll->get_value();
+ update();
+}
+
+void AnimationTreePlayerEditor::_node_menu_item(int p_item) {
+
+ switch (p_item) {
+
+ case NODE_DISCONNECT: {
+
+ if (rclick_type == CLICK_INPUT_SLOT) {
+
+ anim_tree->disconnect_nodes(rclick_node, rclick_slot);
+ update();
+ }
+
+ if (rclick_type == CLICK_OUTPUT_SLOT) {
+
+ List<AnimationTreePlayer::Connection> connections;
+ anim_tree->get_connection_list(&connections);
+
+ for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
+
+ const AnimationTreePlayer::Connection &c = E->get();
+ if (c.dst_node == rclick_node) {
+
+ anim_tree->disconnect_nodes(c.dst_node, c.dst_input);
+ }
+ }
+ update();
+ }
+
+ } break;
+ case NODE_RENAME: {
+
+ renaming_edit = true;
+ edited_node = rclick_node;
+ _popup_edit_dialog();
+
+ } break;
+ case NODE_ADD_INPUT: {
+
+ anim_tree->transition_node_set_input_count(rclick_node, anim_tree->transition_node_get_input_count(rclick_node) + 1);
+ update();
+ } break;
+ case NODE_DELETE_INPUT: {
+
+ anim_tree->transition_node_delete_input(rclick_node, rclick_slot);
+ update();
+ } break;
+ case NODE_SET_AUTOADVANCE: {
+
+ anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, true);
+ update();
+
+ } break;
+ case NODE_CLEAR_AUTOADVANCE: {
+
+ anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, false);
+ update();
+
+ } break;
+
+ case NODE_ERASE: {
+
+ if (rclick_node == "out")
+ break;
+ order.erase(rclick_node);
+ anim_tree->remove_node(rclick_node);
+ update();
+ } break;
+ }
+}
+
+StringName AnimationTreePlayerEditor::_add_node(int p_item) {
+
+ static const char *bname[] = {
+ "out",
+ "anim",
+ "oneshot",
+ "mix",
+ "blend2",
+ "blend3",
+ "blend4",
+ "scale",
+ "seek",
+ "transition"
+ };
+
+ String name;
+ int idx = 1;
+
+ while (true) {
+
+ name = bname[p_item];
+ if (idx > 1)
+ name += " " + itos(idx);
+ if (anim_tree->node_exists(name))
+ idx++;
+ else
+ break;
+ }
+
+ anim_tree->add_node((AnimationTreePlayer::NodeType)p_item, name);
+ anim_tree->node_set_position(name, Point2(last_x, last_y));
+ order.push_back(name);
+ last_x += 10;
+ last_y += 10;
+ last_x = last_x % (int)get_size().width;
+ last_y = last_y % (int)get_size().height;
+ update();
+
+ return name;
+};
+
+void AnimationTreePlayerEditor::_file_dialog_selected(String p_path) {
+
+ switch (file_op) {
+
+ case MENU_IMPORT_ANIMATIONS: {
+ Vector<String> files = file_dialog->get_selected_files();
+
+ for (int i = 0; i < files.size(); i++) {
+
+ StringName node = _add_node(AnimationTreePlayer::NODE_ANIMATION);
+
+ RES anim = ResourceLoader::load(files[i]);
+ anim_tree->animation_node_set_animation(node, anim);
+ //anim_tree->node_set_name(node, files[i].get_file());
+ };
+ } break;
+
+ default:
+ break;
+ };
+};
+
+void AnimationTreePlayerEditor::_add_menu_item(int p_item) {
+
+ if (p_item == MENU_GRAPH_CLEAR) {
+
+ //clear
+ } else if (p_item == MENU_IMPORT_ANIMATIONS) {
+
+ file_op = MENU_IMPORT_ANIMATIONS;
+ file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ file_dialog->popup_centered_ratio();
+
+ } else {
+
+ _add_node(p_item);
+ }
+}
+
+Size2 AnimationTreePlayerEditor::get_minimum_size() const {
+
+ return Size2(10, 200);
+}
+
+void AnimationTreePlayerEditor::_find_paths_for_filter(const StringName &p_node, Set<String> &paths) {
+
+ ERR_FAIL_COND(!anim_tree->node_exists(p_node));
+
+ for (int i = 0; i < anim_tree->node_get_input_count(p_node); i++) {
+
+ StringName port = anim_tree->node_get_input_source(p_node, i);
+ if (port == StringName())
+ continue;
+ _find_paths_for_filter(port, paths);
+ }
+
+ if (anim_tree->node_get_type(p_node) == AnimationTreePlayer::NODE_ANIMATION) {
+
+ Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
+ if (anim.is_valid()) {
+
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ paths.insert(anim->track_get_path(i));
+ }
+ }
+ }
+}
+
+void AnimationTreePlayerEditor::_filter_edited() {
+
+ TreeItem *ed = filter->get_edited();
+ if (!ed)
+ return;
+
+ if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
+ anim_tree->oneshot_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
+ } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
+ anim_tree->blend2_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
+ } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
+ anim_tree->animation_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
+ }
+}
+
+void AnimationTreePlayerEditor::_edit_filters() {
+
+ filter_dialog->popup_centered_ratio();
+ filter->clear();
+
+ Set<String> npb;
+ _find_paths_for_filter(edited_node, npb);
+
+ TreeItem *root = filter->create_item();
+ filter->set_hide_root(true);
+ Map<String, TreeItem *> pm;
+
+ Node *base = anim_tree->get_node(anim_tree->get_base_path());
+
+ for (Set<String>::Element *E = npb.front(); E; E = E->next()) {
+
+ TreeItem *parent = root;
+ String descr = E->get();
+ if (base) {
+ NodePath np = E->get();
+
+ if (np.get_subname_count() == 1) {
+ Node *n = base->get_node(np);
+ Skeleton *s = Object::cast_to<Skeleton>(n);
+ if (s) {
+
+ String skelbase = E->get().substr(0, E->get().find(":"));
+
+ int bidx = s->find_bone(np.get_subname(0));
+
+ if (bidx != -1) {
+ int bparent = s->get_bone_parent(bidx);
+ //
+ if (bparent != -1) {
+
+ String bpn = skelbase + ":" + s->get_bone_name(bparent);
+ if (pm.has(bpn)) {
+ parent = pm[bpn];
+ descr = np.get_subname(0);
+ }
+ } else {
+
+ if (pm.has(skelbase)) {
+ parent = pm[skelbase];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ TreeItem *it = filter->create_item(parent);
+ it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ it->set_text(0, descr);
+ it->set_metadata(0, NodePath(E->get()));
+ it->set_editable(0, true);
+ if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
+ it->set_checked(0, anim_tree->oneshot_node_is_path_filtered(edited_node, E->get()));
+ } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
+ it->set_checked(0, anim_tree->blend2_node_is_path_filtered(edited_node, E->get()));
+ } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
+ it->set_checked(0, anim_tree->animation_node_is_path_filtered(edited_node, E->get()));
+ }
+ pm[E->get()] = it;
+ }
+}
+
+void AnimationTreePlayerEditor::_bind_methods() {
+
+ ClassDB::bind_method("_add_menu_item", &AnimationTreePlayerEditor::_add_menu_item);
+ ClassDB::bind_method("_node_menu_item", &AnimationTreePlayerEditor::_node_menu_item);
+ ClassDB::bind_method("_gui_input", &AnimationTreePlayerEditor::_gui_input);
+ //ClassDB::bind_method( "_node_param_changed", &AnimationTreeEditor::_node_param_changed );
+ ClassDB::bind_method("_scroll_moved", &AnimationTreePlayerEditor::_scroll_moved);
+ ClassDB::bind_method("_edit_dialog_changeds", &AnimationTreePlayerEditor::_edit_dialog_changeds);
+ ClassDB::bind_method("_edit_dialog_changede", &AnimationTreePlayerEditor::_edit_dialog_changede);
+ ClassDB::bind_method("_edit_dialog_changedf", &AnimationTreePlayerEditor::_edit_dialog_changedf);
+ ClassDB::bind_method("_edit_dialog_changed", &AnimationTreePlayerEditor::_edit_dialog_changed);
+ ClassDB::bind_method("_edit_dialog_animation_changed", &AnimationTreePlayerEditor::_edit_dialog_animation_changed);
+ ClassDB::bind_method("_edit_dialog_edit_animation", &AnimationTreePlayerEditor::_edit_dialog_edit_animation);
+ ClassDB::bind_method("_play_toggled", &AnimationTreePlayerEditor::_play_toggled);
+ ClassDB::bind_method("_edit_oneshot_start", &AnimationTreePlayerEditor::_edit_oneshot_start);
+ ClassDB::bind_method("_file_dialog_selected", &AnimationTreePlayerEditor::_file_dialog_selected);
+ ClassDB::bind_method("_master_anim_menu_item", &AnimationTreePlayerEditor::_master_anim_menu_item);
+ ClassDB::bind_method("_edit_filters", &AnimationTreePlayerEditor::_edit_filters);
+ ClassDB::bind_method("_filter_edited", &AnimationTreePlayerEditor::_filter_edited);
+}
+
+AnimationTreePlayerEditor::AnimationTreePlayerEditor() {
+
+ set_focus_mode(FOCUS_ALL);
+
+ PopupMenu *p;
+ List<PropertyInfo> defaults;
+
+ add_menu = memnew(MenuButton);
+ //add_menu->set_
+ add_menu->set_position(Point2(0, 0));
+ add_menu->set_size(Point2(25, 15));
+ add_child(add_menu);
+
+ p = add_menu->get_popup();
+ p->add_item(TTR("Animation Node"), AnimationTreePlayer::NODE_ANIMATION);
+ p->add_item(TTR("OneShot Node"), AnimationTreePlayer::NODE_ONESHOT);
+ p->add_item(TTR("Mix Node"), AnimationTreePlayer::NODE_MIX);
+ p->add_item(TTR("Blend2 Node"), AnimationTreePlayer::NODE_BLEND2);
+ p->add_item(TTR("Blend3 Node"), AnimationTreePlayer::NODE_BLEND3);
+ p->add_item(TTR("Blend4 Node"), AnimationTreePlayer::NODE_BLEND4);
+ p->add_item(TTR("TimeScale Node"), AnimationTreePlayer::NODE_TIMESCALE);
+ p->add_item(TTR("TimeSeek Node"), AnimationTreePlayer::NODE_TIMESEEK);
+ p->add_item(TTR("Transition Node"), AnimationTreePlayer::NODE_TRANSITION);
+ p->add_separator();
+ p->add_item(TTR("Import Animations..."), MENU_IMPORT_ANIMATIONS); // wtf
+ p->add_separator();
+ p->add_item(TTR("Clear"), MENU_GRAPH_CLEAR);
+
+ p->connect("id_pressed", this, "_add_menu_item");
+
+ play_button = memnew(Button);
+ play_button->set_position(Point2(25, 0));
+ play_button->set_size(Point2(25, 15));
+ add_child(play_button);
+ play_button->set_toggle_mode(true);
+ play_button->connect("pressed", this, "_play_toggled");
+
+ last_x = 50;
+ last_y = 50;
+
+ property_editor = memnew(CustomPropertyEditor);
+ add_child(property_editor);
+ property_editor->connect("variant_changed", this, "_edit_dialog_animation_changed");
+ property_editor->connect("resource_edit_request", this, "_edit_dialog_edit_animation");
+
+ h_scroll = memnew(HScrollBar);
+ v_scroll = memnew(VScrollBar);
+
+ add_child(h_scroll);
+ add_child(v_scroll);
+
+ h_scroll->connect("value_changed", this, "_scroll_moved");
+ v_scroll->connect("value_changed", this, "_scroll_moved");
+
+ node_popup = memnew(PopupMenu);
+ add_child(node_popup);
+ node_popup->set_as_toplevel(true);
+
+ master_anim_popup = memnew(PopupMenu);
+ add_child(master_anim_popup);
+ master_anim_popup->connect("id_pressed", this, "_master_anim_menu_item");
+
+ node_popup->connect("id_pressed", this, "_node_menu_item");
+
+ updating_edit = false;
+
+ edit_dialog = memnew(PopupPanel);
+ //edit_dialog->get_ok()->hide();
+ //edit_dialog->get_cancel()->hide();
+ add_child(edit_dialog);
+
+ edit_option = memnew(OptionButton);
+ edit_option->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ edit_option->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(edit_option);
+ edit_option->connect("item_selected", this, "_edit_dialog_changedf");
+ edit_option->hide();
+
+ for (int i = 0; i < 2; i++) {
+ edit_scroll[i] = memnew(HSlider);
+ edit_scroll[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ edit_scroll[i]->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(edit_scroll[i]);
+ edit_scroll[i]->hide();
+ edit_scroll[i]->connect("value_changed", this, "_edit_dialog_changedf");
+ }
+ for (int i = 0; i < 4; i++) {
+ edit_line[i] = memnew(LineEdit);
+ edit_line[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ edit_line[i]->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(edit_line[i]);
+ edit_line[i]->hide();
+ edit_line[i]->connect("text_changed", this, "_edit_dialog_changeds");
+ edit_line[i]->connect("text_entered", this, "_edit_dialog_changede");
+ edit_label[i] = memnew(Label);
+ edit_dialog->add_child(edit_label[i]);
+ edit_label[i]->hide();
+ }
+
+ edit_button = memnew(Button);
+ edit_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ edit_button->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(edit_button);
+ edit_button->hide();
+ edit_button->connect("pressed", this, "_edit_oneshot_start");
+
+ edit_check = memnew(CheckButton);
+ edit_check->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ edit_check->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(edit_check);
+ edit_check->hide();
+ edit_check->connect("pressed", this, "_edit_dialog_changed");
+
+ file_dialog = memnew(EditorFileDialog);
+ file_dialog->set_enable_multiple_selection(true);
+ file_dialog->set_current_dir(ProjectSettings::get_singleton()->get_resource_path());
+ add_child(file_dialog);
+ file_dialog->connect("file_selected", this, "_file_dialog_selected");
+
+ filter_dialog = memnew(AcceptDialog);
+ filter_dialog->set_title(TTR("Edit Node Filters"));
+ add_child(filter_dialog);
+
+ filter = memnew(Tree);
+ filter_dialog->add_child(filter);
+ //filter_dialog->set_child_rect(filter);
+ filter->connect("item_edited", this, "_filter_edited");
+
+ filter_button = memnew(Button);
+ filter_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
+ filter_button->set_margin(MARGIN_RIGHT, -10);
+ edit_dialog->add_child(filter_button);
+ filter_button->hide();
+ filter_button->set_text(TTR("Filters..."));
+ filter_button->connect("pressed", this, "_edit_filters");
+
+ set_clip_contents(true);
+}
+
+void AnimationTreePlayerEditorPlugin::edit(Object *p_object) {
+
+ anim_tree_editor->edit(Object::cast_to<AnimationTreePlayer>(p_object));
+}
+
+bool AnimationTreePlayerEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_class("AnimationTreePlayer");
+}
+
+void AnimationTreePlayerEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+ //editor->hide_animation_player_editors();
+ //editor->animation_panel_make_visible(true);
+ button->show();
+ editor->make_bottom_panel_item_visible(anim_tree_editor);
+ anim_tree_editor->set_physics_process(true);
+ } else {
+
+ if (anim_tree_editor->is_visible_in_tree())
+ editor->hide_bottom_panel();
+ button->hide();
+ anim_tree_editor->set_physics_process(false);
+ }
+}
+
+AnimationTreePlayerEditorPlugin::AnimationTreePlayerEditorPlugin(EditorNode *p_node) {
+
+ editor = p_node;
+ anim_tree_editor = memnew(AnimationTreePlayerEditor);
+ anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
+
+ button = editor->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor);
+ button->hide();
+}
+
+AnimationTreePlayerEditorPlugin::~AnimationTreePlayerEditorPlugin() {
+}
diff --git a/editor/plugins/animation_tree_player_editor_plugin.h b/editor/plugins/animation_tree_player_editor_plugin.h
new file mode 100644
index 0000000000..d1c5f395e4
--- /dev/null
+++ b/editor/plugins/animation_tree_player_editor_plugin.h
@@ -0,0 +1,187 @@
+/*************************************************************************/
+/* animation_tree_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H
+#define ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H
+
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "editor/property_editor.h"
+#include "scene/animation/animation_tree_player.h"
+#include "scene/gui/button.h"
+#include "scene/gui/popup.h"
+#include "scene/gui/tree.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class AnimationTreePlayerEditor : public Control {
+
+ GDCLASS(AnimationTreePlayerEditor, Control);
+
+ static const char *_node_type_names[];
+
+ enum ClickType {
+ CLICK_NONE,
+ CLICK_NAME,
+ CLICK_NODE,
+ CLICK_INPUT_SLOT,
+ CLICK_OUTPUT_SLOT,
+ CLICK_PARAMETER
+ };
+
+ enum {
+
+ MENU_GRAPH_CLEAR = 100,
+ MENU_IMPORT_ANIMATIONS = 101,
+ NODE_DISCONNECT,
+ NODE_RENAME,
+ NODE_ERASE,
+ NODE_ADD_INPUT,
+ NODE_DELETE_INPUT,
+ NODE_SET_AUTOADVANCE,
+ NODE_CLEAR_AUTOADVANCE
+ };
+
+ bool renaming_edit;
+ StringName edited_node;
+ bool updating_edit;
+ Popup *edit_dialog;
+ HSlider *edit_scroll[2];
+ LineEdit *edit_line[4];
+ OptionButton *edit_option;
+ Label *edit_label[4];
+ Button *edit_button;
+ Button *filter_button;
+ CheckButton *edit_check;
+ EditorFileDialog *file_dialog;
+ int file_op;
+
+ void _popup_edit_dialog();
+
+ void _setup_edit_dialog(const StringName &p_node);
+ PopupMenu *master_anim_popup;
+ PopupMenu *node_popup;
+ PopupMenu *add_popup;
+ HScrollBar *h_scroll;
+ VScrollBar *v_scroll;
+ MenuButton *add_menu;
+
+ CustomPropertyEditor *property_editor;
+
+ AnimationTreePlayer *anim_tree;
+ List<StringName> order;
+ Set<StringName> active_nodes;
+
+ int last_x, last_y;
+
+ Point2 offset;
+ ClickType click_type;
+ Point2 click_pos;
+ StringName click_node;
+ int click_slot;
+ Point2 click_motion;
+ ClickType rclick_type;
+ StringName rclick_node;
+ int rclick_slot;
+
+ Button *play_button;
+
+ Size2 _get_maximum_size();
+ Size2 get_node_size(const StringName &p_node) const;
+ void _draw_node(const StringName &p_node);
+
+ AcceptDialog *filter_dialog;
+ Tree *filter;
+
+ void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color);
+ void _update_scrollbars();
+ void _scroll_moved(float);
+ void _play_toggled();
+ /*
+ void _node_param_changed();
+ void _node_add_callback();
+ void _node_add(VisualServer::AnimationTreeNodeType p_type);
+ void _node_edit_property(const StringName& p_node);
+*/
+
+ void _master_anim_menu_item(int p_item);
+ void _node_menu_item(int p_item);
+ void _add_menu_item(int p_item);
+
+ void _filter_edited();
+ void _find_paths_for_filter(const StringName &p_node, Set<String> &paths);
+ void _edit_filters();
+
+ void _edit_oneshot_start();
+ void _edit_dialog_animation_changed();
+ void _edit_dialog_edit_animation();
+ void _edit_dialog_changeds(String);
+ void _edit_dialog_changede(String);
+ void _edit_dialog_changedf(float);
+ void _edit_dialog_changed();
+ void _dialog_changed() const;
+ ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const;
+ Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot);
+
+ StringName _add_node(int p_item);
+ void _file_dialog_selected(String p_path);
+
+protected:
+ void _notification(int p_what);
+ void _gui_input(Ref<InputEvent> p_event);
+ static void _bind_methods();
+
+public:
+ virtual Size2 get_minimum_size() const;
+ void edit(AnimationTreePlayer *p_anim_tree);
+ AnimationTreePlayerEditor();
+};
+
+class AnimationTreePlayerEditorPlugin : public EditorPlugin {
+
+ GDCLASS(AnimationTreePlayerEditorPlugin, EditorPlugin);
+
+ AnimationTreePlayerEditor *anim_tree_editor;
+ EditorNode *editor;
+ Button *button;
+
+public:
+ virtual String get_name() const { return "AnimTree"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual void make_visible(bool p_visible);
+
+ AnimationTreePlayerEditorPlugin(EditorNode *p_node);
+ ~AnimationTreePlayerEditorPlugin();
+};
+
+#endif // ANIMATION_TREE_EDITOR_PLUGIN_H
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index e98dfceb90..66770d98e5 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -384,14 +384,11 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int
return;
}
- progress->set_max(download->get_body_size());
- progress->set_value(download->get_downloaded_bytes());
-
install->set_disabled(false);
+ status->set_text(TTR("Success!"));
+ // Make the progress bar invisible but don't reflow other Controls around it
+ progress->set_modulate(Color(0, 0, 0, 0));
- progress->set_value(download->get_downloaded_bytes());
-
- status->set_text(TTR("Success!") + " (" + String::humanize_size(download->get_downloaded_bytes()) + ")");
set_process(false);
}
@@ -413,25 +410,46 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) {
if (p_what == NOTIFICATION_PROCESS) {
- progress->set_max(download->get_body_size());
- progress->set_value(download->get_downloaded_bytes());
+ // Make the progress bar visible again when retrying the download
+ progress->set_modulate(Color(1, 1, 1, 1));
+
+ if (download->get_downloaded_bytes() > 0) {
+ progress->set_max(download->get_body_size());
+ progress->set_value(download->get_downloaded_bytes());
+ }
int cstatus = download->get_http_client_status();
- if (cstatus == HTTPClient::STATUS_BODY)
- status->set_text(TTR("Fetching:") + " " + String::humanize_size(download->get_downloaded_bytes()));
+ if (cstatus == HTTPClient::STATUS_BODY) {
+ if (download->get_body_size() > 0) {
+ status->set_text(
+ vformat(
+ TTR("Downloading (%s / %s)..."),
+ String::humanize_size(download->get_downloaded_bytes()),
+ String::humanize_size(download->get_body_size())));
+ } else {
+ // Total file size is unknown, so it cannot be displayed
+ status->set_text(TTR("Downloading..."));
+ }
+ }
if (cstatus != prev_status) {
switch (cstatus) {
case HTTPClient::STATUS_RESOLVING: {
status->set_text(TTR("Resolving..."));
+ progress->set_max(1);
+ progress->set_value(0);
} break;
case HTTPClient::STATUS_CONNECTING: {
status->set_text(TTR("Connecting..."));
+ progress->set_max(1);
+ progress->set_value(0);
} break;
case HTTPClient::STATUS_REQUESTING: {
status->set_text(TTR("Requesting..."));
+ progress->set_max(1);
+ progress->set_value(0);
} break;
default: {}
}
@@ -527,7 +545,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
hb2->add_child(retry);
hb2->add_child(install);
- set_custom_minimum_size(Size2(250, 0));
+ set_custom_minimum_size(Size2(310, 0));
download = memnew(HTTPRequest);
add_child(download);
@@ -554,6 +572,8 @@ void EditorAssetLibrary::_notification(int p_what) {
error_tr->set_texture(get_icon("Error", "EditorIcons"));
reverse->set_icon(get_icon("Sort", "EditorIcons"));
+ filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_clear_button_enabled(true);
error_label->raise();
} break;
@@ -604,6 +624,8 @@ void EditorAssetLibrary::_notification(int p_what) {
library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree"));
error_tr->set_texture(get_icon("Error", "EditorIcons"));
reverse->set_icon(get_icon("Sort", "EditorIcons"));
+ filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_clear_button_enabled(true);
} break;
}
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3738c472e7..72248b62a3 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -375,33 +375,24 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li
// Handles the first element
CanvasItem *canvas_item = p_list.front()->get();
- Rect2 rect;
- if (canvas_item->_edit_use_rect()) {
- rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
- } else {
- rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(Point2()), Size2());
- }
+ Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
// Expand with the other ones
for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) {
CanvasItem *canvas_item = E->get();
Transform2D xform = canvas_item->get_global_transform_with_canvas();
- if (canvas_item->_edit_use_rect()) {
- Rect2 current_rect = canvas_item->_edit_get_rect();
- rect.expand_to(xform.xform(current_rect.position));
- rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
- rect.expand_to(xform.xform(current_rect.position + current_rect.size));
- rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y)));
- } else {
- rect.expand_to(xform.xform(Point2()));
- }
+ Rect2 current_rect = canvas_item->_edit_get_rect();
+ rect.expand_to(xform.xform(current_rect.position));
+ rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
+ rect.expand_to(xform.xform(current_rect.position + current_rect.size));
+ rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y)));
}
return rect;
}
-void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
+void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, bool include_locked_nodes) {
if (!p_node)
return;
if (Object::cast_to<Viewport>(p_node))
@@ -409,12 +400,6 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- /*bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != "";
- bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
- bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
-
- if (!lock_children && editable) {}*/
-
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
if (canvas_item && !canvas_item->is_set_as_toplevel()) {
_expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
@@ -424,28 +409,17 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
}
}
- if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) {
+ if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !canvas_item->has_meta("_edit_lock_"))) {
Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
- if (canvas_item->_edit_use_rect()) {
- Rect2 rect = canvas_item->_edit_get_rect();
- if (r_first) {
- r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
- r_first = false;
- }
- if (r_rect.size != Size2()) {
- r_rect.expand_to(xform.xform(rect.position));
- r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0)));
- r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y)));
- r_rect.expand_to(xform.xform(rect.position + rect.size));
- }
- } else {
- if (r_first) {
- r_rect = Rect2(xform.xform(Point2()), Size2());
- r_first = false;
- } else {
- r_rect.expand_to(xform.xform(Point2()));
- }
+ Rect2 rect = canvas_item->_edit_get_rect();
+ if (r_first) {
+ r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
+ r_first = false;
}
+ r_rect.expand_to(xform.xform(rect.position));
+ r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0)));
+ r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y)));
+ r_rect.expand_to(xform.xform(rect.position + rect.size));
}
}
@@ -2302,14 +2276,14 @@ void CanvasItemEditor::_draw_grid() {
real_grid_offset = grid_offset;
}
- const Color grid_minor_color = get_color("grid_minor_color", "Editor");
+ const Color grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
if (grid_step.x != 0) {
for (int i = 0; i < s.width; i++) {
int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - real_grid_offset.x) / (grid_step.x * Math::pow(2.0, grid_step_multiplier))));
if (i == 0)
last_cell = cell;
if (last_cell != cell)
- viewport->draw_line(Point2(i, 0), Point2(i, s.height), grid_minor_color);
+ viewport->draw_line(Point2(i, 0), Point2(i, s.height), grid_color);
last_cell = cell;
}
}
@@ -2320,7 +2294,7 @@ void CanvasItemEditor::_draw_grid() {
if (i == 0)
last_cell = cell;
if (last_cell != cell)
- viewport->draw_line(Point2(0, i), Point2(s.width, i), grid_minor_color);
+ viewport->draw_line(Point2(0, i), Point2(s.width, i), grid_color);
last_cell = cell;
}
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index adc4010f39..2c943385ad 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -390,7 +390,7 @@ class CanvasItemEditor : public VBoxContainer {
List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
- void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
+ void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Rect2 _get_encompassing_rect(const Node *p_node);
Object *_get_editor_data(Object *p_what);
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 49c54ad67d..f5bdf77973 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -616,8 +616,8 @@ void CurveEditor::_draw() {
Vector2 min_edge = get_world_pos(Vector2(0, view_size.y));
Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0));
- const Color grid_color0 = get_color("grid_major_color", "Editor");
- const Color grid_color1 = get_color("grid_minor_color", "Editor");
+ const Color grid_color0 = Color(1.0, 1.0, 1.0, 0.15);
+ const Color grid_color1 = Color(1.0, 1.0, 1.0, 0.07);
draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0);
draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0);
draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0);
diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp
index c2b17189ef..b50e0dfe88 100644
--- a/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/editor/plugins/particles_2d_editor_plugin.cpp
@@ -68,6 +68,11 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) {
switch (p_idx) {
case MENU_GENERATE_VISIBILITY_RECT: {
+ float gen_time = particles->get_lifetime();
+ if (gen_time < 1.0)
+ generate_seconds->set_value(1.0);
+ else
+ generate_seconds->set_value(trunc(gen_time) + 1.0);
generate_aabb->popup_centered_minsize();
} break;
case MENU_LOAD_EMISSION_MASK: {
@@ -90,6 +95,12 @@ void Particles2DEditorPlugin::_generate_visibility_rect() {
EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
+ bool was_emitting = particles->is_emitting();
+ if (!was_emitting) {
+ particles->set_emitting(true);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
Rect2 rect;
while (running < time) {
@@ -106,6 +117,10 @@ void Particles2DEditorPlugin::_generate_visibility_rect() {
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
}
+ if (!was_emitting) {
+ particles->set_emitting(false);
+ }
+
particles->set_visibility_rect(rect);
}
diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp
index 1f5a4a8a36..6a99dcb9a5 100644
--- a/editor/plugins/particles_editor_plugin.cpp
+++ b/editor/plugins/particles_editor_plugin.cpp
@@ -270,6 +270,12 @@ void ParticlesEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_GENERATE_AABB: {
+ float gen_time = node->get_lifetime();
+
+ if (gen_time < 1.0)
+ generate_seconds->set_value(1.0);
+ else
+ generate_seconds->set_value(trunc(gen_time) + 1.0);
generate_aabb->popup_centered_minsize();
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: {
@@ -323,7 +329,14 @@ void ParticlesEditor::_generate_aabb() {
EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time));
+ bool was_emitting = node->is_emitting();
+ if (!was_emitting) {
+ node->set_emitting(true);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
AABB rect;
+
while (running < time) {
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
@@ -339,6 +352,10 @@ void ParticlesEditor::_generate_aabb() {
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
}
+ if (!was_emitting) {
+ node->set_emitting(false);
+ }
+
node->set_visibility_aabb(rect);
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index af242e2d98..1bb7c98114 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -219,6 +219,9 @@ void ScriptEditorQuickOpen::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", this, "_confirmed");
+
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
} break;
}
}
@@ -839,6 +842,19 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) {
void ScriptEditor::_file_dialog_action(String p_file) {
switch (file_dialog_option) {
+ case FILE_NEW_TEXTFILE: {
+ Error err;
+ FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ if (err) {
+ memdelete(file);
+ editor->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!"));
+ break;
+ }
+ file->close();
+ memdelete(file);
+
+ // fallthrough to open the file.
+ }
case FILE_OPEN: {
List<String> extensions;
@@ -867,7 +883,7 @@ void ScriptEditor::_file_dialog_action(String p_file) {
file_dialog_option = -1;
return;
}
- }
+ } break;
case FILE_SAVE_AS: {
ScriptEditorBase *current = _get_current_editor();
@@ -926,6 +942,15 @@ void ScriptEditor::_menu_option(int p_option) {
script_create_dialog->config("Node", ".gd");
script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE);
} break;
+ case FILE_NEW_TEXTFILE: {
+ file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
+ file_dialog_option = FILE_NEW_TEXTFILE;
+
+ file_dialog->clear_filters();
+ file_dialog->popup_centered_ratio();
+ file_dialog->set_title(TTR("New TextFile..."));
+ } break;
case FILE_OPEN: {
file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
@@ -1934,7 +1959,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
if (!se)
continue;
- if (se->get_edited_resource() == p_resource) {
+ if ((script != NULL && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) {
if (should_open) {
if (tab_container->get_current_tab() != i) {
@@ -2384,9 +2409,23 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->is_pressed()) {
+ switch (mb->get_button_index()) {
+
+ case BUTTON_MIDDLE: {
+ // Right-click selects automatically; middle-click does not.
+ int idx = script_list->get_item_at_position(mb->get_position(), true);
+ if (idx >= 0) {
+ script_list->select(idx);
+ _script_selected(idx);
+ _menu_option(FILE_CLOSE);
+ }
+ } break;
- _make_script_list_context_menu();
+ case BUTTON_RIGHT: {
+ _make_script_list_context_menu();
+ } break;
+ }
}
}
@@ -2894,7 +2933,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(140);
_sort_list_on_update = true;
- script_list->connect("gui_input", this, "_script_list_gui_input");
+ script_list->connect("gui_input", this, "_script_list_gui_input", varray(), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
script_list->set_drag_forwarding(this);
@@ -2957,7 +2996,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(file_menu);
file_menu->set_text(TTR("File"));
file_menu->get_popup()->set_hide_on_window_lose_focus(true);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New")), FILE_NEW);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script")), FILE_NEW);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New TextFile")), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open")), FILE_OPEN);
file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 186c80a5f9..737f17358b 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -130,6 +130,7 @@ class ScriptEditor : public PanelContainer {
EditorNode *editor;
enum {
FILE_NEW,
+ FILE_NEW_TEXTFILE,
FILE_OPEN,
FILE_OPEN_RECENT,
FILE_SAVE,
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 8871d8ac7e..7ad117deb6 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2081,6 +2081,15 @@ void SpatialEditorViewport::set_message(String p_message, float p_time) {
message_time = p_time;
}
+void SpatialEditorPlugin::edited_scene_changed() {
+ for (int i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) {
+ SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i);
+ if (viewport->is_visible()) {
+ viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED);
+ }
+ }
+}
+
void SpatialEditorViewport::_notification(int p_what) {
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
@@ -2824,7 +2833,7 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
dd = 0.0001;
float gsize = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
- gizmo_scale = (gsize / Math::abs(dd));
+ gizmo_scale = (gsize / Math::abs(dd)) * MAX(1, EDSCALE) / viewport_container->get_stretch_shrink();
Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
xform.basis.scale(scale);
@@ -3346,7 +3355,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p
if (root_node) {
list.push_back(root_node);
} else {
- accept->get_ok()->set_text(TTR("OK :("));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("No parent to instance a child at."));
accept->popup_centered_minsize();
_remove_preview();
@@ -3386,6 +3395,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
clicked = 0;
clicked_includes_current = false;
orthogonal = false;
+ lock_rotation = false;
message_time = 0;
zoom_indicator_delay = 0.0;
@@ -3849,10 +3859,6 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
}
}
-int SpatialEditor::get_skeleton_visibility_state() const {
- return view_menu->get_popup()->get_item_state(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON));
-}
-
void SpatialEditor::update_transform_gizmo() {
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4008,9 +4014,9 @@ Dictionary SpatialEditor::get_state() const {
Dictionary gizmos_status;
for (int i = 0; i < gizmo_plugins.size(); i++) {
if (!gizmo_plugins[i]->can_be_hidden()) continue;
- bool checked = gizmos_menu->get_popup()->is_item_checked(gizmos_menu->get_popup()->get_item_index(i));
+ int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
String name = gizmo_plugins[i]->get_name();
- gizmos_status[name] = checked;
+ gizmos_status[name] = state;
}
d["gizmos_status"] = gizmos_status;
@@ -4096,14 +4102,29 @@ void SpatialEditor::set_state(const Dictionary &p_state) {
for (int j = 0; j < gizmo_plugins.size(); ++j) {
if (!gizmo_plugins[j]->can_be_hidden()) continue;
- bool checked = true;
+ int state = EditorSpatialGizmoPlugin::ON_TOP;
for (uint32_t i = 0; i < keys.size(); i++) {
if (gizmo_plugins.write[j]->get_name() == keys[i]) {
- checked = gizmos_status[keys[i]];
+ state = gizmos_status[keys[i]];
}
}
- gizmos_menu->get_popup()->set_item_checked(gizmos_menu->get_popup()->get_item_index(j), checked);
- gizmo_plugins.write[j]->set_hidden(!checked);
+
+ const int idx = gizmos_menu->get_item_index(j);
+
+ gizmos_menu->set_item_multistate(idx, state);
+ gizmo_plugins.write[j]->set_state(state);
+
+ switch (state) {
+ case EditorSpatialGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
+ break;
+ case EditorSpatialGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
+ break;
+ case EditorSpatialGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
+ break;
+ }
}
}
}
@@ -4200,12 +4221,27 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
}
void SpatialEditor::_menu_gizmo_toggled(int p_option) {
- bool is_checked = gizmos_menu->get_popup()->is_item_checked(gizmos_menu->get_popup()->get_item_index(p_option));
- is_checked = !is_checked;
- gizmo_plugins.write[p_option]->set_hidden(!is_checked);
+ const int idx = gizmos_menu->get_item_index(p_option);
+ gizmos_menu->toggle_item_multistate(idx);
- gizmos_menu->get_popup()->set_item_checked(gizmos_menu->get_popup()->get_item_index(p_option), is_checked);
+ // Change icon
+ const int state = gizmos_menu->get_item_state(idx);
+ switch (state) {
+ case EditorSpatialGizmoPlugin::ON_TOP:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible"));
+ break;
+ case EditorSpatialGizmoPlugin::VISIBLE:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray"));
+ break;
+ case EditorSpatialGizmoPlugin::HIDDEN:
+ gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden"));
+ break;
+ }
+
+ gizmo_plugins.write[p_option]->set_state(state);
+
+ update_all_gizmos();
}
void SpatialEditor::_menu_item_pressed(int p_option) {
@@ -4316,10 +4352,13 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
- is_checked = !is_checked;
- VisualServer::get_singleton()->instance_set_visible(origin_instance, is_checked);
+ origin_enabled = !is_checked;
+ VisualServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled);
+ // Update the grid since its appearance depends on whether the origin is enabled
+ _finish_grid();
+ _init_grid();
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), is_checked);
+ view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled);
} break;
case MENU_VIEW_GRID: {
@@ -4382,28 +4421,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
_refresh_menu_icons();
} break;
- case MENU_VISIBILITY_SKELETON: {
-
- const int idx = view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON);
- view_menu->get_popup()->toggle_item_multistate(idx);
-
- // Change icon
- const int state = view_menu->get_popup()->get_item_state(idx);
- switch (state) {
- case 0:
- view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden"));
- break;
- case 1:
- view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible"));
- break;
- case 2:
- view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray"));
- break;
- }
-
- update_all_gizmos();
-
- } break;
}
}
@@ -4513,9 +4530,9 @@ void SpatialEditor::_init_indicators() {
nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
};
- int arrow_sides = 6;
+ int arrow_sides = 16;
- for (int k = 0; k < 6; k++) {
+ for (int k = 0; k < arrow_sides; k++) {
Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
@@ -4599,10 +4616,10 @@ void SpatialEditor::_init_indicators() {
ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
};
- for (int k = 0; k < 32; k++) {
+ for (int k = 0; k < 64; k++) {
- Basis ma(ivec, Math_PI * 2 * float(k) / 32);
- Basis mb(ivec, Math_PI * 2 * float(k + 1) / 32);
+ Basis ma(ivec, Math_PI * 2 * float(k) / 64);
+ Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64);
for (int j = 0; j < 4; j++) {
@@ -4729,14 +4746,13 @@ struct _GizmoPluginComparator {
void SpatialEditor::_init_gizmos_menu() {
_register_all_gizmos();
- PopupMenu *p = gizmos_menu->get_popup();
-
gizmo_plugins.sort_custom<_GizmoPluginComparator>();
for (int i = 0; i < gizmo_plugins.size(); ++i) {
if (!gizmo_plugins[i]->can_be_hidden()) continue;
String plugin_name = gizmo_plugins[i]->get_name();
- p->add_check_item(TTR(plugin_name), i);
+ gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::ON_TOP, i);
+ gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible"));
}
}
@@ -4765,7 +4781,11 @@ void SpatialEditor::_init_grid() {
Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
Color line_color = secondary_grid_color;
- if (j % primary_grid_steps == 0) {
+ if (origin_enabled && j == 0) {
+ // Don't draw the center lines of the grid if the origin is enabled
+ // The origin would overlap the grid lines in this case, causing flickering
+ continue;
+ } else if (j % primary_grid_steps == 0) {
line_color = primary_grid_color;
}
@@ -5020,7 +5040,6 @@ void SpatialEditor::_notification(int p_what) {
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
- view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON), view_menu->get_popup()->get_icon("visibility_visible"));
_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
@@ -5175,9 +5194,10 @@ void SpatialEditor::_register_all_gizmos() {
register_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin)));
register_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin)));
register_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin)));
- register_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin)));
register_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin)));
register_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin)));
+ register_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin)));
register_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
register_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
register_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin)));
@@ -5397,24 +5417,25 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
+ p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
+
+ p->add_separator();
+
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS);
- p->add_separator();
- p->add_multistate_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON);
-
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
p->connect("id_pressed", this, "_menu_item_pressed");
- gizmos_menu = memnew(MenuButton);
- gizmos_menu->set_text(TTR("Gizmos"));
- hbc_menu->add_child(gizmos_menu);
- gizmos_menu->get_popup()->set_hide_on_checkable_item_selection(false);
- gizmos_menu->get_popup()->connect("id_pressed", this, "_menu_gizmo_toggled");
+ gizmos_menu = memnew(PopupMenu);
+ p->add_child(gizmos_menu);
+ gizmos_menu->set_name("GizmosMenu");
+ gizmos_menu->set_hide_on_checkable_item_selection(false);
+ gizmos_menu->connect("id_pressed", this, "_menu_gizmo_toggled");
/* REST OF MENU */
@@ -5662,6 +5683,7 @@ void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color
material->set_albedo(color);
material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN + 1);
if (p_use_vertex_color) {
material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
@@ -5709,6 +5731,7 @@ void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const
icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture);
icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
+ icon->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN);
if (p_on_top && selected) {
icon->set_on_top_of_alpha();
@@ -5755,7 +5778,16 @@ Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name
if (p_gizmo == NULL) return materials[p_name][0];
int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
- return materials[p_name][index];
+
+ Ref<SpatialMaterial> mat = materials[p_name][index];
+
+ if (current_state == ON_TOP && p_gizmo->is_selected()) {
+ mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true);
+ } else {
+ mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false);
+ }
+
+ return mat;
}
Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) {
@@ -5766,7 +5798,7 @@ Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial)
ref->set_plugin(this);
ref->set_spatial_node(p_spatial);
- ref->set_hidden(hidden);
+ ref->set_hidden(current_state == HIDDEN);
current_gizmos.push_back(ref.ptr());
return ref;
@@ -5791,10 +5823,10 @@ bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const {
return false;
}
-void EditorSpatialGizmoPlugin::set_hidden(bool p_hidden) {
- hidden = p_hidden;
+void EditorSpatialGizmoPlugin::set_state(int p_state) {
+ current_state = p_state;
for (int i = 0; i < current_gizmos.size(); ++i) {
- current_gizmos[i]->set_hidden(hidden);
+ current_gizmos[i]->set_hidden(current_state == HIDDEN);
}
}
@@ -5803,7 +5835,7 @@ void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) {
}
EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() {
- hidden = false;
+ current_state = ON_TOP;
}
EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() {
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 42e6a24bc5..5850c0dbf1 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -508,6 +508,7 @@ private:
RID origin;
RID origin_instance;
+ bool origin_enabled;
RID grid[3];
RID grid_instance[3];
bool grid_visible[3]; //currently visible
@@ -560,10 +561,10 @@ private:
MENU_VIEW_USE_4_VIEWPORTS,
MENU_VIEW_ORIGIN,
MENU_VIEW_GRID,
+ MENU_VIEW_GIZMOS_3D_ICONS,
MENU_VIEW_CAMERA_SETTINGS,
MENU_LOCK_SELECTED,
MENU_UNLOCK_SELECTED,
- MENU_VISIBILITY_SKELETON,
MENU_SNAP_TO_FLOOR
};
@@ -571,7 +572,7 @@ private:
Button *tool_option_button[TOOL_OPT_MAX];
MenuButton *transform_menu;
- MenuButton *gizmos_menu;
+ PopupMenu *gizmos_menu;
MenuButton *view_menu;
ToolButton *lock_button;
@@ -675,8 +676,6 @@ public:
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
- int get_skeleton_visibility_state() const;
-
void update_transform_gizmo();
void update_all_gizmos();
void snap_selected_nodes_to_floor();
@@ -743,6 +742,8 @@ public:
virtual void set_state(const Dictionary &p_state);
virtual void clear() { spatial_editor->clear(); }
+ virtual void edited_scene_changed();
+
SpatialEditorPlugin(EditorNode *p_node);
~SpatialEditorPlugin();
};
@@ -751,7 +752,13 @@ class EditorSpatialGizmoPlugin : public Resource {
GDCLASS(EditorSpatialGizmoPlugin, Resource);
- bool hidden;
+public:
+ static const int ON_TOP = 0;
+ static const int VISIBLE = 1;
+ static const int HIDDEN = 2;
+
+private:
+ int current_state;
List<EditorSpatialGizmo *> current_gizmos;
HashMap<String, Vector<Ref<SpatialMaterial> > > materials;
@@ -779,7 +786,7 @@ public:
virtual bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { return false; }
Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial);
- void set_hidden(bool p_hidden);
+ void set_state(int p_state);
void unregister_gizmo(EditorSpatialGizmo *p_gizmo);
EditorSpatialGizmoPlugin();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0419c3d4b1..4a9cbfe535 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -70,7 +70,7 @@ void TextureRegionEditor::_region_draw() {
VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
if (snap_mode == SNAP_GRID) {
- Color grid_color = get_color("grid_major_color", "Editor");
+ Color grid_color = Color(1.0, 1.0, 1.0, 0.15);
Size2 s = edit_draw->get_size();
int last_cell = 0;
@@ -603,7 +603,6 @@ void TextureRegionEditor::_notification(int p_what) {
zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
- icon_zoom->set_texture(get_icon("Zoom", "EditorIcons"));
} break;
}
}
@@ -865,7 +864,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
hb_grid->add_child(sb_step_y);
hb_grid->add_child(memnew(VSeparator));
- hb_grid->add_child(memnew(Label(TTR("Separation:"))));
+ hb_grid->add_child(memnew(Label(TTR("Sep.:"))));
sb_sep_x = memnew(SpinBox);
sb_sep_x->set_min(0);
@@ -898,10 +897,6 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
separator->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb_tools->add_child(separator);
- icon_zoom = memnew(TextureRect);
- icon_zoom->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
- hb_tools->add_child(icon_zoom);
-
zoom_out = memnew(ToolButton);
zoom_out->connect("pressed", this, "_zoom_out");
hb_tools->add_child(zoom_out);
@@ -940,16 +935,15 @@ bool TextureRegionEditorPlugin::handles(Object *p_object) const {
void TextureRegionEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
texture_region_button->show();
- if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region())) {
+ if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region()) || texture_region_button->is_pressed()) {
editor->make_bottom_panel_item_visible(region_editor);
- } else {
- if (texture_region_button->is_pressed())
- region_editor->show();
}
} else {
+ if (region_editor->is_visible_in_tree()) {
+ editor->hide_bottom_panel();
+ }
texture_region_button->hide();
region_editor->edit(NULL);
- region_editor->hide();
}
}
@@ -1001,10 +995,9 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) {
editor = p_node;
region_editor = memnew(TextureRegionEditor(p_node));
- texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor);
- texture_region_button->set_tooltip(TTR("Texture Region Editor"));
-
region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
region_editor->hide();
+
+ texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor);
texture_region_button->hide();
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index bd93be9267..670cc86bbb 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -56,7 +56,6 @@ class TextureRegionEditor : public Control {
friend class TextureRegionEditorPlugin;
MenuButton *snap_mode_button;
- TextureRect *icon_zoom;
ToolButton *zoom_in;
ToolButton *zoom_reset;
ToolButton *zoom_out;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 0b84535c19..3d14db7d0e 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -73,7 +73,8 @@ void TileMapEditor::_notification(int p_what) {
rotate_180->set_icon(get_icon("Rotate180", "EditorIcons"));
rotate_270->set_icon(get_icon("Rotate270", "EditorIcons"));
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
PopupMenu *p = options->get_popup();
p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons"));
@@ -532,10 +533,9 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era
return PoolVector<Vector2>();
}
- for (int i = ids.size() - 1; i >= 0; i--) {
- if (ids[i] == prev_id) {
- return PoolVector<Vector2>();
- }
+ if (ids.size() == 1 && ids[0] == prev_id) {
+ // Same ID, nothing to change
+ return PoolVector<Vector2>();
}
Rect2i r = node->get_used_rect();
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 8d1db5de8f..490ebeca26 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -307,6 +307,11 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", p);
tool_hb->add_child(tool_workspacemode[i]);
}
+ Control *spacer = memnew(Control);
+ spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tool_hb->add_child(spacer);
+ tool_hb->move_child(spacer, (int)WORKSPACE_CREATE_SINGLE);
+
tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true);
workspace_mode = WORKSPACE_EDIT;
@@ -314,9 +319,6 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
main_vb->add_child(memnew(HSeparator));
tool_hb = memnew(HBoxContainer);
- Control *spacer = memnew(Control);
- spacer->set_custom_minimum_size(Size2(30, 0));
- tool_hb->add_child(spacer);
g = Ref<ButtonGroup>(memnew(ButtonGroup));
String label[EDITMODE_MAX] = { "Region", "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" };
@@ -335,7 +337,8 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
edit_mode = EDITMODE_COLLISION;
main_vb->add_child(tool_hb);
- main_vb->add_child(memnew(HSeparator));
+ separator_editmode = memnew(HSeparator);
+ main_vb->add_child(separator_editmode);
toolbar = memnew(HBoxContainer);
Ref<ButtonGroup> tg(memnew(ButtonGroup));
@@ -369,13 +372,17 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
toolbar->add_child(tools[SHAPE_NEW_POLYGON]);
tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true);
tools[SHAPE_NEW_POLYGON]->set_button_group(tg);
- toolbar->add_child(memnew(VSeparator));
+
+ separator_delete = memnew(VSeparator);
+ toolbar->add_child(separator_delete);
tools[SHAPE_DELETE] = memnew(ToolButton);
p = Vector<Variant>();
p.push_back((int)SHAPE_DELETE);
tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p);
toolbar->add_child(tools[SHAPE_DELETE]);
- toolbar->add_child(memnew(VSeparator));
+
+ separator_grid = memnew(VSeparator);
+ toolbar->add_child(separator_grid);
tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton);
tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true);
tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true);
@@ -588,10 +595,16 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[BITMASK_PASTE]->hide();
tools[BITMASK_CLEAR]->hide();
tools[SHAPE_NEW_POLYGON]->hide();
- if (workspace_mode == WORKSPACE_EDIT)
+
+ if (workspace_mode == WORKSPACE_EDIT) {
+ separator_delete->show();
tools[SHAPE_DELETE]->show();
- else
+ } else {
+ separator_delete->hide();
tools[SHAPE_DELETE]->hide();
+ }
+
+ separator_grid->show();
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_GRID_SNAP]->show();
@@ -605,7 +618,11 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[BITMASK_PASTE]->show();
tools[BITMASK_CLEAR]->show();
tools[SHAPE_NEW_POLYGON]->hide();
+
+ separator_delete->hide();
tools[SHAPE_DELETE]->hide();
+
+ separator_grid->hide();
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_GRID_SNAP]->hide();
@@ -621,7 +638,11 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[BITMASK_PASTE]->hide();
tools[BITMASK_CLEAR]->hide();
tools[SHAPE_NEW_POLYGON]->show();
+
+ separator_delete->show();
tools[SHAPE_DELETE]->show();
+
+ separator_grid->show();
tools[SHAPE_KEEP_INSIDE_TILE]->show();
tools[TOOL_GRID_SNAP]->show();
@@ -635,9 +656,14 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[BITMASK_PASTE]->hide();
tools[BITMASK_CLEAR]->hide();
tools[SHAPE_NEW_POLYGON]->hide();
+
+ separator_delete->hide();
tools[SHAPE_DELETE]->hide();
+
+ separator_grid->show();
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_GRID_SNAP]->show();
+
if (edit_mode == EDITMODE_ICON) {
tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it."));
spin_priority->hide();
@@ -661,6 +687,7 @@ void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) {
tool_editmode[EDITMODE_REGION]->show();
tool_editmode[EDITMODE_REGION]->set_pressed(true);
_on_edit_mode_changed(EDITMODE_REGION);
+ separator_editmode->show();
}
}
@@ -2076,6 +2103,7 @@ void TileSetEditor::update_workspace_tile_mode() {
tool_editmode[EDITMODE_REGION]->show();
tool_editmode[EDITMODE_REGION]->set_pressed(true);
_on_edit_mode_changed(EDITMODE_REGION);
+ separator_editmode->show();
return;
}
@@ -2086,12 +2114,16 @@ void TileSetEditor::update_workspace_tile_mode() {
for (int i = 0; i < ZOOM_OUT; i++) {
tools[i]->hide();
}
+ separator_editmode->hide();
+ separator_delete->hide();
+ separator_grid->hide();
return;
}
for (int i = 0; i < EDITMODE_MAX; i++) {
tool_editmode[i]->show();
}
+ separator_editmode->show();
if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) {
if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) {
@@ -2336,12 +2368,10 @@ bool TileSetEditorPlugin::handles(Object *p_node) const {
void TileSetEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
tileset_editor_button->show();
- if (tileset_editor_button->is_pressed()) {
- tileset_editor->show();
- }
+ editor->make_bottom_panel_item_visible(tileset_editor);
get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process");
} else {
- tileset_editor->hide();
+ editor->hide_bottom_panel();
tileset_editor_button->hide();
get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process");
}
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 0c175e718c..23bf68b90f 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -40,12 +40,12 @@
#define WORKSPACE_MARGIN Vector2(10, 10)
class TilesetEditorContext;
-class TileSetEditor : public Panel {
+class TileSetEditor : public Control {
friend class TileSetEditorPlugin;
friend class TilesetEditorContext;
- GDCLASS(TileSetEditor, Panel)
+ GDCLASS(TileSetEditor, Control)
enum TextureToolButtons {
TOOL_TILESET_ADD_TEXTURE,
@@ -131,8 +131,11 @@ class TileSetEditor : public Panel {
Control *workspace;
Button *tool_workspacemode[WORKSPACE_MODE_MAX];
Button *tool_editmode[EDITMODE_MAX];
+ HSeparator *separator_editmode;
HBoxContainer *toolbar;
ToolButton *tools[TOOL_MAX];
+ VSeparator *separator_delete;
+ VSeparator *separator_grid;
SpinBox *spin_priority;
WorkspaceMode workspace_mode;
EditMode edit_mode;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9218fed907..63e89b78ea 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -119,6 +119,9 @@ void VisualShaderEditor::_update_graph() {
if (updating)
return;
+ if (visual_shader.is_null())
+ return;
+
graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE);
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 170546f14c..019d5d382c 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "project_export.h"
+
#include "compressed_translation.h"
#include "editor_data.h"
#include "editor_node.h"
@@ -231,7 +232,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
if (error != String()) {
- Vector<String> items = error.split("\n");
+ Vector<String> items = error.split("\n", false);
error = "";
for (int i = 0; i < items.size(); i++) {
if (i > 0)
@@ -389,7 +390,6 @@ void ProjectExportDialog::_patch_deleted() {
void ProjectExportDialog::_update_parameters(const String &p_edited_property) {
_edit_preset(presets->get_current());
- parameters->update_tree();
}
void ProjectExportDialog::_runnable_pressed() {
@@ -756,7 +756,7 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
if (err != OK) {
- error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted: ") + platform->get_name());
+ error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
error_dialog->show();
error_dialog->popup_centered_minsize(Size2(300, 80));
ERR_PRINT("Failed to export project");
@@ -842,12 +842,10 @@ ProjectExportDialog::ProjectExportDialog() {
settings_vb->add_child(sections);
sections->set_v_size_flags(SIZE_EXPAND_FILL);
- parameters = memnew(PropertyEditor);
+ parameters = memnew(EditorInspector);
sections->add_child(parameters);
parameters->set_name(TTR("Options"));
- parameters->hide_top_label();
parameters->set_v_size_flags(SIZE_EXPAND_FILL);
-
parameters->connect("property_edited", this, "_update_parameters");
VBoxContainer *resources_vb = memnew(VBoxContainer);
@@ -956,7 +954,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_error = memnew(Label);
main_vb->add_child(export_error);
export_error->hide();
- export_error->add_color_override("font_color", get_color("error_color", "Editor"));
+ export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
export_templates_error = memnew(HBoxContainer);
main_vb->add_child(export_templates_error);
@@ -964,7 +962,7 @@ ProjectExportDialog::ProjectExportDialog() {
Label *export_error2 = memnew(Label);
export_templates_error->add_child(export_error2);
- export_error2->add_color_override("font_color", get_color("error_color", "Editor"));
+ export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
error_dialog = memnew(AcceptDialog);
@@ -975,6 +973,7 @@ ProjectExportDialog::ProjectExportDialog() {
LinkButton *download_templates = memnew(LinkButton);
download_templates->set_text(TTR("Manage Export Templates"));
+ download_templates->set_v_size_flags(SIZE_SHRINK_CENTER);
export_templates_error->add_child(download_templates);
download_templates->connect("pressed", this, "_open_export_template_manager");
diff --git a/editor/project_export.h b/editor/project_export.h
index b62254974d..1f8723febd 100644
--- a/editor/project_export.h
+++ b/editor/project_export.h
@@ -31,26 +31,27 @@
#ifndef PROJECT_EXPORT_SETTINGS_H
#define PROJECT_EXPORT_SETTINGS_H
+#include "core/os/dir_access.h"
+#include "core/os/thread.h"
+#include "editor/editor_export.h"
#include "editor/editor_file_dialog.h"
-#include "os/dir_access.h"
-#include "os/thread.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
#include "scene/gui/button.h"
+#include "scene/gui/check_button.h"
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/label.h"
#include "scene/gui/link_button.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/rich_text_label.h"
+#include "scene/gui/slider.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/tree.h"
#include "scene/main/timer.h"
-#include "editor/editor_file_system.h"
-#include "editor_export.h"
-#include "property_editor.h"
-#include "scene/gui/slider.h"
-
class EditorNode;
class ProjectExportDialog : public ConfirmationDialog {
@@ -64,12 +65,9 @@ private:
ItemList *presets;
LineEdit *name;
- PropertyEditor *parameters;
+ EditorInspector *parameters;
CheckButton *runnable;
- //EditorFileDialog *pck_export;
- //EditorFileDialog *file_export;
-
Button *button_export;
bool updating;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 95d39953cf..aad9258ed9 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -915,12 +915,6 @@ void ProjectManager::_update_project_buttons() {
CanvasItem *item = Object::cast_to<CanvasItem>(scroll_children->get_child(i));
item->update();
-
- Button *show = Object::cast_to<Button>(item->get_node(NodePath("project/path_box/show")));
- if (show) {
- String current = item->get_meta("name");
- show->set_visible(selected_list.has(current));
- }
}
bool empty_selection = selected_list.empty();
@@ -1316,7 +1310,6 @@ void ProjectManager::_load_recent_projects() {
path_hb->add_child(show);
show->connect("pressed", this, "_show_project", varray(path));
show->set_tooltip(TTR("Show In File Manager"));
- show->set_visible(false);
Label *fpath = memnew(Label(path));
fpath->set_name("path");
@@ -1757,6 +1750,8 @@ ProjectManager::ProjectManager() {
editor_set_scale(custom_display_scale);
} break;
}
+
+ OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE));
}
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -1782,7 +1777,6 @@ ProjectManager::ProjectManager() {
String cp;
cp += 0xA9;
- cp += '0';
OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors");
HBoxContainer *top_hb = memnew(HBoxContainer);
@@ -1825,7 +1819,7 @@ ProjectManager::ProjectManager() {
project_filter = memnew(ProjectListFilter);
search_box->add_child(project_filter);
project_filter->connect("filter_changed", this, "_load_recent_projects");
- project_filter->set_custom_minimum_size(Size2(250, 10));
+ project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE);
search_tree_vb->add_child(search_box);
PanelContainer *pc = memnew(PanelContainer);
@@ -2023,18 +2017,6 @@ void ProjectListFilter::_setup_filters() {
filter_option->add_item(TTR("Path"));
}
-void ProjectListFilter::_command(int p_command) {
- switch (p_command) {
-
- case CMD_CLEAR_FILTER: {
- if (search_box->get_text() != "") {
- search_box->clear();
- emit_signal("filter_changed");
- }
- } break;
- }
-}
-
void ProjectListFilter::_search_text_changed(const String &p_newtext) {
emit_signal("filter_changed");
}
@@ -2057,13 +2039,14 @@ void ProjectListFilter::_filter_option_selected(int p_idx) {
void ProjectListFilter::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE)
- clear_search_button->set_icon(get_icon("Close", "EditorIcons"));
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ }
}
void ProjectListFilter::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_command"), &ProjectListFilter::_command);
ClassDB::bind_method(D_METHOD("_search_text_changed"), &ProjectListFilter::_search_text_changed);
ClassDB::bind_method(D_METHOD("_filter_option_selected"), &ProjectListFilter::_filter_option_selected);
@@ -2088,8 +2071,4 @@ ProjectListFilter::ProjectListFilter() {
search_box->connect("text_changed", this, "_search_text_changed");
search_box->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(search_box);
-
- clear_search_button = memnew(ToolButton);
- clear_search_button->connect("pressed", this, "_command", make_binds(CMD_CLEAR_FILTER));
- add_child(clear_search_button);
}
diff --git a/editor/project_manager.h b/editor/project_manager.h
index a9d23b1f71..ad21e00b0d 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -128,13 +128,8 @@ class ProjectListFilter : public HBoxContainer {
private:
friend class ProjectManager;
- enum Command {
- CMD_CLEAR_FILTER,
- };
-
OptionButton *filter_option;
LineEdit *search_box;
- ToolButton *clear_search_button;
enum FilterOption {
FILTER_NAME,
@@ -142,7 +137,6 @@ private:
};
FilterOption _current_filter;
- void _command(int p_command);
void _search_text_changed(const String &p_newtext);
void _setup_filters();
void _filter_option_selected(int p_idx);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 2b2e03ce38..970302e058 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -81,7 +81,8 @@ void ProjectSettingsEditor::_notification(int p_what) {
globals_editor->edit(ProjectSettings::get_singleton());
search_button->set_icon(get_icon("Search", "EditorIcons"));
- clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
action_add_error->add_color_override("font_color", get_color("error_color", "Editor"));
@@ -119,7 +120,8 @@ void ProjectSettingsEditor::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
search_button->set_icon(get_icon("Search", "EditorIcons"));
- clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
action_add_error->add_color_override("font_color", get_color("error_color", "Editor"));
popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons"));
popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons"));
@@ -213,10 +215,8 @@ void ProjectSettingsEditor::_action_edited() {
undo_redo->create_action(TTR("Change Action deadzone"));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action);
- undo_redo->add_do_method(this, "_update_actions");
undo_redo->add_do_method(this, "_settings_changed");
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action);
- undo_redo->add_undo_method(this, "_update_actions");
undo_redo->add_undo_method(this, "_settings_changed");
undo_redo->commit_action();
}
@@ -806,6 +806,10 @@ void ProjectSettingsEditor::popup_project_settings() {
plugin_settings->update_plugins();
}
+void ProjectSettingsEditor::update_plugins() {
+ plugin_settings->update_plugins();
+}
+
void ProjectSettingsEditor::_item_selected(const String &p_path) {
String selected_path = p_path;
@@ -1591,15 +1595,6 @@ void ProjectSettingsEditor::_toggle_search_bar(bool p_pressed) {
}
}
-void ProjectSettingsEditor::_clear_search_box() {
-
- if (search_box->get_text() == "")
- return;
-
- search_box->clear();
- globals_editor->get_inspector()->update_tree();
-}
-
void ProjectSettingsEditor::set_plugins_page() {
tab_container->set_current_tab(plugin_settings->get_index());
@@ -1662,7 +1657,6 @@ void ProjectSettingsEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_translation_filter_option_changed"), &ProjectSettingsEditor::_translation_filter_option_changed);
ClassDB::bind_method(D_METHOD("_translation_filter_mode_changed"), &ProjectSettingsEditor::_translation_filter_mode_changed);
- ClassDB::bind_method(D_METHOD("_clear_search_box"), &ProjectSettingsEditor::_clear_search_box);
ClassDB::bind_method(D_METHOD("_toggle_search_bar"), &ProjectSettingsEditor::_toggle_search_bar);
ClassDB::bind_method(D_METHOD("_copy_to_platform_about_to_show"), &ProjectSettingsEditor::_copy_to_platform_about_to_show);
@@ -1753,10 +1747,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_bar->add_child(search_box);
- clear_button = memnew(ToolButton);
- search_bar->add_child(clear_button);
- clear_button->connect("pressed", this, "_clear_search_box");
-
globals_editor = memnew(SectionedInspector);
props_base->add_child(globals_editor);
globals_editor->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo());
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 3b74ae1909..1344da1de7 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -69,7 +69,6 @@ class ProjectSettingsEditor : public AcceptDialog {
HBoxContainer *search_bar;
Button *search_button;
LineEdit *search_box;
- ToolButton *clear_button;
HBoxContainer *add_prop_bar;
AcceptDialog *message;
@@ -158,7 +157,6 @@ class ProjectSettingsEditor : public AcceptDialog {
void _translation_filter_mode_changed(int p_mode);
void _toggle_search_bar(bool p_pressed);
- void _clear_search_box();
void _copy_to_platform_about_to_show();
@@ -188,6 +186,7 @@ public:
static ProjectSettingsEditor *get_singleton() { return singleton; }
void popup_project_settings();
void set_plugins_page();
+ void update_plugins();
EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; }
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index b370a711e3..408e67149a 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -287,7 +287,11 @@ void CustomPropertyEditor::_menu_option(int p_which) {
Object *obj = ClassDB::instance(intype);
if (!obj) {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ if (ScriptServer::is_global_class(intype)) {
+ obj = EditorNode::get_editor_data().script_class_instance(intype);
+ } else {
+ obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ }
}
ERR_BREAK(!obj);
@@ -1132,7 +1136,11 @@ void CustomPropertyEditor::_type_create_selected(int p_idx) {
Object *obj = ClassDB::instance(intype);
if (!obj) {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ if (ScriptServer::is_global_class(intype)) {
+ obj = EditorNode::get_editor_data().script_class_instance(intype);
+ } else {
+ obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ }
}
ERR_FAIL_COND(!obj);
@@ -1334,7 +1342,11 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
Object *obj = ClassDB::instance(intype);
if (!obj) {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ if (ScriptServer::is_global_class(intype)) {
+ obj = EditorNode::get_editor_data().script_class_instance(intype);
+ } else {
+ obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
+ }
}
ERR_BREAK(!obj);
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index 907bb50f7e..d2101f1e00 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -258,6 +258,9 @@ void EditorQuickOpen::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
connect("confirmed", this, "_confirmed");
+
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
}
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index d9419af549..607d974025 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -119,7 +119,7 @@ void SceneTreeDock::instance(const String &p_file) {
if (!edited_scene) {
current_option = -1;
- accept->get_ok()->set_text(TTR("OK :("));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("No parent to instance a child at."));
accept->popup_centered_minsize();
return;
@@ -365,10 +365,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *l = ScriptServer::get_language(i);
if (l->get_type() == existing->get_class()) {
- if (EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
- String name = l->get_global_class_name(existing->get_path(), NULL);
- inherits = editor->get_editor_data().script_class_get_base(name);
- } else if (l->can_inherit_from_file()) {
+ String name = l->get_global_class_name(existing->get_path());
+ if (ScriptServer::is_global_class(name)) {
+ if (EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) {
+ inherits = editor->get_editor_data().script_class_get_base(name);
+ } else if (l->can_inherit_from_file()) {
+ inherits = "\"" + existing->get_path() + "\"";
+ }
+ } else {
inherits = "\"" + existing->get_path() + "\"";
}
}
@@ -395,6 +399,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
const RefPtr empty;
editor_data->get_undo_redo().add_do_method(E->get(), "set_script", empty);
editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
+
+ editor_data->get_undo_redo().add_do_method(E->get(), "set_meta", "_editor_icon", get_icon(E->get()->get_class(), "EditorIcons"));
+ editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", E->get()->get_meta("_editor_icon"));
}
}
@@ -402,7 +409,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
editor_data->get_undo_redo().commit_action();
-
} break;
case TOOL_MOVE_UP:
case TOOL_MOVE_DOWN: {
@@ -797,18 +803,38 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} break;
case TOOL_CREATE_2D_SCENE:
case TOOL_CREATE_3D_SCENE:
- case TOOL_CREATE_USER_INTERFACE: {
+ case TOOL_CREATE_USER_INTERFACE:
+ case TOOL_CREATE_FAVORITE: {
Node *new_node;
- switch (p_tool) {
- case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break;
- case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break;
- case TOOL_CREATE_USER_INTERFACE: {
- Control *node = memnew(Control);
- node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs.
- new_node = node;
- } break;
+ if (TOOL_CREATE_FAVORITE == p_tool) {
+ String name = selected_favorite_root.get_slicec(' ', 0);
+ if (ScriptServer::is_global_class(name)) {
+ new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_base(name)));
+ Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script");
+ if (new_node && script.is_valid()) {
+ new_node->set_script(script.get_ref_ptr());
+ new_node->set_name(name);
+ }
+ } else {
+ new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root));
+ }
+ if (!new_node) {
+ ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead.");
+ new_node = memnew(Node);
+ }
+ } else {
+ switch (p_tool) {
+ case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break;
+ case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break;
+ case TOOL_CREATE_USER_INTERFACE: {
+ Control *node = memnew(Control);
+ node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs.
+ new_node = node;
+
+ } break;
+ }
}
editor_data->get_undo_redo().create_action("New Scene Root");
@@ -862,39 +888,67 @@ void SceneTreeDock::_notification(int p_what) {
button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons"));
button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons"));
- filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_clear_button_enabled(true);
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed");
- create_root_dialog->add_child(memnew(Label(TTR("Create Root Node:"))));
+ // create_root_dialog
+ HBoxContainer *top_row = memnew(HBoxContainer);
+ top_row->set_name("NodeShortcutsTopRow");
+ top_row->set_h_size_flags(SIZE_EXPAND_FILL);
+ top_row->add_child(memnew(Label(TTR("Create Root Node:"))));
+ top_row->add_spacer();
- Button *button_2d = memnew(Button);
- create_root_dialog->add_child(button_2d);
+ ToolButton *node_shortcuts_toggle = memnew(ToolButton);
+ node_shortcuts_toggle->set_name("NodeShortcutsToggle");
+ node_shortcuts_toggle->set_icon(get_icon("Favorites", "EditorIcons"));
+ node_shortcuts_toggle->set_toggle_mode(true);
+ node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
+ node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT);
+ node_shortcuts_toggle->connect("pressed", this, "_update_create_root_dialog");
+ top_row->add_child(node_shortcuts_toggle);
+
+ create_root_dialog->add_child(top_row);
+ VBoxContainer *node_shortcuts = memnew(VBoxContainer);
+ node_shortcuts->set_name("NodeShortcuts");
+
+ VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer);
+ beginner_node_shortcuts->set_name("BeginnerNodeShortcuts");
+ node_shortcuts->add_child(beginner_node_shortcuts);
+
+ Button *button_2d = memnew(Button);
+ beginner_node_shortcuts->add_child(button_2d);
button_2d->set_text(TTR("2D Scene"));
button_2d->set_icon(get_icon("Node2D", "EditorIcons"));
button_2d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_2D_SCENE, false));
Button *button_3d = memnew(Button);
- create_root_dialog->add_child(button_3d);
+ beginner_node_shortcuts->add_child(button_3d);
button_3d->set_text(TTR("3D Scene"));
button_3d->set_icon(get_icon("Spatial", "EditorIcons"));
button_3d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_3D_SCENE, false));
Button *button_ui = memnew(Button);
- create_root_dialog->add_child(button_ui);
+ beginner_node_shortcuts->add_child(button_ui);
button_ui->set_text(TTR("User Interface"));
button_ui->set_icon(get_icon("Control", "EditorIcons"));
button_ui->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_USER_INTERFACE, false));
+ VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer);
+ favorite_node_shortcuts->set_name("FavoriteNodeShortcuts");
+ node_shortcuts->add_child(favorite_node_shortcuts);
+
Button *button_custom = memnew(Button);
- create_root_dialog->add_child(button_custom);
+ node_shortcuts->add_child(button_custom);
button_custom->set_text(TTR("Custom Node"));
button_custom->set_icon(get_icon("Add", "EditorIcons"));
button_custom->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false));
- create_root_dialog->add_spacer();
-
+ node_shortcuts->add_spacer();
+ create_root_dialog->add_child(node_shortcuts);
+ _update_create_root_dialog();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -910,7 +964,8 @@ void SceneTreeDock::_notification(int p_what) {
button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons"));
button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons"));
- filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ filter->set_right_icon(get_icon("Search", "EditorIcons"));
+ filter->set_clear_button_enabled(true);
} break;
case NOTIFICATION_PROCESS: {
@@ -1249,7 +1304,7 @@ bool SceneTreeDock::_validate_no_foreign() {
if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) {
- accept->get_ok()->set_text(TTR("Makes Sense!"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can't operate on nodes from a foreign scene!"));
accept->popup_centered_minsize();
return false;
@@ -1257,7 +1312,7 @@ bool SceneTreeDock::_validate_no_foreign() {
if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) {
- accept->get_ok()->set_text(TTR("Makes Sense!"));
+ accept->get_ok()->set_text(TTR("OK"));
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
accept->popup_centered_minsize();
return false;
@@ -1441,9 +1496,23 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
Ref<Script> existing = E->get()->get_script();
editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script.get_ref_ptr());
editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
+
+ String icon_path;
+ String name = p_script->get_language()->get_global_class_name(p_script->get_path(), NULL, &icon_path);
+ if (ScriptServer::is_global_class(name)) {
+ RES icon = ResourceLoader::load(icon_path);
+ editor_data->get_undo_redo().add_do_method(E->get(), "set_meta", "_editor_icon", icon);
+ String existing_name = existing.is_valid() ? existing->get_language()->get_global_class_name(existing->get_path()) : String();
+ if (existing.is_null() || !ScriptServer::is_global_class(existing_name)) {
+ editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", get_icon(E->get()->get_class(), "EditorIcons"));
+ } else {
+ editor_data->get_undo_redo().add_undo_method(E->get(), "set_meta", "_editor_icon", editor_data->script_class_get_icon_path(existing_name));
+ }
+ }
}
editor_data->get_undo_redo().commit_action();
+ print_line("test: " + String(Variant(selected.front()->get()->get_meta("_editor_icon"))));
editor->push_item(p_script.operator->());
}
@@ -2148,6 +2217,67 @@ void SceneTreeDock::_local_tree_selected() {
edit_local->set_pressed(true);
}
+void SceneTreeDock::_update_create_root_dialog() {
+
+ BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle")));
+ Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcuts"));
+
+ if (!toggle || !node_shortcuts)
+ return;
+
+ Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts")));
+ Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts")));
+
+ if (!beginner_nodes || !favorite_nodes)
+ return;
+
+ EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed());
+ EditorSettings::get_singleton()->save();
+ if (toggle->is_pressed()) {
+
+ for (int i = 0; i < favorite_nodes->get_child_count(); i++) {
+ favorite_nodes->get_child(i)->queue_delete();
+ }
+
+ FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ);
+
+ if (f) {
+
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+
+ if (l != String()) {
+ Button *button = memnew(Button);
+ favorite_nodes->add_child(button);
+ button->set_text(TTR(l));
+ String name = l.get_slicec(' ', 0);
+ if (ScriptServer::is_global_class(name))
+ name = ScriptServer::get_global_class_base(name);
+ button->set_icon(get_icon(name, "EditorIcons"));
+ button->connect("pressed", this, "_favorite_root_selected", make_binds(l));
+ }
+ }
+
+ memdelete(f);
+ }
+
+ if (!favorite_nodes->is_visible_in_tree()) {
+ favorite_nodes->show();
+ beginner_nodes->hide();
+ }
+ } else {
+ if (!beginner_nodes->is_visible_in_tree()) {
+ beginner_nodes->show();
+ favorite_nodes->hide();
+ }
+ }
+}
+
+void SceneTreeDock::_favorite_root_selected(const String &p_class) {
+ selected_favorite_root = p_class;
+ _tool_selected(TOOL_CREATE_FAVORITE, false);
+}
+
void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tool_selected"), &SceneTreeDock::_tool_selected, DEFVAL(false));
@@ -2176,6 +2306,8 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected);
ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected);
ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button);
+ ClassDB::bind_method(D_METHOD("_favorite_root_selected"), &SceneTreeDock::_favorite_root_selected);
+ ClassDB::bind_method(D_METHOD("_update_create_root_dialog"), &SceneTreeDock::_update_create_root_dialog);
ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance);
@@ -2301,6 +2433,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
create_dialog->set_base_type("Node");
add_child(create_dialog);
create_dialog->connect("create", this, "_create");
+ create_dialog->connect("favorites_updated", this, "_update_create_root_dialog");
+ EditorFileSystem::get_singleton()->connect("script_classes_updated", create_dialog, "_save_and_update_favorite_list");
rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo()));
add_child(rename_dialog);
@@ -2347,11 +2481,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
clear_inherit_confirm = memnew(ConfirmationDialog);
clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)"));
- clear_inherit_confirm->get_ok()->set_text(TTR("Clear!"));
+ clear_inherit_confirm->get_ok()->set_text(TTR("Clear"));
add_child(clear_inherit_confirm);
set_process_input(true);
set_process(true);
EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true);
+ EDITOR_DEF("_use_favorites_root_selection", false);
}
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 57f4759747..34a7c98d11 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -86,6 +86,7 @@ class SceneTreeDock : public VBoxContainer {
TOOL_CREATE_2D_SCENE,
TOOL_CREATE_3D_SCENE,
TOOL_CREATE_USER_INTERFACE,
+ TOOL_CREATE_FAVORITE,
};
@@ -141,6 +142,7 @@ class SceneTreeDock : public VBoxContainer {
EditorNode *editor;
VBoxContainer *create_root_dialog;
+ String selected_favorite_root;
void _add_children_to_popup(Object *p_obj, int p_depth);
@@ -201,6 +203,9 @@ class SceneTreeDock : public VBoxContainer {
void _remote_tree_selected();
void _local_tree_selected();
+ void _update_create_root_dialog();
+ void _favorite_root_selected(const String &p_class);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index e483fde4bc..746e1cd28f 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -734,7 +734,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
error_list->set_item_metadata(error_list->get_item_count() - 1, stack);
- error_count++;
+ if (warning)
+ warning_count++;
+ else
+ error_count++;
} else if (p_msg == "profile_sig") {
//cache a signature
@@ -1011,20 +1014,26 @@ void ScriptEditorDebugger::_notification(int p_what) {
}
}
- if (error_count != last_error_count) {
+ if (error_count != last_error_count || warning_count != last_warning_count) {
- if (error_count == 0) {
+ if (error_count == 0 && warning_count == 0) {
error_split->set_name(TTR("Errors"));
debugger_button->set_text(TTR("Debugger"));
debugger_button->set_icon(Ref<Texture>());
tabs->set_tab_icon(error_split->get_index(), Ref<Texture>());
} else {
- error_split->set_name(TTR("Errors") + " (" + itos(error_count) + ")");
- debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count) + ")");
- debugger_button->set_icon(get_icon("Error", "EditorIcons"));
- tabs->set_tab_icon(error_split->get_index(), get_icon("Error", "EditorIcons"));
+ error_split->set_name(TTR("Errors") + " (" + itos(error_count + warning_count) + ")");
+ debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")");
+ if (error_count == 0) {
+ debugger_button->set_icon(get_icon("Warning", "EditorIcons"));
+ tabs->set_tab_icon(error_split->get_index(), get_icon("Warning", "EditorIcons"));
+ } else {
+ debugger_button->set_icon(get_icon("Error", "EditorIcons"));
+ tabs->set_tab_icon(error_split->get_index(), get_icon("Error", "EditorIcons"));
+ }
}
last_error_count = error_count;
+ last_warning_count = warning_count;
}
if (connection.is_null()) {
@@ -1054,6 +1063,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
error_list->clear();
error_stack->clear();
error_count = 0;
+ warning_count = 0;
profiler_signature.clear();
//live_edit_root->set_text("/root");
@@ -1198,7 +1208,7 @@ void ScriptEditorDebugger::start() {
int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
if (server->listen(remote_port) != OK) {
- EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true);
+ EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), EditorLog::MSG_TYPE_ERROR);
return;
}
@@ -1230,6 +1240,9 @@ void ScriptEditorDebugger::stop() {
if (connection.is_valid()) {
EditorNode::get_log()->add_message("** Debug Process Stopped **");
connection.unref();
+
+ reason->set_text("");
+ reason->set_tooltip("");
}
pending_in_queue = 0;
@@ -1750,6 +1763,7 @@ void ScriptEditorDebugger::_clear_errors_list() {
error_list->clear();
error_count = 0;
+ warning_count = 0;
_notification(NOTIFICATION_PROCESS);
}
@@ -2162,9 +2176,11 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
live_debug = false;
last_path_id = false;
error_count = 0;
+ warning_count = 0;
hide_on_stop = true;
enable_external_editor = false;
last_error_count = 0;
+ last_warning_count = 0;
EditorNode::get_singleton()->get_pause_button()->connect("pressed", this, "_paused");
}
diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h
index f7fe348b65..ce705aa35b 100644
--- a/editor/script_editor_debugger.h
+++ b/editor/script_editor_debugger.h
@@ -96,7 +96,9 @@ class ScriptEditorDebugger : public Control {
EditorFileDialog *file_dialog;
int error_count;
+ int warning_count;
int last_error_count;
+ int last_warning_count;
bool hide_on_stop;
bool enable_external_editor;
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index fe379703e5..4ebba73cb3 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -114,22 +114,6 @@ void EditorSettingsDialog::popup_edit_settings() {
_focus_current_search_box();
}
-void EditorSettingsDialog::_clear_search_box() {
-
- if (search_box->get_text() == "")
- return;
-
- search_box->clear();
- inspector->get_inspector()->update_tree();
-}
-
-void EditorSettingsDialog::_clear_shortcut_search_box() {
- if (shortcut_search_box->get_text() == "")
- return;
-
- shortcut_search_box->clear();
-}
-
void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) {
shortcut_filter = p_filter;
_update_shortcuts();
@@ -198,10 +182,10 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
void EditorSettingsDialog::_update_icons() {
- search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
- shortcut_search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
- clear_button->set_icon(get_icon("Close", "EditorIcons"));
- shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ shortcut_search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ shortcut_search_box->set_clear_button_enabled(true);
restart_close_button->set_icon(get_icon("Close", "EditorIcons"));
restart_container->add_style_override("panel", get_stylebox("bg", "Tree"));
@@ -411,8 +395,6 @@ void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_settings_save"), &EditorSettingsDialog::_settings_save);
ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed);
ClassDB::bind_method(D_METHOD("_settings_property_edited"), &EditorSettingsDialog::_settings_property_edited);
- ClassDB::bind_method(D_METHOD("_clear_search_box"), &EditorSettingsDialog::_clear_search_box);
- ClassDB::bind_method(D_METHOD("_clear_shortcut_search_box"), &EditorSettingsDialog::_clear_shortcut_search_box);
ClassDB::bind_method(D_METHOD("_shortcut_button_pressed"), &EditorSettingsDialog::_shortcut_button_pressed);
ClassDB::bind_method(D_METHOD("_filter_shortcuts"), &EditorSettingsDialog::_filter_shortcuts);
ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
@@ -451,10 +433,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(search_box);
- clear_button = memnew(ToolButton);
- hbc->add_child(clear_button);
- clear_button->connect("pressed", this, "_clear_search_box");
-
inspector = memnew(SectionedInspector);
//inspector->hide_top_label();
inspector->get_inspector()->set_use_filter(true);
@@ -500,10 +478,6 @@ EditorSettingsDialog::EditorSettingsDialog() {
hbc->add_child(shortcut_search_box);
shortcut_search_box->connect("text_changed", this, "_filter_shortcuts");
- shortcut_clear_button = memnew(ToolButton);
- hbc->add_child(shortcut_clear_button);
- shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box");
-
shortcuts = memnew(Tree);
tab_shortcuts->add_child(shortcuts, true);
shortcuts->set_v_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/settings_config_dialog.h b/editor/settings_config_dialog.h
index 6cf2eb6bdf..37d32e401d 100644
--- a/editor/settings_config_dialog.h
+++ b/editor/settings_config_dialog.h
@@ -52,8 +52,6 @@ class EditorSettingsDialog : public AcceptDialog {
LineEdit *search_box;
LineEdit *shortcut_search_box;
- ToolButton *clear_button;
- ToolButton *shortcut_clear_button;
SectionedInspector *inspector;
Timer *timer;
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index b0505eebda..889d34544a 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -48,7 +48,7 @@
// It's so ugly it will eat them alive
// The previous comment is kept only for historical reasons.
-// No children will be harmed by the visioning of this file... hopefully.
+// No children will be harmed by the viewing of this file... hopefully.
#define HANDLE_HALF_SIZE 9.5
@@ -531,6 +531,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point,
rect.set_position(center - rect.get_size() / 2.0);
if (rect.has_point(p_point)) {
+ r_pos = t.origin;
+ r_normal = -p_camera->project_ray_normal(p_point);
return true;
}
@@ -675,7 +677,7 @@ void EditorSpatialGizmo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments);
ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorSpatialGizmo::add_collision_triangles);
ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1));
- ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_handles", "handles", "material", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node);
ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear);
ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorSpatialGizmo::set_hidden);
@@ -1472,34 +1474,6 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
p_gizmo->clear();
Ref<Material> material = get_material("skeleton_material", p_gizmo);
- SpatialMaterial *sm = Object::cast_to<SpatialMaterial>(material.ptr());
-
- { // Reset
- Color c(sm->get_albedo());
- c.a = 1;
- sm->set_albedo(c);
- }
- if (sm) {
- switch (SpatialEditor::get_singleton()->get_skeleton_visibility_state()) {
- case 0: {
- // Hidden
- Color c(sm->get_albedo());
- c.a = 0;
- sm->set_albedo(c);
- sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
- } break;
- case 1:
- // Visible
- sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, false);
- sm->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN);
- sm->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false);
- break;
- case 2:
- // x-ray
- sm->set_on_top_of_alpha();
- break;
- }
- }
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
@@ -1946,6 +1920,38 @@ void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
/////
+void SpringArmSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ SpringArm *spring_arm = Object::cast_to<SpringArm>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Vector<Vector3> lines;
+
+ lines.push_back(Vector3());
+ lines.push_back(Vector3(0, 0, 1.0) * spring_arm->get_length());
+
+ Ref<SpatialMaterial> material = get_material("shape_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+}
+
+SpringArmSpatialGizmoPlugin::SpringArmSpatialGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+}
+
+bool SpringArmSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<SpringArm>(p_spatial) != NULL;
+}
+
+String SpringArmSpatialGizmoPlugin::get_name() const {
+ return "SpringArm";
+}
+
+/////
+
VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
index 877590b91d..6f29e9d999 100644
--- a/editor/spatial_editor_gizmos.h
+++ b/editor/spatial_editor_gizmos.h
@@ -49,6 +49,7 @@
#include "scene/3d/ray_cast.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/room_instance.h"
+#include "scene/3d/spring_arm.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body.h"
#include "scene/3d/visibility_notifier.h"
@@ -196,6 +197,18 @@ public:
RayCastSpatialGizmoPlugin();
};
+class SpringArmSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
+
+ GDCLASS(SpringArmSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
+
+public:
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ SpringArmSpatialGizmoPlugin();
+};
+
class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
@@ -330,14 +343,12 @@ public:
};
class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
-
GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
bool has_gizmo(Spatial *p_spatial);
String get_name() const;
void redraw(EditorSpatialGizmo *p_gizmo);
-
CollisionPolygonSpatialGizmoPlugin();
};