PageRenderTime 69ms CodeModel.GetById 9ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 1ms

/src/org/mt4j/components/visibleComponents/widgets/MTTextArea.java

http://mt4j.googlecode.com/
Java | 1331 lines | 767 code | 200 blank | 364 comment | 156 complexity | 64c6300a39465ecffdb3a77ad47b7899 MD5 | raw file
   1/***********************************************************************
   2 * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
   3 *  
   4 *   This program is free software: you can redistribute it and/or modify
   5 *   it under the terms of the GNU General Public License as published by
   6 *   the Free Software Foundation, either version 3 of the License, or
   7 *   (at your option) any later version.
   8 *
   9 *   This program is distributed in the hope that it will be useful,
  10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 *   GNU General Public License for more details.
  13 *
  14 *   You should have received a copy of the GNU General Public License
  15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16 *
  17 ***********************************************************************/
  18package org.mt4j.components.visibleComponents.widgets;
  19
  20import java.util.ArrayList;
  21import java.util.List;
  22
  23import javax.media.opengl.GL;
  24import javax.media.opengl.glu.GLU;
  25
  26import org.mt4j.MTApplication;
  27import org.mt4j.components.TransformSpace;
  28import org.mt4j.components.clipping.Clip;
  29import org.mt4j.components.css.style.CSSFont;
  30import org.mt4j.components.css.style.CSSStyle;
  31import org.mt4j.components.visibleComponents.font.BitmapFont;
  32import org.mt4j.components.visibleComponents.font.BitmapFontCharacter;
  33import org.mt4j.components.visibleComponents.font.FontManager;
  34import org.mt4j.components.visibleComponents.font.IFont;
  35import org.mt4j.components.visibleComponents.font.IFontCharacter;
  36import org.mt4j.components.visibleComponents.shapes.MTRectangle;
  37import org.mt4j.components.visibleComponents.widgets.keyboard.ITextInputListener;
  38import org.mt4j.components.visibleComponents.widgets.keyboard.MTKeyboard;
  39import org.mt4j.input.inputProcessors.componentProcessors.lassoProcessor.IdragClusterable;
  40import org.mt4j.util.MT4jSettings;
  41import org.mt4j.util.MTColor;
  42import org.mt4j.util.math.Matrix;
  43import org.mt4j.util.math.Tools3D;
  44import org.mt4j.util.math.Vector3D;
  45import org.mt4j.util.math.Vertex;
  46
  47import processing.core.PApplet;
  48import processing.core.PGraphics;
  49
  50/**
  51 * The Class MTTextArea. This widget allows to display text with a specified font.
  52 * If the constructor with no fixed text are dimensions is used, the text area will
  53 * expand itself to fit the text in. 
  54 * <br>
  55 * If the constructor with fixed dimensions is used, the text will have word wrapping
  56 * and be clipped to the specified dimensions.
  57 * 
  58 * @author Christopher Ruff
  59 */
  60public class MTTextArea extends MTRectangle implements IdragClusterable, ITextInputListener, Comparable<Object>{
  61
  62//Standard expand direction is {@link ExpandDirection#UP} for
  63// backward compatibility.
  64    /**
  65     * Determines the vertical expand direction of the {@link MTTextArea}
  66     * if the text area will expand itself to fit the text in.
  67     *
  68     * 
  69     */
  70    public enum ExpandDirection {
  71        /** Expand the {@link MTTextArea} in top direction if necessary. */  
  72        UP,
  73        /** Expand the {@link MTTextArea} in bottom direction if necassary. */
  74        DOWN
  75    }
  76    
  77	/** The pa. */
  78	private PApplet pa;
  79	
  80	/** The character list. */
  81	private ArrayList<IFontCharacter> characterList;
  82	
  83	/** The font. */
  84	private IFont font;
  85	
  86	/** The font b box height. */
  87	private int fontHeight;
  88	
  89	/** The show caret. */
  90	private boolean showCaret;
  91	
  92	/** The show caret time. */
  93	private long showCaretTime; //ms
  94	
  95	/** The caret time counter. */
  96	private int caretTimeCounter = 0;
  97	
  98	/** The enable caret. */
  99	private boolean enableCaret;
 100	
 101	/** The caret width. */
 102	private float caretWidth;
 103
 104	private int innerPaddingTop;
 105	private int innerPaddingLeft;
 106	
 107	private float totalScrollTextX;
 108	private float totalScrollTextY;
 109	
 110	private static final int MODE_EXPAND = 0;
 111	private static final int MODE_WRAP = 1;
 112	
 113	private int mode;
 114
 115	private static ArtificalLineBreak artificialLineBreak;
 116
 117    private ExpandDirection expandDirection ;
 118	
 119	//TODO different font sizes in one textarea?
 120	//TODO (create mode : expand vertically but do word wrap horizontally?
 121    
 122    /**
 123     * Instantiates a new text area. This constructor creates
 124     * a text area with variable dimensions that expands itself when text is added.
 125     * A default font is used.
 126     *
 127     * @param pApplet the applet
 128     */
 129	public MTTextArea(PApplet pApplet) {
 130		this(pApplet, FontManager.getInstance().getDefaultFont(pApplet));
 131	}
 132	
 133	
 134    private boolean ignoreCSSFont = false;
 135    
 136    /**
 137     * Instantiates a new text area. This constructor creates
 138     * a text area with variable dimensions that expands itself when text is added.
 139     *
 140     * @param pApplet the applet
 141     * @param font the font
 142     */
 143	public MTTextArea(MTApplication pApplet, CSSFont font) {
 144		this(pApplet, FontManager.getInstance().getDefaultFont(pApplet));
 145		this.getCssHelper().getPrivateStyleSheets().add(new CSSStyle(font,pApplet));
 146	}
 147	
 148    
 149	/**
 150	 * Instantiates a new text area. This constructor creates
 151	 * a text area with variable dimensions that expands itself when text is added.
 152	 * 
 153	 * @param pApplet the applet
 154	 * @param font the font
 155	 */
 156	public MTTextArea(PApplet pApplet, IFont font) {
 157		super(	pApplet, 0, 	//upper left corner
 158				0, 	//width
 159				0,  //height
 160				0);
 161		
 162		init(pApplet, font, MODE_EXPAND);
 163		
 164		//Position textarea at 0,0
 165		this.setUpperLeftPos(Vector3D.ZERO_VECTOR);
 166		
 167		//Expand vertically at enter 
 168		this.setHeightLocal(this.getTotalLinesHeight());
 169		this.setWidthLocal(getMaxLineWidth());
 170		
 171		//Disable font being overwritten by CSS
 172		this.ignoreCSSFont = true;
 173	}
 174	
 175	
 176	
 177	/**
 178	 * Instantiates a new mT text area.
 179	 *
 180	 * @param x the x
 181	 * @param y the y
 182	 * @param width the width
 183	 * @param height the height
 184	 * @param pApplet the applet
 185	 * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter.
 186	 */
 187	public MTTextArea(float x, float y, float width, float height, PApplet pApplet) {
 188		this(pApplet, x, y, width, height, FontManager.getInstance().getDefaultFont(pApplet));
 189	}
 190	
 191    /**
 192     * Instantiates a new mT text area.
 193     * This constructor creates a textarea with fixed dimensions.
 194     * If the text exceeds the dimensions the text is clipped.
 195     * A default font is used.
 196     * @param pApplet the applet
 197     * @param x the x
 198     * @param y the y
 199     * @param width the width
 200     * @param height the height
 201     */
 202	public MTTextArea(PApplet pApplet, float x, float y, float width, float height) {
 203		this(pApplet, x, y, width, height, FontManager.getInstance().getDefaultFont(pApplet));
 204	}
 205	
 206	
 207	/**
 208	 * Instantiates a new mT text area.
 209	 *
 210	 * @param x the x
 211	 * @param y the y
 212	 * @param width the width
 213	 * @param height the height
 214	 * @param font the font
 215	 * @param pApplet the applet
 216	 * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter.
 217	 */
 218	public MTTextArea(float x, float y, float width, float height, IFont font, PApplet pApplet) {
 219		this(pApplet, x, y, width, height, font);
 220	}
 221    
 222	/**
 223	 * Instantiates a new mT text area. 
 224	 * This constructor creates a textarea with fixed dimensions. 
 225	 * If the text exceeds the dimensions the text is clipped.
 226	 * @param pApplet the applet
 227	 * @param x the x
 228	 * @param y the y
 229	 * @param width the width
 230	 * @param height the height
 231	 * @param font the font
 232	 */
 233	public MTTextArea(PApplet pApplet, float x, float y, float width, float height, IFont font) {
 234		super(	pApplet, 0, 	//upper left corner
 235				0, 	//width
 236				width,  //height
 237				height);
 238		
 239		init(pApplet, font, MODE_WRAP);
 240		
 241		//Position textarea at x,y
 242		this.setUpperLeftPos(new Vector3D(x,y,0));
 243		this.setUpperLeftPos(new Vector3D(x,y,0));
 244		
 245		//Disable font being overwritten by CSS
 246		this.ignoreCSSFont = true;
 247	}
 248	
 249	
 250	
 251	public boolean isIgnoreCSSFont() {
 252		return ignoreCSSFont;
 253	}
 254
 255	public void setIgnoreCSSFont(boolean ignoreCSSFont) {
 256		this.ignoreCSSFont = ignoreCSSFont;
 257	}
 258
 259	private void setUpperLeftPos(Vector3D pos){
 260		//Position textarea at 0,0
 261		PositionAnchor prevAnchor = this.getAnchor();
 262		this.setAnchor(PositionAnchor.UPPER_LEFT);
 263		this.setPositionGlobal(pos);
 264		this.setAnchor(prevAnchor);
 265	}
 266	
 267	public MTTextArea(MTApplication app) {
 268		this(app, app.getCssStyleManager().getDefaultFont(app));
 269	}
 270	
 271	private void init(PApplet pApplet, IFont font, int mode){
 272		this.pa = pApplet;
 273		this.font = font;
 274		this.expandDirection = ExpandDirection.DOWN;
 275		
 276		this.mode = mode;
 277		switch (this.mode) {
 278		case MODE_EXPAND:
 279			//We dont have to clip since we expand the area
 280			break;
 281		case MODE_WRAP:
 282			if (MT4jSettings.getInstance().isOpenGlMode()){ 
 283				//Clip the text to the area
 284				this.setClip(new Clip(pApplet, this.getVerticesLocal()[0].x, this.getVerticesLocal()[0].y, this.getWidthXY(TransformSpace.LOCAL), this.getHeightXY(TransformSpace.LOCAL)));
 285			}
 286			break;
 287		default:
 288			break;
 289		}
 290		
 291		characterList = new ArrayList<IFontCharacter>();
 292		
 293		if (MT4jSettings.getInstance().isOpenGlMode())
 294			this.setUseDirectGL(true);
 295		
 296		fontHeight = font.getFontAbsoluteHeight();
 297		
 298		caretWidth = 0; 
 299		innerPaddingTop = 5;
 300		innerPaddingLeft = 8;
 301		
 302		showCaret 	= false;
 303		enableCaret = false;
 304		showCaretTime = 600;
 305		
 306		this.setStrokeWeight(1.5f);
 307		this.setStrokeColor(new MTColor(255, 255, 255, 255));
 308		this.setDrawSmooth(true);
 309		
 310		//Draw this component and its children above 
 311		//everything previously drawn and avoid z-fighting
 312		this.setDepthBufferDisabled(true);
 313		
 314		this.totalScrollTextX = 0.0f;
 315		this.totalScrollTextY = 0.0f;
 316		
 317		if (artificialLineBreak == null){
 318			artificialLineBreak = new ArtificalLineBreak();
 319		}
 320		
 321		this.isBitmapFont = (font instanceof BitmapFont);
 322	}
 323	
 324	
 325	/**
 326	 * Sets the font.
 327	 * @param font the new font
 328	 */
 329	public void setFont(IFont font){
 330		if (this.characterList != null) {
 331		this.font = font;
 332		this.fontHeight = font.getFontAbsoluteHeight();
 333		this.isBitmapFont = (font instanceof BitmapFont);
 334		this.updateLayout();
 335		}
 336	}
 337
 338	
 339	@Override
 340	public void updateComponent(long timeDelta) {
 341		super.updateComponent(timeDelta);
 342		if (enableCaret){
 343			caretTimeCounter+=timeDelta;
 344			if (caretTimeCounter >= showCaretTime && !showCaret){
 345				showCaret 		 = true;
 346				caretTimeCounter = 0;
 347			}else if (caretTimeCounter >= showCaretTime && showCaret){
 348				showCaret 		 = false;
 349				caretTimeCounter = 0;
 350			}
 351		}
 352	}
 353	
 354	
 355	@Override
 356	public void preDraw(PGraphics graphics) {
 357		super.preDraw(graphics);
 358		
 359		//Hack for drawing anti aliased stroke outline over the clipped area
 360		noStrokeSettingSaved = this.isNoStroke();
 361		if (this.mode == MODE_WRAP && this.getClip() != null && !this.isNoStroke()){
 362			this.setNoStroke(true);	
 363		}
 364	}
 365	
 366	//FIXME TEST Align/round text with screen pixels
 367	private boolean textPositionRounding = true;
 368	private boolean snapVectorDirty = false;
 369	private Vector3D defaultScale = new Vector3D(1,1,1);
 370	private Vector3D globalTranslation = new Vector3D();
 371	private Vector3D rounded = new Vector3D();
 372	private float tolerance = 0.05f;
 373	private boolean isBitmapFont = false;
 374	private Vector3D diff = new Vector3D(0,0,0);
 375	
 376	public void setTextPositionRounding(boolean snap){
 377		this.textPositionRounding = snap;
 378	}
 379	
 380	public boolean isTextPositionRounding(){
 381		return this.textPositionRounding;
 382	}
 383	
 384	@Override
 385	public void setMatricesDirty(boolean baseMatrixDirty) {
 386		super.setMatricesDirty(baseMatrixDirty);
 387		if (baseMatrixDirty)
 388			snapVectorDirty = baseMatrixDirty;
 389	}
 390	
 391	
 392	private boolean useDisplayList = false;
 393	private boolean contentDisplayListDirty = true;
 394	private void setContentDisplayListDirty(boolean dirty){
 395		this.contentDisplayListDirty = dirty;
 396		this.useDisplayList = (!this.contentDisplayListDirty);
 397	}
 398	private int displayListID = 0;
 399	
 400	public int useContentDisplayList(){
 401		if (enableCaret)
 402			return -1;
 403		
 404		GL gl = GLU.getCurrentGL();
 405		//Delete old one
 406		if (this.displayListID != 0){
 407			gl.glDeleteLists(this.displayListID, 1);
 408		}
 409		
 410		//Create new list
 411		int listIDFill = gl.glGenLists(1);
 412		if (listIDFill == 0){
 413			System.err.println("Failed to create fill display list");
 414		}
 415		
 416		int thisLineTotalXAdvancement = 0;
 417		int lastXAdvancement = innerPaddingLeft;
 418		//To set caret at most left start pos when charlist empty (looks better)
 419		if (enableCaret && showCaret && characterList.size() == 1){
 420			lastXAdvancement = 0;
 421		}
 422		
 423		//Record list
 424		gl.glNewList(listIDFill, GL.GL_COMPILE);
 425			drawCharactersGL(gl, characterList, characterList.size(), lastXAdvancement, thisLineTotalXAdvancement);
 426		gl.glEndList();
 427		
 428		if (listIDFill != 0){
 429			useDisplayList = true;
 430			displayListID = listIDFill;
 431		}
 432
 433		this.setContentDisplayListDirty(false);
 434		return (listIDFill == 0)?  -1 : listIDFill;
 435	}
 436	
 437	
 438	@Override
 439		protected void destroyComponent() {
 440			super.destroyComponent();
 441			
 442			if (MT4jSettings.getInstance().isOpenGlMode() && this.displayListID != 0){
 443				GL gl = GLU.getCurrentGL();
 444				//Delete old one
 445				if (gl != null){
 446					gl.glDeleteLists(this.displayListID, 1);
 447				}
 448			}
 449		}
 450	
 451	@Override
 452	public void drawComponent(PGraphics g) {
 453		super.drawComponent(g);
 454		
 455		//FIXME snapping wont be useful if textarea is created at non-integer value!? and if Camera isnt default camera
 456		//if global matrix set dirty and comp not scaled -> calculate new diff vector -> apply
 457		//if snap enabled -> apply diff vector
 458		boolean applySnap = false;
 459		if (isBitmapFont && textPositionRounding){
 460			if (snapVectorDirty){ //Calc new snap vector
 461				Matrix m = this.getGlobalMatrix();
 462				if (m.getScale().equalsVectorWithTolerance(defaultScale, tolerance)){ //Only if no scale applied
 463					applySnap = true;
 464					globalTranslation.setXYZ(m.m03, m.m13, m.m23);
 465					rounded.setXYZ(Math.round(globalTranslation.x), Math.round(globalTranslation.y), Math.round(globalTranslation.z));
 466//					rounded.setXYZ((int)globalTranslation.x, (int)globalTranslation.y, (int)globalTranslation.z);
 467					rounded.subtractLocal(globalTranslation);
 468					
 469					diff.setXYZ(rounded.x, rounded.y, rounded.z);
 470					snapVectorDirty = false;
 471					
 472					g.pushMatrix();
 473					g.translate(diff.x, diff.y, diff.z);
 474				}else{ //global matrix was set dirty but the textarea is scaled -> dont apply snapvector because it gets blurry anyway if scaled
 475//					snapVectorDirty = false; //because only if scale changes back to 1,1,1 we have to calc new snapvector again
 476					applySnap = false;
 477				}
 478			}else{ //new Snap vector already calculated since global matrix was changed 
 479				applySnap = true;
 480				g.pushMatrix();
 481				g.translate(diff.x, diff.y, diff.z);
 482			}
 483		}
 484		
 485		//Add caret if its time 
 486		if (enableCaret && showCaret){
 487			characterList.add(this.getFont().getFontCharacterByUnicode("|"));
 488		}
 489		
 490		int charListSize = characterList.size();
 491		int thisLineTotalXAdvancement = 0;
 492		int lastXAdvancement = innerPaddingLeft;
 493
 494		//Account for TOP inner padding if using WRAP mode -> translate text
 495		switch (this.mode) {
 496		case MODE_EXPAND:
 497			//Dont need to translate for innerpadding TOP because we do that in setHeight() making the whole textarea bigger
 498			g.pushMatrix(); 
 499			g.translate(0, innerPaddingTop);
 500			break;
 501		case MODE_WRAP:
 502			//Need to translate innerpadding TOP because we shouldnt make the textarea bigger like in expand mode
 503			g.pushMatrix();
 504			g.translate(0, innerPaddingTop);
 505			break;
 506		default:
 507			break;
 508		}
 509		
 510//		/*//
 511		//To set caret at most left start pos when charlist empty (looks better)
 512		if (enableCaret && showCaret && charListSize == 1){
 513			lastXAdvancement = 0;
 514		}
 515//		*/
 516		
 517		if (this.isUseDirectGL()){
 518			GL gl = Tools3D.beginGL(pa);
 519			if (totalScrollTextX != 0.0f || totalScrollTextY != 0.0f){
 520				gl.glTranslatef(totalScrollTextX, totalScrollTextY + font.getFontMaxAscent(), 0);
 521			}else{
 522				gl.glTranslatef(0, font.getFontMaxAscent(), 0);
 523			}
 524			
 525			/*
 526			//Disabled so that no new list is created everytime something changes
 527			if (!enableCaret && useDisplayList && this.contentDisplayListDirty){
 528				//Re-Create displaylist
 529				this.useContentDisplayList();
 530			}
 531			*/
 532			
 533			//TODO avoid many stateChanges
 534			//in bitmap font mode for example:
 535			//enable textures, enable vertex arrays and color only once!
 536			
 537			if(!enableCaret && useDisplayList && this.displayListID != 0){
 538				gl.glCallList(this.displayListID);
 539			}else{
 540				drawCharactersGL(gl, characterList, charListSize, lastXAdvancement, thisLineTotalXAdvancement);
 541			}
 542			
 543			Tools3D.endGL(pa);
 544		}
 545		else{ //P3D rendering
 546			g.pushMatrix(); //FIXME TEST text scrolling - but IMHO better done with parent list/scroll container
 547			g.translate(totalScrollTextX, totalScrollTextY + font.getFontMaxAscent(), 0);
 548			
 549			//Set the color for all characters (since the characters dont set their own fill/stroke color anymore
 550			MTColor fillColor = this.getFont().getFillColor();
 551			g.fill(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha());
 552			g.stroke(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha());
 553			g.tint(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha()); 
 554			
 555			for (int i = 0; i < charListSize; i++) {
 556				IFontCharacter character = characterList.get(i);
 557				//Step to the right by the amount of the last characters x advancement
 558				pa.translate(lastXAdvancement, 0, 0); //original
 559				//Save total amount gone to the right in this line
 560				thisLineTotalXAdvancement += lastXAdvancement;
 561				lastXAdvancement = 0;
 562				
 563				//Draw the letter
 564				character.drawComponent(g);
 565				
 566				//Check if newLine occurs, goto start at new line
 567				if (character.getUnicode().equals("\n")){
 568					pa.translate(-thisLineTotalXAdvancement, fontHeight, 0);
 569					thisLineTotalXAdvancement = 0;
 570					lastXAdvancement = innerPaddingLeft;
 571				}else{
 572					//If caret is showing and we are at index one before caret calc the advancement
 573					if (enableCaret && showCaret && i == charListSize - 2){
 574						if (character.getUnicode().equals("\t")){
 575							lastXAdvancement = character.getHorizontalDist() - character.getHorizontalDist( ) / 20;
 576						}else{
 577							//approximated value, cant get the real one
 578							lastXAdvancement = 2 + character.getHorizontalDist() - (character.getHorizontalDist() / 3);
 579						}
 580					}else{
 581						lastXAdvancement = character.getHorizontalDist();
 582					}
 583				}
 584			}
 585			
 586			g.tint(255,255,255,255); //Reset Tint
 587			
 588			g.popMatrix();//FIXME TEST text scrolling - but IMHO better done with parent list/scroll container
 589		}
 590		
 591		//Innerpadding TOP for wrapped textarea -> translates the text content downwards
 592		switch (this.mode) {
 593		case MODE_EXPAND:
 594			g.popMatrix();
 595			break;
 596		case MODE_WRAP:
 597			//Need to translate innerpadding because we shouldnt make the textarea bigger
 598			g.popMatrix();
 599			break;
 600		default:
 601			break;
 602		}
 603		
 604		//remove caret
 605		if (enableCaret && showCaret){
 606			characterList.remove(charListSize-1);
 607		}
 608		
 609		//FIXME TEST
 610		if (isBitmapFont && textPositionRounding && applySnap){
 611			g.popMatrix();
 612		}
 613	}
 614	
 615	
 616	public void setFontColor(MTColor fontColor){
 617		this.getFont().setFillColor(fontColor);
 618	}
 619	
 620	private void drawCharactersGL(GL gl, List<IFontCharacter> characterList, int charListSize, int lastXAdv, int lineTotalAdv){
 621		int lastXAdvancement = lastXAdv;
 622		int thisLineTotalXAdvancement = lineTotalAdv;
 623		
 624		//Set the color for all characters (since the characters dont set their own fill/stroke color anymore
 625		MTColor fillColor = this.getFont().getFillColor();
 626		gl.glColor4f(fillColor.getR()/255f, fillColor.getG()/255f, fillColor.getB()/255f, fillColor.getAlpha()/255f); 
 627		
 628		for (int i = 0; i < charListSize; i++) {
 629			IFontCharacter character = characterList.get(i);
 630			//Step to the right by the amount of the last characters x advancement
 631			gl.glTranslatef(lastXAdvancement, 0, 0);
 632			//Save total amount gone to the right in this line 
 633			thisLineTotalXAdvancement += lastXAdvancement;
 634			lastXAdvancement = 0;
 635
 636			//Draw the letter
 637			character.drawComponent(gl);
 638
 639			//Check if newLine occurs, goto start at new line
 640			if (character.getUnicode().equals("\n")){
 641				gl.glTranslatef(-thisLineTotalXAdvancement, fontHeight, 0);
 642				thisLineTotalXAdvancement = 0;
 643				lastXAdvancement = innerPaddingLeft;
 644			}else{
 645				//If caret is showing and we are at index one before caret calc the advancement to include the caret in the text area
 646				if (enableCaret && showCaret && i == charListSize-2){
 647					if (character.getUnicode().equals("\t")){
 648						lastXAdvancement = character.getHorizontalDist() - character.getHorizontalDist() / 20;
 649					}else{
 650						//approximated value, cant get the real one
 651						lastXAdvancement = 2 + character.getHorizontalDist() - (character.getHorizontalDist() / 3);
 652					}
 653				}else{
 654					lastXAdvancement = character.getHorizontalDist();
 655				}
 656			}
 657		}
 658	}
 659	
 660	private boolean noStrokeSettingSaved;
 661	
 662	@Override
 663	public void postDraw(PGraphics graphics) {
 664		super.postDraw(graphics);
 665		//Hack for drawing anti aliased stroke outline over the clipped area
 666		if (this.mode == MODE_WRAP && this.getClip()!= null && !noStrokeSettingSaved){
 667			this.setNoStroke(noStrokeSettingSaved);
 668			boolean noFillSavedSetting = this.isNoFill();
 669			this.setNoFill(true);
 670			super.drawComponent(graphics);//Draw only stroke line after we ended clipping do preserve anti aliasing - hack
 671			this.setNoFill(noFillSavedSetting);
 672		}
 673	}
 674	
 675	//FIXME TEST scrolling (used in MTTextField for example)
 676	protected void scrollTextX(float amount){
 677		this.totalScrollTextX += amount;
 678	}
 679	protected void scrollTextY(float amount){
 680		this.totalScrollTextY += amount;
 681	}
 682	protected float getScrollTextX() {
 683		return this.totalScrollTextX;
 684	}
 685	protected float getScrollTextY() {
 686		return this.totalScrollTextY;
 687	}
 688	
 689	
 690	//FIXME TEST ?
 691	/**
 692	 * Changes the texture filtering for the textarea's bitmap font.
 693	 * (if a bitmap font is used).
 694	 * If the parameter is "true" this will allow the text being scaled without getting
 695	 * too pixelated. If the text isnt going to be scaled ever, it is best to leave or
 696	 * set this to "false" for a sharper text.
 697	 * <br>NOTE: Only applies if OpenGL is the renderer and the textarea uses a bitmap font.
 698	 * <br>NOTE: This affects the whole bitmap font so if it is used elsewhere it is changed 
 699	 * there, too.
 700	 * 
 701	 * @param scalable the new bitmap font scalable
 702	 */
 703	public void setBitmapFontTextureFiltered(boolean scalable){
 704		if (MT4jSettings.getInstance().isOpenGlMode() && this.getFont() instanceof BitmapFont){
 705			BitmapFont font = (BitmapFont)this.getFont();
 706			IFontCharacter[] characters = font.getCharacters();
 707            for (IFontCharacter fontCharacter : characters) {
 708                if (fontCharacter instanceof BitmapFontCharacter) {
 709                    BitmapFontCharacter bChar = (BitmapFontCharacter) fontCharacter;
 710                    bChar.setTextureFiltered(scalable);
 711                }
 712            }
 713		}
 714	}
 715	
 716	
 717	
 718	/**
 719	 * Sets the width local.
 720	 * 
 721	 * @param width the new width local
 722	 */
 723	@Override
 724	public void setWidthLocal(float width){
 725		super.setWidthLocal(width);
 726		switch (this.mode) {
 727		case MODE_EXPAND:
 728			
 729			break;
 730		case MODE_WRAP:
 731			//if in MODE_WRAP also reset the size of the CLIP SHAPE!
 732			if (MT4jSettings.getInstance().isOpenGlMode() && this.getClip() != null && this.getClip().getClipShape() instanceof MTRectangle){ 
 733				MTRectangle clipRect = (MTRectangle)this.getClip().getClipShape();
 734				//				clipRect.setWidthLocal(this.getWidthXY(TransformSpace.LOCAL));
 735				//Clip the text to the area
 736				//				this.setClip(new Clip(pApplet, this.getVerticesLocal()[0].x, this.getVerticesLocal()[0].y, this.getWidthXY(TransformSpace.LOCAL), this.getHeightXY(TransformSpace.LOCAL)));
 737				//				clipRect.setVertices(Vertex.getDeepVertexArrayCopy(this.getVerticesLocal()));
 738				clipRect.setVertices(this.getVerticesLocal());
 739			}
 740			this.updateLayout();
 741			break;
 742		default:
 743			break;
 744		}
 745	}
 746	/**
 747	 * Sets the height local.
 748	 * 
 749	 * @param height the new height local
 750	 */
 751	@Override
 752	public void setHeightLocal(float height){ 
 753		Vertex[] v = this.getVerticesLocal();
 754		switch (this.mode) {
 755		case MODE_EXPAND:
 756			this.setVertices(new Vertex[]{
 757					new Vertex(v[0].x,	0, 								v[0].z, v[0].getTexCoordU(), v[0].getTexCoordV(), v[0].getR(), v[0].getG(), v[0].getB(), v[0].getA()), 
 758					new Vertex(v[1].x, 	0, 								v[1].z, v[1].getTexCoordU(), v[1].getTexCoordV(), v[1].getR(), v[1].getG(), v[1].getB(), v[1].getA()), 
 759					new Vertex(v[2].x, 	height + (2 * innerPaddingTop), v[2].z, v[2].getTexCoordU(), v[2].getTexCoordV(), v[2].getR(), v[2].getG(), v[2].getB(), v[2].getA()), 
 760					new Vertex(v[3].x,	height + (2 * innerPaddingTop),	v[3].z, v[3].getTexCoordU(), v[3].getTexCoordV(), v[3].getR(), v[3].getG(), v[3].getB(), v[3].getA()), 
 761					new Vertex(v[4].x,	0,								v[4].z, v[4].getTexCoordU(), v[4].getTexCoordV(), v[4].getR(), v[4].getG(), v[4].getB(), v[4].getA()),
 762			});
 763			break;
 764		case MODE_WRAP:
 765			super.setHeightLocal(height);
 766			//if in MODE_WRAP also reset the size of the CLIP SHAPE!
 767			if (MT4jSettings.getInstance().isOpenGlMode() && this.getClip() != null && this.getClip().getClipShape() instanceof MTRectangle){ 
 768				MTRectangle clipRect = (MTRectangle)this.getClip().getClipShape();
 769				//				clipRect.setVertices(Vertex.getDeepVertexArrayCopy(this.getVerticesLocal()));
 770				clipRect.setVertices(this.getVerticesLocal());
 771			}
 772			this.updateLayout();
 773			break;
 774		default:
 775			break;
 776		}
 777	}
 778
 779    /**
 780     * Returns the currently active expand direction of the text area.
 781     * (Only has an impact if the wrap mode of the textarea equals MODE_EXPAND!)
 782     *
 783     * @return the active expand direction
 784     */
 785    public ExpandDirection getExpandDirection() {
 786        return expandDirection;
 787    }
 788
 789    /**
 790     * Sets the expand direction to be used by the text area if a new line is added.
 791     *(Only has an impact if the wrap mode of the textarea equals MODE_EXPAND!)
 792     * @see {@link ExpandDirection}
 793     * @param direction the expand direction to be used
 794     */
 795    public void setExpandDirection(ExpandDirection direction) {
 796        expandDirection = direction;
 797        this.updateLayout(); //This wont translate the area to its original place if expand mode was UP and is now down..
 798    }
 799
 800    @Override
 801	public void setSizeLocal(float width, float height) {
 802		if (width > 0 && height > 0){
 803			Vertex[] v = this.getVerticesLocal();
 804			switch (this.mode) {
 805			case MODE_EXPAND:
 806				this.setVertices(new Vertex[]{
 807						new Vertex(v[0].x,			0, 								v[0].z, v[0].getTexCoordU(), v[0].getTexCoordV(), v[0].getR(), v[0].getG(), v[0].getB(), v[0].getA()), 
 808						new Vertex(v[0].x+width, 	0, 								v[1].z, v[1].getTexCoordU(), v[1].getTexCoordV(), v[1].getR(), v[1].getG(), v[1].getB(), v[1].getA()), 
 809						new Vertex(v[0].x+width, 	height + (2 * innerPaddingTop), v[2].getTexCoordV(), v[2].getR(), v[2].getG(), v[2].getB(), v[2].getA()), 
 810						new Vertex(v[3].x,			height + (2 * innerPaddingTop),	v[3].z, v[3].getTexCoordU(), v[3].getTexCoordV(), v[3].getR(), v[3].getG(), v[3].getB(), v[3].getA()), 
 811						new Vertex(v[4].x,			0,								v[4].z, v[4].getTexCoordU(), v[4].getTexCoordV(), v[4].getR(), v[4].getG(), v[4].getB(), v[4].getA()), 
 812				});
 813				break;
 814			case MODE_WRAP:
 815				super.setSizeLocal(width, height);
 816				//if in MODE_WRAP also reset the size of the CLIP SHAPE!
 817				if (MT4jSettings.getInstance().isOpenGlMode() && this.getClip() != null && this.getClip().getClipShape() instanceof MTRectangle){ 
 818					MTRectangle clipRect = (MTRectangle)this.getClip().getClipShape();
 819					//clipRect.setVertices(Vertex.getDeepVertexArrayCopy(this.getVerticesLocal()));
 820					clipRect.setVertices(this.getVerticesLocal());
 821				}
 822				this.updateLayout();
 823				break;
 824			default:
 825				break;
 826			}
 827		}
 828	}
 829	
 830	
 831	/**
 832	 * Appends the string to the textarea.
 833	 * 
 834	 * @param string the string
 835	 */
 836	synchronized public void appendText(String string){
 837		for (int i = 0; i < string.length(); i++) {
 838			appendCharByUnicode(string.substring(i, i+1));
 839		}
 840	}
 841	
 842	/**
 843	 * Sets the provided string as the text of this textarea.
 844	 * 
 845	 * @param string the string
 846	 */
 847	synchronized public void setText(String string){
 848		clear();
 849		for (int i = 0; i < string.length(); i++) {
 850			appendCharByUnicode(string.substring(i, i+1));
 851		}
 852		
 853		//FIXME TEST
 854		/*
 855		if (MT4jSettings.getInstance().isOpenGlMode()){
 856			if (getRenderer() instanceof MTApplication) {
 857				MTApplication app = (MTApplication) getRenderer();
 858				if (app.isRenderThreadCurrent()){
 859					this.useContentDisplayList();
 860				}else{
 861					app.invokeLater(new Runnable() {
 862						public void run() {
 863							useContentDisplayList();
 864						}
 865					});
 866				}
 867			}else{
 868				this.useContentDisplayList();
 869			}
 870		}
 871		*/
 872	}
 873	
 874	
 875	/* (non-Javadoc)
 876	 * @see org.mt4j.components.visibleComponents.widgets.keyboard.ITextInputListener#getText()
 877	 */
 878	public String getText(){
 879		String returnString = "";
 880        for (IFontCharacter character : this.characterList) {
 881            String unicode = character.getUnicode();
 882            if (!character.equals(MTTextArea.artificialLineBreak)) {
 883                returnString += unicode;
 884            }
 885        }
 886		return returnString;
 887	}
 888	
 889	
 890	/**
 891	 * Append char by name.
 892	 * @param characterName the character name
 893	 */
 894	synchronized public void appendCharByName(String characterName){
 895		//Get the character from the font
 896		IFontCharacter character = font.getFontCharacterByName(characterName);
 897		if (character == null){
 898			System.err.println("Error adding character with name '" + characterName + "' to the textarea. The font couldnt find the character. -> Trying to use 'missing glyph'");
 899			character = font.getFontCharacterByName("missing-glyph");
 900			if (character != null)
 901				addCharacter(character);
 902		}else{
 903			addCharacter(character);
 904		}
 905	}
 906	
 907	
 908	
 909	/* (non-Javadoc)
 910	 * @see org.mt4j.components.visibleComponents.widgets.keyboard.ITextInputListener#appendCharByUnicode(java.lang.String)
 911	 */
 912	synchronized public void appendCharByUnicode(String unicode){
 913		//Get the character from the font
 914		IFontCharacter character = font.getFontCharacterByUnicode(unicode);
 915		if (character == null){
 916//			System.err.println("Error adding character with unicode '" + unicode + "' to the textarea. The font couldnt find the character. ->Trying to use 'missing glyph'");
 917			character = font.getFontCharacterByUnicode("missing-glyph");
 918			if (character != null)
 919				addCharacter(character);
 920		}else{
 921			addCharacter(character);
 922		}
 923	}
 924	
 925	
 926	/**
 927	 * Gets the characters. Also returns articifially added new line characters that were
 928	 * added by the MTTextArea
 929	 * @return the characters
 930	 */
 931	public IFontCharacter[] getCharacters(){
 932		return this.characterList.toArray(new IFontCharacter[this.characterList.size()]);
 933	}
 934	
 935	
 936	/**
 937	 * Adds the character.
 938	 * 
 939	 * @param character the character
 940	 */
 941	private void addCharacter(IFontCharacter character){
 942		this.characterList.add(character);
 943		
 944		this.characterAdded(character);
 945		
 946		this.setContentDisplayListDirty(true);
 947	}
 948	
 949	/**
 950	 * Invoked everytime a character is added.
 951	 *
 952	 * @param character the character
 953	 */
 954	protected void characterAdded(IFontCharacter character){
 955		switch (this.mode) {
 956		case MODE_EXPAND:
 957			if (character.getUnicode().equals("\n")){
 958				//Expand vertically at enter 
 959				this.setHeightLocal(this.getTotalLinesHeight());
 960				//Moves the Textarea up at a enter character instead of down
 961                if (getExpandDirection() == ExpandDirection.UP)
 962                    this.translate(new Vector3D(0, -fontHeight, 0));
 963            }else{
 964				//Expand the textbox to the extend of the widest line width
 965				this.setWidthLocal(getMaxLineWidth());
 966			}
 967			break;
 968		case MODE_WRAP:
 969			float localWidth = this.getWidthXY(TransformSpace.LOCAL);
 970//			float maxLineWidth = this.getMaxLineWidth(); 
 971			float maxLineWidth = this.getLastLineWidth();
 972			
 973			if (this.characterList.size() > 0 && maxLineWidth > localWidth ) {
 974//			if (this.characterList.size() > 0 && maxLineWidth > (localWidth - 2 * this.getInnerPaddingLeft())) {
 975//				this.characterList.add(this.characterList.size() -1 , this.font.getFontCharacterByUnicode("\n"));
 976				try {
 977					int lastSpacePos = getLastWhiteSpace();
 978					if (lastSpacePos != -1 ){ //&& !this.characterList.get(characterList.size()-1).getUnicode().equals("\n")
 979//						this.characterList.add(lastSpacePos + 1, this.font.getFontCharacterByUnicode("\n"));
 980						this.characterList.add(lastSpacePos + 1, MTTextArea.artificialLineBreak);
 981					}else{
 982						return;
 983					}
 984				} catch (Exception e) {
 985					e.printStackTrace();
 986				}
 987			}
 988			break;
 989		default:
 990			break;
 991		}
 992	}
 993	
 994	
 995	private int getLastWhiteSpace(){
 996		for (int i = this.characterList.size()-1; i > 0; i--) {
 997			IFontCharacter character = this.characterList.get(i);
 998			if (character.getUnicode().equals(" ")){
 999				return i;
1000			}else if (character.getUnicode().equals("\n")){// stop search when newline found before first whitespace
1001				return -1;
1002			}
1003		}
1004		return -1;
1005	}
1006	
1007	
1008	/**
1009	 * When Character removed.
1010	 *
1011	 * @param character the character
1012	 */
1013	protected void characterRemoved(IFontCharacter character){
1014		switch (this.mode) {
1015		case MODE_EXPAND:
1016			//Resize text field
1017			if (character.getUnicode().equals("\n")){
1018				//Reduce field vertically at enter
1019				this.setHeightLocal(this.getTotalLinesHeight());
1020				//makes the textarea go down when a line is removed instead staying at the same loc.
1021				if (getExpandDirection() == ExpandDirection.UP)
1022                    translate(new Vector3D(0, fontHeight, 0));
1023			}else{
1024				//Reduce field horizontally
1025				this.setWidthLocal(getMaxLineWidth());
1026			}
1027			break;
1028		case MODE_WRAP:
1029			
1030			break;
1031		default:
1032			break;
1033		}
1034	}
1035	
1036	
1037	
1038	/**
1039	 * resets the textarea, clears all characters.
1040	 */
1041	public void clear(){
1042		while (!characterList.isEmpty()){
1043			removeLastCharacter();
1044		}
1045	}
1046	
1047	
1048	/**
1049	 * Removes the last character in the textarea.
1050	 */
1051	synchronized public void removeLastCharacter(){
1052		if (this.characterList.isEmpty())
1053			return;
1054		
1055		//REMOVE THE CHARACTER
1056		IFontCharacter lastCharacter = this.characterList.get(this.characterList.size()-1);
1057		this.characterList.remove(this.characterList.size()-1);
1058		
1059		this.characterRemoved(lastCharacter);
1060		
1061		this.setContentDisplayListDirty(true);
1062	}
1063	
1064	
1065	/**
1066	 * Gets the last line width.
1067	 *
1068	 * @return the last line width
1069	 */
1070	protected float getLastLineWidth(){
1071		float currentLineWidth = 2 * this.getInnerPaddingLeft() + caretWidth;
1072        for (IFontCharacter character : this.characterList) {
1073            if (character.getUnicode().equals("\n")) {
1074                currentLineWidth = 2 * this.getInnerPaddingLeft() + caretWidth;
1075            } else {
1076                currentLineWidth += character.getHorizontalDist();
1077            }
1078        }
1079		return currentLineWidth;
1080	}
1081	
1082	
1083	/**
1084	 * Gets the max line width. The padding is also added.
1085	 * 
1086	 * @return the max line width
1087	 */
1088	protected float getMaxLineWidth(){
1089		float currentLineWidth = 2 * this.getInnerPaddingLeft() + caretWidth;
1090		float maxWidth = currentLineWidth;
1091
1092        for (IFontCharacter character : this.characterList) {
1093            if (character.getUnicode().equals("\n")) {
1094                if (currentLineWidth > maxWidth) {
1095                    maxWidth = currentLineWidth;
1096                }
1097                currentLineWidth = 2 * this.getInnerPaddingLeft() + caretWidth;
1098            } else {
1099                currentLineWidth += character.getHorizontalDist();
1100                if (currentLineWidth > maxWidth) {
1101                    maxWidth = currentLineWidth;
1102                }
1103            }
1104        }
1105		return maxWidth;
1106	}
1107
1108	
1109	/**
1110	 * Gets the total lines height. Padding is not included
1111	 * 
1112	 * @return the total lines height
1113	 */
1114	protected float getTotalLinesHeight(){
1115		float height = fontHeight ;//
1116        for (IFontCharacter character : this.characterList) {
1117            if (character.getUnicode().equals("\n")) {
1118                height += fontHeight;
1119            }
1120        }
1121		return height;
1122	}
1123	
1124	
1125	/**
1126	 * Sets the padding (Top: 5 + value, Left: 8 + value)
1127	 * @param padding
1128	 */
1129	
1130	public void setPadding(float padding) {
1131		innerPaddingTop = 5 + (int)padding;
1132		innerPaddingLeft = 8 + (int)padding;
1133		this.updateLayout();
1134	}
1135	
1136	
1137	public void setInnerPadding(int innerPadding){
1138		this.setInnerPaddingTop(innerPadding);
1139		this.setInnerPaddingLeft(innerPadding);
1140	}
1141
1142	public float getInnerPaddingTop() {
1143		return this.innerPaddingTop;
1144	}
1145
1146	public void setInnerPaddingTop(int innerPaddingTop) {
1147		this.innerPaddingTop = innerPaddingTop;
1148		switch (this.mode) {
1149		case MODE_EXPAND:
1150			//At MODE_EXPAND we re-set the text so the size gets re-calculated
1151			//We can safely do this since in EXPAND mode we didnt add any artificial control characters
1152			this.updateLayout();
1153			break;
1154		case MODE_WRAP:
1155			//At MODE_WRAP the padding is done with gl_Translate calls so we dont have to reset the size
1156			//TODO also reset? this.setText(this.getText());?
1157			break;
1158		default:
1159			break;
1160		}
1161	}
1162
1163	public float getInnerPaddingLeft() {
1164		return this.innerPaddingLeft;
1165	}
1166
1167	public void setInnerPaddingLeft(int innerPaddingLeft) {
1168		this.innerPaddingLeft = innerPaddingLeft;
1169		switch (this.mode) {
1170		case MODE_EXPAND:
1171			//At MODE_EXPAND we re-set the text so the size gets re-calculated
1172			//We can safely do this since in EXPAND mode we didnt add any artificial control characters
1173			this.updateLayout();
1174			break;
1175		case MODE_WRAP:
1176			// WE HAVE TO RESET THE ORIGINAL TEXT BECAUSE WE BREAK THE LINE AT DIFFERENT POSITIONS IF THE INNERPADDING IS CHANGED!
1177			this.updateLayout();
1178			break;
1179		default:
1180			break;
1181		}
1182	}
1183	
1184	/**
1185	 * Updates layout. (just does this.setText(this.getText()))
1186	 */
1187	protected void updateLayout(){
1188		if (this.mode == MODE_EXPAND){
1189			this.setHeightLocal(this.getTotalLinesHeight());
1190			this.setWidthLocal(getMaxLineWidth());
1191		}
1192		this.setText(this.getText());
1193	}
1194
1195
1196	/**
1197	 * Gets the line count.
1198	 * 
1199	 * @return the line count
1200	 */
1201	public int getLineCount(){
1202		int count = 0;
1203        for (IFontCharacter character : this.characterList) {
1204            if (character.getUnicode().equals("\n")) {
1205                count++;
1206            }
1207        }
1208		return count;
1209	}
1210	
1211	
1212	
1213	/**
1214	 * Gets the font.
1215	 * 
1216	 * @return the font
1217	 */
1218	public IFont getFont() {
1219		return font;
1220	}
1221
1222	/**
1223	 * Snap to keyboard.
1224	 * 
1225	 * @param mtKeyboard the mt keyboard
1226	 */
1227	public void snapToKeyboard(MTKeyboard mtKeyboard){
1228		//OLD WAY
1229//		this.translate(new Vector3D(30, -(getFont().getFontAbsoluteHeight() * (getLineCount())) + getFont().getFontMaxDescent() - borderHeight, 0));
1230		mtKeyboard.addChild(this);
1231		this.setPositionRelativeToParent(new Vector3D(40, -this.getHeightXY(TransformSpace.LOCAL)*0.5f));
1232	}
1233
1234
1235	public boolean isSelected() {
1236		// TODO Auto-generated method stub
1237		return false;
1238	}
1239
1240	public void setSelected(boolean selected) {
1241		// TODO Auto-generated method stub
1242	}
1243
1244
1245	/**
1246	 * Checks if is enable caret.
1247	 * 
1248	 * @return true, if is enable caret
1249	 */
1250	public boolean isEnableCaret() {
1251		return enableCaret;
1252	}
1253
1254
1255	/**
1256	 * Sets the enable caret.
1257	 * 
1258	 * @param enableCaret the new enable caret
1259	 */
1260	public void setEnableCaret(boolean enableCaret) {
1261		if (this.getFont().getFontCharacterByUnicode("|") != null){
1262			this.enableCaret = enableCaret;
1263			
1264			if (enableCaret){
1265				this.caretWidth = 10;
1266			}else{
1267				this.caretWidth = 0;
1268			}
1269			
1270			if (this.mode == MODE_EXPAND){
1271				this.setWidthLocal(this.getMaxLineWidth());
1272			}
1273		}else{
1274			System.err.println("Cant enable caret for this textfield, the font doesent include the letter '|'");
1275		}
1276		
1277		this.setContentDisplayListDirty(true);
1278	}
1279
1280
1281	public int compareTo(Object o) {
1282		if (o instanceof MTTextArea) {
1283			MTTextArea ta = (MTTextArea)o;
1284			return this.getText().compareToIgnoreCase(ta.getText());
1285		} else {
1286			return 0;
1287		}
1288	}
1289	
1290	
1291	
1292	/**
1293	 * Artifical line break to be used instead of the regular line break
1294	 * to indicate that this linebreak was added by the text area itself for
1295	 * layout reasons and doesent really belong to the supplied text.
1296	 * 
1297	 * @author Christopher Ruff
1298	 */
1299	protected class ArtificalLineBreak implements IFontCharacter{
1300		public void drawComponent(PGraphics g) {}
1301		public void drawComponent(GL gl) {	}
1302		public void destroy() {	}
1303		public int getHorizontalDist() {
1304			return 0;
1305		}
1306		public String getUnicode() {
1307			return "\n";
1308		}
1309		
1310	}
1311	
1312	
1313	@Override
1314	protected void applyStyleSheetCustom(CSSStyle virtualStyleSheet) {
1315		super.applyStyleSheetCustom(virtualStyleSheet);
1316
1317		if (this.getRenderer() instanceof MTApplication) {
1318			MTApplication app = (MTApplication) this.getRenderer();
1319			if (!virtualStyleSheet.getFont().equals(
1320					app.getCssStyleManager().getDefaultFont(app))
1321					&& !this.isIgnoreCSSFont()) {
1322				this.setFont(virtualStyleSheet.getFont());
1323			}
1324			if (virtualStyleSheet.isModifiedPaddingWidth()) {
1325				this.setPadding(virtualStyleSheet.getPaddingWidth());
1326			}
1327		}
1328	}
1329
1330	
1331}