Multiple, simultaneous node editing spuport!!
..but will you be brave enough to try it? :)
This commit is contained in:
parent
0d77277a86
commit
eff2931b2a
@ -39,7 +39,7 @@ void EditorHistory::_cleanup_history() {
|
|||||||
bool fail=false;
|
bool fail=false;
|
||||||
|
|
||||||
for(int j=0;j<history[i].path.size();j++) {
|
for(int j=0;j<history[i].path.size();j++) {
|
||||||
if (!history[i].path[j].res.is_null())
|
if (!history[i].path[j].ref.is_null())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ObjectDB::get_instance(history[i].path[j].object))
|
if (ObjectDB::get_instance(history[i].path[j].object))
|
||||||
@ -70,10 +70,10 @@ void EditorHistory::_add_object(ObjectID p_object,const String& p_property,int p
|
|||||||
|
|
||||||
Object *obj = ObjectDB::get_instance(p_object);
|
Object *obj = ObjectDB::get_instance(p_object);
|
||||||
ERR_FAIL_COND(!obj);
|
ERR_FAIL_COND(!obj);
|
||||||
Resource *r = obj->cast_to<Resource>();
|
Reference *r = obj->cast_to<Reference>();
|
||||||
Obj o;
|
Obj o;
|
||||||
if (r)
|
if (r)
|
||||||
o.res=RES(r);
|
o.ref=REF(r);
|
||||||
o.object=p_object;
|
o.object=p_object;
|
||||||
o.property=p_property;
|
o.property=p_property;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class EditorHistory {
|
|||||||
|
|
||||||
struct Obj {
|
struct Obj {
|
||||||
|
|
||||||
RES res;
|
REF ref;
|
||||||
ObjectID object;
|
ObjectID object;
|
||||||
String property;
|
String property;
|
||||||
};
|
};
|
||||||
|
@ -1427,10 +1427,7 @@ void EditorNode::_edit_current() {
|
|||||||
|
|
||||||
resources_dock->add_resource(Ref<Resource>(current_res));
|
resources_dock->add_resource(Ref<Resource>(current_res));
|
||||||
//top_pallete->set_current_tab(1);
|
//top_pallete->set_current_tab(1);
|
||||||
}
|
} else if (current_obj->is_type("Node")) {
|
||||||
|
|
||||||
|
|
||||||
if (current_obj->is_type("Node")) {
|
|
||||||
|
|
||||||
Node * current_node = current_obj->cast_to<Node>();
|
Node * current_node = current_obj->cast_to<Node>();
|
||||||
ERR_FAIL_COND(!current_node);
|
ERR_FAIL_COND(!current_node);
|
||||||
@ -1445,6 +1442,12 @@ void EditorNode::_edit_current() {
|
|||||||
|
|
||||||
//top_pallete->set_current_tab(0);
|
//top_pallete->set_current_tab(0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
property_editor->edit( current_obj );
|
||||||
|
//scene_tree_dock->set_selected(current_node);
|
||||||
|
//object_menu->get_popup()->clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Take care of PLUGIN EDITOR */
|
/* Take care of PLUGIN EDITOR */
|
||||||
|
BIN
tools/editor/icons/icon_multi_node_edit.png
Normal file
BIN
tools/editor/icons/icon_multi_node_edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 576 B |
118
tools/editor/multi_node_edit.cpp
Normal file
118
tools/editor/multi_node_edit.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#include "multi_node_edit.h"
|
||||||
|
#include "editor_node.h"
|
||||||
|
|
||||||
|
bool MultiNodeEdit::_set(const StringName& p_name, const Variant& p_value){
|
||||||
|
|
||||||
|
Node *es = EditorNode::get_singleton()->get_edited_scene();
|
||||||
|
if (!es)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
|
||||||
|
|
||||||
|
ur->create_action("MultiNode Set "+String(p_name));
|
||||||
|
for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
|
||||||
|
|
||||||
|
if (!es->has_node(E->get()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Node*n=es->get_node(E->get());
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ur->add_do_property(n,p_name,p_value);
|
||||||
|
ur->add_undo_property(n,p_name,n->get(p_name));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ur->commit_action();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MultiNodeEdit::_get(const StringName& p_name,Variant &r_ret) const {
|
||||||
|
|
||||||
|
Node *es = EditorNode::get_singleton()->get_edited_scene();
|
||||||
|
if (!es)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
|
||||||
|
|
||||||
|
if (!es->has_node(E->get()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const Node*n=es->get_node(E->get());
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool found;
|
||||||
|
r_ret=n->get(p_name,&found);
|
||||||
|
if (found)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiNodeEdit::_get_property_list( List<PropertyInfo> *p_list) const{
|
||||||
|
|
||||||
|
HashMap<String,PLData> usage;
|
||||||
|
|
||||||
|
Node *es = EditorNode::get_singleton()->get_edited_scene();
|
||||||
|
if (!es)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int nc=0;
|
||||||
|
|
||||||
|
List<PLData*> datas;
|
||||||
|
|
||||||
|
for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
|
||||||
|
|
||||||
|
if (!es->has_node(E->get()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Node*n=es->get_node(E->get());
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
List<PropertyInfo> plist;
|
||||||
|
n->get_property_list(&plist,true);
|
||||||
|
|
||||||
|
for(List<PropertyInfo>::Element *F=plist.front();F;F=F->next()) {
|
||||||
|
|
||||||
|
if (!usage.has(F->get().name)) {
|
||||||
|
PLData pld;
|
||||||
|
pld.uses=0;
|
||||||
|
pld.info=F->get();
|
||||||
|
usage[F->get().name]=pld;
|
||||||
|
datas.push_back(usage.getptr(F->get().name));
|
||||||
|
}
|
||||||
|
|
||||||
|
usage[F->get().name].uses++;
|
||||||
|
}
|
||||||
|
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (List<PLData*>::Element *E=datas.front();E;E=E->next()) {
|
||||||
|
|
||||||
|
if (nc==E->get()->uses) {
|
||||||
|
p_list->push_back(E->get()->info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiNodeEdit::clear_nodes() {
|
||||||
|
|
||||||
|
nodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiNodeEdit::add_node(const NodePath& p_node){
|
||||||
|
|
||||||
|
nodes.push_back(p_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiNodeEdit::MultiNodeEdit()
|
||||||
|
{
|
||||||
|
}
|
32
tools/editor/multi_node_edit.h
Normal file
32
tools/editor/multi_node_edit.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef MULTI_NODE_EDIT_H
|
||||||
|
#define MULTI_NODE_EDIT_H
|
||||||
|
|
||||||
|
#include "scene/main/node.h"
|
||||||
|
|
||||||
|
class MultiNodeEdit : public Reference {
|
||||||
|
|
||||||
|
OBJ_TYPE(MultiNodeEdit,Reference);
|
||||||
|
|
||||||
|
List<NodePath> nodes;
|
||||||
|
struct PLData {
|
||||||
|
int uses;
|
||||||
|
PropertyInfo info;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool _set(const StringName& p_name, const Variant& p_value);
|
||||||
|
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||||
|
void _get_property_list( List<PropertyInfo> *p_list) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void clear_nodes();
|
||||||
|
void add_node(const NodePath& p_node);
|
||||||
|
|
||||||
|
MultiNodeEdit();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MULTI_NODE_EDIT_H
|
@ -39,6 +39,7 @@
|
|||||||
#include "editor_settings.h"
|
#include "editor_settings.h"
|
||||||
#include "editor_import_export.h"
|
#include "editor_import_export.h"
|
||||||
#include "editor_node.h"
|
#include "editor_node.h"
|
||||||
|
#include "multi_node_edit.h"
|
||||||
|
|
||||||
void CustomPropertyEditor::_notification(int p_what) {
|
void CustomPropertyEditor::_notification(int p_what) {
|
||||||
|
|
||||||
@ -2676,7 +2677,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!undo_redo) {
|
if (!undo_redo || obj->cast_to<MultiNodeEdit>()) { //kind of hacky
|
||||||
|
|
||||||
obj->set(p_name,p_value);
|
obj->set(p_name,p_value);
|
||||||
_changed_callbacks(obj,p_name);
|
_changed_callbacks(obj,p_name);
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
|
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
|
||||||
#include "script_editor_debugger.h"
|
#include "script_editor_debugger.h"
|
||||||
#include "tools/editor/plugins/script_editor_plugin.h"
|
#include "tools/editor/plugins/script_editor_plugin.h"
|
||||||
|
#include "multi_node_edit.h"
|
||||||
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
|
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
|
||||||
|
|
||||||
|
|
||||||
@ -449,6 +449,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||||||
reparent_dialog->popup_centered_ratio();
|
reparent_dialog->popup_centered_ratio();
|
||||||
reparent_dialog->set_current( nodeset );
|
reparent_dialog->set_current( nodeset );
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case TOOL_MULTI_EDIT: {
|
||||||
|
|
||||||
|
Node*root=EditorNode::get_singleton()->get_edited_scene();
|
||||||
|
if (!root)
|
||||||
|
break;
|
||||||
|
Ref<MultiNodeEdit> mne = memnew( MultiNodeEdit );
|
||||||
|
for (const Map<Node*,Object*>::Element *E=EditorNode::get_singleton()->get_editor_selection()->get_selection().front();E;E=E->next()) {
|
||||||
|
mne->add_node(root->get_path_to(E->key()));
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorNode::get_singleton()->push_item(mne.ptr());
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case TOOL_ERASE: {
|
case TOOL_ERASE: {
|
||||||
|
|
||||||
@ -507,6 +520,7 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
"MoveDown",
|
"MoveDown",
|
||||||
"Duplicate",
|
"Duplicate",
|
||||||
"Reparent",
|
"Reparent",
|
||||||
|
"MultiNodeEdit",
|
||||||
"Remove",
|
"Remove",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -515,6 +529,8 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
for(int i=0;i<TOOL_BUTTON_MAX;i++)
|
for(int i=0;i<TOOL_BUTTON_MAX;i++)
|
||||||
tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons"));
|
tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons"));
|
||||||
|
|
||||||
|
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed");
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,9 +1091,19 @@ void SceneTreeDock::_update_tool_buttons() {
|
|||||||
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
|
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
|
||||||
tool_buttons[TOOL_REPARENT]->set_disabled(disable_root);
|
tool_buttons[TOOL_REPARENT]->set_disabled(disable_root);
|
||||||
tool_buttons[TOOL_ERASE]->set_disabled(disable);
|
tool_buttons[TOOL_ERASE]->set_disabled(disable);
|
||||||
|
tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SceneTreeDock::_selection_changed() {
|
||||||
|
|
||||||
|
tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SceneTreeDock::_create() {
|
void SceneTreeDock::_create() {
|
||||||
|
|
||||||
|
|
||||||
@ -1262,6 +1288,7 @@ void SceneTreeDock::_bind_methods() {
|
|||||||
ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm);
|
ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm);
|
||||||
ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed);
|
ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed);
|
||||||
ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene);
|
ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene);
|
||||||
|
ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed);
|
||||||
|
|
||||||
ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance);
|
ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance);
|
||||||
}
|
}
|
||||||
@ -1364,6 +1391,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
|
|||||||
|
|
||||||
hbc_bottom->add_spacer();
|
hbc_bottom->add_spacer();
|
||||||
|
|
||||||
|
tb = memnew( ToolButton );
|
||||||
|
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_MULTI_EDIT, false));
|
||||||
|
tb->set_tooltip("Multi-Edit Selected Nodes");
|
||||||
|
hbc_bottom->add_child(tb);
|
||||||
|
tool_buttons[TOOL_MULTI_EDIT]=tb;
|
||||||
|
|
||||||
tb = memnew( ToolButton );
|
tb = memnew( ToolButton );
|
||||||
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false));
|
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false));
|
||||||
tb->set_tooltip("Erase Selected Node(s)");
|
tb->set_tooltip("Erase Selected Node(s)");
|
||||||
|
@ -62,6 +62,7 @@ class SceneTreeDock : public VBoxContainer {
|
|||||||
TOOL_MOVE_DOWN,
|
TOOL_MOVE_DOWN,
|
||||||
TOOL_DUPLICATE,
|
TOOL_DUPLICATE,
|
||||||
TOOL_REPARENT,
|
TOOL_REPARENT,
|
||||||
|
TOOL_MULTI_EDIT,
|
||||||
TOOL_ERASE,
|
TOOL_ERASE,
|
||||||
TOOL_BUTTON_MAX
|
TOOL_BUTTON_MAX
|
||||||
};
|
};
|
||||||
@ -119,6 +120,7 @@ class SceneTreeDock : public VBoxContainer {
|
|||||||
void _import_subscene();
|
void _import_subscene();
|
||||||
|
|
||||||
bool _validate_no_foreign();
|
bool _validate_no_foreign();
|
||||||
|
void _selection_changed();
|
||||||
|
|
||||||
void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames);
|
void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user