package org.oscim.overlay; import java.util.List; import org.oscim.core.MercatorProjection; import org.oscim.overlay.ResourceProxy.bitmap; import org.oscim.view.MapView; import org.oscim.view.MapViewPosition; import android.content.Context; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.MotionEvent; public class ItemizedIconOverlay extends ItemizedOverlay { private static final String TAG = ItemizedIconOverlay.class.getSimpleName(); protected final List mItemList; protected OnItemGestureListener mOnItemGestureListener; private int mDrawnItemsLimit = Integer.MAX_VALUE; private final Point mTouchScreenPoint = new Point(); private final Point mItemPoint = new Point(); public ItemizedIconOverlay( final MapView mapView, final List pList, final Drawable pDefaultMarker, final ItemizedIconOverlay.OnItemGestureListener pOnItemGestureListener, final ResourceProxy pResourceProxy) { super(mapView, pDefaultMarker, pResourceProxy); this.mItemList = pList; this.mOnItemGestureListener = pOnItemGestureListener; populate(); } public ItemizedIconOverlay( final MapView mapView, final List pList, final ItemizedIconOverlay.OnItemGestureListener pOnItemGestureListener, final ResourceProxy pResourceProxy) { this(mapView, pList, pResourceProxy.getDrawable(bitmap.marker_default), pOnItemGestureListener, pResourceProxy); } public ItemizedIconOverlay( final MapView mapView, final Context pContext, final List pList, final ItemizedIconOverlay.OnItemGestureListener pOnItemGestureListener) { this(mapView, pList, new DefaultResourceProxyImpl(pContext) .getDrawable(bitmap.marker_default), pOnItemGestureListener, new DefaultResourceProxyImpl(pContext)); } @Override public boolean onSnapToItem(final int pX, final int pY, final Point pSnapPoint, final MapView pMapView) { // TODO Implement this! return false; } @Override protected Item createItem(final int index) { return mItemList.get(index); } @Override public int size() { return Math.min(mItemList.size(), mDrawnItemsLimit); } public boolean addItem(final Item item) { final boolean result = mItemList.add(item); populate(); return result; } public void addItem(final int location, final Item item) { mItemList.add(location, item); } public boolean addItems(final List items) { final boolean result = mItemList.addAll(items); populate(); return result; } public void removeAllItems() { removeAllItems(true); } public void removeAllItems(final boolean withPopulate) { mItemList.clear(); if (withPopulate) { populate(); } } public boolean removeItem(final Item item) { final boolean result = mItemList.remove(item); populate(); return result; } public Item removeItem(final int position) { final Item result = mItemList.remove(position); populate(); return result; } /** * Each of these methods performs a item sensitive check. If the item is * located its corresponding method is called. The result of the call is * returned. Helper methods are provided so that child classes may more * easily override behavior without resorting to overriding the * ItemGestureListener methods. */ @Override public boolean onSingleTapUp(final MotionEvent event, final MapView mapView) { return (activateSelectedItems(event, mapView, new ActiveItem() { @Override public boolean run(final int index) { final ItemizedIconOverlay that = ItemizedIconOverlay.this; if (that.mOnItemGestureListener == null) { return false; } return onSingleTapUpHelper(index, that.mItemList.get(index), mapView); } })) || super.onSingleTapUp(event, mapView); } /** * @param index * ... * @param item * ... * @param mapView * ... * @return ... */ protected boolean onSingleTapUpHelper(final int index, final Item item, final MapView mapView) { return this.mOnItemGestureListener.onItemSingleTapUp(index, item); } @Override public boolean onLongPress(final MotionEvent event, final MapView mapView) { Log.d(TAG, "onLongPress"); return (activateSelectedItems(event, mapView, new ActiveItem() { @Override public boolean run(final int index) { final ItemizedIconOverlay that = ItemizedIconOverlay.this; if (that.mOnItemGestureListener == null) { return false; } return onLongPressHelper(index, getItem(index)); } })) || super.onLongPress(event, mapView); } protected boolean onLongPressHelper(final int index, final Item item) { return this.mOnItemGestureListener.onItemLongPress(index, item); } /** * When a content sensitive action is performed the content item needs to be * identified. This method does that and then performs the assigned task on * that item. * @param event * ... * @param mapView * ... * @param task * .. * @return true if event is handled false otherwise */ private boolean activateSelectedItems(final MotionEvent event, final MapView mapView, final ActiveItem task) { // final Projection pj = mapView.getProjection(); final int eventX = (int) event.getX(); final int eventY = (int) event.getY(); // Log.d("...", "test items " + eventX + " " + eventY); /* These objects are created to avoid construct new ones every cycle. */ // pj.fromMapPixels(eventX, eventY, mTouchScreenPoint); MapViewPosition mapViewPosition = mMapView.getMapViewPosition(); byte z = mapViewPosition.getMapPosition().zoomLevel; mapViewPosition.getScreenPointOnMap(eventX, eventY, mTouchScreenPoint); int nearest = -1; double dist = Double.MAX_VALUE; // TODO use intermediate projection and bounding box test for (int i = 0; i < this.mItemList.size(); ++i) { final Item item = getItem(i); // final Drawable marker = (item.getMarker(0) == null) ? this.mDefaultMarker : item // .getMarker(0); // int x = (int) MercatorProjection.longitudeToPixelX(item.getPoint().getLongitude(), z); // int y = (int) MercatorProjection.latitudeToPixelY(item.getPoint().getLatitude(), z); MercatorProjection.projectPoint(item.getPoint(), z, mItemPoint); // pj.toPixels(item.getPoint(), mItemPoint); // Log.d("...", (x - mTouchScreenPoint.x) + " " + (y - mTouchScreenPoint.y)); float dx = mItemPoint.x - mTouchScreenPoint.x; float dy = mItemPoint.y - mTouchScreenPoint.y; double d = Math.sqrt(dx * dx + dy * dy); if (d < 50) { // Log.d("...", "HIT! " + (x - mTouchScreenPoint.x) + " " + (y - mTouchScreenPoint.y)); if (d < dist) { dist = d; nearest = i; } // if (hitTest(item, marker, mTouchScreenPoint.x - mItemPoint.x, mTouchScreenPoint.y // - mItemPoint.y)) { } } if (nearest >= 0 && task.run(nearest)) { return true; } return false; } // =========================================================== // Getter & Setter // =========================================================== public int getDrawnItemsLimit() { return this.mDrawnItemsLimit; } public void setDrawnItemsLimit(final int aLimit) { this.mDrawnItemsLimit = aLimit; } // =========================================================== // Inner and Anonymous Classes // =========================================================== /** * When the item is touched one of these methods may be invoked depending on * the type of touch. Each of them returns true if the event was completely * handled. * @param * .... */ public static interface OnItemGestureListener { public boolean onItemSingleTapUp(final int index, final T item); public boolean onItemLongPress(final int index, final T item); } public static interface ActiveItem { public boolean run(final int aIndex); } }