package org.xbmc.android.remote.presentation.widget;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xbmc.android.remote.R;
import org.xbmc.api.type.ThumbSize;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class JewelView extends View {
private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
private Bitmap mPosterOverlay;
private Bitmap mPoster;
private Paint mPaint;
private float mPosterAR;
private int coverWidth, coverHeight;
private int originalWidth, originalHeight;
private int totalWidth, totalHeight;
private int specifiedWidth = 0;
private int specifiedHeight = 0;
private float scaled;
private int originalCoverHeight, originalCoverWidth;
private JewelType mType;
public final static float AR_LANDSCAPE_SQUARE = 0.8f;
public final static float AR_SQUARE_POSTER = 1.25f;
public final static float AR_OVERLAY = 1.25f;
private final static String TAG = "JewelView";
public JewelView(Context context) {
super(context);
init(context);
}
public JewelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
// read layout width and height from xml element
final Pattern p = Pattern.compile("([\\-\\d]+)");
final String h = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_height");
final String w = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_width");
if (w != null) {
try {
Matcher matcher = p.matcher(w);
if (matcher.find()) {
specifiedWidth = Integer.parseInt(matcher.group(1));
}
} catch (Exception e) { }
}
if (h != null) {
try {
Matcher matcher = p.matcher(h);
if (matcher.find()) {
specifiedHeight = Integer.parseInt(matcher.group(1));
}
} catch (Exception e) { }
}
}
public void setCover(int coverResource) {
// Log.d(TAG, "setCover(" + coverResource + ")");
setCover(BitmapFactory.decodeResource(getContext().getResources(), coverResource));
}
public void setCover(Bitmap cover) {
mPoster = cover;
mPosterAR = (float) cover.getHeight() / (float) cover.getWidth();
// Log.d(TAG, "setCover(), AR = " + mPosterAR);
mType = JewelType.get(mPosterAR);
if (mType != null) {
Log.i(TAG, "Set aspect ratio type for " + mPosterAR + " to " + mType);
mPosterOverlay = BitmapFactory.decodeResource(getContext().getResources(), mType.overlayResource);
} else {
Log.w(TAG, "Unable to get aspect ratio type for " + mPosterAR);
}
requestLayout();
invalidate();
}
private final void init(Context context) {
mPaint = new Paint();
// final int padding = ThumbSize.scale(3);
// setPadding(padding, padding, padding, padding);
setCover(R.drawable.default_jewel);
}
/**
* @see android.view.View#measure(int, int)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " + MeasureSpec.toString(heightMeasureSpec));
if (mType == null) {
setMeasuredDimension(0, 0);
return;
}
final int modeWidth = specifiedWidth > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(widthMeasureSpec);
final int modeHeight = specifiedHeight > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(heightMeasureSpec);
originalWidth = mPosterOverlay.getWidth();
originalHeight = mPosterOverlay.getHeight();
if (modeHeight == modeWidth) {
final float canvasAR = (float)MeasureSpec.getSize(heightMeasureSpec) / (float)MeasureSpec.getSize(widthMeasureSpec);
// Log.d(TAG, "Patt, calculating from canvas AR (" + canvasAR + ")");
if (mPosterAR > canvasAR * mType.overlayAR) {
setMeasuredDimensionByHeight(MeasureSpec.getSize(heightMeasureSpec));
} else {
setMeasuredDimensionByWidth(MeasureSpec.getSize(widthMeasureSpec));
}
} else if (modeHeight == MeasureSpec.EXACTLY && modeWidth != MeasureSpec.EXACTLY && mPosterAR > AR_LANDSCAPE_SQUARE) {
// reference is height, make width dependent on height.
setMeasuredDimensionByHeight(specifiedHeight > 0 ? ThumbSize.scale(specifiedHeight) : MeasureSpec.getSize(heightMeasureSpec));
} else {
// reference is width, make height dependent on width.
setMeasuredDimensionByWidth(specifiedWidth > 0 ? ThumbSize.scale(specifiedWidth) : MeasureSpec.getSize(widthMeasureSpec));
}
// fill_parent -> MeasureSpec.EXACTLY
// wrap_content -> MeasureSpec.AT_MOST
}
private void setMeasuredDimensionByHeight(int height) {
final Rect posterPosition = mType.posterPosition;
totalHeight = height;
originalCoverHeight = originalHeight - ThumbSize.scale(posterPosition.top + posterPosition.bottom);
originalCoverWidth = Math.round((float) originalCoverHeight / mPosterAR);
scaled = (float) totalHeight / (float) originalHeight;
coverHeight = Math.round((float) originalCoverHeight * scaled);
coverWidth = Math.round((float) originalCoverWidth * scaled);
totalWidth = coverWidth + Math.round((float) ThumbSize.scale(posterPosition.left + posterPosition.right) * scaled);
// Log.d(TAG, "Measuring by height (" + height + ") -> " + totalWidth + "x" + totalHeight);
setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding);
}
private void setMeasuredDimensionByWidth(int width) {
final Rect posterPosition = mType.posterPosition;
totalWidth = width;
originalCoverWidth = originalWidth - ThumbSize.scale(posterPosition.left + posterPosition.right);
originalCoverHeight = Math.round((float) originalCoverWidth * mPosterAR);
scaled = (float) totalWidth / (float) originalWidth;
coverHeight = Math.round((float) originalCoverHeight * scaled);
coverWidth = Math.round((float) originalCoverWidth * scaled);
totalHeight = coverHeight + Math.round((float) ThumbSize.scale(posterPosition.top + posterPosition.bottom) * scaled);
// Log.d(TAG, "Measuring by width (" + width + ") -> " + totalWidth + "x" + totalHeight);
setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding);
}
/**
* Render the text
*
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
synchronized (this) {
if (mType != null) {
// Log.i(TAG, "Drawing " + mType);
// Rect(left: 48, top: 11, right: 17, bottom: 19)
final Rect posterPosition = mType.posterPosition;
final int pdnLeft = Math.round((float) ThumbSize.scale(posterPosition.left) * scaled);
final int pdnTop = Math.round((float) ThumbSize.scale(posterPosition.top) * scaled);
mPaint.setDither(true);
mPaint.setFilterBitmap(true);
// draw actual poster
canvas.drawBitmap(mPoster, new Rect(0, 0, mPoster.getWidth(), mPoster.getHeight()),
new Rect(pdnLeft, pdnTop, pdnLeft + coverWidth, pdnTop + coverHeight), mPaint);
// draw case overlay
canvas.drawBitmap(mPosterOverlay, new Rect(0, 0, originalWidth, originalHeight),
new Rect(0, 0, totalWidth, totalHeight), mPaint);
}
}
}
private static class JewelType {
private final static JewelType[] TYPES = {
// l t r b
new JewelType(new Rect(48, 11, 17, 19), AR_SQUARE_POSTER, 2000f, R.drawable.jewel_dvd, "Portrait (1:1.48)", 0, 1),
new JewelType(new Rect(41, 12, 17, 18), AR_LANDSCAPE_SQUARE, AR_SQUARE_POSTER, R.drawable.jewel_cd, "Cover (square)", 0, 1.105263157894737f),
new JewelType(new Rect(16, 11, 10, 34), 0.35f, AR_LANDSCAPE_SQUARE, R.drawable.jewel_tv, "Landscape (16:9)", ThumbSize.scale(30), 1)
};
public static final JewelType get(float ar) {
for (JewelType jewelType : TYPES) {
if (ar >= jewelType.minAR && ar < jewelType.maxAR) {
return jewelType;
}
}
return null;
}
public final Rect posterPosition;
public final float minAR, maxAR;
public final int overlayResource;
public final String name;
public final int bottomPadding;
public final float overlayAR;
public JewelType(Rect posterPosition, float minAR, float maxAR, int overlayResource, String name, int bottomPadding, float overlayAR) {
this.posterPosition = posterPosition;
this.minAR = minAR;
this.maxAR = maxAR;
this.overlayResource = overlayResource;
this.name = name;
this.bottomPadding = bottomPadding;
this.overlayAR = overlayAR;
}
@Override
public String toString() {
return name;
}
}
}