/** * Modifies the passed-in token list to start at the specified offset. For example, if the token * list covered positions 20-60 in the document (inclusive) like so: * * <pre> * [token1] -> [token2] -> [token3] -> [token4] * 20 30 31 40 41 50 51 60 * </pre> * * and you used this method to make the token list start at position 44, then the token list would * be modified to be the following: * * <pre> * [part-of-old-token3] -> [token4] * 44 50 51 60 * </pre> * * Tokens that come before the specified position are forever lost, and the token containing that * position is made to begin at that position if necessary. All token types remain the same as * they were originally. * * <p>This method can be useful if you are only interested in part of a token list (i.e., the line * it represents), but you don't want to modify the token list yourself. * * @param tokenList The list to make start at the specified position. This parameter is modified. * @param pos The position at which the new token list is to start. If this position is not in the * passed-in token list, returned token list will either be <code>null</code> or the * unpaintable token(s) at the end of the passed-in token list. * @param e How to expand tabs. * @param textArea The text area from which the token list came. * @param x0 The initial x-pixel position of the old token list. * @return The width, in pixels, of the part of the token list "removed from the front." This way, * you know the x-offset of the "new" token list. */ public static float makeTokenListStartAt( Token tokenList, int pos, TabExpander e, final RSyntaxTextArea textArea, float x0) { Token t = tokenList; // Loop through the token list until you find the one that contains // pos. Remember the cumulative width of all of these tokens. while (t != null && t.isPaintable() && !t.containsPosition(pos)) { x0 += t.getWidth(textArea, e, x0); t = t.getNextToken(); } // Make the token that contains pos start at pos. if (t != null && t.isPaintable() && t.offset != pos) { // Number of chars between p0 and token start. int difference = pos - t.offset; x0 += t.getWidthUpTo(t.textCount - difference + 1, textArea, e, x0); t.makeStartAt(pos); } // Make the passed-in token list point to the proper place. // t can be null, for example, if line ends with unended MLC. if (t != null && t.isPaintable()) tokenList.copyFrom(t); else tokenList = null; t = null; // Return the x-offset (in pixels) of the newly-modified t. return x0; }
/** * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple * lines if necessary. * * @param g The graphics context in which to paint. * @param r The rectangle in which to paint. * @param view The <code>View</code> to paint. * @param fontHeight The height of the font being used. * @param y The y-coordinate at which to begin painting. */ protected void drawView(Graphics2D g, Rectangle r, View view, int fontHeight, int y) { float x = r.x; LayeredHighlighter h = (LayeredHighlighter) host.getHighlighter(); RSyntaxDocument document = (RSyntaxDocument) getDocument(); Element map = getElement(); int p0 = view.getStartOffset(); int lineNumber = map.getElementIndex(p0); int p1 = view.getEndOffset(); // - 1; setSegment(p0, p1 - 1, document, drawSeg); // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")"); int start = p0 - drawSeg.offset; Token token = document.getTokenListForLine(lineNumber); // If this line is an empty line, then the token list is simply a // null token. In this case, the line highlight will be skipped in // the loop below, so unfortunately we must manually do it here. if (token != null && token.type == Token.NULL) { h.paintLayeredHighlights(g, p0, p1, r, host, this); return; } // Loop through all tokens in this view and paint them! while (token != null && token.isPaintable()) { int p = calculateBreakPosition(p0, token, x); x = r.x; h.paintLayeredHighlights(g, p0, p, r, host, this); while (token != null && token.isPaintable() && token.offset + token.textCount - 1 < p) { // <=p) { x = token.paint(g, x, y, host, this); token = token.getNextToken(); } if (token != null && token.isPaintable() && token.offset < p) { int tokenOffset = token.offset; Token temp = new DefaultToken(drawSeg, tokenOffset - start, p - 1 - start, tokenOffset, token.type); temp.paint(g, x, y, host, this); temp = null; token.makeStartAt(p); } p0 = (p == p0) ? p1 : p; y += fontHeight; } // End of while (token!=null && token.isPaintable()). // NOTE: We should re-use code from Token (paintBackground()) here, // but don't because I'm just too lazy. if (host.getEOLMarkersVisible()) { g.setColor(host.getForegroundForTokenType(Token.WHITESPACE)); g.setFont(host.getFontForTokenType(Token.WHITESPACE)); g.drawString("\u00B6", x, y - fontHeight); } }
/** * Draws a single view (i.e., a line of text for a wrapped view), wrapping the text onto multiple * lines if necessary. Any selected text is rendered with the editor's "selected text" color. * * @param painter The painter to use to render tokens. * @param g The graphics context in which to paint. * @param r The rectangle in which to paint. * @param view The <code>View</code> to paint. * @param fontHeight The height of the font being used. * @param y The y-coordinate at which to begin painting. * @param selStart The start of the selection. * @param selEnd The end of the selection. */ protected void drawViewWithSelection( TokenPainter painter, Graphics2D g, Rectangle r, View view, int fontHeight, int y, int selStart, int selEnd) { float x = r.x; LayeredHighlighter h = (LayeredHighlighter) host.getHighlighter(); RSyntaxDocument document = (RSyntaxDocument) getDocument(); Element map = getElement(); int p0 = view.getStartOffset(); int lineNumber = map.getElementIndex(p0); int p1 = view.getEndOffset(); // - 1; setSegment(p0, p1 - 1, document, drawSeg); // System.err.println("drawSeg=='" + drawSeg + "' (p0/p1==" + p0 + "/" + p1 + ")"); int start = p0 - drawSeg.offset; Token token = document.getTokenListForLine(lineNumber); // If this line is an empty line, then the token list is simply a // null token. In this case, the line highlight will be skipped in // the loop below, so unfortunately we must manually do it here. if (token != null && token.type == Token.NULL) { h.paintLayeredHighlights(g, p0, p1, r, host, this); return; } // Loop through all tokens in this view and paint them! while (token != null && token.isPaintable()) { int p = calculateBreakPosition(p0, token, x); x = r.x; h.paintLayeredHighlights(g, p0, p, r, host, this); while (token != null && token.isPaintable() && token.offset + token.textCount - 1 < p) { // <=p) { // Selection starts in this token if (token.containsPosition(selStart)) { if (selStart > token.offset) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.offset; x = painter.paint(tempToken, g, x, y, host, this); token.makeStartAt(selStart); } int selCount = Math.min(token.textCount, selEnd - token.offset); if (selCount == token.textCount) { x = painter.paintSelected(token, g, x, y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x, y, host, this); token.makeStartAt(token.offset + selCount); x = painter.paint(token, g, x, y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.offset; x = painter.paintSelected(tempToken, g, x, y, host, this); token.makeStartAt(selEnd); x = painter.paint(token, g, x, y, host, this); } // This token is entirely selected else if (token.offset >= selStart && (token.offset + token.textCount) <= selEnd) { x = painter.paintSelected(token, g, x, y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x, y, host, this); } token = token.getNextToken(); } // If there's a token that's going to be split onto the next line if (token != null && token.isPaintable() && token.offset < p) { int tokenOffset = token.offset; Token orig = token; token = new Token(drawSeg, tokenOffset - start, p - 1 - start, tokenOffset, token.type); // Selection starts in this token if (token.containsPosition(selStart)) { if (selStart > token.offset) { tempToken.copyFrom(token); tempToken.textCount = selStart - tempToken.offset; x = painter.paint(tempToken, g, x, y, host, this); token.makeStartAt(selStart); } int selCount = Math.min(token.textCount, selEnd - token.offset); if (selCount == token.textCount) { x = painter.paintSelected(token, g, x, y, host, this); } else { tempToken.copyFrom(token); tempToken.textCount = selCount; x = painter.paintSelected(tempToken, g, x, y, host, this); token.makeStartAt(token.offset + selCount); x = painter.paint(token, g, x, y, host, this); } } // Selection ends in this token else if (token.containsPosition(selEnd)) { tempToken.copyFrom(token); tempToken.textCount = selEnd - tempToken.offset; x = painter.paintSelected(tempToken, g, x, y, host, this); token.makeStartAt(selEnd); x = painter.paint(token, g, x, y, host, this); } // This token is entirely selected else if (token.offset >= selStart && (token.offset + token.textCount) <= selEnd) { x = painter.paintSelected(token, g, x, y, host, this); } // This token is entirely unselected else { x = painter.paint(token, g, x, y, host, this); } token = orig; token.makeStartAt(p); } p0 = (p == p0) ? p1 : p; y += fontHeight; } // End of while (token!=null && token.isPaintable()). // NOTE: We should re-use code from Token (paintBackground()) here, // but don't because I'm just too lazy. if (host.getEOLMarkersVisible()) { g.setColor(host.getForegroundForTokenType(Token.WHITESPACE)); g.setFont(host.getFontForTokenType(Token.WHITESPACE)); g.drawString("\u00B6", x, y - fontHeight); } }