diff options
28 files changed, 913 insertions, 432 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 8d6662157d..4f5358591a 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1347,6 +1347,10 @@ bool _Directory::file_exists(String p_file){ return d->file_exists(p_file); } +bool _Directory::dir_exists(String p_dir) { + ERR_FAIL_COND_V(!d,false); + return d->dir_exists(p_dir); +} int _Directory::get_space_left(){ @@ -1386,6 +1390,7 @@ void _Directory::_bind_methods() { ObjectTypeDB::bind_method(_MD("make_dir:Error","name"),&_Directory::make_dir); ObjectTypeDB::bind_method(_MD("make_dir_recursive:Error","name"),&_Directory::make_dir_recursive); ObjectTypeDB::bind_method(_MD("file_exists","name"),&_Directory::file_exists); + ObjectTypeDB::bind_method(_MD("dir_exists","name"),&_Directory::dir_exists); // ObjectTypeDB::bind_method(_MD("get_modified_time","file"),&_Directory::get_modified_time); ObjectTypeDB::bind_method(_MD("get_space_left"),&_Directory::get_space_left); ObjectTypeDB::bind_method(_MD("copy:Error","from","to"),&_Directory::copy); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index bb68bbaad8..02fe3e8874 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -350,6 +350,7 @@ public: Error make_dir_recursive(String p_dir); bool file_exists(String p_file); + bool dir_exists(String p_dir); int get_space_left(); diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 6a28fa9dae..e2cb300ebc 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -443,6 +443,11 @@ bool DirAccessPack::file_exists(String p_file){ return current->files.has(p_file); } +bool DirAccessPack::dir_exists(String p_dir) { + + return current->subdirs.has(p_dir); +} + Error DirAccessPack::make_dir(String p_dir){ return ERR_UNAVAILABLE; diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 07ce8cbaf8..a4c750bf3c 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -190,6 +190,7 @@ public: virtual bool file_exists(String p_file); + virtual bool dir_exists(String p_dir); virtual Error make_dir(String p_dir); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index f67a10df2e..37fc9c4a0a 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -112,6 +112,7 @@ void PacketPeer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_var"),&PacketPeer::_bnd_get_var); ObjectTypeDB::bind_method(_MD("put_var", "var:Variant"),&PacketPeer::put_var); + ObjectTypeDB::bind_method(_MD("get_available_packet_count"),&PacketPeer::get_available_packet_count); }; /***************/ diff --git a/core/os/dir_access.h b/core/os/dir_access.h index 58a925465a..d8672218bd 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -91,7 +91,7 @@ public: virtual Error erase_contents_recursive(); //super dangerous, use with care! virtual bool file_exists(String p_file)=0; - + virtual bool dir_exists(String p_dir)=0; virtual size_t get_space_left()=0; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 63d0fcec3a..c245e01ee0 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -567,6 +567,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var VCALL_PTR0R( Matrix32, affine_inverse ); VCALL_PTR0R( Matrix32, get_rotation ); VCALL_PTR0R( Matrix32, get_origin ); + VCALL_PTR0R( Matrix32, get_scale ); VCALL_PTR0R( Matrix32, orthonormalized ); VCALL_PTR1R( Matrix32, rotated ); VCALL_PTR1R( Matrix32, scaled ); @@ -1377,6 +1378,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC0(MATRIX32,MATRIX32,Matrix32,affine_inverse,varray()); ADDFUNC0(MATRIX32,REAL,Matrix32,get_rotation,varray()); ADDFUNC0(MATRIX32,VECTOR2,Matrix32,get_origin,varray()); + ADDFUNC0(MATRIX32,VECTOR2,Matrix32,get_scale,varray()); ADDFUNC0(MATRIX32,MATRIX32,Matrix32,orthonormalized,varray()); ADDFUNC1(MATRIX32,MATRIX32,Matrix32,rotated,REAL,"phi",varray()); ADDFUNC1(MATRIX32,MATRIX32,Matrix32,scaled,VECTOR2,"scale",varray()); diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index fff86c5a7e..452d791d96 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -81,6 +81,26 @@ bool DirAccessUnix::file_exists(String p_file) { } +bool DirAccessUnix::dir_exists(String p_dir) { + + GLOBAL_LOCK_FUNCTION + + + if (p_dir.is_rel_path()) + p_dir=current_dir+"/"+p_dir; + else + p_dir=fix_path(p_dir); + + struct stat flags; + bool success = (stat(p_dir.utf8().get_data(),&flags)==0); + + if (success && S_ISDIR(flags.st_mode)) + return true; + + return false; + +} + uint64_t DirAccessUnix::get_modified_time(String p_file) { if (p_file.is_rel_path()) diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 7ede4fc31c..119cb5c3f4 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -66,7 +66,9 @@ public: virtual String get_current_dir(); ///< return current dir location virtual Error make_dir(String p_dir); - virtual bool file_exists(String p_file); + virtual bool file_exists(String p_file); + virtual bool dir_exists(String p_dir); + virtual uint64_t get_modified_time(String p_file); diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index f91ad36ef9..dfcf479fc0 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -93,6 +93,9 @@ Error TCPServerPosix::listen(uint16_t p_port,const List<String> *p_accepted_host close(sockfd); ERR_FAIL_V(FAILED); }; + } + else { + return ERR_ALREADY_IN_USE; }; if (listen_sockfd != -1) { diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 30f6ff6d8c..aacd02ca24 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -303,6 +303,39 @@ bool DirAccessWindows::file_exists(String p_file) { return false; } +bool DirAccessWindows::dir_exists(String p_dir) { + + GLOBAL_LOCK_FUNCTION + + if (!p_dir.is_abs_path()) + p_dir=get_current_dir()+"/"+p_dir; + p_dir=fix_path(p_dir); + + p_dir.replace("/","\\"); + + if (unicode) { + + DWORD fileAttr; + + fileAttr = GetFileAttributesW(p_dir.c_str()); + if (0xFFFFFFFF == fileAttr) + return false; + + return (fileAttr&FILE_ATTRIBUTE_DIRECTORY); + + } else { + DWORD fileAttr; + + fileAttr = GetFileAttributesA(p_dir.ascii().get_data()); + if (0xFFFFFFFF == fileAttr) + return false; + return (fileAttr&FILE_ATTRIBUTE_DIRECTORY); + + } + + return false; +} + Error DirAccessWindows::rename(String p_path,String p_new_path) { p_path=fix_path(p_path); diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index 926497c583..36530ba9b3 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -74,6 +74,7 @@ public: virtual bool file_exists(String p_file); + virtual bool dir_exists(String p_dir); virtual Error make_dir(String p_dir); diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 0c8a5785f8..f32e16e7d8 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -179,6 +179,32 @@ bool DirAccessJAndroid::file_exists(String p_file){ return exists; } +bool DirAccessJAndroid::dir_exists(String p_dir) { + + JNIEnv *env = ThreadAndroid::get_env(); + + String sd; + if (current_dir=="") + sd=p_dir; + else + sd=current_dir+"/"+p_dir; + + String path=fix_path(sd).simplify_path(); + if (path.begins_with("/")) + path=path.substr(1,path.length()); + else if (path.begins_with("res://")) + path=path.substr(6,path.length()); + + jstring js = env->NewStringUTF(path.utf8().get_data()); + int res = env->CallIntMethod(io,_dir_open,js); + if (res<=0) + return false; + + env->CallVoidMethod(io,_dir_close,res); + env->DeleteLocalRef(js); + + return true; +} Error DirAccessJAndroid::make_dir(String p_dir){ diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index b6e3fe393f..958ea34891 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -70,6 +70,7 @@ public: virtual bool file_exists(String p_file); + virtual bool dir_exists(String p_dir); virtual Error make_dir(String p_dir); diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java index bd973ce49b..9cadeb4231 100644 --- a/platform/android/java/src/com/android/godot/Godot.java +++ b/platform/android/java/src/com/android/godot/Godot.java @@ -62,6 +62,7 @@ import android.widget.FrameLayout; import com.android.godot.input.*; import java.io.InputStream; +import javax.microedition.khronos.opengles.GL10; public class Godot extends Activity implements SensorEventListener { @@ -116,11 +117,13 @@ public class Godot extends Activity implements SensorEventListener } - protected void onMainResume() { - - - } + protected void onMainPause() {} + protected void onMainResume() {} + protected void onMainDestroy() {} + protected void onGLDrawFrame(GL10 gl) {} + protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call + //protected void onGLSurfaceCreated(GL10 gl, EGLConfig config) {} // singletons won't be ready until first GodotLib.step() public void registerMethods() {} } @@ -141,6 +144,7 @@ public class Godot extends Activity implements SensorEventListener private Sensor mAccelerometer; public FrameLayout layout; + public RelativeLayout adLayout; static public GodotIO io; @@ -154,7 +158,6 @@ public class Godot extends Activity implements SensorEventListener static int singleton_count=0; - public interface ResultCallback { public void callback(int requestCode, int resultCode, Intent data); }; @@ -197,6 +200,12 @@ public class Godot extends Activity implements SensorEventListener edittext.setView(mView); io.setEdit(edittext); + + // Ad layout + adLayout = new RelativeLayout(this); + adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); + layout.addView(adLayout); + } private static Godot _self; @@ -206,46 +215,46 @@ public class Godot extends Activity implements SensorEventListener } - private String[] getCommandLine() { - - InputStream is; - try { - is = getAssets().open("/_cl_"); - byte[] len = new byte[4]; - int r = is.read(len); - if (r<4) { - System.out.printf("**ERROR** Wrong cmdline length.\n"); - return new String[0]; - } - int argc=((int)(len[3])<<24) | ((int)(len[2])<<16) | ((int)(len[1])<<8) | ((int)(len[0])); - String[] cmdline = new String[argc]; - for(int i=0;i<argc;i++) { - r = is.read(len); - if (r<4) { - System.out.printf("**ERROR** Wrong cmdline param lenght.\n"); - return new String[0]; - } - int strlen=((int)(len[3])<<24) | ((int)(len[2])<<16) | ((int)(len[1])<<8) | ((int)(len[0])); - if (strlen>65535) { - System.out.printf("**ERROR** Wrong command len\n"); - return new String[0]; - } - byte[] arg = new byte[strlen]; - r = is.read(arg); - if (r!=strlen) { - cmdline[i]=new String(arg,"UTF-8"); - } - - } - - return cmdline; - } catch (Exception e) { - - return new String[0]; - } - - - } + private String[] getCommandLine() { + + InputStream is; + try { + is = getAssets().open("/_cl_"); + byte[] len = new byte[4]; + int r = is.read(len); + if (r<4) { + System.out.printf("**ERROR** Wrong cmdline length.\n"); + return new String[0]; + } + int argc=((int)(len[3])<<24) | ((int)(len[2])<<16) | ((int)(len[1])<<8) | ((int)(len[0])); + String[] cmdline = new String[argc]; + for(int i=0;i<argc;i++) { + r = is.read(len); + if (r<4) { + System.out.printf("**ERROR** Wrong cmdline param lenght.\n"); + return new String[0]; + } + int strlen=((int)(len[3])<<24) | ((int)(len[2])<<16) | ((int)(len[1])<<8) | ((int)(len[0])); + if (strlen>65535) { + System.out.printf("**ERROR** Wrong command len\n"); + return new String[0]; + } + byte[] arg = new byte[strlen]; + r = is.read(arg); + if (r!=strlen) { + cmdline[i]=new String(arg,"UTF-8"); + } + + } + + return cmdline; + } catch (Exception e) { + + return new String[0]; + } + + + } @Override protected void onCreate(Bundle icicle) { @@ -282,6 +291,9 @@ public class Godot extends Activity implements SensorEventListener @Override protected void onDestroy(){ if(mPaymentsManager != null ) mPaymentsManager.destroy(); + for(int i=0;i<singleton_count;i++) { + singletons[i].onMainDestroy(); + } super.onDestroy(); } @@ -291,6 +303,9 @@ public class Godot extends Activity implements SensorEventListener mSensorManager.unregisterListener(this); GodotLib.focusout(); + for(int i=0;i<singleton_count;i++) { + singletons[i].onMainPause(); + } } @Override protected void onResume() { @@ -396,31 +411,31 @@ public class Godot extends Activity implements SensorEventListener return true; } - @Override public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { - String s = event.getCharacters(); - if (s == null || s.length() == 0) - return super.onKeyMultiple(inKeyCode, repeatCount, event); - - final char[] cc = s.toCharArray(); - int cnt = 0; - for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0); - if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); - final Activity me = this; - queueEvent(new Runnable() { - // This method will be called on the rendering thread: - public void run() { - for (int i = 0, n = cc.length; i < n; i++) { - int keyCode; - if ((keyCode = cc[i]) != 0) { - // Simulate key down and up... - GodotLib.key(0, keyCode, true); - GodotLib.key(0, keyCode, false); - } - } - } - }); - return true; - } + @Override public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { + String s = event.getCharacters(); + if (s == null || s.length() == 0) + return super.onKeyMultiple(inKeyCode, repeatCount, event); + + final char[] cc = s.toCharArray(); + int cnt = 0; + for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0); + if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); + final Activity me = this; + queueEvent(new Runnable() { + // This method will be called on the rendering thread: + public void run() { + for (int i = 0, n = cc.length; i < n; i++) { + int keyCode; + if ((keyCode = cc[i]) != 0) { + // Simulate key down and up... + GodotLib.key(0, keyCode, true); + GodotLib.key(0, keyCode, false); + } + } + } + }); + return true; + } private void queueEvent(Runnable runnable) { // TODO Auto-generated method stub diff --git a/platform/android/java/src/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java index 1993be8d2c..f02cc00c28 100644 --- a/platform/android/java/src/com/android/godot/GodotView.java +++ b/platform/android/java/src/com/android/godot/GodotView.java @@ -62,13 +62,14 @@ import javax.microedition.khronos.opengles.GL10; * bit depths). Failure to do so would result in an EGL_BAD_MATCH error. */ public class GodotView extends GLSurfaceView { - private static String TAG = "GodotView"; - private static final boolean DEBUG = false; - private static Context ctx; - private static GodotIO io; - private static boolean firsttime=true; - private static boolean use_gl2=false; + private static String TAG = "GodotView"; + private static final boolean DEBUG = false; + private static Context ctx; + + private static GodotIO io; + private static boolean firsttime=true; + private static boolean use_gl2=false; private Godot activity; @@ -113,37 +114,37 @@ public class GodotView extends GLSurfaceView { return super.onKeyDown(keyCode, event); } - private void init(boolean translucent, int depth, int stencil) { + private void init(boolean translucent, int depth, int stencil) { - this.setFocusableInTouchMode(true); - /* By default, GLSurfaceView() creates a RGB_565 opaque surface. - * If we want a translucent one, we should change the surface's - * format here, using PixelFormat.TRANSLUCENT for GL Surfaces - * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. - */ - if (translucent) { - this.getHolder().setFormat(PixelFormat.TRANSLUCENT); - } + this.setFocusableInTouchMode(true); + /* By default, GLSurfaceView() creates a RGB_565 opaque surface. + * If we want a translucent one, we should change the surface's + * format here, using PixelFormat.TRANSLUCENT for GL Surfaces + * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. + */ + if (translucent) { + this.getHolder().setFormat(PixelFormat.TRANSLUCENT); + } - /* Setup the context factory for 2.0 rendering. - * See ContextFactory class definition below - */ - setEGLContextFactory(new ContextFactory()); - - /* We need to choose an EGLConfig that matches the format of - * our surface exactly. This is going to be done in our - * custom config chooser. See ConfigChooser class definition - * below. - */ - setEGLConfigChooser( translucent ? - new ConfigChooser(8, 8, 8, 8, depth, stencil) : - new ConfigChooser(5, 6, 5, 0, depth, stencil) ); - - /* Set the renderer responsible for frame rendering */ - setRenderer(new Renderer()); - } + /* Setup the context factory for 2.0 rendering. + * See ContextFactory class definition below + */ + setEGLContextFactory(new ContextFactory()); + + /* We need to choose an EGLConfig that matches the format of + * our surface exactly. This is going to be done in our + * custom config chooser. See ConfigChooser class definition + * below. + */ + setEGLConfigChooser( translucent ? + new ConfigChooser(8, 8, 8, 8, depth, stencil) : + new ConfigChooser(5, 6, 5, 0, depth, stencil) ); + + /* Set the renderer responsible for frame rendering */ + setRenderer(new Renderer()); + } - private static class ContextFactory implements GLSurfaceView.EGLContextFactory { + private static class ContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { if (use_gl2) @@ -151,11 +152,11 @@ public class GodotView extends GLSurfaceView { else Log.w(TAG, "creating OpenGL ES 1.1 context :"); - checkEglError("Before eglCreateContext", egl); - int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; - EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null); - checkEglError("After eglCreateContext", egl); - return context; + checkEglError("Before eglCreateContext", egl); + int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; + EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null); + checkEglError("After eglCreateContext", egl); + return context; } public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { @@ -170,225 +171,231 @@ public class GodotView extends GLSurfaceView { } } - private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { - - public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { - mRedSize = r; - mGreenSize = g; - mBlueSize = b; - mAlphaSize = a; - mDepthSize = depth; - mStencilSize = stencil; - } + private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { - /* This EGL config specification is used to specify 2.0 rendering. - * We use a minimum size of 4 bits for red/green/blue, but will - * perform actual matching in chooseConfig() below. - */ - private static int EGL_OPENGL_ES2_BIT = 4; - private static int[] s_configAttribs2 = - { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, - // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL10.EGL_NONE - }; - private static int[] s_configAttribs = - { - EGL10.EGL_RED_SIZE, 4, - EGL10.EGL_GREEN_SIZE, 4, - EGL10.EGL_BLUE_SIZE, 4, - // EGL10.EGL_DEPTH_SIZE, 16, - // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, - EGL10.EGL_NONE - }; + public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { + mRedSize = r; + mGreenSize = g; + mBlueSize = b; + mAlphaSize = a; + mDepthSize = depth; + mStencilSize = stencil; + } - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + /* This EGL config specification is used to specify 2.0 rendering. + * We use a minimum size of 4 bits for red/green/blue, but will + * perform actual matching in chooseConfig() below. + */ + private static int EGL_OPENGL_ES2_BIT = 4; + private static int[] s_configAttribs2 = + { + EGL10.EGL_RED_SIZE, 4, + EGL10.EGL_GREEN_SIZE, 4, + EGL10.EGL_BLUE_SIZE, 4, + // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; + private static int[] s_configAttribs = + { + EGL10.EGL_RED_SIZE, 4, + EGL10.EGL_GREEN_SIZE, 4, + EGL10.EGL_BLUE_SIZE, 4, + // EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE, + EGL10.EGL_NONE + }; + + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + + /* Get the number of minimally matching EGL configurations + */ + int[] num_config = new int[1]; + egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config); + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + throw new IllegalArgumentException("No configs match configSpec"); + } + + /* Allocate then read the array of minimally matching EGL configs + */ + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config); + + if (DEBUG) { + printConfigs(egl, display, configs); + } + /* Now return the "best" one + */ + return chooseConfig(egl, display, configs); + } - /* Get the number of minimally matching EGL configurations - */ - int[] num_config = new int[1]; - egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config); + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, + EGLConfig[] configs) { + for(EGLConfig config : configs) { + int d = findConfigAttrib(egl, display, config, + EGL10.EGL_DEPTH_SIZE, 0); + int s = findConfigAttrib(egl, display, config, + EGL10.EGL_STENCIL_SIZE, 0); + + // We need at least mDepthSize and mStencilSize bits + if (d < mDepthSize || s < mStencilSize) + continue; + + // We want an *exact* match for red/green/blue/alpha + int r = findConfigAttrib(egl, display, config, + EGL10.EGL_RED_SIZE, 0); + int g = findConfigAttrib(egl, display, config, + EGL10.EGL_GREEN_SIZE, 0); + int b = findConfigAttrib(egl, display, config, + EGL10.EGL_BLUE_SIZE, 0); + int a = findConfigAttrib(egl, display, config, + EGL10.EGL_ALPHA_SIZE, 0); + + if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) + return config; + } + return null; + } - int numConfigs = num_config[0]; + private int findConfigAttrib(EGL10 egl, EGLDisplay display, + EGLConfig config, int attribute, int defaultValue) { - if (numConfigs <= 0) { - throw new IllegalArgumentException("No configs match configSpec"); - } + if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { + return mValue[0]; + } + return defaultValue; + } - /* Allocate then read the array of minimally matching EGL configs - */ - EGLConfig[] configs = new EGLConfig[numConfigs]; - egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config); + private void printConfigs(EGL10 egl, EGLDisplay display, + EGLConfig[] configs) { + int numConfigs = configs.length; + Log.w(TAG, String.format("%d configurations", numConfigs)); + for (int i = 0; i < numConfigs; i++) { + Log.w(TAG, String.format("Configuration %d:\n", i)); + printConfig(egl, display, configs[i]); + } + } - if (DEBUG) { - printConfigs(egl, display, configs); - } - /* Now return the "best" one - */ - return chooseConfig(egl, display, configs); - } + private void printConfig(EGL10 egl, EGLDisplay display, + EGLConfig config) { + int[] attributes = { + EGL10.EGL_BUFFER_SIZE, + EGL10.EGL_ALPHA_SIZE, + EGL10.EGL_BLUE_SIZE, + EGL10.EGL_GREEN_SIZE, + EGL10.EGL_RED_SIZE, + EGL10.EGL_DEPTH_SIZE, + EGL10.EGL_STENCIL_SIZE, + EGL10.EGL_CONFIG_CAVEAT, + EGL10.EGL_CONFIG_ID, + EGL10.EGL_LEVEL, + EGL10.EGL_MAX_PBUFFER_HEIGHT, + EGL10.EGL_MAX_PBUFFER_PIXELS, + EGL10.EGL_MAX_PBUFFER_WIDTH, + EGL10.EGL_NATIVE_RENDERABLE, + EGL10.EGL_NATIVE_VISUAL_ID, + EGL10.EGL_NATIVE_VISUAL_TYPE, + 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, + EGL10.EGL_SAMPLES, + EGL10.EGL_SAMPLE_BUFFERS, + EGL10.EGL_SURFACE_TYPE, + EGL10.EGL_TRANSPARENT_TYPE, + EGL10.EGL_TRANSPARENT_RED_VALUE, + EGL10.EGL_TRANSPARENT_GREEN_VALUE, + EGL10.EGL_TRANSPARENT_BLUE_VALUE, + 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, + 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, + 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, + 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, + EGL10.EGL_LUMINANCE_SIZE, + EGL10.EGL_ALPHA_MASK_SIZE, + EGL10.EGL_COLOR_BUFFER_TYPE, + EGL10.EGL_RENDERABLE_TYPE, + 0x3042 // EGL10.EGL_CONFORMANT + }; + String[] names = { + "EGL_BUFFER_SIZE", + "EGL_ALPHA_SIZE", + "EGL_BLUE_SIZE", + "EGL_GREEN_SIZE", + "EGL_RED_SIZE", + "EGL_DEPTH_SIZE", + "EGL_STENCIL_SIZE", + "EGL_CONFIG_CAVEAT", + "EGL_CONFIG_ID", + "EGL_LEVEL", + "EGL_MAX_PBUFFER_HEIGHT", + "EGL_MAX_PBUFFER_PIXELS", + "EGL_MAX_PBUFFER_WIDTH", + "EGL_NATIVE_RENDERABLE", + "EGL_NATIVE_VISUAL_ID", + "EGL_NATIVE_VISUAL_TYPE", + "EGL_PRESERVED_RESOURCES", + "EGL_SAMPLES", + "EGL_SAMPLE_BUFFERS", + "EGL_SURFACE_TYPE", + "EGL_TRANSPARENT_TYPE", + "EGL_TRANSPARENT_RED_VALUE", + "EGL_TRANSPARENT_GREEN_VALUE", + "EGL_TRANSPARENT_BLUE_VALUE", + "EGL_BIND_TO_TEXTURE_RGB", + "EGL_BIND_TO_TEXTURE_RGBA", + "EGL_MIN_SWAP_INTERVAL", + "EGL_MAX_SWAP_INTERVAL", + "EGL_LUMINANCE_SIZE", + "EGL_ALPHA_MASK_SIZE", + "EGL_COLOR_BUFFER_TYPE", + "EGL_RENDERABLE_TYPE", + "EGL_CONFORMANT" + }; + int[] value = new int[1]; + for (int i = 0; i < attributes.length; i++) { + int attribute = attributes[i]; + String name = names[i]; + if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { + Log.w(TAG, String.format(" %s: %d\n", name, value[0])); + } else { + // Log.w(TAG, String.format(" %s: failed\n", name)); + while (egl.eglGetError() != EGL10.EGL_SUCCESS); + } + } + } - public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - for(EGLConfig config : configs) { - int d = findConfigAttrib(egl, display, config, - EGL10.EGL_DEPTH_SIZE, 0); - int s = findConfigAttrib(egl, display, config, - EGL10.EGL_STENCIL_SIZE, 0); - - // We need at least mDepthSize and mStencilSize bits - if (d < mDepthSize || s < mStencilSize) - continue; - - // We want an *exact* match for red/green/blue/alpha - int r = findConfigAttrib(egl, display, config, - EGL10.EGL_RED_SIZE, 0); - int g = findConfigAttrib(egl, display, config, - EGL10.EGL_GREEN_SIZE, 0); - int b = findConfigAttrib(egl, display, config, - EGL10.EGL_BLUE_SIZE, 0); - int a = findConfigAttrib(egl, display, config, - EGL10.EGL_ALPHA_SIZE, 0); - - if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) - return config; - } - return null; + // Subclasses can adjust these values: + protected int mRedSize; + protected int mGreenSize; + protected int mBlueSize; + protected int mAlphaSize; + protected int mDepthSize; + protected int mStencilSize; + private int[] mValue = new int[1]; } - private int findConfigAttrib(EGL10 egl, EGLDisplay display, - EGLConfig config, int attribute, int defaultValue) { - - if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { - return mValue[0]; - } - return defaultValue; - } + private static class Renderer implements GLSurfaceView.Renderer { - private void printConfigs(EGL10 egl, EGLDisplay display, - EGLConfig[] configs) { - int numConfigs = configs.length; - Log.w(TAG, String.format("%d configurations", numConfigs)); - for (int i = 0; i < numConfigs; i++) { - Log.w(TAG, String.format("Configuration %d:\n", i)); - printConfig(egl, display, configs[i]); - } - } - private void printConfig(EGL10 egl, EGLDisplay display, - EGLConfig config) { - int[] attributes = { - EGL10.EGL_BUFFER_SIZE, - EGL10.EGL_ALPHA_SIZE, - EGL10.EGL_BLUE_SIZE, - EGL10.EGL_GREEN_SIZE, - EGL10.EGL_RED_SIZE, - EGL10.EGL_DEPTH_SIZE, - EGL10.EGL_STENCIL_SIZE, - EGL10.EGL_CONFIG_CAVEAT, - EGL10.EGL_CONFIG_ID, - EGL10.EGL_LEVEL, - EGL10.EGL_MAX_PBUFFER_HEIGHT, - EGL10.EGL_MAX_PBUFFER_PIXELS, - EGL10.EGL_MAX_PBUFFER_WIDTH, - EGL10.EGL_NATIVE_RENDERABLE, - EGL10.EGL_NATIVE_VISUAL_ID, - EGL10.EGL_NATIVE_VISUAL_TYPE, - 0x3030, // EGL10.EGL_PRESERVED_RESOURCES, - EGL10.EGL_SAMPLES, - EGL10.EGL_SAMPLE_BUFFERS, - EGL10.EGL_SURFACE_TYPE, - EGL10.EGL_TRANSPARENT_TYPE, - EGL10.EGL_TRANSPARENT_RED_VALUE, - EGL10.EGL_TRANSPARENT_GREEN_VALUE, - EGL10.EGL_TRANSPARENT_BLUE_VALUE, - 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, - 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, - 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, - 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, - EGL10.EGL_LUMINANCE_SIZE, - EGL10.EGL_ALPHA_MASK_SIZE, - EGL10.EGL_COLOR_BUFFER_TYPE, - EGL10.EGL_RENDERABLE_TYPE, - 0x3042 // EGL10.EGL_CONFORMANT - }; - String[] names = { - "EGL_BUFFER_SIZE", - "EGL_ALPHA_SIZE", - "EGL_BLUE_SIZE", - "EGL_GREEN_SIZE", - "EGL_RED_SIZE", - "EGL_DEPTH_SIZE", - "EGL_STENCIL_SIZE", - "EGL_CONFIG_CAVEAT", - "EGL_CONFIG_ID", - "EGL_LEVEL", - "EGL_MAX_PBUFFER_HEIGHT", - "EGL_MAX_PBUFFER_PIXELS", - "EGL_MAX_PBUFFER_WIDTH", - "EGL_NATIVE_RENDERABLE", - "EGL_NATIVE_VISUAL_ID", - "EGL_NATIVE_VISUAL_TYPE", - "EGL_PRESERVED_RESOURCES", - "EGL_SAMPLES", - "EGL_SAMPLE_BUFFERS", - "EGL_SURFACE_TYPE", - "EGL_TRANSPARENT_TYPE", - "EGL_TRANSPARENT_RED_VALUE", - "EGL_TRANSPARENT_GREEN_VALUE", - "EGL_TRANSPARENT_BLUE_VALUE", - "EGL_BIND_TO_TEXTURE_RGB", - "EGL_BIND_TO_TEXTURE_RGBA", - "EGL_MIN_SWAP_INTERVAL", - "EGL_MAX_SWAP_INTERVAL", - "EGL_LUMINANCE_SIZE", - "EGL_ALPHA_MASK_SIZE", - "EGL_COLOR_BUFFER_TYPE", - "EGL_RENDERABLE_TYPE", - "EGL_CONFORMANT" - }; - int[] value = new int[1]; - for (int i = 0; i < attributes.length; i++) { - int attribute = attributes[i]; - String name = names[i]; - if ( egl.eglGetConfigAttrib(display, config, attribute, value)) { - Log.w(TAG, String.format(" %s: %d\n", name, value[0])); - } else { - // Log.w(TAG, String.format(" %s: failed\n", name)); - while (egl.eglGetError() != EGL10.EGL_SUCCESS); + public void onDrawFrame(GL10 gl) { + GodotLib.step(); + for(int i=0;i<Godot.singleton_count;i++) { + Godot.singletons[i].onGLDrawFrame(gl); + } } - } - } - - // Subclasses can adjust these values: - protected int mRedSize; - protected int mGreenSize; - protected int mBlueSize; - protected int mAlphaSize; - protected int mDepthSize; - protected int mStencilSize; - private int[] mValue = new int[1]; - } - - private static class Renderer implements GLSurfaceView.Renderer { + public void onSurfaceChanged(GL10 gl, int width, int height) { - public void onDrawFrame(GL10 gl) { - GodotLib.step(); - } - - public void onSurfaceChanged(GL10 gl, int width, int height) { - - GodotLib.resize(width, height,!firsttime); - firsttime=false; - } + GodotLib.resize(width, height,!firsttime); + firsttime=false; + for(int i=0;i<Godot.singleton_count;i++) { + Godot.singletons[i].onGLSurfaceChanged(gl, width, height); + } + } - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - GodotLib.newcontext(); + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + GodotLib.newcontext(); + } } - } } diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 4362b8f2c4..b11994eef0 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -153,6 +153,14 @@ jvalue _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_ar v.l=arr; } break; + case Variant::RAW_ARRAY: { + DVector<uint8_t> array = *p_arg; + jbyteArray arr = env->NewByteArray(array.size()); + DVector<uint8_t>::Read r = array.read(); + env->SetByteArrayRegion(arr,0,array.size(),reinterpret_cast<const signed char*>(r.ptr())); + v.l=arr; + + } break; case Variant::REAL_ARRAY: { DVector<float> array = *p_arg; @@ -244,6 +252,19 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) { return sarr; }; + if (name == "[B") { + + jbyteArray arr = (jbyteArray)obj; + int fCount = env->GetArrayLength(arr); + DVector<uint8_t> sarr; + sarr.resize(fCount); + + DVector<uint8_t>::Write w = sarr.write(); + env->GetByteArrayRegion(arr,0,fCount,reinterpret_cast<signed char*>(w.ptr())); + w = DVector<uint8_t>::Write(); + return sarr; + }; + if (name == "java.lang.Float" || name == "java.lang.Double") { jclass nclass = env->FindClass("java/lang/Number"); @@ -1346,6 +1367,7 @@ static Variant::Type get_jni_type(const String& p_type) { {"double", Variant::REAL}, {"java.lang.String",Variant::STRING}, {"[I",Variant::INT_ARRAY}, + {"[B",Variant::RAW_ARRAY}, {"[F",Variant::REAL_ARRAY}, {"[java.lang.String",Variant::STRING_ARRAY}, {"com.android.godot.Dictionary", Variant::DICTIONARY}, @@ -1381,6 +1403,7 @@ static const char* get_jni_sig(const String& p_type) { {"java.lang.String","Ljava/lang/String;"}, {"com.android.godot.Dictionary", "Lcom/android/godot/Dictionary;"}, {"[I","[I"}, + {"[B","[B"}, {"[F","[F"}, {"[java.lang.String","[Ljava/lang/String;"}, {NULL,"V"} diff --git a/platform/flash/dir_access_flash.cpp b/platform/flash/dir_access_flash.cpp index a0f1679243..4b8992f9d6 100644 --- a/platform/flash/dir_access_flash.cpp +++ b/platform/flash/dir_access_flash.cpp @@ -156,6 +156,26 @@ bool DirAccessFlash::file_exists(String p_file) { return success; }; +bool DirAccessFlash::dir_exists(String p_dir) { + + GLOBAL_LOCK_FUNCTION + + + if (p_dir.is_rel_path()) + p_dir=current_dir+"/"+p_dir; + else + p_dir=fix_path(p_dir); + + struct stat flags; + bool success = (stat(p_dir.utf8().get_data(),&flags)==0); + + if (success && S_ISDIR(flags.st_mode)) { + return true; + } + + return false; +}; + size_t DirAccessFlash::get_space_left() { return 0; diff --git a/platform/flash/dir_access_flash.h b/platform/flash/dir_access_flash.h index 09e0b844ce..1378a6e56f 100644 --- a/platform/flash/dir_access_flash.h +++ b/platform/flash/dir_access_flash.h @@ -45,6 +45,7 @@ public: Error make_dir(String p_dir); bool file_exists(String p_file); + bool dir_exists(String p_dir); size_t get_space_left(); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 7f71332517..0e21540e13 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -143,10 +143,12 @@ def configure(env): mingw_prefix=""
if (env["force_32_bits"]!="no"):
- env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
- env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
- env.Append(CCFLAGS=['-m32'])
- env.Append(LINKFLAGS=['-m32'])
+ env['OBJSUFFIX'] = ".32"+env['OBJSUFFIX']
+ env['LIBSUFFIX'] = ".32"+env['LIBSUFFIX']
+ env.Append(CCFLAGS=['-m32'])
+ env.Append(LINKFLAGS=['-m32'])
+ env.Append(LINKFLAGS=['-static-libgcc'])
+ env.Append(LINKFLAGS=['-static-libstdc++'])
diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp index 7b35bcc7ad..e77ca6feaa 100644 --- a/platform/windows/tcp_server_winsock.cpp +++ b/platform/windows/tcp_server_winsock.cpp @@ -86,6 +86,9 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_ho closesocket(sockfd);
ERR_FAIL_V(FAILED);
};
+ }
+ else {
+ return ERR_ALREADY_IN_USE;
};
if (listen_sockfd != INVALID_SOCKET) {
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 14d31b864c..e7d9a4d691 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -204,6 +204,20 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi XChangeWindowAttributes(x11_display, x11_window,CWEventMask,&new_attr); + XClassHint* classHint; + + /* set the titlebar name */ + XStoreName(x11_display, x11_window, "Godot"); + + /* set the name and class hints for the window manager to use */ + classHint = XAllocClassHint(); + if (classHint) { + classHint->res_name = "Godot"; + classHint->res_class = "Godot"; + } + XSetClassHint(x11_display, x11_window, classHint); + XFree(classHint); + wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true); XSetWMProtocols(x11_display, x11_window, &wm_delete, 1); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index a2f837c3c4..b7918994d8 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -398,12 +398,15 @@ void Label::regenerate_word_cache() { } if (current=='\n') { - insert_newline=true; } else { total_char_cache++; } + if (i<text.length() && text[i] == ' ') { + total_char_cache--; // do not count spaces + } + } else { @@ -442,7 +445,8 @@ void Label::regenerate_word_cache() { last_width=line_width; } - + + total_char_cache -= line_count + 1; // do not count new lines (including the first one) if (!autowrap) { @@ -519,6 +523,7 @@ String Label::get_text() const { return text; } + void Label::set_visible_characters(int p_amount) { visible_chars=p_amount; @@ -582,7 +587,7 @@ void Label::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible"),_SCS("set_percent_visible"),_SCS("get_percent_visible") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_percent_visible"),_SCS("get_percent_visible") ); } diff --git a/tools/editor/icons/SCsub b/tools/editor/icons/SCsub index a7e550feac..aea053d22b 100644 --- a/tools/editor/icons/SCsub +++ b/tools/editor/icons/SCsub @@ -3,13 +3,15 @@ Import('env') def make_editor_icons_action(target, source, env): import os + import cStringIO dst = target[0].srcnode().abspath pixmaps = source + + s = cStringIO.StringIO() - f = open(dst,"wb") - f.write("#include \"editor_icons.h\"\n\n") - f.write("#include \"scene/resources/theme.h\"\n\n") + s.write("#include \"editor_icons.h\"\n\n") + s.write("#include \"scene/resources/theme.h\"\n\n") for x in pixmaps: @@ -17,37 +19,41 @@ def make_editor_icons_action(target, source, env): var_str=os.path.basename(x)[:-4]+"_png"; #print(var_str) - f.write("static const unsigned char "+ var_str +"[]={\n"); + s.write("static const unsigned char "+ var_str +"[]={\n"); pngf=open(x,"rb"); b=pngf.read(1); while(len(b)==1): - f.write(hex(ord(b))) + s.write(hex(ord(b))) b=pngf.read(1); if (len(b)==1): - f.write(",") + s.write(",") - f.write("\n};\n\n\n"); + s.write("\n};\n\n\n"); pngf.close(); - f.write("static Ref<ImageTexture> make_icon(const uint8_t* p_png) {\n") - f.write("\tRef<ImageTexture> texture( memnew( ImageTexture ) );\n") - f.write("\ttexture->create_from_image( Image(p_png),ImageTexture::FLAG_FILTER );\n") - f.write("\treturn texture;\n") - f.write("}\n\n") + s.write("static Ref<ImageTexture> make_icon(const uint8_t* p_png) {\n") + s.write("\tRef<ImageTexture> texture( memnew( ImageTexture ) );\n") + s.write("\ttexture->create_from_image( Image(p_png),ImageTexture::FLAG_FILTER );\n") + s.write("\treturn texture;\n") + s.write("}\n\n") - f.write("void editor_register_icons(Ref<Theme> p_theme) {\n\n") + s.write("void editor_register_icons(Ref<Theme> p_theme) {\n\n") for x in pixmaps: x=os.path.basename(str(x)) type=x[5:-4].title().replace("_",""); var_str=x[:-4]+"_png"; - f.write("\tp_theme->set_icon(\""+type+"\",\"EditorIcons\",make_icon("+var_str+"));\n"); + s.write("\tp_theme->set_icon(\""+type+"\",\"EditorIcons\",make_icon("+var_str+"));\n"); - f.write("\n\n}\n\n"); + s.write("\n\n}\n\n"); + + f = open(dst,"wb") + f.write(s.getvalue()) f.close() + s.close() make_editor_icons_builder = Builder(action=make_editor_icons_action, suffix = '.cpp', diff --git a/tools/editor/project_manager.cpp b/tools/editor/project_manager.cpp index c45e7441b8..bd8f1641e2 100644 --- a/tools/editor/project_manager.cpp +++ b/tools/editor/project_manager.cpp @@ -98,22 +98,21 @@ class NewProjectDialog : public ConfirmationDialog { void _path_text_changed(const String& p_path) { - _test_path(); - if (import_mode) { + if ( _test_path() ) { String sp=p_path; sp=sp.replace("\\","/"); int lidx=sp.find_last("/"); + if (lidx!=-1) { sp=sp.substr(lidx+1,sp.length()); } - if (sp=="") + if (sp=="" && import_mode ) sp="Imported Project"; project_name->set_text(sp); } - } void _file_selected(const String& p_path) { @@ -338,21 +337,23 @@ struct ProjectItem { String path; String conf; uint64_t last_modified; + bool favorite; ProjectItem() {} - ProjectItem(const String &p_project, const String &p_path, const String &p_conf, uint64_t p_last_modified) { - project = p_project; path = p_path; conf = p_conf; last_modified = p_last_modified; + ProjectItem(const String &p_project, const String &p_path, const String &p_conf, uint64_t p_last_modified, bool p_favorite=false) { + project = p_project; path = p_path; conf = p_conf; last_modified = p_last_modified; favorite=p_favorite; } _FORCE_INLINE_ bool operator <(const ProjectItem& l) const { return last_modified > l.last_modified; } + _FORCE_INLINE_ bool operator ==(const ProjectItem& l) const { return project==l.project; } }; + void ProjectManager::_panel_draw(Node *p_hb) { HBoxContainer *hb = p_hb->cast_to<HBoxContainer>(); hb->draw_line(Point2(0,hb->get_size().y+1),Point2(hb->get_size().x-10,hb->get_size().y+1),get_color("guide_color","Tree")); - if (hb->get_meta("name")==selected) { - + if (selected_list.has(hb->get_meta("name"))) { hb->draw_style_box(get_stylebox("selected","Tree"),Rect2(Point2(),hb->get_size()-Size2(10,0))); } } @@ -361,20 +362,90 @@ void ProjectManager::_panel_input(const InputEvent& p_ev,Node *p_hb) { if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { - selected = p_hb->get_meta("name"); - selected_main = p_hb->get_meta("main_scene"); + String clicked = p_hb->get_meta("name"); + String clicked_main_scene = p_hb->get_meta("main_scene"); + + if (p_ev.key.mod.shift && selected_list.size()>0 && last_clicked!="" && clicked != last_clicked) { + + int clicked_id = -1; + int last_clicked_id = -1; + for(int i=0;i<scroll_childs->get_child_count();i++) { + HBoxContainer *hb = scroll_childs->get_child(i)->cast_to<HBoxContainer>(); + if (!hb) continue; + if (hb->get_meta("name") == clicked) clicked_id = i; + if (hb->get_meta("name") == last_clicked) last_clicked_id = i; + } + + if (last_clicked_id!=-1 && clicked_id!=-1) { + int min = clicked_id < last_clicked_id? clicked_id : last_clicked_id; + int max = clicked_id > last_clicked_id? clicked_id : last_clicked_id; + for(int i=0; i<scroll_childs->get_child_count(); ++i) { + HBoxContainer *hb = scroll_childs->get_child(i)->cast_to<HBoxContainer>(); + if (!hb) continue; + if (i!=clicked_id && (i<min || i>max) && !p_ev.key.mod.control) { + selected_list.erase(hb->get_meta("name")); + } else if (i>=min && i<=max) { + selected_list.insert(hb->get_meta("name"), hb->get_meta("main_scene")); + } + } + } + + } else if (selected_list.has(clicked) && p_ev.key.mod.control) { + + selected_list.erase(clicked); + + } else { + + last_clicked = clicked; + if (p_ev.key.mod.control || selected_list.size()==0) { + selected_list.insert(clicked, clicked_main_scene); + } else { + selected_list.clear(); + selected_list.insert(clicked, clicked_main_scene); + } + } + + String single_selected = ""; + if (selected_list.size() == 1) { + single_selected = selected_list.front()->key(); + } + + single_selected_main = ""; for(int i=0;i<scroll_childs->get_child_count();i++) { - scroll_childs->get_child(i)->cast_to<CanvasItem>()->update(); + CanvasItem *item = scroll_childs->get_child(i)->cast_to<CanvasItem>(); + item->update(); + + if (single_selected!="" && single_selected == item->get_meta("name")) + single_selected_main = item->get_meta("main_scene"); } - erase_btn->set_disabled(false); - open_btn->set_disabled(false); - run_btn->set_disabled(selected_main==""); + + erase_btn->set_disabled(selected_list.size()<1); + open_btn->set_disabled(selected_list.size()<1); + run_btn->set_disabled(selected_list.size()<1 || (selected_list.size()==1 && single_selected_main=="")); if (p_ev.mouse_button.doubleclick) _open_project(); //open if doubleclicked + + } +} + +void ProjectManager::_favorite_pressed(Node *p_hb) { + + String clicked = p_hb->get_meta("name"); + bool favorite = !p_hb->get_meta("favorite"); + String proj=clicked.replace(":::",":/"); + proj=proj.replace("::","/"); + + if (favorite) { + EditorSettings::get_singleton()->set("favorite_projects/"+clicked,proj); + } else { + EditorSettings::get_singleton()->erase("favorite_projects/"+clicked); } + EditorSettings::get_singleton()->save(); + _load_recent_projects(); } + void ProjectManager::_load_recent_projects() { while(scroll_childs->get_child_count()>0) { @@ -387,12 +458,14 @@ void ProjectManager::_load_recent_projects() { Color font_color = get_color("font_color","Tree"); List<ProjectItem> projects; + List<ProjectItem> favorite_projects; for(List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) { String _name = E->get().name; - if (!_name.begins_with("projects/")) + if (!_name.begins_with("projects/") && !_name.begins_with("favorite_projects/")) continue; + bool favorite = (_name.begins_with("favorite_projects/"))?true:false; String project = _name.get_slice("/",1); String path = EditorSettings::get_singleton()->get(_name); @@ -408,11 +481,27 @@ void ProjectManager::_load_recent_projects() { last_modified = cache_modified; } - ProjectItem item(project, path, conf, last_modified); - projects.push_back(item); + ProjectItem item(project, path, conf, last_modified, favorite); + if (favorite) + favorite_projects.push_back(item); + else + projects.push_back(item); } projects.sort(); + favorite_projects.sort(); + + for(List<ProjectItem>::Element *E=projects.front();E;) { + List<ProjectItem>::Element *next = E->next(); + if (favorite_projects.find(E->get()) != NULL) + projects.erase(E->get()); + E=next; + } + for(List<ProjectItem>::Element *E=favorite_projects.back();E;E=E->prev()) { + projects.push_front(E->get()); + } + + Ref<Texture> favorite_icon = get_icon("Favorites","EditorIcons"); for(List<ProjectItem>::Element *E=projects.front();E;E=E->next()) { @@ -420,6 +509,7 @@ void ProjectManager::_load_recent_projects() { String project = item.project; String path = item.path; String conf = item.conf; + bool is_favorite = item.favorite; Ref<ConfigFile> cf = memnew( ConfigFile ); Error err = cf->load(conf); @@ -428,7 +518,6 @@ void ProjectManager::_load_recent_projects() { Ref<Texture> icon; String project_name="Unnamed Project"; - if (cf->has_section_key("application","icon")) { String appicon = cf->get_value("application","icon"); if (appicon!="") { @@ -457,15 +546,27 @@ void ProjectManager::_load_recent_projects() { main_scene = cf->get_value("application","main_scene"); } - HBoxContainer *hb = memnew( HBoxContainer ); hb->set_meta("name",project); hb->set_meta("main_scene",main_scene); + hb->set_meta("favorite",is_favorite); hb->connect("draw",this,"_panel_draw",varray(hb)); hb->connect("input_event",this,"_panel_input",varray(hb)); + + VBoxContainer *favorite_box = memnew( VBoxContainer ); + TextureButton *favorite = memnew( TextureButton ); + favorite->set_normal_texture(favorite_icon); + if (!is_favorite) + favorite->set_opacity(0.2); + favorite->set_v_size_flags(SIZE_EXPAND); + favorite->connect("pressed",this,"_favorite_pressed",varray(hb)); + favorite_box->add_child(favorite); + hb->add_child(favorite_box); + TextureFrame *tf = memnew( TextureFrame ); tf->set_texture(icon); hb->add_child(tf); + VBoxContainer *vb = memnew(VBoxContainer); hb->add_child(vb); EmptyControl *ec = memnew( EmptyControl ); @@ -483,68 +584,92 @@ void ProjectManager::_load_recent_projects() { scroll_childs->add_child(hb); } - erase_btn->set_disabled(selected==""); - open_btn->set_disabled(selected==""); - if (selected=="") - run_btn->set_disabled(true); + erase_btn->set_disabled(selected_list.size()<1); + open_btn->set_disabled(selected_list.size()<1); + run_btn->set_disabled(selected_list.size()<1 || (selected_list.size()==1 && single_selected_main=="")); } -void ProjectManager::_open_project() { - +void ProjectManager::_open_project_confirm() { - if (selected=="") { - return; - } + for (Map<String,String>::Element *E=selected_list.front(); E; E=E->next()) { + const String &selected = E->key(); + String path = EditorSettings::get_singleton()->get("projects/"+selected); + print_line("OPENING: "+path+" ("+selected+")"); - String path = EditorSettings::get_singleton()->get("projects/"+selected); - print_line("OPENING: "+path+" ("+selected+")"); + List<String> args; - List<String> args; + args.push_back("-path"); + args.push_back(path); + args.push_back("-editor"); - args.push_back("-path"); - args.push_back(path); + const String &selected_main = E->get(); + if (selected_main!="") { + args.push_back(selected_main); + } - args.push_back("-editor"); + String exec = OS::get_singleton()->get_executable_path(); - if (selected_main!="") { - args.push_back(selected_main); + OS::ProcessID pid=0; + Error err = OS::get_singleton()->execute(exec,args,false,&pid); + ERR_FAIL_COND(err); } - String exec = OS::get_singleton()->get_executable_path(); + get_scene()->quit(); +} - OS::ProcessID pid=0; - Error err = OS::get_singleton()->execute(exec,args,false,&pid); - ERR_FAIL_COND(err); +void ProjectManager::_open_project() { - get_scene()->quit(); + if (selected_list.size()<1) { + return; + } + if (selected_list.size()>1) { + multi_open_ask->set_text("Are you sure to open more than one projects?"); + multi_open_ask->popup_centered(Size2(300,100)); + } else { + _open_project_confirm(); + } } -void ProjectManager::_run_project() { +void ProjectManager::_run_project_confirm() { + for (Map<String,String>::Element *E=selected_list.front(); E; E=E->next()) { - if (selected=="") { - return; - } + const String &selected_main = E->get(); + if (selected_main == "") continue; - String path = EditorSettings::get_singleton()->get("projects/"+selected); - print_line("OPENING: "+path+" ("+selected+")"); + const String &selected = E->key(); + String path = EditorSettings::get_singleton()->get("projects/"+selected); + print_line("OPENING: "+path+" ("+selected+")"); - List<String> args; + List<String> args; + args.push_back("-path"); + args.push_back(path); - args.push_back("-path"); - args.push_back(path); + String exec = OS::get_singleton()->get_executable_path(); - String exec = OS::get_singleton()->get_executable_path(); + OS::ProcessID pid=0; + Error err = OS::get_singleton()->execute(exec,args,false,&pid); + ERR_FAIL_COND(err); + } + // get_scene()->quit(); do not quit +} + +void ProjectManager::_run_project() { - OS::ProcessID pid=0; - Error err = OS::get_singleton()->execute(exec,args,false,&pid); - ERR_FAIL_COND(err); -// get_scene()->quit(); do not quit + if (selected_list.size()<1) { + return; + } + if (selected_list.size()>1) { + multi_run_ask->set_text("Are you sure to run more than one projects?"); + multi_run_ask->popup_centered(Size2(300,100)); + } else { + _run_project_confirm(); + } } void ProjectManager::_scan_dir(DirAccess *da,float pos, float total,List<String> *r_projects) { @@ -619,21 +744,24 @@ void ProjectManager::_import_project() { void ProjectManager::_erase_project_confirm() { - if (selected=="") { + if (selected_list.size()==0) { return; } - - EditorSettings::get_singleton()->erase("projects/"+selected); + for (Map<String,String>::Element *E=selected_list.front(); E; E=E->next()) { + EditorSettings::get_singleton()->erase("projects/"+E->key()); + EditorSettings::get_singleton()->erase("favorite_projects/"+E->key()); + } EditorSettings::get_singleton()->save(); - selected=""; - selected_main=""; + selected_list.clear(); + last_clicked = ""; + single_selected_main=""; _load_recent_projects(); } void ProjectManager::_erase_project() { - if (selected=="") + if (selected_list.size()==0) return; @@ -651,7 +779,9 @@ void ProjectManager::_exit_dialog() { void ProjectManager::_bind_methods() { ObjectTypeDB::bind_method("_open_project",&ProjectManager::_open_project); + ObjectTypeDB::bind_method("_open_project_confirm",&ProjectManager::_open_project_confirm); ObjectTypeDB::bind_method("_run_project",&ProjectManager::_run_project); + ObjectTypeDB::bind_method("_run_project_confirm",&ProjectManager::_run_project_confirm); ObjectTypeDB::bind_method("_scan_projects",&ProjectManager::_scan_projects); ObjectTypeDB::bind_method("_scan_begin",&ProjectManager::_scan_begin); ObjectTypeDB::bind_method("_import_project",&ProjectManager::_import_project); @@ -662,6 +792,8 @@ void ProjectManager::_bind_methods() { ObjectTypeDB::bind_method("_load_recent_projects",&ProjectManager::_load_recent_projects); ObjectTypeDB::bind_method("_panel_draw",&ProjectManager::_panel_draw); ObjectTypeDB::bind_method("_panel_input",&ProjectManager::_panel_input); + ObjectTypeDB::bind_method("_favorite_pressed",&ProjectManager::_favorite_pressed); + } @@ -712,7 +844,7 @@ ProjectManager::ProjectManager() { scroll->set_enable_h_scroll(false); VBoxContainer *tree_vb = memnew( VBoxContainer); - tree_hb->add_child(tree_vb); + tree_hb->add_child(tree_vb); scroll_childs = memnew( VBoxContainer ); scroll_childs->set_h_size_flags(SIZE_EXPAND_FILL); scroll->add_child(scroll_childs); @@ -792,6 +924,18 @@ ProjectManager::ProjectManager() { add_child(erase_ask); + multi_open_ask = memnew( ConfirmationDialog ); + multi_open_ask->get_ok()->set_text("Edit"); + multi_open_ask->get_ok()->connect("pressed", this, "_open_project_confirm"); + + add_child(multi_open_ask); + + multi_run_ask = memnew( ConfirmationDialog ); + multi_run_ask->get_ok()->set_text("Run"); + multi_run_ask->get_ok()->connect("pressed", this, "_run_project_confirm"); + + add_child(multi_run_ask); + OS::get_singleton()->set_low_processor_usage_mode(true); npdialog = memnew( NewProjectDialog ); @@ -806,6 +950,7 @@ ProjectManager::ProjectManager() { //get_ok()->set_text("Open"); //get_ok()->set_text("Exit"); + last_clicked = ""; } diff --git a/tools/editor/project_manager.h b/tools/editor/project_manager.h index b3ad106cd8..eebfc56a66 100644 --- a/tools/editor/project_manager.h +++ b/tools/editor/project_manager.h @@ -46,11 +46,14 @@ class ProjectManager : public Control { FileDialog *scan_dir; ConfirmationDialog *erase_ask; + ConfirmationDialog *multi_open_ask; + ConfirmationDialog *multi_run_ask; NewProjectDialog *npdialog; ScrollContainer *scroll; VBoxContainer *scroll_childs; - String selected; - String selected_main; + Map<String, String> selected_list; // name -> main_scene + String last_clicked; + String single_selected_main; bool importing; void _item_doubleclicked(); @@ -59,7 +62,9 @@ class ProjectManager : public Control { void _scan_projects(); void _run_project(); + void _run_project_confirm(); void _open_project(); + void _open_project_confirm(); void _import_project(); void _new_project(); void _erase_project(); @@ -72,6 +77,7 @@ class ProjectManager : public Control { void _panel_draw(Node *p_hb); void _panel_input(const InputEvent& p_ev,Node *p_hb); + void _favorite_pressed(Node *p_hb); protected: diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 86331faa1d..bc0d48367a 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -37,12 +37,14 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) { + String search_term = tree_filter->get_search_term(); + String file_filter = tree_filter->get_file_filter(); + TreeItem *item = tree->create_item(p_parent); item->set_text(0,p_dir->get_name()+"/"); item->set_icon(0,get_icon("Folder","EditorIcons")); item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); - bool has_items=false; for(int i=0;i<p_dir->get_subdir_count();i++) { @@ -53,6 +55,15 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di for (int i=0;i<p_dir->get_file_count();i++) { + String file_name = p_dir->get_file(i); + String extension = file_name.extension(); + + if (search_term!="" && file_name.findn(search_term)==-1) + continue; + + if (file_filter!="*" && extension != file_filter ) + continue; + bool isfave = favorites.has(p_dir->get_file_path(i)); if (button_favorite->is_pressed() && !isfave) continue; @@ -61,7 +72,7 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di fitem->set_cell_mode(0,TreeItem::CELL_MODE_CHECK); fitem->set_editable(0,true); fitem->set_checked(0,isfave); - fitem->set_text(0,p_dir->get_file(i)); + fitem->set_text(0,file_name); Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),"EditorIcons")?p_dir->get_file_type(i):String("Object")),"EditorIcons"); fitem->set_icon(0, icon ); @@ -251,45 +262,40 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { editor=p_editor; - tree = memnew( Tree ); - add_child(tree); - tree->set_area_as_parent_rect(); - tree->set_anchor_and_margin(MARGIN_TOP,Control::ANCHOR_BEGIN,25); - tree->connect("item_edited",this,"_favorite_toggled"); - + HBoxContainer *toolbar_hbc = memnew( HBoxContainer ); + add_child(toolbar_hbc); button_reload = memnew( Button ); - button_reload->set_pos(Point2(3,2)); - button_reload->set_size(Point2(20,5)); button_reload->set_flat(true); - add_child(button_reload); - button_reload->connect("pressed",this,"_rescan"); + button_reload->connect("pressed",this,"_rescan"); + toolbar_hbc->add_child(button_reload); button_favorite = memnew( Button ); - button_favorite->set_pos(Point2(28,2)); - button_favorite->set_size(Point2(20,5)); button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); - add_child(button_favorite); button_favorite->connect("toggled",this,"_favorites_toggled"); + toolbar_hbc->add_child(button_favorite); - button_instance = memnew( Button ); - button_instance->set_anchor(MARGIN_LEFT,ANCHOR_END); - button_instance->set_anchor(MARGIN_RIGHT,ANCHOR_END); - button_instance->set_begin(Point2(3+20,2)); - button_instance->set_end(Point2(2+15,5)); - button_instance->set_flat(true); - add_child(button_instance); - button_instance->connect("pressed",this,"_instance_pressed"); + toolbar_hbc->add_spacer(); button_open = memnew( Button ); - button_open->set_anchor(MARGIN_LEFT,ANCHOR_END); - button_open->set_anchor(MARGIN_RIGHT,ANCHOR_END); - button_open->set_begin(Point2(3+45,2)); - button_open->set_end(Point2(2+34,5)); button_open->set_flat(true); - add_child(button_open); button_open->connect("pressed",this,"_open_pressed"); + toolbar_hbc->add_child(button_open); + + button_instance = memnew( Button ); + button_instance->set_flat(true); + button_instance->connect("pressed",this,"_instance_pressed"); + toolbar_hbc->add_child(button_instance); + + tree = memnew( Tree ); + tree_filter=memnew( ScenesDockFilter(tree) ); + tree_filter->connect("filter_changed", this, "_update_tree"); + add_child(tree_filter); + add_child(tree); + + tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->connect("item_edited",this,"_favorite_toggled"); timer = memnew( Timer ); timer->set_one_shot(true); @@ -300,10 +306,102 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { updating_tree=false; +} +ScenesDock::~ScenesDock() { } -ScenesDock::~ScenesDock() { +void ScenesDockFilter::_setup_filters() { + + file_filter->clear(); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("",&extensions); + + file_filter->add_item("All Files (*)"); + filters.push_back("*"); + + List<String> filter_texts; + for(int i=0;i<extensions.size();i++) { + filter_texts.push_back("*."+extensions[i]+" ; "+extensions[i].to_upper()); + filters.push_back(extensions[i]); + } + for(int i=0;i<filter_texts.size();i++) { + + String flt=filter_texts[i].get_slice(";",0).strip_edges(); + String desc=filter_texts[i].get_slice(";",1).strip_edges(); + if (desc.length()) + file_filter->add_item(desc+" ( "+flt+" )"); + else + file_filter->add_item("( "+flt+" )"); + } +} + +void ScenesDockFilter::_command(int p_command) { + switch (p_command) { + + case CMD_CLEAR_FILTER: { + if (search_box->get_text()!="") { + search_box->clear(); + emit_signal("filter_changed"); + } + }break; + } +} + +void ScenesDockFilter::_search_text_changed(const String &p_newtext) { + emit_signal("filter_changed"); +} + +String ScenesDockFilter::get_search_term() { + return search_box->get_text().strip_edges(); +} + +String ScenesDockFilter::get_file_filter() { + return _current_filter; +} + +void ScenesDockFilter::_file_filter_selected(int p_idx) { + String selected = filters[file_filter->get_selected()]; + if (_current_filter != selected ) { + _current_filter = selected; + emit_signal("filter_changed"); + } } + +void ScenesDockFilter::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_command"),&ScenesDockFilter::_command); + ObjectTypeDB::bind_method(_MD("_search_text_changed"), &ScenesDockFilter::_search_text_changed); + ObjectTypeDB::bind_method(_MD("_file_filter_selected"), &ScenesDockFilter::_file_filter_selected); + + ADD_SIGNAL( MethodInfo("filter_changed") ); +} + +ScenesDockFilter::ScenesDockFilter(Tree *p_tree) { + + _current_filter = "*"; + + tree = p_tree; + + file_filter = memnew( OptionButton ); + file_filter->set_custom_minimum_size(Size2(90,10)); + file_filter->set_clip_text(true); + file_filter->connect("item_selected", this, "_file_filter_selected"); + add_child(file_filter); + + _setup_filters(); + + search_box = memnew( LineEdit ); + search_box->connect("text_changed",this,"_search_text_changed"); + search_box->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(search_box); + + clear_search_button = memnew( Button ); + clear_search_button->set_text("clear"); + clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER)); + add_child(clear_search_button); + +} + diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index eab31a5a4d..cf48e2885f 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -34,6 +34,8 @@ #include "scene/gui/tree.h" #include "scene/gui/label.h" #include "scene/gui/button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/box_container.h" #include "os/dir_access.h" #include "os/thread.h" @@ -42,8 +44,9 @@ class EditorNode; -class ScenesDock : public Control { - OBJ_TYPE( ScenesDock, Control ); +class ScenesDockFilter; +class ScenesDock : public VBoxContainer { + OBJ_TYPE( ScenesDock, VBoxContainer ); EditorNode *editor; Set<String> favorites; @@ -54,6 +57,8 @@ class ScenesDock : public Control { Button *button_open; Timer *timer; + ScenesDockFilter *tree_filter; + bool updating_tree; Tree * tree; bool _create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir); @@ -77,4 +82,34 @@ public: ~ScenesDock(); }; +class ScenesDockFilter : public HBoxContainer { + + OBJ_TYPE( ScenesDockFilter, HBoxContainer ); + + enum Command { + CMD_CLEAR_FILTER, + }; + + Tree *tree; + OptionButton *file_filter; + LineEdit *search_box; + Button *clear_search_button; + + String _current_filter; + Vector<String> filters; + + void _command(int p_command); + void _search_text_changed(const String& p_newtext); + void _setup_filters(); + void _file_filter_selected(int p_idx); + +protected: + static void _bind_methods(); + +public: + String get_search_term(); + String get_file_filter(); + ScenesDockFilter(Tree *p_tree); +}; + #endif // SCENES_DOCK_H |