package totalcross.ui.anim;
import totalcross.sys.*;
import totalcross.ui.*;
/** Creates an animation that follows a path.
* @since TotalCross 3.03
*/
public class PathAnimation extends ControlAnimation
{
private int xf,yf,x,y;
private int dir;
private PathAnimation(Control c, AnimationFinished animFinish, int totalTime)
{
super(c,animFinish,totalTime);
}
private void setPath(int x0, int y0, int xf, int yf) throws Exception
{
x = x0;
y = y0;
this.xf = xf;
this.yf = yf;
}
protected void animate()
{
update();
c.setRect(x,y,Control.KEEP,Control.KEEP);
Window.needsPaint = true;
}
public void stop(boolean abort)
{
super.stop(abort);
switch (dir)
{
case Control.LEFT: c.setSet(Control.LEFT,Control.TOP); break;
case Control.RIGHT: c.setSet(Control.RIGHT,Control.TOP); break;
case Control.TOP: c.setSet(Control.CENTER,Control.TOP); break;
case Control.BOTTOM: c.setSet(Control.CENTER,Control.BOTTOM); break;
case Control.CENTER: c.setSet(Control.CENTER,Control.CENTER); break;
}
}
private void update()
{
double distanceRemaining = Math.sqrt((xf-x)*(xf-x) + (yf-y)*(yf-y));
int speed = (int)Math.ceil(computeSpeed(distanceRemaining));
if ((x == xf && y == yf) || speed == 0)
{
x = xf; y = yf;
stop(false);
return;
}
int dx = xf - this.x;
int dy = yf - this.y;
int steps;
if (dx == 0) // vertical move
{
steps = Math.min(dy >= 0 ? dy : -dy, speed);
if (dy < 0)
this.y -= steps;
else
if (dy > 0)
this.y += steps;
}
else
if (dy == 0) // horizontal move
{
steps = Math.min(dx >= 0 ? dx : -dx, speed);
if (dx < 0)
this.x -= steps;
else
if (dx > 0)
this.x += steps;
}
else
{
dx = dx >= 0 ? dx : -dx;
dy = dy >= 0 ? dy : -dy;
int CurrentX = this.x;
int CurrentY = this.y;
int Xincr = (this.x > xf) ? -1 : 1;
int Yincr = (this.y > yf) ? -1 : 1;
steps = speed;
if (dx >= dy)
{
int dPr = dy << 1;
int dPru = dPr - (dx << 1);
int P = dPr - dx;
for (; dx >= 0 && steps > 0; dx--)
{
this.x = CurrentX;
this.y = CurrentY;
CurrentX += Xincr;
steps--;
if (P > 0)
{
CurrentY += Yincr;
steps--;
P += dPru;
}
else P += dPr;
}
}
else
{
int dPr = dx << 1;
int dPru = dPr - (dy << 1);
int P = dPr - dy;
for (; dy >= 0 && steps > 0; dy--)
{
this.x = CurrentX;
this.y = CurrentY;
CurrentY += Yincr;
steps--;
if (P > 0)
{
CurrentX += Xincr;
steps--;
P += dPru;
}
else P += dPr;
}
}
}
}
/** Creates a path animation, moving the control to the given x and y positions.
* @param c The control to be moved
* @param toX The destination X coordinate
* @param toY The destination Y coordinate
* @param animFinish An interface method to be called when the animation finished, or null if none.
* @param totalTime The total time in millis that the animation will take, or -1 to use the default value (800ms).
*/
public static PathAnimation create(Control c, int toX, int toY, AnimationFinished animFinish, int totalTime) throws Exception
{
PathAnimation anim = new PathAnimation(c,animFinish,totalTime);
anim.setPath(c.getX(),c.getY(),toX,toY);
return anim;
}
/** Creates a path animation, moving the control from a position to another.
* @param c The control to be moved
* @param fromX The origin X coordinate
* @param fromY The origin Y coordinate
* @param toX The destination X coordinate
* @param toY The destination Y coordinate
* @param animFinish An interface method to be called when the animation finished, or null if none.
* @param totalTime The total time in millis that the animation will take, or -1 to use the default value (800ms).
*/
public static PathAnimation create(Control c, int fromX, int fromY, int toX, int toY, AnimationFinished animFinish, int totalTime) throws Exception
{
PathAnimation anim = new PathAnimation(c,animFinish,totalTime);
anim.setPath(fromX,fromY,toX,toY);
return anim;
}
/** Creates a path animation, moving the control in a direction.
* @param c The control to be moved
* @param direction One of BOTTOM, -BOTTOM, TOP, -TOP, LEFT, -LEFT, RIGHT, -RIGHT. Any other value will return null.
* @param animFinish An interface method to be called when the animation finished, or null if none.
* @param totalTime The total time in millis that the animation will take, or -1 to use the default value (800ms).
*/
public static PathAnimation create(Control c, int direction, AnimationFinished animFinish, int totalTime) throws Exception
{
PathAnimation anim = new PathAnimation(c,animFinish,totalTime);
anim.dir = direction;
int x0,y0,xf,yf;
int pw = c instanceof Window ? Settings.screenWidth : c.getParent().getWidth();
int ph = c instanceof Window ? Settings.screenHeight : c.getParent().getHeight();
int cw = c.getWidth();
int ch = c.getHeight();
xf = x0 = (pw - cw) / 2;
y0 = yf = (ph - ch) / 2;
switch (direction)
{
case -Control.BOTTOM:
y0 = c.getY();
yf = ph;
break;
case Control.BOTTOM:
y0 = ph;
yf = ph - ch;
break;
case -Control.TOP:
y0 = c.getY();
yf = -ch;
break;
case Control.TOP:
y0 = -ch;
yf = 0;
break;
case -Control.LEFT:
x0 = c.getX();
xf = -cw;
break;
case Control.LEFT:
x0 = -cw;
xf = 0;
break;
case -Control.RIGHT:
x0 = c.getX();
xf = pw;
break;
case Control.RIGHT:
x0 = pw;
xf = pw - cw;
break;
default:
return null;
}
anim.setPath(x0,y0,xf,yf);
return anim;
}
}