diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index a197eb9dced8..620bc22df373 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -47,6 +47,7 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/project_settings_editor.h" #include "editor/property_selector.h" +#include "editor/scene_tree_dock.h" #include "scene/2d/gpu_particles_2d.h" #include "scene/3d/fog_volume.h" #include "scene/3d/gpu_particles_3d.h" @@ -2769,7 +2770,7 @@ EditorPropertyColor::EditorPropertyColor() { void EditorPropertyNodePath::_set_read_only(bool p_read_only) { assign->set_disabled(p_read_only); - clear->set_disabled(p_read_only); + menu->set_disabled(p_read_only); }; Variant EditorPropertyNodePath::_get_cache_value(const StringName &p_prop, bool &r_valid) const { @@ -2817,9 +2818,79 @@ void EditorPropertyNodePath::_node_assign() { scene_tree->popup_scenetree_dialog(); } -void EditorPropertyNodePath::_node_clear() { - emit_changed(get_edited_property(), Variant()); - update_property(); +void EditorPropertyNodePath::_update_menu() { + const NodePath &np = _get_node_path(); + + menu->get_popup()->set_item_disabled(ACTION_CLEAR, np.is_empty()); + menu->get_popup()->set_item_disabled(ACTION_COPY, np.is_empty()); + + Node *edited_node = Object::cast_to(get_edited_object()); + menu->get_popup()->set_item_disabled(ACTION_SELECT, !edited_node || !edited_node->has_node(np)); +} + +void EditorPropertyNodePath::_menu_option(int p_idx) { + switch (p_idx) { + case ACTION_CLEAR: { + emit_changed(get_edited_property(), NodePath()); + update_property(); + } break; + + case ACTION_COPY: { + DisplayServer::get_singleton()->clipboard_set(_get_node_path()); + } break; + + case ACTION_EDIT: { + assign->hide(); + menu->hide(); + + const NodePath &np = _get_node_path(); + edit->set_text(np); + edit->show(); + callable_mp((Control *)edit, &Control::grab_focus).call_deferred(); + } break; + + case ACTION_SELECT: { + const Node *edited_node = get_base_node(); + ERR_FAIL_NULL(edited_node); + + const NodePath &np = _get_node_path(); + Node *target_node = edited_node->get_node_or_null(np); + ERR_FAIL_NULL(target_node); + + SceneTreeDock::get_singleton()->set_selected(target_node); + } break; + } +} + +void EditorPropertyNodePath::_accept_text() { + _text_submitted(edit->get_text()); +} + +void EditorPropertyNodePath::_text_submitted(const String &p_text) { + NodePath np = p_text; + emit_changed(get_edited_property(), np); + edit->hide(); + assign->show(); + menu->show(); +} + +const NodePath EditorPropertyNodePath::_get_node_path() const { + const Node *base_node = const_cast(this)->get_base_node(); + + Variant val = get_edited_property_value(); + Node *n = Object::cast_to(val); + if (n) { + if (!n->is_inside_tree()) { + return NodePath(); + } + if (base_node) { + return base_node->get_path_to(n); + } else { + return get_tree()->get_edited_scene_root()->get_path_to(n); + } + } else { + return val; + } } bool EditorPropertyNodePath::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { @@ -2865,26 +2936,11 @@ bool EditorPropertyNodePath::is_drop_valid(const Dictionary &p_drag_data) const } void EditorPropertyNodePath::update_property() { - Node *base_node = get_base_node(); - - NodePath p; - Variant val = get_edited_object()->get(get_edited_property()); - Node *n = Object::cast_to(val); - if (n) { - if (!n->is_inside_tree()) { - return; - } - if (base_node) { - p = base_node->get_path_to(n); - } else { - p = get_tree()->get_edited_scene_root()->get_path_to(n); - } - } else { - p = get_edited_property_value(); - } - + const Node *base_node = get_base_node(); + const NodePath &p = _get_node_path(); assign->set_tooltip_text(p); - if (p == NodePath()) { + + if (p.is_empty()) { assign->set_icon(Ref()); assign->set_text(TTR("Assign...")); assign->set_flat(false); @@ -2898,7 +2954,7 @@ void EditorPropertyNodePath::update_property() { return; } - Node *target_node = base_node->get_node(p); + const Node *target_node = base_node->get_node(p); ERR_FAIL_NULL(target_node); if (String(target_node->get_name()).contains("@")) { @@ -2922,14 +2978,15 @@ void EditorPropertyNodePath::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - Ref t = get_editor_theme_icon(SNAME("Clear")); - clear->set_icon(t); + menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl"))); + menu->get_popup()->set_item_icon(ACTION_CLEAR, get_editor_theme_icon(SNAME("Clear"))); + menu->get_popup()->set_item_icon(ACTION_COPY, get_editor_theme_icon(SNAME("ActionCopy"))); + menu->get_popup()->set_item_icon(ACTION_EDIT, get_editor_theme_icon(SNAME("Edit"))); + menu->get_popup()->set_item_icon(ACTION_SELECT, get_editor_theme_icon(SNAME("ExternalLink"))); } break; } } -void EditorPropertyNodePath::_bind_methods() { -} Node *EditorPropertyNodePath::get_base_node() { if (!base_hint.is_empty() && get_tree()->get_root()->has_node(base_hint)) { return get_tree()->get_root()->get_node(base_hint); @@ -2973,12 +3030,23 @@ EditorPropertyNodePath::EditorPropertyNodePath() { SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath); hbc->add_child(assign); - clear = memnew(Button); - clear->set_flat(true); - clear->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_clear)); - hbc->add_child(clear); - - scene_tree = nullptr; //do not allocate unnecessarily + menu = memnew(MenuButton); + menu->set_flat(true); + menu->connect(SNAME("about_to_popup"), callable_mp(this, &EditorPropertyNodePath::_update_menu)); + hbc->add_child(menu); + + menu->get_popup()->add_item(TTR("Clear"), ACTION_CLEAR); + menu->get_popup()->add_item(TTR("Copy as Text"), ACTION_COPY); + menu->get_popup()->add_item(TTR("Edit"), ACTION_EDIT); + menu->get_popup()->add_item(TTR("Show Node in Tree"), ACTION_SELECT); + menu->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &EditorPropertyNodePath::_menu_option)); + + edit = memnew(LineEdit); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->hide(); + edit->connect(SNAME("focus_exited"), callable_mp(this, &EditorPropertyNodePath::_accept_text)); + edit->connect(SNAME("text_submitted"), callable_mp(this, &EditorPropertyNodePath::_text_submitted)); + hbc->add_child(edit); } ///////////////////// RID ///////////////////////// diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 5feb40b3d73f..ff9d47627a94 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -40,6 +40,7 @@ class EditorFileDialog; class EditorLocaleDialog; class EditorResourcePicker; class EditorSpinSlider; +class MenuButton; class PropertySelector; class SceneTreeDialog; class TextEdit; @@ -649,8 +650,18 @@ class EditorPropertyColor : public EditorProperty { class EditorPropertyNodePath : public EditorProperty { GDCLASS(EditorPropertyNodePath, EditorProperty); + + enum { + ACTION_CLEAR, + ACTION_COPY, + ACTION_EDIT, + ACTION_SELECT, + }; + Button *assign = nullptr; - Button *clear = nullptr; + MenuButton *menu = nullptr; + LineEdit *edit = nullptr; + SceneTreeDialog *scene_tree = nullptr; NodePath base_hint; bool use_path_from_scene_root = false; @@ -659,8 +670,12 @@ class EditorPropertyNodePath : public EditorProperty { Vector valid_types; void _node_selected(const NodePath &p_path); void _node_assign(); - void _node_clear(); Node *get_base_node(); + void _update_menu(); + void _menu_option(int p_idx); + void _accept_text(); + void _text_submitted(const String &p_text); + const NodePath _get_node_path() const; bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); @@ -670,7 +685,6 @@ class EditorPropertyNodePath : public EditorProperty { protected: virtual void _set_read_only(bool p_read_only) override; - static void _bind_methods(); void _notification(int p_what); public: