View Javadoc

    1   /*
    2    * TextAreaPainter.java - Paints the text area
    3    * Copyright (C) 1999 Slava Pestov
    4    *
    5    * 08/05/2002	Cursor (caret) rendering fixed for JDK 1.4 (Anonymous)
    6    *
    7    * You may use and modify this package for any purpose. Redistribution is
    8    * permitted, in both source and binary form, provided that this notice
    9    * remains intact in all source distributions of this package.
    10   */
    11
    12  package org.syntax.jedit;
    13
    14  import java.awt.Color;
    15  import java.awt.Cursor;
    16  import java.awt.Dimension;
    17  import java.awt.Font;
    18  import java.awt.FontMetrics;
    19  import java.awt.Graphics;
    20  import java.awt.Rectangle;
    21  import java.awt.Toolkit;
    22  import java.awt.event.MouseEvent;
    23
    24  import javax.swing.JComponent;
    25  import javax.swing.ToolTipManager;
    26  import javax.swing.text.PlainDocument;
    27  import javax.swing.text.Segment;
    28  import javax.swing.text.TabExpander;
    29  import javax.swing.text.Utilities;
    30
    31  import org.syntax.jedit.tokenmarker.Token;
    32  import org.syntax.jedit.tokenmarker.TokenMarker;
    33
    34  import com.eviware.soapui.SoapUI;
    35
    36  /***
    37   * The text area repaint manager. It performs double buffering and paints
    38   * lines of text.
    39   * @author Slava Pestov
    40   * @version $Id$
    41   */
    42  public class TextAreaPainter extends JComponent implements TabExpander
    43  {
    44  	private int areaWidth;
    45  	private int areaHeight;
    46
    47  	/***
    48  	 * Creates a new repaint manager. This should be not be called
    49  	 * directly.
    50  	 */
    51  	public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
    52  	{
    53  		this.textArea = textArea;
    54
    55  		setAutoscrolls(true);
    56  		setDoubleBuffered(true);
    57  		setOpaque(true);
    58  		setBorder( null );
    59
    60  		ToolTipManager.sharedInstance().registerComponent(this);
    61
    62  		currentLine = new Segment();
    63  		currentLineIndex = -1;
    64
    65  		setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
    66
    67  		setFont(new Font("Monospaced",Font.PLAIN,14));
    68  		setForeground(Color.black);
    69  		setBackground(Color.white);
    70
    71  		blockCaret = defaults.blockCaret;
    72  		styles = defaults.styles;
    73  		//cols = defaults.cols;
    74  		//rows = defaults.rows;
    75  		caretColor = defaults.caretColor;
    76  		selectionColor = defaults.selectionColor;
    77  		lineHighlightColor = defaults.lineHighlightColor;
    78  		lineHighlight = defaults.lineHighlight;
    79  		bracketHighlightColor = defaults.bracketHighlightColor;
    80  		bracketHighlight = defaults.bracketHighlight;
    81  		paintInvalid = defaults.paintInvalid;
    82  		eolMarkerColor = defaults.eolMarkerColor;
    83  		eolMarkers = defaults.eolMarkers;
    84  	}
    85
    86  	/***
    87  	 * Returns if this component can be traversed by pressing the
    88  	 * Tab key. This returns false.
    89  	 */
    90  	public final boolean isManagingFocus()
    91  	{
    92  		return false;
    93  	}
    94
    95  	/***
    96  	 * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
    97  	 * will be used to paint tokens with id = <i>n</i>.
    98  	 * @see org.syntax.jedit.Token
    99  	 */
    100 	public final SyntaxStyle[] getStyles()
    101 	{
    102 		return styles;
    103 	}
    104
    105 	/***
    106 	 * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
    107 	 * will be used to paint tokens with id = <i>n</i>.
    108 	 * @param styles The syntax styles
    109 	 * @see org.syntax.jedit.Token
    110 	 */
    111 	public final void setStyles(SyntaxStyle[] styles)
    112 	{
    113 		this.styles = styles;
    114 		repaint();
    115 	}
    116
    117 	/***
    118 	 * Returns the caret color.
    119 	 */
    120 	public final Color getCaretColor()
    121 	{
    122 		return caretColor;
    123 	}
    124
    125 	/***
    126 	 * Sets the caret color.
    127 	 * @param caretColor The caret color
    128 	 */
    129 	public final void setCaretColor(Color caretColor)
    130 	{
    131 		this.caretColor = caretColor;
    132 		invalidateSelectedLines();
    133 	}
    134
    135 	/***
    136 	 * Returns the selection color.
    137 	 */
    138 	public final Color getSelectionColor()
    139 	{
    140 		return selectionColor;
    141 	}
    142
    143 	/***
    144 	 * Sets the selection color.
    145 	 * @param selectionColor The selection color
    146 	 */
    147 	public final void setSelectionColor(Color selectionColor)
    148 	{
    149 		this.selectionColor = selectionColor;
    150 		invalidateSelectedLines();
    151 	}
    152
    153 	/***
    154 	 * Returns the line highlight color.
    155 	 */
    156 	public final Color getLineHighlightColor()
    157 	{
    158 		return lineHighlightColor;
    159 	}
    160
    161 	/***
    162 	 * Sets the line highlight color.
    163 	 * @param lineHighlightColor The line highlight color
    164 	 */
    165 	public final void setLineHighlightColor(Color lineHighlightColor)
    166 	{
    167 		this.lineHighlightColor = lineHighlightColor;
    168 		invalidateSelectedLines();
    169 	}
    170
    171 	/***
    172 	 * Returns true if line highlight is enabled, false otherwise.
    173 	 */
    174 	public final boolean isLineHighlightEnabled()
    175 	{
    176 		return lineHighlight;
    177 	}
    178
    179 	/***
    180 	 * Enables or disables current line highlighting.
    181 	 * @param lineHighlight True if current line highlight should be enabled,
    182 	 * false otherwise
    183 	 */
    184 	public final void setLineHighlightEnabled(boolean lineHighlight)
    185 	{
    186 		this.lineHighlight = lineHighlight;
    187 		invalidateSelectedLines();
    188 	}
    189
    190 	/***
    191 	 * Returns the bracket highlight color.
    192 	 */
    193 	public final Color getBracketHighlightColor()
    194 	{
    195 		return bracketHighlightColor;
    196 	}
    197
    198 	/***
    199 	 * Sets the bracket highlight color.
    200 	 * @param bracketHighlightColor The bracket highlight color
    201 	 */
    202 	public final void setBracketHighlightColor(Color bracketHighlightColor)
    203 	{
    204 		this.bracketHighlightColor = bracketHighlightColor;
    205 		invalidateLine(textArea.getBracketLine());
    206 	}
    207
    208 	/***
    209 	 * Returns true if bracket highlighting is enabled, false otherwise.
    210 	 * When bracket highlighting is enabled, the bracket matching the
    211 	 * one before the caret (if any) is highlighted.
    212 	 */
    213 	public final boolean isBracketHighlightEnabled()
    214 	{
    215 		return bracketHighlight;
    216 	}
    217
    218 	/***
    219 	 * Enables or disables bracket highlighting.
    220 	 * When bracket highlighting is enabled, the bracket matching the
    221 	 * one before the caret (if any) is highlighted.
    222 	 * @param bracketHighlight True if bracket highlighting should be
    223 	 * enabled, false otherwise
    224 	 */
    225 	public final void setBracketHighlightEnabled(boolean bracketHighlight)
    226 	{
    227 		this.bracketHighlight = bracketHighlight;
    228 		invalidateLine(textArea.getBracketLine());
    229 	}
    230
    231 	/***
    232 	 * Returns true if the caret should be drawn as a block, false otherwise.
    233 	 */
    234 	public final boolean isBlockCaretEnabled()
    235 	{
    236 		return blockCaret;
    237 	}
    238
    239 	/***
    240 	 * Sets if the caret should be drawn as a block, false otherwise.
    241 	 * @param blockCaret True if the caret should be drawn as a block,
    242 	 * false otherwise.
    243 	 */
    244 	public final void setBlockCaretEnabled(boolean blockCaret)
    245 	{
    246 		this.blockCaret = blockCaret;
    247 		invalidateSelectedLines();
    248 	}
    249
    250 	/***
    251 	 * Returns the EOL marker color.
    252 	 */
    253 	public final Color getEOLMarkerColor()
    254 	{
    255 		return eolMarkerColor;
    256 	}
    257
    258 	/***
    259 	 * Sets the EOL marker color.
    260 	 * @param eolMarkerColor The EOL marker color
    261 	 */
    262 	public final void setEOLMarkerColor(Color eolMarkerColor)
    263 	{
    264 		this.eolMarkerColor = eolMarkerColor;
    265 		repaint();
    266 	}
    267
    268 	/***
    269 	 * Returns true if EOL markers are drawn, false otherwise.
    270 	 */
    271 	public final boolean getEOLMarkersPainted()
    272 	{
    273 		return eolMarkers;
    274 	}
    275
    276 	/***
    277 	 * Sets if EOL markers are to be drawn.
    278 	 * @param eolMarkers True if EOL markers should be drawn, false otherwise
    279 	 */
    280 	public final void setEOLMarkersPainted(boolean eolMarkers)
    281 	{
    282 		this.eolMarkers = eolMarkers;
    283 		repaint();
    284 	}
    285
    286 	/***
    287 	 * Returns true if invalid lines are painted as red tildes (~),
    288 	 * false otherwise.
    289 	 */
    290 	public boolean getInvalidLinesPainted()
    291 	{
    292 		return paintInvalid;
    293 	}
    294
    295 	/***
    296 	 * Sets if invalid lines are to be painted as red tildes.
    297 	 * @param paintInvalid True if invalid lines should be drawn, false otherwise
    298 	 */
    299 	public void setInvalidLinesPainted(boolean paintInvalid)
    300 	{
    301 		this.paintInvalid = paintInvalid;
    302 	}
    303
    304 	/***
    305 	 * Adds a custom highlight painter.
    306 	 * @param highlight The highlight
    307 	 */
    308 	public void addCustomHighlight(Highlight highlight)
    309 	{
    310 		highlight.init(textArea,highlights);
    311 		highlights = highlight;
    312 	}
    313
    314 	/***
    315 	 * Highlight interface.
    316 	 */
    317 	public interface Highlight
    318 	{
    319 		/***
    320 		 * Called after the highlight painter has been added.
    321 		 * @param textArea The text area
    322 		 * @param next The painter this one should delegate to
    323 		 */
    324 		void init(JEditTextArea textArea, Highlight next);
    325
    326 		/***
    327 		 * This should paint the highlight and delgate to the
    328 		 * next highlight painter.
    329 		 * @param gfx The graphics context
    330 		 * @param line The line number
    331 		 * @param y The y co-ordinate of the line
    332 		 */
    333 		void paintHighlight(Graphics gfx, int line, int y);
    334
    335 		/***
    336 		 * Returns the tool tip to display at the specified
    337 		 * location. If this highlighter doesn't know what to
    338 		 * display, it should delegate to the next highlight
    339 		 * painter.
    340 		 * @param evt The mouse event
    341 		 */
    342 		String getToolTipText(MouseEvent evt);
    343 	}
    344
    345 	/***
    346 	 * Returns the tool tip to display at the specified location.
    347 	 * @param evt The mouse event
    348 	 */
    349 	public String getToolTipText(MouseEvent evt)
    350 	{
    351 		if(highlights != null)
    352 			return highlights.getToolTipText(evt);
    353 		else
    354 			return null;
    355 	}
    356
    357 	/***
    358 	 * Returns the font metrics used by this component.
    359 	 */
    360 	public FontMetrics getFontMetrics()
    361 	{
    362 		return fm;
    363 	}
    364
    365 	/***
    366 	 * Sets the font for this component. This is overridden to update the
    367 	 * cached font metrics and to recalculate which lines are visible.
    368 	 * @param font The font
    369 	 */
    370 	public void setFont(Font font)
    371 	{
    372 		super.setFont(font);
    373 		fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
    374 		textArea.recalculateVisibleLines();
    375 	}
    376
    377 	/***
    378 	 * Repaints the text.
    379 	 * @param g The graphics context
    380 	 */
    381 	public void paint(Graphics gfx)
    382 	{
    383 		Rectangle clipRect = gfx.getClipBounds();
    384
    385 		gfx.setColor(getBackground());
    386 		gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
    387
    388 		// We don't use yToLine() here because that method doesn't
    389 		// return lines past the end of the document
    390 		int height = fm.getHeight();
    391 		int firstLine = textArea.getFirstLine();
    392 		int firstInvalid = firstLine + clipRect.y / height;
    393 		// Because the clipRect's height is usually an even multiple
    394 		// of the font height, we subtract 1 from it, otherwise one
    395 		// too many lines will always be painted.
    396 		int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
    397
    398 		try
    399 		{
    400 			TokenMarker tokenMarker = textArea.getDocument()
    401 				.getTokenMarker();
    402 			int x = 0; //-textArea.getHorizontalOffset();
    403
    404 			for(int line = firstInvalid; line <= lastInvalid; line++)
    405 			{
    406 				paintLine(gfx,tokenMarker,line,x);
    407 			}
    408
    409 			if(tokenMarker != null && tokenMarker.isNextLineRequested())
    410 			{
    411 				int h = clipRect.y + clipRect.height;
    412 				repaint(0,h,getWidth(),getHeight() - h);
    413 			}
    414 		}
    415 		catch(Exception e)
    416 		{
    417 			System.err.println("Error repainting line"
    418 				+ " range {" + firstInvalid + ","
    419 				+ lastInvalid + "}:");
    420 			SoapUI.logError( e );
    421 		}
    422 	}
    423
    424 	/***
    425 	 * Marks a line as needing a repaint.
    426 	 * @param line The line to invalidate
    427 	 */
    428 	public final void invalidateLine(int line)
    429 	{
    430 		repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
    431 			getWidth(),fm.getHeight());
    432 	}
    433
    434 	/***
    435 	 * Marks a range of lines as needing a repaint.
    436 	 * @param firstLine The first line to invalidate
    437 	 * @param lastLine The last line to invalidate
    438 	 */
    439 	public final void invalidateLineRange(int firstLine, int lastLine)
    440 	{
    441 		repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
    442 			getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
    443 	}
    444
    445 	/***
    446 	 * Repaints the lines containing the selection.
    447 	 */
    448 	public final void invalidateSelectedLines()
    449 	{
    450 		invalidateLineRange(textArea.getSelectionStartLine(),
    451 			textArea.getSelectionEndLine());
    452 	}
    453
    454 	/***
    455 	 * Implementation of TabExpander interface. Returns next tab stop after
    456 	 * a specified point.
    457 	 * @param x The x co-ordinate
    458 	 * @param tabOffset Ignored
    459 	 * @return The next tab stop after <i>x</i>
    460 	 */
    461 	public float nextTabStop(float x, int tabOffset)
    462 	{
    463 		if( tabSize == 0 )
    464 			initTabSize();
    465
    466 		int offset = 0; // -textArea.getHorizontalOffset();
    467 		int ntabs = ((int)x - offset) / tabSize;
    468 		return (ntabs + 1) * tabSize + offset;
    469 	}
    470
    471 	private void initTabSize()
    472 	{
    473 		tabSize = fm.charWidth(' ') * ((Integer)textArea
    474 					.getDocument().getProperty(
    475 					PlainDocument.tabSizeAttribute)).intValue();
    476 		if( tabSize == 0 )
    477 			tabSize = fm.charWidth(' ') * 4;
    478 	}
    479
    480 	/***
    481 	 * Returns the painter's preferred size.
    482 	 */
    483 	public Dimension getPreferredSize()
    484 	{
    485 		Dimension dim = new Dimension();
    486 		dim.width = fm.charWidth('w') * textArea.getMaxLineLength() + 5;
    487 		dim.height = fm.getHeight() * textArea.getLineCount() + 5;
    488 		return dim;
    489 	}
    490
    491
    492 	/***
    493 	 * Returns the painter's minimum size.
    494 	 */
    495 	public Dimension getMinimumSize()
    496 	{
    497 		return getPreferredSize();
    498 	}
    499
    500 	public Dimension getMaximumSize()
    501 	{
    502 		return getPreferredSize();
    503 	}
    504
    505 	// package-private members
    506 	int currentLineIndex;
    507 	Token currentLineTokens;
    508 	Segment currentLine;
    509
    510 	// protected members
    511 	protected JEditTextArea textArea;
    512
    513 	protected SyntaxStyle[] styles;
    514 	protected Color caretColor;
    515 	protected Color selectionColor;
    516 	protected Color lineHighlightColor;
    517 	protected Color bracketHighlightColor;
    518 	protected Color eolMarkerColor;
    519
    520 	protected boolean blockCaret;
    521 	protected boolean lineHighlight;
    522 	protected boolean bracketHighlight;
    523 	protected boolean paintInvalid;
    524 	protected boolean eolMarkers;
    525 	//protected int cols;
    526 	//protected int rows;
    527
    528 	protected int tabSize;
    529 	protected FontMetrics fm;
    530
    531 	protected Highlight highlights;
    532
    533 	protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
    534 		int line, int x)
    535 	{
    536 		Font defaultFont = getFont();
    537 		Color defaultColor = getForeground();
    538
    539 		currentLineIndex = line;
    540 		int y = textArea.lineToY(line);
    541
    542 		int lineWidth = 0;
    543
    544 		if(line < 0 || line >= textArea.getLineCount())
    545 		{
    546 			if(paintInvalid)
    547 			{
    548 				paintHighlight(gfx,line,y);
    549 				styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
    550 				gfx.drawString("~",0,y + fm.getHeight());
    551 			}
    552 		}
    553 		else if(tokenMarker == null)
    554 		{
    555 			lineWidth = paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
    556 		}
    557 		else
    558 		{
    559 			lineWidth = paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
    560 				defaultColor,x,y);
    561 		}
    562
    563 		if( lineWidth > areaWidth )
    564 			areaWidth = lineWidth;
    565 	}
    566
    567 	protected int paintPlainLine(Graphics gfx, int line, Font defaultFont,
    568 		Color defaultColor, int x, int y)
    569 	{
    570 		paintHighlight(gfx,line,y);
    571 		textArea.getLineText(line,currentLine);
    572
    573 		gfx.setFont(defaultFont);
    574 		gfx.setColor(defaultColor);
    575
    576 		y += fm.getHeight();
    577 		x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
    578
    579 		if(eolMarkers)
    580 		{
    581 			gfx.setColor(eolMarkerColor);
    582 			gfx.drawString(".",x,y);
    583 		}
    584
    585 		return x;
    586 	}
    587
    588 	protected int paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
    589 		int line, Font defaultFont, Color defaultColor, int x, int y)
    590 	{
    591 		textArea.getLineText(currentLineIndex,currentLine);
    592 		currentLineTokens = tokenMarker.markTokens(currentLine,
    593 			currentLineIndex);
    594
    595 		paintHighlight(gfx,line,y);
    596
    597 		gfx.setFont(defaultFont);
    598 		gfx.setColor(defaultColor);
    599 		y += fm.getHeight();
    600 		x = SyntaxUtilities.paintSyntaxLine(currentLine,
    601 			currentLineTokens,styles,this,gfx,x,y);
    602
    603 		if(eolMarkers)
    604 		{
    605 			gfx.setColor(eolMarkerColor);
    606 			gfx.drawString(".",x,y);
    607 		}
    608
    609 		return x;
    610 	}
    611
    612 	protected void paintHighlight(Graphics gfx, int line, int y)
    613 	{
    614 		if(line >= textArea.getSelectionStartLine()
    615 			&& line <= textArea.getSelectionEndLine())
    616 			paintLineHighlight(gfx,line,y);
    617
    618 		if(highlights != null)
    619 			highlights.paintHighlight(gfx,line,y);
    620
    621 		if(bracketHighlight && line == textArea.getBracketLine())
    622 			paintBracketHighlight(gfx,line,y);
    623
    624 		if(line == textArea.getCaretLine())
    625 			paintCaret(gfx,line,y);
    626 	}
    627
    628 	protected void paintLineHighlight(Graphics gfx, int line, int y)
    629 	{
    630 		int height = fm.getHeight();
    631 		y += fm.getLeading() + fm.getMaxDescent();
    632
    633 		int selectionStart = textArea.getSelectionStart();
    634 		int selectionEnd = textArea.getSelectionEnd();
    635
    636 		if(selectionStart == selectionEnd)
    637 		{
    638 			if(lineHighlight)
    639 			{
    640 				gfx.setColor(lineHighlightColor);
    641 				gfx.fillRect(0,y,getWidth(),height);
    642 			}
    643 		}
    644 		else
    645 		{
    646 			gfx.setColor(selectionColor);
    647
    648 			int selectionStartLine = textArea.getSelectionStartLine();
    649 			int selectionEndLine = textArea.getSelectionEndLine();
    650 			int lineStart = textArea.getLineStartOffset(line);
    651
    652 			int x1, x2;
    653 			if(textArea.isSelectionRectangular())
    654 			{
    655 				int lineLen = textArea.getTabExpandedLineLength(line);
    656 				x1 = textArea._offsetToX(line,Math.min(lineLen,
    657 					selectionStart - textArea.getLineStartOffset(
    658 					selectionStartLine)));
    659 				x2 = textArea._offsetToX(line,Math.min(lineLen,
    660 					selectionEnd - textArea.getLineStartOffset(
    661 					selectionEndLine)));
    662 				if(x1 == x2)
    663 					x2++;
    664 			}
    665 			else if(selectionStartLine == selectionEndLine)
    666 			{
    667 				x1 = textArea._offsetToX(line,
    668 					selectionStart - lineStart);
    669 				x2 = textArea._offsetToX(line,
    670 					selectionEnd - lineStart);
    671 			}
    672 			else if(line == selectionStartLine)
    673 			{
    674 				x1 = textArea._offsetToX(line,
    675 					selectionStart - lineStart);
    676 				x2 = getWidth();
    677 			}
    678 			else if(line == selectionEndLine)
    679 			{
    680 				x1 = 0;
    681 				x2 = textArea._offsetToX(line,
    682 					selectionEnd - lineStart);
    683 			}
    684 			else
    685 			{
    686 				x1 = 0;
    687 				x2 = getWidth();
    688 			}
    689
    690 			// "inlined" min/max()
    691 			gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
    692 				(x1 - x2) : (x2 - x1),height);
    693 		}
    694
    695 	}
    696
    697 	protected void paintBracketHighlight(Graphics gfx, int line, int y)
    698 	{
    699 		int position = textArea.getBracketPosition();
    700 		if(position == -1)
    701 			return;
    702 		y += fm.getLeading() + fm.getMaxDescent();
    703 		int x = textArea._offsetToX(line,position);
    704 		gfx.setColor(bracketHighlightColor);
    705 		// Hack!!! Since there is no fast way to get the character
    706 		// from the bracket matching routine, we use ( since all
    707 		// brackets probably have the same width anyway
    708 		gfx.drawRect(x,y,fm.charWidth('(') - 1,
    709 			fm.getHeight() - 1);
    710 	}
    711
    712 protected void paintCaret(Graphics gfx, int line, int y)
    713 	{
    714 		if(textArea.isCaretVisible())
    715 		{
    716 			int offset = textArea.getCaretPosition()
    717 				- textArea.getLineStartOffset(line);
    718 			int caretX = textArea._offsetToX(line,offset);
    719 			int caretWidth = ((blockCaret ||
    720 				textArea.isOverwriteEnabled()) ?
    721 				fm.charWidth('w') : 1);
    722 			y += fm.getLeading() + fm.getMaxDescent();
    723 			int height = fm.getHeight();
    724
    725 			gfx.setColor(caretColor);
    726
    727 			if(textArea.isOverwriteEnabled())
    728 			{
    729 				gfx.fillRect(caretX,y + height - 1,
    730 					caretWidth,1);
    731 			}
    732 			else
    733 			{
    734 				gfx.drawRect(caretX,y,caretWidth, height - 1);
    735 			}
    736 		}
    737 	}
    738 }