Bläddra i källkod

Merge branch 'master' of https://github.com/okamstudio/godot

# Solved Conflicts:
#	tools/editor/property_editor.cpp
#	tools/editor/property_editor.h
Mariano Javier Suligoy 10 år sedan
förälder
incheckning
c688b55019

+ 0 - 1
core/globals.cpp

@@ -1477,7 +1477,6 @@ Globals::Globals() {
 	custom_prop_info["render/mipmap_policy"]=PropertyInfo(Variant::INT,"render/mipmap_policy",PROPERTY_HINT_ENUM,"Allow,Allow For Po2,Disallow");
 	custom_prop_info["render/thread_model"]=PropertyInfo(Variant::INT,"render/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
 	custom_prop_info["physics_2d/thread_model"]=PropertyInfo(Variant::INT,"physics_2d/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
-	set("display/emulate_touchscreen",false);
 
 	using_datapack=false;
 }

+ 19 - 0
core/object_type_db.cpp

@@ -746,6 +746,25 @@ bool ObjectTypeDB::has_method(StringName p_type,StringName p_method,bool p_no_in
 
 }
 
+bool ObjectTypeDB::get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter) {
+
+	TypeInfo *type=types.getptr(p_class);
+	TypeInfo *check=type;
+	while(check) {
+
+		if (check->property_setget.has(p_prop)) {
+			r_class=check->name;
+			r_setter=check->property_setget[p_prop].setter;
+			return true;
+		}
+
+		check=check->inherits_ptr;
+	}
+
+	return false;
+
+}
+
 #ifdef DEBUG_METHODS_ENABLED
 MethodBind* ObjectTypeDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
 	StringName mdname=method_name.name;

+ 3 - 1
core/object_type_db.h

@@ -475,7 +475,9 @@ public:
 	static void get_integer_constant_list(const StringName& p_type, List<String> *p_constants, bool p_no_inheritance=false);
 	static int get_integer_constant(const StringName& p_type, const StringName &p_name, bool *p_success=NULL);
 	static StringName get_category(const StringName& p_node);
-	
+
+	static bool get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter);
+
 	static void set_type_enabled(StringName p_type,bool p_enable);
 	static bool is_type_enabled(StringName p_type);
 

+ 43 - 0
core/os/input.cpp

@@ -271,6 +271,38 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
 				mouse_button_mask|=(1<<p_event.mouse_button.button_index);
 			else
 				mouse_button_mask&=~(1<<p_event.mouse_button.button_index);
+
+			if (main_loop && emulate_touch && p_event.mouse_button.button_index==1) {
+				InputEventScreenTouch touch_event;
+				touch_event.index=0;
+				touch_event.pressed=p_event.mouse_button.pressed;
+				touch_event.x=p_event.mouse_button.x;
+				touch_event.y=p_event.mouse_button.y;
+				InputEvent ev;
+				ev.type=InputEvent::SCREEN_TOUCH;
+				ev.screen_touch=touch_event;
+				main_loop->input_event(ev);
+			}
+		} break;
+		case InputEvent::MOUSE_MOTION: {
+
+			if (main_loop && emulate_touch && p_event.mouse_motion.button_mask&1) {
+				InputEventScreenDrag drag_event;
+				drag_event.index=0;
+				drag_event.x=p_event.mouse_motion.x;
+				drag_event.y=p_event.mouse_motion.y;
+				drag_event.relative_x=p_event.mouse_motion.relative_x;
+				drag_event.relative_y=p_event.mouse_motion.relative_y;
+				drag_event.speed_x=p_event.mouse_motion.speed_x;
+				drag_event.speed_y=p_event.mouse_motion.speed_y;
+
+				InputEvent ev;
+				ev.type=InputEvent::SCREEN_DRAG;
+				ev.screen_drag=drag_event;
+
+				main_loop->input_event(ev);
+			}
+
 		} break;
 		case InputEvent::JOYSTICK_BUTTON: {
 
@@ -362,8 +394,19 @@ void InputDefault::action_release(const StringName& p_action){
 	}
 }
 
+void InputDefault::set_emulate_touch(bool p_emulate) {
+
+	emulate_touch=p_emulate;
+}
+
+bool InputDefault::is_emulating_touchscreen() const {
+
+	return emulate_touch;
+}
+
 InputDefault::InputDefault() {
 
 	mouse_button_mask=0;
+	emulate_touch=false;
 	main_loop=NULL;
 }

+ 7 - 0
core/os/input.h

@@ -78,6 +78,8 @@ public:
 
 	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
+	virtual bool is_emulating_touchscreen() const=0;
+
 
 	Input();
 };
@@ -99,6 +101,8 @@ class InputDefault : public Input {
 	Vector2 mouse_pos;
 	MainLoop *main_loop;
 
+	bool emulate_touch;
+
 	struct SpeedTrack {
 
 		uint64_t last_tick;
@@ -147,6 +151,9 @@ public:
 
 	void iteration(float p_step);
 
+	void set_emulate_touch(bool p_emulate);
+	virtual bool is_emulating_touchscreen() const;
+
 	InputDefault();
 
 };

+ 2 - 2
core/os/os.cpp

@@ -31,7 +31,7 @@
 #include <stdarg.h>
 #include "dir_access.h"
 #include "globals.h"
-
+#include "input.h"
 
 OS* OS::singleton=NULL;
 
@@ -363,7 +363,7 @@ Error OS::set_cwd(const String& p_cwd) {
 bool OS::has_touchscreen_ui_hint() const {
 
 	//return false;
-	return GLOBAL_DEF("display/emulate_touchscreen",false);
+	return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
 }
 
 int OS::get_free_static_memory() const {

+ 31 - 0
core/ustring.cpp

@@ -3048,6 +3048,37 @@ bool String::is_valid_identifier() const {
 
 //kind of poor should be rewritten properly
 
+String String::world_wrap(int p_chars_per_line) const {
+
+	int from=0;
+	int last_space=0;
+	String ret;
+	for(int i=0;i<length();i++) {
+		if (i-from>=p_chars_per_line) {
+			if (last_space==-1) {
+				ret+=substr(from,i-from+1)+"\n";
+			} else {
+				ret+=substr(from,last_space-from)+"\n";
+				i=last_space; //rewind
+			}
+			from=i+1;
+			last_space=-1;
+		} else if (operator[](i)==' ' || operator[](i)=='\t') {
+			last_space=i;
+		} else if (operator[](i)=='\n') {
+			ret+=substr(from,i-from);
+			from=i+1;
+			last_space=-1;
+		}
+	}
+
+	if (from<length()) {
+		ret+=substr(from,length());
+	}
+
+	return ret;
+}
+
 String String::c_unescape() const {
 
 	String escaped=*this;

+ 1 - 0
core/ustring.h

@@ -209,6 +209,7 @@ public:
 	String xml_unescape() const;
 	String c_escape() const;
 	String c_unescape() const;
+	String world_wrap(int p_chars_per_line) const;
 	
 	String percent_encode() const;
 	String percent_decode() const;

+ 9 - 1
main/main.cpp

@@ -75,7 +75,7 @@
 #include "core/io/file_access_zip.h"
 #include "translation.h"
 #include "version.h"
-
+#include "os/input.h"
 #include "performance.h"
 
 static Globals *globals=NULL;
@@ -847,6 +847,14 @@ Error Main::setup2() {
 	GLOBAL_DEF("application/icon",String());
 	Globals::get_singleton()->set_custom_property_info("application/icon",PropertyInfo(Variant::STRING,"application/icon",PROPERTY_HINT_FILE,"*.png,*.webp"));
 
+	if (bool(GLOBAL_DEF("display/emulate_touchscreen",false))) {
+		if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
+			//only if no touchscreen ui hint, set emulation
+			InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
+			if (id)
+				id->set_emulate_touch(true);
+		}
+	}
 	MAIN_PRINT("Main: Load Remaps");
 
 	path_remap->load_remaps();

+ 3 - 3
modules/gdscript/gd_parser.cpp

@@ -2625,14 +2625,14 @@ void GDParser::_parse_class(ClassNode *p_class) {
 
 					Node *subexpr=NULL;
 
-					subexpr = _parse_and_reduce_expression(p_class,false);
+					subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
 					if (!subexpr)
 						return;
 
 					member.expression=subexpr;
 
 					if (autoexport) {
-						if (subexpr->type==Node::TYPE_ARRAY) {
+						if (1)/*(subexpr->type==Node::TYPE_ARRAY) {
 
 							member._export.type=Variant::ARRAY;
 
@@ -2640,7 +2640,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
 
 							member._export.type=Variant::DICTIONARY;
 
-						} else {
+						} else*/ {
 
 							if (subexpr->type!=Node::TYPE_CONSTANT) {
 

+ 51 - 2
platform/x11/os_x11.cpp

@@ -504,6 +504,23 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
 	mouse_mode=p_mode;
 
 	if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+		while(true) {
+			//flush pending motion events
+
+			if (XPending(x11_display) > 0) {
+				XEvent event;
+				XPeekEvent(x11_display, &event);
+				if (event.type==MotionNotify) {
+					XNextEvent(x11_display,&event);
+				} else {
+					break;
+				}
+			} else {
+				break;
+			}
+		}
+
 		if (XGrabPointer(x11_display, x11_window, True,
 				    ButtonPressMask | ButtonReleaseMask |
 				    PointerMotionMask, GrabModeAsync, GrabModeAsync,
@@ -518,6 +535,8 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
 			      0,0,0,0, (int)center.x, (int)center.y);
 
 		input->set_mouse_pos(center);
+	} else {
+		do_mouse_warp=false;
 	}
 }
 
@@ -1131,7 +1150,7 @@ void OS_X11::process_xevents() {
 
 	//printf("checking events %i\n", XPending(x11_display));
 
-	bool do_mouse_warp=false;
+	do_mouse_warp=false;
 
 	while (XPending(x11_display) > 0) {
 		XEvent event;
@@ -1244,8 +1263,38 @@ void OS_X11::process_xevents() {
 			
 		} break;	
 		case MotionNotify: {
-						
+
+			// FUCK YOU X11 API YOU SERIOUSLY GROSS ME OUT
+			// YOU ARE AS GROSS AS LOOKING AT A PUTRID PILE
+			// OF POOP STICKING OUT OF A CLOGGED TOILET
+			// HOW THE FUCK I AM SUPPOSED TO KNOW WHICH ONE
+			// OF THE MOTION NOTIFY EVENTS IS THE ONE GENERATED
+			// BY WARPING THE MOUSE POINTER?
+			// YOU ARE FORCING ME TO FILTER ONE BY ONE TO FIND IT
+			// PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL
+			// MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG.
+
 			
+			while(true) {
+				if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) {
+					//this is likely the warp event since it was warped here
+					center=Vector2(event.xmotion.x,event.xmotion.y);
+					break;
+				}
+
+				if (XPending(x11_display) > 0) {
+					XEvent tevent;
+					XPeekEvent(x11_display, &tevent);
+					if (tevent.type==MotionNotify) {
+						XNextEvent(x11_display,&event);
+					} else {
+						break;
+					}
+				} else {
+					break;
+				}
+			}
+
 			last_timestamp=event.xmotion.time;
 		
 			// Motion is also simple.

+ 1 - 0
platform/x11/os_x11.h

@@ -114,6 +114,7 @@ class OS_X11 : public OS_Unix {
 	bool minimized;
 	int dpad_last[2];
 
+	bool do_mouse_warp;
 
 	const char *cursor_theme;
 	int cursor_size;

+ 2 - 2
scene/2d/sprite.cpp

@@ -322,8 +322,8 @@ void Sprite::_bind_methods() {
 	ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
-	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
-	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
 	ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));

+ 2 - 2
scene/3d/sprite_3d.cpp

@@ -578,8 +578,8 @@ void Sprite3D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite3D::get_hframes);
 
 	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
 	ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));

+ 53 - 1
scene/gui/spin_box.cpp

@@ -27,7 +27,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "spin_box.h"
-
+#include "os/input.h"
 
 Size2 SpinBox::get_minimum_size() const {
 
@@ -62,6 +62,13 @@ LineEdit *SpinBox::get_line_edit() {
 }
 
 
+void SpinBox::_line_edit_input(const InputEvent& p_event) {
+
+
+
+}
+
+
 void SpinBox::_input_event(const InputEvent& p_event) {
 
 	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed) {
@@ -94,6 +101,48 @@ void SpinBox::_input_event(const InputEvent& p_event) {
 			} break;
 		}
 	}
+
+	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+		//set_default_cursor_shape(CURSOR_VSIZE);
+		Vector2 cpos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y);
+		drag.mouse_pos=cpos;
+	}
+
+	if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+		//set_default_cursor_shape(CURSOR_ARROW);
+		if (drag.enabled) {
+			drag.enabled=false;
+			Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+			warp_mouse(drag.capture_pos);
+		}
+	}
+
+	if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_button.button_mask&1) {
+
+		Vector2 cpos = Vector2(p_event.mouse_motion.x,p_event.mouse_motion.y);
+		if (drag.enabled) {
+
+			float diff_y = drag.mouse_pos.y - cpos.y;
+			diff_y=pow(ABS(diff_y),1.8)*SGN(diff_y);
+			diff_y*=0.1;
+
+			drag.mouse_pos=cpos;
+			drag.base_val=CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max());
+
+			set_val( drag.base_val);
+
+		} else if (drag.mouse_pos.distance_to(cpos)>2) {
+
+			Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+			drag.enabled=true;
+			drag.base_val=get_val();
+			drag.mouse_pos=cpos;
+			drag.capture_pos=cpos;
+
+		}
+	}
 }
 
 
@@ -177,6 +226,7 @@ void SpinBox::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("is_editable"),&SpinBox::is_editable);
 	ObjectTypeDB::bind_method(_MD("_line_edit_focus_exit"),&SpinBox::_line_edit_focus_exit);
 	ObjectTypeDB::bind_method(_MD("get_line_edit"),&SpinBox::get_line_edit);
+	ObjectTypeDB::bind_method(_MD("_line_edit_input"),&SpinBox::_line_edit_input);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"editable"),_SCS("set_editable"),_SCS("is_editable"));
@@ -196,4 +246,6 @@ SpinBox::SpinBox() {
 	//connect("value_changed",this,"_value_changed");
 	line_edit->connect("text_entered",this,"_text_entered",Vector<Variant>(),CONNECT_DEFERRED);
 	line_edit->connect("focus_exit",this,"_line_edit_focus_exit",Vector<Variant>(),CONNECT_DEFERRED);
+	line_edit->connect("input_event",this,"_line_edit_input");
+	drag.enabled=false;
 }

+ 12 - 0
scene/gui/spin_box.h

@@ -44,6 +44,18 @@ class SpinBox : public Range {
 	String prefix;
 	String suffix;
 
+	void _line_edit_input(const InputEvent& p_event);
+
+
+	struct Drag {
+		float base_val;
+		bool enabled;
+		Vector2 from;
+		Vector2	mouse_pos;
+		Vector2 capture_pos;
+	} drag;
+
+
 	void _line_edit_focus_exit();
 
 protected:

+ 80 - 28
scene/gui/tree.cpp

@@ -31,7 +31,7 @@
 #include "os/os.h"
 #include "os/keyboard.h"
 #include "globals.h"
-
+#include "os/input.h"
 
 
 
@@ -70,6 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const {
 	else
 		return icon_region.size;
 }
+
 void TreeItem::Cell::draw_icon(const RID& p_where, const Point2& p_pos, const Size2& p_size) const{
 
 	if (icon.is_null())
@@ -728,14 +729,20 @@ TreeItem::~TreeItem() {
 		tree->root=0;
 	}
 
-	if (tree && tree->popup_edited_item==this)
+	if (tree && tree->popup_edited_item==this) {
 		tree->popup_edited_item=NULL;
+		tree->pressing_for_editor=false;
+
+	}
 
 	if (tree && tree->selected_item==this)
 		tree->selected_item=NULL;
 
-	if (tree && tree->edited_item==this)
+	if (tree && tree->edited_item==this) {
 		tree->edited_item=NULL;
+		tree->pressing_for_editor=false;
+	}
+
 
 }
 
@@ -1292,7 +1299,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 	
 		} else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) {
 	
-			if (&selected_cell==&c) {
+			if (!r_in_range && &selected_cell==&c) {
 		
 
 				if (!selected_cell.selected) {
@@ -1301,6 +1308,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 					
 					selected_item=p_selected;
 					selected_col=i;
+
 					emit_signal("cell_selected");
 					if (select_mode==SELECT_MULTI)
 						emit_signal("multi_selected",p_current,i,true);
@@ -1317,6 +1325,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
 
 				if (r_in_range && *r_in_range) {
 
+
 					if (!c.selected && c.selectable) {
 						c.selected=true;
 						emit_signal("multi_selected",p_current,i,true);
@@ -1467,7 +1476,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 					if (select_mode==SELECT_MULTI && p_mod.shift && selected_item && selected_item!=p_item) {
 
 						bool inrange=false;
-						print_line("SELECT MULTI AND SHIFT AND ALL");
+
 						select_single_item( p_item, root, col,selected_item,&inrange );
 					} else {
 						select_single_item( p_item, root, col );
@@ -1490,7 +1499,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 
 		/* editing */
 
-		bool bring_up_editor=c.selected && already_selected;
+		bool bring_up_editor=c.selected;// && already_selected;
 		bool bring_up_value_editor=false;
 		String editor_text=c.text;
 
@@ -1605,31 +1614,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
 			return -1;
 
 
-		click_handled=true;
+
+		click_handled=true;		
 		popup_edited_item=p_item;
 		popup_edited_item_col=col;
-		text_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset );
-		text_editor->set_size( Size2(col_width,item_h));
-		text_editor->clear();
-		text_editor->set_text( editor_text );
-		text_editor->select_all();
-
-		if (bring_up_value_editor) {
 
-			value_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset+Point2i(0,text_editor->get_size().height) );
-			value_editor->set_size( Size2(col_width,1));
-			value_editor->show_modal();
-			updating_value_editor=true;
-			value_editor->set_min( c.min );
-			value_editor->set_max( c.max );
-			value_editor->set_step( c.step );
-			value_editor->set_val( c.val );
-			value_editor->set_exp_unit_value( c.expr );
-			updating_value_editor=false;
-		}
-
-		text_editor->show_modal();
-		text_editor->grab_focus();
+		pressing_item_rect=Rect2(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset,Size2(col_width,item_h));
+		pressing_for_editor_text=editor_text;
+		pressing_for_editor=true;
 
 		return -1; //select
 	} else {
@@ -2062,6 +2054,33 @@ void Tree::_input_event(InputEvent p_event) {
 				update();
 			}
 
+			if (pressing_for_editor && popup_edited_item && popup_edited_item->get_cell_mode(popup_edited_item_col)==TreeItem::CELL_MODE_RANGE) {
+				//range drag
+
+				if (!range_drag_enabled) {
+
+					Vector2 cpos = Vector2(b.x,b.y);
+					if (cpos.distance_to(pressing_pos)>2) {
+						range_drag_enabled=true;
+						range_drag_capture_pos=cpos;
+						range_drag_base=popup_edited_item->get_range(popup_edited_item_col);
+						Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+					}
+				} else {
+
+					TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col];
+					float diff_y = -b.relative_y;
+					diff_y=pow(ABS(diff_y),1.8)*SGN(diff_y);
+					diff_y*=0.1;
+					range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max);
+
+					popup_edited_item->set_range(popup_edited_item_col,range_drag_base);
+					item_edited(popup_edited_item_col,popup_edited_item);
+
+				}
+
+			}
+
 			if (drag_touching && ! drag_touching_deaccel) {
 
 
@@ -2084,6 +2103,31 @@ void Tree::_input_event(InputEvent p_event) {
 
 				if (b.button_index==BUTTON_LEFT) {
 
+					if (pressing_for_editor) {
+
+						if (range_drag_enabled) {
+
+							range_drag_enabled=false;
+							Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+							warp_mouse(range_drag_capture_pos);
+						} else {
+							text_editor->set_pos(pressing_item_rect.pos);
+							text_editor->set_size(pressing_item_rect.size);
+
+							text_editor->clear();
+							text_editor->set_text( pressing_for_editor_text );
+							text_editor->select_all();
+
+							text_editor->show_modal();
+							text_editor->grab_focus();
+
+						}
+						pressing_for_editor=false;
+
+					}
+
+
+
 					if (cache.click_type==Cache::CLICK_BUTTON) {
 						emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id);
 
@@ -2145,11 +2189,15 @@ void Tree::_input_event(InputEvent p_event) {
 						break;
 
 					click_handled=false;
+					pressing_for_editor=false;
 
 					blocked++;
 					bool handled = propagate_mouse_event(pos+cache.offset,0,0,b.doubleclick,root,b.button_index,b.mod);
 					blocked--;
 
+					if (pressing_for_editor) {
+						pressing_pos=Point2(b.x,b.y);
+					}
 
 
 					if (drag_touching) {
@@ -2615,6 +2663,8 @@ void Tree::clear() {
 	selected_item=NULL;
 	edited_item=NULL;
 	popup_edited_item=NULL;
+	selected_item=NULL;
+	pressing_for_editor=false;
 
 	update();
 };
@@ -3189,6 +3239,8 @@ Tree::Tree() {
 	drag_speed=0;
 	drag_touching=false;
 	drag_touching_deaccel=false;
+	pressing_for_editor=false;
+	range_drag_enabled=false;
 
 }
 

+ 11 - 0
scene/gui/tree.h

@@ -258,7 +258,18 @@ friend class TreeItem;
 	TreeItem *popup_edited_item;
 	TreeItem *selected_item;
 	TreeItem *edited_item;
+
+
 	int pressed_button;
+	bool pressing_for_editor;
+	String pressing_for_editor_text;
+	Vector2 pressing_pos;
+	Rect2 pressing_item_rect;
+
+	float range_drag_base;
+	bool range_drag_enabled;
+	Vector2 range_drag_capture_pos;
+
 
 	//TreeItem *cursor_item;
 	//int cursor_column;

+ 1 - 1
scene/resources/default_theme/default_theme.cpp

@@ -297,7 +297,7 @@ void make_default_theme() {
 	t->set_color("font_color_hover","MenuButton", control_font_color_hover );
 	t->set_color("font_color_disabled","MenuButton", Color(1,1,1,0.3) );
 
-	t->set_constant("hseparation","MenuButton", 0 );
+	t->set_constant("hseparation","MenuButton", 3 );
 
 	// CheckBox
 

+ 231 - 0
tools/editor/array_property_edit.cpp

@@ -0,0 +1,231 @@
+#include "array_property_edit.h"
+
+#include "editor_node.h"
+
+#define ITEMS_PER_PAGE 100
+
+Variant ArrayPropertyEdit::get_array() const{
+
+	Object*o = ObjectDB::get_instance(obj);
+	if (!o)
+		return Array();
+	Variant arr=o->get(property);
+	if (!arr.is_array()) {
+		Variant::CallError ce;
+		arr=Variant::construct(default_type,NULL,0,ce);
+	}
+	return arr;
+}
+
+void ArrayPropertyEdit::_notif_change() {
+	_change_notify();
+}
+void ArrayPropertyEdit::_notif_changev(const String& p_v) {
+
+	_change_notify(p_v.utf8().get_data());
+}
+
+void ArrayPropertyEdit::_set_size(int p_size) {
+
+	Variant arr = get_array();
+	arr.call("resize",p_size);
+	Object*o = ObjectDB::get_instance(obj);
+	if (!o)
+		return;
+
+	o->set(property,arr);
+
+}
+
+void ArrayPropertyEdit::_set_value(int p_idx,const Variant& p_value) {
+
+	Variant arr = get_array();
+	arr.set(p_idx,p_value);
+	Object*o = ObjectDB::get_instance(obj);
+	if (!o)
+		return;
+
+	o->set(property,arr);
+}
+
+bool ArrayPropertyEdit::_set(const StringName& p_name, const Variant& p_value){
+
+	String pn=p_name;
+
+	if (pn.begins_with("array/")) {
+
+		if (pn=="array/size") {
+
+			Variant arr = get_array();
+			int size = arr.call("size");
+
+			int newsize=p_value;
+			if (newsize==size)
+				return true;
+
+			UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+			ur->create_action("Resize Array");
+			ur->add_do_method(this,"_set_size",newsize);
+			ur->add_undo_method(this,"_set_size",size);
+			if (newsize<size) {
+				for(int i=newsize;i<size;i++) {
+					ur->add_undo_method(this,"_set_value",i,arr.get(i));
+
+				}
+			}
+			ur->add_do_method(this,"_notif_change");
+			ur->add_undo_method(this,"_notif_change");
+			ur->commit_action();
+			return true;
+		}
+		if (pn=="array/page") {
+			page=p_value;
+			_change_notify();
+			return true;
+		}
+	} else if (pn.begins_with("indices")) {
+
+		if (pn.find("_")!=-1) {
+			//type
+			int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int();
+
+			int type = p_value;
+
+			Variant arr = get_array();
+
+			Variant value = arr.get(idx);
+			if (value.get_type()!=type && type>=0 && type<Variant::VARIANT_MAX) {
+				Variant::CallError ce;
+				Variant new_value=Variant::construct(Variant::Type(type),NULL,0,ce);
+				UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+				ur->create_action("Change Array Value Type");
+				ur->add_do_method(this,"_set_value",idx,new_value);
+				ur->add_undo_method(this,"_set_value",idx,value);
+				ur->add_do_method(this,"_notif_change");
+				ur->add_undo_method(this,"_notif_change");
+				ur->commit_action();
+
+			}
+			return true;
+
+		} else {
+			int idx=pn.get_slicec('/',1).to_int();
+			Variant arr = get_array();
+
+			Variant value = arr.get(idx);
+			UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+			ur->create_action("Change Array Value");
+			ur->add_do_method(this,"_set_value",idx,p_value);
+			ur->add_undo_method(this,"_set_value",idx,value);
+			ur->add_do_method(this,"_notif_changev",p_name);
+			ur->add_undo_method(this,"_notif_changev",p_name);
+			ur->commit_action();
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool ArrayPropertyEdit::_get(const StringName& p_name,Variant &r_ret) const {
+
+	Variant arr = get_array();
+	//int size = arr.call("size");
+
+	String pn=p_name;
+	if (pn.begins_with("array/")) {
+
+		if (pn=="array/size") {
+			r_ret=arr.call("size");
+			return true;
+		}
+		if (pn=="array/page") {
+			r_ret=page;
+			return true;
+		}
+	} else if (pn.begins_with("indices")) {
+
+		if (pn.find("_")!=-1) {
+			//type
+			int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int();
+			bool valid;
+			r_ret=arr.get(idx,&valid);
+			if (valid)
+				r_ret=r_ret.get_type();
+			return valid;
+
+		} else {
+			int idx=pn.get_slicec('/',1).to_int();
+			bool valid;
+			r_ret=arr.get(idx,&valid);
+			return valid;
+		}
+	}
+
+	return false;
+}
+
+void ArrayPropertyEdit::_get_property_list( List<PropertyInfo> *p_list) const{
+
+	Variant arr = get_array();
+	int size = arr.call("size");
+
+	p_list->push_back( PropertyInfo(Variant::INT,"array/size",PROPERTY_HINT_RANGE,"0,100000,1") );
+	int pages = size/ITEMS_PER_PAGE;
+	if (pages>0)
+		p_list->push_back( PropertyInfo(Variant::INT,"array/page",PROPERTY_HINT_RANGE,"0,"+itos(pages)+",1") );
+
+	int offset=page*ITEMS_PER_PAGE;
+
+	int items=MIN(size-offset,ITEMS_PER_PAGE);
+
+
+	for(int i=0;i<items;i++) {
+
+		Variant v=arr.get(i+offset);
+		if (arr.get_type()==Variant::ARRAY) {
+			p_list->push_back(PropertyInfo(Variant::INT,"indices/"+itos(i+offset)+"_type",PROPERTY_HINT_ENUM,vtypes));
+		}
+		if (arr.get_type()!=Variant::ARRAY || v.get_type()!=Variant::NIL) {
+			PropertyInfo pi(v.get_type(),"indices/"+itos(i+offset));
+			if (v.get_type()==Variant::OBJECT) {
+				pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
+				pi.hint_string="Resource";
+			}
+			p_list->push_back(pi);
+		}
+	}
+
+}
+
+void ArrayPropertyEdit::edit(Object* p_obj,const StringName& p_prop,Variant::Type p_deftype) {
+
+	page=0;
+	property=p_prop;
+	obj=p_obj->get_instance_ID();
+	default_type=p_deftype;
+
+}
+
+void ArrayPropertyEdit::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("_set_size"),&ArrayPropertyEdit::_set_size);
+	ObjectTypeDB::bind_method(_MD("_set_value"),&ArrayPropertyEdit::_set_value);
+	ObjectTypeDB::bind_method(_MD("_notif_change"),&ArrayPropertyEdit::_notif_change);
+	ObjectTypeDB::bind_method(_MD("_notif_changev"),&ArrayPropertyEdit::_notif_changev);
+}
+
+ArrayPropertyEdit::ArrayPropertyEdit()
+{
+	page=0;
+	for(int i=0;i<Variant::VARIANT_MAX;i++) {
+
+		if (i>0)
+			vtypes+=",";
+		vtypes+=Variant::get_type_name( Variant::Type(i) );
+	}
+	default_type=Variant::NIL;
+
+}

+ 36 - 0
tools/editor/array_property_edit.h

@@ -0,0 +1,36 @@
+#ifndef ARRAY_PROPERTY_EDIT_H
+#define ARRAY_PROPERTY_EDIT_H
+
+#include "scene/main/node.h"
+
+class ArrayPropertyEdit : public Reference {
+
+	OBJ_TYPE(ArrayPropertyEdit,Reference);
+
+	int page;
+	ObjectID obj;
+	StringName property;
+	String vtypes;
+	Variant get_array() const;
+	Variant::Type default_type;
+
+	void _notif_change();
+	void _notif_changev(const String& p_v);
+	void _set_size(int p_size);
+	void _set_value(int p_idx,const Variant& p_value);
+
+protected:
+
+	static void _bind_methods();
+	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 edit(Object* p_obj, const StringName& p_prop, Variant::Type p_deftype);
+
+	ArrayPropertyEdit();
+};
+
+#endif // ARRAY_PROPERTY_EDIT_H

+ 1 - 1
tools/editor/editor_data.cpp

@@ -523,7 +523,7 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const {
 	if (!edited_scene[p_idx].root)
 		return Ref<Script>();
 	Ref<Script> s=edited_scene[p_idx].root->get_script();
-	if (!s.is_valid()) {
+	if (!s.is_valid() && edited_scene[p_idx].root->get_child_count()) {
 		Node *n = edited_scene[p_idx].root->get_child(0);
 		while(!s.is_valid() && n && n->get_filename()==String()) {
 			s=n->get_script();

+ 11 - 1
tools/editor/editor_node.cpp

@@ -93,7 +93,7 @@
 #include "plugins/light_occluder_2d_editor_plugin.h"
 #include "plugins/color_ramp_editor_plugin.h"
 #include "plugins/collision_shape_2d_editor_plugin.h"
-
+#include "os/input.h"
 // end
 #include "tools/editor/io_plugins/editor_texture_import_plugin.h"
 #include "tools/editor/io_plugins/editor_scene_import_plugin.h"
@@ -1765,6 +1765,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
 
 			int idx = editor_data.add_edited_scene(-1);
 			_scene_tab_changed(idx);
+			editor_data.clear_editor_states();
 
 			//_cleanup_scene();
 
@@ -4163,6 +4164,14 @@ EditorNode::EditorNode() {
 
 	EditorHelp::generate_doc(); //before any editor classes are crated
 
+	if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
+		//only if no touchscreen ui hint, set emulation
+		InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
+		if (id)
+			id->set_emulate_touch(false); //just disable just in case
+	}
+
+
 	singleton=this;
 	last_checked_version=0;
 	changing_scene=false;
@@ -4835,6 +4844,7 @@ EditorNode::EditorNode() {
 	property_editor->set_autoclear(true);
 	property_editor->set_show_categories(true);
 	property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+	property_editor->set_use_doc_hints(true);
 	
 	property_editor->hide_top_label();
 

+ 43 - 0
tools/editor/plugins/animation_player_editor_plugin.cpp

@@ -549,6 +549,49 @@ void AnimationPlayerEditor::ensure_visibility() {
 	_animation_edit();
 }
 
+Dictionary AnimationPlayerEditor::get_state() const {
+
+	Dictionary d;
+
+	d["visible"]=is_visible();
+	if (is_visible() && player) {
+		d["player"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
+		d["animation"]=player->get_current_animation();
+		d["editing"]=edit_anim->is_pressed();
+	}
+
+	return d;
+
+}
+void AnimationPlayerEditor::set_state(const Dictionary& p_state) {
+
+	if (p_state.has("visible") && p_state["visible"]) {
+
+		Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]);
+		if (n && n->cast_to<AnimationPlayer>()) {
+			player=n->cast_to<AnimationPlayer>();
+			_update_player();
+			show();
+			set_process(true);
+			ensure_visibility();
+			EditorNode::get_singleton()->animation_panel_make_visible(true);
+
+			if (p_state.has("animation")) {
+				String anim = p_state["animation"];
+				_select_anim_by_name(anim);
+				if (p_state.has("editing") && p_state["editing"]) {
+
+					edit_anim->set_pressed(true);
+					_animation_edit();
+				}
+			}
+
+		}
+	}
+
+}
+
+
 void AnimationPlayerEditor::_animation_resource_edit() {
 
 	if (animation->get_item_count()) {

+ 7 - 0
tools/editor/plugins/animation_player_editor_plugin.h

@@ -151,6 +151,10 @@ protected:
 	static void _bind_methods();
 public:
 
+	Dictionary get_state() const;
+	void set_state(const Dictionary& p_state);
+
+
 	void ensure_visibility();
 
 	void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo=p_undo_redo; }
@@ -167,6 +171,9 @@ class AnimationPlayerEditorPlugin : public EditorPlugin {
 
 public:
 
+	virtual Dictionary get_state() const { return anim_editor->get_state(); }
+	virtual void set_state(const Dictionary& p_state)  { anim_editor->set_state(p_state); }
+
 	virtual String get_name() const { return "Anim"; }
 	bool has_main_screen() const { return false; }
 	virtual void edit(Object *p_node);

+ 2 - 0
tools/editor/plugins/mesh_editor_plugin.cpp

@@ -216,6 +216,8 @@ MeshInstanceEditor::MeshInstanceEditor() {
 	SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
 
 	options->set_text("Mesh");
+	options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance","EditorIcons"));
+
 	options->get_popup()->add_item("Create Trimesh Static Body",MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
 	options->get_popup()->add_item("Create Convex Static Body",MENU_OPTION_CREATE_STATIC_CONVEX_BODY);
 	options->get_popup()->add_separator();

+ 2 - 0
tools/editor/plugins/multimesh_editor_plugin.cpp

@@ -330,6 +330,8 @@ MultiMeshEditor::MultiMeshEditor() {
 	options->set_area_as_parent_rect();
 
 	options->set_text("MultiMesh");
+	options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance","EditorIcons"));
+
 	options->get_popup()->add_item("Populate Surface");
 	options->get_popup()->connect("item_pressed", this,"_menu_option");
 

+ 1 - 0
tools/editor/plugins/particles_2d_editor_plugin.cpp

@@ -146,6 +146,7 @@ void Particles2DEditorPlugin::_notification(int p_what) {
 	if (p_what==NOTIFICATION_ENTER_TREE) {
 
 		menu->get_popup()->connect("item_pressed",this,"_menu_callback");
+		menu->set_icon(menu->get_popup()->get_icon("Particles2D","EditorIcons"));
 		file->connect("file_selected",this,"_file_selected");
 	}
 }

+ 1 - 0
tools/editor/plugins/particles_editor_plugin.cpp

@@ -111,6 +111,7 @@ void ParticlesEditor::_populate() {
 void ParticlesEditor::_notification(int p_notification) {
 
 	if (p_notification==NOTIFICATION_ENTER_TREE) {
+		options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons"));
 
 	}
 }

+ 16 - 1
tools/editor/plugins/spatial_editor_plugin.cpp

@@ -2168,7 +2168,18 @@ void SpatialEditorViewport::set_state(const Dictionary& p_state) {
 		view_menu->get_popup()->set_item_checked( idx, listener );
 	}
 
-
+	if (p_state.has("previewing")) {
+		Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
+		if (pv && pv->cast_to<Camera>()) {
+			previewing=pv->cast_to<Camera>();
+			previewing->connect("exit_tree",this,"_preview_exited_scene");
+			VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), previewing->get_camera() ); //replace
+			view_menu->hide();
+			surface->update();
+			preview_camera->set_pressed(true);
+			preview_camera->show();
+		}
+	}
 }
 
 Dictionary SpatialEditorViewport::get_state() const {
@@ -2181,6 +2192,10 @@ Dictionary SpatialEditorViewport::get_state() const {
 	d["use_environment"]=camera->get_environment().is_valid();
 	d["use_orthogonal"]=camera->get_projection()==Camera::PROJECTION_ORTHOGONAL;
 	d["listener"]=viewport->is_audio_listener();
+	if (previewing) {
+		d["previewing"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
+	}
+
 	return d;
 }
 

+ 163 - 11
tools/editor/property_editor.cpp

@@ -40,6 +40,8 @@
 #include "editor_import_export.h"
 #include "editor_node.h"
 #include "multi_node_edit.h"
+#include "array_property_edit.h"
+#include "editor_help.h"
 
 void CustomPropertyEditor::_notification(int p_what) {
 
@@ -2270,6 +2272,23 @@ void PropertyEditor::update_tree() {
 			sep->set_selectable(1,false);
 			sep->set_custom_bg_color(0,get_color("prop_category","Editor"));
 			sep->set_custom_bg_color(1,get_color("prop_category","Editor"));
+
+			if (use_doc_hints) {
+				StringName type=p.name;
+				if (!class_descr_cache.has(type)) {
+
+					String descr;
+					DocData *dd=EditorHelp::get_doc_data();
+					Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type);
+					if (E) {
+						descr=E->get().brief_description;
+					}
+					class_descr_cache[type]=descr.world_wrap(80);
+
+				}
+
+				sep->set_tooltip(0,"Class: "+p.name+":\n\n"+class_descr_cache[type]);
+			}
 			//sep->set_custom_color(0,Color(1,1,1));
 
 
@@ -2323,6 +2342,42 @@ void PropertyEditor::update_tree() {
 
 		item->set_tooltip(0, p.name);
 
+		if (use_doc_hints) {
+			StringName setter;
+			StringName type;
+			if (ObjectTypeDB::get_setter_and_type_for_property(obj->get_type_name(),p.name,type,setter)) {
+
+				String descr;
+				bool found=false;
+				Map<StringName,Map<StringName,String> >::Element *E=descr_cache.find(type);
+				if (E) {
+
+					Map<StringName,String>::Element *F=E->get().find(setter);
+					if (F) {
+						found=true;
+						descr=F->get();
+					}
+				}
+				if (!found) {
+
+					DocData *dd=EditorHelp::get_doc_data();
+					Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type);
+					if (E) {
+						for(int i=0;i<E->get().methods.size();i++) {
+							if (E->get().methods[i].name==setter.operator String()) {
+								descr=E->get().methods[i].description.strip_edges().world_wrap(80);
+							}
+						}
+					}
+
+					descr_cache[type][setter]=descr;
+				}
+
+				item->set_tooltip(0, "Property: "+p.name+"\n\n"+descr);
+			}
+		}
+		//EditorHelp::get_doc_data();
+
 		Dictionary d;
 		d["name"]=p.name;
 		d["type"]=(int)p.type;
@@ -2405,8 +2460,10 @@ void PropertyEditor::update_tree() {
 
 
 				item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE );
+				if (p.hint==PROPERTY_HINT_SPRITE_FRAME) {
+					item->set_range_config(1,0,99999,1);
 
-				if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) {
+				} else if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) {
 
 					int c = p.hint_string.get_slice_count(",");
 					float min=0,max=100,step=1;
@@ -2507,11 +2564,32 @@ void PropertyEditor::update_tree() {
 				}
 
 			} break;
+			case Variant::ARRAY: {
+
+				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"Array["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"Array[]");
+				item->set_icon( 0, get_icon("ArrayData","EditorIcons") );
+
+
+			} break;
+
 			case Variant::INT_ARRAY: {
 
 				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
-				item->set_editable( 1, !read_only );
-				item->set_text(1,"[IntArray]");
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"IntArray["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"IntArray[]");
 				item->set_icon( 0, get_icon("ArrayInt","EditorIcons") );
 
 
@@ -2519,26 +2597,86 @@ void PropertyEditor::update_tree() {
 			case Variant::REAL_ARRAY: {
 
 				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
-				item->set_editable( 1, !read_only );
-				item->set_text(1,"[RealArray]");
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"FloatArray["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"FloatArray[]");
 				item->set_icon( 0, get_icon("ArrayReal","EditorIcons") );
 
+
 			} break;
 			case Variant::STRING_ARRAY: {
 
 				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
-				item->set_editable( 1, !read_only );
-				item->set_text(1,"[StringArray]");
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"String["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"String[]");
 				item->set_icon( 0, get_icon("ArrayString","EditorIcons") );
 
+
 			} break;
 			case Variant::RAW_ARRAY: {
 
 				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
-				item->set_editable( 1, !read_only );
-				item->set_text(1,"[Raw Data]");
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"Byte["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"Byte[]");
 				item->set_icon( 0, get_icon("ArrayData","EditorIcons") );
 
+
+			} break;
+			case Variant::VECTOR2_ARRAY: {
+
+				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"Vector2["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"Vector2[]");
+				item->set_icon( 0, get_icon("Vector2","EditorIcons") );
+
+
+			} break;
+			case Variant::VECTOR3_ARRAY: {
+
+				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"Vector3["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"Vector3[]");
+				item->set_icon( 0, get_icon("Vector","EditorIcons") );
+
+
+			} break;
+			case Variant::COLOR_ARRAY: {
+
+				item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+				item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+				Variant v = obj->get(p.name);
+				if (v.is_array())
+					item->set_text(1,"Color["+itos(v.call("size"))+"]");
+				else
+					item->set_text(1,"Color[]");
+				item->set_icon( 0, get_icon("Color","EditorIcons") );
+
+
 			} break;
 			case Variant::VECTOR2: {
 
@@ -2734,7 +2872,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
 		}
 	}
 
-	if (!undo_redo || obj->cast_to<MultiNodeEdit>()) { //kind of hacky
+	if (!undo_redo || obj->cast_to<MultiNodeEdit>() || obj->cast_to<ArrayPropertyEdit>()) { //kind of hacky
 
 		obj->set(p_name,p_value);
 		_changed_callbacks(obj,p_name);
@@ -3054,6 +3192,19 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
 
 				emit_signal("resource_selected",r,n);
 			}
+		} 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);
+
+			if (v.get_type()!=t) {
+				Variant::CallError ce;
+				v=Variant::construct(Variant::Type(t),NULL,0,ce);
+			}
+
+			Ref<ArrayPropertyEdit> ape = memnew( ArrayPropertyEdit );
+			ape->edit(obj,n,Variant::Type(t));
+
+			EditorNode::get_singleton()->push_item(ape.ptr());
 		}
 	}
 }
@@ -3239,7 +3390,8 @@ PropertyEditor::PropertyEditor() {
 	read_only=false;
 	show_categories=false;
 	refresh_countdown=0;
-
+	use_doc_hints=false;
+	
 }
 
 

+ 8 - 2
tools/editor/property_editor.h

@@ -96,6 +96,7 @@ class CustomPropertyEditor : public Popup {
 	SpinBox *spinbox;
 	HSlider *slider;
 
+
 	Control *easing_draw;
 
 	Object* owner;
@@ -159,10 +160,14 @@ class PropertyEditor : public Control {
 	bool read_only;
 	bool show_categories;
 	float refresh_countdown;
+	bool use_doc_hints;
 
 	HashMap<String,String> pending;
 	String selected_property;
 
+	Map<StringName,Map<StringName,String> > descr_cache;
+	Map<StringName,String > class_descr_cache;
+	
 	CustomPropertyEditor *custom_editor;
 
 	void _resource_edit_request();
@@ -219,8 +224,9 @@ public:
 	void set_autoclear(bool p_enable);
 
 	void set_show_categories(bool p_show);
-
-	PropertyEditor();
+	void set_use_doc_hints(bool p_enable) { use_doc_hints=p_enable; }
+	
+	PropertyEditor();	
 	~PropertyEditor();
 
 };