Large improvements on scene packing and management

-Ability to edit and keep changes of instanced scenes and sub-scenes
-Ability to inherit from other scenes
This commit is contained in:
reduz 2015-10-10 09:09:09 -03:00
parent afbb0ca8d7
commit 422929e87f
19 changed files with 2313 additions and 223 deletions

View file

@ -286,6 +286,37 @@ NodePath::NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_
data->property=p_property;
}
void NodePath::simplify() {
if (!data)
return;
for(int i=0;i<data->path.size();i++) {
if (data->path.size()==1)
break;
if (data->path[i].operator String()==".") {
data->path.remove(i);
i--;
} else if (data->path[i].operator String()==".." && i>0 && data->path[i-1].operator String()!="." && data->path[i-1].operator String()!="..") {
//remove both
data->path.remove(i-1);
data->path.remove(i-1);
i-=2;
if (data->path.size()==0) {
data->path.push_back(".");
break;
}
}
}
}
NodePath NodePath::simplified() const {
NodePath np=*this;
np.simplify();
return np;
}
NodePath::NodePath(const String& p_path) {
data=NULL;

View file

@ -84,7 +84,10 @@ public:
bool operator==(const NodePath& p_path) const;
bool operator!=(const NodePath& p_path) const;
void operator=(const NodePath& p_path);
void simplify();
NodePath simplified() const;
NodePath(const Vector<StringName>& p_path,bool p_absolute,const String& p_property="");
NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
NodePath(const NodePath& p_path);

View file

@ -130,7 +130,7 @@ public:
void set_name(const String& p_name);
String get_name() const;
void set_path(const String& p_path,bool p_take_over=false);
virtual void set_path(const String& p_path,bool p_take_over=false);
String get_path() const;
void set_subindex(int p_sub_index);

View file

@ -18,3 +18,11 @@ func _ready():
# Initalization here
pass
func _on_coin_area_enter( area ):
pass # replace with function body
func _on_coin_area_enter_shape( area_id, area, area_shape, area_shape ):
pass # replace with function body

View file

@ -841,6 +841,20 @@ Node *Node::get_child(int p_index) const {
return data.children[p_index];
}
Node *Node::_get_child_by_name(const StringName& p_name) const {
int cc=data.children.size();
Node* const* cd=data.children.ptr();
for(int i=0;i<cc;i++){
if (cd[i]->data.name==p_name)
return cd[i];
}
return NULL;
}
Node *Node::_get_node(const NodePath& p_path) const {
ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
@ -906,8 +920,10 @@ Node *Node::_get_node(const NodePath& p_path) const {
Node *Node::get_node(const NodePath& p_path) const {
Node *node = _get_node(p_path);
ERR_EXPLAIN("Node not found: "+p_path);
ERR_FAIL_COND_V(!node,NULL);
if (!node) {
ERR_EXPLAIN("Node not found: "+p_path);
ERR_FAIL_COND_V(!node,NULL);
}
return node;
}
@ -1332,7 +1348,29 @@ String Node::get_filename() const {
return data.filename;
}
void Node::set_editable_instance(Node* p_node,bool p_editable) {
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(!is_a_parent_of(p_node));
NodePath p = get_path_to(p_node);
if (!p_editable)
data.editable_instances.erase(p);
else
data.editable_instances[p]=true;
}
bool Node::is_editable_instance(Node *p_node) const {
if (!p_node)
return false; //easier, null is never editable :)
ERR_FAIL_COND_V(!is_a_parent_of(p_node),false);
NodePath p = get_path_to(p_node);
return data.editable_instances.has(p);
}
#if 0
void Node::generate_instance_state() {
@ -1383,6 +1421,28 @@ Dictionary Node::get_instance_state() const {
return data.instance_state;
}
#endif
void Node::set_scene_instance_state(const Ref<SceneState>& p_state) {
data.instance_state=p_state;
}
Ref<SceneState> Node::get_scene_instance_state() const{
return data.instance_state;
}
void Node::set_scene_inherited_state(const Ref<SceneState>& p_state) {
data.inherited_state=p_state;
}
Ref<SceneState> Node::get_scene_inherited_state() const{
return data.inherited_state;
}
Vector<StringName> Node::get_instance_groups() const {
return data.instance_groups;

View file

@ -38,6 +38,7 @@
class Viewport;
class SceneState;
class Node : public Object {
OBJ_TYPE( Node, Object );
@ -69,7 +70,11 @@ private:
struct Data {
String filename;
Dictionary instance_state;
Ref<SceneState> instance_state;
Ref<SceneState> inherited_state;
HashMap<NodePath,int> editable_instances;
Vector<StringName> instance_groups;
Vector<Connection> instance_connections;
@ -96,6 +101,7 @@ private:
PauseMode pause_mode;
Node *pause_owner;
// variables used to properly sort the node when processing, ignored otherwise
//should move all the stuff below to bits
bool fixed_process;
bool idle_process;
@ -105,6 +111,7 @@ private:
bool parent_owned;
bool in_constructor;
} data;
@ -112,6 +119,7 @@ private:
virtual bool _use_builtin_script() const { return true; }
Node *_get_node(const NodePath& p_path) const;
Node *_get_child_by_name(const StringName& p_name) const;
@ -151,7 +159,7 @@ protected:
static void _bind_methods();
friend class PackedScene;
friend class SceneState;
void _add_child_nocheck(Node* p_child,const StringName& p_name);
void _set_owner_nocheck(Node* p_owner);
@ -208,7 +216,7 @@ public:
struct GroupInfo {
String name;
StringName name;
bool persistent;
};
@ -229,7 +237,10 @@ public:
void set_filename(const String& p_filename);
String get_filename() const;
void set_editable_instance(Node* p_node,bool p_editable);
bool is_editable_instance(Node* p_node) const;
/* NOTIFICATIONS */
void propagate_notification(int p_notification);
@ -261,8 +272,12 @@ public:
//Node *clone_tree() const;
// used by editors, to save what has changed only
void generate_instance_state();
Dictionary get_instance_state() const;
void set_scene_instance_state(const Ref<SceneState>& p_state);
Ref<SceneState> get_scene_instance_state() const;
void set_scene_inherited_state(const Ref<SceneState>& p_state);
Ref<SceneState> get_scene_inherited_state() const;
Vector<StringName> get_instance_groups() const;
Vector<Connection> get_instance_connections() const;

View file

@ -216,7 +216,7 @@
#include "scene/3d/collision_polygon.h"
#endif
#include "scene/resources/scene_format_text.h"
static ResourceFormatLoaderImage *resource_loader_image=NULL;
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
@ -229,6 +229,8 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
static ResourceFormatLoaderShader *resource_loader_shader=NULL;
static ResourceFormatSaverText *resource_saver_text=NULL;
//static SceneStringNames *string_names;
void register_scene_types() {
@ -612,6 +614,9 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
resource_saver_text = memnew( ResourceFormatSaverText );
ResourceSaver::add_resource_format_saver(resource_saver_text);
}
void unregister_scene_types() {
@ -629,5 +634,9 @@ void unregister_scene_types() {
memdelete( resource_loader_theme );
memdelete( resource_loader_shader );
if (resource_saver_text) {
memdelete(resource_saver_text);
}
SceneStringNames::free();
}

File diff suppressed because it is too large Load diff

View file

@ -32,18 +32,32 @@
#include "resource.h"
#include "scene/main/node.h"
class PackedScene : public Resource {
OBJ_TYPE( PackedScene, Resource );
RES_BASE_EXTENSION("scn");
class SceneState : public Reference {
OBJ_TYPE( SceneState, Reference );
Vector<StringName> names;
Vector<Variant> variants;
Vector<NodePath> node_paths;
Vector<NodePath> editable_instances;
mutable HashMap<NodePath,int> node_path_cache;
mutable Map<int,int> base_scene_node_remap;
int base_scene_idx;
//missing - instances
//missing groups
//missing - owner
//missing - override names and values
enum {
FLAG_ID_IS_PATH=(1<<30),
FLAG_MASK=(1<<24)-1,
NO_PARENT_SAVED=0x7FFFFFFF,
TYPE_INSTANCED=0x7FFFFFFF,
};
struct NodeData {
int parent;
@ -59,9 +73,15 @@ class PackedScene : public Resource {
};
Vector<Property> properties;
Vector<int> groups;
Vector<int> groups;
};
struct PackState {
Ref<SceneState> state;
int node;
PackState() { node=-1; }
};
Vector<NodeData> nodes;
@ -77,16 +97,75 @@ class PackedScene : public Resource {
Vector<ConnectionData> connections;
Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
String path;
_FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
public:
int find_node_by_path(const NodePath& p_node) const;
Variant get_property_value(int p_node,const StringName& p_property,bool &found) const;
bool is_node_in_group(int p_node,const StringName& p_group) const;
bool is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const;
void set_bundled_scene(const Dictionary& p_dictionary);
Dictionary get_bundled_scene() const;
Error pack(Node *p_scene);
void set_path(const String &p_path);
String get_path() const;
void clear();
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
//build-unbuild API
int get_node_count() const;
StringName get_node_type(int p_idx) const;
StringName get_node_name(int p_idx) const;
NodePath get_node_path(int p_idx,bool p_for_parent=false) const;
NodePath get_node_owner_path(int p_idx) const;
Ref<PackedScene> get_node_instance(int p_idx) const;
Vector<StringName> get_node_groups(int p_idx) const;
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx,int p_prop) const;
Variant get_node_property_value(int p_idx,int p_prop) const;
int get_connection_count() const;
NodePath get_connection_source(int p_idx) const;
StringName get_connection_signal(int p_idx) const;
NodePath get_connection_target(int p_idx) const;
StringName get_connection_method(int p_idx) const;
int get_connection_flags(int p_idx) const;
Array get_connection_binds(int p_idx) const;
Vector<NodePath> get_editable_instances() const;
SceneState();
};
class PackedScene : public Resource {
OBJ_TYPE(PackedScene, Resource );
RES_BASE_EXTENSION("scn");
Ref<SceneState> state;
void _set_bundled_scene(const Dictionary& p_scene);
Dictionary _get_bundled_scene() const;
protected:
static void _bind_methods();
public:
@ -98,7 +177,12 @@ public:
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
virtual void set_path(const String& p_path,bool p_take_over=false);
Ref<SceneState> get_state();
PackedScene();
};
#endif // SCENE_PRELOADER_H

View file

@ -0,0 +1,792 @@
#include "scene_format_text.h"
#include "globals.h"
#include "version.h"
#include "os/dir_access.h"
#define FORMAT_VERSION 1
void ResourceFormatSaverTextInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
if (r_ok)
*r_ok=false;
if (p_name!=String()) {
f->store_string(p_name+" = ");
}
switch( p_property.get_type() ) {
case Variant::NIL: {
f->store_string("null");
} break;
case Variant::BOOL: {
f->store_string(p_property.operator bool() ? "true":"false" );
} break;
case Variant::INT: {
f->store_string( itos(p_property.operator int()) );
} break;
case Variant::REAL: {
f->store_string( rtoss(p_property.operator real_t()) );
} break;
case Variant::STRING: {
String str=p_property;
str="\""+str.c_escape()+"\"";
f->store_string( str );
} break;
case Variant::VECTOR2: {
Vector2 v = p_property;
f->store_string("Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" );
} break;
case Variant::RECT2: {
Rect2 aabb = p_property;
f->store_string("Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" );
} break;
case Variant::VECTOR3: {
Vector3 v = p_property;
f->store_string("Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )");
} break;
case Variant::PLANE: {
Plane p = p_property;
f->store_string("Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" );
} break;
case Variant::_AABB: {
AABB aabb = p_property;
f->store_string("AABB( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z)+" )" );
} break;
case Variant::QUAT: {
Quat quat = p_property;
f->store_string("Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )");
} break;
case Variant::MATRIX32: {
String s="Matrix32( ";
Matrix32 m3 = p_property;
for (int i=0;i<3;i++) {
for (int j=0;j<2;j++) {
if (i!=0 || j!=0)
s+=", ";
s+=rtoss( m3.elements[i][j] );
}
}
f->store_string(s+" )");
} break;
case Variant::MATRIX3: {
String s="Matrix3( ";
Matrix3 m3 = p_property;
for (int i=0;i<3;i++) {
for (int j=0;j<3;j++) {
if (i!=0 || j!=0)
s+=", ";
s+=rtoss( m3.elements[i][j] );
}
}
f->store_string(s+" )");
} break;
case Variant::TRANSFORM: {
String s="Transform( ";
Transform t = p_property;
Matrix3 &m3 = t.basis;
for (int i=0;i<3;i++) {
for (int j=0;j<3;j++) {
if (i!=0 || j!=0)
s+=", ";
s+=rtoss( m3.elements[i][j] );
}
}
s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
f->store_string(s+" )");
} break;
// misc types
case Variant::COLOR: {
Color c = p_property;
f->store_string("Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )");
} break;
case Variant::IMAGE: {
Image img=p_property;
if (img.empty()) {
f->store_string("RawImage()");
break;
}
String imgstr="RawImage( ";
imgstr+=itos(img.get_width());
imgstr+=", "+itos(img.get_height());
imgstr+=", "+itos(img.get_mipmaps());
imgstr+=", ";
switch(img.get_format()) {
case Image::FORMAT_GRAYSCALE: imgstr+="GRAYSCALE"; break;
case Image::FORMAT_INTENSITY: imgstr+="INTENSITY"; break;
case Image::FORMAT_GRAYSCALE_ALPHA: imgstr+="GRAYSCALE_ALPHA"; break;
case Image::FORMAT_RGB: imgstr+="RGB"; break;
case Image::FORMAT_RGBA: imgstr+="RGBA"; break;
case Image::FORMAT_INDEXED : imgstr+="INDEXED"; break;
case Image::FORMAT_INDEXED_ALPHA: imgstr+="INDEXED_ALPHA"; break;
case Image::FORMAT_BC1: imgstr+="BC1"; break;
case Image::FORMAT_BC2: imgstr+="BC2"; break;
case Image::FORMAT_BC3: imgstr+="BC3"; break;
case Image::FORMAT_BC4: imgstr+="BC4"; break;
case Image::FORMAT_BC5: imgstr+="BC5"; break;
case Image::FORMAT_PVRTC2: imgstr+="PVRTC2"; break;
case Image::FORMAT_PVRTC2_ALPHA: imgstr+="PVRTC2_ALPHA"; break;
case Image::FORMAT_PVRTC4: imgstr+="PVRTC4"; break;
case Image::FORMAT_PVRTC4_ALPHA: imgstr+="PVRTC4_ALPHA"; break;
case Image::FORMAT_ETC: imgstr+="ETC"; break;
case Image::FORMAT_ATC: imgstr+="ATC"; break;
case Image::FORMAT_ATC_ALPHA_EXPLICIT: imgstr+="ATC_ALPHA_EXPLICIT"; break;
case Image::FORMAT_ATC_ALPHA_INTERPOLATED: imgstr+="ATC_ALPHA_INTERPOLATED"; break;
case Image::FORMAT_CUSTOM: imgstr+="CUSTOM"; break;
default: {}
}
String s;
DVector<uint8_t> data = img.get_data();
int len = data.size();
DVector<uint8_t>::Read r = data.read();
const uint8_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
uint8_t byte = ptr[i];
const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
s+=str;
}
imgstr+=", ";
f->store_string(imgstr);
f->store_string(s);
f->store_string(" )");
} break;
case Variant::NODE_PATH: {
String str=p_property;
str="NodePath(\""+str.c_escape()+"\")";
f->store_string(str);
} break;
case Variant::OBJECT: {
RES res = p_property;
if (res.is_null()) {
f->store_string("null");
if (r_ok)
*r_ok=true;
break; // don't save it
}
if (external_resources.has(res)) {
f->store_string("ExtResource( "+itos(external_resources[res]+1)+" )");
} else {
if (internal_resources.has(res)) {
f->store_string("SubResource( "+itos(internal_resources[res])+" )");
} else if (res->get_path().length() && res->get_path().find("::")==-1) {
//external resource
String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
f->store_string("Resource( \""+path+"\" )");
} else {
f->store_string("null");
ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
ERR_BREAK(true);
//internal resource
}
}
} break;
case Variant::INPUT_EVENT: {
f->store_string("InputEvent()"); //will be added later
} break;
case Variant::DICTIONARY: {
Dictionary dict = p_property;
List<Variant> keys;
dict.get_key_list(&keys);
keys.sort();
f->store_string("{ ");
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
//if (!_check_type(dict[E->get()]))
// continue;
bool ok;
write_property("",E->get(),&ok);
ERR_CONTINUE(!ok);
f->store_string(":");
write_property("",dict[E->get()],&ok);
if (!ok)
write_property("",Variant()); //at least make the file consistent..
if (E->next())
f->store_string(", ");
}
f->store_string(" }");
} break;
case Variant::ARRAY: {
f->store_string("[ ");
Array array = p_property;
int len=array.size();
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
write_property("",array[i]);
}
f->store_string(" ]");
} break;
case Variant::RAW_ARRAY: {
f->store_string("RawArray( ");
String s;
DVector<uint8_t> data = p_property;
int len = data.size();
DVector<uint8_t>::Read r = data.read();
const uint8_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
uint8_t byte = ptr[i];
const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
f->store_string(str);
}
f->store_string(" )");
} break;
case Variant::INT_ARRAY: {
f->store_string("IntArray( ");
DVector<int> data = p_property;
int len = data.size();
DVector<int>::Read r = data.read();
const int *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(itos(ptr[i]));
}
f->store_string(" )");
} break;
case Variant::REAL_ARRAY: {
f->store_string("FloatArray( ");
DVector<real_t> data = p_property;
int len = data.size();
DVector<real_t>::Read r = data.read();
const real_t *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i]));
}
f->store_string(" )");
} break;
case Variant::STRING_ARRAY: {
f->store_string("StringArray( ");
DVector<String> data = p_property;
int len = data.size();
DVector<String>::Read r = data.read();
const String *ptr=r.ptr();;
String s;
//write_string("\n");
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
String str=ptr[i];
f->store_string(""+str.c_escape()+"\"");
}
f->store_string(" )");
} break;
case Variant::VECTOR2_ARRAY: {
f->store_string("Vector2Array( ");
DVector<Vector2> data = p_property;
int len = data.size();
DVector<Vector2>::Read r = data.read();
const Vector2 *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) );
}
f->store_string(" )");
} break;
case Variant::VECTOR3_ARRAY: {
f->store_string("Vector3Array( ");
DVector<Vector3> data = p_property;
int len = data.size();
DVector<Vector3>::Read r = data.read();
const Vector3 *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) );
}
f->store_string(" )");
} break;
case Variant::COLOR_ARRAY: {
f->store_string("ColorArray( ");
DVector<Color> data = p_property;
int len = data.size();
DVector<Color>::Read r = data.read();
const Color *ptr=r.ptr();;
for (int i=0;i<len;i++) {
if (i>0)
f->store_string(", ");
f->store_string(rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) );
}
f->store_string(" )");
} break;
default: {}
}
if (r_ok)
*r_ok=true;
}
void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) {
switch(p_variant.get_type()) {
case Variant::OBJECT: {
RES res = p_variant.operator RefPtr();
if (res.is_null() || external_resources.has(res))
return;
if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
int index = external_resources.size();
external_resources[res]=index;
return;
}
if (resource_set.has(res))
return;
List<PropertyInfo> property_list;
res->get_property_list( &property_list );
property_list.sort();
List<PropertyInfo>::Element *I=property_list.front();
while(I) {
PropertyInfo pi=I->get();
if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
Variant v=res->get(I->get().name);
_find_resources(v);
}
I=I->next();
}
resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
saved_resources.push_back(res);
} break;
case Variant::ARRAY: {
Array varray=p_variant;
int len=varray.size();
for(int i=0;i<len;i++) {
Variant v=varray.get(i);
_find_resources(v);
}
} break;
case Variant::DICTIONARY: {
Dictionary d=p_variant;
List<Variant> keys;
d.get_key_list(&keys);
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
Variant v = d[E->get()];
_find_resources(v);
}
} break;
default: {}
}
}
Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
if (p_path.ends_with(".tscn")) {
packed_scene=p_resource;
}
Error err;
f = FileAccess::open(p_path, FileAccess::WRITE,&err);
ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
FileAccessRef _fref(f);
local_path = Globals::get_singleton()->localize_path(p_path);
relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
if (!p_path.begins_with("res://")) {
takeover_paths=false;
}
// save resources
_find_resources(p_resource,true);
if (packed_scene.is_valid()) {
//add instances to external resources if saving a packed scene
for(int i=0;i<packed_scene->get_state()->get_node_count();i++) {
Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i);
if (instance.is_valid() && !external_resources.has(instance)) {
int index = external_resources.size();
external_resources[instance]=index;
}
}
}
ERR_FAIL_COND_V(err!=OK,err);
{
String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource ";
if (packed_scene.is_null())
title+="type=\""+p_resource->get_type()+"\" ";
int load_steps=saved_resources.size()+external_resources.size();
//if (packed_scene.is_valid()) {
// load_steps+=packed_scene->get_node_count();
//}
//no, better to not use load steps from nodes, no point to that
if (load_steps>1) {
title+="load_steps="+itos(load_steps)+" ";
}
title+="format="+itos(FORMAT_VERSION)+"";
//title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";
f->store_string(title);
f->store_line("]\n"); //one empty line
}
for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
String p = E->key()->get_path();
f->store_string("[ext_resource path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" id="+itos(E->get()+1)+"]\n"); //bundled
}
if (external_resources.size())
f->store_line(String()); //separate
Set<int> used_indices;
for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
RES res = E->get();
if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) {
if (res->get_subindex()!=0) {
if (used_indices.has(res->get_subindex())) {
res->set_subindex(0); //repeated
} else {
used_indices.insert(res->get_subindex());
}
}
}
}
for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
RES res = E->get();
ERR_CONTINUE(!resource_set.has(res));
bool main = (E->next()==NULL);
if (main && packed_scene.is_valid())
break; //save as a scene
if (main) {
f->store_line("[resource]\n");
} else {
String line="[sub_resource ";
if (res->get_subindex()==0) {
int new_subindex=1;
if (used_indices.size()) {
new_subindex=used_indices.back()->get()+1;
}
res->set_subindex(new_subindex);
used_indices.insert(new_subindex);
}
int idx = res->get_subindex();
line+="type=\""+res->get_type()+"\" id="+itos(idx);
f->store_line(line+"]\n");
if (takeover_paths) {
res->set_path(p_path+"::"+itos(idx),true);
}
internal_resources[res]=idx;
}
List<PropertyInfo> property_list;
res->get_property_list(&property_list);
// property_list.sort();
for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
if (skip_editor && PE->get().name.begins_with("__editor"))
continue;
if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
String name = PE->get().name;
Variant value = res->get(name);
if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
continue;
if (PE->get().type==Variant::OBJECT && value.is_zero())
continue;
write_property(name,value);
f->store_string("\n");
}
}
f->store_string("\n");
}
if (packed_scene.is_valid()) {
//if this is a scene, save nodes and connections!
Ref<SceneState> state = packed_scene->get_state();
for(int i=0;i<state->get_node_count();i++) {
StringName type = state->get_node_type(i);
StringName name = state->get_node_name(i);
NodePath path = state->get_node_path(i,true);
NodePath owner = state->get_node_owner_path(i);
Ref<PackedScene> instance = state->get_node_instance(i);
Vector<StringName> groups = state->get_node_groups(i);
String header="[node";
header+=" name=\""+String(name)+"\"";
if (type!=StringName()) {
header+=" type=\""+String(type)+"\"";
}
if (path!=NodePath()) {
header+=" parent=\""+String(path.simplified())+"\"";
}
if (owner!=NodePath() && owner!=NodePath(".")) {
header+=" owner=\""+String(owner.simplified())+"\"";
}
if (groups.size()) {
String sgroups=" groups=[ ";
for(int j=0;j<groups.size();j++) {
if (j>0)
sgroups+=", ";
sgroups+="\""+groups[i].operator String().c_escape()+"\"";
}
sgroups+=" ]";
header+=sgroups;
}
f->store_string(header);
if (instance.is_valid()) {
f->store_string(" instance=");
write_property("",instance);
}
f->store_line("]\n");
for(int j=0;j<state->get_node_property_count(i);j++) {
write_property(state->get_node_property_name(i,j),state->get_node_property_value(i,j));
f->store_line(String());
}
if (state->get_node_property_count(i)) {
//add space
f->store_line(String());
}
}
for(int i=0;i<state->get_connection_count();i++) {
String connstr="[connection";
connstr+=" signal=\""+String(state->get_connection_signal(i))+"\"";
connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\"";
connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\"";
connstr+=" method=\""+String(state->get_connection_method(i))+"\"";
int flags = state->get_connection_flags(i);
if (flags!=Object::CONNECT_PERSIST) {
connstr+=" flags="+itos(flags);
}
Array binds=state->get_connection_binds(i);
f->store_string(connstr);
if (binds.size()) {
f->store_string(" binds=");
write_property("",binds);
}
f->store_line("]\n");
}
f->store_line(String());
Vector<NodePath> editable_instances = state->get_editable_instances();
for(int i=0;i<editable_instances.size();i++) {
f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]");
}
}
if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
f->close();
return ERR_CANT_CREATE;
}
f->close();
//memdelete(f);
return OK;
}
Error ResourceFormatSaverText::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
if (p_path.ends_with(".sct") && p_resource->get_type()!="PackedScene") {
return ERR_FILE_UNRECOGNIZED;
}
ResourceFormatSaverTextInstance saver;
return saver.save(p_path,p_resource,p_flags);
}
bool ResourceFormatSaverText::recognize(const RES& p_resource) const {
return true; // all recognized!
}
void ResourceFormatSaverText::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
p_extensions->push_back("tres"); //text resource
if (p_resource->get_type()=="PackedScene")
p_extensions->push_back("tscn"); //text scene
}
ResourceFormatSaverText* ResourceFormatSaverText::singleton=NULL;
ResourceFormatSaverText::ResourceFormatSaverText() {
singleton=this;
}

View file

@ -0,0 +1,46 @@
#ifndef SCENE_FORMAT_TEXT_H
#define SCENE_FORMAT_TEXT_H
#include "io/resource_loader.h"
#include "io/resource_saver.h"
#include "os/file_access.h"
#include "scene/resources/packed_scene.h"
class ResourceFormatSaverTextInstance {
String local_path;
Ref<PackedScene> packed_scene;
bool takeover_paths;
bool relative_paths;
bool bundle_resources;
bool skip_editor;
FileAccess *f;
Set<RES> resource_set;
List<RES> saved_resources;
Map<RES,int> external_resources;
Map<RES,int> internal_resources;
void _find_resources(const Variant& p_variant,bool p_main=false);
void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
public:
Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
};
class ResourceFormatSaverText : public ResourceFormatSaver {
public:
static ResourceFormatSaverText* singleton;
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
virtual bool recognize(const RES& p_resource) const;
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
ResourceFormatSaverText();
};
#endif // SCENE_FORMAT_TEXT_H

View file

@ -1107,6 +1107,11 @@ void EditorNode::_dialog_action(String p_file) {
push_item(res.operator->() );
} break;
case FILE_NEW_INHERITED_SCENE: {
load_scene(p_file,false,true);
} break;
case FILE_OPEN_SCENE: {
@ -1930,6 +1935,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
case FILE_NEW_INHERITED_SCENE:
case FILE_OPEN_SCENE: {
@ -1950,7 +1956,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
if (scene) {
file->set_current_path(scene->get_filename());
};
file->set_title("Open Scene");
file->set_title(p_option==FILE_OPEN_SCENE?"Open Scene":"Open Base Scene");
file->popup_centered_ratio();
} break;
@ -3311,7 +3317,7 @@ void EditorNode::fix_dependencies(const String& p_for_file) {
dependency_fixer->edit(p_for_file);
}
Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bool p_set_inherited) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
@ -3441,6 +3447,13 @@ Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
}
*/
if (p_set_inherited) {
Ref<SceneState> state = sdata->get_state();
state->set_path(lpath);
new_scene->set_scene_inherited_state(state);
}
set_edited_scene(new_scene);
_get_scene_metadata();
/*
@ -4793,6 +4806,7 @@ EditorNode::EditorNode() {
file_menu->set_tooltip("Operations with scene files.");
p=file_menu->get_popup();
p->add_item("New Scene",FILE_NEW_SCENE);
p->add_item("New Inherited Scene..",FILE_NEW_INHERITED_SCENE);
p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
p->add_separator();
p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);

View file

@ -107,6 +107,7 @@ class EditorNode : public Node {
enum MenuOptions {
FILE_NEW_SCENE,
FILE_NEW_INHERITED_SCENE,
FILE_OPEN_SCENE,
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
@ -565,7 +566,7 @@ public:
void fix_dependencies(const String& p_for_file);
void clear_scene() { _cleanup_scene(); }
Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false);
Error load_scene(const String& p_scene, bool p_ignore_broken_deps=false, bool p_set_inherited=false);
Error load_resource(const String& p_scene);
bool is_scene_open(const String& p_path);

View file

@ -42,6 +42,8 @@
#include "multi_node_edit.h"
#include "array_property_edit.h"
#include "editor_help.h"
#include "scene/resources/packed_scene.h"
void CustomPropertyEditor::_notification(int p_what) {
@ -1655,25 +1657,101 @@ CustomPropertyEditor::CustomPropertyEditor() {
menu->connect("item_pressed",this,"_menu_option");
}
bool PropertyEditor::_might_be_in_instance() {
Node *PropertyEditor::get_instanced_node() {
//this sucks badly
if (!obj)
return NULL;
Node *node = obj->cast_to<Node>();
Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
bool might_be=false;
while(node) {
if (node->get_scene_instance_state().is_valid()) {
might_be=true;
break;
}
if (node==edited_scene) {
if (node->get_scene_inherited_state().is_valid()) {
might_be=true;
break;
}
might_be=false;
break;
}
node=node->get_owner();
}
return might_be;
}
bool PropertyEditor::_get_instanced_node_original_property(const StringName& p_prop,Variant& value) {
Node *node = obj->cast_to<Node>();
if (!node)
return NULL;
return false;
if (node->get_filename()=="")
return NULL;
Node *orig=node;
if (!node->get_owner())
return NULL; //scene root i guess
Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
return node;
bool found=false;
// print_line("for prop - "+String(p_prop));
while(node) {
Ref<SceneState> ss;
if (node==edited_scene) {
ss=node->get_scene_inherited_state();
} else {
ss=node->get_scene_instance_state();
}
// print_line("at - "+String(edited_scene->get_path_to(node)));
if (ss.is_valid()) {
NodePath np = node->get_path_to(orig);
int node_idx = ss->find_node_by_path(np);
// print_line("\t valid, nodeidx "+itos(node_idx));
if (node_idx>=0) {
bool lfound=false;
Variant lvar;
lvar=ss->get_property_value(node_idx,p_prop,lfound);
if (lfound) {
found=true;
value=lvar;
// print_line("\t found value "+String(value));
}
}
}
if (node==edited_scene) {
//just in case
break;
}
node=node->get_owner();
}
return found;
}
bool PropertyEditor::_is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage) {
if (p_orig.get_type()==Variant::NIL) {
//special cases
if (p_current.is_zero() && p_usage&PROPERTY_USAGE_STORE_IF_NONZERO)
return false;
if (p_current.is_one() && p_usage&PROPERTY_USAGE_STORE_IF_NONONE)
return false;
}
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL,p_current,p_orig));
}
TreeItem *PropertyEditor::find_item(TreeItem *p_item,const String& p_name) {
@ -1910,6 +1988,8 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
}
void PropertyEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
@ -1950,12 +2030,16 @@ void PropertyEditor::_notification(int p_what) {
if (!item)
continue;
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(*k)) {
Variant vorig;
Dictionary d=item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(*k,vorig) || usage) {
Variant v = obj->get(*k);
Variant vorig = d[*k];
int found=-1;
for(int i=0;i<item->get_button_count(1);i++) {
@ -1966,7 +2050,7 @@ void PropertyEditor::_notification(int p_what) {
}
}
bool changed = ! (v==vorig);
bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
@ -2049,12 +2133,14 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
if (name!=String()) {
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(name)) {
Variant vorig;
Dictionary d=p_item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(name,vorig) || usage) {
Variant v = obj->get(name);
Variant vorig = d[name];
int found=-1;
for(int i=0;i<p_item->get_button_count(1);i++) {
@ -2065,7 +2151,7 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
}
}
bool changed = ! (v==vorig);
bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
@ -2326,7 +2412,8 @@ void PropertyEditor::update_tree() {
d["type"]=(int)p.type;
d["hint"]=(int)p.hint;
d["hint_text"]=p.hint_string;
d["usage"]=(int)p.usage;
item->set_metadata( 0, d );
item->set_metadata( 1, p.name );
@ -2777,14 +2864,17 @@ void PropertyEditor::update_tree() {
}
}
if (get_instanced_node()) {
if (_might_be_in_instance()) {
Dictionary d = get_instanced_node()->get_instance_state();
if (d.has(p.name)) {
Variant vorig;
Dictionary d=item->get_metadata(0);
int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
if (_get_instanced_node_original_property(p.name,vorig) || usage) {
Variant v = obj->get(p.name);
Variant vorig = d[p.name];
if (! (v==vorig)) {
if (_is_property_different(v,vorig,usage)) {
//print_line("FOR "+String(p.name)+" RELOAD WITH: "+String(v)+"("+Variant::get_type_name(v.get_type())+")=="+String(vorig)+"("+Variant::get_type_name(vorig.get_type())+")");
item->add_button(1,get_icon("Reload","EditorIcons"),3);
}
}
@ -3081,17 +3171,18 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
} else if (p_button==3) {
if (!get_instanced_node())
if (!_might_be_in_instance())
return;
if (!d.has("name"))
return;
String prop=d["name"];
Dictionary d2 = get_instanced_node()->get_instance_state();
if (d2.has(prop)) {
Variant vorig;
_edit_set(prop,d2[prop]);
if (_get_instanced_node_original_property(prop,vorig)) {
_edit_set(prop,vorig);
}
} else {

View file

@ -121,6 +121,7 @@ class CustomPropertyEditor : public Popup {
void show_value_editors(int p_amount);
void config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings);
void config_action_buttons(const List<String>& p_strings);
protected:
void _notification(int p_what);
@ -184,13 +185,17 @@ class PropertyEditor : public Control {
virtual void _changed_callback(Object *p_changed,const char * p_what);
virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
void _edit_button(Object *p_item, int p_column, int p_button);
void _node_removed(Node *p_node);
void _edit_set(const String& p_name, const Variant& p_value);
void _draw_flags(Object *ti,const Rect2& p_rect);
Node *get_instanced_node();
bool _might_be_in_instance();
bool _get_instanced_node_original_property(const StringName& p_prop,Variant& value);
bool _is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage=0);
void _refresh_item(TreeItem *p_item);
void _set_range_def(Object *p_item, String prop, float p_frame);

View file

@ -103,6 +103,7 @@ ReparentDialog::ReparentDialog() {
add_child(node_only);
node_only->hide();
tree->set_show_enabled_subscene(true);
//vbc->add_margin_child("Options:",node_only);;

View file

@ -36,8 +36,8 @@
#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) {
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
uint32_t sc = p_event.key.get_scancode_with_modifiers();
if (!p_event.key.pressed || p_event.key.echo)
@ -71,7 +71,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
Node*instanced_scene=NULL;
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (sdata.is_valid())
instanced_scene=sdata->instance();
instanced_scene=sdata->instance(true);
if (!instanced_scene) {
@ -96,7 +96,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
}
instanced_scene->generate_instance_state();
//instanced_scene->generate_instance_state();
instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
editor_data->get_undo_redo().create_action("Instance Scene");
@ -158,8 +158,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
case TOOL_NEW: {
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
create_dialog->popup_centered_ratio();
} break;
case TOOL_INSTANCE: {
@ -176,8 +176,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
@ -202,8 +202,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!current)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
connect_dialog->popup_centered_ratio();
connect_dialog->set_node(current);
@ -213,8 +213,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *current = scene_tree->get_selected();
if (!current)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
groups_editor->set_current(current);
groups_editor->popup_centered_ratio();
} break;
@ -224,8 +224,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!selected)
break;
if (!_validate_no_foreign())
break;
//if (!_validate_no_foreign())
// break;
Ref<Script> existing = selected->get_script();
if (existing.is_valid())
@ -573,9 +573,9 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
ERR_FAIL_COND_V(!sd.is_valid(),NULL);
node = sd->instance();
node = sd->instance(true);
ERR_FAIL_COND_V(!node,NULL);
node->generate_instance_state();
//node->generate_instance_state();
} else {
Object *obj = ObjectTypeDB::instance(p_node->get_type());
ERR_FAIL_COND_V(!obj,NULL);
@ -874,6 +874,16 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
if (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(E->get()))>=0) {
accept->get_ok()->set_text("Makes Sense!");
accept->set_text("Can't operate on nodes the current scene inherits from!");
accept->popup_centered_minsize();
return false;
}
}
return true;
@ -1078,14 +1088,15 @@ void SceneTreeDock::_delete_confirm() {
void SceneTreeDock::_update_tool_buttons() {
Node *sel = scene_tree->get_selected();
bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene);
bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene) || (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(sel))>=0);
bool disable_root = disable || sel->get_parent()==scene_root;
bool disable_edit = !sel;
tool_buttons[TOOL_INSTANCE]->set_disabled(disable);
tool_buttons[TOOL_INSTANCE]->set_disabled(disable_edit);
tool_buttons[TOOL_REPLACE]->set_disabled(disable);
tool_buttons[TOOL_CONNECT]->set_disabled(disable);
tool_buttons[TOOL_GROUP]->set_disabled(disable);
tool_buttons[TOOL_SCRIPT]->set_disabled(disable);
tool_buttons[TOOL_CONNECT]->set_disabled(disable_edit);
tool_buttons[TOOL_GROUP]->set_disabled(disable_edit);
tool_buttons[TOOL_SCRIPT]->set_disabled(disable_edit);
tool_buttons[TOOL_MOVE_UP]->set_disabled(disable_root);
tool_buttons[TOOL_MOVE_DOWN]->set_disabled(disable_root);
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);

View file

@ -34,6 +34,8 @@
#include "scene/main/viewport.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
#include "scene/resources/packed_scene.h"
Node *SceneTreeEditor::get_scene_node() {
ERR_FAIL_COND_V(!is_inside_tree(),NULL);
@ -57,22 +59,38 @@ void SceneTreeEditor::_subscene_option(int p_idx) {
switch(p_idx) {
case SCENE_MENU_SHOW_CHILDREN: {
case SCENE_MENU_EDITABLE_CHILDREN: {
if (node->has_meta("__editor_show_subtree")) {
instance_menu->set_item_checked(0,true);
node->set_meta("__editor_show_subtree",Variant());
_update_tree();
} else {
node->set_meta("__editor_show_subtree",true);
_update_tree();
}
bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
editable = !editable;
//node->set_instance_children_editable(editable);
EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,editable);
instance_menu->set_item_checked(0,editable);
_update_tree();
} break;
case SCENE_MENU_OPEN: {
emit_signal("open",node->get_filename());
} break;
case SCENE_MENU_CLEAR_INHERITANCE: {
clear_inherit_confirm->popup_centered_minsize();
} break;
case SCENE_MENU_OPEN_INHERITED: {
if (node && node->get_scene_inherited_state().is_valid()) {
emit_signal("open",node->get_scene_inherited_state()->get_path());
}
} break;
case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: {
if (node && node->get_scene_inherited_state().is_valid()) {
node->set_scene_inherited_state(Ref<SceneState>());
update_tree();
EditorNode::get_singleton()->get_property_editor()->update_tree();
}
} break;
}
@ -94,15 +112,24 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
Rect2 item_rect = tree->get_item_rect(item,0);
item_rect.pos.y-=tree->get_scroll().y;
item_rect.pos+=tree->get_global_pos();
instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
instance_menu->set_size(Vector2(item_rect.size.x,0));
if (n->has_meta("__editor_show_subtree"))
instance_menu->set_item_checked(0,true);
else
instance_menu->set_item_checked(0,false);
instance_menu->popup();
instance_node=n->get_instance_ID();
if (n==get_scene_node()) {
inheritance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
inheritance_menu->set_size(Vector2(item_rect.size.x,0));
inheritance_menu->popup();
instance_node=n->get_instance_ID();
} else {
instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
instance_menu->set_size(Vector2(item_rect.size.x,0));
if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n))
instance_menu->set_item_checked(0,true);
else
instance_menu->set_item_checked(0,false);
instance_menu->popup();
instance_node=n->get_instance_ID();
}
//emit_signal("open",n->get_filename());
} else if (p_id==BUTTON_SCRIPT) {
RefPtr script=n->get_script();
@ -168,15 +195,17 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
bool part_of_subscene=false;
if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && p_node->get_owner()->get_owner()==get_scene_node() && p_node->get_owner()->has_meta("__editor_show_subtree")) {
if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && (get_scene_node()->is_editable_instance(p_node->get_owner()))) {
part_of_subscene=true;
//allow
} else {
return;
}
} else {
part_of_subscene = get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node))>=0;
}
TreeItem *item = tree->create_item(p_parent);
@ -199,6 +228,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
icon=get_icon( (has_icon(p_node->get_type(),"EditorIcons")?p_node->get_type():String("Object")),"EditorIcons");
item->set_icon(0, icon );
item->set_metadata( 0,p_node->get_path() );
if (part_of_subscene) {
//item->set_selectable(0,marked_selectable);
@ -221,7 +251,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
}
}
if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
if (p_node==get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
item->set_tooltip(0,"Inherits: "+p_node->get_scene_inherited_state()->get_path()+"\nType: "+p_node->get_type());
} else if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
@ -489,6 +522,9 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("node_removed",this,"_node_removed");
instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
tree->connect("item_collapsed",this,"_cell_collapsed");
inheritance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
clear_inherit_confirm->connect("confirmed",this,"_subscene_option",varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM));
// get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED);
// get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED);
@ -499,6 +535,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->disconnect("tree_changed",this,"_tree_changed");
get_tree()->disconnect("node_removed",this,"_node_removed");
tree->disconnect("item_collapsed",this,"_cell_collapsed");
clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
_update_tree();
}
@ -788,12 +825,26 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
blocked=0;
instance_menu = memnew( PopupMenu );
instance_menu->add_check_item("Show Children",SCENE_MENU_SHOW_CHILDREN);
instance_menu->add_check_item("Editable Children",SCENE_MENU_EDITABLE_CHILDREN);
instance_menu->add_separator();
instance_menu->add_item("Open in Editor",SCENE_MENU_OPEN);
instance_menu->connect("item_pressed",this,"_subscene_option");
add_child(instance_menu);
inheritance_menu = memnew( PopupMenu );
inheritance_menu->add_item("Clear Inheritance",SCENE_MENU_CLEAR_INHERITANCE);
inheritance_menu->add_separator();
inheritance_menu->add_item("Open in Editor",SCENE_MENU_OPEN_INHERITED);
inheritance_menu->connect("item_pressed",this,"_subscene_option");
add_child(inheritance_menu);
clear_inherit_confirm = memnew( ConfirmationDialog );
clear_inherit_confirm->set_text("Clear Inheritance? (No Undo!)");
clear_inherit_confirm->get_ok()->set_text("Clear!");
add_child(clear_inherit_confirm);
}

View file

@ -52,16 +52,21 @@ class SceneTreeEditor : public Control {
};
enum {
SCENE_MENU_SHOW_CHILDREN,
SCENE_MENU_EDITABLE_CHILDREN,
SCENE_MENU_OPEN,
SCENE_MENU_CLEAR_INHERITANCE,
SCENE_MENU_OPEN_INHERITED,
SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
};
Tree *tree;
Node *selected;
PopupMenu *instance_menu;
PopupMenu *inheritance_menu;
ObjectID instance_node;
AcceptDialog *error;
ConfirmationDialog *clear_inherit_confirm;
int blocked;