/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2001-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.ui;
import totalcross.ui.gfx.*;
/**
* PagePosition implements the empty and filled balls that indicates the current
* page in a set of pages, very common on Android and iPhone.
*
* It has three properties:
* <ol>
* <li> visible count: the number of visible balls
* <li> count: the number of balls that will be displayed. Can be less, equal or greater than visible count
* <li> position: the current position of the filled ball
* </ol>
*
* @since TotalCross 1.3
*/
public class PagePosition extends Control
{
protected int visibleCount, count, position=1;
/** Constructs a new PagePosition with the given number of visible balls.
* This number cannot be changed later.
*/
public PagePosition(int visibleCount)
{
this.count = this.visibleCount = visibleCount;
}
/** Sets the balls count. Invalid values are forced to a valid range. */
public void setCount(int c)
{
if (c < 1) c = 1;
count = c;
Window.needsPaint = true;
}
/** Sets the current position (starting at 1). Invalid values are forced to a valid range. */
public void setPosition(int p)
{
if (p < 1) p = 1; else
if (p > count) p = count;
position = p;
Window.needsPaint = true;
}
/** Returns the visibleCount passed in the constructor. */
public int getVisibleCount()
{
return visibleCount;
}
/** Returns the ball count. */
public int getCount()
{
return count;
}
/** Returns the current position */
public int getPosition()
{
return position;
}
/** Increments the current position. If wrap is true, when position gets above count, it wraps to 1. */
public void inc(boolean wrap)
{
if (wrap && ++position > count)
position = 1;
else
if (!wrap && position < count)
position++;
Window.needsPaint = true;
}
/** Decrements the current position. If wrap is true, when position gets below 1, it wraps to count. */
public void dec(boolean wrap)
{
if (wrap && --position < 1)
position = count;
else
if (!wrap && position > 1)
position--;
Window.needsPaint = true;
}
public void onPaint(Graphics g)
{
if (!transparentBackground)
{
g.backColor = backColor;
g.fillRect(0,0,width,height);
}
int pos = position-1;
int k = Math.min(height,width/(visibleCount+1));
int r = k/3;
int n = count < visibleCount ? count : visibleCount;
int mid = n / 2;
int pageCount = count / visibleCount;
boolean exactFraction = (count % visibleCount) == 0;
if (exactFraction)
pageCount--;
int curPage = pos / visibleCount;
boolean leftArrow = count > visibleCount && (n==1 ? position > 1 : pos >= visibleCount);
boolean rightArrow = count > visibleCount && (n==1 ? position < count : curPage < pageCount);
int x = 0;
int y = (k-r*2)/2;
int x2 = width-r-1;
// draw the arrows
if (leftArrow)
g.drawArrow(x,y,r+1, Graphics.ARROW_LEFT, false, foreColor);
if (rightArrow)
g.drawArrow(x2,y,r+1, Graphics.ARROW_RIGHT, false, foreColor);
x += k-r;
int x0 = x;
if (count < visibleCount) // center
x0 = x = (width-n*k)/2 + r;
g.backColor = g.foreColor = foreColor;
// draw the empty circles
for (int i = rightArrow ? n : exactFraction ? visibleCount : count % visibleCount; --i >= 0; x += k)
g.drawCircle(x+r,y+r,r);
// draw the current position
int p = n == 1 ? mid : leftArrow && rightArrow ? pos % visibleCount : rightArrow ? pos : pos % visibleCount;
x = x0 + (n == 1 ? 0 : p * k);
g.fillCircle(x+r,y+r,r);
}
public int getPreferredWidth()
{
return getPreferredHeight()*(visibleCount+1)+1;
}
public int getPreferredHeight()
{
return fmH/2;
}
}