diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_inspector.cpp | 7 | ||||
-rw-r--r-- | editor/editor_node.cpp | 9 | ||||
-rw-r--r-- | editor/plugins/root_motion_editor_plugin.cpp | 292 | ||||
-rw-r--r-- | editor/plugins/root_motion_editor_plugin.h | 42 |
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 |