package com.rubika.aotalk.ui.improvedtextview;
import java.util.ArrayList;
import java.util.WeakHashMap;
import com.rubika.aotalk.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Pair;
import android.widget.TextView;
public class ImprovedTextView extends TextView {
private ArrayList<Shadow> outerShadows;
private WeakHashMap<String, Pair<Canvas, Bitmap>> canvasStore;
private float strokeWidth;
private Integer strokeColor;
private Join strokeJoin;
private float strokeMiter;
private int[] lockedCompoundPadding;
private boolean frozen = false;
public ImprovedTextView(Context context) {
super(context);
init(null);
}
public ImprovedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ImprovedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
@SuppressWarnings("deprecation")
public void init(AttributeSet attrs){
outerShadows = new ArrayList<Shadow>();
if(canvasStore == null){
canvasStore = new WeakHashMap<String, Pair<Canvas, Bitmap>>();
}
if(attrs != null){
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView);
String typefaceName = a.getString( R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvTypeface);
if(typefaceName != null) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), String.format("fonts/%s.ttf", typefaceName));
setTypeface(tf);
}
if(a.hasValue(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvBackground)){
Drawable background = a.getDrawable(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvBackground);
if(background != null){
this.setBackgroundDrawable(background);
}else{
this.setBackgroundColor(a.getColor(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvBackground, 0xff000000));
}
}
if(a.hasValue(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvOuterShadowColor)){
this.addOuterShadow(a.getFloat(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvOuterShadowRadius, 0),
a.getFloat(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvOuterShadowDx, 0),
a.getFloat(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvOuterShadowDy, 0),
a.getColor(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvOuterShadowColor, 0xff000000));
}
if(a.hasValue(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvStrokeColor)){
float strokeWidth = a.getFloat(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvStrokeWidth, 1);
int strokeColor = a.getColor(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvStrokeColor, 0xff000000);
float strokeMiter = a.getFloat(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvStrokeMiter, 10);
Join strokeJoin = null;
switch(a.getInt(R.styleable.com_rubika_aotalk_improvedtextview_ImprovedTextView_mtvStrokeJoinStyle, 0)){
case(0): strokeJoin = Join.MITER; break;
case(1): strokeJoin = Join.BEVEL; break;
case(2): strokeJoin = Join.ROUND; break;
}
this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter);
}
}
}
public void setStroke(float width, int color, Join join, float miter){
strokeWidth = width;
strokeColor = color;
strokeJoin = join;
strokeMiter = miter;
}
public void setStroke(float width, int color){
setStroke(width, color, Join.MITER, 10);
}
public void addOuterShadow(float r, float dx, float dy, int color){
if(r == 0){ r = 0.0001f; }
outerShadows.add(new Shadow(r,dx,dy,color));
}
public void clearOuterShadows(){
outerShadows.clear();
}
PorterDuffXfermode xmode1 = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
PorterDuffXfermode xmode2 = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
Rect r = new Rect();
@SuppressWarnings("deprecation")
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
freeze();
Drawable restoreBackground = this.getBackground();
Drawable[] restoreDrawables = this.getCompoundDrawables();
int restoreColor = this.getCurrentTextColor();
this.setCompoundDrawables(null, null, null, null);
for(Shadow shadow : outerShadows){
this.setShadowLayer(shadow.r, shadow.dx, shadow.dy, shadow.color);
super.onDraw(canvas);
}
this.setShadowLayer(0,0,0,0);
this.setTextColor(restoreColor);
if(strokeColor != null){
TextPaint paint = this.getPaint();
paint.setStyle(Style.STROKE);
paint.setStrokeJoin(strokeJoin);
paint.setStrokeMiter(strokeMiter);
this.setTextColor(strokeColor);
paint.setStrokeWidth(strokeWidth);
super.onDraw(canvas);
paint.setStyle(Style.FILL);
this.setTextColor(restoreColor);
}
if(restoreDrawables != null){
this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0], restoreDrawables[1], restoreDrawables[2], restoreDrawables[3]);
}
this.setBackgroundDrawable(restoreBackground);
this.setTextColor(restoreColor);
unfreeze();
}
// Keep these things locked while onDraw in processing
public void freeze(){
lockedCompoundPadding = new int[]{
getCompoundPaddingLeft(),
getCompoundPaddingRight(),
getCompoundPaddingTop(),
getCompoundPaddingBottom()
};
frozen = true;
}
public void unfreeze(){
frozen = false;
}
@Override
public void requestLayout(){
if(!frozen) super.requestLayout();
}
@Override
public void postInvalidate(){
if(!frozen) super.postInvalidate();
}
@Override
public void postInvalidate(int left, int top, int right, int bottom){
if(!frozen) super.postInvalidate(left, top, right, bottom);
}
@Override
public void invalidate(){
if(!frozen) super.invalidate();
}
@Override
public void invalidate(Rect rect){
if(!frozen) super.invalidate(rect);
}
@Override
public void invalidate(int l, int t, int r, int b){
if(!frozen) super.invalidate(l,t,r,b);
}
@Override
public int getCompoundPaddingLeft(){
return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0];
}
@Override
public int getCompoundPaddingRight(){
return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1];
}
@Override
public int getCompoundPaddingTop(){
return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2];
}
@Override
public int getCompoundPaddingBottom(){
return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3];
}
public static class Shadow{
float r;
float dx;
float dy;
int color;
public Shadow(float r, float dx, float dy, int color){
this.r = r;
this.dx = dx;
this.dy = dy;
this.color = color;
}
}
}