summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/editor_inspector.cpp7
-rw-r--r--editor/editor_node.cpp9
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp292
-rw-r--r--editor/plugins/root_motion_editor_plugin.h42
4 files changed, 346 insertions, 4 deletions
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 9a3174fb1a..79746dcb5a 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1464,7 +1464,8 @@ void EditorInspector::update_tree() {
#endif
for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
Ref<EditorInspectorPlugin> ped = E->get();
- ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage);
+ bool exclusive = ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage);
+
List<EditorInspectorPlugin::AddedEditor> editors = ped->added_editors; //make a copy, since plugins may be used again in a sub-inspector
ped->added_editors.clear();
@@ -1532,6 +1533,10 @@ void EditorInspector::update_tree() {
}
}
}
+
+ if (exclusive) {
+ break;
+ }
}
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 67e1ca79f3..52f356813a 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -99,6 +99,7 @@
#include "editor/plugins/physical_bone_plugin.h"
#include "editor/plugins/polygon_2d_editor_plugin.h"
#include "editor/plugins/resource_preloader_editor_plugin.h"
+#include "editor/plugins/root_motion_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/plugins/script_text_editor.h"
#include "editor/plugins/shader_editor_plugin.h"
@@ -4635,6 +4636,10 @@ EditorNode::EditorNode() {
Ref<EditorInspectorDefaultPlugin> eidp;
eidp.instance();
EditorInspector::add_inspector_plugin(eidp);
+
+ Ref<EditorInspectorRootMotionPlugin> rmp;
+ rmp.instance();
+ EditorInspector::add_inspector_plugin(rmp);
}
_pvrtc_register_compressors();
@@ -4660,9 +4665,7 @@ EditorNode::EditorNode() {
GLOBAL_DEF("editor/main_run_args", "");
- ClassDB::set_class_enabled("CollisionShape", true);
- ClassDB::set_class_enabled("CollisionShape2D", true);
- ClassDB::set_class_enabled("CollisionPolygon2D", true);
+ ClassDB::set_class_enabled("RootMotionView", true);
//defs here, use EDITOR_GET in logic
EDITOR_DEF("interface/scene_tabs/always_show_close_button", false);
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
new file mode 100644
index 0000000000..e316116b43
--- /dev/null
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -0,0 +1,292 @@
+#include "root_motion_editor_plugin.h"
+#include "editor/editor_node.h"
+#include "scene/main/viewport.h"
+
+void EditorPropertyRootMotion::_confirmed() {
+
+ TreeItem *ti = filters->get_selected();
+ if (!ti)
+ return;
+
+ NodePath path = ti->get_metadata(0);
+ emit_signal("property_changed", get_edited_property(), path);
+ update_property();
+ filter_dialog->hide(); //may come from activated
+}
+
+void EditorPropertyRootMotion::_node_assign() {
+
+ NodePath current = get_edited_object()->get(get_edited_property());
+
+ AnimationTree *atree = Object::cast_to<AnimationTree>(get_edited_object());
+ if (!atree->has_node(atree->get_animation_player())) {
+ EditorNode::get_singleton()->show_warning(TTR("AnimationTree has no path set to an AnimationPlayer"));
+ return;
+ }
+ AnimationPlayer *player = Object::cast_to<AnimationPlayer>(atree->get_node(atree->get_animation_player()));
+ if (!player) {
+ EditorNode::get_singleton()->show_warning(TTR("Path to AnimationPlayer is invalid"));
+ return;
+ }
+
+ Node *base = player->get_node(player->get_root());
+
+ if (!base) {
+ EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names."));
+ return;
+ }
+
+ Set<String> paths;
+ {
+ List<StringName> animations;
+ player->get_animation_list(&animations);
+
+ for (List<StringName>::Element *E = animations.front(); E; E = E->next()) {
+
+ Ref<Animation> anim = player->get_animation(E->get());
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ paths.insert(anim->track_get_path(i));
+ }
+ }
+ }
+
+ filters->clear();
+ TreeItem *root = filters->create_item();
+
+ Map<String, TreeItem *> parenthood;
+
+ for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
+
+ NodePath path = E->get();
+ TreeItem *ti = NULL;
+ String accum;
+ for (int i = 0; i < path.get_name_count(); i++) {
+ String name = path.get_name(i);
+ if (accum != String()) {
+ accum += "/";
+ }
+ accum += name;
+ if (!parenthood.has(accum)) {
+ if (ti) {
+ ti = filters->create_item(ti);
+ } else {
+ ti = filters->create_item(root);
+ }
+ parenthood[accum] = ti;
+ ti->set_text(0, name);
+ ti->set_selectable(0, false);
+ ti->set_editable(0, false);
+
+ if (base->has_node(accum)) {
+ Node *node = base->get_node(accum);
+ if (has_icon(node->get_class(), "EditorIcons")) {
+ ti->set_icon(0, get_icon(node->get_class(), "EditorIcons"));
+ } else {
+ ti->set_icon(0, get_icon("Node", "EditorIcons"));
+ }
+ }
+
+ } else {
+ ti = parenthood[accum];
+ }
+ }
+
+ Node *node = NULL;
+ if (base->has_node(accum)) {
+ node = base->get_node(accum);
+ }
+ if (!node)
+ continue; //no node, cant edit
+
+ if (path.get_subname_count()) {
+
+ String concat = path.get_concatenated_subnames();
+
+ Skeleton *skeleton = Object::cast_to<Skeleton>(node);
+ if (skeleton && skeleton->find_bone(concat) != -1) {
+ //path in skeleton
+ String bone = concat;
+ int idx = skeleton->find_bone(bone);
+ List<String> bone_path;
+ while (idx != -1) {
+ bone_path.push_front(skeleton->get_bone_name(idx));
+ idx = skeleton->get_bone_parent(idx);
+ }
+
+ accum += ":";
+ for (List<String>::Element *F = bone_path.front(); F; F = F->next()) {
+ if (F != bone_path.front()) {
+ accum += "/";
+ }
+
+ accum += F->get();
+ if (!parenthood.has(accum)) {
+ ti = filters->create_item(ti);
+ parenthood[accum] = ti;
+ ti->set_text(0, F->get());
+ ti->set_selectable(0, false);
+ ti->set_editable(0, false);
+ ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ } else {
+ ti = parenthood[accum];
+ }
+ }
+
+ ti->set_selectable(0, true);
+ ti->set_text(0, concat);
+ ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons"));
+ ti->set_metadata(0, path);
+ if (path == current) {
+ ti->select(0);
+ }
+
+ } else {
+ //just a property
+ ti = filters->create_item(ti);
+ ti->set_text(0, concat);
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, path);
+ if (path == current) {
+ ti->select(0);
+ }
+ }
+ } else {
+ if (ti) {
+ //just a node, likely call or animation track
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, path);
+ if (path == current) {
+ ti->select(0);
+ }
+ }
+ }
+ }
+
+ filters->ensure_cursor_is_visible();
+ filter_dialog->popup_centered_ratio();
+}
+
+void EditorPropertyRootMotion::_node_clear() {
+
+ emit_signal("property_changed", get_edited_property(), NodePath());
+ update_property();
+}
+
+void EditorPropertyRootMotion::update_property() {
+
+ NodePath p = get_edited_object()->get(get_edited_property());
+
+ assign->set_tooltip(p);
+ if (p == NodePath()) {
+ assign->set_icon(Ref<Texture>());
+ assign->set_text(TTR("Assign.."));
+ assign->set_flat(false);
+ return;
+ }
+ assign->set_flat(true);
+
+ Node *base_node = NULL;
+ if (base_hint != NodePath()) {
+ if (get_tree()->get_root()->has_node(base_hint)) {
+ base_node = get_tree()->get_root()->get_node(base_hint);
+ }
+ } else {
+ base_node = Object::cast_to<Node>(get_edited_object());
+ }
+
+ if (!base_node || !base_node->has_node(p)) {
+ assign->set_icon(Ref<Texture>());
+ assign->set_text(p);
+ return;
+ }
+
+ Node *target_node = base_node->get_node(p);
+ ERR_FAIL_COND(!target_node);
+
+ assign->set_text(target_node->get_name());
+
+ Ref<Texture> icon;
+ if (has_icon(target_node->get_class(), "EditorIcons"))
+ icon = get_icon(target_node->get_class(), "EditorIcons");
+ else
+ icon = get_icon("Node", "EditorIcons");
+
+ assign->set_icon(icon);
+}
+
+void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) {
+
+ base_hint = p_base_hint;
+}
+
+void EditorPropertyRootMotion::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ Ref<Texture> t = get_icon("Clear", "EditorIcons");
+ clear->set_icon(t);
+ }
+}
+
+void EditorPropertyRootMotion::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_confirmed"), &EditorPropertyRootMotion::_confirmed);
+ ClassDB::bind_method(D_METHOD("_node_assign"), &EditorPropertyRootMotion::_node_assign);
+ ClassDB::bind_method(D_METHOD("_node_clear"), &EditorPropertyRootMotion::_node_clear);
+}
+
+EditorPropertyRootMotion::EditorPropertyRootMotion() {
+
+ HBoxContainer *hbc = memnew(HBoxContainer);
+ add_child(hbc);
+ assign = memnew(Button);
+ assign->set_flat(true);
+ assign->set_h_size_flags(SIZE_EXPAND_FILL);
+ assign->set_clip_text(true);
+ assign->connect("pressed", this, "_node_assign");
+ hbc->add_child(assign);
+
+ clear = memnew(Button);
+ clear->set_flat(true);
+ clear->connect("pressed", this, "_node_clear");
+ hbc->add_child(clear);
+
+ filter_dialog = memnew(ConfirmationDialog);
+ add_child(filter_dialog);
+ filter_dialog->set_title(TTR("Edit Filtered Tracks:"));
+ filter_dialog->connect("confirmed", this, "_confirmed");
+
+ filters = memnew(Tree);
+ filter_dialog->add_child(filters);
+ filters->set_v_size_flags(SIZE_EXPAND_FILL);
+ filters->set_hide_root(true);
+ filters->connect("item_activated", this, "_confirmed");
+ //filters->connect("item_edited", this, "_filter_edited");
+}
+//////////////////////////
+
+bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) {
+ return true; //can handle everything
+}
+
+void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) {
+ //do none
+}
+
+bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) {
+
+ if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) {
+ print_line("use custom!");
+ EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion);
+ if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) {
+ editor->setup(p_hint_text);
+ }
+ add_property_editor(p_path, editor);
+ return true;
+ }
+
+ return false; //can be overriden, although it will most likely be last anyway
+}
+
+void EditorInspectorRootMotionPlugin::parse_end() {
+ //do none
+}
diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h
new file mode 100644
index 0000000000..84af47872f
--- /dev/null
+++ b/editor/plugins/root_motion_editor_plugin.h
@@ -0,0 +1,42 @@
+#ifndef ROOT_MOTION_EDITOR_PLUGIN_H
+#define ROOT_MOTION_EDITOR_PLUGIN_H
+
+#include "editor/editor_inspector.h"
+#include "editor/editor_spin_slider.h"
+#include "editor/property_selector.h"
+#include "scene/animation/animation_tree.h"
+
+class EditorPropertyRootMotion : public EditorProperty {
+ GDCLASS(EditorPropertyRootMotion, EditorProperty)
+ Button *assign;
+ Button *clear;
+ NodePath base_hint;
+
+ ConfirmationDialog *filter_dialog;
+ Tree *filters;
+
+ void _confirmed();
+ void _node_assign();
+ void _node_clear();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ virtual void update_property();
+ void setup(const NodePath &p_base_hint);
+ EditorPropertyRootMotion();
+};
+
+class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorRootMotionPlugin, EditorInspectorPlugin)
+
+public:
+ virtual bool can_handle(Object *p_object);
+ virtual void parse_begin(Object *p_object);
+ virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage);
+ virtual void parse_end();
+};
+
+#endif // ROOT_MOTION_EDITOR_PLUGIN_H