package uk.org.smithfamily.mslogger.widgets.renderers;
import uk.org.smithfamily.mslogger.dashboards.DashboardView;
import uk.org.smithfamily.mslogger.widgets.Indicator;
import uk.org.smithfamily.mslogger.widgets.Indicator.DisplayType;
import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.graphics.Path.FillType;
import android.util.SparseArray;
/**
*
*/
public class Gauge extends Painter
{
public Gauge(final DashboardView parent, final Indicator model, final Context c)
{
super(parent, model, c);
}
private final double pi = Math.PI;
private Paint titlePaint;
private Paint valuePaint;
private Paint pointerPaint;
private Paint scalePaint;
private RectF rimRect;
private Paint rimPaint;
private Paint rimCirclePaint;
private RectF faceRect;
private Paint facePaint;
private Paint backgroundPaint;
private volatile Bitmap background;
private final SparseArray<Bitmap> backgrounds = new SparseArray<Bitmap>(4);
private int lastBGColour;
private static final float rimSize = 0.02f;
@Override
protected void init(final Context c)
{
initDrawingTools(c);
}
private synchronized void regenerateBackground(final int width, final int height)
{
if ((height == 0) || (width == 0))
{
return;
}
final int index = getBgColour();
background = backgrounds.get(index);
if (background != null)
{
return;
}
background = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas backgroundCanvas = new Canvas(background);
final float scale = Math.min(height, width);
backgroundCanvas.save(Canvas.MATRIX_SAVE_FLAG);
backgroundCanvas.scale(scale, scale);
drawFace(backgroundCanvas);
drawScale(backgroundCanvas);
drawTitle(backgroundCanvas);
backgrounds.put(index, background);
}
private synchronized void drawBackground(final Canvas canvas)
{
final int height = (int) (bottom - top);
final int width = (int) (right - left);
if ((background == null) || (getBgColour() != lastBGColour))
{
regenerateBackground(width, height);
lastBGColour = getBgColour();
}
canvas.drawBitmap(background, left, top, backgroundPaint);
}
/**
*
* @param canvas
*/
@Override
public void renderFrame(final Canvas canvas)
{
final int height = (int) (bottom - top);
final int width = (int) (right - left);
if ((width == 0) || (height == 0))
{// We're not ready to do this yet
return;
}
drawBackground(canvas);
final float scale = Math.min(height, width);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(left, top);
canvas.scale(scale, scale);
drawPointer(canvas);
if (model.isDisabled())
{
model.setValue(model.getMin());
}
else
{
drawValue(canvas);
}
canvas.restore();
}
/**
*
* @param context
*/
private void initDrawingTools(final Context context)
{
int anti_alias_flag = Paint.ANTI_ALIAS_FLAG;
if (parent.isInEditMode())
{
anti_alias_flag = 0;
}
rimRect = new RectF(0.0f, 0.0f, 1.0f, 1.0f);
faceRect = new RectF();
if (!parent.isInEditMode())
{
faceRect.set(rimRect.left + rimSize, rimRect.top + rimSize, rimRect.right - rimSize, rimRect.bottom - rimSize);
}
else
{
faceRect = rimRect;
}
// the linear gradient is a bit skewed for realism
rimPaint = new Paint();
if (!parent.isInEditMode())
{
rimPaint.setFlags(anti_alias_flag);
rimPaint.setShader(new LinearGradient(0.40f, 0.0f, 0.60f, 1.0f, Color.rgb(0xf0, 0xf5, 0xf0), Color.rgb(0x30, 0x31, 0x30), Shader.TileMode.CLAMP));
}
rimCirclePaint = new Paint();
if (!parent.isInEditMode())
{
rimCirclePaint.setAntiAlias(true);
rimCirclePaint.setStyle(Paint.Style.STROKE);
rimCirclePaint.setColor(Color.argb(0x4f, 0x33, 0x36, 0x33));
rimCirclePaint.setStrokeWidth(0.005f);
}
facePaint = new Paint();
facePaint.setFilterBitmap(true);
facePaint.setStyle(Paint.Style.FILL);
facePaint.setColor(Color.BLACK);
facePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
titlePaint = new Paint();
titlePaint.setColor(Color.WHITE);
titlePaint.setTextAlign(Paint.Align.CENTER);
titlePaint.setFlags(anti_alias_flag);
titlePaint.setLinearText(true);
titlePaint.setAntiAlias(true);
valuePaint = new Paint();
valuePaint.setColor(Color.WHITE);
valuePaint.setTextSize(0.1f);
valuePaint.setTextAlign(Paint.Align.CENTER);
valuePaint.setFlags(anti_alias_flag);
valuePaint.setLinearText(true);
valuePaint.setAntiAlias(true);
pointerPaint = new Paint();
pointerPaint.setColor(Color.WHITE);
pointerPaint.setAntiAlias(true);
pointerPaint.setStrokeWidth((0.5f / 48.0f));
pointerPaint.setStyle(Style.FILL_AND_STROKE);
pointerPaint.setFlags(anti_alias_flag);
pointerPaint.setAntiAlias(true);
scalePaint = new Paint();
scalePaint.setColor(Color.WHITE);
scalePaint.setAntiAlias(true);
scalePaint.setTextSize(0.05f);
scalePaint.setTextAlign(Paint.Align.CENTER);
scalePaint.setFlags(anti_alias_flag);
scalePaint.setAntiAlias(true);
scalePaint.setLinearText(true);
backgroundPaint = new Paint();
backgroundPaint.setFilterBitmap(true);
}
/**
*
* @param canvas
*/
private void drawTitle(final Canvas canvas)
{
titlePaint.setTextSize(0.07f);
titlePaint.setColor(getFgColour());
canvas.drawText(model.getTitle(), 0.5f, 0.25f, titlePaint);
titlePaint.setTextSize(0.05f);
canvas.drawText(model.getUnits(), 0.5f, 0.32f, titlePaint);
}
/**
*
* @param canvas
*/
private void drawValue(final Canvas canvas)
{
valuePaint.setColor(getFgColour());
final float displayValue = (float) (Math.floor((model.getValue() / Math.pow(10, -model.getVd())) + 0.5) * Math.pow(10, -model.getVd()));
String text;
if (model.getVd() <= 0)
{
text = Integer.toString((int) displayValue);
}
else
{
text = Float.toString(displayValue);
}
canvas.drawText(text, 0.5f, 0.65f, valuePaint);
}
/**
*
* @param canvas
*/
private void drawPointer(final Canvas canvas)
{
final float backRadius = 0.042f;
final double angularRange = 270.0 / (model.getMax() - model.getMin());
double pointerValue = currentValue;
if (pointerValue < model.getMin())
{
pointerValue = model.getMin();
}
if (pointerValue > model.getMax())
{
pointerValue = model.getMax();
}
pointerPaint.setColor(getFgColour());
canvas.drawCircle(0.5f, 0.5f, backRadius / 2.0f, pointerPaint);
final Path pointerPath = new Path(); // X Y
pointerPath.setFillType(FillType.EVEN_ODD);
pointerPath.moveTo(0.5f, 0.1f); // 0.500, 0.100
pointerPath.lineTo(0.5f + 0.010f, 0.5f + 0.05f); // 0.501, 0.505
pointerPath.lineTo(0.5f - 0.010f, 0.5f + 0.05f); // 0.499, 0.505
pointerPath.lineTo(0.5f, 0.1f); // 0.500, 0.100
canvas.save(Canvas.MATRIX_SAVE_FLAG);
final double angle = (((pointerValue - model.getMin()) * angularRange) + model.getOffsetAngle()) - 180;
canvas.rotate((float) angle, 0.5f, 0.5f);
canvas.drawPath(pointerPath, pointerPaint);
canvas.restore();
}
/**
*
* @param canvas
*/
private void drawScale(final Canvas canvas)
{
final float radius = 0.42f;
scalePaint.setColor(getFgColour());
final double range = (model.getMax() - model.getMin());
final double tenpower = Math.floor(Math.log10(range));
final double scalefactor = Math.pow(10, tenpower);
final double gaugeMax = model.getMax();
final double gaugeMin = model.getMin();
final double gaugeRange = gaugeMax - gaugeMin;
double step = scalefactor;
while ((gaugeRange / step) < 10)
{
step = step / 2;
}
for (double val = gaugeMin; val <= gaugeMax; val += step)
{
final float displayValue = (float) (Math.floor((val / Math.pow(10, -model.getLd())) + 0.5) * Math.pow(10, -model.getLd()));
String text;
if (model.getLd() <= 0)
{
text = Integer.toString((int) displayValue);
}
else
{
text = Float.toString(displayValue);
}
final double anglerange = 270.0 / gaugeRange;
final double angle = ((val - gaugeMin) * anglerange) + model.getOffsetAngle();
final double rads = (angle * pi) / 180.0;
final float x = (float) (0.5f - (radius * Math.cos(rads - (pi / 2.0))));
final float y = (float) (0.5f - (radius * Math.sin(rads - (pi / 2.0))));
canvas.drawText(text, x, y, scalePaint);
}
}
@Override
protected int getFgColour()
{
if (model.isDisabled())
{
return Color.DKGRAY;
}
if ((model.getValue() > model.getLowW()) && (model.getValue() < model.getHiW()))
{
return Color.WHITE;
}
else
{
return Color.BLACK;
}
}
/**
*
* @return
*/
private int getBgColour()
{
int c = Color.GRAY;
final double value = model.getValue();
if ((value > model.getLowW()) && (value < model.getHiW()))
{
c = Color.BLACK;
}
else if ((value <= model.getLowW()) || (value >= model.getHiW()))
{
c = Color.YELLOW;
}
if ((value <= model.getLowD()) || (value >= model.getHiD()))
{
c = Color.RED;
}
if (model.isDisabled())
{
c = Color.GRAY;
}
return c;
}
/**
*
* @param canvas
*/
private void drawFace(final Canvas canvas)
{
if (parent.isInEditMode())
{
facePaint.setColor(Color.RED);
facePaint.setStyle(Style.FILL);
canvas.drawOval(rimRect, facePaint);
return;
}
canvas.drawOval(rimRect, rimPaint);
// now the outer rim circle
canvas.drawOval(rimRect, rimCirclePaint);
facePaint.setColor(getBgColour());
canvas.drawOval(faceRect, facePaint);
}
/**
*
*/
@Override
public DisplayType getType()
{
return DisplayType.GAUGE;
}
@Override
protected synchronized void invalidateCaches()
{
int key = 0;
for (int i = 0; i < backgrounds.size(); i++)
{
key = backgrounds.keyAt(i);
final Bitmap b = backgrounds.get(key);
b.recycle();
}
backgrounds.clear();
background = null;
}
}