package com.robert.maps.applib.overlays;
import org.andnav.osm.util.GeoPoint;
import org.andnav.osm.views.util.constants.OpenStreetMapViewConstants;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import com.robert.maps.applib.R;
import com.robert.maps.applib.kml.PoiManager;
import com.robert.maps.applib.kml.PoiPoint;
import com.robert.maps.applib.utils.Ut;
import com.robert.maps.applib.view.TileView;
import com.robert.maps.applib.view.TileViewOverlay;
public class PoiOverlay extends TileViewOverlay {
private Context mCtx;
private PoiManager mPoiManager;
private int mTapId;
private GeoPoint mLastMapCenter;
private int mLastZoom;
private PoiListThread mThread;
private RelativeLayout mT;
private float mDensity;
private boolean mNeedUpdateList = false;
public static int NO_TAP = -9999;
protected OnItemTapListener<PoiPoint> mOnItemTapListener;
protected OnItemLongPressListener<PoiPoint> mOnItemLongPressListener;
protected SparseArray<PoiPoint> mItemList;
protected final Point mMarkerHotSpot;
protected final int mMarkerWidth, mMarkerHeight;
private boolean mCanUpdateList = true;
protected SparseArray<Drawable> mBtnMap;
public int getTapIndex() {
return mTapId;
}
public void setTapIndex(int mTapIndex) {
this.mTapId = mTapIndex;
}
public void UpdateList() {
mNeedUpdateList = true;
}
public PoiOverlay(Context ctx, PoiManager poiManager,
OnItemTapListener<PoiPoint> onItemTapListener, boolean hidepoi)
{
mCtx = ctx;
mPoiManager = poiManager;
mCanUpdateList = !hidepoi;
mTapId = NO_TAP;
Drawable marker = ctx.getResources().getDrawable(R.drawable.poi);
this.mMarkerWidth = marker.getIntrinsicWidth();
this.mMarkerHeight = marker.getIntrinsicHeight();
mBtnMap = new SparseArray<Drawable>();
mBtnMap.put(Integer.valueOf(R.drawable.poi), marker);
this.mMarkerHotSpot = new Point(0, mMarkerHeight);
this.mOnItemTapListener = onItemTapListener;
mLastMapCenter = null;
mLastZoom = -1;
mThread = new PoiListThread();
this.mT = (RelativeLayout) LayoutInflater.from(ctx).inflate(R.layout.poi_descr, null);
this.mT.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
DisplayMetrics metrics = new DisplayMetrics();
((Activity) ctx).getWindowManager().getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
}
public void clearPoiList() {
if(mItemList == null)
mItemList = new SparseArray<PoiPoint>();
else
mItemList.clear();
}
public void setGpsStatusGeoPoint(final int id, final GeoPoint geopoint, final String title, final String descr) {
PoiPoint poi = new PoiPoint(id, title, descr, geopoint, 0, R.drawable.poi_satttelite);
if(mItemList == null)
mItemList = new SparseArray<PoiPoint>();
mItemList.put(poi.getId(), poi);
mCanUpdateList = false;
mTapId = NO_TAP;
}
@Override
public void onDraw(Canvas c, TileView mapView) {
final com.robert.maps.applib.view.TileView.OpenStreetMapViewProjection pj = mapView.getProjection();
final Point curScreenCoords = new Point();
if (mCanUpdateList){
boolean looseCenter = false;
GeoPoint center = mapView.getMapCenter();
GeoPoint lefttop = pj.fromPixels(0, 0);
double deltaX = Math.abs(center.getLongitude() - lefttop.getLongitude());
double deltaY = Math.abs(center.getLatitude() - lefttop.getLatitude());
if (mLastMapCenter == null || mLastZoom != mapView.getZoomLevel())
looseCenter = true;
else if(0.7 * deltaX < Math.abs(center.getLongitude() - mLastMapCenter.getLongitude()) || 0.7 * deltaY < Math.abs(center.getLatitude() - mLastMapCenter.getLatitude()))
looseCenter = true;
if(looseCenter || mNeedUpdateList){
mLastMapCenter = center;
mLastZoom = mapView.getZoomLevel();
mNeedUpdateList = false;
mThread.setParams(1.5*deltaX, 1.5*deltaY);
mThread.run();
}
}
if (this.mItemList != null) {
/*
* Draw in backward cycle, so the items with the least index are on
* the front.
*/
for (int i = this.mItemList.size() - 1; i >= 0; i--) {
if (i != mTapId) {
PoiPoint item = this.mItemList.valueAt(i);
pj.toPixels(item.GeoPoint, curScreenCoords);
c.save();
c.rotate(mapView.getBearing(), curScreenCoords.x,
curScreenCoords.y);
onDrawItem(c, item.getId(), curScreenCoords);
c.restore();
}
}
if (mTapId > NO_TAP) {
PoiPoint item = this.mItemList.get(mTapId);
if(item != null) {
pj.toPixels(item.GeoPoint, curScreenCoords);
c.save();
c.rotate(mapView.getBearing(), curScreenCoords.x,
curScreenCoords.y);
onDrawItem(c, mTapId, curScreenCoords);
c.restore();
}
}
}
}
protected void onDrawItem(Canvas c, int id, Point screenCoords) {
final PoiPoint focusedItem = mItemList.get(id);
if (id == mTapId) {
final ImageView pic = (ImageView) mT.findViewById(R.id.pic);
final TextView title = (TextView) mT.findViewById(R.id.poi_title);
final TextView descr = (TextView) mT.findViewById(R.id.descr);
final TextView coord = (TextView) mT.findViewById(R.id.coord);
pic.setImageResource(focusedItem.IconId);
title.setText(focusedItem.Title);
descr.setText(focusedItem.Descr);
coord.setText(Ut.formatGeoPoint(focusedItem.GeoPoint, mCtx));
mT.measure(0, 0);
mT.layout(0, 0, mT.getMeasuredWidth(), mT.getMeasuredHeight());
c.save();
c.translate(screenCoords.x, screenCoords.y - pic.getMeasuredHeight() - pic.getTop());
mT.draw(c);
c.restore();
} else {
final int left = screenCoords.x - this.mMarkerHotSpot.x;
final int right = left + this.mMarkerWidth;
final int top = screenCoords.y - this.mMarkerHotSpot.y;
final int bottom = top + this.mMarkerHeight;
Drawable marker = null;
if(mBtnMap.indexOfKey(focusedItem.IconId) > 0)
marker = mBtnMap.get(focusedItem.IconId);
else {
try{
marker = mCtx.getResources().getDrawable(focusedItem.IconId);
} catch (Exception e) {
marker = mCtx.getResources().getDrawable(R.drawable.poi);
}
mBtnMap.put(focusedItem.IconId, marker);
}
marker.setBounds(left, top, right, bottom);
marker.draw(c);
if(OpenStreetMapViewConstants.DEBUGMODE){
final int pxUp = 2;
final int left2 = (int)(screenCoords.x + mDensity*(5 - pxUp));
final int right2 = (int)(screenCoords.x + mDensity*(38 + pxUp));
final int top2 = (int)(screenCoords.y - this.mMarkerHotSpot.y - mDensity*(pxUp));
final int bottom2 = (int)(top2 + mDensity*(33 + pxUp));
Paint p = new Paint();
c.drawLine(left2, top2, right2, bottom2, p);
c.drawLine(right2, top2, left2, bottom2, p);
c.drawLine(screenCoords.x - 5, screenCoords.y - 5, screenCoords.x + 5, screenCoords.y + 5, p);
c.drawLine(screenCoords.x - 5, screenCoords.y + 5, screenCoords.x + 5, screenCoords.y - 5, p);
}
}
}
public PoiPoint getPoiPoint(final int id){
return this.mItemList.get(id);
}
public int getMarkerAtPoint(final int eventX, final int eventY, TileView mapView){
if(this.mItemList != null){
final com.robert.maps.applib.view.TileView.OpenStreetMapViewProjection pj = mapView.getProjection();
final Rect curMarkerBounds = new Rect();
final Point mCurScreenCoords = new Point();
for(int i = 0; i < this.mItemList.size(); i++){
final PoiPoint mItem = this.mItemList.valueAt(i);
pj.toPixels(mItem.GeoPoint, mapView.getBearing(), mCurScreenCoords);
final int pxUp = 2;
final int left = (int)(mCurScreenCoords.x + mDensity*(5 - pxUp));
final int right = (int)(mCurScreenCoords.x + mDensity*(38 + pxUp));
final int top = (int)(mCurScreenCoords.y - this.mMarkerHotSpot.y - mDensity*(pxUp));
final int bottom = (int)(top + mDensity*(33 + pxUp));
curMarkerBounds.set(left, top, right, bottom);
if(curMarkerBounds.contains(eventX, eventY))
return mItem.getId();
}
}
return NO_TAP;
}
@Override
public boolean onSingleTapUp(MotionEvent event, TileView mapView) {
final int id = getMarkerAtPoint((int)event.getX(), (int)event.getY(), mapView);
if (id > NO_TAP)
if (onTap(id))
return true;
return super.onSingleTapUp(event, mapView);
}
@Override
public int onLongPress(MotionEvent event, TileView mapView) {
final int id = getMarkerAtPoint((int)event.getX(), (int)event.getY(), mapView);
mapView.mPoiMenuInfo.MarkerIndex = id;
mapView.mPoiMenuInfo.EventGeoPoint = mapView.getProjection().fromPixels((int)event.getX(), (int)event.getY(), mapView.getBearing());
if (id > NO_TAP)
return 1;
//if (onLongLongPress(id))
return super.onLongPress(event, mapView);
}
private boolean onLongLongPress(int id) {
return false;
}
protected boolean onTap(int id) {
if(mTapId == id)
mTapId = NO_TAP;
else
mTapId = id;
if(this.mOnItemTapListener != null)
return this.mOnItemTapListener.onItemTap(id, this.mItemList.get(id));
else
return false;
}
@SuppressWarnings("hiding")
public static interface OnItemTapListener<PoiPoint>{
public boolean onItemTap(final int aIndex, final PoiPoint aItem);
}
@SuppressWarnings("hiding")
public static interface OnItemLongPressListener<PoiPoint>{
public boolean onItemLongPress(final int aIndex, final PoiPoint aItem);
}
@Override
protected void onDrawFinished(Canvas c, TileView osmv) {
}
private class PoiListThread extends Thread {
private double mdeltaX;
private double mdeltaY;
public void setParams(double deltaX, double deltaY){
mdeltaX = deltaX;
mdeltaY = deltaY;
}
@Override
public void run() {
mItemList = mPoiManager.getPoiListNotHidden(mLastZoom, mLastMapCenter, mdeltaX, mdeltaY);
super.run();
}
}
}