/**
* Squidy Interaction Library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Squidy Interaction Library 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. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Squidy Interaction Library. If not, see
* <http://www.gnu.org/licenses/>.
*
* 2009 Human-Computer Interaction Group, University of Konstanz.
* <http://hci.uni-konstanz.de>
*
* Please contact info@squidy-lib.de or visit our website
* <http://www.squidy-lib.de> for further information.
*/
package org.squidy.designer.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squidy.designer.zoom.ActionShape;
/**
* <code>DrawableString</code>.
*
* <pre>
* Date: 21.08.2009
* Time: 14:06:42
* </pre>
*
*
* @author
* Toni Zeitler
* <a href="mailto:anton.zeitler@campus.lmu.de">anton.zeitler@campus.lmu.de</a>
* Media Informatics Group
* University of Munich (LMU)
*
* @version $Id: DrawableString.java 772 2011-09-16 15:39:44Z raedle $
* @since 1.0.0
*/
public class DrawableString {
public enum AlignmentH {
LEFT, CENTER, RIGHT
}
public enum AlignmentV {
TOP, CENTER, BOTTOM
}
// input
private String value;
private Color color;
private Font font;
private Rectangle bounds;
private AlignmentH alignmentH = AlignmentH.CENTER;
private AlignmentV alignmentV = AlignmentV.CENTER;
private int offsetX;
private int offsetY;
// calculated
private int positionX;
private int positionY;
private String drawValue;
private boolean dirty = true;
// Logger to log info, error, debug,... messages.
private static final Log LOG = LogFactory.getLog(DrawableString.class);
private class Cache {
private class Item {
public String drawValue;
public int positionX;
public Item(String drawValue, int positionX) {
super();
this.drawValue = drawValue;
this.positionX = positionX;
}
}
private Item items[][][];
public Cache() {
super();
items = new Item[100][][];
}
public void put(String drawValue, int positionX, double scale) {
if (scale >= 100.0)
return;
int i2 = (int)(scale * 100.0);
int i1 = i2 / 10;
int i0 = i1 / 10;
i2 -= i1 * 10;
i1 -= i0 * 10;
if (items[i0] == null)
items[i0] = new Item[10][];
if (items[i0][i1] == null)
items[i0][i1] = new Item[10];
if (items[i0][i1][i2] == null)
items[i0][i1][i2] = new Item(drawValue, positionX);
else {
items[i0][i1][i2].drawValue = drawValue;
items[i0][i1][i2].positionX = positionX;
}
}
public Item get(double scale) {
if (scale >= 100.0)
return null;
int i2 = (int)(scale * 100.0);
int i1 = i2 / 10;
int i0 = i1 / 10;
i2 -= i1 * 10;
i1 -= i0 * 10;
if (items[i0] == null)
return null;
if (items[i0][i1] == null)
return null;
if (items[i0][i1][i2] == null)
return null;
return items[i0][i1][i2];
}
}
private Cache cache;
/**
*
*/
public DrawableString() {
super();
}
/**
* @param fullString
*/
public DrawableString(String fullString) {
this.value = fullString;
}
/**
* @param fullString
* @param color
* @param font
* @param bounds
*/
public DrawableString(String fullString, Color color, Font font, Rectangle bounds) {
this.value = fullString;
this.color = color;
this.font = font;
this.bounds = bounds;
}
/**
* @param g
*/
private void update(Graphics2D g, double viewScale) {
Cache.Item item;
// use screen if no bounds set
if (bounds == null) {
bounds = g.getDeviceConfiguration().getBounds();
}
// get item extents from cache or calculate
if (cache == null || dirty) {
cache = new Cache();
item = null;
} else {
item = cache.get(viewScale);
}
if (item != null) {
drawValue = item.drawValue;
positionX = item.positionX;
} else {
FontMetrics fm;
int width, height;
// font width does not scale linear to view scale
fm = g.getFontMetrics();
drawValue = FontUtils.createCroppedLabelIfNecessary(fm, value, bounds.width - 50);
positionX = bounds.x;
if (alignmentH == AlignmentH.CENTER) {
width = FontUtils.getWidthOfText(fm, drawValue);
positionX += (bounds.width - width) / 2;
} else if (alignmentH == AlignmentH.RIGHT) {
width = FontUtils.getWidthOfText(fm, drawValue);
positionX += (bounds.width - width);
}
// font height keeps the same all the time
if (dirty) {
positionY = bounds.y;
if (alignmentV == AlignmentV.CENTER) {
height = (int)fm.getLineMetrics(drawValue, g).getHeight();
positionY += (bounds.height - height) / 2;
} else if (alignmentV == AlignmentV.BOTTOM) {
height = (int)fm.getLineMetrics(drawValue, g).getHeight();
positionY += (bounds.height - height);
}
}
// store extents in cache
cache.put(drawValue, positionX, viewScale);
}
dirty = false;
}
/**
* @param g
*/
public void draw(Graphics2D g, double viewScale) {
if (value == null)
return;
if (color != null)
g.setColor(color);
if (font != null)
g.setFont(font);
update(g, viewScale);
if (drawValue != null)
g.drawString(drawValue, positionX + offsetX, positionY + offsetY);
}
/**
*
*/
public void invalidate() {
dirty = true;
}
/**
* @return
*/
public String get() {
return value;
}
/**
* @param value
*/
public void set(String value) {
if (this.value != value) {
this.value = value;
dirty = true;
}
}
/**
* @return
*/
public Color getColor() {
return color;
}
/**
* @param color
*/
public void setColor(Color color) {
this.color = color;
}
/**
* @return
*/
public Font getFont() {
return font;
}
/**
* @param font
*/
public void setFont(Font font) {
this.font = font;
dirty = true;
}
/**
* @return
*/
public Rectangle getBounds() {
return bounds;
}
/**
* @param bounds
*/
public void setBounds(Rectangle bounds) {
if (bounds != null && !bounds.equals(this.bounds)) {
this.bounds = bounds;
dirty = true;
}
}
/**
* @return
*/
public AlignmentH getAlignmentH() {
return alignmentH;
}
/**
* @param alignmentH
*/
public void setAlignmentH(AlignmentH alignmentH) {
this.alignmentH = alignmentH;
}
/**
* @return
*/
public AlignmentV getAlignmentV() {
return alignmentV;
}
/**
* @param alignmentV
*/
public void setAlignmentV(AlignmentV alignmentV) {
this.alignmentV = alignmentV;
}
/**
* @return
*/
public int getOffsetX() {
return offsetX;
}
/**
* @param offsetX
*/
public void setOffsetX(int offsetX) {
this.offsetX = offsetX;
}
/**
* @return
*/
public int getOffsetY() {
return offsetY;
}
/**
* @param offsetY
*/
public void setOffsetY(int offsetY) {
this.offsetY = offsetY;
}
}