All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.ui.rsyntaxtextarea.VisibleWhitespaceTokenPainter Maven / Gradle / Ivy

The newest version!
/*
 * 03/16/2013
 *
 * VisibleWhitespaceTokenPainter - Renders tokens in an instance of
 * RSyntaxTextArea, with special glyphs to denote spaces and tabs.
 * 
 * This library is distributed under a modified BSD license.  See the included
 * RSyntaxTextArea.License.txt file for details.
 */
package org.fife.ui.rsyntaxtextarea;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import javax.swing.text.TabExpander;


/**
 * A token painter that visibly renders whitespace (spaces and tabs).

* * The current implementation paints as follows: *

    *
  • The first tab or space, if any, is found in the token.
  • *
  • If a tab was found, all characters up to it are painted as a * group.
  • *
  • If a space was found, all characters up to and including it are * painted (it is painted with a special symbol to denote it as * a space).
  • *
  • If neither a tab nor a whitespace was found, all characters in the * token are painted.
  • *
  • Repeat until all characters are painted.
  • *
* This means that rendering hints are applied to all groups of characters * within a token, excluding whitespace and tabs.

* * A problem with this implementation is that FontMetrics.charsWidth() is still * used to calculate the width of a group of chars painted. Thus, the group of * characters will be painted with the rendering hints specified, but the * following tab (or group of characters if the current group was the end of a * token) will not necessarily be painted at the proper x-coordinate (as * FontMetrics.charsWidth() returns an int and not a * float). The way around this would be to calculate the token's * width in such a way that a float is returned (Font.getStringBounds()?). * * @author Robert Futrell * @version 1.0 */ class VisibleWhitespaceTokenPainter extends DefaultTokenPainter { /** * {@inheritDoc} */ @Override protected float paintImpl(Token token, Graphics2D g, float x, float y, RSyntaxTextArea host, TabExpander e, float clipStart, boolean selected, boolean useSTC) { int origX = (int)x; int textOffs = token.getTextOffset(); char[] text = token.getTextArray(); int end = textOffs + token.length(); float nextX = x; int flushLen = 0; int flushIndex = textOffs; Color fg = useSTC ? host.getSelectedTextColor() : host.getForegroundForToken(token); Color bg = selected ? null : host.getBackgroundForToken(token); g.setFont(host.getFontForTokenType(token.getType())); FontMetrics fm = host.getFontMetricsForTokenType(token.getType()); int ascent = fm.getAscent(); int height = fm.getHeight(); for (int i=textOffs; i 0) { g.drawChars(text, flushIndex, flushLen, (int)x,(int)y); flushLen = 0; } flushIndex = i + 1; // Draw an arrow representing the tab. int halfHeight = height / 2; int quarterHeight = halfHeight / 2; int ymid = (int)y - ascent + halfHeight; g.drawLine((int)nextX,ymid, (int)nextNextX,ymid); g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid-quarterHeight); g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid+quarterHeight); x = nextNextX; break; case ' ': // NOTE: There is a little bit of a "fudge factor" // here when "smooth text" is enabled, as "width" // below may well not be the width given to the space // by fm.charsWidth() (it depends on how it places the // space with respect to the preceding character). // But, we assume the approximation is close enough for // our drawing a dot for the space. // "flushLen+1" ensures text is aligned correctly (or, // aligned the same as in getWidth()). nextX = x+fm.charsWidth(text, flushIndex,flushLen+1); int width = fm.charWidth(' '); // Paint background. if (bg!=null) { paintBackground(x,y, nextX-x,height, g, ascent, host, bg); } g.setColor(fg); // Paint chars before space. if (flushLen>0) { g.drawChars(text, flushIndex, flushLen, (int)x,(int)y); flushLen = 0; } // Paint a dot representing the space. int dotX = (int)(nextX - width/2f); // "2.0f" for FindBugs int dotY = (int)(y - ascent + height/2f); // Ditto g.drawLine(dotX, dotY, dotX, dotY); flushIndex = i + 1; x = nextX; break; case '\f': // ??? // fall-through for now. default: flushLen += 1; break; } } nextX = x+fm.charsWidth(text, flushIndex,flushLen); if (flushLen>0 && nextX>=clipStart) { if (bg!=null) { paintBackground(x,y, nextX-x,height, g, ascent, host, bg); } g.setColor(fg); g.drawChars(text, flushIndex, flushLen, (int)x,(int)y); } if (host.getUnderlineForToken(token)) { g.setColor(fg); int y2 = (int)(y+1); g.drawLine(origX,y2, (int)nextX,y2); } // Don't check if it's whitespace - some TokenMakers may return types // other than Token.WHITESPACE for spaces (such as Token.IDENTIFIER). // This also allows us to paint tab lines for MLC's. if (host.getPaintTabLines() && origX==host.getMargin().left) {// && isWhitespace()) { paintTabLines(token, origX, (int)y, (int)nextX, g, e, host); } return nextX; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy