package org.tndata.android.compass.ui;

import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;


public class FontFitTextView extends TextView{
    private static final float THRESHOLD = 0.5f;

    //Attributes
    private Paint mTestPaint;


    public FontFitTextView(Context context){
        super(context);
        initialise();
    }

    public FontFitTextView(Context context, AttributeSet attrs){
        super(context, attrs);
        initialise();
    }

    private void initialise(){
        mTestPaint = new Paint();
        mTestPaint.set(this.getPaint());
    }

    /**
     * Re size the font so the specified text fits in the text box
     * assuming the text box is the specified width.
     */
    private void refitText(String text, int textWidth){
        if (textWidth > 0){
            int targetWidth = textWidth-this.getPaddingLeft()-this.getPaddingRight();
            float high, low;

            //Test the current size
            mTestPaint.set(this.getPaint());
            mTestPaint.setTextSize(getTextSize());
            //If the target width is lower than the text width at that size
            if (targetWidth < mTestPaint.measureText(text)){
                //Find values for high and low such that low = high/2 and the target width
                //  is somewhere in between.
                high = getTextSize();
                low = high/2;
                mTestPaint.setTextSize(low);
                while (targetWidth < mTestPaint.measureText(text)){
                    high /= 2;
                    low /= 2;
                    mTestPaint.setTextSize(low);
                }

                //Do a binary search between high and low to find the optimal value
                while (high-low > THRESHOLD){
                    float size = (high+low)/2;
                    mTestPaint.setTextSize(size);
                    if (mTestPaint.measureText(text) >= targetWidth){
                        high = size;
                    }
                    else{
                        low = size; // too small
                    }
                }
                setTextSize(TypedValue.COMPLEX_UNIT_PX, low);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int height = getMeasuredHeight();
        refitText(this.getText().toString(), parentWidth);
        this.setMeasuredDimension(parentWidth, height);
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int before, int after){
        refitText(text.toString(), this.getWidth());
    }

    @Override
    protected void onSizeChanged(int wid, int hht, int oldWid, int oldHgt){
        if (wid != oldWid){
            refitText(this.getText().toString(), wid);
        }
    }
}

@@ -196,16 +196,202 @@
 View;%0A%0A%0A
+/**%0A * A class that scales down the font size if needed to make it fit inside a TextView%0A * of a fixed size.%0A *%0A * @author Original author unknown%0A * @author Edited by Ismael Alonso%0A */%0A
 public c
@@ -528,16 +528,94 @@
 aint;%0A%0A%0A
+    /**%0A     * Constructor.%0A     *%0A     * @param context the context.%0A     */%0A
     publ
@@ -700,24 +700,165 @@
 e();%0A    %7D%0A%0A
+    /**%0A     * Constructor. For xml initialisation.%0A     *%0A     * @param context the context.%0A     * @param attrs the attribute set.%0A     */%0A
     public F
@@ -966,24 +966,129 @@
 e();%0A    %7D%0A%0A
+    /**%0A     * Creates the test paint, which will be used later on to take measures of the text.%0A     */%0A
     private 
@@ -1207,15 +1207,17 @@
   * 
-Re size
+Decreases
  the
@@ -1227,23 +1227,23 @@
 nt s
-o the specified
+ize so that the
  tex
@@ -1260,68 +1260,183 @@
 the 
-text box%0A     * assuming the text box is the specified width
+TextView in the cases where%0A     * the text would be wider than the TextView.%0A     *%0A     * @param text the TextView's text.%0A     * @param viewWidth the width of this TextView
 .%0A  
@@ -1485,20 +1485,20 @@
 xt, int 
-text
+view
 Width)%7B%0A
@@ -1509,20 +1509,20 @@
     if (
-text
+view
 Width %3E 
@@ -1555,20 +1555,20 @@
 Width = 
-text
+view
 Width-th
@@ -2777,21 +2777,8 @@
 ize;
- // too small
 %0A   
@@ -2805,32 +2805,117 @@
                %7D
+%0A%0A                //Finally, set the size as the lower value to avoid overestimating.
 %0A               

Add documentation