package com.BeeFramework.theme;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import com.BeeFramework.example.R;
import com.external.activeandroid.util.Log;
/*
* ______ ______ ______
* /\ __ \ /\ ___\ /\ ___\
* \ \ __< \ \ __\_ \ \ __\_
* \ \_____\ \ \_____\ \ \_____\
* \/_____/ \/_____/ \/_____/
*
*
* Copyright (c) 2013-2014, {Bee} open source community
* http://www.bee-framework.com
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
public class BeeBitmapDrawable extends BeeDrawable
{
private static final int[] attrArray = {android.R.attr.src ,android.R.attr.antialias, android.R.attr.filter, android.R.attr.dither,android.R.attr.gravity, android.R.attr.tileMode};
private static final int DEFAULT_PAINT_FLAGS =
Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
private BeeBitmapState mBitmapState;
private Bitmap mBitmap;
private int mTargetDensity;
private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
private boolean mApplyGravity;
private boolean mMutated;
// These are scaled to match the target density.
private int mBitmapWidth;
private int mBitmapHeight;
// Mirroring matrix for using with Shaders
private Matrix mMirrorMatrix;
public BeeBitmapDrawable(Bitmap bitmap) {
this(new BeeBitmapState(bitmap), null);
}
public BeeBitmapDrawable(Resources res,Bitmap bitmap)
{
this(new BeeBitmapState(bitmap),res);
mBitmapState.mTargetDensity = mTargetDensity;
}
private BeeBitmapDrawable(BeeBitmapState state, Resources res) {
mBitmapState = state;
if (res != null) {
mTargetDensity = res.getDisplayMetrics().densityDpi;
} else {
mTargetDensity = state.mTargetDensity;
}
setBitmap(state != null ? state.mBitmap : null);
}
public BeeBitmapDrawable(String filepath)
{
this(new BeeBitmapState(BitmapFactory.decodeFile(filepath)),null);
if (mBitmap == null)
{
}
}
public BeeBitmapDrawable(Resources res) {
mBitmapState = new BeeBitmapState((Bitmap) null);
mBitmapState.mTargetDensity = mTargetDensity;
}
private void setBitmap(Bitmap bitmap) {
if (bitmap != mBitmap) {
mBitmap = bitmap;
if (bitmap != null) {
computeBitmapSize();
} else {
mBitmapWidth = mBitmapHeight = -1;
}
invalidateSelf();
}
}
private void computeBitmapSize() {
mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
}
public void setTargetDensity(Canvas canvas) {
setTargetDensity(canvas.getDensity());
}
public void setTargetDensity(DisplayMetrics metrics) {
setTargetDensity(metrics.densityDpi);
}
public void setTargetDensity(int density) {
if (mTargetDensity != density) {
mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
if (mBitmap != null) {
computeBitmapSize();
}
invalidateSelf();
}
}
private boolean needMirroring() {
return false ;
}
private void updateMirrorMatrix(float dx) {
if (mMirrorMatrix == null) {
mMirrorMatrix = new Matrix();
}
mMirrorMatrix.setTranslate(dx, 0);
mMirrorMatrix.preScale(-1.0f, 1.0f);
}
public void setGravity(int gravity) {
if (mBitmapState.mGravity != gravity) {
mBitmapState.mGravity = gravity;
mApplyGravity = true;
invalidateSelf();
}
}
public void setMipMap(boolean mipMap) {
if (mBitmapState.mBitmap != null) {
mBitmapState.mBitmap.setHasMipMap(mipMap);
invalidateSelf();
}
}
public void setAntiAlias(boolean aa) {
mBitmapState.mPaint.setAntiAlias(aa);
invalidateSelf();
}
public void setFilterBitmap(boolean filter) {
mBitmapState.mPaint.setFilterBitmap(filter);
invalidateSelf();
}
public void setDither(boolean dither) {
mBitmapState.mPaint.setDither(dither);
invalidateSelf();
}
public void setTileModeX(Shader.TileMode mode) {
setTileModeXY(mode, mBitmapState.mTileModeY);
}
public final void setTileModeY(Shader.TileMode mode) {
setTileModeXY(mBitmapState.mTileModeX, mode);
}
public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
final BeeBitmapState state = mBitmapState;
if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
state.mTileModeX = xmode;
state.mTileModeY = ymode;
state.mRebuildShader = true;
invalidateSelf();
}
}
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mApplyGravity = true;
Shader shader = mBitmapState.mPaint.getShader();
if (shader != null)
{
if (mMirrorMatrix != null)
{
mMirrorMatrix = null;
shader.setLocalMatrix(new Matrix());
}
}
}
@Override
public void draw(Canvas canvas)
{
Bitmap bitmap = mBitmap;
if (bitmap != null)
{
final BeeBitmapState state = mBitmapState;
if (state.mRebuildShader)
{
Shader.TileMode tmx = state.mTileModeX;
Shader.TileMode tmy = state.mTileModeY;
if (tmx == null && tmy == null)
{
state.mPaint.setShader(null);
}
else
{
state.mPaint.setShader(new BitmapShader(bitmap,
tmx == null ? Shader.TileMode.CLAMP :tmx,
tmx == null ? Shader.TileMode.CLAMP :tmy));
}
state.mRebuildShader = false;
copyBounds(mDstRect);
}
Shader shader = state.mPaint.getShader();
if (shader == null )
{
if (mApplyGravity)
{
Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,getBounds(),mDstRect, View.LAYOUT_DIRECTION_LTR);
mApplyGravity = false;
}
if (needMirroring())
{
updateMirrorMatrix(mDstRect.right - mDstRect.left);
shader.setLocalMatrix(mMirrorMatrix);
}
else
{
if (mMirrorMatrix != null)
{
mMirrorMatrix = null;
shader.setLocalMatrix(new Matrix());
}
}
canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
}
else
{
if (mApplyGravity)
{
copyBounds(mDstRect);
mApplyGravity = false;
}
if (needMirroring())
{
updateMirrorMatrix(mDstRect.right - mDstRect.left);
shader.setLocalMatrix(mMirrorMatrix);
}
else
{
if (mMirrorMatrix != null)
{
mMirrorMatrix = null;
shader.setLocalMatrix(new Matrix());
}
}
canvas.drawRect(mDstRect,state.mPaint);
}
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public int getOpacity() {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
public void inflate(Resources r, XmlPullParser parser,AttributeSet attrs)
throws XmlPullParserException, IOException
{
int attrsCount = attrs.getAttributeCount();
Paint localPaint = new Paint();
for (int i = 0; i < attrsCount; i++)
{
String attrsName = attrs.getAttributeName(i);
if (attrsName.equalsIgnoreCase("src"))
{
String resName = attrs.getAttributeValue(i);
TypedValue paramTypedValue = new TypedValue();
String[] attrvalues = resName.split("/");
String attrType = attrvalues[0];
attrType = attrType.replaceAll("@","");
String attrName = attrvalues[1];
int resId = r.getIdentifier(attrName,attrType,"com.BeeFramework.example");
int resId2 = ResourcesFactory.getResId(attrName,R.drawable.class);
r.getValue(resId,paramTypedValue,true);
String fileName = paramTypedValue.string.toString();
String absolutePath = ThemeManager.getInstance().getThemeFilePath() +"/"+ fileName;
final Bitmap bitmap = BitmapFactory.decodeFile(absolutePath);
if (bitmap == null)
{
throw new XmlPullParserException(parser.getPositionDescription() +
": <bitmap> requires a valid src attribute");
}
else
{
mBitmap = bitmap;
}
}
else if (attrsName.equalsIgnoreCase("antialias"))
{
localPaint.setAntiAlias(attrs.getAttributeBooleanValue(i,localPaint.isAntiAlias()));
}
else if (attrsName.equalsIgnoreCase("filter"))
{
localPaint.setFilterBitmap(attrs.getAttributeBooleanValue(i,localPaint.isFilterBitmap()));
}
else if (attrsName.equalsIgnoreCase("dither"))
{
localPaint.setDither(attrs.getAttributeBooleanValue(i,localPaint.isDither()));
}
else if (attrsName.equalsIgnoreCase("gravity"))
{
int gravity = attrs.getAttributeIntValue(i, Gravity.FILL);
setGravity(gravity);
}
else if (attrsName.equalsIgnoreCase("tileMode"))
{
int tileMode = attrs.getAttributeIntValue(i,-1);
if (tileMode != -1)
{
switch (tileMode)
{
case 0:
setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
break;
case 1:
setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
break;
case 2:
setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
}
}
}
Log.d(attrsName);
}
}
final static public class BeeBitmapState extends ConstantState
{
Bitmap mBitmap;
int mChangingConfigurations;
int mGravity = new Gravity().FILL;
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX = null;
Shader.TileMode mTileModeY = null;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mRebuildShader;
boolean mAutoMirrored;
BeeBitmapState(Bitmap bitmap)
{
mBitmap = bitmap;
}
BeeBitmapState(BeeBitmapState bitmapState)
{
this(bitmapState.mBitmap);
mChangingConfigurations = bitmapState.mChangingConfigurations;
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
mTargetDensity = bitmapState.mTargetDensity;
mPaint = new Paint(bitmapState.mPaint);
mRebuildShader = bitmapState.mRebuildShader;
mAutoMirrored = bitmapState.mAutoMirrored;
}
public Bitmap getBitmap()
{
return mBitmap;
}
@Override
public Drawable newDrawable() {
return new BeeBitmapDrawable(this,null);
}
@Override
public int getChangingConfigurations() {
return 0;
}
}
}