All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osmdroid.views.overlay.ItemizedOverlayWithFocus Maven / Gradle / Ivy

There is a newer version: 6.1.20
Show newest version
// Created by plusminus on 20:50:06 - 03.10.2008
package org.osmdroid.views.overlay;

import java.util.List;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.OverlayItem.HotspotPlace;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;

public class ItemizedOverlayWithFocus extends ItemizedIconOverlay {

	// ===========================================================
	// Constants
	// ===========================================================

	public static final int DESCRIPTION_BOX_PADDING = 3;
	public static final int DESCRIPTION_BOX_CORNERWIDTH = 3;

	public static final int DESCRIPTION_LINE_HEIGHT = 12;
	/** Additional to DESCRIPTION_LINE_HEIGHT. */
	public static final int DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT = 2;

	// protected static final Point DEFAULTMARKER_FOCUSED_HOTSPOT = new Point(10, 19);
	protected static final int DEFAULTMARKER_BACKGROUNDCOLOR = Color.rgb(101, 185, 74);

	protected static final int DESCRIPTION_MAXWIDTH = 200;

	// ===========================================================
	// Fields
	// ===========================================================

	protected final int mMarkerFocusedBackgroundColor;
	protected final Paint mMarkerBackgroundPaint, mDescriptionPaint, mTitlePaint;

	protected Drawable mMarkerFocusedBase;
	protected int mFocusedItemIndex;
	protected boolean mFocusItemsOnTap;
	private final Point mFocusedScreenCoords = new Point();

	private final String UNKNOWN;

	// ===========================================================
	// Constructors
	// ===========================================================

	public ItemizedOverlayWithFocus(final Context ctx, final List aList,
			final OnItemGestureListener aOnItemTapListener) {
		this(aList, aOnItemTapListener, new DefaultResourceProxyImpl(ctx));
	}

	public ItemizedOverlayWithFocus(final List aList,
			final OnItemGestureListener aOnItemTapListener, final ResourceProxy pResourceProxy) {
		this(aList, pResourceProxy.getDrawable(ResourceProxy.bitmap.marker_default), null, NOT_SET,
				aOnItemTapListener, pResourceProxy);
	}

	public ItemizedOverlayWithFocus(final List aList, final Drawable pMarker,
			final Drawable pMarkerFocused, final int pFocusedBackgroundColor,
			final OnItemGestureListener aOnItemTapListener, final ResourceProxy pResourceProxy) {

		super(aList, pMarker, aOnItemTapListener, pResourceProxy);

		UNKNOWN = mResourceProxy.getString(ResourceProxy.string.unknown);

		if (pMarkerFocused == null) {
			this.mMarkerFocusedBase = boundToHotspot(
					mResourceProxy.getDrawable(ResourceProxy.bitmap.marker_default_focused_base),
					HotspotPlace.BOTTOM_CENTER);
		} else
			this.mMarkerFocusedBase = pMarkerFocused;

		this.mMarkerFocusedBackgroundColor = (pFocusedBackgroundColor != NOT_SET) ? pFocusedBackgroundColor
				: DEFAULTMARKER_BACKGROUNDCOLOR;

		this.mMarkerBackgroundPaint = new Paint(); // Color is set in onDraw(...)

		this.mDescriptionPaint = new Paint();
		this.mDescriptionPaint.setAntiAlias(true);
		this.mTitlePaint = new Paint();
		this.mTitlePaint.setFakeBoldText(true);
		this.mTitlePaint.setAntiAlias(true);
		this.unSetFocusedItem();
	}

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	public Item getFocusedItem() {
		if (this.mFocusedItemIndex == NOT_SET) {
			return null;
		}
		return this.mItemList.get(this.mFocusedItemIndex);
	}

	public void setFocusedItem(final int pIndex) {
		this.mFocusedItemIndex = pIndex;
	}

	public void unSetFocusedItem() {
		this.mFocusedItemIndex = NOT_SET;
	}

	public void setFocusedItem(final Item pItem) {
		final int indexFound = super.mItemList.indexOf(pItem);
		if (indexFound < 0) {
			throw new IllegalArgumentException();
		}

		this.setFocusedItem(indexFound);
	}

	public void setFocusItemsOnTap(final boolean doit) {
		this.mFocusItemsOnTap = doit;
	}

	// ===========================================================
	// Methods from SuperClass/Interfaces
	// ===========================================================

	@Override
	protected boolean onSingleTapUpHelper(final int index, final Item item, final MapView mapView) {
		if (this.mFocusItemsOnTap) {
			this.mFocusedItemIndex = index;
			mapView.postInvalidate();
		}
		return this.mOnItemGestureListener.onItemSingleTapUp(index, item);
	}

	private final Rect mRect = new Rect();

	@Override
	public void draw(final Canvas c, final MapView osmv, final boolean shadow) {

		super.draw(c, osmv, shadow);

		if (shadow) {
			return;
		}

		if (this.mFocusedItemIndex == NOT_SET) {
			return;
		}

		// get focused item's preferred marker & hotspot
		final Item focusedItem = super.mItemList.get(this.mFocusedItemIndex);
		Drawable markerFocusedBase = focusedItem.getMarker(OverlayItem.ITEM_STATE_FOCUSED_MASK);
		if (markerFocusedBase == null) {
			markerFocusedBase = this.mMarkerFocusedBase;
		}

		/* Calculate and set the bounds of the marker. */
		osmv.getProjection().toMapPixels(focusedItem.mGeoPoint, mFocusedScreenCoords);

		markerFocusedBase.copyBounds(mRect);
		mRect.offset(mFocusedScreenCoords.x, mFocusedScreenCoords.y);

		/* Strings of the OverlayItem, we need. */
		final String itemTitle = (focusedItem.mTitle == null) ? UNKNOWN : focusedItem.mTitle;
		final String itemDescription = (focusedItem.mDescription == null) ? UNKNOWN
				: focusedItem.mDescription;

		/*
		 * Store the width needed for each char in the description to a float array. This is pretty
		 * efficient.
		 */
		final float[] widths = new float[itemDescription.length()];
		this.mDescriptionPaint.getTextWidths(itemDescription, widths);

		final StringBuilder sb = new StringBuilder();
		int maxWidth = 0;
		int curLineWidth = 0;
		int lastStop = 0;
		int i;
		int lastwhitespace = 0;
		/*
		 * Loop through the charwidth array and harshly insert a linebreak, when the width gets
		 * bigger than DESCRIPTION_MAXWIDTH.
		 */
		for (i = 0; i < widths.length; i++) {
			if (!Character.isLetter(itemDescription.charAt(i))) {
				lastwhitespace = i;
			}

			final float charwidth = widths[i];

			if (curLineWidth + charwidth > DESCRIPTION_MAXWIDTH) {
				if (lastStop == lastwhitespace) {
					i--;
				} else {
					i = lastwhitespace;
				}

				sb.append(itemDescription.subSequence(lastStop, i));
				sb.append('\n');

				lastStop = i;
				maxWidth = Math.max(maxWidth, curLineWidth);
				curLineWidth = 0;
			}

			curLineWidth += charwidth;
		}
		/* Add the last line to the rest to the buffer. */
		if (i != lastStop) {
			final String rest = itemDescription.substring(lastStop, i);
			maxWidth = Math.max(maxWidth, (int) this.mDescriptionPaint.measureText(rest));
			sb.append(rest);
		}
		final String[] lines = sb.toString().split("\n");

		/*
		 * The title also needs to be taken into consideration for the width calculation.
		 */
		final int titleWidth = (int) this.mDescriptionPaint.measureText(itemTitle);

		maxWidth = Math.max(maxWidth, titleWidth);
		final int descWidth = Math.min(maxWidth, DESCRIPTION_MAXWIDTH);

		/* Calculate the bounds of the Description box that needs to be drawn. */
		final int descBoxLeft = mRect.left - descWidth / 2 - DESCRIPTION_BOX_PADDING
				+ mRect.width() / 2;
		final int descBoxRight = descBoxLeft + descWidth + 2 * DESCRIPTION_BOX_PADDING;
		final int descBoxBottom = mRect.top;
		final int descBoxTop = descBoxBottom - DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT
				- (lines.length + 1) * DESCRIPTION_LINE_HEIGHT /* +1 because of the title. */
				- 2 * DESCRIPTION_BOX_PADDING;

		/* Twice draw a RoundRect, once in black with 1px as a small border. */
		this.mMarkerBackgroundPaint.setColor(Color.BLACK);
		c.drawRoundRect(new RectF(descBoxLeft - 1, descBoxTop - 1, descBoxRight + 1,
				descBoxBottom + 1), DESCRIPTION_BOX_CORNERWIDTH, DESCRIPTION_BOX_CORNERWIDTH,
				this.mDescriptionPaint);
		this.mMarkerBackgroundPaint.setColor(this.mMarkerFocusedBackgroundColor);
		c.drawRoundRect(new RectF(descBoxLeft, descBoxTop, descBoxRight, descBoxBottom),
				DESCRIPTION_BOX_CORNERWIDTH, DESCRIPTION_BOX_CORNERWIDTH,
				this.mMarkerBackgroundPaint);

		final int descLeft = descBoxLeft + DESCRIPTION_BOX_PADDING;
		int descTextLineBottom = descBoxBottom - DESCRIPTION_BOX_PADDING;

		/* Draw all the lines of the description. */
		for (int j = lines.length - 1; j >= 0; j--) {
			c.drawText(lines[j].trim(), descLeft, descTextLineBottom, this.mDescriptionPaint);
			descTextLineBottom -= DESCRIPTION_LINE_HEIGHT;
		}
		/* Draw the title. */
		c.drawText(itemTitle, descLeft, descTextLineBottom - DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT,
				this.mTitlePaint);
		c.drawLine(descBoxLeft, descTextLineBottom, descBoxRight, descTextLineBottom,
				mDescriptionPaint);

		/*
		 * Finally draw the marker base. This is done in the end to make it look better.
		 */
		Overlay.drawAt(c, markerFocusedBase, mFocusedScreenCoords.x, mFocusedScreenCoords.y, false);
	}

	// ===========================================================
	// Methods
	// ===========================================================

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy