/*
* (c) Copyright 2009 Tim Jenkins
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package com.screenrunner.data;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.text.AttributedString;
import java.util.ArrayList;
public class TextStyle {
public static final int ALIGN_CENTER = 0;
public static final int ALIGN_NORTH = 1;
public static final int ALIGN_SOUTH = 2;
public static final int ALIGN_WEST = 3;
public static final int ALIGN_EAST = 4;
public static final int ALIGN_NORTHEAST = 5;
public static final int ALIGN_NORTHWEST = 6;
public static final int ALIGN_SOUTHEAST = 7;
public static final int ALIGN_SOUTHWEST = 8;
private Font _font;
private int _maxFontSize;
private Color _color;
private boolean _underline;
private boolean _outline;
private boolean _shadow;
private int _align;
private Margins _margins;
public TextStyle() {
_font = new Font("Sans-serif", Font.PLAIN, 12);
_maxFontSize = 12;
_color = Color.white;
_underline = false;
_outline = false;
_shadow = false;
_align = ALIGN_CENTER;
_margins = new Margins();
}
public TextStyle(TextStyle source) {
_font = source._font;
_maxFontSize = source._maxFontSize;
_color = source._color;
_underline = source._underline;
_outline = source._outline;
_shadow = source._shadow;
_align = source._align;
_margins = new Margins(source._margins);
}
public Font getFont() { return _font; }
public int getMaxFontSize() { return _maxFontSize; }
public Color getColor() { return _color; }
public boolean getUnderline() { return _underline; }
public boolean getOutline() { return _outline; }
public boolean getShadow() { return _shadow; }
public int getAlign() { return _align; }
public Margins getMargins() { return _margins; }
public Margins getMargins(float scale) { return new Margins(_margins, scale); }
public void setFont(Font value) { _font = value; }
public void setFont(String name, int style, int size) { _font = new Font(name, style, size); }
public void setMaxFontSize(int value) { _maxFontSize = value; }
public void setColor(Color value) { _color = value; }
public void setUnderline(boolean value) { _underline = value; }
public void setOutline(boolean value) { _outline = value; }
public void setShadow(boolean value) { _shadow = value; }
public void setAlign(int value) { _align = value; }
public void setMargins(Margins value) { _margins = value; }
public void setMargins(int left, int top, int right, int bottom) { _margins = new Margins(left, top, right, bottom); }
public void drawText(Graphics2D g, Dimension dispSize, float scale, String text) {
//System.out.println("DrawText: " + text);
if(g == null) return;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Margins m = getMargins(scale);
Rectangle dispArea = new Rectangle(m.getLeft(), m.getTop(), (int)dispSize.getWidth() - (m.getLeft() + m.getRight()), (int)dispSize.getHeight() - (m.getBottom() + m.getTop()));
//Rectangle2D dispArea = getAdjustedRect(dispSize, m);
if(text == null || text.length() == 0) return;
int max = (int)(getMaxFontSize() * scale);
int min = 1;
int cur = max;
ArrayList<TextLayout> layouts = new ArrayList<TextLayout>();
FontMetrics metrics = null;
while(max >= min) {
cur = min + ((max - min) / 2);
Font font = getFont().deriveFont((float)cur);
AttributedString attrstr = new AttributedString(text);
attrstr.addAttribute(TextAttribute.FONT, font);
FontRenderContext frc = g.getFontRenderContext();
LineBreakMeasurer lbm = new LineBreakMeasurer(attrstr.getIterator(), frc);
layouts.clear();
int pos = lbm.getPosition();
int linebreak = text.indexOf("\n", pos);
TextLayout tl = lbm.nextLayout((float)dispArea.getWidth(), (linebreak == -1 ? text.length() : linebreak + 1), false);
do {
layouts.add(tl);
pos = lbm.getPosition();
linebreak = text.indexOf("\n", pos);
tl = lbm.nextLayout((float)dispArea.getWidth(), (linebreak == -1 ? text.length() : linebreak + 1), false);
} while(tl != null);
metrics = g.getFontMetrics(font);
int h = metrics.getHeight() * layouts.size();
if(h < dispArea.getHeight()) {
min = cur + 1;
cur = min;
} else if(h > dispArea.getHeight()) {
max = cur - 1;
} else {
break;
}
}
int lineHeight = metrics.getHeight();
int startLinePos = lineHeight;
int totalHeight = lineHeight * layouts.size();
switch(getAlign()) {
case ALIGN_NORTHWEST:
case ALIGN_NORTH:
case ALIGN_NORTHEAST:
startLinePos = (int)dispArea.getY() + lineHeight;
break;
case ALIGN_WEST:
case ALIGN_CENTER:
case ALIGN_EAST:
startLinePos = (int)dispArea.getY() + (int)((dispArea.getHeight() - totalHeight) / 2) + lineHeight;
break;
case ALIGN_SOUTHWEST:
case ALIGN_SOUTH:
case ALIGN_SOUTHEAST:
startLinePos = (int)(dispArea.getY() + dispArea.getHeight()) - totalHeight + lineHeight;
break;
}
g.setStroke(new BasicStroke(4 * scale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
for(int i = 0; i < layouts.size(); i++) {
Shape shape = layouts.get(i).getOutline(null);
Rectangle2D bounds = shape.getBounds2D();
int lineWidth = (int)Math.ceil(bounds.getWidth());
int lineX = 0;
int lineY = startLinePos + (i * lineHeight);
switch(getAlign()) {
case ALIGN_NORTHWEST:
case ALIGN_WEST:
case ALIGN_SOUTHWEST:
lineX = (int)dispArea.getX();
break;
case ALIGN_NORTH:
case ALIGN_CENTER:
case ALIGN_SOUTH:
lineX = (int)dispArea.getX() + (int)((dispArea.getWidth() - lineWidth) / 2);
break;
case ALIGN_NORTHEAST:
case ALIGN_EAST:
case ALIGN_SOUTHEAST:
lineX = (int)(dispArea.getX() + dispArea.getWidth()) - lineWidth;
break;
}
if(getShadow()) {
g.setTransform(AffineTransform.getTranslateInstance(lineX + ((cur / 30.0) * scale), lineY + ((cur / 20) * scale)));
g.setColor(Color.black);
g.draw(shape);
g.fill(shape);
}
g.setTransform(AffineTransform.getTranslateInstance(lineX, lineY));
if(getOutline()) {
g.setColor(Color.black);
g.draw(shape);
}
g.setColor(getColor());
g.fill(shape);
}
}
}