Browse Source

Real-Time Remote Inspector support

Juan Linietsky 9 years ago
parent
commit
b2a4908e9c

+ 1 - 1
core/object.cpp

@@ -1396,7 +1396,7 @@ Error Object::connect(const StringName& p_signal, Object *p_to_object, const Str
 			signal_is_valid=true;
 			signal_is_valid=true;
 
 
 		if (!signal_is_valid) {
 		if (!signal_is_valid) {
-			ERR_EXPLAIN("Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_method+"'");
+			ERR_EXPLAIN("In Object of type '"+String(get_type())+"': Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_object->get_type()+"."+p_to_method+"'");
 			ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER);
 			ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER);
 		}
 		}
 		signal_map[p_signal]=Signal();
 		signal_map[p_signal]=Signal();

+ 1 - 0
core/object.h

@@ -67,6 +67,7 @@ enum PropertyHint {
 	PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
 	PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
+	PROPERTY_HINT_OBJECT_ID,
 	PROPERTY_HINT_MAX,
 	PROPERTY_HINT_MAX,
 };
 };
 
 

+ 99 - 0
core/script_debugger_remote.cpp

@@ -283,6 +283,14 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
 			} else if (command=="request_video_mem") {
 			} else if (command=="request_video_mem") {
 
 
 				_send_video_memory();
 				_send_video_memory();
+			} else if (command=="inspect_object") {
+
+				ObjectID id = cmd[1];
+				_send_object_id(id);
+			} else if (command=="set_object_property") {
+
+				_set_object_property(cmd[1],cmd[2],cmd[3]);
+
 			} else if (command=="breakpoint") {
 			} else if (command=="breakpoint") {
 
 
 				bool set = cmd[3];
 				bool set = cmd[3];
@@ -539,6 +547,89 @@ bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) {
 	return true;
 	return true;
 }
 }
 
 
+
+void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
+
+	Object* obj = ObjectDB::get_instance(p_id);
+	if (!obj)
+		return;
+
+	List<PropertyInfo> pinfo;
+	obj->get_property_list(&pinfo,true);
+
+	int props_to_send=0;
+	for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+		if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) {
+			props_to_send++;
+		}
+	}
+
+	packet_peer_stream->put_var("message:inspect_object");
+	packet_peer_stream->put_var(props_to_send*5+4);
+	packet_peer_stream->put_var(p_id);
+	packet_peer_stream->put_var(obj->get_type());
+	if (obj->is_type("Resource") || obj->is_type("Node"))
+		packet_peer_stream->put_var(obj->call("get_path"));
+	else
+		packet_peer_stream->put_var("");
+
+	packet_peer_stream->put_var(props_to_send);
+
+	for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+		if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) {
+
+			if (E->get().usage&PROPERTY_USAGE_CATEGORY) {
+				packet_peer_stream->put_var("*"+E->get().name);
+			} else {
+				packet_peer_stream->put_var(E->get().name);
+			}
+
+			Variant var = obj->get(E->get().name);
+
+			if (E->get().type==Variant::OBJECT || var.get_type()==Variant::OBJECT) {
+
+				ObjectID id2;
+				Object *obj=var;
+				if (obj) {
+					id2=obj->get_instance_ID();
+				} else {
+					id2=0;
+				}
+
+				packet_peer_stream->put_var(Variant::INT); //hint string
+				packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_ID); //hint
+				packet_peer_stream->put_var(E->get().hint_string); //hint string
+				packet_peer_stream->put_var(id2);	 //value
+			} else {
+				packet_peer_stream->put_var(E->get().type);
+				packet_peer_stream->put_var(E->get().hint);
+				packet_peer_stream->put_var(E->get().hint_string);
+				//only send information that can be sent..
+				if (var.get_type()==Variant::IMAGE) {
+					var=Image();
+				}
+				if (var.get_type()>=Variant::DICTIONARY) {
+					var=Array(); //send none for now, may be to big
+				}
+				packet_peer_stream->put_var(var);
+			}
+
+		}
+	}
+
+}
+
+void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String& p_property, const Variant& p_value) {
+
+	Object* obj = ObjectDB::get_instance(p_id);
+	if (!obj)
+		return;
+
+	obj->set(p_property,p_value);
+}
+
 void ScriptDebuggerRemote::_poll_events() {
 void ScriptDebuggerRemote::_poll_events() {
 
 
 	//this si called from ::idle_poll, happens only when running the game,
 	//this si called from ::idle_poll, happens only when running the game,
@@ -575,6 +666,14 @@ void ScriptDebuggerRemote::_poll_events() {
 		} else if (command=="request_video_mem") {
 		} else if (command=="request_video_mem") {
 
 
 			_send_video_memory();
 			_send_video_memory();
+		} else if (command=="inspect_object") {
+
+			ObjectID id = cmd[1];
+			_send_object_id(id);
+		} else if (command=="set_object_property") {
+
+			_set_object_property(cmd[1],cmd[2],cmd[3]);
+
 		} else if (command=="start_profiling") {
 		} else if (command=="start_profiling") {
 
 
 			for(int i=0;i<ScriptServer::get_language_count();i++) {
 			for(int i=0;i<ScriptServer::get_language_count();i++) {

+ 3 - 0
core/script_debugger_remote.h

@@ -111,6 +111,9 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 	RequestSceneTreeMessageFunc request_scene_tree;
 	RequestSceneTreeMessageFunc request_scene_tree;
 	void *request_scene_tree_ud;
 	void *request_scene_tree_ud;
 
 
+	void _set_object_property(ObjectID p_id, const String& p_property, const Variant& p_value);
+
+	void _send_object_id(ObjectID p_id);
 	void _send_video_memory();
 	void _send_video_memory();
 	LiveEditFuncs *live_edit_funcs;
 	LiveEditFuncs *live_edit_funcs;
 
 

+ 1 - 0
scene/main/scene_main_loop.cpp

@@ -1002,6 +1002,7 @@ static void _fill_array(Node *p_node, Array& array, int p_level) {
 	array.push_back(p_level);
 	array.push_back(p_level);
 	array.push_back(p_node->get_name());
 	array.push_back(p_node->get_name());
 	array.push_back(p_node->get_type());
 	array.push_back(p_node->get_type());
+	array.push_back(p_node->get_instance_ID());
 	for(int i=0;i<p_node->get_child_count();i++) {
 	for(int i=0;i<p_node->get_child_count();i++) {
 
 
 		_fill_array(p_node->get_child(i),array,p_level+1);
 		_fill_array(p_node->get_child(i),array,p_level+1);

+ 32 - 0
tools/editor/property_editor.cpp

@@ -2989,6 +2989,32 @@ void PropertyEditor::update_tree() {
 					item->set_range(1, obj->get( p.name ) );
 					item->set_range(1, obj->get( p.name ) );
 					item->set_editable(1,!read_only);
 					item->set_editable(1,!read_only);
 					break;
 					break;
+				} else if (p.hint==PROPERTY_HINT_OBJECT_ID) {
+
+//					int c = p.hint_string.get_slice_count(",");
+					item->set_cell_mode(1,TreeItem::CELL_MODE_CUSTOM);
+
+					String type=p.hint_string;
+					if (type=="")
+						type="Object";
+
+					ObjectID id = obj->get( p.name );
+					if (id!=0) {
+						item->set_text(1,type+" ID: "+itos(id));
+						item->add_button(1,get_icon("EditResource","EditorIcons"));
+					} else {
+						item->set_text(1,"[Empty]");
+					}
+
+					if (has_icon(p.hint_string,"EditorIcons")) {
+						type=p.hint_string;
+					} else {
+						type="Object";
+					}
+
+					item->set_icon(0,get_icon(type,"EditorIcons"));
+
+					break;
 
 
 				} else {
 				} else {
 					if (p.type == Variant::REAL) {
 					if (p.type == Variant::REAL) {
@@ -3758,6 +3784,11 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
 
 
 				emit_signal("resource_selected",r,n);
 				emit_signal("resource_selected",r,n);
 			}
 			}
+		} else if (t==Variant::INT && h==PROPERTY_HINT_OBJECT_ID) {
+
+			emit_signal("object_id_selected",obj->get(n));
+			print_line("OBJ ID SELECTED");
+
 		} else if (t==Variant::ARRAY || t==Variant::INT_ARRAY || t==Variant::REAL_ARRAY || t==Variant::STRING_ARRAY || t==Variant::VECTOR2_ARRAY || t==Variant::VECTOR3_ARRAY || t==Variant::COLOR_ARRAY || t==Variant::RAW_ARRAY) {
 		} else if (t==Variant::ARRAY || t==Variant::INT_ARRAY || t==Variant::REAL_ARRAY || t==Variant::STRING_ARRAY || t==Variant::VECTOR2_ARRAY || t==Variant::VECTOR3_ARRAY || t==Variant::COLOR_ARRAY || t==Variant::RAW_ARRAY) {
 
 
 			Variant v = obj->get(n);
 			Variant v = obj->get(n);
@@ -3860,6 +3891,7 @@ void PropertyEditor::_bind_methods() {
 
 
 	ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value")));
 	ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value")));
 	ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
 	ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
+	ADD_SIGNAL( MethodInfo("object_id_selected", PropertyInfo( Variant::INT, "id")) );
 	ADD_SIGNAL( MethodInfo("property_keyed",PropertyInfo( Variant::STRING, "property")));
 	ADD_SIGNAL( MethodInfo("property_keyed",PropertyInfo( Variant::STRING, "property")));
 	ADD_SIGNAL( MethodInfo("property_edited",PropertyInfo( Variant::STRING, "property")));
 	ADD_SIGNAL( MethodInfo("property_edited",PropertyInfo( Variant::STRING, "property")));
 }
 }

+ 502 - 223
tools/editor/script_editor_debugger.cpp

@@ -111,6 +111,68 @@ public:
 	}
 	}
 };
 };
 
 
+
+class ScriptEditorDebuggerInspectedObject : public Object {
+
+	OBJ_TYPE( ScriptEditorDebuggerInspectedObject, Object);
+
+
+
+
+protected:
+
+	bool _set(const StringName& p_name, const Variant& p_value) {
+
+		if (!prop_values.has(p_name))
+			return false;
+
+		emit_signal("value_edited",p_name,p_value);
+		prop_values[p_name]=p_value;
+		return true;
+	}
+
+	bool _get(const StringName& p_name,Variant &r_ret) const {
+
+		if (!prop_values.has(p_name))
+			return false;
+
+		r_ret=prop_values[p_name];
+		return true;
+
+	}
+	void _get_property_list( List<PropertyInfo> *p_list) const {
+
+		p_list->clear(); //sorry, no want category
+		for (const List<PropertyInfo>::Element *E=prop_list.front();E;E=E->next()) {
+			p_list->push_back(E->get());
+		}
+	}
+
+
+	static void _bind_methods() {
+
+		ADD_SIGNAL(MethodInfo("value_edited"));
+	}
+
+public:
+
+	ObjectID last_edited_id;
+	List<PropertyInfo> prop_list;
+	Map<StringName,Variant> prop_values;
+
+	void update() {
+		_change_notify();
+	}
+
+	void update_single(const char* p_prop) {
+		_change_notify(p_prop);
+	}
+
+	ScriptEditorDebuggerInspectedObject() { last_edited_id=0; }
+
+
+};
+
 void ScriptEditorDebugger::debug_next() {
 void ScriptEditorDebugger::debug_next() {
 
 
 	ERR_FAIL_COND(!breaked);
 	ERR_FAIL_COND(!breaked);
@@ -160,6 +222,72 @@ void ScriptEditorDebugger::debug_continue() {
 
 
 }
 }
 
 
+void ScriptEditorDebugger::_scene_tree_folded(Object* obj) {
+
+
+	if (updating_scene_tree) {
+
+		return;
+	}
+	TreeItem *item=obj->cast_to<TreeItem>();
+
+	if (!item)
+		return;
+
+	ObjectID id = item->get_metadata(0);
+	if (item->is_collapsed()) {
+		unfold_cache.erase(id);
+	} else {
+		unfold_cache.insert(id);
+	}
+
+
+}
+
+void ScriptEditorDebugger::_scene_tree_selected() {
+
+
+	if (updating_scene_tree) {
+
+		return;
+	}
+	TreeItem *item = inspect_scene_tree->get_selected();
+	if (!item) {
+
+		return;
+	}
+
+	inspected_object_id = item->get_metadata(0);
+
+	Array msg;
+	msg.push_back("inspect_object");
+	msg.push_back(inspected_object_id);
+	ppeer->put_var(msg);
+
+}
+
+void ScriptEditorDebugger::_scene_tree_property_value_edited(const String& p_prop,const Variant& p_value) {
+
+
+	Array msg;
+	msg.push_back("set_object_property");
+	msg.push_back(inspected_object_id);
+	msg.push_back(p_prop);
+	msg.push_back(p_value);
+	ppeer->put_var(msg);
+	inspect_edited_object_timeout=0.7; //avoid annoyance, don't request soon after editing
+}
+
+void ScriptEditorDebugger::_scene_tree_property_select_object(ObjectID p_object) {
+
+	inspected_object_id=p_object;
+	Array msg;
+	msg.push_back("inspect_object");
+	msg.push_back(inspected_object_id);
+	ppeer->put_var(msg);
+
+}
+
 void ScriptEditorDebugger::_scene_tree_request() {
 void ScriptEditorDebugger::_scene_tree_request() {
 
 
 	ERR_FAIL_COND(connection.is_null());
 	ERR_FAIL_COND(connection.is_null());
@@ -246,10 +374,12 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
 
 
 	} else if (p_msg=="message:scene_tree") {
 	} else if (p_msg=="message:scene_tree") {
 
 
-		scene_tree->clear();
+		inspect_scene_tree->clear();
 		Map<int,TreeItem*> lv;
 		Map<int,TreeItem*> lv;
 
 
-		for(int i=0;i<p_data.size();i+=3) {
+		updating_scene_tree=true;
+
+		for(int i=0;i<p_data.size();i+=4) {
 
 
 			TreeItem *p;
 			TreeItem *p;
 			int level = p_data[i];
 			int level = p_data[i];
@@ -260,15 +390,90 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
 				p=lv[level-1];
 				p=lv[level-1];
 			}
 			}
 
 
-			TreeItem *it = scene_tree->create_item(p);
+
+			TreeItem *it = inspect_scene_tree->create_item(p);
+
+			ObjectID id = ObjectID(p_data[i+3]);
+
 			it->set_text(0,p_data[i+1]);
 			it->set_text(0,p_data[i+1]);
 			if (has_icon(p_data[i+2],"EditorIcons"))
 			if (has_icon(p_data[i+2],"EditorIcons"))
 				it->set_icon(0,get_icon(p_data[i+2],"EditorIcons"));
 				it->set_icon(0,get_icon(p_data[i+2],"EditorIcons"));
+			it->set_metadata(0,id);
+			if (id==inspected_object_id) {
+				it->select(0);
+			}
+
+			if (p) {
+				if (!unfold_cache.has(id)) {
+					it->set_collapsed(true);
+				}
+			} else {
+				if (unfold_cache.has(id)) { //reverse for root
+					it->set_collapsed(true);
+				}
+			}
 			lv[level]=it;
 			lv[level]=it;
 		}
 		}
+		updating_scene_tree=false;
 
 
 		le_clear->set_disabled(false);
 		le_clear->set_disabled(false);
 		le_set->set_disabled(false);
 		le_set->set_disabled(false);
+	} else if (p_msg=="message:inspect_object") {
+
+
+		ObjectID id = p_data[0];
+		String type = p_data[1];
+		Variant path = p_data[2]; //what to do yet, i don't  know
+		int prop_count=p_data[3];
+
+		int idx=4;
+
+
+		if (inspected_object->last_edited_id!=id) {
+			inspected_object->prop_list.clear();
+			inspected_object->prop_values.clear();
+		}
+
+		for(int i=0;i<prop_count;i++) {
+
+			PropertyInfo pinfo;
+			pinfo.name=p_data[idx++];
+			pinfo.type=Variant::Type(int(p_data[idx++]));
+			pinfo.hint=PropertyHint(int(p_data[idx++]));
+			pinfo.hint_string=p_data[idx++];
+			if (pinfo.name.begins_with("*")) {
+				pinfo.name=pinfo.name.substr(1,pinfo.name.length());
+				pinfo.usage=PROPERTY_USAGE_CATEGORY;
+			} else {
+				pinfo.usage=PROPERTY_USAGE_EDITOR;
+			}
+
+			if (inspected_object->last_edited_id!=id) {
+				//don't update.. it's the same, instead refresh
+				inspected_object->prop_list.push_back(pinfo);
+			}
+
+
+			inspected_object->prop_values[pinfo.name]=p_data[idx++];
+
+			if (inspected_object->last_edited_id==id) {
+				//same, just update value, don't rebuild
+				inspected_object->update_single(pinfo.name.ascii().get_data());
+			}
+
+		}
+
+
+
+		if (inspected_object->last_edited_id!=id) {
+			//only if different
+			inspected_object->update();
+		}
+
+		inspected_object->last_edited_id=id;
+
+
+		inspect_properties->edit(inspected_object);
 
 
 	} else if (p_msg=="message:video_mem") {
 	} else if (p_msg=="message:video_mem") {
 
 
@@ -684,7 +889,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
 			forward->set_icon( get_icon("Forward","EditorIcons"));
 			forward->set_icon( get_icon("Forward","EditorIcons"));
 			dobreak->set_icon( get_icon("Pause","EditorIcons"));
 			dobreak->set_icon( get_icon("Pause","EditorIcons"));
 			docontinue->set_icon( get_icon("DebugContinue","EditorIcons"));
 			docontinue->set_icon( get_icon("DebugContinue","EditorIcons"));
-			scene_tree_refresh->set_icon( get_icon("Reload","EditorIcons"));
+			//scene_tree_refresh->set_icon( get_icon("Reload","EditorIcons"));
 			le_set->connect("pressed",this,"_live_edit_set");
 			le_set->connect("pressed",this,"_live_edit_set");
 			le_clear->connect("pressed",this,"_live_edit_clear");
 			le_clear->connect("pressed",this,"_live_edit_clear");
 			error_list->connect("item_selected",this,"_error_selected");
 			error_list->connect("item_selected",this,"_error_selected");
@@ -694,6 +899,36 @@ void ScriptEditorDebugger::_notification(int p_what) {
 		} break;
 		} break;
 		case NOTIFICATION_PROCESS: {
 		case NOTIFICATION_PROCESS: {
 
 
+			if (connection.is_valid()) {
+				inspect_scene_tree_timeout-=get_process_delta_time();
+				if (inspect_scene_tree_timeout<0) {
+					inspect_scene_tree_timeout=EditorSettings::get_singleton()->get("debugger/scene_tree_refresh_interval");
+					if (inspect_scene_tree->is_visible()) {
+						_scene_tree_request();
+
+						if (inspected_object_id!=0) {
+							//take the chance and re-inspect selected object
+							Array msg;
+							msg.push_back("inspect_object");
+							msg.push_back(inspected_object_id);
+							ppeer->put_var(msg);
+						}
+					}
+				}
+
+				inspect_edited_object_timeout-=get_process_delta_time();
+				if (inspect_edited_object_timeout<0) {
+					inspect_edited_object_timeout=EditorSettings::get_singleton()->get("debugger/remote_inspect_refresh_interval");
+					if (inspect_scene_tree->is_visible() && inspected_object_id) {
+						//take the chance and re-inspect selected object
+						Array msg;
+						msg.push_back("inspect_object");
+						msg.push_back(inspected_object_id);
+						ppeer->put_var(msg);
+					}
+				}
+			}
+
 			if (error_count!=last_error_count) {
 			if (error_count!=last_error_count) {
 
 
 				if (error_count==0) {
 				if (error_count==0) {
@@ -732,7 +967,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
 					reason->set_tooltip(TTR("Child Process Connected"));
 					reason->set_tooltip(TTR("Child Process Connected"));
 					profiler->clear();
 					profiler->clear();
 
 
-					scene_tree->clear();
+					inspect_scene_tree->clear();
 					le_set->set_disabled(true);
 					le_set->set_disabled(true);
 					le_clear->set_disabled(false);
 					le_clear->set_disabled(false);
 					error_list->clear();
 					error_list->clear();
@@ -904,6 +1139,9 @@ void ScriptEditorDebugger::stop(){
 	le_set->set_disabled(true);
 	le_set->set_disabled(true);
 	profiler->set_enabled(true);
 	profiler->set_enabled(true);
 
 
+	inspect_properties->edit(NULL);
+	inspect_scene_tree->clear();
+
 	EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
 	EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
 	EditorNode::get_singleton()->get_pause_button()->set_disabled(true);
 	EditorNode::get_singleton()->get_pause_button()->set_disabled(true);
 
 
@@ -1191,7 +1429,7 @@ void ScriptEditorDebugger::_live_edit_set() {
 	if (!connection.is_valid())
 	if (!connection.is_valid())
 		return;
 		return;
 
 
-	TreeItem* ti = scene_tree->get_selected();
+	TreeItem* ti = inspect_scene_tree->get_selected();
 	if (!ti)
 	if (!ti)
 		return;
 		return;
 	String path;
 	String path;
@@ -1408,6 +1646,9 @@ void ScriptEditorDebugger::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("_paused"),&ScriptEditorDebugger::_paused);
 	ObjectTypeDB::bind_method(_MD("_paused"),&ScriptEditorDebugger::_paused);
 
 
+	ObjectTypeDB::bind_method(_MD("_scene_tree_selected"),&ScriptEditorDebugger::_scene_tree_selected);
+	ObjectTypeDB::bind_method(_MD("_scene_tree_folded"),&ScriptEditorDebugger::_scene_tree_folded);
+
 
 
 	ObjectTypeDB::bind_method(_MD("live_debug_create_node"),&ScriptEditorDebugger::live_debug_create_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_create_node"),&ScriptEditorDebugger::live_debug_create_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_instance_node"),&ScriptEditorDebugger::live_debug_instance_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_instance_node"),&ScriptEditorDebugger::live_debug_instance_node);
@@ -1416,6 +1657,8 @@ void ScriptEditorDebugger::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("live_debug_restore_node"),&ScriptEditorDebugger::live_debug_restore_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_restore_node"),&ScriptEditorDebugger::live_debug_restore_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_duplicate_node"),&ScriptEditorDebugger::live_debug_duplicate_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_duplicate_node"),&ScriptEditorDebugger::live_debug_duplicate_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_reparent_node"),&ScriptEditorDebugger::live_debug_reparent_node);
 	ObjectTypeDB::bind_method(_MD("live_debug_reparent_node"),&ScriptEditorDebugger::live_debug_reparent_node);
+	ObjectTypeDB::bind_method(_MD("_scene_tree_property_select_object"),&ScriptEditorDebugger::_scene_tree_property_select_object);
+	ObjectTypeDB::bind_method(_MD("_scene_tree_property_value_edited"),&ScriptEditorDebugger::_scene_tree_property_value_edited);
 
 
 	ADD_SIGNAL(MethodInfo("goto_script_line"));
 	ADD_SIGNAL(MethodInfo("goto_script_line"));
 	ADD_SIGNAL(MethodInfo("breaked",PropertyInfo(Variant::BOOL,"reallydid"),PropertyInfo(Variant::BOOL,"can_debug")));
 	ADD_SIGNAL(MethodInfo("breaked",PropertyInfo(Variant::BOOL,"reallydid"),PropertyInfo(Variant::BOOL,"can_debug")));
@@ -1435,249 +1678,284 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
 	add_child(tabs);
 	add_child(tabs);
 
 
 
 
-	VBoxContainer *vbc = memnew( VBoxContainer );
-	vbc->set_name(TTR("Debugger"));
-	//tabs->add_child(vbc);
-	Control *dbg=vbc;
+	{ //debugger
+		VBoxContainer *vbc = memnew( VBoxContainer );
+		vbc->set_name(TTR("Debugger"));
+		//tabs->add_child(vbc);
+		Control *dbg=vbc;
 
 
-	HBoxContainer *hbc = memnew( HBoxContainer );
-	vbc->add_child(hbc);
+		HBoxContainer *hbc = memnew( HBoxContainer );
+		vbc->add_child(hbc);
 
 
 
 
-	reason = memnew( LineEdit );
-	reason->set_text("");
-	reason->set_editable(false);
-	hbc->add_child(reason);
-	reason->add_color_override("font_color",Color(1,0.4,0.0,0.8));
-	reason->set_h_size_flags(SIZE_EXPAND_FILL);
-	//reason->set_clip_text(true);
+		reason = memnew( LineEdit );
+		reason->set_text("");
+		reason->set_editable(false);
+		hbc->add_child(reason);
+		reason->add_color_override("font_color",Color(1,0.4,0.0,0.8));
+		reason->set_h_size_flags(SIZE_EXPAND_FILL);
+		//reason->set_clip_text(true);
 
 
-	hbc->add_child( memnew( VSeparator) );
+		hbc->add_child( memnew( VSeparator) );
 
 
-	step = memnew( Button );
-	hbc->add_child(step);
-	step->set_tooltip(TTR("Step Into"));
-	step->connect("pressed",this,"debug_step");
+		step = memnew( Button );
+		hbc->add_child(step);
+		step->set_tooltip(TTR("Step Into"));
+		step->connect("pressed",this,"debug_step");
 
 
-	next = memnew( Button );
-	hbc->add_child(next);
-	next->set_tooltip(TTR("Step Over"));
-	next->connect("pressed",this,"debug_next");
+		next = memnew( Button );
+		hbc->add_child(next);
+		next->set_tooltip(TTR("Step Over"));
+		next->connect("pressed",this,"debug_next");
 
 
-	hbc->add_child( memnew( VSeparator) );
+		hbc->add_child( memnew( VSeparator) );
 
 
-	dobreak = memnew( Button );
-	hbc->add_child(dobreak);
-	dobreak->set_tooltip(TTR("Break"));
-	dobreak->connect("pressed",this,"debug_break");
+		dobreak = memnew( Button );
+		hbc->add_child(dobreak);
+		dobreak->set_tooltip(TTR("Break"));
+		dobreak->connect("pressed",this,"debug_break");
 
 
-	docontinue = memnew( Button );
-	hbc->add_child(docontinue);
-	docontinue->set_tooltip(TTR("Continue"));
-	docontinue->connect("pressed",this,"debug_continue");
+		docontinue = memnew( Button );
+		hbc->add_child(docontinue);
+		docontinue->set_tooltip(TTR("Continue"));
+		docontinue->connect("pressed",this,"debug_continue");
 
 
-	hbc->add_child( memnew( VSeparator) );
+		hbc->add_child( memnew( VSeparator) );
 
 
-	back = memnew( Button );
-	hbc->add_child(back);
-	back->set_tooltip(TTR("Inspect Previous Instance"));
+		back = memnew( Button );
+		hbc->add_child(back);
+		back->set_tooltip(TTR("Inspect Previous Instance"));
 
 
-	forward = memnew( Button );
-	hbc->add_child(forward);
-	forward->set_tooltip(TTR("Inspect Next Instance"));
+		forward = memnew( Button );
+		hbc->add_child(forward);
+		forward->set_tooltip(TTR("Inspect Next Instance"));
 
 
 
 
-	HSplitContainer *sc = memnew( HSplitContainer );
-	vbc->add_child(sc);
-	sc->set_v_size_flags(SIZE_EXPAND_FILL);
+		HSplitContainer *sc = memnew( HSplitContainer );
+		vbc->add_child(sc);
+		sc->set_v_size_flags(SIZE_EXPAND_FILL);
 
 
-	stack_dump = memnew( Tree );
-	stack_dump->set_columns(1);
-	stack_dump->set_column_titles_visible(true);
-	stack_dump->set_column_title(0,TTR("Stack Frames"));
-	stack_dump->set_h_size_flags(SIZE_EXPAND_FILL);
-	stack_dump->set_hide_root(true);
-	stack_dump->connect("cell_selected",this,"_stack_dump_frame_selected");
-	sc->add_child(stack_dump);
+		stack_dump = memnew( Tree );
+		stack_dump->set_columns(1);
+		stack_dump->set_column_titles_visible(true);
+		stack_dump->set_column_title(0,TTR("Stack Frames"));
+		stack_dump->set_h_size_flags(SIZE_EXPAND_FILL);
+		stack_dump->set_hide_root(true);
+		stack_dump->connect("cell_selected",this,"_stack_dump_frame_selected");
+		sc->add_child(stack_dump);
 
 
-	inspector = memnew( PropertyEditor );
-	inspector->set_h_size_flags(SIZE_EXPAND_FILL);
-	inspector->hide_top_label();
-	inspector->get_scene_tree()->set_column_title(0,TTR("Variable"));
-	inspector->set_capitalize_paths(false);
-	inspector->set_read_only(true);
-	sc->add_child(inspector);
+		inspector = memnew( PropertyEditor );
+		inspector->set_h_size_flags(SIZE_EXPAND_FILL);
+		inspector->hide_top_label();
+		inspector->get_scene_tree()->set_column_title(0,TTR("Variable"));
+		inspector->set_capitalize_paths(false);
+		inspector->set_read_only(true);
+		sc->add_child(inspector);
 
 
-	server = TCP_Server::create_ref();
+		server = TCP_Server::create_ref();
 
 
-	pending_in_queue=0;
+		pending_in_queue=0;
 
 
-	variables = memnew( ScriptEditorDebuggerVariables );
-
-	breaked=false;
-
-	tabs->add_child(dbg);
-	//tabs->move_child(vbc,0);
-
-	hbc = memnew( HBoxContainer );
-	vbc->add_child(hbc);
-
-
-	error_split = memnew( HSplitContainer );
-	VBoxContainer *errvb = memnew( VBoxContainer );
-	errvb->set_h_size_flags(SIZE_EXPAND_FILL);
-	error_list = memnew( ItemList );
-	errvb->add_margin_child(TTR("Errors:"),error_list,true);
-	error_split->add_child(errvb);
-
-	errvb = memnew( VBoxContainer );
-	errvb->set_h_size_flags(SIZE_EXPAND_FILL);
-	error_stack = memnew( ItemList );
-	errvb->add_margin_child(TTR("Stack Trace (if applicable):"),error_stack,true);
-	error_split->add_child(errvb);
-
-	error_split->set_name(TTR("Errors"));
-	tabs->add_child(error_split);
-
-	profiler = memnew( EditorProfiler );
-	profiler->set_name("Profiler");
-	tabs->add_child(profiler);
-	profiler->connect("enable_profiling",this,"_profiler_activate");
-	profiler->connect("break_request",this,"_profiler_seeked");
-
-
-	HSplitContainer *hsp = memnew( HSplitContainer );
-
-	perf_monitors = memnew(Tree);
-	perf_monitors->set_columns(2);
-	perf_monitors->set_column_title(0,TTR("Monitor"));
-	perf_monitors->set_column_title(1,TTR("Value"));
-	perf_monitors->set_column_titles_visible(true);
-	hsp->add_child(perf_monitors);
-	perf_monitors->set_select_mode(Tree::SELECT_MULTI);
-	perf_monitors->connect("multi_selected",this,"_performance_select");
-	perf_draw = memnew( Control );
-	perf_draw->connect("draw",this,"_performance_draw");
-	hsp->add_child(perf_draw);
-	hsp->set_name("Metrics");
-	hsp->set_split_offset(300);
-	tabs->add_child(hsp);
-	perf_max.resize(Performance::MONITOR_MAX);
-
-	Map<String,TreeItem*> bases;
-	TreeItem *root=perf_monitors->create_item();
-	perf_monitors->set_hide_root(true);
-	for(int i=0;i<Performance::MONITOR_MAX;i++) {
+		variables = memnew( ScriptEditorDebuggerVariables );
 
 
-		String n = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i));
-		String base = n.get_slice("/",0);
-		String name = n.get_slice("/",1);
-		if (!bases.has(base)) {
-			TreeItem *b = perf_monitors->create_item(root);
-			b->set_text(0,base.capitalize());
-			b->set_editable(0,false);
-			b->set_selectable(0,false);
-			bases[base]=b;
-		}
+		breaked=false;
+
+		tabs->add_child(dbg);
+		//tabs->move_child(vbc,0);
+
+		hbc = memnew( HBoxContainer );
+		vbc->add_child(hbc);
+
+	}
+
+	{  //errors
+
+
+		error_split = memnew( HSplitContainer );
+		VBoxContainer *errvb = memnew( VBoxContainer );
+		errvb->set_h_size_flags(SIZE_EXPAND_FILL);
+		error_list = memnew( ItemList );
+		errvb->add_margin_child(TTR("Errors:"),error_list,true);
+		error_split->add_child(errvb);
+
+		errvb = memnew( VBoxContainer );
+		errvb->set_h_size_flags(SIZE_EXPAND_FILL);
+		error_stack = memnew( ItemList );
+		errvb->add_margin_child(TTR("Stack Trace (if applicable):"),error_stack,true);
+		error_split->add_child(errvb);
+
+		error_split->set_name(TTR("Errors"));
+		tabs->add_child(error_split);
+	}
+
+
+	{ // inquire
 
 
-		TreeItem *it = perf_monitors->create_item(bases[base]);
-		it->set_editable(0,false);
-		it->set_selectable(0,true);
-		it->set_text(0,name.capitalize());
-		perf_items.push_back(it);
-		perf_max[i]=0;
 
 
+		inspect_info = memnew( HSplitContainer );
+		inspect_info->set_name(TTR("Remote Inspector"));
+		tabs->add_child(inspect_info);
+
+		VBoxContainer *info_left = memnew(VBoxContainer);
+		info_left->set_h_size_flags(SIZE_EXPAND_FILL);
+		inspect_info->add_child(info_left);
+
+		inspect_scene_tree = memnew( Tree );
+		info_left->add_margin_child("Live Scene Tree:",inspect_scene_tree,true);
+		inspect_scene_tree->connect("cell_selected",this,"_scene_tree_selected");
+		inspect_scene_tree->connect("item_collapsed",this,"_scene_tree_folded");
+
+		//
+
+		VBoxContainer *info_right = memnew(VBoxContainer);
+		info_right->set_h_size_flags(SIZE_EXPAND_FILL);
+		inspect_info->add_child(info_right);
+
+		inspect_properties = memnew( PropertyEditor );
+		inspect_properties->hide_top_label();
+		inspect_properties->set_show_categories(true);
+		inspect_properties->connect("object_id_selected",this,"_scene_tree_property_select_object");
+
+		info_right->add_margin_child("Remote Object Properties: ",inspect_properties,true);
+
+		inspect_scene_tree_timeout=EDITOR_DEF("debugger/scene_tree_refresh_interval",1.0);
+		inspect_edited_object_timeout=EDITOR_DEF("debugger/remote_inspect_refresh_interval",0.2);
+		inspected_object_id=0;
+		updating_scene_tree=false;
+
+		inspected_object = memnew( ScriptEditorDebuggerInspectedObject );
+		inspected_object->connect("value_edited",this,"_scene_tree_property_value_edited");
 	}
 	}
 
 
-	VBoxContainer *vmem_vb = memnew( VBoxContainer );
-	HBoxContainer *vmem_hb = memnew( HBoxContainer );
-	Label *vmlb = memnew(Label(TTR("List of Video Memory Usage by Resource:")+" ") );
-	vmlb->set_h_size_flags(SIZE_EXPAND_FILL);
-	vmem_hb->add_child( vmlb );
-	vmem_hb->add_child( memnew(Label(TTR("Total:")+" ")) );
-	vmem_total = memnew( LineEdit );
-	vmem_total->set_editable(false);
-	vmem_total->set_custom_minimum_size(Size2(100,1));
-	vmem_hb->add_child(vmem_total);
-	vmem_refresh = memnew( Button );
-	vmem_hb->add_child(vmem_refresh);
-	vmem_vb->add_child(vmem_hb);
-	vmem_refresh->connect("pressed",this,"_video_mem_request");
-
-	MarginContainer *vmmc = memnew( MarginContainer );
-	vmem_tree = memnew( Tree );
-	vmem_tree->set_v_size_flags(SIZE_EXPAND_FILL);
-	vmem_tree->set_h_size_flags(SIZE_EXPAND_FILL);
-	vmmc->add_child(vmem_tree);
-	vmmc->set_v_size_flags(SIZE_EXPAND_FILL);
-	vmem_vb->add_child(vmmc);
-
-	vmem_vb->set_name(TTR("Video Mem"));
-	vmem_tree->set_columns(4);
-	vmem_tree->set_column_titles_visible(true);
-	vmem_tree->set_column_title(0,TTR("Resource Path"));
-	vmem_tree->set_column_expand(0,true);
-	vmem_tree->set_column_expand(1,false);
-	vmem_tree->set_column_title(1,TTR("Type"));
-	vmem_tree->set_column_min_width(1,100);
-	vmem_tree->set_column_expand(2,false);
-	vmem_tree->set_column_title(2,TTR("Format"));
-	vmem_tree->set_column_min_width(2,150);
-	vmem_tree->set_column_expand(3,false);
-	vmem_tree->set_column_title(3,TTR("Usage"));
-	vmem_tree->set_column_min_width(3,80);
-	vmem_tree->set_hide_root(true);
-
-	tabs->add_child(vmem_vb);
-
-	info = memnew( HSplitContainer );
-	info->set_name(TTR("Info"));
-	tabs->add_child(info);
-
-	VBoxContainer *info_left = memnew( VBoxContainer );
-	info_left->set_h_size_flags(SIZE_EXPAND_FILL);
-	info->add_child(info_left);
-	clicked_ctrl = memnew( LineEdit );
-	info_left->add_margin_child(TTR("Clicked Control:"),clicked_ctrl);
-	clicked_ctrl_type = memnew( LineEdit );
-	info_left->add_margin_child(TTR("Clicked Control Type:"),clicked_ctrl_type);
-
-	live_edit_root = memnew( LineEdit );
-
-	{
-		HBoxContainer *lehb = memnew( HBoxContainer );
-		Label *l = memnew( Label(TTR("Live Edit Root:")) );
-		lehb->add_child(l);
-		l->set_h_size_flags(SIZE_EXPAND_FILL);
-		le_set = memnew( Button(TTR("Set From Tree")) );
-		lehb->add_child(le_set);
-		le_clear = memnew( Button(TTR("Clear")) );
-		lehb->add_child(le_clear);
-		info_left->add_child(lehb);
-		MarginContainer *mc = memnew( MarginContainer );
-		mc->add_child(live_edit_root);
-		info_left->add_child(mc);
-		le_set->set_disabled(true);
-		le_clear->set_disabled(true);
+	{ //profiler
+		profiler = memnew( EditorProfiler );
+		profiler->set_name("Profiler");
+		tabs->add_child(profiler);
+		profiler->connect("enable_profiling",this,"_profiler_activate");
+		profiler->connect("break_request",this,"_profiler_seeked");
+	}
+
+
+	{ //monitors
+
+		HSplitContainer *hsp = memnew( HSplitContainer );
+
+		perf_monitors = memnew(Tree);
+		perf_monitors->set_columns(2);
+		perf_monitors->set_column_title(0,TTR("Monitor"));
+		perf_monitors->set_column_title(1,TTR("Value"));
+		perf_monitors->set_column_titles_visible(true);
+		hsp->add_child(perf_monitors);
+		perf_monitors->set_select_mode(Tree::SELECT_MULTI);
+		perf_monitors->connect("multi_selected",this,"_performance_select");
+		perf_draw = memnew( Control );
+		perf_draw->connect("draw",this,"_performance_draw");
+		hsp->add_child(perf_draw);
+		hsp->set_name("Monitors");
+		hsp->set_split_offset(300);
+		tabs->add_child(hsp);
+		perf_max.resize(Performance::MONITOR_MAX);
+
+		Map<String,TreeItem*> bases;
+		TreeItem *root=perf_monitors->create_item();
+		perf_monitors->set_hide_root(true);
+		for(int i=0;i<Performance::MONITOR_MAX;i++) {
+
+			String n = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i));
+			String base = n.get_slice("/",0);
+			String name = n.get_slice("/",1);
+			if (!bases.has(base)) {
+				TreeItem *b = perf_monitors->create_item(root);
+				b->set_text(0,base.capitalize());
+				b->set_editable(0,false);
+				b->set_selectable(0,false);
+				bases[base]=b;
+			}
+
+			TreeItem *it = perf_monitors->create_item(bases[base]);
+			it->set_editable(0,false);
+			it->set_selectable(0,true);
+			it->set_text(0,name.capitalize());
+			perf_items.push_back(it);
+			perf_max[i]=0;
+
+		}
+	}
+
+	{ //vmem inspect
+		VBoxContainer *vmem_vb = memnew( VBoxContainer );
+		HBoxContainer *vmem_hb = memnew( HBoxContainer );
+		Label *vmlb = memnew(Label(TTR("List of Video Memory Usage by Resource:")+" ") );
+		vmlb->set_h_size_flags(SIZE_EXPAND_FILL);
+		vmem_hb->add_child( vmlb );
+		vmem_hb->add_child( memnew(Label(TTR("Total:")+" ")) );
+		vmem_total = memnew( LineEdit );
+		vmem_total->set_editable(false);
+		vmem_total->set_custom_minimum_size(Size2(100,1));
+		vmem_hb->add_child(vmem_total);
+		vmem_refresh = memnew( Button );
+		vmem_hb->add_child(vmem_refresh);
+		vmem_vb->add_child(vmem_hb);
+		vmem_refresh->connect("pressed",this,"_video_mem_request");
+
+		MarginContainer *vmmc = memnew( MarginContainer );
+		vmem_tree = memnew( Tree );
+		vmem_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+		vmem_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+		vmmc->add_child(vmem_tree);
+		vmmc->set_v_size_flags(SIZE_EXPAND_FILL);
+		vmem_vb->add_child(vmmc);
+
+		vmem_vb->set_name(TTR("Video Mem"));
+		vmem_tree->set_columns(4);
+		vmem_tree->set_column_titles_visible(true);
+		vmem_tree->set_column_title(0,TTR("Resource Path"));
+		vmem_tree->set_column_expand(0,true);
+		vmem_tree->set_column_expand(1,false);
+		vmem_tree->set_column_title(1,TTR("Type"));
+		vmem_tree->set_column_min_width(1,100);
+		vmem_tree->set_column_expand(2,false);
+		vmem_tree->set_column_title(2,TTR("Format"));
+		vmem_tree->set_column_min_width(2,150);
+		vmem_tree->set_column_expand(3,false);
+		vmem_tree->set_column_title(3,TTR("Usage"));
+		vmem_tree->set_column_min_width(3,80);
+		vmem_tree->set_hide_root(true);
+
+		tabs->add_child(vmem_vb);
+	}
+
+	{ // misc
+		VBoxContainer *info_left = memnew( VBoxContainer );
+		info_left->set_h_size_flags(SIZE_EXPAND_FILL);
+		info_left->set_name("Misc");
+		tabs->add_child(info_left);
+		clicked_ctrl = memnew( LineEdit );
+		info_left->add_margin_child(TTR("Clicked Control:"),clicked_ctrl);
+		clicked_ctrl_type = memnew( LineEdit );
+		info_left->add_margin_child(TTR("Clicked Control Type:"),clicked_ctrl_type);
+
+		live_edit_root = memnew( LineEdit );
+
+		{
+			HBoxContainer *lehb = memnew( HBoxContainer );
+			Label *l = memnew( Label(TTR("Live Edit Root:")) );
+			lehb->add_child(l);
+			l->set_h_size_flags(SIZE_EXPAND_FILL);
+			le_set = memnew( Button(TTR("Set From Tree")) );
+			lehb->add_child(le_set);
+			le_clear = memnew( Button(TTR("Clear")) );
+			lehb->add_child(le_clear);
+			info_left->add_child(lehb);
+			MarginContainer *mc = memnew( MarginContainer );
+			mc->add_child(live_edit_root);
+			info_left->add_child(mc);
+			le_set->set_disabled(true);
+			le_clear->set_disabled(true);
+		}
+
 	}
 	}
 
 
-	VBoxContainer *info_right = memnew(VBoxContainer);
-	info_right->set_h_size_flags(SIZE_EXPAND_FILL);
-	info->add_child(info_right);
-	HBoxContainer *inforhb = memnew( HBoxContainer );
-	info_right->add_child(inforhb);
-	Label *l2 = memnew( Label(TTR("Scene Tree:") ) );
-	l2->set_h_size_flags(SIZE_EXPAND_FILL);
-	inforhb->add_child( l2 );
-	Button *refresh = memnew( Button );
-	inforhb->add_child(refresh);
-	refresh->connect("pressed",this,"_scene_tree_request");
-	scene_tree_refresh=refresh;
-	MarginContainer *infomc = memnew( MarginContainer );
-	info_right->add_child(infomc);
-	infomc->set_v_size_flags(SIZE_EXPAND_FILL);
-	scene_tree = memnew( Tree );
-	infomc->add_child(scene_tree);
 
 
 
 
 	msgdialog = memnew( AcceptDialog );
 	msgdialog = memnew( AcceptDialog );
@@ -1706,5 +1984,6 @@ ScriptEditorDebugger::~ScriptEditorDebugger() {
 	ppeer->set_stream_peer(Ref<StreamPeer>());
 	ppeer->set_stream_peer(Ref<StreamPeer>());
 
 
 	server->stop();
 	server->stop();
+	memdelete(inspected_object);
 
 
 }
 }

+ 24 - 4
tools/editor/script_editor_debugger.h

@@ -33,7 +33,7 @@
 #include "scene/gui/button.h"
 #include "scene/gui/button.h"
 #include "core/io/tcp_server.h"
 #include "core/io/tcp_server.h"
 #include "core/io/packet_peer.h"
 #include "core/io/packet_peer.h"
-
+#include "property_editor.h"
 
 
 class Tree;
 class Tree;
 class PropertyEditor;
 class PropertyEditor;
@@ -49,6 +49,10 @@ class HSplitContainer;
 class ItemList;
 class ItemList;
 class EditorProfiler;
 class EditorProfiler;
 
 
+
+
+class ScriptEditorDebuggerInspectedObject;
+
 class ScriptEditorDebugger : public Control {
 class ScriptEditorDebugger : public Control {
 
 
 	OBJ_TYPE( ScriptEditorDebugger, Control );
 	OBJ_TYPE( ScriptEditorDebugger, Control );
@@ -61,12 +65,23 @@ class ScriptEditorDebugger : public Control {
 	LineEdit *clicked_ctrl;
 	LineEdit *clicked_ctrl;
 	LineEdit *clicked_ctrl_type;
 	LineEdit *clicked_ctrl_type;
 	LineEdit *live_edit_root;
 	LineEdit *live_edit_root;
-	Tree *scene_tree;
-	HSplitContainer *info;
-	Button *scene_tree_refresh;
 	Button *le_set;
 	Button *le_set;
 	Button *le_clear;
 	Button *le_clear;
 
 
+
+
+	Tree *inspect_scene_tree;
+	HSplitContainer *inspect_info;
+	PropertyEditor *inspect_properties;
+	float inspect_scene_tree_timeout;
+	float inspect_edited_object_timeout;
+	ObjectID inspected_object_id;
+	ScriptEditorDebuggerInspectedObject *inspected_object;
+	bool updating_scene_tree;
+	Set<ObjectID> unfold_cache;
+
+
+
 	HSplitContainer *error_split;
 	HSplitContainer *error_split;
 	ItemList *error_list;
 	ItemList *error_list;
 	ItemList *error_stack;
 	ItemList *error_stack;
@@ -132,8 +147,13 @@ class ScriptEditorDebugger : public Control {
 	void _stack_dump_frame_selected();
 	void _stack_dump_frame_selected();
 	void _output_clear();
 	void _output_clear();
 
 
+
+	void _scene_tree_folded(Object* obj);
+	void _scene_tree_selected();
 	void _scene_tree_request();
 	void _scene_tree_request();
 	void _parse_message(const String& p_msg,const Array& p_data);
 	void _parse_message(const String& p_msg,const Array& p_data);
+	void _scene_tree_property_select_object(ObjectID p_object);
+	void _scene_tree_property_value_edited(const String& p_prop,const Variant& p_value);
 
 
 	void _video_mem_request();
 	void _video_mem_request();