/**
* Copyright (c) 2003-2008, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.ui.hud.utils;
import java.awt.FontMetrics;
import java.awt.geom.Rectangle2D;
import org.xith3d.scenegraph.Texture2DCanvas;
import org.xith3d.ui.text2d.TextAlignment;
/**
* {@link MultilineText} splits an input string at the newline character
* and calculates sizes and offsets in pixels.
*
* @author Marvin Froehlich (aka Qudus)
*/
public class MultilineText
{
private String text = null;
private String[] lines = new String[ 0 ];
private int numLines = 0;
private Rectangle2D[] bounds = null;
private int offset_y = 0;
private int totalWidth = 0;
private int totalHeight = 0;
private int min_pos_x = 0;
private int[] pos_x = null;
private int[] pos_y = null;
private int dirty = ~0;
public final int getNumLines()
{
return ( numLines );
}
public final String getLine( int index )
{
return ( lines[index] );
}
public final int getMinPosX()
{
return ( min_pos_x );
}
public final int getPosX( int lineIndex )
{
return ( pos_x[lineIndex] );
}
public final int getPosY( int lineIndex )
{
return ( pos_y[lineIndex] );
}
public final int getLineOffsetY( int lineIndex )
{
return ( (int)bounds[lineIndex].getY() );
}
public final int getWidth( int lineIndex )
{
return ( (int)bounds[lineIndex].getWidth() );
}
public final int getHeight( int lineIndex )
{
return ( (int)bounds[lineIndex].getHeight() );
}
public final int getTotalWidth()
{
return ( totalWidth );
}
public final int getTotalHeight()
{
return ( totalHeight );
}
public final int getOffsetY()
{
return ( offset_y );
}
private static final String getLine( String text, int fromIdx, int toIdx )
{
if ( ( toIdx - fromIdx >= 1 ) && ( text.charAt( fromIdx ) == '\r' ) )
{
if ( ( toIdx - fromIdx >= 2 ) && ( text.charAt( toIdx - 1 ) == '\r' ) )
return ( text.substring( fromIdx + 1, toIdx - 1 ) );
return ( text.substring( fromIdx + 1, toIdx ));
}
if ( ( toIdx - fromIdx >= 2 ) && ( text.charAt( toIdx - 1 ) == '\r' ) )
{
return ( text.substring( fromIdx, toIdx - 1 ) );
}
if ( ( fromIdx == 0 ) && ( toIdx == text.length() ) )
return ( text );
return ( text.substring( fromIdx, toIdx ) );
}
private int splitText()
{
int newNumLines = 0;
int off = 0;
int idx = text.indexOf( '\n', off );
if ( idx < 0 )
{
// Single-line text
if ( lines.length < 1 )
lines = new String[ 1 ];
lines[0] = getLine( text, 0, text.length() );
newNumLines = 1;
}
else
{
// Multi-line text
do
{
if ( idx < 0 )
idx = text.length();
if ( lines.length < newNumLines + 1 )
{
String[] tmp = new String[ lines.length + 1 ];
System.arraycopy( lines, 0, tmp, 0, lines.length );
lines = tmp;
}
lines[ newNumLines++ ] = getLine( text, off, idx );
off = idx + 1;
}
while ( ( ( idx = text.indexOf( '\n', off ) ) >= 0 ) || ( off < text.length() - 1 ) );
}
for ( int i = newNumLines; i < numLines; i++ )
{
lines[i] = null;
bounds[i] = null;
//lineMetrics[i] = null;
}
numLines = newNumLines;
return ( numLines );
}
/**
* Sets the new text and instantly splits it.
* {@link #update(Texture2DCanvas, int, int, int, int, int, int, TextAlignment)}
* must be called to update the sizes and offsets.
*
* @param text
*/
public void setText( String text )
{
this.text = text;
splitText();
//this.dirty |= 1;
this.dirty = ~0;
}
/**
* Marks sizes and offsets dirty.
*/
public void setPositionDirty()
{
this.dirty |= 2;
}
/**
* Updates all dirty content.
*
* @param texCanvas
* @param width
* @param height
* @param paddingLeft
* @param paddingRight
* @param paddingTop
* @param paddingBottom
* @param alignment
*/
public void update( Texture2DCanvas texCanvas, int width, int height, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, TextAlignment alignment )
{
if ( dirty == 0 )
return;
if ( ( dirty & 1 ) != 0 )
{
FontMetrics metrics = texCanvas.getFontMetrics();
if ( numLines == 0 )
{
min_pos_x = 0;
totalWidth = 0;
totalHeight = 0;
offset_y = 0;
}
else
{
if ( ( bounds == null ) || ( bounds.length < numLines ) )
bounds = new Rectangle2D[ numLines ];
totalHeight = 0;
for ( int i = 0; i < numLines; i++ )
{
bounds[i] = metrics.getStringBounds( lines[i], texCanvas );
totalHeight += bounds[i].getHeight();
}
offset_y = (int)bounds[0].getY();
}
if ( ( pos_x == null ) || ( pos_x.length < numLines ) )
pos_x = new int[ numLines ];
if ( ( pos_y == null ) || ( pos_y.length < numLines ) )
pos_y = new int[ numLines ];
dirty |= 2;
}
if ( ( dirty & 2 ) != 0 )
{
int y = paddingTop - offset_y;
if ( alignment.isVCenterAligned() )
y += (int)( ( height - paddingTop - paddingBottom - totalHeight ) / 2.0 );
else if ( alignment.isBottomAligned() )
y += (int)( height - paddingTop - paddingBottom - totalHeight );
for ( int i = 0; i < numLines; i++ )
{
pos_x[i] = paddingLeft;
if ( alignment.isHCenterAligned() )
pos_x[i] += (int)( ( width - paddingLeft - paddingRight - bounds[i].getWidth() ) / 2.0 );
else if ( alignment.isRightAligned() )
pos_x[i] += (int)( width - paddingLeft - paddingRight - bounds[i].getWidth() );
pos_y[i] = y;
y += bounds[i].getHeight();
}
}
if ( ( dirty & ( 1 | 2 ) ) != 0 )
{
if ( numLines == 0 )
{
min_pos_x = 0;
totalWidth = 0;
}
else
{
min_pos_x = Integer.MAX_VALUE;
totalWidth = 0;
for ( int i = 0; i < numLines; i++ )
{
min_pos_x = Math.min( min_pos_x, pos_x[i] );
totalWidth = Math.max( totalWidth, pos_x[i] + (int)bounds[i].getWidth() );
}
totalWidth -= min_pos_x;
}
}
dirty = 0;
}
public MultilineText()
{
}
}