Преглед изворни кода

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

Juan Linietsky пре 9 година
родитељ
комит
c650d4e19c
49 измењених фајлова са 1107 додато и 577 уклоњено
  1. 1 0
      .gitignore
  2. 1 0
      SConstruct
  3. 1 0
      core/os/os.h
  4. 7 15
      core/ustring.cpp
  5. 20 18
      core/vector.h
  6. BIN
      demos/viewport/gui_in_3d/gui.scn
  7. 5 5
      doc/base/classes.xml
  8. 51 12
      drivers/gles2/rasterizer_gles2.cpp
  9. 3 1
      drivers/nrex/README.md
  10. 67 34
      drivers/nrex/nrex.cpp
  11. 34 7
      drivers/nrex/nrex.hpp
  12. 3 3
      drivers/nrex/regex.cpp
  13. 1 1
      drivers/nrex/regex.h
  14. 8 0
      drivers/unix/SCsub
  15. 8 0
      drivers/unix/os_unix.cpp
  16. 3 0
      drivers/unix/os_unix.h
  17. 0 6
      modules/gdscript/gd_tokenizer.cpp
  18. 16 13
      platform/android/export/export.cpp
  19. 11 7
      platform/bb10/export/export.cpp
  20. 16 11
      platform/javascript/export/export.cpp
  21. 13 10
      platform/osx/export/export.cpp
  22. 5 2
      platform/x11/detect.py
  23. 3 2
      platform/x11/os_x11.cpp
  24. 1 1
      platform/x11/platform_config.h
  25. 10 0
      scene/2d/canvas_item.cpp
  26. 1 0
      scene/2d/canvas_item.h
  27. 4 11
      scene/3d/physics_body.cpp
  28. 1 1
      scene/3d/physics_body.h
  29. 10 0
      scene/3d/spatial.cpp
  30. 1 0
      scene/3d/spatial.h
  31. 14 8
      servers/physics/body_sw.cpp
  32. 1 1
      servers/physics/body_sw.h
  33. 9 7
      servers/physics/space_sw.cpp
  34. 15 10
      servers/physics_2d/body_2d_sw.cpp
  35. 1 1
      servers/physics_2d/body_2d_sw.h
  36. 11 3
      servers/visual/shader_language.cpp
  37. 60 15
      tools/editor/editor_import_export.cpp
  38. 2 0
      tools/editor/editor_import_export.h
  39. 59 0
      tools/editor/editor_layout_dialog.cpp
  40. 53 0
      tools/editor/editor_layout_dialog.h
  41. 190 20
      tools/editor/editor_node.cpp
  42. 15 1
      tools/editor/editor_node.h
  43. 1 0
      tools/editor/editor_settings.h
  44. 72 93
      tools/editor/groups_editor.cpp
  45. 18 18
      tools/editor/groups_editor.h
  46. 165 200
      tools/editor/plugins/item_list_editor_plugin.cpp
  47. 102 36
      tools/editor/plugins/item_list_editor_plugin.h
  48. 11 3
      tools/editor/property_editor.cpp
  49. 3 1
      tools/editor/property_editor.h

+ 1 - 0
.gitignore

@@ -15,6 +15,7 @@ core/method_bind.inc
 core/method_bind_ext.inc
 core/script_encryption_key.cpp
 core/global_defaults.cpp
+drivers/unix/os_unix_global_settings_path.cpp
 tools/editor/register_exporters.cpp
 tools/editor/doc_data_compressed.h
 tools/editor/editor_icons.cpp

+ 1 - 0
SConstruct

@@ -127,6 +127,7 @@ opts.Add("CXX", "Compiler");
 opts.Add("CCFLAGS", "Custom flags for the C++ compiler");
 opts.Add("CFLAGS", "Custom flags for the C compiler");
 opts.Add("LINKFLAGS", "Custom flags for the linker");
+opts.Add('unix_global_settings_path', 'unix-specific path to system-wide settings. Currently only used by templates.','')
 opts.Add('disable_3d', 'Disable 3D nodes for smaller executable (yes/no)', "no")
 opts.Add('disable_advanced_gui', 'Disable advance 3D gui nodes and behaviors (yes/no)', "no")
 opts.Add('colored', 'Enable colored output for the compilation (yes/no)', 'no')

+ 1 - 0
core/os/os.h

@@ -184,6 +184,7 @@ public:
 	virtual void set_low_processor_usage_mode(bool p_enabled);
 	virtual bool is_in_low_processor_usage_mode() const;
 
+	virtual String get_installed_templates_path() const { return ""; };
 	virtual String get_executable_path() const;
 	virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL)=0;
 	virtual Error kill(const ProcessID& p_pid)=0;

+ 7 - 15
core/ustring.cpp

@@ -897,17 +897,8 @@ String String::num(double p_num,int p_decimals) {
 	}
 	char buf[256];
 
-#if defined(__GNUC__)
-#ifdef MINGW_ENABLED
-	//snprintf is inexplicably broken in mingw
-	//sprintf(buf,fmt,p_num);
-	_snprintf(buf,256,fmt,p_num);
-#else
+#if defined(__GNUC__) || defined(_MSC_VER)
 	snprintf(buf,256,fmt,p_num);
-#endif
-
-#elif defined(_MSC_VER)
-	_snprintf(buf,256,fmt,p_num);
 #else
 	sprintf(buf,fmt,p_num);
 #endif
@@ -1178,10 +1169,7 @@ String String::num_scientific(double p_num) {
 
 	char buf[256];
 
-#if defined(_MSC_VER) || defined(MINGW_ENABLED)
-
-	_snprintf(buf,256,"%lg",p_num);
-#elif defined(__GNUC__)
+#if defined(__GNUC__) || defined(_MSC_VER)
 	snprintf(buf,256,"%lg",p_num);
 #else
 	sprintf(buf,"%.16lg",p_num);
@@ -3096,7 +3084,11 @@ String String::http_escape() const {
             res += ord;
         } else {
             char h_Val[3];
-			snprintf(h_Val, 3, "%.2X", ord);
+#if defined(__GNUC__) || defined(_MSC_VER)
+            snprintf(h_Val, 3, "%.2X", ord);
+#else
+            sprintf(h_Val, "%.2X", ord);
+#endif
             res += "%";
             res += h_Val;
         }

+ 20 - 18
core/vector.h

@@ -42,7 +42,7 @@
 template<class T>
 class Vector {
 
-	mutable void* _ptr;
+	mutable T* _ptr;
  
  	// internal helpers
  
@@ -51,21 +51,21 @@ class Vector {
 		if (!_ptr)
  			return NULL;
  			
-		return reinterpret_cast<SafeRefCount*>(_ptr);
+		return reinterpret_cast<SafeRefCount*>((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount));
  	}
  	
 	_FORCE_INLINE_ int* _get_size() const  {
  	
 		if (!_ptr)
  			return NULL;
-		return reinterpret_cast<int*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount));
+		return reinterpret_cast<int*>((uint8_t*)_ptr-sizeof(int));
  		
  	}
 	_FORCE_INLINE_ T* _get_data() const {
  	
 		if (!_ptr)
  			return NULL;
-		return reinterpret_cast<T*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount)+sizeof(int));
+		return reinterpret_cast<T*>(_ptr);
  		
  	}
  	
@@ -88,11 +88,11 @@ public:
 	_FORCE_INLINE_ void clear() { resize(0); }
 	
 	_FORCE_INLINE_ int size() const {
-		
-		if (!_ptr)
-			return 0;
+		int* size = _get_size();
+		if (size)
+			return *size;
 		else		
-			return *reinterpret_cast<int*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount));
+			return 0;
 	}
 	_FORCE_INLINE_ bool empty() const { return _ptr == 0; }
 	Error resize(int p_size);
@@ -174,7 +174,7 @@ void Vector<T>::_unref(void *p_data) {
 	if (!p_data)
 		return;
 		
-	SafeRefCount *src = reinterpret_cast<SafeRefCount*>(p_data);
+	SafeRefCount *src = reinterpret_cast<SafeRefCount*>((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount));
 	
 	if (!src->unref())
 		return; // still in use
@@ -189,7 +189,7 @@ void Vector<T>::_unref(void *p_data) {
 	}
 	
 	// free mem
-	memfree(p_data);
+	memfree((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount));
 
 }
 
@@ -201,7 +201,8 @@ void Vector<T>::_copy_on_write() {
 	
 	if (_get_refcount()->get() > 1 ) {
 		/* in use by more than me */
-		SafeRefCount *src_new=(SafeRefCount *)memalloc(_get_alloc_size(*_get_size()));
+		void* mem_new = memalloc(_get_alloc_size(*_get_size()));
+		SafeRefCount *src_new=(SafeRefCount *)mem_new;
 		src_new->init();
 		int * _size = (int*)(src_new+1);
 		*_size=*_get_size();
@@ -215,7 +216,7 @@ void Vector<T>::_copy_on_write() {
 		}
 		
 		_unref(_ptr);
-		_ptr=src_new;
+		_ptr=_data;
 	}
 
 }
@@ -260,16 +261,17 @@ Error Vector<T>::resize(int p_size) {
 
 		if (size()==0) {
 			// alloc from scratch
-			_ptr = (T*)memalloc(_get_alloc_size(p_size));
-			ERR_FAIL_COND_V( !_ptr ,ERR_OUT_OF_MEMORY);
+			void* ptr=memalloc(_get_alloc_size(p_size));
+			ERR_FAIL_COND_V( !ptr ,ERR_OUT_OF_MEMORY);
+			_ptr=(T*)((uint8_t*)ptr+sizeof(int)+sizeof(SafeRefCount));
 			_get_refcount()->init(); // init refcount
 			*_get_size()=0; // init size (currently, none)
 
 		} else {
 			
-			void *_ptrnew = (T*)memrealloc(_ptr,_get_alloc_size(p_size));
+			void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount),_get_alloc_size(p_size));
 			ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY);
-			_ptr=_ptrnew;
+			_ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount));
 		}
 
 		// construct the newly created elements
@@ -291,10 +293,10 @@ Error Vector<T>::resize(int p_size) {
 			t->~T();
 		}
 
-		void *_ptrnew = (T*)memrealloc(_ptr,_get_alloc_size(p_size));
+		void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount),_get_alloc_size(p_size));
 		ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY);
 		
-		_ptr=_ptrnew;
+		_ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount));
 		
 		*_get_size()=p_size;
 				

BIN
demos/viewport/gui_in_3d/gui.scn


+ 5 - 5
doc/base/classes.xml

@@ -15053,14 +15053,13 @@ returns:= "username=user&amp;password=pass"
 			<description>
 			</description>
 		</method>
-		<method name="can_move_to">
+		<method name="can_teleport_to">
 			<return type="bool">
 			</return>
 			<argument index="0" name="position" type="Vector3">
 			</argument>
-			<argument index="1" name="arg1" type="bool">
-			</argument>
 			<description>
+			Returns whether the KinematicBody can be teleported to the destination given as an argument, checking all collision shapes of the body against potential colliders at the destination.
 			</description>
 		</method>
 		<method name="is_colliding" qualifiers="const">
@@ -26960,7 +26959,7 @@ This method controls whether the position between two cached points is interpola
 		Lazy (non-greedy) quantifiers [code]*?[/code]
 		Begining [code]^[/code] and end [code]$[/code] anchors
 		Alternation [code]|[/code]
-		Backreferences [code]\1[/code] to [code]\9[/code]
+		Backreferences [code]\1[/code] and [code]\g{1}[/code]
 		POSIX character classes [code][[:alnum:]][/code]
 		Lookahead [code](?=)[/code], [code](?!)[/code] and lookbehind [code](?&lt;=)[/code], [code](?&lt;!)[/code]
 		ASCII [code]\xFF[/code] and Unicode [code]\uFFFF[/code] code points (in a style similar to Python)
@@ -26972,9 +26971,10 @@ This method controls whether the position between two cached points is interpola
 			</return>
 			<argument index="0" name="pattern" type="String">
 			</argument>
-			<argument index="1" name="expanded" type="bool" default="true">
+			<argument index="1" name="capture" type="int" default="9">
 			</argument>
 			<description>
+            Compiles and assign the regular expression pattern to use. The limit on the number of capturing groups can be specified or made unlimited if negative.
 			</description>
 		</method>
 		<method name="find" qualifiers="const">

+ 51 - 12
drivers/gles2/rasterizer_gles2.cpp

@@ -9169,10 +9169,23 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem
 							//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
 							//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
 
-							int x = current_clip->final_clip_rect.pos.x;
-							int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
-							int w = current_clip->final_clip_rect.size.x;
-							int h = current_clip->final_clip_rect.size.y;
+							int x;
+							int y;
+							int w;
+							int h;
+
+							if (current_rt) {
+								x = current_clip->final_clip_rect.pos.x;
+								y = current_clip->final_clip_rect.pos.y;
+								w = current_clip->final_clip_rect.size.x;
+								h = current_clip->final_clip_rect.size.y;
+							}
+							else {
+								x = current_clip->final_clip_rect.pos.x;
+								y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+								w = current_clip->final_clip_rect.size.x;
+								h = current_clip->final_clip_rect.size.y;
+							}
 
 							glScissor(x,y,w,h);
 
@@ -9362,10 +9375,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 				int w = current_clip->final_clip_rect.size.x;
 				int h = current_clip->final_clip_rect.size.y;
 */
-				int x = current_clip->final_clip_rect.pos.x;
-				int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
-				int w = current_clip->final_clip_rect.size.x;
-				int h = current_clip->final_clip_rect.size.y;
+				int x;
+				int y;
+				int w;
+				int h;
+
+				if (current_rt) {
+					x = current_clip->final_clip_rect.pos.x;
+					y = current_clip->final_clip_rect.pos.y;
+					w = current_clip->final_clip_rect.size.x;
+					h = current_clip->final_clip_rect.size.y;
+				}
+				else {
+					x = current_clip->final_clip_rect.pos.x;
+					y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+					w = current_clip->final_clip_rect.size.x;
+					h = current_clip->final_clip_rect.size.y;
+				}
 
 				glScissor(x,y,w,h);
 
@@ -9667,10 +9693,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
 			//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
 			//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
 
-			int x = current_clip->final_clip_rect.pos.x;
-			int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
-			int w = current_clip->final_clip_rect.size.x;
-			int h = current_clip->final_clip_rect.size.y;
+			int x;
+			int y;
+			int w;
+			int h;
+
+			if (current_rt) {
+				x = current_clip->final_clip_rect.pos.x;
+				y = current_clip->final_clip_rect.pos.y;
+				w = current_clip->final_clip_rect.size.x;
+				h = current_clip->final_clip_rect.size.y;
+			}
+			else {
+				x = current_clip->final_clip_rect.pos.x;
+				y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+				w = current_clip->final_clip_rect.size.x;
+				h = current_clip->final_clip_rect.size.y;
+			}
 
 			glScissor(x,y,w,h);
 

+ 3 - 1
drivers/nrex/README.md

@@ -1,5 +1,7 @@
 # NREX: Node RegEx
 
+Version 0.1
+
 Small node-based regular expression library. It only does text pattern
 matchhing, not replacement. To use add the files `nrex.hpp`, `nrex.cpp`
 and `nrex_config.h` to your project and follow the example:
@@ -32,7 +34,7 @@ Currently supported features:
  * Unicode `\uFFFF` code points
  * Positive `(?=)` and negative `(?!)` lookahead
  * Positive `(?<=)` and negative `(?<!)` lookbehind (fixed length and no alternations)
- * Backreferences `\1` to `\9` (with option to expand to `\99`)
+ * Backreferences `\1` and `\g{1}` (limited by default to 9 - can be unlimited)
 
 ## License
 

+ 67 - 34
drivers/nrex/nrex.cpp

@@ -1,4 +1,5 @@
 //  NREX: Node RegEx
+//  Version 0.1
 //
 //  Copyright (c) 2015, Zher Huei Lee
 //  All rights reserved.
@@ -299,6 +300,10 @@ struct nrex_node_group : public nrex_node
             {
                 length = 1;
             }
+            if (mode == LookAhead || mode == LookBehind)
+            {
+                quantifiable = false;
+            }
         }
 
         virtual ~nrex_node_group()
@@ -322,6 +327,10 @@ struct nrex_node_group : public nrex_node
                 int offset = 0;
                 if (mode == LookBehind)
                 {
+                    if (pos < length)
+                    {
+                        return -1;
+                    }
                     offset = length;
                 }
                 int res = childset[i]->test(s, pos - offset);
@@ -450,7 +459,7 @@ struct nrex_node_char : public nrex_node
 
         int test(nrex_search* s, int pos) const
         {
-            if (s->end == pos || s->at(pos) != ch)
+            if (s->end <= pos || 0 > pos || s->at(pos) != ch)
             {
                 return -1;
             }
@@ -473,7 +482,7 @@ struct nrex_node_range : public nrex_node
 
         int test(nrex_search* s, int pos) const
         {
-            if (s->end == pos)
+            if (s->end <= pos || 0 > pos)
             {
                 return -1;
             }
@@ -555,7 +564,7 @@ struct nrex_node_class : public nrex_node
 
         int test(nrex_search* s, int pos) const
         {
-            if (s->end == pos)
+            if (s->end <= pos || 0 > pos)
             {
                 return -1;
             }
@@ -727,7 +736,7 @@ struct nrex_node_shorthand : public nrex_node
 
         int test(nrex_search* s, int pos) const
         {
-            if (s->end == pos)
+            if (s->end <= pos || 0 > pos)
             {
                 return -1;
             }
@@ -811,16 +820,12 @@ struct nrex_node_quantifier : public nrex_node
 
         int test(nrex_search* s, int pos) const
         {
-            return test_step(s, pos, 1);
+            return test_step(s, pos, 0, pos);
         }
 
-        int test_step(nrex_search* s, int pos, int level) const
+        int test_step(nrex_search* s, int pos, int level, int start) const
         {
-            if (max == 0)
-            {
-                return pos;
-            }
-            if ((max >= 1 && level > max) || pos > s->end)
+            if (pos > s->end)
             {
                 return -1;
             }
@@ -840,14 +845,26 @@ struct nrex_node_quantifier : public nrex_node
                     return res;
                 }
             }
-            int res = child->test(s, pos);
-            if (s->complete)
+            if (max >= 0 && level > max)
             {
-                return res;
+                return -1;
+            }
+            if (level > 1 && level > min + 1 && pos == start)
+            {
+                return -1;
+            }
+            int res = pos;
+            if (level >= 1)
+            {
+                res = child->test(s, pos);
+                if (s->complete)
+                {
+                    return res;
+                }
             }
             if (res >= 0)
             {
-                int res_step = test_step(s, res, level + 1);
+                int res_step = test_step(s, res, level + 1, start);
                 if (res_step >= 0)
                 {
                     return res_step;
@@ -983,6 +1000,13 @@ nrex::nrex()
 {
 }
 
+nrex::nrex(const nrex_char* pattern, int captures)
+    : _capturing(0)
+    , _root(NULL)
+{
+    compile(pattern, captures);
+}
+
 nrex::~nrex()
 {
     if (_root)
@@ -1008,10 +1032,14 @@ void nrex::reset()
 
 int nrex::capture_size() const
 {
-    return _capturing + 1;
+    if (_root)
+    {
+        return _capturing + 1;
+    }
+    return 0;
 }
 
-bool nrex::compile(const nrex_char* pattern, bool extended)
+bool nrex::compile(const nrex_char* pattern, int captures)
 {
     reset();
     nrex_node_group* root = NREX_NEW(nrex_node_group(_capturing));
@@ -1053,7 +1081,7 @@ bool nrex::compile(const nrex_char* pattern, bool extended)
                     NREX_COMPILE_ERROR("unrecognised qualifier for group");
                 }
             }
-            else if ((!extended && _capturing < 9) || (extended && _capturing < 99))
+            else if (captures >= 0 && _capturing < captures)
             {
                 nrex_node_group* group = NREX_NEW(nrex_node_group(++_capturing));
                 stack.top()->add_child(group);
@@ -1190,15 +1218,6 @@ bool nrex::compile(const nrex_char* pattern, bool extended)
         }
         else if (nrex_is_quantifier(c[0]))
         {
-            if (stack.top()->back == NULL || !stack.top()->back->quantifiable)
-            {
-                if (c[0] == '{')
-                {
-                    stack.top()->add_child(NREX_NEW(nrex_node_char('{')));
-                    continue;
-                }
-                NREX_COMPILE_ERROR("element not quantifiable");
-            }
             int min = 0;
             int max = -1;
             bool valid_quantifier = true;
@@ -1270,6 +1289,10 @@ bool nrex::compile(const nrex_char* pattern, bool extended)
             }
             if (valid_quantifier)
             {
+                if (stack.top()->back == NULL || !stack.top()->back->quantifiable)
+                {
+                    NREX_COMPILE_ERROR("element not quantifiable");
+                }
                 nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier(min, max));
                 if (min == max)
                 {
@@ -1323,20 +1346,26 @@ bool nrex::compile(const nrex_char* pattern, bool extended)
                 stack.top()->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
                 ++c;
             }
-            else if ('1' <= c[1] && c[1] <= '9')
+            else if (('1' <= c[1] && c[1] <= '9') || (c[1] == 'g' && c[2] == '{'))
             {
                 int ref = 0;
-                if (extended && '0' <= c[2] && c[2] <= '9')
+                bool unclosed = false;
+                if (c[1] == 'g')
                 {
-                    ref = int(c[1] - '0') * 10 + int(c[2] - '0');
+                    unclosed = true;
                     c = &c[2];
                 }
-                else
+                while ('0' <= c[1] && c[1] <= '9')
                 {
-                    ref = int(c[1] - '0');
+                    ref = ref * 10 + int(c[1] - '0');
                     ++c;
                 }
-                if (ref > _capturing)
+                if (c[1] == '}')
+                {
+                    unclosed = false;
+                    ++c;
+                }
+                if (ref > _capturing || ref <= 0 || unclosed)
                 {
                     NREX_COMPILE_ERROR("backreference to non-existent capture");
                 }
@@ -1377,6 +1406,10 @@ bool nrex::compile(const nrex_char* pattern, bool extended)
 
 bool nrex::match(const nrex_char* str, nrex_result* captures, int offset, int end) const
 {
+    if (!_root)
+    {
+        return false;
+    }
     nrex_search s(str, captures);
     if (end >= offset)
     {
@@ -1386,7 +1419,7 @@ bool nrex::match(const nrex_char* str, nrex_result* captures, int offset, int en
     {
         s.end = NREX_STRLEN(str);
     }
-    for (int i = offset; i < s.end; ++i)
+    for (int i = offset; i <= s.end; ++i)
     {
         for (int c = 0; c <= _capturing; ++c)
         {

+ 34 - 7
drivers/nrex/nrex.hpp

@@ -1,4 +1,5 @@
 //  NREX: Node RegEx
+//  Version 0.1
 //
 //  Copyright (c) 2015, Zher Huei Lee
 //  All rights reserved.
@@ -59,7 +60,32 @@ class nrex
         int _capturing;
         nrex_node* _root;
     public:
+
+        /*!
+         * \brief Initialises an empty regex container
+         */
         nrex();
+
+        /*!
+         * \brief Initialises and compiles the regex pattern
+         *
+         * This calls nrex::compile() with the same arguments. To check whether
+         * the compilation was successfull, use nrex::valid().
+         *
+         * If the NREX_THROW_ERROR was defined it would automatically throw a
+         * runtime error nrex_compile_error if it encounters a problem when
+         * parsing the pattern.
+         *
+         * \param pattern   The regex pattern
+         * \param captures  The maximum number of capture groups to allow. Any
+         *                  extra would be converted to non-capturing groups.
+         *                  If negative, no limit would be imposed. Defaults
+         *                  to 9.
+         *
+         * \see nrex::compile()
+         */
+        nrex(const nrex_char* pattern, int captures = 9);
+
         ~nrex();
 
         /*!
@@ -78,9 +104,9 @@ class nrex
          *
          * This is used to provide the array size of the captures needed for
          * nrex::match() to work. The size is actually the number of capture
-         * groups + one for the matching of the entire pattern. The result is
-         * always capped at 10 or 100, depending on the extend option given in
-         * nrex::compile() (default 10).
+         * groups + one for the matching of the entire pattern. This can be
+         * capped using the extra argument given in nrex::compile()
+         * (default 10).
          *
          * \return The number of captures
          */
@@ -97,12 +123,13 @@ class nrex
          * parsing the pattern.
          *
          * \param pattern   The regex pattern
-         * \param extended  If true, raises the limit on number of capture
-         *                  groups and back-references to 99. Otherwise limited
-         *                  to 9. Defaults to false.
+         * \param captures  The maximum number of capture groups to allow. Any
+         *                  extra would be converted to non-capturing groups.
+         *                  If negative, no limit would be imposed. Defaults
+         *                  to 9.
          * \return True if the pattern was succesfully compiled
          */
-        bool compile(const nrex_char* pattern, bool extended = false);
+        bool compile(const nrex_char* pattern, int captures = 9);
 
         /*!
          * \brief Uses the pattern to search through the provided string

+ 3 - 3
drivers/nrex/regex.cpp

@@ -15,7 +15,7 @@
 
 void RegEx::_bind_methods() {
 
-	ObjectTypeDB::bind_method(_MD("compile","pattern", "expanded"),&RegEx::compile, DEFVAL(true));
+	ObjectTypeDB::bind_method(_MD("compile","pattern", "capture"),&RegEx::compile, DEFVAL(9));
 	ObjectTypeDB::bind_method(_MD("find","text","start","end"),&RegEx::find, DEFVAL(0), DEFVAL(-1));
 	ObjectTypeDB::bind_method(_MD("clear"),&RegEx::clear);
 	ObjectTypeDB::bind_method(_MD("is_valid"),&RegEx::is_valid);
@@ -68,11 +68,11 @@ String RegEx::get_capture(int capture) const {
 
 }
 
-Error RegEx::compile(const String& p_pattern, bool expanded) {
+Error RegEx::compile(const String& p_pattern, int capture) {
 
 	clear();
 
-	exp.compile(p_pattern.c_str(), expanded);
+	exp.compile(p_pattern.c_str(), capture);
 
 	ERR_FAIL_COND_V( !exp.valid(), FAILED );
 

+ 1 - 1
drivers/nrex/regex.h

@@ -36,7 +36,7 @@ public:
 	bool is_valid() const;
 	int get_capture_count() const;
 	String get_capture(int capture) const;
-	Error compile(const String& p_pattern, bool expanded = false);
+	Error compile(const String& p_pattern, int capture = 9);
 	int find(const String& p_text, int p_start = 0, int p_end = -1) const;
 
 	RegEx();

+ 8 - 0
drivers/unix/SCsub

@@ -1,5 +1,13 @@
 Import('env')
 
+ed_gl_set='#include "os_unix.h"\n'
+ed_gl_set+='String OS_Unix::get_global_settings_path() const {\n'
+ed_gl_set+='\treturn "' + env["unix_global_settings_path"]+'";\n'
+ed_gl_set+='}\n'
+f = open("os_unix_global_settings_path.cpp","wb")
+f.write(ed_gl_set)
+f.close()
+
 env.add_source_files(env.drivers_sources,"*.cpp")
 
 Export('env')

+ 8 - 0
drivers/unix/os_unix.cpp

@@ -477,6 +477,14 @@ String OS_Unix::get_data_dir() const {
 
 }
 
+String OS_Unix::get_installed_templates_path() const {
+	String p=get_global_settings_path();
+	if (p!="")
+		return p+"/templates/";
+	else
+		return "";
+}
+
 String OS_Unix::get_executable_path() const {
 
 #ifdef __linux__

+ 3 - 0
drivers/unix/os_unix.h

@@ -64,6 +64,8 @@ protected:
 	
 	String stdin_buf;
 
+	String get_global_settings_path() const;
+
 public:
 
 
@@ -111,6 +113,7 @@ public:
 
 	virtual void debug_break();
 
+	virtual String get_installed_templates_path() const;
 	virtual String get_executable_path() const;
 	virtual String get_data_dir() const;
 

+ 0 - 6
modules/gdscript/gd_tokenizer.cpp

@@ -774,20 +774,15 @@ void GDTokenizerText::_advance() {
 							{Variant::INT,"int"},
 							{Variant::REAL,"float"},
 							{Variant::STRING,"String"},
-							{Variant::VECTOR2,"vec2"},
 							{Variant::VECTOR2,"Vector2"},
 							{Variant::RECT2,"Rect2"},
 							{Variant::MATRIX32,"Matrix32"},
-							{Variant::MATRIX32,"mat32"},
-							{Variant::VECTOR3,"vec3"},
 							{Variant::VECTOR3,"Vector3"},
 							{Variant::_AABB,"AABB"},
 							{Variant::_AABB,"Rect3"},
 							{Variant::PLANE,"Plane"},
 							{Variant::QUAT,"Quat"},
-							{Variant::MATRIX3,"mat3"},
 							{Variant::MATRIX3,"Matrix3"},
-							{Variant::TRANSFORM,"trn"},
 							{Variant::TRANSFORM,"Transform"},
 							{Variant::COLOR,"Color"},
 							{Variant::IMAGE,"Image"},
@@ -795,7 +790,6 @@ void GDTokenizerText::_advance() {
 							{Variant::OBJECT,"Object"},
 							{Variant::INPUT_EVENT,"InputEvent"},
 							{Variant::NODE_PATH,"NodePath"},
-							{Variant::DICTIONARY,"dict"},
 							{Variant::DICTIONARY,"Dictionary"},
 							{Variant::ARRAY,"Array"},
 							{Variant::RAW_ARRAY,"RawArray"},

+ 16 - 13
platform/android/export/export.cpp

@@ -1020,18 +1020,24 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 
 	EditorProgress ep("export","Exporting for Android",104);
 
-	String apk_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	if (p_debug) {
-
-		src_apk=custom_debug_package!=""?custom_debug_package:apk_path+"android_debug.apk";
-	} else {
-
-		src_apk=custom_release_package!=""?custom_release_package:apk_path+"android_release.apk";
+	if (p_debug)
+		src_apk=custom_debug_package;
+	else
+		src_apk=custom_release_package;
 
+	if (src_apk=="") {
+		String err;
+		if (p_debug) {
+			src_apk=find_export_template("android_debug.apk", &err);
+		} else {
+			src_apk=find_export_template("android_release.apk", &err);
+		}
+		if (src_apk=="") {
+			EditorNode::add_io_error(err);
+			return ERR_FILE_NOT_FOUND;
+		}
 	}
 
-
 	FileAccess *src_f=NULL;
 	zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
 
@@ -1659,10 +1665,7 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const {
 		err+="Debug Keystore not configured in editor settings.\n";
 	}
 
-
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	if (!FileAccess::exists(exe_path+"android_debug.apk") || !FileAccess::exists(exe_path+"android_release.apk")) {
+	if (!exists_export_template("android_debug.apk") || !exists_export_template("android_release.apk")) {
 		valid=false;
 		err+="No export templates found.\nDownload and install export templates.\n";
 	}

+ 11 - 7
platform/bb10/export/export.cpp

@@ -275,10 +275,16 @@ Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debu
 
 	EditorProgress ep("export","Exporting for BlackBerry 10",104);
 
-	String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	String src_template=custom_package!=""?custom_package:template_path.plus_file("bb10.zip");
-
+	String src_template=custom_package;
+
+	if (src_template=="") {
+		String err;
+		src_template = find_export_template("bb10.zip", &err);
+		if (src_template=="") {
+			EditorNode::add_io_error(err);
+			return ERR_FILE_NOT_FOUND;
+		}
+	}
 
 	FileAccess *src_f=NULL;
 	zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -733,9 +739,7 @@ bool EditorExportPlatformBB10::can_export(String *r_error) const {
 		err+="Blackberry host tools not configured in editor settings.\n";
 	}
 
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	if (!FileAccess::exists(exe_path+"bb10.zip")) {
+	if (!exists_export_template("bb10.zip")) {
 		valid=false;
 		err+="No export template found.\nDownload and install export templates.\n";
 	}

+ 16 - 11
platform/javascript/export/export.cpp

@@ -205,18 +205,24 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool
 
 	EditorProgress ep("export","Exporting for javascript",104);
 
-	String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	if (p_debug) {
-
-		src_template=custom_debug_package!=""?custom_debug_package:template_path+"javascript_debug.zip";
-	} else {
-
-		src_template=custom_release_package!=""?custom_release_package:template_path+"javascript_release.zip";
+	if (p_debug)
+		src_template=custom_debug_package;
+	else
+		src_template=custom_release_package;
 
+	if (src_template=="") {
+		String err;
+		if (p_debug) {
+			src_template=find_export_template("javascript_debug.zip", &err);
+		} else {
+			src_template=find_export_template("javascript_release.zip", &err);
+		}
+		if (src_template=="") {
+			EditorNode::add_io_error(err);
+			return ERR_FILE_NOT_FOUND;
+		}
 	}
 
-
 	FileAccess *src_f=NULL;
 	zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
 
@@ -337,9 +343,8 @@ bool EditorExportPlatformJavaScript::can_export(String *r_error) const {
 
 	bool valid=true;
 	String err;
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
 
-	if (!FileAccess::exists(exe_path+"javascript_debug.zip") || !FileAccess::exists(exe_path+"javascript_release.zip")) {
+	if (!exists_export_template("javascript_debug.zip") || !exists_export_template("javascript_release.zip")) {
 		valid=false;
 		err+="No export templates found.\nDownload and install export templates.\n";
 	}

+ 13 - 10
platform/osx/export/export.cpp

@@ -251,15 +251,19 @@ Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug
 
 	EditorProgress ep("export","Exporting for OSX",104);
 
-	String pkg_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/osx.zip";
-
-	if (p_debug) {
-
-		src_pkg=custom_debug_package!=""?custom_debug_package:pkg_path;
-	} else {
-
-		src_pkg=custom_release_package!=""?custom_release_package:pkg_path;
 
+	if (p_debug)
+		src_pkg=custom_debug_package;
+	else
+		src_pkg=custom_release_package;
+
+	if (src_pkg=="") {
+		String err;
+		src_pkg=find_export_template("osx.zip", &err);
+		if (src_pkg=="") {
+			EditorNode::add_io_error(err);
+			return ERR_FILE_NOT_FOUND;
+		}
 	}
 
 
@@ -464,9 +468,8 @@ bool EditorExportPlatformOSX::can_export(String *r_error) const {
 
 	bool valid=true;
 	String err;
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
 
-	if (!FileAccess::exists(exe_path+"osx.zip")) {
+	if (!exists_export_template("osx.zip")) {
 		valid=false;
 		err+="No export templates found.\nDownload and install export templates.\n";
 	}

+ 5 - 2
platform/x11/detect.py

@@ -1,6 +1,7 @@
 
 import os
 import sys	
+import platform
 
 
 def is_active():
@@ -147,7 +148,9 @@ def configure(env):
 
 	
 	env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
-	env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+	if platform.platform() == 'Linux':
+		env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+		env.Append(LIBS=['asound'])
 
 	if (env["pulseaudio"]=="yes"):
 		if not os.system("pkg-config --exists libpulse-simple"):
@@ -158,7 +161,7 @@ def configure(env):
 			print("PulseAudio development libraries not found, disabling driver")
 
 	env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES_OVER_GL'])
-	env.Append(LIBS=['GL', 'GLU', 'pthread','asound','z']) #TODO detect linux/BSD!
+	env.Append(LIBS=['GL', 'GLU', 'pthread', 'z'])
 	#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
 
 #host compiler is default..

+ 3 - 2
platform/x11/os_x11.cpp

@@ -32,6 +32,7 @@
 #include "key_mapping_x11.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include "print_string.h"
 #include "servers/physics/physics_server_sw.h"
 #include "errno.h"
@@ -1672,7 +1673,7 @@ void OS_X11::close_joystick(int p_id) {
 };
 
 void OS_X11::probe_joystick(int p_id) {
-	#ifndef __FreeBSD__
+	#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 
 	if (p_id == -1) {
 
@@ -1727,7 +1728,7 @@ void OS_X11::move_window_to_foreground() {
 }
 
 void OS_X11::process_joysticks() {
-	#ifndef __FreeBSD__
+	#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 	int bytes;
 	js_event events[32];
 	InputEvent ievent;

+ 1 - 1
platform/x11/platform_config.h

@@ -29,7 +29,7 @@
 #ifdef __linux__
 #include <alloca.h>
 #endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
 #include <stdlib.h>
 #endif
 

+ 10 - 0
scene/2d/canvas_item.cpp

@@ -309,6 +309,15 @@ void CanvasItem::hide() {
 	_change_notify("visibility/visible");
 }
 
+void CanvasItem::set_hidden(bool p_hidden) {
+	
+	if (hidden == p_hidden) {
+		return;
+	}
+	
+	_set_visible_(!p_hidden);
+}
+
 
 Variant CanvasItem::edit_get_state() const {
 
@@ -1043,6 +1052,7 @@ void CanvasItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("is_hidden"),&CanvasItem::is_hidden);
 	ObjectTypeDB::bind_method(_MD("show"),&CanvasItem::show);
 	ObjectTypeDB::bind_method(_MD("hide"),&CanvasItem::hide);
+	ObjectTypeDB::bind_method(_MD("set_hidden","hidden"),&CanvasItem::set_hidden);
 
 	ObjectTypeDB::bind_method(_MD("update"),&CanvasItem::update);
 

+ 1 - 0
scene/2d/canvas_item.h

@@ -190,6 +190,7 @@ public:
 	bool is_hidden() const;
 	void show();
 	void hide();
+	void set_hidden(bool p_hidden);
 
 	void update();
 

+ 4 - 11
scene/3d/physics_body.cpp

@@ -1073,7 +1073,7 @@ Vector3 KinematicBody::move_to(const Vector3& p_position) {
 	return move(p_position-get_global_transform().origin);
 }
 
-bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) {
+bool KinematicBody::can_teleport_to(const Vector3& p_position) {
 
 	ERR_FAIL_COND_V(!is_inside_tree(),false);
 	PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space());
@@ -1089,25 +1089,18 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) {
 	if (collide_character)
 		mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
 
-	Vector3 motion = p_position-get_global_transform().origin;
 	Transform xform=get_global_transform();
-
-	if (true || p_discrete) {
-
-		xform.origin+=motion;
-		motion=Vector3();
-	}
+	xform.origin=p_position;
 
 	Set<RID> exclude;
 	exclude.insert(get_rid());
 
-	//fill exclude list..
 	for(int i=0;i<get_shape_count();i++) {
 
 		if (is_shape_set_as_trigger(i))
 			continue;
 
-		bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask);
+		bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,1,exclude,get_layer_mask(),mask);
 		if (col)
 			return false;
 	}
@@ -1205,7 +1198,7 @@ void KinematicBody::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody::move);
 	ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody::move_to);
 
-	ObjectTypeDB::bind_method(_MD("can_move_to","position"),&KinematicBody::can_move_to);
+	ObjectTypeDB::bind_method(_MD("can_teleport_to","position"),&KinematicBody::can_teleport_to);
 
 	ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody::is_colliding);
 

+ 1 - 1
scene/3d/physics_body.h

@@ -304,7 +304,7 @@ public:
 	Vector3 move(const Vector3& p_motion);
 	Vector3 move_to(const Vector3& p_position);
 
-	bool can_move_to(const Vector3& p_position,bool p_discrete=false);
+	bool can_teleport_to(const Vector3& p_position);
 	bool is_colliding() const;
 	Vector3 get_collision_pos() const;
 	Vector3 get_collision_normal() const;

+ 10 - 0
scene/3d/spatial.cpp

@@ -594,6 +594,15 @@ bool Spatial::is_hidden() const{
 	return !data.visible;
 }
 
+void Spatial::set_hidden(bool p_hidden) {
+	
+	if (data.visible != p_hidden) {
+		return;
+	}
+	
+	_set_visible_(!p_hidden);
+}
+
 void Spatial::_set_visible_(bool p_visible) {
 
 	if (p_visible)
@@ -742,6 +751,7 @@ void Spatial::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide);
 	ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible);
 	ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden);
+	ObjectTypeDB::bind_method(_MD("set_hidden","hidden"), &Spatial::set_hidden);
 
 	ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_);
 	ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_);

+ 1 - 0
scene/3d/spatial.h

@@ -191,6 +191,7 @@ public:
 	void hide();
 	bool is_visible() const;
 	bool is_hidden() const;
+	void set_hidden(bool p_hidden);
 
 #ifdef TOOLS_ENABLED
 	void set_import_transform(const Transform& p_transform)	;

+ 14 - 8
servers/physics/body_sw.cpp

@@ -382,7 +382,7 @@ void BodySW::set_space(SpaceSW *p_space){
 
 }
 
-void BodySW::_compute_area_gravity(const AreaSW *p_area) {
+void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
 
 	if (p_area->is_gravity_point()) {
 		if(p_area->get_gravity_distance_scale() > 0) {
@@ -394,6 +394,9 @@ void BodySW::_compute_area_gravity(const AreaSW *p_area) {
 	} else {
 		gravity += p_area->get_gravity_vector() * p_area->get_gravity();
 	}
+
+	area_linear_damp += p_area->get_linear_damp();
+	area_angular_damp += p_area->get_angular_damp();
 }
 
 void BodySW::integrate_forces(real_t p_step) {
@@ -409,13 +412,15 @@ void BodySW::integrate_forces(real_t p_step) {
 
 	int ac = areas.size();
 	bool replace = false;
-	gravity=Vector3(0,0,0);
+	gravity = Vector3(0,0,0);
+	area_linear_damp = 0;
+	area_angular_damp = 0;
 	if (ac) {
 		areas.sort();
 		const AreaCMP *aa = &areas[0];
 		damp_area = aa[ac-1].area;
 		for(int i=ac-1;i>=0;i--) {
-			_compute_area_gravity(aa[i].area);
+			_compute_area_gravity_and_dampenings(aa[i].area);
 			if (aa[i].area->get_space_override_mode() == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE) {
 				replace = true;
 				break;
@@ -424,20 +429,21 @@ void BodySW::integrate_forces(real_t p_step) {
 	}
 
 	if( !replace ) {
-		_compute_area_gravity(def_area);
+		_compute_area_gravity_and_dampenings(def_area);
 	}
 
 	gravity*=gravity_scale;
 
+	// If less than 0, override dampenings with that of the Body
 	if (angular_damp>=0)
 		area_angular_damp=angular_damp;
-	else
-		area_angular_damp=damp_area->get_angular_damp();
+	//else
+	//	area_angular_damp=damp_area->get_angular_damp();
 
 	if (linear_damp>=0)
 		area_linear_damp=linear_damp;
-	else
-		area_linear_damp=damp_area->get_linear_damp();
+	//else
+	//	area_linear_damp=damp_area->get_linear_damp();
 
 
 	Vector3 motion;

+ 1 - 1
servers/physics/body_sw.h

@@ -130,7 +130,7 @@ class BodySW : public CollisionObjectSW {
 	BodySW *island_next;
 	BodySW *island_list_next;
 
-	_FORCE_INLINE_ void _compute_area_gravity(const AreaSW *p_area);
+	_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const AreaSW *p_area);
 
 	_FORCE_INLINE_ void _update_inertia_tensor();
 

+ 9 - 7
servers/physics/space_sw.cpp

@@ -175,13 +175,15 @@ int PhysicsDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Transfo
 		if (!CollisionSolverSW::solve_static(shape,p_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), NULL,NULL,NULL,p_margin,0))
 			continue;
 
-		r_results[cc].collider_id=col_obj->get_instance_id();
-		if (r_results[cc].collider_id!=0)
-			r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id);
-		else
-			r_results[cc].collider=NULL;
-		r_results[cc].rid=col_obj->get_self();
-		r_results[cc].shape=shape_idx;
+		if (r_results) {
+			r_results[cc].collider_id=col_obj->get_instance_id();
+			if (r_results[cc].collider_id!=0)
+				r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id);
+			else
+				r_results[cc].collider=NULL;
+			r_results[cc].rid=col_obj->get_self();
+			r_results[cc].shape=shape_idx;
+		}
 
 		cc++;
 

+ 15 - 10
servers/physics_2d/body_2d_sw.cpp

@@ -380,7 +380,7 @@ void Body2DSW::set_space(Space2DSW *p_space){
 
 }
 
-void Body2DSW::_compute_area_gravity(const Area2DSW *p_area) {
+void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
 
 	if (p_area->is_gravity_point()) {
 		if(p_area->get_gravity_distance_scale() > 0) {
@@ -393,6 +393,8 @@ void Body2DSW::_compute_area_gravity(const Area2DSW *p_area) {
 		gravity += p_area->get_gravity_vector() * p_area->get_gravity();
 	}
 
+	area_linear_damp += p_area->get_linear_damp();
+	area_angular_damp += p_area->get_angular_damp();
 }
 
 void Body2DSW::integrate_forces(real_t p_step) {
@@ -406,13 +408,15 @@ void Body2DSW::integrate_forces(real_t p_step) {
 
 	int ac = areas.size();
 	bool replace = false;
-	gravity=Vector2(0,0);
+	gravity = Vector2(0,0);
+	area_angular_damp = 0;
+	area_linear_damp = 0;
 	if (ac) {
 		areas.sort();
 		const AreaCMP *aa = &areas[0];
 		damp_area = aa[ac-1].area;
 		for(int i=ac-1;i>=0;i--) {
-			_compute_area_gravity(aa[i].area);
+			_compute_area_gravity_and_dampenings(aa[i].area);
 			if (aa[i].area->get_space_override_mode() == Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE) {
 				replace = true;
 				break;
@@ -420,19 +424,20 @@ void Body2DSW::integrate_forces(real_t p_step) {
 		}
 	}
 	if( !replace ) {
-		_compute_area_gravity(def_area);
+		_compute_area_gravity_and_dampenings(def_area);
 	}
 	gravity*=gravity_scale;
 
+	// If less than 0, override dampenings with that of the Body2D
 	if (angular_damp>=0)
-		area_angular_damp=angular_damp;
-	else
-		area_angular_damp=damp_area->get_angular_damp();
+		area_angular_damp = angular_damp;
+	//else
+	//	area_angular_damp=damp_area->get_angular_damp();
 
 	if (linear_damp>=0)
-		area_linear_damp=linear_damp;
-	else
-		area_linear_damp=damp_area->get_linear_damp();
+		area_linear_damp = linear_damp;
+	//else
+	//	area_linear_damp=damp_area->get_linear_damp();
 
 	Vector2 motion;
 	bool do_motion=false;

+ 1 - 1
servers/physics_2d/body_2d_sw.h

@@ -132,7 +132,7 @@ class Body2DSW : public CollisionObject2DSW {
 	Body2DSW *island_next;
 	Body2DSW *island_list_next;
 
-	_FORCE_INLINE_ void _compute_area_gravity(const Area2DSW *p_area);
+	_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
 
 friend class Physics2DDirectBodyStateSW; // i give up, too many functions to expose
 

+ 11 - 3
servers/visual/shader_language.cpp

@@ -2341,19 +2341,27 @@ Error ShaderLanguage::parse_flow_if(Parser& parser,Node *p_parent,Node **r_state
 
 	parser.advance();
 
+	if (parser.get_token_type()!=TK_CURLY_BRACKET_OPEN) {
+		parser.set_error("Expected statement block after 'if()'");
+		return ERR_PARSE_ERROR;
+	}
+
 	Node *substatement=NULL;
 	err = parse_statement(parser,cf,&substatement);
 	if (err)
 		return err;
 
-
 	cf->statements.push_back(substatement);
 
-
-
 	if (parser.get_token_type()==TK_CF_ELSE) {
 
 		parser.advance();
+
+		if (parser.get_token_type()!=TK_CURLY_BRACKET_OPEN) {
+			parser.set_error("Expected statement block after 'else'");
+			return ERR_PARSE_ERROR;
+		}
+
 		substatement=NULL;
 		err = parse_statement(parser,cf,&substatement);
 		if (err)

+ 60 - 15
tools/editor/editor_import_export.cpp

@@ -399,6 +399,40 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
 
 }
 
+String EditorExportPlatform::find_export_template(String template_file_name, String *err) const {
+	String user_file = EditorSettings::get_singleton()->get_settings_path()
+		+"/templates/"+template_file_name;
+	String system_file=OS::get_singleton()->get_installed_templates_path();
+	bool has_system_path=(system_file!="");
+	system_file+=template_file_name;
+
+	// Prefer user file
+	if (FileAccess::exists(user_file)) {
+		return user_file;
+	}
+
+	// Now check system file
+	if (has_system_path) {
+		if (FileAccess::exists(system_file)) {
+			return system_file;
+		}
+	}
+
+	// Not found
+	if (err) {
+		*err+="No export template found at \""+user_file+"\"";
+		if (has_system_path)
+			*err+="\n or \""+system_file+"\".";
+		else
+			*err+=".";
+	}
+	return "";
+}
+
+bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const {
+	return find_export_template(template_file_name,err)!="";
+}
+
 ///////////////////////////////////////
 
 
@@ -1131,19 +1165,32 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug,
 
 	ep.step("Setting Up..",0);
 
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-	if (use64) {
-		if (p_debug)
-			exe_path=custom_debug_binary!=""?custom_debug_binary:exe_path+debug_binary64;
-		else
-			exe_path=custom_release_binary!=""?custom_release_binary:exe_path+release_binary64;
-	} else {
+	String exe_path="";
 
-		if (p_debug)
-			exe_path=custom_debug_binary!=""?custom_debug_binary:exe_path+debug_binary32;
-		else
-			exe_path=custom_release_binary!=""?custom_release_binary:exe_path+release_binary32;
+	if (p_debug)
+		exe_path=custom_debug_binary;
+	else
+		exe_path=custom_release_binary;
 
+	if (exe_path=="") {
+		String fname;
+		if (use64) {
+			if (p_debug)
+				fname=debug_binary64;
+			else
+				fname=release_binary64;
+		} else {
+			if (p_debug)
+				fname=debug_binary32;
+			else
+				fname=release_binary32;
+		}
+		String err="";
+		exe_path=find_export_template(fname,&err);
+		if (exe_path=="") {
+			EditorNode::add_io_error(err);
+			return ERR_FILE_CANT_READ;
+		}
 	}
 
 	FileAccess *src_exe=FileAccess::open(exe_path,FileAccess::READ);
@@ -1207,14 +1254,12 @@ bool EditorExportPlatformPC::can_export(String *r_error) const {
 	String err;
 	bool valid=true;
 
-	String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
-	if (use64 && (!FileAccess::exists(exe_path+debug_binary64) || !FileAccess::exists(exe_path+release_binary64))) {
+	if (use64 && (!exists_export_template(debug_binary64)) || !exists_export_template(release_binary64)) {
 		valid=false;
 		err="No 64 bits export templates found.\nDownload and install export templates.\n";
 	}
 
-	if (!use64 && (!FileAccess::exists(exe_path+debug_binary32) || !FileAccess::exists(exe_path+release_binary32))) {
+	if (!use64 && (!exists_export_template(debug_binary32) || !exists_export_template(release_binary32))) {
 		valid=false;
 		err="No 32 bits export templates found.\nDownload and install export templates.\n";
 	}

+ 2 - 0
tools/editor/editor_import_export.h

@@ -86,6 +86,8 @@ protected:
 	Vector<uint8_t> get_exported_file_default(String& p_fname) const;
 	virtual Vector<uint8_t> get_exported_file(String& p_fname) const;
 	virtual Vector<StringName> get_dependencies(bool p_bundles) const;
+	virtual String find_export_template(String template_file_name, String *err=NULL) const;
+	virtual bool exists_export_template(String template_file_name, String *err=NULL) const;
 
 	struct TempData {
 

+ 59 - 0
tools/editor/editor_layout_dialog.cpp

@@ -0,0 +1,59 @@
+/*************************************************************************/
+/*  editor_node.cpp                                                      */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "editor_layout_dialog.h"
+#include "object_type_db.h"
+
+void EditorLayoutDialog::clear_layout_name() {
+
+	layout_name->clear();
+}
+
+void EditorLayoutDialog::ok_pressed() {
+
+	if (layout_name->get_text()!="") {
+		emit_signal("layout_selected", layout_name->get_text());
+	}
+}
+
+void EditorLayoutDialog::_bind_methods() {
+
+	ADD_SIGNAL(MethodInfo("layout_selected",PropertyInfo( Variant::STRING,"layout_name")));
+}
+
+EditorLayoutDialog::EditorLayoutDialog()
+{
+
+	layout_name = memnew( LineEdit );
+	layout_name->set_margin(MARGIN_TOP,5);
+	layout_name->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5);
+	layout_name->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5);
+	add_child(layout_name);
+	move_child(layout_name, get_label()->get_index()+1);
+}

+ 53 - 0
tools/editor/editor_layout_dialog.h

@@ -0,0 +1,53 @@
+/*************************************************************************/
+/*  editor_layout_dialog.h                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef EDITOR_LAYOUT_DIALOG_H
+#define EDITOR_LAYOUT_DIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/line_edit.h"
+
+class EditorLayoutDialog : public ConfirmationDialog {
+
+	OBJ_TYPE( EditorLayoutDialog, ConfirmationDialog );
+
+	LineEdit *layout_name;
+
+protected:
+
+	static void _bind_methods();
+	virtual void ok_pressed();
+
+public:
+	void clear_layout_name();
+
+	EditorLayoutDialog();
+};
+
+#endif // EDITOR_LAYOUT_DIALOG_H

+ 190 - 20
tools/editor/editor_node.cpp

@@ -543,7 +543,6 @@ void EditorNode::save_resource_as(const Ref<Resource>& p_resource) {
 }
 
 
-
 void EditorNode::_menu_option(int p_option) {
 	
 	_menu_option_confirm(p_option,false);
@@ -1409,6 +1408,69 @@ void EditorNode::_dialog_action(String p_file) {
 
 			save_resource_in_path(current_res,p_file);
 
+		} break;
+		case SETTINGS_LAYOUT_SAVE: {
+
+			if (p_file.empty())
+				return;
+
+			if (p_file=="Default") {
+				confirm_error->set_text("Cannot overwrite default layout!");
+				confirm_error->popup_centered_minsize();
+				return;
+			}
+
+			Ref<ConfigFile> config;
+			config.instance();
+			Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+			if (err!=OK && err!=ERR_FILE_NOT_FOUND) {
+				return; //no config
+			}
+
+			_save_docks_to_config(config, p_file);
+
+			config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+
+			layout_dialog->hide();
+			_update_layouts_menu();
+
+		} break;
+		case SETTINGS_LAYOUT_DELETE: {
+
+			if (p_file.empty())
+				return;
+
+			if (p_file=="Default") {
+				confirm_error->set_text("Cannot delete default layout!");
+				confirm_error->popup_centered_minsize();
+				return;
+			}
+
+			Ref<ConfigFile> config;
+			config.instance();
+			Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+			if (err!=OK) {
+				return; //no config
+			}
+
+			if (!config->has_section(p_file)) {
+				confirm_error->set_text("Layout name not found!");
+				confirm_error->popup_centered_minsize();
+				return;
+			}
+
+			// erase
+			List<String> keys;
+			config->get_section_keys(p_file, &keys);
+			for (List<String>::Element *E=keys.front();E;E=E->next()) {
+				config->set_value(p_file, E->get(), Variant());
+			}
+
+			config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+
+			layout_dialog->hide();
+			_update_layouts_menu();
+
 		} break;
 		default: { //save scene?
 		
@@ -4033,6 +4095,9 @@ void EditorNode::_bind_methods() {
 	ObjectTypeDB::bind_method("_dock_move_left",&EditorNode::_dock_move_left);
 	ObjectTypeDB::bind_method("_dock_move_right",&EditorNode::_dock_move_right);
 
+	ObjectTypeDB::bind_method("_layout_menu_option",&EditorNode::_layout_menu_option);
+	ObjectTypeDB::bind_method("_layout_dialog_action",&EditorNode::_dialog_action);
+
 	ObjectTypeDB::bind_method("set_current_scene",&EditorNode::set_current_scene);
 	ObjectTypeDB::bind_method("set_current_version",&EditorNode::set_current_version);
 	ObjectTypeDB::bind_method("_scene_tab_changed",&EditorNode::_scene_tab_changed);
@@ -4327,6 +4392,15 @@ void EditorNode::_save_docks() {
 	Ref<ConfigFile> config;
 	config.instance();
 
+	_save_docks_to_config(config, "docks");
+	editor_data.get_plugin_window_layout(config);
+
+	config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
+
+}
+
+void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String& p_section) {
+
 	for(int i=0;i<DOCK_SLOT_MAX;i++) {
 		String names;
 		for(int j=0;j<dock_slot[i]->get_tab_count();j++) {
@@ -4337,7 +4411,7 @@ void EditorNode::_save_docks() {
 		}
 
 		if (names!="") {
-			config->set_value("docks","dock_"+itos(i+1),names);
+			p_layout->set_value(p_section,"dock_"+itos(i+1),names);
 		}
 	}
 
@@ -4351,7 +4425,7 @@ void EditorNode::_save_docks() {
 	for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
 
 		if (splits[i]->is_visible()) {
-			config->set_value("docks","dock_split_"+itos(i+1),splits[i]->get_split_offset());
+			p_layout->set_value(p_section,"dock_split_"+itos(i+1),splits[i]->get_split_offset());
 		}
 	}
 
@@ -4365,13 +4439,9 @@ void EditorNode::_save_docks() {
 
 	for(int i=0;i<4;i++) {
 
-		config->set_value("docks","dock_hsplit_"+itos(i+1),h_splits[i]->get_split_offset());
+		p_layout->set_value(p_section,"dock_hsplit_"+itos(i+1),h_splits[i]->get_split_offset());
 	}
 
-	editor_data.get_plugin_window_layout(config);
-
-	config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
-
 }
 
 void EditorNode::save_layout() {
@@ -4393,12 +4463,19 @@ void EditorNode::_load_docks() {
 		return; //no config
 	}
 
+	_load_docks_from_config(config, "docks");
+	editor_data.set_plugin_window_layout(config);
+
+}
+
+void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String& p_section) {
+
 	for(int i=0;i<DOCK_SLOT_MAX;i++) {
 
-		if (!config->has_section_key("docks","dock_"+itos(i+1)))
+		if (!p_layout->has_section_key(p_section,"dock_"+itos(i+1)))
 			continue;
 
-		Vector<String> names = String(config->get_value("docks","dock_"+itos(i+1))).split(",");
+		Vector<String> names = String(p_layout->get_value(p_section,"dock_"+itos(i+1))).split(",");
 
 		for(int j=0;j<names.size();j++) {
 
@@ -4418,7 +4495,7 @@ void EditorNode::_load_docks() {
 			if (atidx==-1) //well, it's not anywhere
 				continue;
 
-			if (atidx==j) {
+			if (atidx==i) {
 				node->raise();
 				continue;
 			}
@@ -4433,7 +4510,6 @@ void EditorNode::_load_docks() {
 			dock_slot[i]->add_child(node);
 			dock_slot[i]->show();
 		}
-
 	}
 
 	VSplitContainer*splits[DOCK_SLOT_MAX/2]={
@@ -4445,14 +4521,14 @@ void EditorNode::_load_docks() {
 
 	for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
 
-		if (!config->has_section_key("docks","dock_split_"+itos(i+1)))
+		if (!p_layout->has_section_key(p_section,"dock_split_"+itos(i+1)))
 			continue;
 
-		int ofs = config->get_value("docks","dock_split_"+itos(i+1));
+		int ofs = p_layout->get_value(p_section,"dock_split_"+itos(i+1));
 		splits[i]->set_split_offset(ofs);
 	}
 
-	HSplitContainer *h_splits[4]={
+	HSplitContainer*h_splits[4]={
 		left_l_hsplit,
 		left_r_hsplit,
 		main_hsplit,
@@ -4460,9 +4536,9 @@ void EditorNode::_load_docks() {
 	};
 
 	for(int i=0;i<4;i++) {
-		if (!config->has_section_key("docks","dock_hsplit_"+itos(i+1)))
+		if (!p_layout->has_section_key(p_section,"dock_hsplit_"+itos(i+1)))
 			continue;
-		int ofs = config->get_value("docks","dock_hsplit_"+itos(i+1));
+		int ofs = p_layout->get_value(p_section,"dock_hsplit_"+itos(i+1));
 		h_splits[i]->set_split_offset(ofs);
 	}
 
@@ -4480,8 +4556,78 @@ void EditorNode::_load_docks() {
 			dock_slot[i]->set_current_tab(0);
 		}
 	}
+}
 
-	editor_data.set_plugin_window_layout(config);
+
+void EditorNode::_update_layouts_menu() {
+
+	editor_layouts->clear();
+	editor_layouts->set_size(Vector2());
+	editor_layouts->add_item("Save Layout", SETTINGS_LAYOUT_SAVE);
+	editor_layouts->add_item("Delete Layout", SETTINGS_LAYOUT_DELETE);
+	editor_layouts->add_separator();
+	editor_layouts->add_item("Default", SETTINGS_LAYOUT_DEFAULT);
+
+	Ref<ConfigFile> config;
+	config.instance();
+	Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+	if (err!=OK) {
+		return; //no config
+	}
+
+	List<String> layouts;
+	config.ptr()->get_sections(&layouts);
+
+	for (List<String>::Element *E=layouts.front();E;E=E->next()) {
+
+		String layout=E->get();
+
+		if (layout!="Default")
+			editor_layouts->add_item(layout);
+	}
+
+}
+
+void EditorNode::_layout_menu_option(int p_id) {
+
+	switch (p_id) {
+
+		case SETTINGS_LAYOUT_SAVE: {
+
+			current_option=p_id;
+			layout_dialog->clear_layout_name();
+			layout_dialog->set_title("Save Layout");
+			layout_dialog->get_ok()->set_text("Save");
+			layout_dialog->popup_centered();
+		} break;
+		case SETTINGS_LAYOUT_DELETE: {
+
+			current_option=p_id;
+			layout_dialog->clear_layout_name();
+			layout_dialog->set_title("Delete Layout");
+			layout_dialog->get_ok()->set_text("Delete");
+			layout_dialog->popup_centered();
+		} break;
+		case SETTINGS_LAYOUT_DEFAULT: {
+
+			_load_docks_from_config(default_theme, "docks");
+			_save_docks();
+		} break;
+		default: {
+
+			Ref<ConfigFile> config;
+			config.instance();
+			Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+			if (err!=OK) {
+				return; //no config
+			}
+
+			int idx=editor_layouts->get_item_index(p_id);
+			_load_docks_from_config(config, editor_layouts->get_item_text(idx));
+			_save_docks();
+
+		}
+	}
 
 }
 
@@ -5237,17 +5383,29 @@ EditorNode::EditorNode() {
 	right_menu_hb->add_child( settings_menu );
 	p=settings_menu->get_popup();
 
-
 	//p->add_item("Export Settings",SETTINGS_EXPORT_PREFERENCES);
 	p->add_item("Editor Settings",SETTINGS_PREFERENCES);
 	//p->add_item("Optimization Presets",SETTINGS_OPTIMIZED_PRESETS);
 	p->add_separator();
+	editor_layouts = memnew( PopupMenu );
+	editor_layouts->set_name("Layouts");
+	p->add_child(editor_layouts);
+	editor_layouts->connect("item_pressed",this,"_layout_menu_option");
+	p->add_submenu_item("Editor Layout", "Layouts");
+	p->add_separator();
 	p->add_check_item("Show Animation",SETTINGS_SHOW_ANIMATION,KEY_MASK_CMD+KEY_N);
 	p->add_separator();
 	p->add_item("Install Export Templates",SETTINGS_LOAD_EXPORT_TEMPLATES);
 	p->add_separator();
 	p->add_item("About",SETTINGS_ABOUT);
 
+	layout_dialog = memnew( EditorLayoutDialog );
+	gui_base->add_child(layout_dialog);
+	layout_dialog->set_hide_on_ok(false);
+	layout_dialog->set_size(Size2(175, 70));
+	confirm_error = memnew( AcceptDialog  );
+	layout_dialog->add_child(confirm_error);
+	layout_dialog->connect("layout_selected", this,"_layout_dialog_action");
 
 	sources_button = memnew( ToolButton );
 	right_menu_hb->add_child(sources_button);
@@ -5434,7 +5592,19 @@ EditorNode::EditorNode() {
 	scenes_dock->connect("open",this,"open_request");
 	scenes_dock->connect("instance",this,"_instance_request");
 
+	const String docks_section = "docks";
+
+	default_theme.instance();
+	default_theme->set_value(docks_section, "dock_3", "Scene");
+	default_theme->set_value(docks_section, "dock_4", "FileSystem");
+	default_theme->set_value(docks_section, "dock_5", "Inspector");
+
+	for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+		default_theme->set_value(docks_section, "dock_hsplit_"+itos(i+1), 0);
+	for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+		default_theme->set_value(docks_section, "dock_split_"+itos(i+1), 0);
 
+	_update_layouts_menu();
 
 	log = memnew( EditorLog );
 	center_split->add_child(log);
@@ -5743,7 +5913,7 @@ EditorNode::EditorNode() {
 	resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin )));
 
 	circle_step_msec=OS::get_singleton()->get_ticks_msec();
-	circle_step_frame=OS::get_singleton()->get_frames_drawn();;
+	circle_step_frame=OS::get_singleton()->get_frames_drawn();
 	circle_step=0;
 
 	_rebuild_import_menu();

+ 15 - 1
tools/editor/editor_node.h

@@ -76,6 +76,7 @@
 #include "editor_reimport_dialog.h"
 #include "import_settings.h"
 #include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_layout_dialog.h"
 
 #include "fileserver/editor_file_server.h"
 #include "editor_resource_preview.h"
@@ -167,6 +168,9 @@ class EditorNode : public Node {
 		SETTINGS_EXPORT_PREFERENCES,
 		SETTINGS_PREFERENCES,
 		SETTINGS_OPTIMIZED_PRESETS,
+		SETTINGS_LAYOUT_SAVE,
+		SETTINGS_LAYOUT_DELETE,
+		SETTINGS_LAYOUT_DEFAULT,
 		SETTINGS_SHOW_ANIMATION,
 		SETTINGS_LOAD_EXPORT_TEMPLATES,
 		SETTINGS_HELP,
@@ -284,6 +288,11 @@ class EditorNode : public Node {
 	AcceptDialog *about;
 	AcceptDialog *warning;
 
+	Ref<ConfigFile> default_theme;
+	PopupMenu *editor_layouts;
+	EditorLayoutDialog *layout_dialog;
+	AcceptDialog *confirm_error;
+
 	//OptimizedPresetsDialog *optimized_presets;
 	EditorSettingsDialog *settings_config_dialog;
 	RunSettingsDialog *run_settings_dialog;
@@ -523,13 +532,18 @@ class EditorNode : public Node {
 
 	void _save_docks();
 	void _load_docks();
+	void _save_docks_to_config(Ref<ConfigFile> p_layout, const String& p_section);
+	void _load_docks_from_config(Ref<ConfigFile> p_layout, const String& p_section);
+
+	void _update_layouts_menu();
+	void _layout_menu_option(int p_idx);
 
 	void _toggle_search_bar(bool p_pressed);
 	void _clear_search_box();
 
 protected:
 	void _notification(int p_what);
-	static void _bind_methods();		
+	static void _bind_methods();
 public:
 
 	enum EditorTable {

+ 1 - 0
tools/editor/editor_settings.h

@@ -107,6 +107,7 @@ public:
 	static EditorSettings *get_singleton();
 	void erase(String p_var);
 	String get_settings_path() const;
+	String get_global_settings_path() const;
 	String get_project_settings_path() const;
 
 	const Map<String,Plugin>& get_plugins() const { return plugins; }

+ 72 - 93
tools/editor/groups_editor.cpp

@@ -27,151 +27,130 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "groups_editor.h"
-#include "scene/gui/box_container.h"
 
+#include "scene/gui/box_container.h"
 #include "scene/gui/label.h"
 
+void GroupsEditor::_add_group(const String& p_group) {
 
-#include "print_string.h"
+	if (!node)
+		return;
 
-void GroupsEditor::_notification(int p_what) {
-	
-	if (p_what==NOTIFICATION_ENTER_TREE) {
-		connect("confirmed", this,"_close");
-	}	
-	if (p_what==NOTIFICATION_EXIT_TREE) {
-		disconnect("confirmed", this,"_close");
-	}
-}
+	String name = group_name->get_text();
+	if (name.strip_edges()=="")
+		return;
 
-void GroupsEditor::_close() {
-	
-	hide();
-	
-}
-void GroupsEditor::_add() {
-	
-	if (!node)
+	if (node->is_in_group(name))
 		return;
-		
-	undo_redo->create_action("Add To Group");
-	undo_redo->add_do_method(node,"add_to_group",group_name->get_text(),true);
-	undo_redo->add_undo_method(node,"remove_from_group",group_name->get_text());
 
+	undo_redo->create_action("Add to Group");
+
+	undo_redo->add_do_method(node,"add_to_group",name,true);
 	undo_redo->add_do_method(this,"update_tree");
+	undo_redo->add_undo_method(node,"remove_from_group",name,get_text());
 	undo_redo->add_undo_method(this,"update_tree");
 
 	undo_redo->commit_action();
 }
 
+void GroupsEditor::_remove_group(Object *p_item, int p_column, int p_id) {
 
-void GroupsEditor::_remove() {
-	
-	if (!tree->get_selected())
-		return;
 	if (!node)
 		return;
 
-	TreeItem *sel = tree->get_selected();
-	if (!sel)
+	TreeItem *ti = p_item->cast_to<TreeItem>();
+	if (!ti)
 		return;
-		
-	node->remove_from_group( sel->get_text(0) );
-	update_tree();
+
+	String name = ti->get_text(0);
+
+	undo_redo->create_action("Remove from Group");
+
+	undo_redo->add_do_method(node,"remove_from_group",name);
+	undo_redo->add_do_method(this,"update_tree");
+	undo_redo->add_undo_method(node,"add_to_group",name,true);
+	undo_redo->add_undo_method(this,"update_tree");
+
+	undo_redo->commit_action();
 }
 
+struct _GroupInfoComparator {
+
+	bool operator()(const Node::GroupInfo& p_a, const Node::GroupInfo& p_b) const {
+		return p_a.name.operator String() < p_b.name.operator String();
+	}
+};
+
 void GroupsEditor::update_tree() {
 
-	
 	tree->clear();
-	
+
 	if (!node)
 		return;
-		
-	List<GroupInfo> groups;
+
+	List<Node::GroupInfo> groups;
 	node->get_groups(&groups);
-	
+	groups.sort_custom<_GroupInfoComparator>();
+
 	TreeItem *root=tree->create_item();
-	
+
 	for(List<GroupInfo>::Element *E=groups.front();E;E=E->next()) {
-	
-		if (!E->get().persistent)
+
+		Node::GroupInfo gi = E->get();
+		if (!gi.persistent)
 			continue;
+
 		TreeItem *item=tree->create_item(root);
-		item->set_text(0, E->get().name);	
-	
+		item->set_text(0, gi.name);
+		item->add_button(0, get_icon("Remove", "EditorIcons"), 0);
 	}
-
 }
 
 void GroupsEditor::set_current(Node* p_node) {
-	
+
 	node=p_node;
 	update_tree();
-
 }
 
 void GroupsEditor::_bind_methods() {
-	
-	ObjectTypeDB::bind_method("_add",&GroupsEditor::_add);
-	ObjectTypeDB::bind_method("_close",&GroupsEditor::_close);
-	ObjectTypeDB::bind_method("_remove",&GroupsEditor::_remove);	
+
+	ObjectTypeDB::bind_method("_add_group",&GroupsEditor::_add_group);
+	ObjectTypeDB::bind_method("_remove_group",&GroupsEditor::_remove_group);
 	ObjectTypeDB::bind_method("update_tree",&GroupsEditor::update_tree);
 }
 
 GroupsEditor::GroupsEditor() {
 
+	node=NULL;
+
 	set_title("Group Editor");
-	
-	Label * label = memnew( Label );
-	label->set_pos( Point2( 8,11) );
-	label->set_text("Groups:");
-	
-	add_child(label);	
-	
-	group_name = memnew(LineEdit);
-	group_name->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	group_name->set_begin( Point2( 15,28) );
-	group_name->set_end( Point2( 94,48 ) );
-	
-	add_child(group_name);
-	
-	tree = memnew( Tree );
-	tree->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	tree->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
-	tree->set_begin( Point2( 15,52) );
-	tree->set_end( Point2( 94,42 ) );
-	tree->set_hide_root(true);		
-	add_child(tree);
-	
+
+	VBoxContainer *vbc = memnew( VBoxContainer );
+	add_child(vbc);
+	set_child_rect(vbc);
+
+	HBoxContainer *hbc = memnew( HBoxContainer );
+	vbc->add_margin_child("Group", hbc);
+
+	group_name = memnew( LineEdit );
+	group_name->set_h_size_flags(SIZE_EXPAND_FILL);
+	hbc->add_child(group_name);
+	group_name->connect("text_entered",this,"_add_group");
+
 	add = memnew( Button );
-	add->set_anchor( MARGIN_LEFT, ANCHOR_END );
-	add->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	add->set_begin( Point2( 90, 28 ) );
-	add->set_end( Point2( 15, 48 ) );	
 	add->set_text("Add");
-	
-	add_child(add);
-	
-	remove = memnew( Button );
-	remove->set_anchor( MARGIN_LEFT, ANCHOR_END );
-	remove->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	remove->set_begin( Point2( 90, 52 ) );
-	remove->set_end( Point2( 15, 72 ) );	
-	remove->set_text("Remove");
-	
-	add_child(remove);
+	hbc->add_child(add);
+	add->connect("pressed", this,"_add_group", varray(String()));
 
-	get_ok()->set_text("Close");
-			
-	add->connect("pressed", this,"_add");
-	remove->connect("pressed", this,"_remove");	
+	tree = memnew( Tree );
+	tree->set_hide_root(true);
+	tree->set_v_size_flags(SIZE_EXPAND_FILL);
+	vbc->add_margin_child("Node Group(s)", tree, true);
+	tree->connect("button_pressed",this,"_remove_group");
 
-	
-	node=NULL;
+	get_ok()->set_text("Close");
 }
 
-
 GroupsEditor::~GroupsEditor()
 {
 }

+ 18 - 18
tools/editor/groups_editor.h

@@ -29,42 +29,42 @@
 #ifndef GROUPS_EDITOR_H
 #define GROUPS_EDITOR_H
 
-
 #include "scene/gui/dialogs.h"
 #include "scene/gui/button.h"
 #include "scene/gui/tree.h"
 #include "scene/gui/line_edit.h"
 #include "undo_redo.h"
+
 /**
 @author Juan Linietsky <[email protected]>
 */
-class GroupsEditor : public ConfirmationDialog {
-	
-	OBJ_TYPE( GroupsEditor, ConfirmationDialog );
-	
+
+class GroupsEditor : public AcceptDialog {
+
+	OBJ_TYPE(GroupsEditor,AcceptDialog);
+
+	Node *node;
+
 	LineEdit *group_name;
-	Tree *tree;
 	Button *add;
-	Button *remove;
-	Node *node;
+	Tree *tree;
+
 	UndoRedo *undo_redo;
-	
+
 	void update_tree();
-	void _add();
-	void _remove();
+	void _add_group(const String& p_group="");
+	void _remove_group(Object *p_item, int p_column, int p_id);
 	void _close();
-	
 protected:
-	
-	void _notification(int p_what);
-	static void _bind_methods();	
+
+	static void _bind_methods();
 public:
-	
+
 	void set_undo_redo(UndoRedo *p_undoredo) { undo_redo=p_undoredo; }
 	void set_current(Node* p_node);
-	
+
 	GroupsEditor();	
 	~GroupsEditor();
-	
 };
+
 #endif

+ 165 - 200
tools/editor/plugins/item_list_editor_plugin.cpp

@@ -30,7 +30,6 @@
 
 #include "io/resource_loader.h"
 
-
 bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
 
 	String name = p_name;
@@ -45,12 +44,10 @@ bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
 		set_item_checkable(idx,p_value);
 	else if (what=="checked")
 		set_item_checked(idx,p_value);
-	else if (what=="enabled")
-		set_item_enabled(idx,p_value);
-	else if (what=="accel")
-		set_item_accel(idx,p_value);
 	else if (what=="id")
 		set_item_id(idx,p_value);
+	else if (what=="enabled")
+		set_item_enabled(idx,p_value);
 	else if (what=="separator")
 		set_item_separator(idx,p_value);
 	else
@@ -60,6 +57,7 @@ bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
 }
 
 bool ItemListPlugin::_get(const StringName& p_name,Variant &r_ret) const {
+
 	String name = p_name;
 	int idx = name.get_slice("/",0).to_int();
 	String what=name.get_slice("/",1);
@@ -72,12 +70,10 @@ bool ItemListPlugin::_get(const StringName& p_name,Variant &r_ret) const {
 		r_ret=is_item_checkable(idx);
 	else if (what=="checked")
 		r_ret=is_item_checked(idx);
-	else if (what=="enabled")
-		r_ret=is_item_enabled(idx);
-	else if (what=="accel")
-		r_ret=get_item_accel(idx);
 	else if (what=="id")
 		r_ret=get_item_id(idx);
+	else if (what=="enabled")
+		r_ret=is_item_enabled(idx);
 	else if (what=="separator")
 		r_ret=is_item_separator(idx);
 	else
@@ -93,66 +89,119 @@ void ItemListPlugin::_get_property_list( List<PropertyInfo> *p_list) const {
 
 		p_list->push_back( PropertyInfo(Variant::STRING,base+"text") );
 		p_list->push_back( PropertyInfo(Variant::OBJECT,base+"icon",PROPERTY_HINT_RESOURCE_TYPE,"Texture") );
-		if (get_flags()&FLAG_CHECKABLE) {
 
+		int flags = get_flags();
+
+		if (flags&FLAG_CHECKABLE) {
 			p_list->push_back( PropertyInfo(Variant::BOOL,base+"checkable") );
 			p_list->push_back( PropertyInfo(Variant::BOOL,base+"checked") );
-
 		}
-		if (get_flags()&FLAG_ENABLE) {
 
+		if (flags&FLAG_ID)
+			p_list->push_back( PropertyInfo(Variant::INT,base+"id",PROPERTY_HINT_RANGE,"-1,4096") );
+
+		if (flags&FLAG_ENABLE)
 			p_list->push_back( PropertyInfo(Variant::BOOL,base+"enabled") );
 
-		}
-		if (get_flags()&FLAG_ACCEL) {
+		if (flags&FLAG_SEPARATOR)
+			p_list->push_back( PropertyInfo(Variant::BOOL,base+"separator") );
+	}
+}
 
-			p_list->push_back( PropertyInfo(Variant::INT,base+"accel",PROPERTY_HINT_KEY_ACCEL) );
+///////////////////////////////////////////////////////////////
+///////////////////////// PLUGINS /////////////////////////////
+///////////////////////////////////////////////////////////////
 
-		}
-		if (get_flags()&FLAG_ID) {
+void ItemListOptionButtonPlugin::set_object(Object *p_object) {
 
-			p_list->push_back( PropertyInfo(Variant::INT,base+"id",PROPERTY_HINT_RANGE,"-1,4096") );
+	ob = p_object->cast_to<OptionButton>();
+}
 
-		}
-		if (get_flags()&FLAG_SEPARATOR) {
+bool ItemListOptionButtonPlugin::handles(Object *p_object) const {
 
-			p_list->push_back( PropertyInfo(Variant::BOOL,base+"separator") );
+	return p_object->is_type("OptionButton"); 
+}
 
-		}
-	}
+int ItemListOptionButtonPlugin::get_flags() const {
+
+	return FLAG_ICON|FLAG_ID|FLAG_ENABLE;
 }
 
-void ItemListEditor::_node_removed(Node *p_node) {
+void ItemListOptionButtonPlugin::add_item() {
 
-	if(p_node==item_list) {
-		item_list=NULL;
-		hide();
-		dialog->hide();
-	}
+	ob->add_item( "Item "+itos(ob->get_item_count()));
+	_change_notify(); 
+}
 
+int ItemListOptionButtonPlugin::get_item_count() const {
 
+	return ob->get_item_count(); 
 }
 
-void ItemListEditor::_delete_pressed() {
+void ItemListOptionButtonPlugin::erase(int p_idx) {
 
-	String p = prop_editor->get_selected_path();
+	ob->remove_item(p_idx); 
+	_change_notify();
+}
 
-	if (p.find("/")!=-1) {
+ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
 
-		if (selected_idx<0 || selected_idx>=item_plugins.size())
-			return;
+	ob=NULL; 
+}
 
-		item_plugins[selected_idx]->erase(p.get_slice("/",0).to_int());;
-	}
+///////////////////////////////////////////////////////////////
+
+void ItemListPopupMenuPlugin::set_object(Object *p_object) {
 
+	if (p_object->is_type("MenuButton"))
+		pp = p_object->cast_to<MenuButton>()->get_popup();
+	else
+		pp = p_object->cast_to<PopupMenu>();
 }
 
-void ItemListEditor::_add_pressed() {
+bool ItemListPopupMenuPlugin::handles(Object *p_object) const {
 
-	if (selected_idx<0 || selected_idx>=item_plugins.size())
-		return;
+	return p_object->is_type("PopupMenu") || p_object->is_type("MenuButton");
+}
 
-	item_plugins[selected_idx]->add_item();
+int ItemListPopupMenuPlugin::get_flags() const {
+
+	return FLAG_ICON|FLAG_CHECKABLE|FLAG_ID|FLAG_ENABLE|FLAG_SEPARATOR;
+}
+
+void ItemListPopupMenuPlugin::add_item() {
+
+	pp->add_item( "Item "+itos(pp->get_item_count()));
+	_change_notify();
+}
+
+int ItemListPopupMenuPlugin::get_item_count() const {
+
+	return pp->get_item_count();
+}
+
+void ItemListPopupMenuPlugin::erase(int p_idx) {
+
+	pp->remove_item(p_idx);
+	_change_notify();
+}
+
+ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
+
+	pp=NULL;
+}
+
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+
+void ItemListEditor::_node_removed(Node *p_node) {
+
+	if(p_node==item_list) {
+		item_list=NULL;
+		hide();
+		dialog->hide();
+	}
 }
 
 void ItemListEditor::_notification(int p_notification) {
@@ -160,57 +209,73 @@ void ItemListEditor::_notification(int p_notification) {
 	if (p_notification==NOTIFICATION_ENTER_TREE) {
 
 		add_button->set_icon(get_icon("Add","EditorIcons"));
-		del_button->set_icon(get_icon("Del","EditorIcons"));
+		del_button->set_icon(get_icon("Remove","EditorIcons"));
 	}
 }
 
+void ItemListEditor::_add_pressed() {
 
-void ItemListEditor::_menu_option(int p_option) {
+	if (selected_idx==-1)
+		return;
 
+	item_plugins[selected_idx]->add_item();
+}
 
-	switch(p_option) {
+void ItemListEditor::_delete_pressed() {
 
-		case MENU_EDIT_ITEMS: {
+	TreeItem *ti = tree->get_selected();
 
-			dialog->popup_centered_ratio();
-		} break;
-	}
+	if (!ti)
+		return;
+
+	if (ti->get_parent()!=tree->get_root())
+		return;
+
+	int idx = ti->get_text(0).to_int();
+
+	if (selected_idx==-1)
+		return;
+
+	item_plugins[selected_idx]->erase(idx);
 }
 
+void ItemListEditor::_edit_items() {
+
+	dialog->popup_centered(Vector2(300, 400));
+}
 
 void ItemListEditor::edit(Node *p_item_list) {
 
 	item_list=p_item_list;
 
+	if (!item_list) {
+		selected_idx=-1;
+		property_editor->edit(NULL);
+		return;
+	}
+
 	for(int i=0;i<item_plugins.size();i++) {
 		if (item_plugins[i]->handles(p_item_list)) {
 
 			item_plugins[i]->set_object(p_item_list);
-			prop_editor->edit(item_plugins[i]);
+			property_editor->edit(item_plugins[i]);
+			
+			if (has_icon(item_list->get_type(), "EditorIcons"))
+				toolbar_button->set_icon(get_icon(item_list->get_type(), "EditorIcons"));
+			else
+				toolbar_button->set_icon(Ref<Texture>());
+
 			selected_idx=i;
 			return;
 		}
 	}
 
 	selected_idx=-1;
-
-	prop_editor->edit(NULL);
-
-}
-
-
-void ItemListEditor::_bind_methods() {
-
-	ObjectTypeDB::bind_method("_menu_option",&ItemListEditor::_menu_option);
-	ObjectTypeDB::bind_method("_add_button",&ItemListEditor::_add_pressed);
-	ObjectTypeDB::bind_method("_delete_button",&ItemListEditor::_delete_pressed);
-
-	//ObjectTypeDB::bind_method("_populate",&ItemListEditor::_populate);
-
+	property_editor->edit(NULL);
 }
 
 bool ItemListEditor::handles(Object *p_object) const {
-	return false;
+
 	for(int i=0;i<item_plugins.size();i++)  {
 		if (item_plugins[i]->handles(p_object)) {
 			return true;
@@ -218,57 +283,65 @@ bool ItemListEditor::handles(Object *p_object) const {
 	}
 
 	return false;
+}
 
+void ItemListEditor::_bind_methods() {
+
+	ObjectTypeDB::bind_method("_edit_items",&ItemListEditor::_edit_items);
+	ObjectTypeDB::bind_method("_add_button",&ItemListEditor::_add_pressed);
+	ObjectTypeDB::bind_method("_delete_button",&ItemListEditor::_delete_pressed);
 }
+
 ItemListEditor::ItemListEditor() {
 
 	selected_idx=-1;
-	options = memnew( MenuButton );
-	add_child(options);
-	options->set_area_as_parent_rect();
 
-	options->set_text("Items");
-	options->get_popup()->add_item("Edit Items",MENU_EDIT_ITEMS);
-	//options->get_popup()->add_item("Clear",MENU_CLEAR);
+	add_child( memnew( VSeparator ) );
 
-	options->get_popup()->connect("item_pressed", this,"_menu_option");
+	toolbar_button = memnew( ToolButton );
+	toolbar_button->set_text("Items");
+	add_child(toolbar_button);
+	toolbar_button->connect("pressed",this,"_edit_items");
 
 	dialog = memnew( AcceptDialog );
+	dialog->set_title("Item List Editor");
 	add_child( dialog );
 
-
+	VBoxContainer *vbc = memnew( VBoxContainer );
+	dialog->add_child(vbc);
+	dialog->set_child_rect(vbc);
 
 	HBoxContainer *hbc = memnew( HBoxContainer );
-
-	dialog->add_child(hbc);
-	dialog->set_child_rect(hbc);
-
-	prop_editor = memnew( PropertyEditor );
-
-	hbc->add_child(prop_editor);
-	prop_editor->set_h_size_flags(SIZE_EXPAND_FILL);
-
-	VBoxContainer *vbc = memnew( VBoxContainer );
-	hbc->add_child(vbc);
+	hbc->set_h_size_flags(SIZE_EXPAND_FILL);
+	vbc->add_child(hbc);
 
 	add_button = memnew( Button );
-	//add_button->set_text("Add");
+	add_button->set_text("Add");
+	hbc->add_child(add_button);
 	add_button->connect("pressed",this,"_add_button");
-	vbc->add_child(add_button);
+
+	hbc->add_spacer();
 
 	del_button = memnew( Button );
-	//del_button->set_text("Del");
+	del_button->set_text("Delete");
+	hbc->add_child(del_button);
 	del_button->connect("pressed",this,"_delete_button");
-	vbc->add_child(del_button);
 
-	dialog->set_title("Item List");
-	prop_editor->hide_top_label();
+	property_editor = memnew( PropertyEditor );
+	property_editor->hide_top_label();
+	property_editor->set_subsection_selectable(true);
+	vbc->add_child(property_editor);
+	property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
 
+	tree = property_editor->get_scene_tree();
+}
 
+ItemListEditor::~ItemListEditor() {
 
+	for(int i=0;i<item_plugins.size();i++)
+		memdelete( item_plugins[i] );
 }
 
-
 void ItemListEditorPlugin::edit(Object *p_object) {
 
 	item_list_editor->edit(p_object->cast_to<Node>());
@@ -288,127 +361,19 @@ void ItemListEditorPlugin::make_visible(bool p_visible) {
 		item_list_editor->hide();
 		item_list_editor->edit(NULL);
 	}
-
-}
-
-
-ItemListEditor::~ItemListEditor() {
-
-	for(int i=0;i<item_plugins.size();i++)
-		memdelete( item_plugins[i] );
 }
 
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-
-
-class ItemListOptionButtonPlugin : public ItemListPlugin {
-
-	OBJ_TYPE(ItemListOptionButtonPlugin,ItemListPlugin);
-
-	OptionButton *ob;
-public:
-
-	virtual void set_object(Object *p_object) { ob = p_object->cast_to<OptionButton>(); }
-
-	virtual bool handles(Object *p_object) const { return p_object->cast_to<OptionButton>()!=NULL; }
-
-	virtual int get_flags() const { return FLAG_ICON|FLAG_ID|FLAG_ENABLE; }
-
-	virtual void set_item_text(int p_idx,const String& p_text){ ob->set_item_text(p_idx,p_text);}
-	virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){ ob->set_item_icon(p_idx,p_tex);}
-	virtual void set_item_enabled(int p_idx,int p_enabled){ ob->set_item_disabled(p_idx,!p_enabled);}
-	virtual void set_item_id(int p_idx,int p_id){ ob->set_item_ID(p_idx,p_id);}
-
-
-	virtual String get_item_text(int p_idx) const{ return ob->get_item_text(p_idx); };
-	virtual Ref<Texture> get_item_icon(int p_idx) const{ return ob->get_item_icon(p_idx); };
-	virtual bool is_item_enabled(int p_idx) const{ return !ob->is_item_disabled(p_idx); };
-	virtual int get_item_id(int p_idx) const{ return ob->get_item_ID(p_idx); };
-
-	virtual void add_item() { ob->add_item( "New Item "+itos(ob->get_item_count())); _change_notify();}
-	virtual int get_item_count() const { return ob->get_item_count(); }
-	virtual void erase(int p_idx) { ob->remove_item(p_idx); _change_notify();}
-
-
-	ItemListOptionButtonPlugin() { ob=NULL; }
-};
-
-class ItemListPopupMenuPlugin : public ItemListPlugin {
-
-	OBJ_TYPE(ItemListPopupMenuPlugin,ItemListPlugin);
-
-	PopupMenu *pp;
-public:
-
-	virtual void set_object(Object *p_object) {
-		if (p_object->cast_to<MenuButton>())
-			pp = p_object->cast_to<MenuButton>()->get_popup();
-		else
-			pp = p_object->cast_to<PopupMenu>();
-	}
-
-	virtual bool handles(Object *p_object) const { return p_object->cast_to<PopupMenu>()!=NULL || p_object->cast_to<MenuButton>()!=NULL; }
-
-	virtual int get_flags() const { return FLAG_ICON|FLAG_ID|FLAG_ENABLE|FLAG_CHECKABLE|FLAG_SEPARATOR|FLAG_ACCEL; }
-
-	virtual void set_item_text(int p_idx,const String& p_text){ pp->set_item_text(p_idx,p_text); }
-	virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){ pp->set_item_icon(p_idx,p_tex);}
-	virtual void set_item_checkable(int p_idx,bool p_check){ pp->set_item_as_checkable(p_idx,p_check);}
-	virtual void set_item_checked(int p_idx,bool p_checked){ pp->set_item_checked(p_idx,p_checked);}
-	virtual void set_item_accel(int p_idx,int p_accel){ pp->set_item_accelerator(p_idx,p_accel);}
-	virtual void set_item_enabled(int p_idx,int p_enabled){ pp->set_item_disabled(p_idx,!p_enabled);}
-	virtual void set_item_id(int p_idx,int p_id){ pp->set_item_ID(p_idx,p_idx);}
-	virtual void set_item_separator(int p_idx,bool p_separator){ pp->set_item_as_separator(p_idx,p_separator);}
-
-
-	virtual String get_item_text(int p_idx) const{ return pp->get_item_text(p_idx); };
-	virtual Ref<Texture> get_item_icon(int p_idx) const{ return pp->get_item_icon(p_idx); };
-	virtual bool is_item_checkable(int p_idx) const{ return pp->is_item_checkable(p_idx);  };
-	virtual bool is_item_checked(int p_idx) const{ return pp->is_item_checked(p_idx); };
-	virtual int get_item_accel(int p_idx) const{ return pp->get_item_accelerator(p_idx); };
-	virtual bool is_item_enabled(int p_idx) const{ return !pp->is_item_disabled(p_idx);  };
-	virtual int get_item_id(int p_idx) const{ return pp->get_item_ID(p_idx);  };
-	virtual bool is_item_separator(int p_idx) const{ return pp->is_item_separator(p_idx); };
-
-
-
-	virtual void add_item() { pp->add_item( "New Item "+itos(pp->get_item_count())); _change_notify();}
-	virtual int get_item_count() const { return pp->get_item_count(); }
-	virtual void erase(int p_idx) { pp->remove_item(p_idx); _change_notify();}
-
-
-	ItemListPopupMenuPlugin() { pp=NULL; }
-};
-
-
-
-
-
-
 ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) {
 
 	editor=p_node;
 	item_list_editor = memnew( ItemListEditor );
-	editor->get_viewport()->add_child(item_list_editor);
-
-//	item_list_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
-//	item_list_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
-	item_list_editor->set_margin(MARGIN_LEFT,180);
-	item_list_editor->set_margin(MARGIN_RIGHT,230);
-	item_list_editor->set_margin(MARGIN_TOP,0);
-	item_list_editor->set_margin(MARGIN_BOTTOM,10);
-
+	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(item_list_editor);
 
 	item_list_editor->hide();
-	item_list_editor->add_plugin( memnew( ItemListOptionButtonPlugin) );
-	item_list_editor->add_plugin( memnew( ItemListPopupMenuPlugin) );
+	item_list_editor->add_plugin( memnew( ItemListOptionButtonPlugin ) );
+	item_list_editor->add_plugin( memnew( ItemListPopupMenuPlugin ) );
 }
 
-
 ItemListEditorPlugin::~ItemListEditorPlugin()
 {
 }

+ 102 - 36
tools/editor/plugins/item_list_editor_plugin.h

@@ -31,10 +31,11 @@
 
 #include "tools/editor/editor_plugin.h"
 #include "tools/editor/editor_node.h"
+#include "canvas_item_editor_plugin.h"
+
 #include "scene/gui/option_button.h"
 #include "scene/gui/menu_button.h"
 #include "scene/gui/popup_menu.h"
-#include "scene/gui/spin_box.h"
 
 /**
 	@author Juan Linietsky <[email protected]>
@@ -51,43 +52,42 @@ protected:
 	bool _get(const StringName& p_name,Variant &r_ret) const;
 	void _get_property_list( List<PropertyInfo> *p_list) const;
 
-
 public:
 
 	enum Flags {
 
 		FLAG_ICON=1,
 		FLAG_CHECKABLE=2,
-		FLAG_ACCEL=4,
-		FLAG_ID=8,
-		FLAG_ENABLE=16,
-		FLAG_SEPARATOR=32
+		FLAG_ID=4,
+		FLAG_ENABLE=8,
+		FLAG_SEPARATOR=16
 	};
 
 	virtual void set_object(Object *p_object)=0;
-
 	virtual bool handles(Object *p_object) const=0;
 
 	virtual int get_flags() const=0;
 
-	virtual void set_item_text(int p_idx,const String& p_text){}
-	virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){}
-	virtual void set_item_checkable(int p_idx,bool p_check){}
-	virtual void set_item_checked(int p_idx,bool p_checked){}
-	virtual void set_item_accel(int p_idx,int p_accel){}
-	virtual void set_item_enabled(int p_idx,int p_enabled){}
-	virtual void set_item_id(int p_idx,int p_id){}
-	virtual void set_item_separator(int p_idx,bool p_separator){}
-
-
+	virtual void set_item_text(int p_idx, const String& p_text) {}
 	virtual String get_item_text(int p_idx) const{ return ""; };
+
+	virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) {}
 	virtual Ref<Texture> get_item_icon(int p_idx) const{ return Ref<Texture>(); };
+
+	virtual void set_item_checkable(int p_idx, bool p_check) {}
 	virtual bool is_item_checkable(int p_idx) const{ return false; };
+
+	virtual void set_item_checked(int p_idx, bool p_checked) {}
 	virtual bool is_item_checked(int p_idx) const{ return false; };
-	virtual int get_item_accel(int p_idx) const{ return 0; };
+
+	virtual void set_item_enabled(int p_idx, int p_enabled) {}
 	virtual bool is_item_enabled(int p_idx) const{ return false; };
+
+	virtual void set_item_id(int p_idx, int p_id) {}
 	virtual int get_item_id(int p_idx) const{ return -1; };
-	virtual bool is_item_separator(int p_idx) const{ return false; };
+
+	virtual void set_item_separator(int p_idx, bool p_separator) {}
+	virtual bool is_item_separator(int p_idx) const { return false; };
 
 	virtual void add_item()=0;
 	virtual int get_item_count() const=0;
@@ -96,41 +96,107 @@ public:
 	ItemListPlugin() {}
 };
 
-class ItemListEditor : public Control {
+///////////////////////////////////////////////////////////////
 
-	OBJ_TYPE(ItemListEditor, Control );
+class ItemListOptionButtonPlugin : public ItemListPlugin {
 
-	Node *item_list;
+	OBJ_TYPE(ItemListOptionButtonPlugin,ItemListPlugin);
 
-	enum {
+	OptionButton *ob;
+public:
 
-		MENU_EDIT_ITEMS,
-		MENU_CLEAR
-	};
+	virtual void set_object(Object *p_object);
+	virtual bool handles(Object *p_object) const;
+	virtual int get_flags() const;
 
-	AcceptDialog *dialog;
+	virtual void set_item_text(int p_idx, const String& p_text) { ob->set_item_text(p_idx,p_text); }
+	virtual String get_item_text(int p_idx) const { return ob->get_item_text(p_idx); }
 
-	PropertyEditor *prop_editor;
+	virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) { ob->set_item_icon(p_idx, p_tex); }
+	virtual Ref<Texture> get_item_icon(int p_idx) const { return ob->get_item_icon(p_idx); }
 
-	MenuButton * options;
-	int selected_idx;
+	virtual void set_item_enabled(int p_idx, int p_enabled) { ob->set_item_disabled(p_idx, !p_enabled); }
+	virtual bool is_item_enabled(int p_idx) const { return !ob->is_item_disabled(p_idx); }
+
+	virtual void set_item_id(int p_idx, int p_id) { ob->set_item_ID(p_idx,p_id); }
+	virtual int get_item_id(int p_idx) const { return ob->get_item_ID(p_idx); }
+
+	virtual void add_item();
+	virtual int get_item_count() const;
+	virtual void erase(int p_idx);
+
+	ItemListOptionButtonPlugin();
+};
+
+class ItemListPopupMenuPlugin : public ItemListPlugin {
+
+	OBJ_TYPE(ItemListPopupMenuPlugin,ItemListPlugin);
+
+	PopupMenu *pp;
+public:
+
+	virtual void set_object(Object *p_object);
+	virtual bool handles(Object *p_object) const;
+	virtual int get_flags() const;
 
+	virtual void set_item_text(int p_idx, const String& p_text) { pp->set_item_text(p_idx,p_text); }
+	virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); }
+
+	virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) { pp->set_item_icon(p_idx,p_tex); }
+	virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); }
+
+	virtual void set_item_checkable(int p_idx, bool p_check) { pp->set_item_as_checkable(p_idx,p_check); }
+	virtual bool is_item_checkable(int p_idx) const { return pp->is_item_checkable(p_idx); }
+
+	virtual void set_item_checked(int p_idx, bool p_checked) { pp->set_item_checked(p_idx,p_checked); }
+	virtual bool is_item_checked(int p_idx) const { return pp->is_item_checked(p_idx); }
+
+	virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx,!p_enabled); }
+	virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); }
+
+	virtual void set_item_id(int p_idx, int p_id) { pp->set_item_ID(p_idx,p_idx); }
+	virtual int get_item_id(int p_idx) const { return pp->get_item_ID(p_idx); }
+
+	virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx,p_separator); }
+	virtual bool is_item_separator(int p_idx) const { return pp->is_item_separator(p_idx); }
+
+	virtual void add_item();
+	virtual int get_item_count() const;
+	virtual void erase(int p_idx);
+
+	ItemListPopupMenuPlugin();
+};
+
+///////////////////////////////////////////////////////////////
+
+class ItemListEditor : public HBoxContainer {
+
+	OBJ_TYPE(ItemListEditor,HBoxContainer);
+
+	Node *item_list;
+
+	ToolButton *toolbar_button;
+
+	AcceptDialog *dialog;
+	PropertyEditor *property_editor;
+	Tree *tree;
 	Button *add_button;
 	Button *del_button;
 
-
-//	FileDialog *emission_file_dialog;
-	void _menu_option(int);
+	int selected_idx;
 
 	Vector<ItemListPlugin*> item_plugins;
 
-	void _node_removed(Node *p_node);
+	void _edit_items();
+
 	void _add_pressed();
 	void _delete_pressed();
+
+	void _node_removed(Node *p_node);
+
 protected:
 
 	void _notification(int p_notification);
-
 	static void _bind_methods();
 public:
 
@@ -143,7 +209,7 @@ public:
 
 class ItemListEditorPlugin : public EditorPlugin {
 
-	OBJ_TYPE( ItemListEditorPlugin, EditorPlugin );
+	OBJ_TYPE(ItemListEditorPlugin,EditorPlugin);
 
 	ItemListEditor *item_list_editor;
 	EditorNode *editor;

+ 11 - 3
tools/editor/property_editor.cpp

@@ -2207,9 +2207,9 @@ TreeItem *PropertyEditor::get_parent_node(String p_path,HashMap<String,TreeItem*
 		}
 
 		item->set_editable(0,false);
-		item->set_selectable(0,false);
+		item->set_selectable(0,subsection_selectable);
 		item->set_editable(1,false);
-		item->set_selectable(1,false);
+		item->set_selectable(1,subsection_selectable);
 
 		if (item->get_parent()==root) {
 
@@ -3511,7 +3511,15 @@ void PropertyEditor::register_text_enter(Node* p_line_edit) {
 
 	if (search_box)
 		search_box->connect("text_changed",this,"_filter_changed");
+}
 
+void PropertyEditor::set_subsection_selectable(bool p_selectable) {
+
+	if (p_selectable==subsection_selectable)
+		return;
+
+	subsection_selectable=p_selectable;
+	update_tree();
 }
 
 PropertyEditor::PropertyEditor() {
@@ -3573,8 +3581,8 @@ PropertyEditor::PropertyEditor() {
 	show_categories=false;
 	refresh_countdown=0;
 	use_doc_hints=false;
-
 	use_filter=false;
+	subsection_selectable=false;
 
 }
 

+ 3 - 1
tools/editor/property_editor.h

@@ -163,8 +163,8 @@ class PropertyEditor : public Control {
 	bool show_categories;
 	float refresh_countdown;
 	bool use_doc_hints;
-
 	bool use_filter;
+	bool subsection_selectable;
 
 	HashMap<String,String> pending;
 	String selected_property;
@@ -239,6 +239,8 @@ public:
 	void set_use_filter(bool p_use);
 	void register_text_enter(Node *p_line_edit);
 
+	void set_subsection_selectable(bool p_selectable);
+
 	PropertyEditor();	
 	~PropertyEditor();