下面列出了java.awt.font.TextLayout#getAscent ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(getForeground());
Insets i = getInsets();
float x = i.left;
float y = i.top;
int w = getWidth() - i.left - i.right;
AttributedString as = new AttributedString(getText());
as.addAttribute(TextAttribute.FONT, getFont());
AttributedCharacterIterator aci = as.getIterator();
FontRenderContext frc = g2.getFontRenderContext();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
while (lbm.getPosition() < aci.getEndIndex()) {
TextLayout tl = lbm.nextLayout(w);
tl.draw(g2, x, y + tl.getAscent());
y += tl.getDescent() + tl.getLeading() + tl.getAscent();
}
g2.dispose();
}
void rescale(double scale) {
Rectangle bounds = getBounds(scale);
HashMap settings = new HashMap();
settings.put(TextAttribute.FONT, new Font(style.getFontAttributes(scale * Integer.parseInt(element.getAttribute("size")))));
AttributedCharacterIterator par = (new AttributedString(element.getAttribute("text"), settings)).getIterator();
LineBreakMeasurer lbm = new LineBreakMeasurer(par, new FontRenderContext(null, false, false));
ArrayList drawList = new ArrayList();
int parEnd = par.getEndIndex();
int positionX;
int positionY = bounds.y;
lbm.setPosition(par.getBeginIndex());
while (lbm.getPosition() < parEnd) {
TextLayout layout = lbm.nextLayout(bounds.width);
positionX = bounds.x;
if (!layout.isLeftToRight()) {
positionX += bounds.width - (int) layout.getAdvance();
}
positionY += layout.getAscent();
if (positionY > bounds.y+bounds.height) break;
drawList.add(new Point(positionX, positionY));
drawList.add(layout);
positionY += layout.getDescent() + layout.getLeading();
}
textPositions = new Point[drawList.size()/2];
textLines = new TextLayout[drawList.size()/2];
textScale = scale;
for (int i = 0; i < textPositions.length; i++) {
textPositions[i] = (Point) drawList.get(i*2);
textLines[i] = (TextLayout) drawList.get(i*2+1);
}
}
private void drawText(Graphics2D g2, BandElement band, FontRenderContext frc,
int w, int rowHeight, int titleDelta, int rowPos, String text) {
TextLayout detailLayout = new TextLayout(text, band.getFont(), frc);
float detailHeight = detailLayout.getAscent() + detailLayout.getDescent();
int detailWidth = g2.getFontMetrics(band.getFont()).stringWidth(text);
for (int i = 0; i < columns; i++) {
int alignH = band.getHorizontalAlign();
//System.out.println("alignH=" + alignH);
int x0H;
// left
if (alignH == 2) {
x0H = i * w / columns + 5;
// right
} else if (alignH == 4) {
x0H = (i + 1) * w / columns - detailWidth - 5;
// center
} else {
x0H = i * w / columns + (w / columns - detailWidth) / 2;
}
int y0H = titleDelta + (int) ((rowPos * rowHeight + detailHeight) / 2);
//System.out.println("x0H=" + x0H + " y0H=" + y0H);
AffineTransform atH = AffineTransform.getTranslateInstance(x0H, y0H);
Shape outlineH = detailLayout.getOutline(atH);
g2.setColor(band.getForeground());
g2.fill(outlineH);
}
}
/**
* Returns the logical bounds of the specified array of characters
* in the specified <code>FontRenderContext</code>. The logical
* bounds contains the origin, ascent, advance, and height, which
* includes the leading. The logical bounds does not always enclose
* all the text. For example, in some languages and in some fonts,
* accent marks can be positioned above the ascent or below the
* descent. To obtain a visual bounding box, which encloses all the
* text, use the {@link TextLayout#getBounds() getBounds} method of
* <code>TextLayout</code>.
* <p>Note: The returned bounds is in baseline-relative coordinates
* (see {@link java.awt.Font class notes}).
* @param chars an array of characters
* @param beginIndex the initial offset in the array of
* characters
* @param limit the end offset in the array of characters
* @param frc the specified <code>FontRenderContext</code>
* @return a <code>Rectangle2D</code> that is the bounding box of the
* specified array of characters in the specified
* <code>FontRenderContext</code>.
* @throws IndexOutOfBoundsException if <code>beginIndex</code> is
* less than zero, or <code>limit</code> is greater than the
* length of <code>chars</code>, or <code>beginIndex</code>
* is greater than <code>limit</code>.
* @see FontRenderContext
* @see Font#createGlyphVector
* @since 1.2
*/
public Rectangle2D getStringBounds(char [] chars,
int beginIndex, int limit,
FontRenderContext frc) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
}
if (limit > chars.length) {
throw new IndexOutOfBoundsException("limit: " + limit);
}
if (beginIndex > limit) {
throw new IndexOutOfBoundsException("range length: " +
(limit - beginIndex));
}
// this code should be in textlayout
// quick check for simple text, assume GV ok to use if simple
boolean simple = values == null ||
(values.getKerning() == 0 && values.getLigatures() == 0 &&
values.getBaselineTransform() == null);
if (simple) {
simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
}
if (simple) {
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(this, frc);
return metrics.getSimpleBounds(chars, beginIndex, limit-beginIndex);
} else {
// need char array constructor on textlayout
String str = new String(chars, beginIndex, limit - beginIndex);
TextLayout tl = new TextLayout(str, this, frc);
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() +
tl.getLeading());
}
}
public void runTest(Object ctx, int numReps) {
TLContext tlctx = (TLContext)ctx;
TextLayout tl = tlctx.tl;
float ht = 0;
do {
ht += tl.getAscent();
} while (--numReps >= 0);
}
/**
* Returns the logical bounds of the specified array of characters
* in the specified <code>FontRenderContext</code>. The logical
* bounds contains the origin, ascent, advance, and height, which
* includes the leading. The logical bounds does not always enclose
* all the text. For example, in some languages and in some fonts,
* accent marks can be positioned above the ascent or below the
* descent. To obtain a visual bounding box, which encloses all the
* text, use the {@link TextLayout#getBounds() getBounds} method of
* <code>TextLayout</code>.
* <p>Note: The returned bounds is in baseline-relative coordinates
* (see {@link java.awt.Font class notes}).
* @param chars an array of characters
* @param beginIndex the initial offset in the array of
* characters
* @param limit the end offset in the array of characters
* @param frc the specified <code>FontRenderContext</code>
* @return a <code>Rectangle2D</code> that is the bounding box of the
* specified array of characters in the specified
* <code>FontRenderContext</code>.
* @throws IndexOutOfBoundsException if <code>beginIndex</code> is
* less than zero, or <code>limit</code> is greater than the
* length of <code>chars</code>, or <code>beginIndex</code>
* is greater than <code>limit</code>.
* @see FontRenderContext
* @see Font#createGlyphVector
* @since 1.2
*/
public Rectangle2D getStringBounds(char [] chars,
int beginIndex, int limit,
FontRenderContext frc) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
}
if (limit > chars.length) {
throw new IndexOutOfBoundsException("limit: " + limit);
}
if (beginIndex > limit) {
throw new IndexOutOfBoundsException("range length: " +
(limit - beginIndex));
}
// this code should be in textlayout
// quick check for simple text, assume GV ok to use if simple
boolean simple = values == null ||
(values.getKerning() == 0 && values.getLigatures() == 0 &&
values.getBaselineTransform() == null);
if (simple) {
simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
}
if (simple) {
GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
limit - beginIndex, frc);
return gv.getLogicalBounds();
} else {
// need char array constructor on textlayout
String str = new String(chars, beginIndex, limit - beginIndex);
TextLayout tl = new TextLayout(str, this, frc);
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() +
tl.getLeading());
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (convolvedImage != null) {
int width = getWidth();
int height = getHeight();
synchronized (convolvedImage) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
FontRenderContext context = g2.getFontRenderContext();
TextLayout layout = new TextLayout(message, font, context);
Rectangle2D bounds = layout.getBounds();
int x = (width - convolvedImage.getWidth(null)) / 2;
int y = (int) (height - (convolvedImage.getHeight(null) + bounds.getHeight() + layout.getAscent())) / 2;
g2.drawImage(convolvedImage, x, y, this);
g2.setColor(new Color(0, 0, 0, (int) (gradient * 255)));
layout.draw(g2, (float) (width - bounds.getWidth()) / 2,
(float) (y + convolvedImage.getHeight(null) + bounds.getHeight() + layout.getAscent()));
}
}
}
public void runTest(Object ctx, int numReps) {
TLContext tlctx = (TLContext)ctx;
TextLayout tl = tlctx.tl;
float ht = 0;
do {
ht += tl.getAscent();
} while (--numReps >= 0);
}
/**
* Returns the logical bounds of the specified array of characters
* in the specified <code>FontRenderContext</code>. The logical
* bounds contains the origin, ascent, advance, and height, which
* includes the leading. The logical bounds does not always enclose
* all the text. For example, in some languages and in some fonts,
* accent marks can be positioned above the ascent or below the
* descent. To obtain a visual bounding box, which encloses all the
* text, use the {@link TextLayout#getBounds() getBounds} method of
* <code>TextLayout</code>.
* <p>Note: The returned bounds is in baseline-relative coordinates
* (see {@link java.awt.Font class notes}).
* @param chars an array of characters
* @param beginIndex the initial offset in the array of
* characters
* @param limit the end offset in the array of characters
* @param frc the specified <code>FontRenderContext</code>
* @return a <code>Rectangle2D</code> that is the bounding box of the
* specified array of characters in the specified
* <code>FontRenderContext</code>.
* @throws IndexOutOfBoundsException if <code>beginIndex</code> is
* less than zero, or <code>limit</code> is greater than the
* length of <code>chars</code>, or <code>beginIndex</code>
* is greater than <code>limit</code>.
* @see FontRenderContext
* @see Font#createGlyphVector
* @since 1.2
*/
public Rectangle2D getStringBounds(char [] chars,
int beginIndex, int limit,
FontRenderContext frc) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
}
if (limit > chars.length) {
throw new IndexOutOfBoundsException("limit: " + limit);
}
if (beginIndex > limit) {
throw new IndexOutOfBoundsException("range length: " +
(limit - beginIndex));
}
// this code should be in textlayout
// quick check for simple text, assume GV ok to use if simple
boolean simple = values == null ||
(values.getKerning() == 0 && values.getLigatures() == 0 &&
values.getBaselineTransform() == null);
if (simple) {
simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
}
if (simple) {
GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
limit - beginIndex, frc);
return gv.getLogicalBounds();
} else {
// need char array constructor on textlayout
String str = new String(chars, beginIndex, limit - beginIndex);
TextLayout tl = new TextLayout(str, this, frc);
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() +
tl.getLeading());
}
}
public void runTest(Object ctx, int numReps) {
TLContext tlctx = (TLContext)ctx;
TextLayout tl = tlctx.tl;
float ht = 0;
do {
ht += tl.getAscent();
} while (--numReps >= 0);
}
/**
* Returns the logical bounds of the specified array of characters
* in the specified <code>FontRenderContext</code>. The logical
* bounds contains the origin, ascent, advance, and height, which
* includes the leading. The logical bounds does not always enclose
* all the text. For example, in some languages and in some fonts,
* accent marks can be positioned above the ascent or below the
* descent. To obtain a visual bounding box, which encloses all the
* text, use the {@link TextLayout#getBounds() getBounds} method of
* <code>TextLayout</code>.
* <p>Note: The returned bounds is in baseline-relative coordinates
* (see {@link java.awt.Font class notes}).
* @param chars an array of characters
* @param beginIndex the initial offset in the array of
* characters
* @param limit the end offset in the array of characters
* @param frc the specified <code>FontRenderContext</code>
* @return a <code>Rectangle2D</code> that is the bounding box of the
* specified array of characters in the specified
* <code>FontRenderContext</code>.
* @throws IndexOutOfBoundsException if <code>beginIndex</code> is
* less than zero, or <code>limit</code> is greater than the
* length of <code>chars</code>, or <code>beginIndex</code>
* is greater than <code>limit</code>.
* @see FontRenderContext
* @see Font#createGlyphVector
* @since 1.2
*/
public Rectangle2D getStringBounds(char [] chars,
int beginIndex, int limit,
FontRenderContext frc) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
}
if (limit > chars.length) {
throw new IndexOutOfBoundsException("limit: " + limit);
}
if (beginIndex > limit) {
throw new IndexOutOfBoundsException("range length: " +
(limit - beginIndex));
}
// this code should be in textlayout
// quick check for simple text, assume GV ok to use if simple
boolean simple = values == null ||
(values.getKerning() == 0 && values.getLigatures() == 0 &&
values.getBaselineTransform() == null);
if (simple) {
simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
}
if (simple) {
GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
limit - beginIndex, frc);
return gv.getLogicalBounds();
} else {
// need char array constructor on textlayout
String str = new String(chars, beginIndex, limit - beginIndex);
TextLayout tl = new TextLayout(str, this, frc);
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() +
tl.getLeading());
}
}
public static float getHeight(TextLayout textLayout) {
float height = textLayout.getAscent() + textLayout.getDescent() + textLayout.getLeading();
// Ceil to whole points since when doing a compound TextLayout and then
// using TextLayoutUtils.getRealAlloc() with its TL.getVisualHighlightShape() and doing
// Graphics2D.fill(Shape) on the returned shape then for certain fonts such as
// Lucida Sans Typewriter size=10 on Ubuntu 10.04 the background is rendered one pixel down for certain lines
// so there appear white lines inside a selection.
return (float) Math.ceil(height);
}
/**
* Returns the logical bounds of the specified array of characters
* in the specified <code>FontRenderContext</code>. The logical
* bounds contains the origin, ascent, advance, and height, which
* includes the leading. The logical bounds does not always enclose
* all the text. For example, in some languages and in some fonts,
* accent marks can be positioned above the ascent or below the
* descent. To obtain a visual bounding box, which encloses all the
* text, use the {@link TextLayout#getBounds() getBounds} method of
* <code>TextLayout</code>.
* <p>Note: The returned bounds is in baseline-relative coordinates
* (see {@link java.awt.Font class notes}).
* @param chars an array of characters
* @param beginIndex the initial offset in the array of
* characters
* @param limit the end offset in the array of characters
* @param frc the specified <code>FontRenderContext</code>
* @return a <code>Rectangle2D</code> that is the bounding box of the
* specified array of characters in the specified
* <code>FontRenderContext</code>.
* @throws IndexOutOfBoundsException if <code>beginIndex</code> is
* less than zero, or <code>limit</code> is greater than the
* length of <code>chars</code>, or <code>beginIndex</code>
* is greater than <code>limit</code>.
* @see FontRenderContext
* @see Font#createGlyphVector
* @since 1.2
*/
public Rectangle2D getStringBounds(char [] chars,
int beginIndex, int limit,
FontRenderContext frc) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("beginIndex: " + beginIndex);
}
if (limit > chars.length) {
throw new IndexOutOfBoundsException("limit: " + limit);
}
if (beginIndex > limit) {
throw new IndexOutOfBoundsException("range length: " +
(limit - beginIndex));
}
// this code should be in textlayout
// quick check for simple text, assume GV ok to use if simple
boolean simple = values == null ||
(values.getKerning() == 0 && values.getLigatures() == 0 &&
values.getBaselineTransform() == null);
if (simple) {
simple = ! FontUtilities.isComplexText(chars, beginIndex, limit);
}
if (simple) {
GlyphVector gv = new StandardGlyphVector(this, chars, beginIndex,
limit - beginIndex, frc);
return gv.getLogicalBounds();
} else {
// need char array constructor on textlayout
String str = new String(chars, beginIndex, limit - beginIndex);
TextLayout tl = new TextLayout(str, this, frc);
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() +
tl.getLeading());
}
}
/**
* A utility method that calculates the rotation anchor offsets for a
* string. These offsets are relative to the text starting coordinate
* (BASELINE_LEFT).
*
* @param g2 the graphics device.
* @param text the text.
* @param anchor the anchor point.
*
* @return The offsets.
*/
private static float[] deriveRotationAnchorOffsets(Graphics2D g2,
AttributedString text, TextAnchor anchor) {
float[] result = new float[2];
TextLayout layout = new TextLayout(text.getIterator(),
g2.getFontRenderContext());
Rectangle2D bounds = layout.getBounds();
float ascent = layout.getAscent();
float halfAscent = ascent / 2.0f;
float descent = layout.getDescent();
float leading = layout.getLeading();
float xAdj = 0.0f;
float yAdj = 0.0f;
if (isHorizontalLeft(anchor)) {
xAdj = 0.0f;
}
else if (isHorizontalCenter(anchor)) {
xAdj = (float) bounds.getWidth() / 2.0f;
}
else if (isHorizontalRight(anchor)) {
xAdj = (float) bounds.getWidth();
}
if (isTop(anchor)) {
yAdj = descent + leading - (float) bounds.getHeight();
}
else if (isHalfHeight(anchor)) {
yAdj = descent + leading - (float) (bounds.getHeight() / 2.0);
}
else if (isHalfAscent(anchor)) {
yAdj = -halfAscent;
}
else if (isBaseline(anchor)) {
yAdj = 0.0f;
}
else if (isBottom(anchor)) {
yAdj = descent + leading;
}
result[0] = xAdj;
result[1] = yAdj;
return result;
}
protected void drawMultilineText(String text, int x, int y, int boxWidth, int boxHeight) {
int availableHeight = boxHeight - ICON_SIZE - ICON_PADDING;
// Create an attributed string based in input text
AttributedString attributedString = new AttributedString(text);
attributedString.addAttribute(TextAttribute.FONT, g.getFont());
attributedString.addAttribute(TextAttribute.FOREGROUND, Color.black);
AttributedCharacterIterator characterIterator = attributedString.getIterator();
int width = boxWidth - (2 * TEXT_PADDING);
int currentHeight = 0;
// Prepare a list of lines of text we'll be drawing
List<TextLayout> layouts = new ArrayList<TextLayout>();
String lastLine = null;
LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, g.getFontRenderContext());
TextLayout layout = null;
while (measurer.getPosition() < characterIterator.getEndIndex() && currentHeight <= availableHeight) {
int previousPosition = measurer.getPosition();
// Request next layout
layout = measurer.nextLayout(width);
int height = ((Float) (layout.getDescent() + layout.getAscent() + layout.getLeading())).intValue();
if (currentHeight + height > availableHeight) {
// The line we're about to add should NOT be added anymore, append three dots to previous one instead
// to indicate more text is truncated
layouts.remove(layouts.size() - 1);
if (lastLine.length() >= 4) {
lastLine = lastLine.substring(0, lastLine.length() - 4) + "...";
}
layouts.add(new TextLayout(lastLine, g.getFont(), g.getFontRenderContext()));
} else {
layouts.add(layout);
lastLine = text.substring(previousPosition, measurer.getPosition());
currentHeight += height;
}
}
int currentY = y + ICON_SIZE + ICON_PADDING + ((availableHeight - currentHeight) / 2);
int currentX = 0;
// Actually draw the lines
for (TextLayout textLayout : layouts) {
currentY += textLayout.getAscent();
currentX = TEXT_PADDING + x + ((width - ((Double) textLayout.getBounds().getWidth()).intValue()) / 2);
textLayout.draw(g, currentX, currentY);
currentY += textLayout.getDescent() + textLayout.getLeading();
}
}
/**
* A utility method that calculates the rotation anchor offsets for a
* string. These offsets are relative to the text starting coordinate
* (BASELINE_LEFT).
*
* @param g2 the graphics device.
* @param text the text.
* @param anchor the anchor point.
*
* @return The offsets.
*/
private static float[] deriveRotationAnchorOffsets(Graphics2D g2,
AttributedString text, TextAnchor anchor) {
float[] result = new float[2];
TextLayout layout = new TextLayout(text.getIterator(),
g2.getFontRenderContext());
Rectangle2D bounds = layout.getBounds();
float ascent = layout.getAscent();
float halfAscent = ascent / 2.0f;
float descent = layout.getDescent();
float leading = layout.getLeading();
float xAdj = 0.0f;
float yAdj = 0.0f;
if (isHorizontalLeft(anchor)) {
xAdj = 0.0f;
}
else if (isHorizontalCenter(anchor)) {
xAdj = (float) bounds.getWidth() / 2.0f;
}
else if (isHorizontalRight(anchor)) {
xAdj = (float) bounds.getWidth();
}
if (isTop(anchor)) {
yAdj = descent + leading - (float) bounds.getHeight();
}
else if (isHalfHeight(anchor)) {
yAdj = descent + leading - (float) (bounds.getHeight() / 2.0);
}
else if (isHalfAscent(anchor)) {
yAdj = -halfAscent;
}
else if (isBaseline(anchor)) {
yAdj = 0.0f;
}
else if (isBottom(anchor)) {
yAdj = descent + leading;
}
result[0] = xAdj;
result[1] = yAdj;
return result;
}
private void drawText( Graphics g, int w, int h ) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
g2.fillRect(0, 0, w, h);
g2.setColor(Color.black);
/// sets font, RenderingHints.
setParams( g2 );
/// If flag is set, recalculate fontMetrics and reset the scrollbar
if ( updateFontMetrics || isPrinting ) {
/// NOTE: re-calculates in case G2 transform
/// is something other than NONE
calcFontMetrics( g2, w, h );
updateFontMetrics = false;
}
/// Calculate the amount of text that can be drawn...
calcTextRange();
/// Draw according to the set "Text to Use" mode
if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) {
int charToDraw = drawStart;
if ( showGrid )
drawGrid( g2 );
for ( int i = 0; i < numCharDown && charToDraw <= drawEnd; i++ ) {
for ( int j = 0; j < numCharAcross && charToDraw <= drawEnd; j++, charToDraw++ ) {
int gridLocX = j * gridWidth + canvasInset_X;
int gridLocY = i * gridHeight + canvasInset_Y;
modeSpecificDrawChar( g2, charToDraw,
gridLocX + gridWidth / 2,
gridLocY + maxAscent );
}
}
}
else if ( textToUse == USER_TEXT ) {
g2.drawRect( 0, 0, w - 1, h - 1 );
for ( int i = drawStart; i <= drawEnd; i++ ) {
int lineStartX = canvasInset_Y;
int lineStartY = ( i - drawStart ) * gridHeight + maxAscent;
modeSpecificDrawLine( g2, userText[i], lineStartX, lineStartY );
}
}
else {
float xPos, yPos = (float) canvasInset_Y;
g2.drawRect( 0, 0, w - 1, h - 1 );
for ( int i = drawStart; i <= drawEnd; i++ ) {
TextLayout oneLine = (TextLayout) lineBreakTLs.elementAt( i );
xPos =
oneLine.isLeftToRight() ?
canvasInset_X : ( (float) w - oneLine.getAdvance() - canvasInset_X );
float fmData[] = {0, oneLine.getAscent(), 0, oneLine.getDescent(), 0, oneLine.getLeading()};
if (g2Transform != NONE) {
AffineTransform at = getAffineTransform(g2Transform);
at.transform( fmData, 0, fmData, 0, 3);
}
//yPos += oneLine.getAscent();
yPos += fmData[1]; // ascent
//oneLine.draw( g2, xPos, yPos );
tlDrawLine( g2, oneLine, xPos, yPos );
//yPos += oneLine.getDescent() + oneLine.getLeading();
yPos += fmData[3] + fmData[5]; // descent + leading
}
}
g2.dispose();
}
@Override protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
Insets i = getInsets();
float x0 = i.left;
float y0 = i.top;
Font font = getFont();
String txt = getText();
FontRenderContext frc = g2.getFontRenderContext();
Shape shape = new TextLayout(txt.substring(0, 1), font, frc).getOutline(null);
AffineTransform at1 = AffineTransform.getScaleInstance(5d, 5d);
Shape s1 = at1.createTransformedShape(shape);
Rectangle r = s1.getBounds();
r.grow(6, 2);
int rw = r.width;
int rh = r.height;
AffineTransform at2 = AffineTransform.getTranslateInstance(x0, y0 + rh);
Shape s2 = at2.createTransformedShape(s1);
g2.setPaint(getForeground());
g2.fill(s2);
float x = x0 + rw;
float y = y0;
int w0 = getWidth() - i.left - i.right;
int w = w0 - rw;
AttributedString as = new AttributedString(txt.substring(1));
as.addAttribute(TextAttribute.FONT, font);
AttributedCharacterIterator aci = as.getIterator();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
while (lbm.getPosition() < aci.getEndIndex()) {
TextLayout tl = lbm.nextLayout(w);
tl.draw(g2, x, y + tl.getAscent());
y += tl.getDescent() + tl.getLeading() + tl.getAscent();
if (y0 + rh < y) {
x = x0;
w = w0;
}
}
g2.dispose();
}
protected void drawMultilineText(String text, int x, int y, int boxWidth, int boxHeight) {
int availableHeight = boxHeight - ICON_SIZE - ICON_PADDING;
// Create an attributed string based in input text
AttributedString attributedString = new AttributedString(text);
attributedString.addAttribute(TextAttribute.FONT, g.getFont());
attributedString.addAttribute(TextAttribute.FOREGROUND, Color.black);
AttributedCharacterIterator characterIterator = attributedString.getIterator();
int width = boxWidth - (2 * TEXT_PADDING);
int currentHeight = 0;
// Prepare a list of lines of text we'll be drawing
List<TextLayout> layouts = new ArrayList<TextLayout>();
String lastLine = null;
LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, g.getFontRenderContext());
TextLayout layout = null;
while (measurer.getPosition() < characterIterator.getEndIndex() && currentHeight <= availableHeight) {
int previousPosition = measurer.getPosition();
// Request next layout
layout = measurer.nextLayout(width);
int height = ((Float) (layout.getDescent() + layout.getAscent() + layout.getLeading())).intValue();
if (currentHeight + height > availableHeight) {
// The line we're about to add should NOT be added anymore, append three dots to previous one instead
// to indicate more text is truncated
layouts.remove(layouts.size() - 1);
if (lastLine.length() >= 4) {
lastLine = lastLine.substring(0, lastLine.length() - 4) + "...";
}
layouts.add(new TextLayout(lastLine, g.getFont(), g.getFontRenderContext()));
} else {
layouts.add(layout);
lastLine = text.substring(previousPosition, measurer.getPosition());
currentHeight += height;
}
}
int currentY = y + ICON_SIZE + ICON_PADDING + ((availableHeight - currentHeight) / 2);
int currentX = 0;
// Actually draw the lines
for (TextLayout textLayout : layouts) {
currentY += textLayout.getAscent();
currentX = TEXT_PADDING + x + ((width - ((Double) textLayout.getBounds().getWidth()).intValue()) / 2);
textLayout.draw(g, currentX, currentY);
currentY += textLayout.getDescent() + textLayout.getLeading();
}
}
/**
* Gets the string bounds.
*
* @param tl
* textlayout instance
* @return the string bounds
*/
protected Rectangle2D getStringBounds(TextLayout tl)
{
return new Rectangle2D.Float(0, -tl.getAscent(), tl.getAdvance(),
tl.getAscent() + tl.getDescent() + tl.getLeading());
}