/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-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.chart;
import totalcross.sys.*;
import totalcross.ui.*;
import totalcross.ui.event.ControlEvent;
import totalcross.ui.event.Event;
import totalcross.ui.event.KeyEvent;
import totalcross.ui.event.PenEvent;
import totalcross.ui.gfx.Color;
import totalcross.ui.gfx.Coord;
import totalcross.ui.gfx.Graphics;
import totalcross.ui.gfx.Rect;
import totalcross.util.Vector;
/** Abstract class used by points and line charts.
* @see LineChart
* @see XYChart
*/
public abstract class PointLineChart extends Chart
{
/** Contains all points that are currently painted on this chart */
protected Vector points = new Vector();
/** Flag to indicate whether the lines connecting points must be painted */
public boolean showLines;
/** Flag to indicate whether the points must be painted */
public boolean showPoints;
/** Flag to indicate whether is to show the selected value */
public boolean showValue = true;
/** The current selected series */
private int selectedSeries = -1;
/** The current selected value from <code>selectedSeries</code> */
private int selectedValue = -1;
/** The radious of each point (in pixels) */
public int pointR = 3;
/** The line thickness. */
public int lineThickness=1;
/** Flag to indicate whether this chart is focused */
private boolean hasFocus;
/** The axis that was selected. */
public int selectedAxis=-1;
/** Flag indicating if its to post an event when the user selects an axis. */
public boolean postEventOnAxisSelection;
public void onPaint(Graphics g)
{
// Draw lines
if (showLines)
{
int thick = lineThickness;
for (int i = series.size() - 1; i >= 0; i --) // for each series
{
Series s = (Series) series.items[i];
g.foreColor = s.color;
Vector v = (Vector) points.items[i]; // the series' points
if (v != null)
{
for (int j = 0, n = v.size() - 1; j < n; j++) // for each series point
if (s.yValues[j] != UNSET && s.yValues[j+1] != UNSET)
{
Coord c1 = (Coord) v.items[j];
Coord c2 = (Coord) v.items[j + 1];
g.drawThickLine(c1.x, c1.y, c2.x, c2.y, thick);
}
}
}
}
// Draw points
if (!showLines || showPoints || hasFocus || Settings.fingerTouch)
{
for (int i = series.size() - 1; i >= 0; i --) // for each series
{
Series s = (Series) series.items[i]; // the series
Vector v = (Vector) points.items[i]; // the series' points
if (v != null)
{
for (int j = v.size() - 1; j >= 0; j--) // for each series point
{
Coord c1 = (Coord) v.items[j];
int c = s.color;
if (showValue && selectedSeries == i && selectedValue == j)
c = Color.darker(c);
if (s.dot == null)
{
g.backColor = c;
g.fillCircle(c1.x, c1.y, pointR);
}
else
{
int dy;
int h = s.dot.getHeight();
switch (s.dotVAlign)
{
case Control.TOP : dy = c1.y-h; break;
case Control.BOTTOM: dy = c1.y; break;
default: dy = c1.y-h/2;
}
g.drawImage(s.dot, c1.x-s.dot.getWidth()/2, dy);
}
}
}
}
// Draw selection (text box)
if (selectedSeries != -1 && showValue)
{
Series s = (Series) series.items[selectedSeries];
String text = Convert.toCurrencyString(s.yValues[selectedValue], yDecimalPlaces);
if (s.xValues != null)
text = "(" + Convert.toCurrencyString(s.xValues[selectedValue], xDecimalPlaces) + "," + text + ")";
Coord c = (Coord) ((Vector) points.items[selectedSeries]).items[selectedValue];
drawTextBox(g, c.x, c.y, text);
}
}
}
public void onEvent(Event e)
{
switch (e.type)
{
case PenEvent.PEN_UP:
{
PenEvent pe = (PenEvent)e;
if (!hadParentScrolled() && xAxisX1 <= pe.x && pe.x <= xAxisX2)
{
int d = columnW/4;
for (int i = 0, xx = xAxisX1; xx <= xAxisX2; xx += columnW,i++)
if ((xx-d) <= pe.x && pe.x <= (xx+d))
{
selectedAxis = i;
postPressedEvent();
break;
}
}
break;
}
case PenEvent.PEN_DOWN:
{
PenEvent pe = (PenEvent) e;
int xx = pe.x;
int yy = pe.y;
if (xx < (xAxisX1 - pointR) || xx > (xAxisX2 + pointR) || yy > (yAxisY1 + pointR) || yy < (yAxisY2 - pointR))
{
hasFocus = false;
selectedSeries = -1;
selectedValue = -1;
Window.needsPaint = true;
}
else
{
hasFocus = true;
selectedSeries = -1; // clear selection
selectedValue = -1;
Rect r = new Rect();
int dim = fmH;
r.width = r.height = fmH*2;
for (int i = series.size() - 1; i >= 0; i --) // for each series
{
Vector v = (Vector) points.items[i]; // the series' points
if (v != null)
{
for (int j = v.size() - 1; j >= 0; j --) // for each series point
{
Coord c = (Coord) v.items[j];
r.x = c.x - dim;
r.y = c.y - dim;
if (r.contains(xx, yy))
{
selectedSeries = i;
selectedValue = j;
i = 0; // force outter for to exit
break;
}
}
}
}
Window.needsPaint = true;
}
break;
}
case KeyEvent.SPECIAL_KEY_PRESS:
{
KeyEvent ke = (KeyEvent) e;
if (ke.isActionKey()) // release focus
{
isHighlighting = true;
parent.requestFocus();
}
else if (ke.isNextKey()) // next point
{
if (selectedValue < ((Series) series.items[selectedSeries]).yValues.length - 1)
{
selectedValue ++;
Window.needsPaint = true;
}
else if (selectedSeries < series.size() - 1)
{
selectedSeries ++;
selectedValue = 0;
Window.needsPaint = true;
}
}
else if (ke.isPrevKey()) // previous point
{
if (selectedValue > 0)
{
selectedValue --;
Window.needsPaint = true;
}
else if (selectedSeries > 0)
{
selectedSeries --;
selectedValue = ((Series) series.items[selectedSeries]).yValues.length - 1;
Window.needsPaint = true;
}
}
break;
}
case ControlEvent.FOCUS_IN:
{
hasFocus = true;
if (series.size() > 0 && ((Series) series.items[0]).yValues.length > 0)
{
selectedSeries = 0;
selectedValue = 0;
Window.needsPaint = true;
}
break;
}
case ControlEvent.FOCUS_OUT:
{
hasFocus = false;
selectedSeries = -1;
selectedValue = -1;
Window.needsPaint = true;
break;
}
}
}
}