|
/**
* Virtual3DBoard.java
*
* @author Daniel Höpfl
*
* @see IOutput
*/
package SpringerPack.Boards;
import SpringerPack.*;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Point;
import java.awt.FontMetrics;
import java.awt.Font;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Canvas;
/**
* This class implements an IOutput conform Board.
*
* @see SimpleBoard
* @see IOutput
*/
public class Virtual3DBoard extends IOutput {
private final double mUpperFree = 0.35;
private final double mSmaller = 0.15;
public Polygon getFieldPolygon(int inX, int inY)
{
return new Polygon();
}
/**
* Size of board in fields
*/
private int mSize = 9;
/**
* Width of Board in pixels
*/
private int mWidth = -1;
/**
* Height of Board in pixels
*/
private int mHeight = -1;
/**
* Calculated size of font to fit all used numbers into fields
*/
private int mFontSize = -1;
/**
* the board we draw
*/
private Board mBoard = null;
/**
* X coordinate of start-field
*/
private int mStartX = 0;
/**
* Y coordinate of start-field
*/
private int mStartY = 0;
/**
* Image we can offscreen-draw to.
*/
private Image mImg = null;
/**
* sets a new size of the board in fields
*
* @param inSize size of board asked for (5 ... 16)
*
* @see IOutput#setBoardSize
*/
public void setBoardSize(int inSize) {
if(inSize < 5)
inSize = 5;
mSize = inSize;
mFontSize = -1;
repaint();
}
/**
* sets a board to draw
*
* @param inBoard Board to set
*
* @see IOutput#setBoard
* @see Board
*/
public void setBoard(Board inBoard)
{
mBoard = inBoard;
}
/**
* recursion gets one step deeper
*
* @param inSourceX X of the field we have left
* @param inSourceY Y of the field we have left
* @param inDestX X of the field we jumped to
* @param inDestY Y of the field we jumped to
*
* @see IOutput#deeper
*/
public void deeper(int inSourceX, int inSourceY, int inDestX, int inDestY)
{
repaint();
}
/**
* recursion gets one step higher
*
* @param inSourceX X of the field we have left
* @param inSourceY Y of the field we have left
* @param inDestX X of the field we jumped to
* @param inDestY Y of the field we jumped to
*
* @see IOutput#higher
*/
public void higher(int inSourceX, int inSourceY, int inDestX, int inDestY)
{
repaint();
}
/**
* calculates what field has been clicked
*
* @param inClicked coordinates inside this Component that was
* clicked (0 ... mWidth-1, 0 ... mHeight-1)
*
* @return X/Y-Coordinate of field clicked (if inside board) as Point.
* null else.
*
* @see IOutput#calcStartField
*/
public Point calcStartField(Point inClicked)
{
int oy = (int) (0.5*mUpperFree*mHeight+1);
if(inClicked.y < oy)
return null;
int field_height = (int) ((1-mUpperFree)*mHeight/mSize);
int y = (inClicked.y - oy)/field_height;
if(y >= mSize)
return null;
double lo = ((field_height*mSize - (inClicked.y - oy))*mSmaller*mWidth/(field_height*mSize));
for(int x = 0; x < mSize; x++)
{
int lox = (int) (lo + x*((mWidth-2*lo)/mSize));
int rox = (int) (lo + (x+1)*((mWidth-2*lo)/mSize));
if(inClicked.x >= lox &&
inClicked.x <= rox)
{
return new Point(x,y);
}
}
return null;
}
/**
* set a new starting field
*
* @param inX X coordinate of the field
* @param inY Y coordinate of the field
*
* @see IOutput#setStart
*/
public void setStart(int inX, int inY)
{
mStartX = inX;
mStartY = inY;
setBoard(null);
repaint();
}
/**
* set a new Image for offscreen-drawing
*
* @param inImage the Image to set
* must be big enought to take the whole output area
*
* @see IOutput#setImage
*/
public void setImage(Image inImage) {
mImg = inImage;
}
/**
* catch the setSize function of java.awt.Component to get the
* outer size of our drawing-area
*
* @param inDim size of this element
*
* @see java.awt.Component#setSize
*/
public void setSize(java.awt.Dimension inDim) {
super.setSize(inDim);
mWidth = inDim.width - 1;
mHeight = inDim.height - 1;
mFontSize = -1;
repaint();
}
public void update(Graphics inGraphics) {
// super.update would clear the drawing area
// since we should not have any childs we leave it out
// super.update(inGraphics);
// repaint the board (using offscreen - or not)
paint(inGraphics);
}
/**
* replaces the default (empty) paint method.
* Draws offscreen and copies to screen if there is an Image set
*
* @param inG place to draw to
*
* @see SimpleBoard#update
* @see SimpleBoard#setImage
* @see java.awt.Component#update
* @see java.awt.Graphics
*/
public void paint(Graphics inG) {
// boardsize not set?
if(mWidth < 0 || mHeight < 0)
return;
// by default we draw non-offscreen
Graphics g = inG;
// if there is an Image -> draw offscreen
// we will copy it to the screen later
if(mImg != null)
g = mImg.getGraphics();
// clear background
g.setColor(getBackground());
g.fillRect(0, 0, mWidth+1, mHeight+1);
// calc fontsize
int fontWidth = 0;
int fontHeight = 0;
FontMetrics fontMetrics = null;
if(mFontSize < 0)
{
double width = (mWidth - 2*mSmaller*mWidth)/mSize;
double height = (mHeight - mUpperFree*mHeight)/mSize;
mFontSize = 0;
int step = 64;
while(step > 1)
{
mFontSize += step;
g.setFont(new Font("Dialog", Font.PLAIN, mFontSize));
fontMetrics = g.getFontMetrics();
fontHeight = fontMetrics.getAscent();
fontWidth = 0;
int widestNumber = 0;
for(int i=0; i < 10; i++)
{
int thisWidth;
thisWidth = fontMetrics.stringWidth(new Integer(i).toString());
if(thisWidth > widestNumber)
widestNumber = thisWidth;
}
String theNumberStr = new Integer(mSize * mSize).toString();
fontWidth = theNumberStr.length() * widestNumber;
if(fontWidth > (width - 4) || fontHeight > height)
{
mFontSize -= step;
}
step /= 2;
}
mFontSize += 1;
if(mFontSize < 4)
mFontSize = 4;
}
// set calculated font
g.setFont(new Font("Dialog", Font.PLAIN, mFontSize));
fontMetrics = g.getFontMetrics();
fontHeight = fontMetrics.getAscent();
// draw all the fields
int height = (int) ((1-mUpperFree)*mHeight/mSize);
for(int y=0; y<mSize; y++)
{
for(int x=0; x<mSize; x++)
{
double lo = ((mSize - y)*mSmaller*mWidth/mSize);
int lox = (int) (lo + x*((mWidth-2*lo)/mSize));
int rox = (int) (lo + (x+1)*((mWidth-2*lo)/mSize));
double lu = ((mSize - y - 1)*mSmaller*mWidth/mSize);
int lux = (int) (lu + x*((mWidth-2*lu)/mSize));
int rux = (int) (lu + (x+1)*((mWidth-2*lu)/mSize));
int oy = (int) (y*height+0.5*mUpperFree*mHeight+1);
int uy = oy + height;
// get it chess-colored
if((x+y) % 2 == 1)
g.setColor(getWhiteFieldColor());
else
g.setColor(getBlackFieldColor());
// calc the 4 Points of each field
Polygon p = new Polygon();
p.addPoint(lox, oy);
p.addPoint(rox, oy);
p.addPoint(rux, uy);
p.addPoint(lux, uy);
g.fillPolygon(p);
// is there set a board and currend field has been touched?
if(mBoard != null &&
mBoard.getXY(x,y) > 0)
{
// write number into the field
g.setColor(Color.black);
fontWidth = fontMetrics.stringWidth(new Integer(mBoard.getXY(x,y)).toString());
g.drawString(new Integer(mBoard.getXY(x,y)).toString(),
(int) (0.5*(rux+lux-fontWidth)),
oy+(uy-oy)/2+fontHeight/2);
}
// mark start-field
if( x == mStartX &&
y == mStartY)
{
p = new Polygon();
p.addPoint(lox, oy);
p.addPoint(rox-1, oy);
p.addPoint(rux-1, uy-1);
p.addPoint(lux, uy-1);
g.setColor(getStartFieldBorderColor());
g.drawPolygon(p);
}
}
}
// draw a nice rect around it.
g.setColor(Color.black);
g.drawRect(0, 0, mWidth, mHeight);
Polygon p = new Polygon();
p.addPoint((int) (mSmaller*mWidth)-1, (int) (0.5*mUpperFree*mHeight));
p.addPoint((int) (mWidth - mSmaller*mWidth), (int) (0.5*mUpperFree*mHeight));
p.addPoint(mWidth, (int) ((mSize-1)*height+0.5*mUpperFree*mHeight+1+height));
p.addPoint(-1, (int) ((mSize-1)*height+0.5*mUpperFree*mHeight+1+height));
g.drawPolygon(p);
// copy offscreen drawn image to screen
if(mImg != null)
inG.drawImage(mImg, 0, 0, this);
}
/**
* function to get the Color of "white" fields
*
* @return Color of "white" fields
*
* @see SimpleBoardRed#getWhiteFieldColor
*/
public Color getWhiteFieldColor()
{
return Color.white;
}
/**
* function to get the Color of "black" fields
*
* @return Color of "black" fields
*
* @see SimpleBoardRed#getBlackFieldColor
*/
public Color getBlackFieldColor()
{
return Color.lightGray;
}
/**
* function to get the Color of the outline of the startfield
*
* @return Color of startfields border
*
* @see SimpleBoardRed#getStartFieldBorderColor
*/
public Color getStartFieldBorderColor()
{
return Color.red;
}
}
|