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); } }