/* * Copyright (C) 2009 Muthu Ramadoss. All rights reserved. * * Modified from Romain Guy Shelves project to suit Books-Exchange requirements. * Original source from Shelves - http://code.google.com/p/shelves/ */ /* * Copyright (C) 2008 The Android Open Source Project, Romain Guy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.androidrocks.bex.drawable; import android.graphics.*; import android.graphics.drawable.Drawable; class LayerDrawable extends Drawable implements Drawable.Callback { LayerState mLayerState; private int[] mPaddingL; private int[] mPaddingT; private int[] mPaddingR; private int[] mPaddingB; private final Rect mTmpRect = new Rect(); private Drawable mParent; private boolean mBlockSetBounds; LayerDrawable(Drawable... layers) { this(null, layers); } LayerDrawable(LayerState state, Drawable... layers) { this(state); int length = layers.length; Rec[] r = new Rec[length]; final LayerState layerState = mLayerState; for (int i = 0; i < length; i++) { r[i] = new Rec(); r[i].mDrawable = layers[i]; layers[i].setCallback(this); layerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations(); } layerState.mNum = length; layerState.mArray = r; ensurePadding(); } LayerDrawable(LayerState state) { LayerState as = createConstantState(state); mLayerState = as; if (as.mNum > 0) { ensurePadding(); } } LayerState createConstantState(LayerState state) { return new LayerState(state, this); } public void invalidateDrawable(Drawable who) { invalidateSelf(); } public void scheduleDrawable(Drawable who, Runnable what, long when) { scheduleSelf(what, when); } public void unscheduleDrawable(Drawable who, Runnable what) { unscheduleSelf(what); } @Override public void draw(Canvas canvas) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.draw(canvas); } } @Override public int getChangingConfigurations() { return super.getChangingConfigurations() | mLayerState.mChangingConfigurations | mLayerState.mChildrenChangingConfigurations; } @Override public boolean getPadding(Rect padding) { padding.left = 0; padding.top = 0; padding.right = 0; padding.bottom = 0; final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { reapplyPadding(i, array[i]); padding.left = Math.max(padding.left, mPaddingL[i]); padding.top = Math.max(padding.top, mPaddingT[i]); padding.right = Math.max(padding.right, mPaddingR[i]); padding.bottom = Math.max(padding.bottom, mPaddingB[i]); } return true; } @Override public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setVisible(visible, restart); } return changed; } @Override public void setDither(boolean dither) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setDither(dither); } } @Override public void setAlpha(int alpha) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setAlpha(alpha); } } @Override public void setColorFilter(ColorFilter cf) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { array[i].mDrawable.setColorFilter(cf); } } @Override public int getOpacity() { return mLayerState.getOpacity(); } @Override public boolean isStateful() { return mLayerState.isStateful(); } @Override protected boolean onStateChange(int[] state) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean changed = false; for (int i = 0; i < N; i++) { final Rec r = array[i]; if (r.mDrawable.setState(state)) { changed = true; } if (reapplyPadding(i, r)) { paddingChanged = true; } } if (paddingChanged) { onBoundsChange(getBounds()); } return changed; } @Override protected boolean onLevelChange(int level) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; boolean paddingChanged = false; boolean changed = false; for (int i = 0; i < N; i++) { final Rec r = array[i]; if (r.mDrawable.setLevel(level)) { changed = true; } if (reapplyPadding(i, r)) { paddingChanged = true; } } if (paddingChanged) { onBoundsChange(getBounds()); } return changed; } @Override public void setBounds(int left, int top, int right, int bottom) { if (mBlockSetBounds) return; final int width = mLayerState.mArray[0].mDrawable.getIntrinsicWidth(); left -= (width - (right - left)) / 2.0f; right = left + width; bottom = top + getIntrinsicHeight(); super.setBounds(left, top, right, bottom); if (mParent != null) { mBlockSetBounds = true; mParent.setBounds(left, top, right, bottom); mBlockSetBounds = false; } } public void setParent(Drawable drawable) { mParent = drawable; } @Override protected void onBoundsChange(Rect bounds) { final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; int padL = 0, padT = 0, padR = 0, padB = 0; for (int i = 0; i < N; i++) { final Rec r = array[i]; r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT, bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB); padL += mPaddingL[i]; padR += mPaddingR[i]; padT += mPaddingT[i]; padB += mPaddingB[i]; } } @Override public int getIntrinsicWidth() { int width = -1; final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; int padL = 0, padR = 0; for (int i = 0; i < N; i++) { final Rec r = array[i]; int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { width = w; } padL += mPaddingL[i]; padR += mPaddingR[i]; } return width; } @Override public int getIntrinsicHeight() { int height = -1; final Rec[] array = mLayerState.mArray; final int N = mLayerState.mNum; int padT = 0, padB = 0; for (int i = 0; i < N; i++) { final Rec r = array[i]; int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + +padT + padB; if (h > height) { height = h; } padT += mPaddingT[i]; padB += mPaddingB[i]; } return height; } private boolean reapplyPadding(int i, Rec r) { final Rect rect = mTmpRect; r.mDrawable.getPadding(rect); if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) { mPaddingL[i] = rect.left; mPaddingT[i] = rect.top; mPaddingR[i] = rect.right; mPaddingB[i] = rect.bottom; return true; } return false; } private void ensurePadding() { final int N = mLayerState.mNum; if (mPaddingL != null && mPaddingL.length >= N) { return; } mPaddingL = new int[N]; mPaddingT = new int[N]; mPaddingR = new int[N]; mPaddingB = new int[N]; } @Override public ConstantState getConstantState() { if (mLayerState.canConstantState()) { mLayerState.mChangingConfigurations = super.getChangingConfigurations(); return mLayerState; } return null; } static class Rec { public Drawable mDrawable; public int mInsetL, mInsetT, mInsetR, mInsetB; public int mId; } static class LayerState extends ConstantState { int mNum; Rec[] mArray; int mChangingConfigurations; int mChildrenChangingConfigurations; private boolean mHaveOpacity = false; private int mOpacity; private boolean mHaveStateful = false; private boolean mStateful; private boolean mCheckedConstantState; private boolean mCanConstantState; LayerState(LayerState orig, LayerDrawable owner) { if (orig != null) { final Rec[] origRec = orig.mArray; final int N = orig.mNum; mNum = N; mArray = new Rec[N]; mChangingConfigurations = orig.mChangingConfigurations; mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations; for (int i = 0; i < N; i++) { final Rec r = mArray[i] = new Rec(); final Rec or = origRec[i]; r.mDrawable = or.mDrawable.getConstantState().newDrawable(); r.mDrawable.setCallback(owner); r.mInsetL = or.mInsetL; r.mInsetT = or.mInsetT; r.mInsetR = or.mInsetR; r.mInsetB = or.mInsetB; r.mId = or.mId; } mHaveOpacity = orig.mHaveOpacity; mOpacity = orig.mOpacity; mHaveStateful = orig.mHaveStateful; mStateful = orig.mStateful; mCheckedConstantState = mCanConstantState = true; } else { mNum = 0; mArray = null; } } @Override public Drawable newDrawable() { return new LayerDrawable(this); } @Override public int getChangingConfigurations() { return mChangingConfigurations; } public final int getOpacity() { if (mHaveOpacity) { return mOpacity; } final int N = mNum; final Rec[] array = mArray; int op = N > 0 ? array[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT; for (int i = 1; i < N; i++) { op = Drawable.resolveOpacity(op, array[i].mDrawable.getOpacity()); } mOpacity = op; mHaveOpacity = true; return op; } public final boolean isStateful() { if (mHaveStateful) { return mStateful; } boolean stateful = false; final int N = mNum; final Rec[] array = mArray; for (int i = 0; i < N; i++) { if (array[i].mDrawable.isStateful()) { stateful = true; break; } } mStateful = stateful; mHaveStateful = true; return stateful; } public synchronized boolean canConstantState() { final Rec[] array = mArray; if (!mCheckedConstantState && array != null) { mCanConstantState = true; final int N = mNum; for (int i = 0; i < N; i++) { if (array[i].mDrawable.getConstantState() == null) { mCanConstantState = false; break; } } mCheckedConstantState = true; } return mCanConstantState; } } }