package edu.princeton.cs.algs4.growingtree.framework;
/*
* @(#)DrawingKey.java
*
* Last Modified: 9/15/01
*/
import java.util.*;
import java.lang.*;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
/**
* DrawingKey
implements DrawableKey
for it is a specific type that
* draws Object keys. Its constructor needs the Object key it will draw.
*
* @see DrawableKey
*
* @author Corey Sanders
* @version 2.1 9/15/01
*/
public class DrawingKey extends Object implements DrawableKey {
/**
* Previous Drawn Shape
*/
private Shape currentShape = null;
/**
* Previous Drawn Shape
*/
private Shape originalShape = null;
/**
* Current Transform
*/
private AffineTransform currentTransform = null;
/**
* The current drawing settings of the node.
*/
private KeySettings currentSettings = null;
/**
* The previous drawing settings of the node.
*/
private KeySettings previousSettings = null;
/**
* The count for how many total saves the current Node has been called
* (to save the NodeSettings).
*/
private int countSaves = 0;
/**
* The Object key used to draw this key, using the method toString
.
*/
private KeyType key;
/**
* Constructor that instantiates the DrawingIntegerKey
using the given Object k.
* @param k the Object
drawn to the screen.
*/
public DrawingKey(int k) {
setKey(new KeyType(k));
}
public DrawingKey(KeyType k) {
setKey(k);
}
/**
* Returns a copy of this AffineTransform
object.
* @return an Object
that is a copy of this
* AffineTransform
object.
*/
public Object clone() {
try {
return super.clone();
}
catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* Sets the Object
key of the DrawableKey
.
*
* @param k Object
key for use in drawing the key.
*/
public void setKey(KeyType k) {
key = k;
}
/**
* Gets the Object
key of the DrawableKey
.
*
* @return Object
key used for drawing the key.
*/
public KeyType getKey() {
return key;
}
/**
* Sets the KeySettings
of the DrawableKey
.
* These settings are used for drawing the key in a given Graphics2D.
*
* @param s KeySettings
for use in drawing the key.
*/
public void setSettings(KeySettings s) {
KeySettings newSettings = (KeySettings)s.clone();
// No previous saved settings
if (!isSettingsSaved()) {
// null previous settings
previousSettings = null;
currentSettings = newSettings;
// Reset saves
countSaves = 0;
}
else {
// Set previous settings as s, because currently the settings are saved.
previousSettings = newSettings;
}
}
/**
* Sets the KeySettings
of the DrawableKey
.
* These settings are used for drawing the key in a given Graphics2D.
*
* @param s KeySettings
for use in drawing the key.
*/
public void setKeySettings(KeySettings s) {
currentSettings = (KeySettings)s.clone();
}
/**
* Gets the KeySettings
of the key.
*
* @return KeySettings
for use in drawing the key.
*/
public KeySettings getSettings() {
return currentSettings;
}
/**
* Returns true if the KeySettings are currently saved for the DrawingTree.
*
* @return true if the settings are saved.
*/
public boolean isSettingsSaved() {
// Saved if previousSettings is not null.
return (previousSettings != null);
}
/**
* Saves the settings for the tree, incrementing the count of saves by one and setting the
* previous settings accordingly.
*/
public void saveSettings() {
countSaves++;
if (previousSettings == null) {
previousSettings = (KeySettings)currentSettings.clone();
}
}
/**
* Restores the settings for the tree, decrementing the count of saves by one.
* If the settings have been restored completely, than the KeySettings for the tree
* are set accordingly.
*/
public void restoreSettings() {
countSaves--;
if (countSaves <= 0) { // Completely Restored
currentSettings = previousSettings;
previousSettings = null;
countSaves = 0;
}
}
public void fillKey(Graphics2D g2)
{
}
// Draws this key at the upper left corner of the node
public void drawKeyUpperLeft(Graphics2D g2, AffineTransform a, int width)
{
AffineTransform b = (AffineTransform)a.clone();
double oldXScale = b.getScaleX();
double oldYScale = b.getScaleY();
double ratio = 1.0/5.0;
b.scale(ratio, ratio);
b.translate(-1 * ratio * oldXScale / b.getScaleX(),
-1 * ratio * oldYScale / b.getScaleY());
drawKeyScaled(g2, b, width);
}
public void drawKeyUpperRight(Graphics2D g2, AffineTransform a, int width) {
AffineTransform b = (AffineTransform)a.clone();
double oldXScale = b.getScaleX();
double oldYScale = b.getScaleY();
double ratio = 1.0/5.0;
b.scale(ratio, ratio);
b.translate(5 * ratio * oldXScale / b.getScaleX(),
-1 * ratio * oldYScale / b.getScaleY());
drawKeyScaled(g2, b, width);
}
public void drawKeyLowerRight(Graphics2D g2, AffineTransform a, int width) {
AffineTransform b = (AffineTransform)a.clone();
double oldXScale = b.getScaleX();
double oldYScale = b.getScaleY();
double ratio = 1.0/5.0;
b.scale(ratio, ratio);
b.translate(5 * ratio * oldXScale / b.getScaleX(),
5 * ratio * oldYScale / b.getScaleY());
drawKeyScaled(g2, b, width);
}
public void drawKeyLowerLeft(Graphics2D g2, AffineTransform a, int width) {
AffineTransform b = (AffineTransform)a.clone();
double oldXScale = b.getScaleX();
double oldYScale = b.getScaleY();
double ratio = 1.0/5.0;
b.scale(ratio, ratio);
b.translate(-1 * ratio * oldXScale / b.getScaleX(),
5 * ratio * oldYScale / b.getScaleY());
drawKeyScaled(g2, b, width);
}
/**
* Draws the key in the given Graphics2D, using the AffineTransform passed to it.
* The method uses the AffineTransform using no previous transforms.
*
* @param g2 Graphics2D that this fills with the key.
* @param a AffineTransform
that transforms the key, assuming no previous transforms occur.
*/
public void drawKey(Graphics2D g2, AffineTransform a) {
if (originalShape == null)
setOriginalShape(g2);
// these chars are drawn too wide, so scale them down
if (getKey().isChar()) {
if ((getKey().charValue() == 'i')
|| (getKey().charValue() == 'I')
|| (getKey().charValue() == 'l'))
{
double oldScale = a.getScaleX();
double ratio = 1.0/5.0;
a.scale(ratio, 1);
a.translate(.5 * (1-ratio) * (oldScale / a.getScaleX()), 0);
}
}
currentShape = a.createTransformedShape(originalShape);
drawKey(g2);
}
/* Draws the key so that all characters have the same font size,
* given that the largest key in the tree is width characters wide
*/
public void drawKeyScaled(Graphics2D g2, AffineTransform a, int width)
{
AffineTransform b = (AffineTransform)a.clone();
if (width > 1)
{
double oldScale = b.getScaleX();
int currentWidth = getKey().toString().length();
double ratio = ((double)currentWidth) / width;
b.scale(ratio, 1);
b.translate( .5 * (1 - ratio) * (oldScale / b.getScaleX()), 0);
}
drawKey(g2, b);
}
/**
* Draws the key, first setting all values for the Graphics2D g2.
* The drawing is done using the current Shape, defined generally in drawKey
or
* fillKey
.
*
* @param g2 Graphics2D that the key is painted to.
*/
public void drawKey(Graphics2D g2) {
// Set graphics information
g2.setComposite(getSettings().getKeyComposite());
g2.setPaint(getSettings().getKeyFillPaint());
g2.fill(currentShape);
g2.setStroke(getSettings().getKeyOutlineStroke());
g2.setPaint(getSettings().getKeyOutlinePaint());
g2.draw(currentShape);
}
/**
* sets the Original Shape using the g2 simply for the FontRenderContext
.
* @param g2 Graphics2D that FontRenderContext is aquired from.
*/
private void setOriginalShape(Graphics2D g2) {
String key = getKey().toString();
// Makes a textLayout using the key.
TextLayout text = new TextLayout(key, getSettings().getFont(), g2.getFontRenderContext());
// Makes a Shape
Shape keyShape = text.getOutline(null);
// Get Bounds of the Shape
Rectangle2D keyShapeBounds = keyShape.getBounds2D();
// Scales to size of 1 and transforms to (0,0)
AffineTransform scaleTransform = AffineTransform.getScaleInstance(1 / keyShapeBounds.getWidth() , 1 / keyShapeBounds.getHeight());
AffineTransform translateTransform = AffineTransform.getTranslateInstance((-keyShapeBounds.getX()), (-keyShapeBounds.getY()));
scaleTransform.concatenate(translateTransform);
originalShape = scaleTransform.createTransformedShape(keyShape);
}
}