Multiple, simultaneous node editing spuport!!

..but will you be brave enough to try it? :)
This commit is contained in:
Juan Linietsky 2015-08-25 00:08:45 -03:00
parent 0d77277a86
commit eff2931b2a
9 changed files with 199 additions and 10 deletions

View file

@ -39,7 +39,7 @@ void EditorHistory::_cleanup_history() {
bool fail=false;
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;
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);
ERR_FAIL_COND(!obj);
Resource *r = obj->cast_to<Resource>();
Reference *r = obj->cast_to<Reference>();
Obj o;
if (r)
o.res=RES(r);
o.ref=REF(r);
o.object=p_object;
o.property=p_property;

View file

@ -45,7 +45,7 @@ class EditorHistory {
struct Obj {
RES res;
REF ref;
ObjectID object;
String property;
};

View file

@ -1427,10 +1427,7 @@ void EditorNode::_edit_current() {
resources_dock->add_resource(Ref<Resource>(current_res));
//top_pallete->set_current_tab(1);
}
if (current_obj->is_type("Node")) {
} else if (current_obj->is_type("Node")) {
Node * current_node = current_obj->cast_to<Node>();
ERR_FAIL_COND(!current_node);
@ -1445,6 +1442,12 @@ void EditorNode::_edit_current() {
//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 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

View 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()
{
}

View 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

View file

@ -39,6 +39,7 @@
#include "editor_settings.h"
#include "editor_import_export.h"
#include "editor_node.h"
#include "multi_node_edit.h"
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);
_changed_callbacks(obj,p_name);

View file

@ -35,7 +35,7 @@
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
#include "script_editor_debugger.h"
#include "tools/editor/plugins/script_editor_plugin.h"
#include "multi_node_edit.h"
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->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;
case TOOL_ERASE: {
@ -507,6 +520,7 @@ void SceneTreeDock::_notification(int p_what) {
"MoveDown",
"Duplicate",
"Reparent",
"MultiNodeEdit",
"Remove",
};
@ -515,6 +529,8 @@ void SceneTreeDock::_notification(int p_what) {
for(int i=0;i<TOOL_BUTTON_MAX;i++)
tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons"));
EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed");
} break;
}
}
@ -1075,9 +1091,19 @@ void SceneTreeDock::_update_tool_buttons() {
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
tool_buttons[TOOL_REPARENT]->set_disabled(disable_root);
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() {
@ -1262,6 +1288,7 @@ void SceneTreeDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm);
ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed);
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);
}
@ -1364,6 +1391,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
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->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false));
tb->set_tooltip("Erase Selected Node(s)");

View file

@ -62,6 +62,7 @@ class SceneTreeDock : public VBoxContainer {
TOOL_MOVE_DOWN,
TOOL_DUPLICATE,
TOOL_REPARENT,
TOOL_MULTI_EDIT,
TOOL_ERASE,
TOOL_BUTTON_MAX
};
@ -119,6 +120,7 @@ class SceneTreeDock : public VBoxContainer {
void _import_subscene();
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);