diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_help_search.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/replication_editor_plugin.cpp | 255 | ||||
-rw-r--r-- | editor/plugins/replication_editor_plugin.h | 32 | ||||
-rw-r--r-- | editor/plugins/sprite_frames_editor_plugin.h | 2 | ||||
-rw-r--r-- | editor/scene_tree_dock.cpp | 29 | ||||
-rw-r--r-- | editor/scene_tree_dock.h | 3 |
6 files changed, 299 insertions, 24 deletions
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index b85147fddf..f454ba2c41 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -333,7 +333,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes() { // Match class name. if (search_flags & SEARCH_CLASSES) { // If the search term is empty, add any classes which are not script docs or which don't start with - // a double-quotation. This will ensure that only C++ classes and explictly named classes will + // a double-quotation. This will ensure that only C++ classes and explicitly named classes will // be added. match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name); } diff --git a/editor/plugins/replication_editor_plugin.cpp b/editor/plugins/replication_editor_plugin.cpp index 2a7b3c7a55..6992b5443b 100644 --- a/editor/plugins/replication_editor_plugin.cpp +++ b/editor/plugins/replication_editor_plugin.cpp @@ -37,6 +37,129 @@ #include "scene/gui/tree.h" #include "scene/multiplayer/multiplayer_synchronizer.h" +void ReplicationEditor::_pick_node_filter_text_changed(const String &p_newtext) { + TreeItem *root_item = pick_node->get_scene_tree()->get_scene_tree()->get_root(); + + Vector<Node *> select_candidates; + Node *to_select = nullptr; + + String filter = pick_node->get_filter_line_edit()->get_text(); + + _pick_node_select_recursive(root_item, filter, select_candidates); + + if (!select_candidates.is_empty()) { + for (int i = 0; i < select_candidates.size(); ++i) { + Node *candidate = select_candidates[i]; + + if (((String)candidate->get_name()).to_lower().begins_with(filter.to_lower())) { + to_select = candidate; + break; + } + } + + if (!to_select) { + to_select = select_candidates[0]; + } + } + + pick_node->get_scene_tree()->set_selected(to_select); +} + +void ReplicationEditor::_pick_node_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates) { + if (!p_item) { + return; + } + + NodePath np = p_item->get_metadata(0); + Node *node = get_node(np); + + if (!p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) { + p_select_candidates.push_back(node); + } + + TreeItem *c = p_item->get_first_child(); + + while (c) { + _pick_node_select_recursive(c, p_filter, p_select_candidates); + c = c->get_next(); + } +} + +void ReplicationEditor::_pick_node_filter_input(const Ref<InputEvent> &p_ie) { + Ref<InputEventKey> k = p_ie; + + if (k.is_valid()) { + switch (k->get_keycode()) { + case Key::UP: + case Key::DOWN: + case Key::PAGEUP: + case Key::PAGEDOWN: { + pick_node->get_scene_tree()->get_scene_tree()->gui_input(k); + pick_node->get_filter_line_edit()->accept_event(); + } break; + default: + break; + } + } +} + +void ReplicationEditor::_pick_node_selected(NodePath p_path) { + Node *root = current->get_node(current->get_root_path()); + ERR_FAIL_COND(!root); + Node *node = get_node(p_path); + ERR_FAIL_COND(!node); + NodePath path_to = root->get_path_to(node); + adding_node_path = path_to; + prop_selector->select_property_from_instance(node); +} + +void ReplicationEditor::_pick_new_property() { + if (current == nullptr) { + EditorNode::get_singleton()->show_warning(TTR("Select a replicator node in order to pick a property to add to it.")); + return; + } + Node *root = current->get_node(current->get_root_path()); + if (!root) { + EditorNode::get_singleton()->show_warning(TTR("Not possible to add a new property to synchronize without a root.")); + return; + } + pick_node->popup_scenetree_dialog(); + pick_node->get_filter_line_edit()->clear(); + pick_node->get_filter_line_edit()->grab_focus(); +} + +void ReplicationEditor::_add_sync_property(String p_path) { + config = current->get_replication_config(); + + if (config.is_valid() && config->has_property(p_path)) { + EditorNode::get_singleton()->show_warning(TTR("Property is already being synchronized.")); + return; + } + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(TTR("Add property to synchronizer")); + + if (config.is_null()) { + config.instantiate(); + current->set_replication_config(config); + undo_redo->add_do_method(current, "set_replication_config", config); + undo_redo->add_undo_method(current, "set_replication_config", Ref<SceneReplicationConfig>()); + _update_config(); + } + + undo_redo->add_do_method(config.ptr(), "add_property", p_path); + undo_redo->add_undo_method(config.ptr(), "remove_property", p_path); + undo_redo->add_do_method(this, "_update_config"); + undo_redo->add_undo_method(this, "_update_config"); + undo_redo->commit_action(); +} + +void ReplicationEditor::_pick_node_property_selected(String p_name) { + String adding_prop_path = String(adding_node_path) + ":" + p_name; + + _add_sync_property(adding_prop_path); +} + /// ReplicationEditor ReplicationEditor::ReplicationEditor() { set_v_size_flags(SIZE_EXPAND_FILL); @@ -56,16 +179,44 @@ ReplicationEditor::ReplicationEditor() { vb->set_v_size_flags(SIZE_EXPAND_FILL); add_child(vb); + pick_node = memnew(SceneTreeDialog); + add_child(pick_node); + pick_node->register_text_enter(pick_node->get_filter_line_edit()); + pick_node->set_title(TTR("Pick a node to synchronize:")); + pick_node->connect("selected", callable_mp(this, &ReplicationEditor::_pick_node_selected)); + pick_node->get_filter_line_edit()->connect("text_changed", callable_mp(this, &ReplicationEditor::_pick_node_filter_text_changed)); + pick_node->get_filter_line_edit()->connect("gui_input", callable_mp(this, &ReplicationEditor::_pick_node_filter_input)); + + prop_selector = memnew(PropertySelector); + add_child(prop_selector); + prop_selector->connect("selected", callable_mp(this, &ReplicationEditor::_pick_node_property_selected)); + HBoxContainer *hb = memnew(HBoxContainer); vb->add_child(hb); + + add_pick_button = memnew(Button); + add_pick_button->connect("pressed", callable_mp(this, &ReplicationEditor::_pick_new_property)); + add_pick_button->set_text(TTR("Add property to sync..")); + hb->add_child(add_pick_button); + VSeparator *vs = memnew(VSeparator); + vs->set_custom_minimum_size(Size2(30 * EDSCALE, 0)); + hb->add_child(vs); + hb->add_child(memnew(Label(TTR("Path:")))); np_line_edit = memnew(LineEdit); np_line_edit->set_placeholder(":property"); np_line_edit->set_h_size_flags(SIZE_EXPAND_FILL); hb->add_child(np_line_edit); - add_button = memnew(Button); - add_button->connect("pressed", callable_mp(this, &ReplicationEditor::_add_pressed)); - add_button->set_text(TTR("Add")); - hb->add_child(add_button); + add_from_path_button = memnew(Button); + add_from_path_button->connect("pressed", callable_mp(this, &ReplicationEditor::_add_pressed)); + add_from_path_button->set_text(TTR("Add from path")); + hb->add_child(add_from_path_button); + vs = memnew(VSeparator); + vs->set_custom_minimum_size(Size2(30 * EDSCALE, 0)); + hb->add_child(vs); + pin = memnew(Button); + pin->set_flat(true); + pin->set_toggle_mode(true); + hb->add_child(pin); tree = memnew(Tree); tree->set_hide_root(true); @@ -85,19 +236,88 @@ ReplicationEditor::ReplicationEditor() { tree->connect("item_edited", callable_mp(this, &ReplicationEditor::_tree_item_edited)); tree->set_v_size_flags(SIZE_EXPAND_FILL); vb->add_child(tree); + + drop_label = memnew(Label); + drop_label->set_text(TTR("Add properties using the buttons above or\ndrag them them from the inspector and drop them here.")); + drop_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + drop_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + tree->add_child(drop_label); + drop_label->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + + tree->set_drag_forwarding(this); } void ReplicationEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_config"), &ReplicationEditor::_update_config); ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked); + ClassDB::bind_method("_can_drop_data_fw", &ReplicationEditor::_can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &ReplicationEditor::_drop_data_fw); + ADD_SIGNAL(MethodInfo("keying_changed")); } +bool ReplicationEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + Dictionary d = p_data; + if (!d.has("type")) { + return false; + } + String t = d["type"]; + if (t != "obj_property") { + return false; + } + Object *obj = d["object"]; + if (!obj) { + return false; + } + Node *node = Object::cast_to<Node>(obj); + if (!node) { + return false; + } + + return true; +} + +void ReplicationEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + if (current == nullptr) { + EditorNode::get_singleton()->show_warning(TTR("Select a replicator node in order to pick a property to add to it.")); + return; + } + Node *root = current->get_node(current->get_root_path()); + if (!root) { + EditorNode::get_singleton()->show_warning(TTR("Not possible to add a new property to synchronize without a root.")); + return; + } + + Dictionary d = p_data; + if (!d.has("type")) { + return; + } + String t = d["type"]; + if (t != "obj_property") { + return; + } + Object *obj = d["object"]; + if (!obj) { + return; + } + Node *node = Object::cast_to<Node>(obj); + if (!node) { + return; + } + + String path = root->get_path_to(node); + path += ":" + String(d["property"]); + + _add_sync_property(path); +} + void ReplicationEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel"))); + add_pick_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + pin->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -236,11 +456,15 @@ void ReplicationEditor::_update_config() { deleting = NodePath(); tree->clear(); tree->create_item(); + drop_label->set_visible(true); if (!config.is_valid()) { update_keying(); return; } TypedArray<NodePath> props = config->get_properties(); + if (props.size()) { + drop_label->set_visible(false); + } for (int i = 0; i < props.size(); i++) { const NodePath path = props[i]; _add_property(path, config->property_get_spawn(path), config->property_get_sync(path)); @@ -341,7 +565,9 @@ void ReplicationEditor::property_keyed(const String &p_property) { /// ReplicationEditorPlugin ReplicationEditorPlugin::ReplicationEditorPlugin() { repl_editor = memnew(ReplicationEditor); - EditorNode::get_singleton()->add_bottom_panel_item(TTR("Replication"), repl_editor); + button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Replication"), repl_editor); + button->hide(); + repl_editor->get_pin()->connect("pressed", callable_mp(this, &ReplicationEditorPlugin::_pinned)); } ReplicationEditorPlugin::~ReplicationEditorPlugin() { @@ -378,6 +604,17 @@ void ReplicationEditorPlugin::_node_removed(Node *p_node) { if (repl_editor->is_visible_in_tree()) { EditorNode::get_singleton()->hide_bottom_panel(); } + button->hide(); + repl_editor->get_pin()->set_pressed(false); + } +} + +void ReplicationEditorPlugin::_pinned() { + if (!repl_editor->get_pin()->is_pressed()) { + if (repl_editor->is_visible_in_tree()) { + EditorNode::get_singleton()->hide_bottom_panel(); + } + button->hide(); } } @@ -391,6 +628,14 @@ bool ReplicationEditorPlugin::handles(Object *p_object) const { void ReplicationEditorPlugin::make_visible(bool p_visible) { if (p_visible) { + //editor->hide_animation_player_editors(); + //editor->animation_panel_make_visible(true); + button->show(); EditorNode::get_singleton()->make_bottom_panel_item_visible(repl_editor); + } else if (!repl_editor->get_pin()->is_pressed()) { + if (repl_editor->is_visible_in_tree()) { + EditorNode::get_singleton()->hide_bottom_panel(); + } + button->hide(); } } diff --git a/editor/plugins/replication_editor_plugin.h b/editor/plugins/replication_editor_plugin.h index 08e86d1617..b6de08a3a8 100644 --- a/editor/plugins/replication_editor_plugin.h +++ b/editor/plugins/replication_editor_plugin.h @@ -34,6 +34,10 @@ #include "editor/editor_plugin.h" #include "scene/resources/scene_replication_config.h" +#include "editor/editor_spin_slider.h" +#include "editor/property_editor.h" +#include "editor/property_selector.h" + class ConfirmationDialog; class MultiplayerSynchronizer; class Tree; @@ -46,14 +50,23 @@ private: AcceptDialog *error_dialog = nullptr; ConfirmationDialog *delete_dialog = nullptr; - Button *add_button = nullptr; + Button *add_pick_button = nullptr; + Button *add_from_path_button = nullptr; LineEdit *np_line_edit = nullptr; + Label *drop_label = nullptr; + Ref<SceneReplicationConfig> config; NodePath deleting; Tree *tree = nullptr; bool keying = false; + PropertySelector *prop_selector = nullptr; + SceneTreeDialog *pick_node = nullptr; + NodePath adding_node_path; + + Button *pin = nullptr; + Ref<Texture2D> _get_class_icon(const Node *p_node); void _add_pressed(); @@ -64,6 +77,19 @@ private: void _dialog_closed(bool p_confirmed); void _add_property(const NodePath &p_property, bool p_spawn = true, bool p_sync = true); + void _pick_node_filter_text_changed(const String &p_newtext); + void _pick_node_select_recursive(TreeItem *p_item, const String &p_filter, Vector<Node *> &p_select_candidates); + void _pick_node_filter_input(const Ref<InputEvent> &p_ie); + void _pick_node_selected(NodePath p_path); + + void _pick_new_property(); + void _pick_node_property_selected(String p_name); + + 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); + + void _add_sync_property(String p_path); + protected: static void _bind_methods(); @@ -76,6 +102,7 @@ public: MultiplayerSynchronizer *get_current() const { return current; } void property_keyed(const String &p_property); + Button *get_pin() { return pin; } ReplicationEditor(); ~ReplicationEditor() {} }; @@ -84,12 +111,15 @@ class ReplicationEditorPlugin : public EditorPlugin { GDCLASS(ReplicationEditorPlugin, EditorPlugin); private: + Button *button = nullptr; ReplicationEditor *repl_editor = nullptr; void _node_removed(Node *p_node); void _keying_changed(); void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance); + void _pinned(); + protected: void _notification(int p_what); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index f7985aba18..3c8c5ef19d 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -50,7 +50,7 @@ class SpriteFramesEditor : public HSplitContainer { enum { PARAM_USE_CURRENT, // Used in callbacks to indicate `dominant_param` should be not updated. - PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertial" values. + PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertical" values. PARAM_SIZE, // Keep "Size" values. }; int dominant_param = PARAM_FRAME_COUNT; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 2387f65229..c1cc144ff5 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -59,10 +59,7 @@ #endif // MODULE_REGEX_ENABLED void SceneTreeDock::_nodes_drag_begin() { - if (restore_script_editor_on_drag) { - EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); - restore_script_editor_on_drag = false; - } + pending_click_select = nullptr; } void SceneTreeDock::_quick_open() { @@ -74,8 +71,9 @@ void SceneTreeDock::input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - restore_script_editor_on_drag = false; //lost chance + if (pending_click_select && mb.is_valid() && !mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) { + _push_item(pending_click_select); + pending_click_select = nullptr; } } @@ -1369,8 +1367,14 @@ void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) { } void SceneTreeDock::_push_item(Object *p_object) { - if (!Input::get_singleton()->is_key_pressed(Key::ALT)) { - EditorNode::get_singleton()->push_item(p_object); + EditorNode::get_singleton()->push_item(p_object); +} + +void SceneTreeDock::_handle_select(Node *p_node) { + if ((Input::get_singleton()->get_mouse_button_mask() & (MouseButton::MASK_LEFT | MouseButton::MASK_RIGHT)) != MouseButton::NONE) { + pending_click_select = p_node; + } else { + EditorNode::get_singleton()->push_item(p_node); } } @@ -1380,12 +1384,7 @@ void SceneTreeDock::_node_selected() { if (!node) { return; } - - if (ScriptEditor::get_singleton()->is_visible_in_tree()) { - restore_script_editor_on_drag = true; - } - - _push_item(node); + _handle_select(node); } void SceneTreeDock::_node_renamed() { @@ -2148,7 +2147,7 @@ void SceneTreeDock::_selection_changed() { //automatically turn on multi-edit _tool_selected(TOOL_MULTI_EDIT); } else if (selection_size == 1) { - _push_item(editor_selection->get_selection().begin()->key); + _handle_select(editor_selection->get_selection().begin()->key); } else if (selection_size == 0) { _push_item(nullptr); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index aa64945d81..54e6108d84 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -105,7 +105,6 @@ class SceneTreeDock : public VBoxContainer { Vector<ObjectID> subresources; - bool restore_script_editor_on_drag = false; bool reset_create_dialog = false; int current_option = 0; @@ -172,6 +171,7 @@ class SceneTreeDock : public VBoxContainer { void _do_create(Node *p_parent); Node *scene_root = nullptr; Node *edited_scene = nullptr; + Node *pending_click_select = nullptr; VBoxContainer *create_root_dialog = nullptr; String selected_favorite_root; @@ -198,6 +198,7 @@ class SceneTreeDock : public VBoxContainer { void _load_request(const String &p_path); void _script_open_request(const Ref<Script> &p_script); void _push_item(Object *p_object); + void _handle_select(Node *p_node); bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node); bool _track_inherit(const String &p_target_scene_path, Node *p_desired_node); |