package uk.org.smithfamily.mslogger.dashboards;
import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
import uk.org.smithfamily.mslogger.widgets.Indicator;
import uk.org.smithfamily.mslogger.widgets.Location;
import uk.org.smithfamily.mslogger.widgets.renderers.*;
import android.content.Context;
import android.graphics.Canvas;
/**
* I couldn't decide if an Indicator should own it's Painter or if the Painter should own the Indicator. Ultimately neither owns the other, so this
* has both.
*
* @author dgs
*
*/
public class DashboardElement
{
private final Indicator indicator;
private Painter painter;
private final DashboardView parent;
private final Context context;
private float parentH;
private float parentW;
private float originalWidth;
private float originalHeight;
private float scale;
private float scaleY;
private float scaleX;
/**
*
* @param c
* @param i
* @param parent
*/
public DashboardElement(final Context c, final Indicator i, final DashboardView parent)
{
this.context = c;
this.indicator = i;
this.parent = parent;
checkPainterMatchesIndicator();
scaleToParent(parent.getWidth(), parent.getHeight());
}
/**
* Scale the dashboard element according to its parent (A dashboard view)
*
* @param w The width of the parent
* @param h The height of the parent
*/
public void scaleToParent(final int w, final int h)
{
if ((w == 0) || (h == 0))
{
return;
}
Location l = indicator.getLocation();
final float left = (float) (l.getLeft(w));
float right = (float) (l.getRight(w));
final float top = (float) (l.getTop(h));
float bottom = (float) (l.getBottom(h));
// Work out where the middle is as that is what MTC really wants to deal in
final float centreX = (float) ((right + left) / 2.0);
final float centreY = (float) ((top + bottom) / 2.0);
painter.setPos(left, top, right, bottom, centreX, centreY, 1, 1, 0);
this.parentW = w;
this.parentH = h;
originalWidth = painter.getWidth();
originalHeight = painter.getHeight();
right = left + originalWidth;
bottom = top + originalHeight;
l = new Location(left / w, top / h, right / w, bottom / h);
indicator.setLocation(l);
}
/**
* Create a new painter if none already exists or when the display type of the indicator changed
*/
public void checkPainterMatchesIndicator()
{
if ((painter == null) || (painter.getType() != indicator.getDisplayType()))
{
createPainter();
}
}
/**
* Create a Painter object for the dashboard element
*/
private void createPainter()
{
final Painter r;
switch (indicator.getDisplayType())
{
case GAUGE:
r = new Gauge(parent, indicator, context);
break;
case BAR:
r = new BarGraph(parent, indicator, context);
break;
case NUMERIC:
r = new NumericIndicator(parent, indicator, context);
break;
case HISTOGRAM:
r = new Histogram(parent, indicator, context);
break;
default:
r = new Gauge(parent, indicator, context);
break;
}
painter = r;
}
/**
* @return The Indicator object of the dashboard element
*/
public Indicator getIndicator()
{
return indicator;
}
/**
* @return The Painter object of the dashboard element
*/
public Painter getPainter()
{
checkPainterMatchesIndicator();
return painter;
}
/**
*
*/
public void setTargetValue()
{
painter.setTargetValue(indicator.getValue());
}
/**
*
* @return
*/
public boolean updateAnimation()
{
return painter.updateAnimation();
}
/**
*
* @param c
*/
public void renderFrame(final Canvas c)
{
painter.renderFrame(c);
}
/**
* Set the position and scale of an image in screen coordinates
*
* @param newImgPosAndScale
* @return
*/
public boolean setPos(final PositionAndScale newImgPosAndScale)
{
return setPos(newImgPosAndScale.getXOff(), newImgPosAndScale.getYOff(), newImgPosAndScale.getScale(), newImgPosAndScale.getScaleX(), newImgPosAndScale.getScaleY(), newImgPosAndScale.getAngle());
}
/**
* Set the position and scale of an image in screen coordinates
*
* @param centreX
* @param centreY
* @param scaleX
* @param scaleY
* @param angle
* @return
*/
private boolean setPos(float centreX, float centreY, final float scale, float scaleX, float scaleY, final float angle)
{
Location l = indicator.getLocation();
final float width = originalWidth;
final float height = originalHeight;
if (painter.isIsotropic())
{
scaleX = scale;
scaleY = scale;
}
float ws = (width / 2) * scaleX;
float hs = (height / 2) * scaleY;
// Try to ensure we don't vanish into a pixel
ws = Math.max(ws, parentW / 20f);
hs = Math.max(hs, parentH / 20f);
float left = centreX - ws;
float top = centreY - hs;
float right = centreX + ws;
float bottom = centreY + hs;
if (left < 0)
{
centreX -= left;
right -= left;
left = 0;
}
if (top < 0)
{
centreY -= top;
bottom -= top;
top = 0;
}
if (right > parentW)
{
centreX -= (right - parentW);
left -= (right - parentW);
right = parentW;
}
if (bottom > parentH)
{
centreY -= (bottom - parentH);
top -= (bottom - parentH);
bottom = parentH;
}
this.scale = (scaleX + scaleY) / 2.0f;
this.scaleX = scaleX;
this.scaleY = scaleY;
painter.setPos(left, top, right, bottom, centreX, centreY, scaleX, scaleY, angle);
l = new Location(left / parentW, top / parentH, right / parentW, bottom / parentH);
indicator.setLocation(l);
return true;
}
/**
*
* @param scrnX
* @param scrnY
* @return
*/
public boolean contains(final float scrnX, final float scrnY)
{
final Location l = indicator.getLocation();
return ((scrnX >= l.getLeft(parentW)) && (scrnX <= l.getRight(parentW)) && (scrnY >= l.getTop(parentH)) && (scrnY <= l.getBottom(parentH)));
}
/**
* @return
*/
public float getCentreY()
{
final Location l = indicator.getLocation();
return l.getCentreY(parentH);
}
/**
* @return
*/
public float getCentreX()
{
final Location l = indicator.getLocation();
return l.getCentreX(parentW);
}
/**
* @return
*/
public float getScale()
{
return scale;
}
/**
*
*/
public void editStart()
{
// TODO Auto-generated method stub
}
/**
*
*/
public void editFinished()
{
// TODO Auto-generated method stub
}
public double getAngle()
{
return indicator.getOffsetAngle();
}
public float getScaleX()
{
return scaleX;
}
public float getScaleY()
{
return scaleY;
}
}