controlp5/src/controlP5/ControlFont.java

294 lines
9.1 KiB
Java
Executable File

package controlP5;
/**
* controlP5 is a processing gui library.
*
* 2006-2015 by Andreas Schlegel
*
* This 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 2.1
* of the License, or (at your option) any later version.
* This 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 this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
* @author Andreas Schlegel (http://www.sojamo.de)
* @modified ##date##
* @version ##version##
*
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphics;
/**
* A ControlFont is a container for a PFont that can be used to customize the font of a label.
* (Designing the Font handling gave me a big headache, especially when it comes to calculating the
* dimensions of a font which are not available at all times but only at certain times. The current
* status I suppose is a good compromise and works for standard font handling cases. For any special
* cases it will be difficult to convince me to make any changes.)
*
* @example extra/ControlP5controlFont
*/
public class ControlFont {
public static boolean DEBUG = false;
/**
* set the RENDER_2X variable to true to double render text, this makes the font look bolder
* especially in OpenGL mode. use: ControlFont.RENDER_2X = true;
*/
public static boolean RENDER_2X;
/**
* renders a PFont twice for better and sharper readability
*/
public static void sharp( ) {
RENDER_2X = true;
}
/**
* sets the rendering of a PFont back to normal and single rendering.
*/
public static void normal( ) {
RENDER_2X = false;
}
PFont pfont;
List< String > txt;
String s = "";
private int top;
private int bottom;
private int center;
private int height;
private int width;
private int baseline = 0;
private int _myTextHeight = 1;
private int[] offset = new int[ 2 ];
private int size;
public ControlFont( PFont theFont ) {
this( theFont , checkFontSize( theFont ) );
}
public ControlFont( PFont theFont , int theFontSize ) {
this( theFont , theFontSize , theFontSize + 2 );
}
public ControlFont( PFont theFont , int theFontSize , int theLineHeight ) {
pfont = theFont;
size = theFontSize;
txt = new ArrayList< String >( );
}
static private int checkFontSize( PFont theFont ) {
try {
// was: return theFont.getFont().getSize(); but disappeared with p5 2.0b1
return theFont.getSize( );
} catch ( NullPointerException e ) {
System.out.println( "ControlP5: could not find font-size details for font " + theFont.getName( ) + ", use constructor ControlFont(PFont theFont, int theFontSize) to specify the font size." );
return 10;
}
}
public void init( Label theLabel ) {
// when the font changes, init is called.
// width and height should be adjusted to the updated font here,
// but we need PApplet here to determine the width of the label.
// unfortunately we dont have access to PApplet here, so a change
// might result in a 1-frame-flickr but doesnt necessarily need
// to happen.
}
public void setSize( int theSize ) {
size = theSize;
}
public int getSize( ) {
/* quickfix http://code.google.com/p/controlp5/issues/detail?id=46 first check the pfont
* size then default back to size */
return size;
}
public int getOffset( int theIndex ) {
return offset[ theIndex ];
}
public int getTextHeight( ) {
return _myTextHeight;
}
public int getWidth( ) {
return width;
}
public int getHeight( ) {
return height;
}
public int getCenter( ) {
return center;
}
public int getTop( ) {
return top;
}
public int getBottom( ) {
return bottom;
}
public int getBaseline( ) {
return baseline;
}
public PFont getFont( ) {
return pfont;
}
public void adjust( PGraphics theGraphics , Label theLabel ) {
if ( theLabel.isChanged( ) ) {
theGraphics.textFont( pfont , size );
// the origin of a PFont Label is top left corner, therefore
// the following the following measures have to be calculated
// when a font is changed. we have to do that here since PApplet
// is required to calculate a font's ascent and descent value.
// values are calculated based on the baseline (which is 0),
// therefore center and top are negative values.
// to order to sync the line height with the height of the font,
// the value of lineHeightOffset carries this offset value.
// This becomes necessary when working with multiple lines.
top = -( int ) theGraphics.textAscent( );
bottom = ( int ) theGraphics.textDescent( );
center = -( int ) ( ( -top - bottom ) / 2 );
height = theLabel.isMultiline( ) ? theLabel.getHeight( ) : ( int ) ( theGraphics.textAscent( ) + theGraphics.textDescent( ) );
width = theLabel.isMultiline( ) ? theLabel.getWidth( ) : ( int ) theGraphics.textWidth( theLabel.getTextFormatted( ) );
if ( theLabel.isMultiline( ) ) {
calculateHeight( theGraphics , theLabel );
}
theLabel.setChanged( false );
}
}
private void calculateHeight( PGraphics theGraphics , Label theLabel ) {
txt.clear( );
String myString = theLabel.getTextFormatted( );
List< String > paragraphs = Arrays.asList( myString.split( "\n" ) );
// does not recognize linebreaks at the end of theString.
myString = "";
for ( String p : paragraphs ) {
List< String > words = Arrays.asList( p.split( "\\s" ) );
for ( String w : words ) {
if ( theGraphics.textWidth( myString + w ) < width ) {
myString += w + " ";
} else {
txt.add( myString.substring( 0 , PApplet.max( 0 , myString.length( ) - 1 ) ) );
myString = w + " ";
}
}
txt.add( myString.substring( 0 , myString.length( ) - 1 ) );
myString = "";
}
if ( theLabel.getHeight( ) % theLabel.getLineHeight( ) != 0 ) {
txt.add( "" );
}
_myTextHeight = ( PApplet.round( txt.size( ) * theLabel.getLineHeight( ) ) );
int maxLineNum = PApplet.round( theLabel.getHeight( ) / theLabel.getLineHeight( ) );
int offset = ( int ) ( PApplet.max( 0 , txt.size( ) - maxLineNum ) * ( PApplet.abs( theLabel.getOffsetYratio( ) ) ) );
int lim = PApplet.min( txt.size( ) , maxLineNum );
s = "";
for ( int i = 0 ; i < lim ; i++ ) {
s += txt.get( i + offset ) + "\n";
}
}
public int getOverflow( ) {
return ( _myTextHeight - height );
}
public void draw( ControlP5 c , Label theLabel ) {
draw( c.pg , theLabel );
}
public void draw( PGraphics theGraphics , Label theLabel ) {
PFont loadedFont = theGraphics.textFont;
float loadedSize = theGraphics.textSize;
if ( loadedFont == null ) {
theGraphics.textSize( loadedSize ); // forces default font
loadedFont = theGraphics.textFont;
}
int loadedAlign = theGraphics.textAlign;
theGraphics.textFont( pfont , size );
theGraphics.textAlign( theLabel.textAlign );
theGraphics.fill( theLabel.getColor( ) );
if ( theLabel.isMultiline( ) ) {
theGraphics.fill( theLabel.getColor( ) );
theGraphics.textLeading( theLabel.getLineHeight( ) );
theGraphics.text( s , 0 , 0 , theLabel.getWidth( ) , theLabel.getHeight( ) );
} else {
theGraphics.translate( 0 , -top + 1 );
debug( theGraphics , theLabel );
theGraphics.fill( theLabel.getColor( ) );
theGraphics.textLeading( theLabel.getLineHeight( ) );
theGraphics.text( theLabel.getTextFormatted( ) , 0 , 0 );
if ( RENDER_2X ) {
theGraphics.text( theLabel.getTextFormatted( ) , 0 , 0 );
}
}
theGraphics.textFont( loadedFont , loadedSize );
theGraphics.textAlign( loadedAlign );
}
private void debug( PGraphics theGraphics , Label theLabel ) {
if ( DEBUG ) {
theGraphics.stroke( 0 , 255 , 0 ); // BASELINE
theGraphics.line( 0 , getBaseline( ) , theGraphics.textWidth( theLabel.getText( ) ) , getBaseline( ) );
theGraphics.stroke( 0 , 0 , 255 ); // TOP
theGraphics.line( 0 , getTop( ) , theGraphics.textWidth( theLabel.getText( ) ) , getTop( ) );
theGraphics.stroke( 255 , 255 , 0 ); // BOTTOM
theGraphics.line( 0 , getBottom( ) , theGraphics.textWidth( theLabel.getText( ) ) , getBottom( ) );
theGraphics.stroke( 255 , 0 , 0 ); // CENTER
theGraphics.line( 0 , getCenter( ) , theGraphics.textWidth( theLabel.getText( ) ) , getCenter( ) );
theGraphics.stroke( 255 , 128 , 0 ); // CENTER_CAPS
theGraphics.line( 0 , getTop( ) / 2 , theGraphics.textWidth( theLabel.getText( ) ) , getTop( ) / 2 );
theGraphics.noStroke( );
}
}
public static int getWidthFor( String theText , Label theLabel , PGraphics theGraphics ) {
theGraphics.textFont( theLabel.getFont( ).pfont , theLabel.getFont( ).size );
return ( int ) theGraphics.textWidth( theText );
}
}
// textorize, a Ruby-based font rasterizer command line utility for Mac OS X
// http://textorize.org/