From 4e01de31f769f3b6be32f8164021d6d71e10f397 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Fri, 13 Sep 2013 14:41:14 +0200
Subject: [PATCH] some event mechanism

---
 .../src/org/oscim/android/MapView.java        |   5 +-
 .../android/input/AndroidMotionEvent.java     |  11 +-
 .../layers/tile/bitmap/BitmapTileLayer.java   |  75 +++++++++----
 vtm-gdx/src/org/oscim/gdx/GdxMotionEvent.java |   9 +-
 vtm/src/org/oscim/event/EventDispatcher.java  |   7 ++
 vtm/src/org/oscim/event/EventListener.java    |   5 +
 .../{backend/input => event}/KeyEvent.java    |  10 +-
 vtm/src/org/oscim/event/MapEvent.java         |  13 +++
 .../{backend/input => event}/MotionEvent.java |  13 ++-
 vtm/src/org/oscim/event/UpdateEvent.java      |  16 +++
 .../org/oscim/layers/CustomRenderLayer.java   |  18 +--
 vtm/src/org/oscim/layers/InputLayer.java      |   4 +-
 vtm/src/org/oscim/layers/Layer.java           |  42 +++----
 vtm/src/org/oscim/layers/MapEventLayer.java   |  20 +++-
 .../layers/marker/ItemizedIconLayer.java      |   2 +-
 vtm/src/org/oscim/layers/tile/TileLayer.java  |  48 ++++++--
 .../layers/tile/bitmap/BitmapTileLayer.java   |  78 +++++++++----
 .../layers/tile/vector/BuildingLayer.java     |   2 +-
 .../tile/vector/labeling/LabelLayer.java      | 104 ++++++++++++------
 vtm/src/org/oscim/map/Layers.java             |  20 ++--
 vtm/src/org/oscim/map/Map.java                |  47 +++++++-
 21 files changed, 405 insertions(+), 144 deletions(-)
 create mode 100644 vtm/src/org/oscim/event/EventDispatcher.java
 create mode 100644 vtm/src/org/oscim/event/EventListener.java
 rename vtm/src/org/oscim/{backend/input => event}/KeyEvent.java (80%)
 create mode 100644 vtm/src/org/oscim/event/MapEvent.java
 rename vtm/src/org/oscim/{backend/input => event}/MotionEvent.java (85%)
 create mode 100644 vtm/src/org/oscim/event/UpdateEvent.java

diff --git a/vtm-android/src/org/oscim/android/MapView.java b/vtm-android/src/org/oscim/android/MapView.java
index f4db1948..e3e36d31 100644
--- a/vtm-android/src/org/oscim/android/MapView.java
+++ b/vtm-android/src/org/oscim/android/MapView.java
@@ -219,7 +219,7 @@ public class MapView extends RelativeLayout {
 		mPausing = false;
 	}
 
-	AndroidMotionEvent mMotionEvent = new AndroidMotionEvent();
+	AndroidMotionEvent mMotionEvent = new AndroidMotionEvent(this);
 
 	@Override
 	public boolean onTouchEvent(android.view.MotionEvent motionEvent) {
@@ -228,8 +228,9 @@ public class MapView extends RelativeLayout {
 			return false;
 
 		mMotionEvent.wrap(motionEvent);
+		mMap.handleMotionEvent(mMotionEvent);
 
-		return mMap.getLayers().handleMotionEvent(mMotionEvent);
+		return true;
 	}
 
 	// synchronized ???
diff --git a/vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java b/vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java
index 1db6c00a..7715510b 100644
--- a/vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java
+++ b/vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java
@@ -13,10 +13,19 @@
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
 package org.oscim.android.input;
-import org.oscim.backend.input.MotionEvent;
+import org.oscim.event.MotionEvent;
 
 public class AndroidMotionEvent extends MotionEvent {
 
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public AndroidMotionEvent(Object source) {
+		super(source);
+	}
+
 	android.view.MotionEvent mEvent;
 
 	public void wrap(android.view.MotionEvent e){
diff --git a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/bitmap/BitmapTileLayer.java b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
index 7826b748..e8d35b4f 100644
--- a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
+++ b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
@@ -19,6 +19,8 @@ import java.net.URL;
 import org.oscim.backend.canvas.Bitmap;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
+import org.oscim.event.MapEvent;
+import org.oscim.event.UpdateEvent;
 import org.oscim.gdx.client.GwtBitmap;
 import org.oscim.layers.tile.TileLayer;
 import org.oscim.layers.tile.bitmap.TileSource.FadeStep;
@@ -48,33 +50,66 @@ public class BitmapTileLayer extends TileLayer<TileLoader> {
 		mFade = mTileSource.getFadeSteps();
 	}
 
+	//	@Override
+	//	public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
+	//		super.onUpdate(pos, changed, clear);
+	//
+	//		if (mFade == null) {
+	//			mRenderLayer.setBitmapAlpha(1);
+	//			return;
+	//		}
+	//
+	//		float alpha = 0;
+	//		for (FadeStep f : mFade) {
+	//			if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
+	//				continue;
+	//
+	//			if (f.alphaStart == f.alphaEnd) {
+	//				alpha = f.alphaStart;
+	//				break;
+	//			}
+	//			double range = f.scaleEnd / f.scaleStart;
+	//			float a = (float)((range - (pos.scale / f.scaleStart)) / range);
+	//			a = FastMath.clamp(a, 0, 1);
+	//			// interpolate alpha between start and end
+	//			alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
+	//			break;
+	//		}
+	//
+	//		mRenderLayer.setBitmapAlpha(alpha);
+	//	}
+
 	@Override
-	public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
-		super.onUpdate(pos, changed, clear);
+	public void handleEvent(MapEvent event) {
+		super.handleEvent(event);
 
-		if (mFade == null) {
-			mRenderLayer.setBitmapAlpha(1);
-			return;
-		}
+		if (event instanceof UpdateEvent) {
 
-		float alpha = 0;
-		for (FadeStep f : mFade) {
-			if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
-				continue;
+			if (mFade == null) {
+				mRenderLayer.setBitmapAlpha(1);
+				return;
+			}
+			MapPosition pos = mMap.getMapPosition();
 
-			if (f.alphaStart == f.alphaEnd) {
-				alpha = f.alphaStart;
+			float alpha = 0;
+			for (FadeStep f : mFade) {
+				if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
+					continue;
+
+				if (f.alphaStart == f.alphaEnd) {
+					alpha = f.alphaStart;
+					break;
+				}
+				double range = f.scaleEnd / f.scaleStart;
+				float a = (float) ((range - (pos.scale / f.scaleStart)) / range);
+				a = FastMath.clamp(a, 0, 1);
+				// interpolate alpha between start and end
+				alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
 				break;
 			}
-			double range = f.scaleEnd / f.scaleStart;
-			float a = (float)((range - (pos.scale / f.scaleStart)) / range);
-			a = FastMath.clamp(a, 0, 1);
-			// interpolate alpha between start and end
-			alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
-			break;
-		}
 
-		mRenderLayer.setBitmapAlpha(alpha);
+			mRenderLayer.setBitmapAlpha(alpha);
+		}
 	}
 
 	@Override
diff --git a/vtm-gdx/src/org/oscim/gdx/GdxMotionEvent.java b/vtm-gdx/src/org/oscim/gdx/GdxMotionEvent.java
index f50320b7..598c76fd 100644
--- a/vtm-gdx/src/org/oscim/gdx/GdxMotionEvent.java
+++ b/vtm-gdx/src/org/oscim/gdx/GdxMotionEvent.java
@@ -1,12 +1,17 @@
 package org.oscim.gdx;
 
-import org.oscim.backend.input.MotionEvent;
+import org.oscim.event.MotionEvent;
 
-import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.InputProcessor;
 
 public class GdxMotionEvent extends MotionEvent implements InputProcessor{
 
+	private static final long serialVersionUID = 1L;
+
+	public GdxMotionEvent(Object source) {
+		super(source);
+	}
+
 	@Override
 	public int getAction() {
 		return 0;
diff --git a/vtm/src/org/oscim/event/EventDispatcher.java b/vtm/src/org/oscim/event/EventDispatcher.java
new file mode 100644
index 00000000..1b0667cb
--- /dev/null
+++ b/vtm/src/org/oscim/event/EventDispatcher.java
@@ -0,0 +1,7 @@
+package org.oscim.event;
+
+public interface EventDispatcher {
+
+	public void addListener(String type, EventListener listener);
+	public void removeListener(String type, EventListener listener);
+}
diff --git a/vtm/src/org/oscim/event/EventListener.java b/vtm/src/org/oscim/event/EventListener.java
new file mode 100644
index 00000000..fda4d0b6
--- /dev/null
+++ b/vtm/src/org/oscim/event/EventListener.java
@@ -0,0 +1,5 @@
+package org.oscim.event;
+
+public interface EventListener {
+	public void handleEvent(MapEvent event);
+}
diff --git a/vtm/src/org/oscim/backend/input/KeyEvent.java b/vtm/src/org/oscim/event/KeyEvent.java
similarity index 80%
rename from vtm/src/org/oscim/backend/input/KeyEvent.java
rename to vtm/src/org/oscim/event/KeyEvent.java
index a60df751..39c22be2 100644
--- a/vtm/src/org/oscim/backend/input/KeyEvent.java
+++ b/vtm/src/org/oscim/event/KeyEvent.java
@@ -12,8 +12,14 @@
  * You should have received a copy of the GNU Lesser General Public License along with
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package org.oscim.backend.input;
+package org.oscim.event;
 
-public class KeyEvent {
+public class KeyEvent extends MapEvent{
+
+	private static final long serialVersionUID = 1L;
+
+	public KeyEvent(Object source) {
+		super(source);
+	}
 
 }
diff --git a/vtm/src/org/oscim/event/MapEvent.java b/vtm/src/org/oscim/event/MapEvent.java
new file mode 100644
index 00000000..f6cbf3f1
--- /dev/null
+++ b/vtm/src/org/oscim/event/MapEvent.java
@@ -0,0 +1,13 @@
+package org.oscim.event;
+
+import java.util.EventObject;
+
+public class MapEvent extends EventObject {
+
+	private static final long serialVersionUID = 1L;
+
+
+	public MapEvent(Object source) {
+		super(source);
+	}
+}
diff --git a/vtm/src/org/oscim/backend/input/MotionEvent.java b/vtm/src/org/oscim/event/MotionEvent.java
similarity index 85%
rename from vtm/src/org/oscim/backend/input/MotionEvent.java
rename to vtm/src/org/oscim/event/MotionEvent.java
index 2db18042..e2c5f2c7 100644
--- a/vtm/src/org/oscim/backend/input/MotionEvent.java
+++ b/vtm/src/org/oscim/event/MotionEvent.java
@@ -12,9 +12,18 @@
  * You should have received a copy of the GNU Lesser General Public License along with
  * this program. If not, see <http://www.gnu.org/licenses/>.
  */
-package org.oscim.backend.input;
+package org.oscim.event;
 
-public abstract class MotionEvent {
+
+public abstract class MotionEvent extends MapEvent {
+
+	private static final long serialVersionUID = 1L;
+
+	public static final String TYPE = "MotionEvent";
+
+	public MotionEvent(Object source) {
+		super(source);
+	}
 
 	public static final int ACTION_DOWN = 0;
 	public static final int ACTION_UP = 1;
diff --git a/vtm/src/org/oscim/event/UpdateEvent.java b/vtm/src/org/oscim/event/UpdateEvent.java
new file mode 100644
index 00000000..1a650b11
--- /dev/null
+++ b/vtm/src/org/oscim/event/UpdateEvent.java
@@ -0,0 +1,16 @@
+package org.oscim.event;
+
+
+public class UpdateEvent extends MapEvent {
+
+	private static final long serialVersionUID = 1L;
+	public static final String TYPE = "UpdateEvent";
+
+	public UpdateEvent(Object source) {
+		super(source);
+	}
+
+	public boolean positionChanged;
+	public boolean clearMap;
+
+}
diff --git a/vtm/src/org/oscim/layers/CustomRenderLayer.java b/vtm/src/org/oscim/layers/CustomRenderLayer.java
index 67435876..817d8cc2 100644
--- a/vtm/src/org/oscim/layers/CustomRenderLayer.java
+++ b/vtm/src/org/oscim/layers/CustomRenderLayer.java
@@ -44,14 +44,14 @@ public class CustomRenderLayer extends Layer {
 
 	private int someConccurentVariable;
 
-	@Override
-	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
-
-		synchronized (mRenderer) {
-			// chang
-			someConccurentVariable++;
-		}
-
-	}
+//	@Override
+//	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+//
+//		synchronized (mRenderer) {
+//			// chang
+//			someConccurentVariable++;
+//		}
+//
+//	}
 
 }
diff --git a/vtm/src/org/oscim/layers/InputLayer.java b/vtm/src/org/oscim/layers/InputLayer.java
index c1fff873..40108671 100644
--- a/vtm/src/org/oscim/layers/InputLayer.java
+++ b/vtm/src/org/oscim/layers/InputLayer.java
@@ -15,8 +15,8 @@
  */
 package org.oscim.layers;
 
-import org.oscim.backend.input.KeyEvent;
-import org.oscim.backend.input.MotionEvent;
+import org.oscim.event.KeyEvent;
+import org.oscim.event.MotionEvent;
 import org.oscim.map.Map;
 
 public abstract class InputLayer extends Layer {
diff --git a/vtm/src/org/oscim/layers/Layer.java b/vtm/src/org/oscim/layers/Layer.java
index c9da60ad..9fa6ac13 100644
--- a/vtm/src/org/oscim/layers/Layer.java
+++ b/vtm/src/org/oscim/layers/Layer.java
@@ -14,11 +14,12 @@
  */
 package org.oscim.layers;
 
-import org.oscim.core.MapPosition;
+
 import org.oscim.map.Map;
 import org.oscim.renderer.LayerRenderer;
 
-public abstract class Layer {
+public abstract class Layer  {
+
 	public Layer(Map map) {
 		mMap = map;
 	}
@@ -32,33 +33,34 @@ public abstract class Layer {
 		return mRenderer;
 	}
 
-	/**
-	 */
 	public void setEnabled(boolean enabled) {
 		mEnabled = enabled;
 	}
 
-	/**
-	 */
 	public boolean isEnabled() {
 		return mEnabled;
 	}
 
-	/**
-	 * Called before each frame render request (on main thread).
-	 *
-	 * @param mapPosition
-	 *            current MapPosition
-	 * @param changed
-	 *            true when MapPosition has changed since last call
-	 * @param clear
-	 *            Clear all resources that depend on previous map state. Most
-	 *            importantly all resources from previous GL context (hold by
-	 *            RenderLayer)
-	 */
-	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+//	/**
+//	 * Called before each frame render request (on main thread).
+//	 *
+//	 * @param mapPosition
+//	 *            current MapPosition
+//	 * @param changed
+//	 *            true when MapPosition has changed since last call
+//	 * @param clear
+//	 *            Clear all resources that depend on previous map state. Most
+//	 *            importantly all resources from previous GL context (hold by
+//	 *            RenderLayer)
+//	 */
+//	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+//
+//	}
 
-	}
+//	@Override
+//	public void handleEvent(MapEvent e){
+//
+//	}
 
 	/**
 	 * Override to perform clean up of resources before shutdown. By default
diff --git a/vtm/src/org/oscim/layers/MapEventLayer.java b/vtm/src/org/oscim/layers/MapEventLayer.java
index 40c64a86..136e0a62 100644
--- a/vtm/src/org/oscim/layers/MapEventLayer.java
+++ b/vtm/src/org/oscim/layers/MapEventLayer.java
@@ -15,8 +15,10 @@
 package org.oscim.layers;
 
 import org.oscim.backend.Log;
-import org.oscim.backend.input.MotionEvent;
 import org.oscim.core.Tile;
+import org.oscim.event.EventListener;
+import org.oscim.event.MapEvent;
+import org.oscim.event.MotionEvent;
 import org.oscim.map.Map;
 import org.oscim.map.Viewport;
 
@@ -30,7 +32,7 @@ import org.oscim.map.Viewport;
  *        http://en.wikipedia.org/wiki/Viterbi_algorithm
  */
 
-public class MapEventLayer extends InputLayer {
+public class MapEventLayer extends Layer implements EventListener {
 	private static final boolean debug = false;
 	private static final String TAG = MapEventLayer.class.getName();
 
@@ -65,10 +67,21 @@ public class MapEventLayer extends InputLayer {
 
 	public MapEventLayer(Map map) {
 		super(map);
+		map.addListener(MotionEvent.TYPE, this);
 		mMapPosition = map.getViewport();
 		mTracker = new VelocityTracker();
 	}
 
+	@Override
+	public void onDetach() {
+		mMap.removeListener(MotionEvent.TYPE, this);
+	}
+
+	@Override
+	public void handleEvent(MapEvent event){
+		if (event instanceof MotionEvent)
+			onTouchEvent((MotionEvent)event);
+	}
 	//private long mPrevTime;
 
 	private boolean mEnableRotation = true;
@@ -96,7 +109,7 @@ public class MapEventLayer extends InputLayer {
 		mEnableZoom = enable;
 	}
 
-	@Override
+	//@Override
 	public boolean onTouchEvent(MotionEvent e) {
 
 		//mPrevTime = e.getTime();
@@ -441,5 +454,4 @@ public class MapEventLayer extends InputLayer {
 		//	return sum;
 		//}
 	}
-
 }
diff --git a/vtm/src/org/oscim/layers/marker/ItemizedIconLayer.java b/vtm/src/org/oscim/layers/marker/ItemizedIconLayer.java
index 5b1a27a1..a193b1db 100644
--- a/vtm/src/org/oscim/layers/marker/ItemizedIconLayer.java
+++ b/vtm/src/org/oscim/layers/marker/ItemizedIconLayer.java
@@ -17,9 +17,9 @@ package org.oscim.layers.marker;
 
 import java.util.List;
 
-import org.oscim.backend.input.MotionEvent;
 import org.oscim.core.BoundingBox;
 import org.oscim.core.Point;
+import org.oscim.event.MotionEvent;
 import org.oscim.map.Map;
 import org.oscim.map.Viewport;
 
diff --git a/vtm/src/org/oscim/layers/tile/TileLayer.java b/vtm/src/org/oscim/layers/tile/TileLayer.java
index e90c17b5..23a72a2a 100644
--- a/vtm/src/org/oscim/layers/tile/TileLayer.java
+++ b/vtm/src/org/oscim/layers/tile/TileLayer.java
@@ -16,14 +16,16 @@ package org.oscim.layers.tile;
 
 import java.util.ArrayList;
 
-import org.oscim.core.MapPosition;
+import org.oscim.event.EventListener;
+import org.oscim.event.MapEvent;
+import org.oscim.event.UpdateEvent;
 import org.oscim.layers.Layer;
 import org.oscim.map.Map;
 import org.oscim.tiling.TileLoader;
 import org.oscim.tiling.TileManager;
 import org.oscim.tiling.TileRenderer;
 
-public abstract class TileLayer<T extends TileLoader> extends Layer {
+public abstract class TileLayer<T extends TileLoader> extends Layer implements EventListener {
 	//private final static String TAG = TileLayer.class.getName();
 	private final static int MAX_ZOOMLEVEL = 17;
 	private final static int MIN_ZOOMLEVEL = 2;
@@ -59,6 +61,8 @@ public abstract class TileLayer<T extends TileLoader> extends Layer {
 		// RenderLayer is working in GL Thread and actually
 		// drawing loaded tiles to screen.
 		mRenderer = mRenderLayer = new TileRenderer(mTileManager);
+
+		map.addListener(UpdateEvent.TYPE, this);
 	}
 
 	abstract protected T createLoader(TileManager tm);
@@ -67,22 +71,44 @@ public abstract class TileLayer<T extends TileLoader> extends Layer {
 		return (TileRenderer) mRenderer;
 	}
 
+	//	@Override
+	//	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+	//
+	//		if (clear || mInitial) {
+	//			mRenderLayer.clearTiles();
+	//			mTileManager.init(mInitial);
+	//			mInitial = false;
+	//			changed = true;
+	//		}
+	//
+	//		if (changed && mTileManager.update(mapPosition))
+	//			notifyLoaders();
+	//	}
+
 	@Override
-	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+	public void handleEvent(MapEvent event) {
+		if (event instanceof UpdateEvent) {
 
-		if (clear || mInitial) {
-			mRenderLayer.clearTiles();
-			mTileManager.init(mInitial);
-			mInitial = false;
-			changed = true;
+			UpdateEvent e = (UpdateEvent) event;
+
+			boolean changed = e.positionChanged;
+
+			if (e.clearMap || mInitial) {
+				mRenderLayer.clearTiles();
+				mTileManager.init(mInitial);
+				mInitial = false;
+				changed = true;
+			}
+
+			if (changed && mTileManager.update(mMap.getMapPosition()))
+				notifyLoaders();
 		}
-
-		if (changed && mTileManager.update(mapPosition))
-			notifyLoaders();
 	}
 
 	@Override
 	public void onDetach() {
+		mMap.removeListener(UpdateEvent.TYPE, this);
+
 		for (T loader : mTileLoader) {
 			loader.pause();
 			loader.interrupt();
diff --git a/vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java b/vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
index 89507469..cf843773 100644
--- a/vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
+++ b/vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
@@ -24,6 +24,8 @@ import org.oscim.backend.CanvasAdapter;
 import org.oscim.backend.canvas.Bitmap;
 import org.oscim.core.MapPosition;
 import org.oscim.core.Tile;
+import org.oscim.event.MapEvent;
+import org.oscim.event.UpdateEvent;
 import org.oscim.layers.tile.TileLayer;
 import org.oscim.layers.tile.bitmap.TileSource.FadeStep;
 import org.oscim.map.Map;
@@ -35,7 +37,7 @@ import org.oscim.tiling.TileManager;
 import org.oscim.utils.FastMath;
 
 
-public class BitmapTileLayer extends TileLayer<TileLoader> {
+public class BitmapTileLayer extends TileLayer<TileLoader>  {
 	private static final int TIMEOUT_CONNECT = 5000;
 	private static final int TIMEOUT_READ = 10000;
 	protected static final String TAG = BitmapTileLayer.class.getName();
@@ -50,33 +52,67 @@ public class BitmapTileLayer extends TileLayer<TileLoader> {
 
 	}
 
+
+//	@Override
+//	public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
+//		super.onUpdate(pos, changed, clear);
+//
+//		if (mFade == null) {
+//			mRenderLayer.setBitmapAlpha(1);
+//			return;
+//		}
+//
+//		float alpha = 0;
+//		for (FadeStep f : mFade) {
+//			if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
+//				continue;
+//
+//			if (f.alphaStart == f.alphaEnd) {
+//				alpha = f.alphaStart;
+//				break;
+//			}
+//			double range = f.scaleEnd / f.scaleStart;
+//			float a = (float)((range - (pos.scale / f.scaleStart)) / range);
+//			a = FastMath.clamp(a, 0, 1);
+//			// interpolate alpha between start and end
+//			alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
+//			break;
+//		}
+//
+//		mRenderLayer.setBitmapAlpha(alpha);
+//	}
+
 	@Override
-	public void onUpdate(MapPosition pos, boolean changed, boolean clear) {
-		super.onUpdate(pos, changed, clear);
+	public void handleEvent(MapEvent event) {
+		super.handleEvent(event);
 
-		if (mFade == null) {
-			mRenderLayer.setBitmapAlpha(1);
-			return;
-		}
+		if (event instanceof UpdateEvent){
 
-		float alpha = 0;
-		for (FadeStep f : mFade) {
-			if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
-				continue;
+			if (mFade == null) {
+				mRenderLayer.setBitmapAlpha(1);
+				return;
+			}
+			MapPosition pos = mMap.getMapPosition();
 
-			if (f.alphaStart == f.alphaEnd) {
-				alpha = f.alphaStart;
+			float alpha = 0;
+			for (FadeStep f : mFade) {
+				if (pos.scale < f.scaleStart || pos.scale > f.scaleEnd)
+					continue;
+
+				if (f.alphaStart == f.alphaEnd) {
+					alpha = f.alphaStart;
+					break;
+				}
+				double range = f.scaleEnd / f.scaleStart;
+				float a = (float)((range - (pos.scale / f.scaleStart)) / range);
+				a = FastMath.clamp(a, 0, 1);
+				// interpolate alpha between start and end
+				alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
 				break;
 			}
-			double range = f.scaleEnd / f.scaleStart;
-			float a = (float)((range - (pos.scale / f.scaleStart)) / range);
-			a = FastMath.clamp(a, 0, 1);
-			// interpolate alpha between start and end
-			alpha = a * f.alphaStart + (1 - a) * f.alphaEnd;
-			break;
-		}
 
-		mRenderLayer.setBitmapAlpha(alpha);
+			mRenderLayer.setBitmapAlpha(alpha);
+		}
 	}
 
 	@Override
diff --git a/vtm/src/org/oscim/layers/tile/vector/BuildingLayer.java b/vtm/src/org/oscim/layers/tile/vector/BuildingLayer.java
index feaeb4d9..18d64339 100644
--- a/vtm/src/org/oscim/layers/tile/vector/BuildingLayer.java
+++ b/vtm/src/org/oscim/layers/tile/vector/BuildingLayer.java
@@ -14,8 +14,8 @@
  */
 package org.oscim.layers.tile.vector;
 
-import org.oscim.backend.input.MotionEvent;
 import org.oscim.core.MapPosition;
+import org.oscim.event.MotionEvent;
 import org.oscim.layers.InputLayer;
 import org.oscim.map.Map;
 import org.oscim.renderer.ExtrusionRenderer;
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
index 15436643..5a492c67 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
@@ -14,54 +14,90 @@
  */
 package org.oscim.layers.tile.vector.labeling;
 
-import org.oscim.backend.input.MotionEvent;
-import org.oscim.core.MapPosition;
-import org.oscim.layers.InputLayer;
+import org.oscim.backend.Log;
+import org.oscim.event.EventListener;
+import org.oscim.event.MapEvent;
+import org.oscim.event.MotionEvent;
+import org.oscim.event.UpdateEvent;
+import org.oscim.layers.Layer;
 import org.oscim.map.Map;
 import org.oscim.tiling.TileRenderer;
 
-import org.oscim.backend.Log;
-
-public class LabelLayer extends InputLayer {
+public class LabelLayer extends Layer implements EventListener {
 	private final static String TAG = LabelLayer.class.getName();
-	final TextRenderer mTextRenderer;
+	private final TextRenderer mTextRenderer;
+
+	private int multi;
 
 	public LabelLayer(Map map, TileRenderer tileRenderLayer) {
 		super(map);
+		map.addListener(UpdateEvent.TYPE, this);
+		map.addListener(MotionEvent.TYPE, this);
 
 		//mTextLayer = new org.oscim.renderer.layers.TextRenderLayer(map, tileRenderLayer);
 		mTextRenderer = new TextRenderer(map, tileRenderLayer);
 		mRenderer = mTextRenderer;
 	}
 
-	@Override
-	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
-		if (clear)
-			mTextRenderer.clearLabels();
-	}
-
-	private int multi;
-
-	@Override
-	public boolean onTouchEvent(MotionEvent e) {
-		int action = e.getAction() & MotionEvent.ACTION_MASK;
-		if (action == MotionEvent.ACTION_POINTER_DOWN) {
-			multi++;
-			mTextRenderer.hold(true);
-		} else if (action == MotionEvent.ACTION_POINTER_UP) {
-			multi--;
-			if (multi == 0)
-				mTextRenderer.hold(false);
-		} else if (action == MotionEvent.ACTION_CANCEL) {
-			multi = 0;
-			Log.d(TAG, "cancel " + multi);
-			mTextRenderer.hold(false);
-		}
-
-		return false;
-	}
-	
 	@Override
 	public void onDetach() {
+		mMap.removeListener(UpdateEvent.TYPE, this);
+		mMap.removeListener(MotionEvent.TYPE, this);
+
+		// TODO stop and clear labeling thread
+		super.onDetach();
 	}
+
+	@Override
+	public void handleEvent(MapEvent event) {
+		if (event instanceof UpdateEvent) {
+
+			UpdateEvent e = (UpdateEvent) event;
+			if (e.clearMap)
+				mTextRenderer.clearLabels();
+
+		} else if (event instanceof MotionEvent) {
+			MotionEvent e = (MotionEvent) event;
+
+			int action = e.getAction() & MotionEvent.ACTION_MASK;
+			if (action == MotionEvent.ACTION_POINTER_DOWN) {
+				multi++;
+				mTextRenderer.hold(true);
+			} else if (action == MotionEvent.ACTION_POINTER_UP) {
+				multi--;
+				if (multi == 0)
+					mTextRenderer.hold(false);
+			} else if (action == MotionEvent.ACTION_CANCEL) {
+				multi = 0;
+				Log.d(TAG, "cancel " + multi);
+				mTextRenderer.hold(false);
+			}
+		}
+	}
+
+	//	@Override
+	//	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+	//		if (clear)
+	//			mTextRenderer.clearLabels();
+	//	}
+
+	//	@Override
+	//	public boolean onTouchEvent(MotionEvent e) {
+	//		int action = e.getAction() & MotionEvent.ACTION_MASK;
+	//		if (action == MotionEvent.ACTION_POINTER_DOWN) {
+	//			multi++;
+	//			mTextRenderer.hold(true);
+	//		} else if (action == MotionEvent.ACTION_POINTER_UP) {
+	//			multi--;
+	//			if (multi == 0)
+	//				mTextRenderer.hold(false);
+	//		} else if (action == MotionEvent.ACTION_CANCEL) {
+	//			multi = 0;
+	//			Log.d(TAG, "cancel " + multi);
+	//			mTextRenderer.hold(false);
+	//		}
+	//
+	//		return false;
+	//	}
+
 }
diff --git a/vtm/src/org/oscim/map/Layers.java b/vtm/src/org/oscim/map/Layers.java
index 32e1cba3..ad262108 100644
--- a/vtm/src/org/oscim/map/Layers.java
+++ b/vtm/src/org/oscim/map/Layers.java
@@ -20,9 +20,9 @@ import java.util.AbstractList;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.oscim.backend.Log;
-import org.oscim.backend.input.KeyEvent;
-import org.oscim.backend.input.MotionEvent;
 import org.oscim.core.MapPosition;
+import org.oscim.event.KeyEvent;
+import org.oscim.event.MotionEvent;
 import org.oscim.layers.InputLayer;
 import org.oscim.layers.Layer;
 import org.oscim.renderer.LayerRenderer;
@@ -74,14 +74,14 @@ public class Layers extends AbstractList<Layer> {
 
 		return mLayerRenderer;
 	}
-
-	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
-		if (mDirtyLayers)
-			updateLayers();
-
-		for (Layer l : mLayers)
-			l.onUpdate(mapPosition, changed, clear);
-	}
+//
+//	public void onUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+//		if (mDirtyLayers)
+//			updateLayers();
+//
+//		for (Layer l : mLayers)
+//			l.onUpdate(mapPosition, changed, clear);
+//	}
 
 	public void destroy() {
 		if (mDirtyLayers)
diff --git a/vtm/src/org/oscim/map/Map.java b/vtm/src/org/oscim/map/Map.java
index b4338ebc..0769e3ec 100644
--- a/vtm/src/org/oscim/map/Map.java
+++ b/vtm/src/org/oscim/map/Map.java
@@ -14,10 +14,16 @@
  */
 package org.oscim.map;
 
+import java.util.ArrayList;
+
 import org.oscim.backend.Log;
 import org.oscim.core.BoundingBox;
 import org.oscim.core.GeoPoint;
 import org.oscim.core.MapPosition;
+import org.oscim.event.EventDispatcher;
+import org.oscim.event.EventListener;
+import org.oscim.event.MotionEvent;
+import org.oscim.event.UpdateEvent;
 import org.oscim.layers.MapEventLayer;
 import org.oscim.layers.tile.bitmap.BitmapTileLayer;
 import org.oscim.layers.tile.vector.VectorTileLayer;
@@ -29,7 +35,7 @@ import org.oscim.theme.ThemeLoader;
 import org.oscim.tiling.source.TileSource;
 import org.oscim.utils.async.AsyncExecutor;
 
-public abstract class Map {
+public abstract class Map implements EventDispatcher {
 
 	private static final String TAG = Map.class.getName();
 
@@ -172,7 +178,15 @@ public abstract class Map {
 		// get the current MapPosition
 		changed |= mViewport.getMapPosition(mMapPosition);
 
-		mLayers.onUpdate(mMapPosition, changed, mClearMap);
+		//mLayers.onUpdate(mMapPosition, changed, mClearMap);
+
+		UpdateEvent e = new UpdateEvent(this);
+		e.clearMap = mClearMap;
+		e.positionChanged = changed;
+
+		for (EventListener l : mUpdateListeners)
+			l.handleEvent(e);
+
 		mClearMap = false;
 	}
 
@@ -223,4 +237,33 @@ public abstract class Map {
 	public MapAnimator getAnimator() {
 		return mAnimator;
 	}
+
+
+	ArrayList<EventListener> mUpdateListeners = new ArrayList<EventListener>();
+	ArrayList<EventListener> mMotionListeners = new ArrayList<EventListener>();
+
+	@Override
+	public void addListener(String type, EventListener listener) {
+		if (type == UpdateEvent.TYPE)
+			mUpdateListeners.add(listener);
+		else if (type == MotionEvent.TYPE)
+			mMotionListeners.add(listener);
+
+	}
+	@Override
+	public void removeListener(String type, EventListener listener) {
+		if (type == UpdateEvent.TYPE)
+			mUpdateListeners.remove(listener);
+		else if (type == MotionEvent.TYPE)
+			mMotionListeners.remove(listener);
+	}
+
+	public MapPosition getMapPosition() {
+		return mMapPosition;
+	}
+
+	public void handleMotionEvent(MotionEvent e) {
+		for (EventListener l : mMotionListeners)
+			l.handleEvent(e);
+	}
 }