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/