diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 8d6662157d8..4f5358591ad 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 bb68bbaad8a..02fe3e88745 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 6a28fa9dae3..e2cb300ebc8 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 07ce8cbaf81..a4c750bf3c7 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 f67a10df2e1..37fc9c4a0ad 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 58a925465ad..d8672218bdc 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 63d0fcec3af..c245e01ee08 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 fff86c5a7ed..452d791d96b 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 7ede4fc31c6..119cb5c3f45 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 f91ad36ef98..dfcf479fc0f 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 *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 30f6ff6d8cb..aacd02ca247 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 926497c5836..36530ba9b39 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 0c8a5785f88..f32e16e7d8f 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 b6e3fe393f4..958ea34891e 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 bd973ce49b0..9cadeb42318 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() { + 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;i65535) { - 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"); - } + 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;i65535) { + 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 cmdline; + } catch (Exception e) { - return new String[0]; - } + 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= 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 1993be8d2c5..f02cc00c285 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 { + 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; - } - - /* 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); - } - - 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; - } - - 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 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 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; } - } + + /* 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); + } + + 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; + } + + 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 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); + } + } + } + + // 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]; } - // 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 { + private static class Renderer implements GLSurfaceView.Renderer { - public void onDrawFrame(GL10 gl) { - GodotLib.step(); + public void onDrawFrame(GL10 gl) { + GodotLib.step(); + for(int i=0;iSetIntArrayRegion(arr,0,array.size(),r.ptr()); v.l=arr; + } break; + case Variant::RAW_ARRAY: { + DVector array = *p_arg; + jbyteArray arr = env->NewByteArray(array.size()); + DVector::Read r = array.read(); + env->SetByteArrayRegion(arr,0,array.size(),reinterpret_cast(r.ptr())); + v.l=arr; + } break; case Variant::REAL_ARRAY: { @@ -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 sarr; + sarr.resize(fCount); + + DVector::Write w = sarr.write(); + env->GetByteArrayRegion(arr,0,fCount,reinterpret_cast(w.ptr())); + w = DVector::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 a0f16792438..4b8992f9d66 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 09e0b844cee..1378a6e56f2 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 7f713325171..0e21540e13c 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 7b35bcc7ad1..e77ca6feaa9 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 *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 14d31b864cb..e7d9a4d691d 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 a2f837c3c49..b7918994d88 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 make_icon(const uint8_t* p_png) {\n") - f.write("\tRef 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 make_icon(const uint8_t* p_png) {\n") + s.write("\tRef 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 p_theme) {\n\n") + s.write("void editor_register_icons(Ref 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 c45e7441b8b..bd8f1641e2c 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(); 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"); - for(int i=0;iget_child_count();i++) { - scroll_childs->get_child(i)->cast_to()->update(); + 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;iget_child_count();i++) { + HBoxContainer *hb = scroll_childs->get_child(i)->cast_to(); + 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; iget_child_count(); ++i) { + HBoxContainer *hb = scroll_childs->get_child(i)->cast_to(); + if (!hb) continue; + if (i!=clicked_id && (imax) && !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); + } } - erase_btn->set_disabled(false); - open_btn->set_disabled(false); - run_btn->set_disabled(selected_main==""); + + String single_selected = ""; + if (selected_list.size() == 1) { + single_selected = selected_list.front()->key(); + } + + single_selected_main = ""; + for(int i=0;iget_child_count();i++) { + CanvasItem *item = scroll_childs->get_child(i)->cast_to(); + item->update(); + + if (single_selected!="" && single_selected == item->get_meta("name")) + single_selected_main = item->get_meta("main_scene"); + } + + 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 projects; + List favorite_projects; for(List::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::Element *E=projects.front();E;) { + List::Element *next = E->next(); + if (favorite_projects.find(E->get()) != NULL) + projects.erase(E->get()); + E=next; + } + for(List::Element *E=favorite_projects.back();E;E=E->prev()) { + projects.push_front(E->get()); + } + + Ref favorite_icon = get_icon("Favorites","EditorIcons"); for(List::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 cf = memnew( ConfigFile ); Error err = cf->load(conf); @@ -428,7 +518,6 @@ void ProjectManager::_load_recent_projects() { Ref 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_confirm() { + + for (Map::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+")"); + + List args; + + args.push_back("-path"); + args.push_back(path); + + args.push_back("-editor"); + + const String &selected_main = E->get(); + if (selected_main!="") { + args.push_back(selected_main); + } + + 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(); } void ProjectManager::_open_project() { - - if (selected=="") { + if (selected_list.size()<1) { return; } - String path = EditorSettings::get_singleton()->get("projects/"+selected); - print_line("OPENING: "+path+" ("+selected+")"); - - List args; - - - args.push_back("-path"); - args.push_back(path); - - args.push_back("-editor"); - - if (selected_main!="") { - args.push_back(selected_main); + 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(); } +} - String exec = OS::get_singleton()->get_executable_path(); +void ProjectManager::_run_project_confirm() { - OS::ProcessID pid=0; - Error err = OS::get_singleton()->execute(exec,args,false,&pid); - ERR_FAIL_COND(err); + for (Map::Element *E=selected_list.front(); E; E=E->next()) { - get_scene()->quit(); + const String &selected_main = E->get(); + if (selected_main == "") continue; + const String &selected = E->key(); + String path = EditorSettings::get_singleton()->get("projects/"+selected); + print_line("OPENING: "+path+" ("+selected+")"); + + List args; + + args.push_back("-path"); + args.push_back(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() { - if (selected=="") { + if (selected_list.size()<1) { return; } - String path = EditorSettings::get_singleton()->get("projects/"+selected); - print_line("OPENING: "+path+" ("+selected+")"); - - List args; - - - args.push_back("-path"); - args.push_back(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 - + 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 *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::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 b3ad106cd86..eebfc56a664 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 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 86331faa1df..bc0d48367a4 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;iget_subdir_count();i++) { @@ -53,6 +55,15 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di for (int i=0;iget_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 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() { } + +void ScenesDockFilter::_setup_filters() { + + file_filter->clear(); + + List extensions; + ResourceLoader::get_recognized_extensions_for_type("",&extensions); + + file_filter->add_item("All Files (*)"); + filters.push_back("*"); + + List filter_texts; + for(int i=0;iadd_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 eab31a5a4d0..cf48e2885f9 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 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 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