package ch.sahits.game.graphic.layout;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import ch.sahits.game.graphic.display.IIndexChangeListener;
import ch.sahits.game.graphic.display.IUpdatableComponent;
/**
* A slider component. The slider has either all labels painted or just the active
* @author Andi Hotz, (c) Sahits GmbH, 2011
* Created on Jun 12, 2011
*
*/
public class Slider extends AbstractMultiselectableComponent<String> implements
IUpdatableComponent {
// TODO add change listener
private final FontMetrics metric;
private boolean paintLabels = false;
private Polygon handle =null;
private IIndexChangeListener changeListener = null;
public Slider(FontMetrics fm){
metric = fm;
}
public void testClick(MouseEvent e) {
if (getBounds().contains(e.getPoint())){
if (e.getX()<handle.getBounds().getMinX()){
decSelection();
} else {
incSelection();
}
gameUpdate();
}
}
@Override
public void testClick(Point p) {
if (getBounds().contains(p)){
if (p.getX()<handle.getBounds().getMinX()){
decSelection();
} else {
incSelection();
}
gameUpdate();
}
}
// @Override
// public void testMouseReleased(MouseEvent e) {
// // do nothing
// }
// private double valueForXPosition(int x) {
// Rectangle bounds = getBounds();
// Rectangle scaled = painter.computeSliderTrack(bounds.width,0,100);
// scaled = new Rectangle(bounds.x+scaled.x, bounds.y+scaled.y, scaled.width, scaled.height);
// x = x - scaled.x; // normalize for x to be between [0,100]
// return x;
// }
// @Override
// public void testMouseDrag(MouseEvent e) {
// // do nothing
//
// }
/**
* Cast the selected index into a percentage
* @return
*/
private float castValue(){
double val = getSelectedIndex();
return castValue(val);
}
/**
* Cast the value into a persentage
* @param val
* @return
*/
private float castValue(double val) {
return (float) (val*100/(getItemCount()-1));
}
// /**
// * compute the angle for an index
// * @param index
// * @return
// */
// private float castIntoRange(int index){
// return castValue(index)*1.6f+10; // angle between 10 and 170°
// }
// /**
// * Compute the closest index from an angle
// * @param angle
// * @return
// */
// private int angleToIndex(double angle){
// return (int) Math.rint((getItemCount()-1)*(angle-10)/160);
// }
@Override
public void paint(Graphics g) {
final float castValue = castValue();
Rectangle bounds = getBounds();
BufferedImage steeringWheel = painter.createSteeringWheel((int)Math.rint(bounds.getWidth()), castValue);
BufferedImage merge = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB);
Graphics drawG = merge.getGraphics();
drawG.drawImage(steeringWheel, 0, 0, null);
g.drawImage(merge, bounds.x, bounds.y, null);
Polygon poly = painter.getSteeringWheelHandle((int)Math.rint(getPreferredSize().getWidth()), castValue());
poly.translate(bounds.x, bounds.y);
handle = poly;
if (!paintLabels()) paintCurrentLabel(g, (int)Math.rint(castValue(getSelectedIndex())));
else paintLabels(g);
}
@Override
public Dimension getPreferredSize() {
final int width = 479;
return new Dimension(width, width/2);
}
/**
* Check if the labels are to be painted
* @return
*/
private boolean paintLabels() {
return paintLabels;
}
/**
* Set the flag to paint the label
* @param paintLabels
*/
public void setPaintLabels(boolean paintLabels) {
this.paintLabels = paintLabels;
}
/**
* Paint the label of the closest labeled value over the handle.
* This makes only sense if the all potential labels are named (evenly
* spaced)
* @param g
* @param value
*/
private void paintCurrentLabel(Graphics g, int value){
Label label = new Label(metric);
label.setText(getSelected());
label.setFont(getFont());
Rectangle rect = handle.getBounds();
paintLabelAt(g, label, rect);
}
/**
* Paint a label a specific position
* @param g
* @param label
* @param rect
*/
private void paintLabelAt(Graphics g, Label label, Rectangle rect) {
int labelCenterX = (int) Math.rint(rect.getCenterX());
int labelCenterY = (int) Math.rint(rect.getCenterY());
int labelLeft = labelCenterX - (label.getPreferredSize().width / 2);
int labelTop = labelCenterY - (label.getPreferredSize().height / 2);
g.translate( labelLeft, labelTop );
label.paint( g );
g.translate( -labelLeft, -labelTop );
}
/**
* Paint the label over the center of the tracker handle (commonly known as thumb)
*/
private void paintHorizontalLabel(Graphics g, int value) {
Rectangle bounds = getBounds();
Polygon poly = painter.getSteeringWheelHandle((int)Math.rint(bounds.getWidth()), castValue(value));
poly.translate(bounds.x, bounds.y);
Rectangle rect = poly.getBounds();
Label label = new Label(metric);
label.setText(getItem(value));
label.setFont(getFont());
paintLabelAt(g, label, rect);
}
/**
* Print all the labels
* @param g
*/
private void paintLabels(Graphics g) {
for (int i = 0; i < getItemCount(); i++) {
paintHorizontalLabel(g, i);
}
}
/**
* set the selected index to specified value.
* If the index is outside of range nothing will happen
*/
public void setSelected(int index){
if (index>=0 && index<getItemCount()){
super.setSelected(index);
}
}
@Override
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
}
public void addChangeListeners(IIndexChangeListener listener){
changeListener=listener;
}
@Override
public void gameUpdate() {
if (changeListener!=null){
changeListener.changeIndex(getSelectedIndex());
}
super.gameUpdate();
}
}