diff --git a/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
index 2cb182e27f76a2c62cd437cbf49a912af730db39..8868ab9f65fe147e603eb8f1fd5e7fcd6277a849 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
@@ -19,14 +19,23 @@ public class GLESRender implements Renderer{
 		mGModel.load(filename);
 	}
 	
-	public void translate(float tx, float ty, float tz){
-		mGModel.translation(tx, ty, tz);
+	public void startInteraction(float x, float y) {
+		mGModel.startEvent(x, y);
 	}
-	public void scale(float sx, float sy, float sz){
-		mGModel.scale(sx, sy, sz);
+	public void endInteraction(float x, float y) {
+		mGModel.endEvent(x, y);
 	}
-	public void rotate(float rx, float ry, float rz){
-		mGModel.rotate(rx, ry, rz);
+	public void rotateModel(float x, float y) {
+		mGModel.rotate(x, y);
+	}
+	public void scaleModel(float s) {
+		mGModel.scale(s);
+	}
+	public void translateModel(float x, float y) {
+		mGModel.translate(x, y);
+	}
+	public void resetModelPosition() {
+		mGModel.resetPosition();
 	}
 	
 	// OpenGL ES methods
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
index f13d71f968f7f75bff5f72c2711cdba21813b023..baff69f3f97bc6e9111612a16c7fff38be1f2d7b 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
@@ -17,9 +17,7 @@ public class Gmsh {
 	private native void loadFile(long ptr, String name); // load a file(OpenProjet)
 	private native void initView(long ptr, int w, int h); // Called each time the GLView change
 	private native void drawView(long ptr); // Called each time the GLView request a render
-	private native void setTranslation(long ptr, float tx, float ty, float tz); // translate the current GModel
-	private native void setScale(long ptr, float sx, float sy, float sz); // scale the current GModel
-	private native void setRotate(long ptr, float rx, float ry, float rz); // rotate the current GModel
+	private native void eventHandler(long ptr, int event, float x, float y);
 	private native void setShow(long ptr, String what, boolean show); // select what to show / hide
 	private native long getOnelabInstance(); // return the singleton of the onelab server
 	public native String[] getParams(); // return the parameters for onelab
@@ -51,18 +49,29 @@ public class Gmsh {
 		this.loadFile(ptr, filename);
 	}
 
-	public void translation(float tx, float ty, float tz)
+	public void startEvent(float x, float y)
 	{
-		this.setTranslation(ptr, tx, ty, tz);
+		this.eventHandler(ptr, 0, x, y);
 	}
-
-	public void scale(float sx, float sy, float sz)
+	public void translate(float x, float y)
 	{
-		this.setScale(ptr, sx, sy, sz);
+		this.eventHandler(ptr, 1, x, y);
 	}
-
-	public void rotate(float rx, float ry, float rz) {
-		this.setRotate(ptr, rx, ry, rz);
+	public void scale(float s)
+	{
+		this.eventHandler(ptr, 2, s, 0);
+	}
+	public void rotate(float x, float y)
+	{
+		this.eventHandler(ptr, 3, x, y);
+	}
+	public void endEvent(float x, float y)
+	{
+		this.eventHandler(ptr, 4, x, y);
+	}
+	public void resetPosition()
+	{
+		this.eventHandler(ptr, 5, 0, 0);
 	}
 	public void showGeom(boolean show)
 	{
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
index 7153b3a390955c6622aa3ffcad05b088b1c80d0b..40156b8e49d3846e89119c4e9fd4d4c390f4b594 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
@@ -102,6 +102,12 @@ public class MainActivity extends Activity {
     	setContentView(layout);
     }
     
+    @Override
+    protected void onDestroy() {
+    	// TODO Unload library ?
+    	super.onDestroy();
+    }
+    
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
     	super.onCreateOptionsMenu(menu);
@@ -134,8 +140,12 @@ public class MainActivity extends Activity {
     public boolean onMenuItemSelected(int featureId, MenuItem item) {
     	if(item.getTitle().equals(getString(R.string.menu_settings)))
     		pager.setCurrentItem(0, true);
-    	else if(item.getTitle().equals(getString(R.string.menu_list)))
-    		this.finish();
+    	else if(item.getTitle().equals(getString(R.string.menu_list))) {
+    		if(this.compute)
+    			loading.show();
+    		else
+    			this.finish();
+    	}
     	else if (item.getTitle().equals(getString(R.string.menu_model)))
     		pager.setCurrentItem(1, true);
     	else if(item.getTitle().equals(getString(R.string.menu_postpro))){
@@ -144,7 +154,7 @@ public class MainActivity extends Activity {
 				.setPositiveButton("Ok", null)
 				.show();
     	}
-    	else if(item.getTitle().equals(getString(R.string.menu_view_x))){
+    	/*else if(item.getTitle().equals(getString(R.string.menu_view_x))){
     		renderer.rotate(0, 0, 0);
     		renderer.rotate(90, 0, 0);
     		glView.requestRender();
@@ -165,7 +175,7 @@ public class MainActivity extends Activity {
 		else if(item.getTitle().equals(getString(R.string.menu_view_translation))){
 			renderer.translate(0, 0, 0);
 			glView.requestRender();
-		}
+		}*/ // TODO
     	return super.onMenuItemSelected(featureId, item);
     }
     
@@ -499,11 +509,11 @@ public class MainActivity extends Activity {
 		@Override
 		protected void onPostExecute(Integer[] result) {
 			Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
-			v.vibrate(350);
+			if(!v.hasVibrator()) // TODO Do not commit this line !
+				v.vibrate(350);
 			reset.setEnabled(true);
 			run.setEnabled(true);
 			//run.setText("Run"); // TODO this seems break the ViewPager
-			pager.postInvalidate();
 			glView.requestRender();
 			super.onPostExecute(result);
 			loading.dismiss();
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
index 45743cf12586ee378e7f51876bc58ee3f7b265a4..9b8e937fad6808a9db9f1b5602637962cf0e687b 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
@@ -107,11 +107,11 @@ public class ParameterString extends Parameter{
 
 				public void onItemSelected(AdapterView<?> parent, View view,
 						int pos, long id) {
-					if(_listView != null) _listView.refresh();
 					setValue(pos);
 					_gmsh.setParam(getType(), getName(), String.valueOf(getValue()));
 					if(_gmsh.onelabCB("check") == 1 && _glView != null)
 						_glView.requestRender();
+					if(_listView != null) _listView.refresh();
 				}
 
 			});
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java b/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java
new file mode 100644
index 0000000000000000000000000000000000000000..3faa40d28370dc246e11841bd6677610847386d0
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java
@@ -0,0 +1,172 @@
+package org.geuz.onelab;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.opengles.GL10;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Bitmap.CompressFormat;
+import android.opengl.GLUtils;
+import android.os.Environment;
+
+public class StringTexture {
+	private String _text;
+	private Bitmap _bitmap;
+	private int[] _textures = new int[1]; // Texture pointer
+	
+	public StringTexture(String s) {
+		_text = s;
+		getBitmapFromText(12.0f, Color.BLACK);
+	}
+	
+	private void getBitmapFromText(float textSize, int textColor) {
+	    Paint paint = new Paint();
+	    paint.setTextSize(textSize);
+	    paint.setColor(textColor);
+	    paint.setTextAlign(Paint.Align.LEFT);
+	    int width = (int) (paint.measureText(_text) + 2.5f); // round
+	    int baseline = (int) (textSize + 2.5f);
+	    int height = (int) (baseline + paint.descent() + 2.5f);
+	    _bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+	    _bitmap.eraseColor(Color.TRANSPARENT);
+	    Canvas canvas = new Canvas(_bitmap);
+	    canvas.setBitmap(_bitmap);
+	    canvas.drawText(_text, 0, baseline, paint);
+	}
+	
+	private void loadGLTexture(GL10 gl) {
+		if(_bitmap == null) return;
+		gl.glGenTextures(1, _textures, 0);
+
+		gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
+		
+		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
+		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
+ 
+		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, _bitmap, 0);
+		
+		_bitmap.recycle();
+	}
+	
+	public void draw(GL10 gl, int x, int y) {
+		gl.glEnable(GL10.GL_TEXTURE_2D);
+		// VERTEX
+		float vertex[] = {
+				-1.0f, -1.0f,  0.0f,		// bottom left
+				-1.0f,  1.0f,  0.0f,		// top left
+				 1.0f, -1.0f,  0.0f,		// bottom right
+				 1.0f,  1.0f,  0.0f			// top right
+		};
+		FloatBuffer vertexBuffer;
+		ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertex.length * 4);
+		vertexByteBuffer.order(ByteOrder.nativeOrder());
+		vertexBuffer = vertexByteBuffer.asFloatBuffer();
+		vertexBuffer.put(vertex);
+		vertexBuffer.position(0);
+		
+		// TEXTURE
+		FloatBuffer textureBuffer;	// buffer holding the texture coordinates
+		float texture[] = {
+				0.0f, 1.0f,		// top left
+				0.0f, 0.0f,		// bottom left
+				1.0f, 1.0f,		// top right
+				1.0f, 0.0f		// bottom right
+		};
+		ByteBuffer textureByteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
+		textureByteBuffer.order(ByteOrder.nativeOrder());
+		textureBuffer = textureByteBuffer.asFloatBuffer();
+		textureBuffer.put(texture);
+		textureBuffer.position(0);
+		loadGLTexture(gl);
+		gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
+		
+		
+		// DRAW
+		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
+		gl.glColor4f(1,1,1,1);
+		gl.glEnable(GL10.GL_BLEND);
+		gl.glBlendFunc(GL10.GL_SRC_COLOR, GL10.GL_ONE_MINUS_SRC_ALPHA);
+		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
+		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
+		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertex.length / 3);
+		gl.glDisable(GL10.GL_BLEND);
+		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
+		gl.glDisable(GL10.GL_TEXTURE_2D);
+	}
+	
+	public static byte[] getBytesFromString(String s, int textSize)
+	{
+		// Generate the bitmap
+		int textColor = Color.BLACK;
+		Paint paint = new Paint();
+	    paint.setTextSize(textSize);
+	    paint.setColor(textColor);
+	    paint.setTextAlign(Paint.Align.LEFT);
+	    int width = (int) (paint.measureText(s) + 0.5f); // round
+	    int i;
+	    for(i=2;i<=width;i*=2); width = i;
+	    int baseline = (int) (textSize + 0.5f);
+	    int height = (int) (baseline + paint.descent() + 0.5f);
+	    for(i=2;i<=height;i*=2); height = i;
+	    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+	    bitmap.eraseColor(Color.WHITE);
+	    Canvas canvas = new Canvas(bitmap);
+	    canvas.setBitmap(bitmap);
+	    canvas.drawText(s, 0, baseline, paint);
+	    // TMP
+		try {
+			FileOutputStream stream = new FileOutputStream(Environment.getExternalStorageDirectory()+"/test.jpg");
+			bitmap.compress(CompressFormat.JPEG, 80, stream);
+		} catch (FileNotFoundException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	    // Get the pixel in a map
+	    ByteBuffer buffer = ByteBuffer.allocateDirect(width*height);
+	    buffer.order(ByteOrder.nativeOrder());
+	    buffer.position(0);
+	    for(int y = 0; y<height;y++)
+			for(int x = 0; x<width;x++)
+				buffer.put((byte) ((bitmap.getPixel(x, y) == Color.BLACK)? 0xFF : 0x00));
+	    buffer.position(0);
+	    byte[] b = new byte[buffer.capacity()];
+	    buffer.get(b);
+	    return b;
+	}
+	public static int getWidthFromString(String s, int textSize)
+	{
+		Paint paint = new Paint();
+	    paint.setTextSize(textSize);
+	    paint.setTextAlign(Paint.Align.LEFT);
+	    int ret = (int) (paint.measureText(s) + 0.5f);
+	    int i;
+	    for(i=2;i<=ret;i*=2); ret = i;
+	    return ret;
+	}
+	public static int getRealWidthFromString(String s, int textSize)
+	{
+		Paint paint = new Paint();
+	    paint.setTextSize(textSize);
+	    paint.setTextAlign(Paint.Align.LEFT);
+	    return (int) (paint.measureText(s) + 0.5f);
+	}
+	public static int getHeightFromString(String s, int textSize)
+	{
+		Paint paint = new Paint();
+	    paint.setTextSize(textSize);
+	    paint.setTextAlign(Paint.Align.LEFT);
+	    int ret = (int) (textSize + 0.5f + paint.descent() + 0.5f);
+	    int i;
+	    for(i=2;i<=ret;i*=2); ret = i;
+	    return ret;
+	}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
index d57d57dfc68c6649d35f11e827101f6bf218d39d..2910b6e3387621e60be52c5254786252a3d8c1da 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
@@ -6,7 +6,6 @@ import android.support.v4.view.MotionEventCompat;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
-import android.view.View;
 import android.view.GestureDetector.OnDoubleTapListener;
 import android.view.GestureDetector.OnGestureListener;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -15,22 +14,26 @@ class mGLSurfaceView extends GLSurfaceView {
 	private float scaleFactor = 1f;
 	private GestureDetector gesture;
 	private ScaleGestureDetector scaleGesture;
-	private float lastX, lastY;
 	private GLESRender _renderer;
 	public mGLSurfaceView(Context context, GLESRender renderer) {
 		super(context);
 		_renderer = renderer;
-		gesture = new GestureDetector(context, new GestureListener(this));
+		gesture = new GestureDetector(context, new GestureListener());
 		scaleGesture = new ScaleGestureDetector(context, new OnScaleGestureListener() {
 			
-			public void onScaleEnd(ScaleGestureDetector detector) {}// UNUSED Auto-generated method stub
+			public void onScaleEnd(ScaleGestureDetector detector) {
+				_renderer.endInteraction(detector.getFocusX(), detector.getFocusY());
+			}
 			
-			public boolean onScaleBegin(ScaleGestureDetector detector) {return true;}// UNUSED Auto-generated method stub
+			public boolean onScaleBegin(ScaleGestureDetector detector) {
+				_renderer.startInteraction(detector.getFocusX(), detector.getFocusY());
+				return true;
+			}
 			
 			public boolean onScale(ScaleGestureDetector detector) {
 				scaleFactor *= detector.getScaleFactor();
-				scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 50.0f)); 
-				_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
+				scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 50.0f)); // limit the scale factor
+				_renderer.scaleModel(scaleFactor);
 				requestRender();
 				return true;
 				
@@ -49,17 +52,14 @@ class mGLSurfaceView extends GLSurfaceView {
 	        int action = MotionEventCompat.getActionMasked(event);
 	        
 	        if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_1_DOWN){
-	        	lastX = x;
-	        	lastY = y;
+	        	_renderer.startInteraction(x,y);
 	        }
 	        else if(action == MotionEvent.ACTION_MOVE){
-	        	float dx = x - lastX,
-	        			dy = y - lastY;
-	        	if(dx != 0 || dy != 0)
-	        		_renderer.rotate(dy, dx, 0);
+	        	_renderer.rotateModel(x, y);
 	        	requestRender();
-	        	lastX = x;
-	        	lastY = y;
+	        }
+	        else if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_1_UP){
+	        	_renderer.endInteraction(x, y);
 	        }
 
 			return true;
@@ -72,12 +72,8 @@ class mGLSurfaceView extends GLSurfaceView {
 	}
 	
 	private class GestureListener implements OnGestureListener, OnDoubleTapListener{
-		//private View view;
-		public GestureListener(View view) {
-			//this.view = view;
-		}
 		public boolean onDown(MotionEvent e) {
-			// UNUSED Auto-generated method stub
+			_renderer.startInteraction(e.getX(),e.getY());
 			return true;
 		}
 
@@ -94,7 +90,7 @@ class mGLSurfaceView extends GLSurfaceView {
 
 		public boolean onScroll(MotionEvent e1, MotionEvent e2,
 				float distanceX, float distanceY) {
-			_renderer.translate(-distanceX, distanceY, 0f);
+			_renderer.translateModel(e2.getX(), e2.getY());
 			requestRender();
 			return false;
 		}
@@ -113,10 +109,8 @@ class mGLSurfaceView extends GLSurfaceView {
 			return false;
 		}
 		public boolean onDoubleTapEvent(MotionEvent e) {
-			_renderer.translate(0f, 0f, 0f);
 			scaleFactor = 1f;
-			_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
-			_renderer.rotate(0, 0, 0);
+			_renderer.resetModelPosition();
 			requestRender();
 			return false;
 		}
@@ -128,6 +122,6 @@ class mGLSurfaceView extends GLSurfaceView {
 	}
 	public void resetScale(){
 		scaleFactor = 1f;
-		_renderer.scale(scaleFactor, scaleFactor, scaleFactor);
+		_renderer.scaleModel(scaleFactor);
 	}	
 }
diff --git a/contrib/mobile/androidGModel.cpp b/contrib/mobile/androidGModel.cpp
index 0827a1aa07362e434fe6a8f996cea965022bcce5..17ecf573e5ec0332b446ddc4ecab59b2f1d990d3 100644
--- a/contrib/mobile/androidGModel.cpp
+++ b/contrib/mobile/androidGModel.cpp
@@ -17,10 +17,12 @@
 #include "drawContext.h"
 
 onelab::server *getOnelab() {return onelab::server::instance();}
-
+extern "C"
+{
 static JavaVM *gJavaVM;
 static JNIEnv *env;
 static jobject gCallbackObject = NULL;
+};
 
 class MobileMessage : public GmshMessage
 {
@@ -94,6 +96,29 @@ void requestRender()
 	env->DeleteLocalRef(jClass);
 }
 
+void getBitmapFromString(const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth)
+{
+	if(!gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
+	jclass jClass = env->FindClass("org/geuz/onelab/StringTexture"); 
+	if(jClass == 0)
+		return;
+	jstring jtext = env->NewStringUTF(text);
+	jmethodID mid = env->GetStaticMethodID(jClass, "getHeightFromString", "(Ljava/lang/String;I)I");
+	*height = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+	mid = env->GetStaticMethodID(jClass, "getWidthFromString", "(Ljava/lang/String;I)I");
+	*width = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+	if(realWidth != NULL){
+		mid = env->GetStaticMethodID(jClass, "getRealWidthFromString", "(Ljava/lang/String;I)I");
+		*realWidth = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+	}
+	mid = env->GetStaticMethodID(jClass, "getBytesFromString", "(Ljava/lang/String;I)[B");
+	jobject jbuffer = env->CallObjectMethod(gCallbackObject, mid, jtext, textsize);
+	jbyteArray *jarray = reinterpret_cast<jbyteArray*>(&jbuffer);
+	*map = (unsigned char *) malloc((*height)*(*width));
+	env->GetByteArrayRegion(*jarray, 0, (*height)*(*width), (jbyte*)*map);
+	env->DeleteLocalRef(jClass);
+}
+
 extern "C" {
 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
 	gJavaVM = vm;
diff --git a/contrib/mobile/androidGModel.h b/contrib/mobile/androidGModel.h
index 21192e45a3d46be22d3a1840ac3eea15587c5ac5..9ae8acdf33eeda61f4794b196cd17ad01979845e 100644
--- a/contrib/mobile/androidGModel.h
+++ b/contrib/mobile/androidGModel.h
@@ -5,7 +5,7 @@
 #ifndef _Included_org_geuz_onelab_Gmsh
 #define _Included_org_geuz_onelab_Gmsh
 void requestRender();
-unsigned char *getBitmapFromString(const char *text);
+void getBitmapFromString(const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth=NULL);
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/contrib/mobile/drawContext.cpp b/contrib/mobile/drawContext.cpp
index fa5875efae988ffbb83be123a7666d8b238b79fc..49fbffd94f57c3af22b05d4e16b7721c10cd0654 100644
--- a/contrib/mobile/drawContext.cpp
+++ b/contrib/mobile/drawContext.cpp
@@ -34,6 +34,7 @@
 #include <gmsh/onelabUtils.h>
 #include <gmsh/PView.h>
 #include <gmsh/PViewOptions.h>
+#include <gmsh/PViewData.h>
 #include <gmsh/Context.h>
 #include <gmsh/StringUtils.h>
 
@@ -43,6 +44,7 @@
 #endif
 
 #include "drawContext.h"
+#include "drawString.h"
 #include "Trackball.h"
 
 static bool locked = false;
@@ -340,101 +342,115 @@ void drawContext::drawScale()
 	glPushMatrix();
 	glLoadIdentity();
 	// Draw the scale bar
-	if(PView::list.size() < 1) return;
-	PView *p = PView::list[PView::list.size()-1];
-	PViewOptions *opt = p->getOptions();
+	int nPview = 0;
+	for(int i=0; i<PView::list.size();i++){
+		PView *p = PView::list[i];
+		PViewOptions *opt = p->getOptions();
+		if(!opt->visible) continue;
     
-	double width = 6*(this->_right -this->_left) / 10.;
-	double height = (this->_top - this->_bottom) / 20.;
-	double box = width / (opt->nbIso ? opt->nbIso : 1);
-	double xmin = this->_left + (this->_right - this->_left -width)/2.;
-	double ymin = this->_bottom + height;
+		double width = 6*(this->_right -this->_left) / 10.;
+		double height = (this->_top - this->_bottom) / 20.;
+		double box = width / (opt->nbIso ? opt->nbIso : 1);
+		double xmin = this->_left + (this->_right - this->_left -width)/2.;
+		double ymin = this->_bottom + height + 2*height*nPview;
     
-    GLfloat *vertex = (GLfloat *)malloc(opt->nbIso*3*4*sizeof(GLfloat));
-    GLubyte *color = (GLubyte *)malloc(opt->nbIso*4*4*sizeof(GLubyte));
-	for(int i = 0; i < opt->nbIso; i++){
-		if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric)
-		{
-			unsigned int col = opt->getColor(i, opt->nbIso);
-			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
-			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
-			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
-			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
-			vertex[i*3*4+0] = xmin + i * box;
-			vertex[i*3*4+1] = ymin;
-			vertex[i*3*4+2] = 0.;
-			vertex[i*3*4+3] = xmin + i * box;
-			vertex[i*3*4+4] = ymin + height;
-			vertex[i*3*4+5] = 0.;
-			vertex[i*3*4+6] = xmin + (i + 1) * box;
-			vertex[i*3*4+7] = ymin;
-			vertex[i*3*4+8] = 0.;
-			vertex[i*3*4+9] = xmin + (i + 1) * box;
-			vertex[i*3*4+10] = ymin + height;
-			vertex[i*3*4+11] = 0.;
-		}
-		else if(opt->intervalsType == PViewOptions::Continuous)
-		{
-			double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
-			double v1 = opt->tmpMin + i * dv;
-			unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
-			color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
-			color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
-			color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
-			color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
-			vertex[i*3*4+0] = xmin + i * box;
-			vertex[i*3*4+1] = ymin;
-			vertex[i*3*4+2] = 0.;
-			vertex[i*3*4+3] = xmin + i * box;
-			vertex[i*3*4+4] = ymin + height;
-			vertex[i*3*4+5] = 0.;
-			double v2 = opt->tmpMin + (i + 1) * dv;
-            unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
-			color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
-			color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
-			color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
-			color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
-			vertex[i*3*4+6] = xmin + (i + 1) * box;
-			vertex[i*3*4+7] = ymin;
-			vertex[i*3*4+8] = 0.;
-			vertex[i*3*4+9] = xmin + (i + 1) * box;
-			vertex[i*3*4+10] = ymin + height;
-			vertex[i*3*4+11] = 0.;
+		GLfloat *vertex = (GLfloat *)malloc(opt->nbIso*3*4*sizeof(GLfloat));
+		GLubyte *color = (GLubyte *)malloc(opt->nbIso*4*4*sizeof(GLubyte));
+		for(int i = 0; i < opt->nbIso; i++){
+			if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric)
+			{
+				unsigned int col = opt->getColor(i, opt->nbIso);
+				color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+				color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+				color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+				color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+				vertex[i*3*4+0] = xmin + i * box;
+				vertex[i*3*4+1] = ymin;
+				vertex[i*3*4+2] = 0.;
+				vertex[i*3*4+3] = xmin + i * box;
+				vertex[i*3*4+4] = ymin + height;
+				vertex[i*3*4+5] = 0.;
+				vertex[i*3*4+6] = xmin + (i + 1) * box;
+				vertex[i*3*4+7] = ymin;
+				vertex[i*3*4+8] = 0.;
+				vertex[i*3*4+9] = xmin + (i + 1) * box;
+				vertex[i*3*4+10] = ymin + height;
+				vertex[i*3*4+11] = 0.;
+			}
+			else if(opt->intervalsType == PViewOptions::Continuous)
+			{
+				double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
+				double v1 = opt->tmpMin + i * dv;
+				unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
+				color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
+				color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
+				color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
+				color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
+				vertex[i*3*4+0] = xmin + i * box;
+				vertex[i*3*4+1] = ymin;
+				vertex[i*3*4+2] = 0.;
+				vertex[i*3*4+3] = xmin + i * box;
+				vertex[i*3*4+4] = ymin + height;
+				vertex[i*3*4+5] = 0.;
+				double v2 = opt->tmpMin + (i + 1) * dv;
+				unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
+				color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
+				color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
+				color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
+				color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
+				vertex[i*3*4+6] = xmin + (i + 1) * box;
+				vertex[i*3*4+7] = ymin;
+				vertex[i*3*4+8] = 0.;
+				vertex[i*3*4+9] = xmin + (i + 1) * box;
+				vertex[i*3*4+10] = ymin + height;
+				vertex[i*3*4+11] = 0.;
+			}
+			else
+			{
+				unsigned int col = opt->getColor(i, opt->nbIso);
+				color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+				color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+				color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+				color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+				vertex[i*3*4+0] = xmin + i * box;
+				vertex[i*3*4+1] = ymin;
+				vertex[i*3*4+2] = 0.;
+				vertex[i*3*4+3] = xmin + i * box;
+				vertex[i*3*4+4] = ymin + height;
+				vertex[i*3*4+5] = 0.;
+				vertex[i*3*4+6] = xmin + (i + 1) * box;
+				vertex[i*3*4+7] = ymin;
+				vertex[i*3*4+8] = 0.;
+				vertex[i*3*4+9] = xmin + (i + 1) * box;
+				vertex[i*3*4+10] = ymin + height;
+				vertex[i*3*4+11] = 0.;
+			}
 		}
+	
+		glVertexPointer(3, GL_FLOAT, 0, vertex);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
+		glEnableClientState(GL_COLOR_ARRAY);
+		if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric || opt->intervalsType == PViewOptions::Continuous)
+			glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
 		else
-		{
-			unsigned int col = opt->getColor(i, opt->nbIso);
-			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
-			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
-			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
-			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
-			vertex[i*3*4+0] = xmin + i * box;
-			vertex[i*3*4+1] = ymin;
-			vertex[i*3*4+2] = 0.;
-			vertex[i*3*4+3] = xmin + i * box;
-			vertex[i*3*4+4] = ymin + height;
-			vertex[i*3*4+5] = 0.;
-			vertex[i*3*4+6] = xmin + (i + 1) * box;
-			vertex[i*3*4+7] = ymin;
-			vertex[i*3*4+8] = 0.;
-			vertex[i*3*4+9] = xmin + (i + 1) * box;
-			vertex[i*3*4+10] = ymin + height;
-			vertex[i*3*4+11] = 0.;
+			glDrawArrays(GL_LINES, 0, opt->nbIso*4);
+		glDisableClientState(GL_COLOR_ARRAY);
+		glDisableClientState(GL_VERTEX_ARRAY);
+		free(vertex);
+		free(color);
+		char label[1024];
+		drawString *lbl = new drawString(p->getData()->getName().c_str(), 16);
+		lbl->draw(xmin+width/2, ymin-height/2, 0., _width/(_right-_left), _height/(_top-_bottom));
+		drawString *val = new drawString(p->getData()->getName().c_str(), 14);
+		for(int i = 0; i < 3; i++) {
+			double v = opt->getScaleValue(i, 3, opt->tmpMin, opt->tmpMax);
+			sprintf(label, opt->format.c_str(), v);
+			val->setText(label);
+			val->draw(xmin+i*width/2, ymin+height/2, 0., _width/(_right-_left), _height/(_top-_bottom));
 		}
+		nPview++;
 	}
-	
-	glVertexPointer(3, GL_FLOAT, 0, vertex);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
-	glEnableClientState(GL_COLOR_ARRAY);
-	if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric || opt->intervalsType == PViewOptions::Continuous)
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
-	else
-		glDrawArrays(GL_LINES, 0, opt->nbIso*4);
-	glDisableClientState(GL_COLOR_ARRAY);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	free(vertex);
-	free(color);
 	glPopMatrix();
 }
 
@@ -491,7 +507,7 @@ void drawContext::drawGeom()
 	glLineWidth(1);
 }
 
-void drawContext::drawAxes(double x0, double y0, double z0, double h)
+void drawContext::drawAxes(float x0, float y0, float z0, float h)
 {
 	glLineWidth(1.);
 	glPushMatrix();
@@ -500,7 +516,7 @@ void drawContext::drawAxes(double x0, double y0, double z0, double h)
 	glMultMatrixf(_rotatef);
 	glTranslatef(-x0, -y0, -z0);
     
-    const GLfloat axes[] = {
+  const GLfloat axes[] = {
 		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
 		(GLfloat)(x0+h), (GLfloat)y0, (GLfloat)z0,
 		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
@@ -508,21 +524,27 @@ void drawContext::drawAxes(double x0, double y0, double z0, double h)
 		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
 		(GLfloat)x0, (GLfloat)y0, (GLfloat)(z0+h),
 	};
-    const GLubyte colors[] = {
-        255, 0, 0, 255,
-        255, 0, 0, 255,
-        0, 0, 255, 255,
-        0, 0, 255, 255,
-        0, 255, 0, 255,
-        0, 255, 0, 255,
-    };
+  GLfloat colors[] = {
+		1., 0, 0, 1.,
+		1., 0, 0, 1.,
+		0, 0, 1., 1.,
+		0, 0, 1., 1.,
+		0, 1., 0, 1.,
+		0, 1., 0, 1.,
+	};
 	glVertexPointer(3, GL_FLOAT, 0, axes);
 	glEnableClientState(GL_VERTEX_ARRAY);
-    glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
-    glEnableClientState(GL_COLOR_ARRAY);
+	glColorPointer(4, GL_FLOAT, 0, colors);
+	glEnableClientState(GL_COLOR_ARRAY);
 	glDrawArrays(GL_LINES, 0, 6);
 	glDisableClientState(GL_VERTEX_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	drawString *x = new drawString("X", 16,colors);
+	x->draw(x0+h, y0, z0, _width/(_right-_left), _height/(_top-_bottom));
+	drawString *y = new drawString("Y", 16,colors+8);
+	y->draw(x0, y0+h, z0, _width/(_right-_left), _height/(_top-_bottom));
+	drawString *z = new drawString("Z", 16,colors+16);
+	z->draw(x0, y0, z0+h, _width/(_right-_left), _height/(_top-_bottom));
 	glPopMatrix();
 	glLineWidth(1);
 }
@@ -577,7 +599,7 @@ void drawContext::drawView()
 	this->drawPost();
 	if(_showGeom) this->drawGeom();
 	if(_showMesh) this->drawMesh();
-	//this->drawScale();
+	this->drawScale();
 	checkGlError("Draw model,post-pro,...");
 }
 
diff --git a/contrib/mobile/drawContext.h b/contrib/mobile/drawContext.h
index 8d0b665108b920be1d0df99fc5547154f93c1702..4a00d9bf933709a9504935b524f8157852b3aea1 100644
--- a/contrib/mobile/drawContext.h
+++ b/contrib/mobile/drawContext.h
@@ -49,7 +49,7 @@ public:
 	float getScale(int i) {if(i>=0 && i<3) return this->_scale[i]; return 0;}
 	void initView(int w, int h);
 	void drawView();
-	void drawAxes(double x0=0., double y0=0., double z0=0., double h=0.5);
+	void drawAxes(float x0=0., float y0=0., float z0=0., float h=0.5);
 	void drawGeom();
 	void drawMesh();
 	void drawPost();
diff --git a/contrib/mobile/drawString.cpp b/contrib/mobile/drawString.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..07e13b166f4a6ffb84bf0be5851ef9aeeef6063f
--- /dev/null
+++ b/contrib/mobile/drawString.cpp
@@ -0,0 +1,73 @@
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include "drawString.h"
+
+drawString::drawString(std::string text, int size, float color[4])
+{
+	_size = size;
+	if(color == NULL)
+		this->setColor(0.0f, 0.0f, 0.0f, 1.0f);
+	else
+		this->setColor(color);
+	this->setText(text);
+}
+
+void drawString::setText(std::string text)
+{
+	this->_text = text;
+	getBitmapFromString(this->_text.c_str(), _size, &this->_map, &this->_height, &this->_width, &this->_realWidth);
+}
+
+void drawString::setColor(float color[4])
+{
+	_color[0] = color[0];
+	_color[1] = color[1];
+	_color[2] = color[2];
+	_color[3] = color[3];
+}
+
+void drawString::setColor(float r, float g, float b, float a)
+{
+	_color[0] = r;
+	_color[1] = g;
+	_color[2] = b;
+	_color[3] = a;
+}
+void drawString::draw(float x, float y, float z, float w, float h, bool center)
+{
+	GLuint textureId;
+	glGenTextures(1, &textureId);
+	glBindTexture(GL_TEXTURE_2D, textureId);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, _width, _height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, _map);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glColor4f(_color[0], _color[1], _color[2], _color[3]);
+	if(center)
+		x-=(float)_realWidth/w/2;
+	GLfloat vertex[] = {
+		 x, y, z, // bottom left
+		 x, y+(float)_height/h, z, // top left
+		 x+(float)_width/w, y, z, // bottom right
+		 x+(float)_width/w, y+(float)_height/h, z, // top right
+	};
+	GLfloat texture[] = {
+		0.0f, 1.0f, // top left
+		0.0f, 0.0f, // bottom left
+		1.0f, 1.0f, // top right
+		1.0f, 0.0f, // bottom right
+	};
+	glEnable(GL_TEXTURE_2D);
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDisable(GL_LIGHTING);
+	glVertexPointer(3, GL_FLOAT, 0, vertex);
+	glTexCoordPointer(2, GL_FLOAT, 0, texture);
+	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	glDisable(GL_TEXTURE_2D);
+	glDisable(GL_BLEND);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	glDeleteTextures(1, &textureId);
+}
diff --git a/contrib/mobile/drawString.h b/contrib/mobile/drawString.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a2640bbae61192cf395fe08e4620cd5e61615bd
--- /dev/null
+++ b/contrib/mobile/drawString.h
@@ -0,0 +1,23 @@
+#include <string>
+
+#include "androidGModel.h"
+
+class drawString
+{
+private:
+	bool _changed; // UNUSED ??
+	std::string _text; // Text to draw
+	float _color[4]; // Text color
+	int _size; // Text size in px
+	int _height, _width, _realWidth; // Size of the texture in px
+	unsigned char *_map;
+
+public:
+	drawString(std::string text, int size=12, float *color=NULL);
+	~drawString(){if(_map)free(_map);}
+
+	void setText(std::string text);
+	void setColor(float *color);
+	void setColor(float r, float g, float b, float a);
+	void draw(float x, float y, float z, float w, float h, bool center=true);
+};