/** * Determines the preferred span for this view along an axis. * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the span the view would like to be rendered into >= 0. Typically the view is told to * render into the span that is returned, although there is no guarantee. The parent may * choose to resize or break the view. * @exception IllegalArgumentException for an invalid axis */ @Override public float getPreferredSpan(int axis) { updateMetrics(); switch (axis) { case View.X_AXIS: float span = longLineWidth + getRhsCorrection(); // fudge factor if (host.getEOLMarkersVisible()) { span += metrics.charWidth('\u00B6'); } return span; case View.Y_AXIS: // We update lineHeight here as when this method is first // called, lineHeight isn't initialized. If we don't do it // here, we get no vertical scrollbar (as lineHeight==0). lineHeight = host != null ? host.getLineHeight() : lineHeight; // return getElement().getElementCount() * lineHeight; int visibleLineCount = getElement().getElementCount(); if (host.isCodeFoldingEnabled()) { visibleLineCount -= host.getFoldManager().getHiddenLineCount(); } return visibleLineCount * (float) lineHeight; default: throw new IllegalArgumentException("Invalid axis: " + axis); } }
/** * Determines the minimum span for this view along an axis. This is implemented to provide the * superclass behavior after first making sure that the current font metrics are cached (for the * nested lines which use the metrics to determine the height of the potentially wrapped lines). * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the span the view would like to be rendered into. Typically the view is told to render * into the span that is returned, although there is no guarantee. The parent may choose to * resize or break the view. * @see View#getMinimumSpan */ public float getMinimumSpan(int axis) { updateMetrics(); float span = super.getPreferredSpan(axis); if (axis == View.X_AXIS) { // EOL marker span += metrics.charWidth('\u00b6'); // metrics set in updateMetrics } return span; }
/** * Iterate over the lines represented by the child elements of the element this view represents, * looking for the line that is the longest. The <em>longLine</em> variable is updated to * represent the longest line contained. The <em>font</em> variable is updated to indicate the * font used to calculate the longest line. */ void calculateLongestLine() { Component c = getContainer(); font = c.getFont(); metrics = c.getFontMetrics(font); tabSize = getTabSize() * metrics.charWidth(' '); Element lines = getElement(); int n = lines.getElementCount(); for (int i = 0; i < n; i++) { Element line = lines.getElement(i); float w = getLineWidth(i); if (w > longLineWidth) { longLineWidth = w; longLine = line; } } }
/** Calculate the width needed to display the maximum line number */ private void setPreferredWidth() { Element root = component.getDocument().getDefaultRootElement(); int lines = root.getElementCount(); int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits); // Update sizes when number of digits in the line number changes if (lastDigits != digits) { lastDigits = digits; FontMetrics fontMetrics = getFontMetrics(getFont()); int width = fontMetrics.charWidth('0') * digits; Insets insets = getInsets(); int preferredWidth = insets.left + insets.right + width; Dimension d = getPreferredSize(); d.setSize(preferredWidth, HEIGHT); setPreferredSize(d); setSize(d); } }
/** * Determines the preferred span for this view along an axis. This is implemented to provide the * superclass behavior after first making sure that the current font metrics are cached (for the * nested lines which use the metrics to determine the height of the potentially wrapped lines). * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the span the view would like to be rendered into. Typically the view is told to render * into the span that is returned, although there is no guarantee. The parent may choose to * resize or break the view. * @see View#getPreferredSpan */ public float getPreferredSpan(int axis) { updateMetrics(); float span = 0; if (axis == View.X_AXIS) { // Add EOL marker span = super.getPreferredSpan(axis); span += metrics.charWidth('\u00b6'); // metrics set in updateMetrics } else { span = super.getPreferredSpan(axis); host = (RSyntaxTextArea) getContainer(); if (host.isCodeFoldingEnabled()) { // TODO: Cache y-offsets again to speed this up // System.out.println("y-axis baby"); int lineCount = host.getLineCount(); FoldManager fm = host.getFoldManager(); for (int i = 0; i < lineCount; i++) { if (fm.isLineHidden(i)) { span -= getSpan(View.Y_AXIS, i); } } } } return span; }
/** * Converts an x co-ordinate to an offset within a line. * * @param line The line * @param x The x co-ordinate */ public int xToOffset(int line, int x) { TokenMarker tokenMarker = getTokenMarker(); /* Use painter's cached info for speed */ FontMetrics fm = painter.getFontMetrics(); getLineText(line, lineSegment); char[] segmentArray = lineSegment.array; int segmentOffset = lineSegment.offset; int segmentCount = lineSegment.count; int width = horizontalOffset; if (tokenMarker == null) { for (int i = 0; i < segmentCount; i++) { char c = segmentArray[i + segmentOffset]; int charWidth; if (c == '\t') charWidth = (int) painter.nextTabStop(width, i) - width; else charWidth = fm.charWidth(c); if (painter.isBlockCaretEnabled()) { if (x - charWidth <= width) return i; } else { if (x - charWidth / 2 <= width) return i; } width += charWidth; } return segmentCount; } else { Token tokens; if (painter.currentLineIndex == line && painter.currentLineTokens != null) tokens = painter.currentLineTokens; else { painter.currentLineIndex = line; tokens = painter.currentLineTokens = tokenMarker.markTokens(lineSegment, line); } int offset = 0; Toolkit toolkit = painter.getToolkit(); Font defaultFont = painter.getFont(); SyntaxStyle[] styles = painter.getStyles(); for (; ; ) { byte id = tokens.id; if (id == Token.END) return offset; if (id == Token.NULL) fm = painter.getFontMetrics(); else fm = styles[id].getFontMetrics(defaultFont); int length = tokens.length; for (int i = 0; i < length; i++) { char c = segmentArray[segmentOffset + offset + i]; int charWidth; if (c == '\t') charWidth = (int) painter.nextTabStop(width, offset + i) - width; else charWidth = fm.charWidth(c); if (painter.isBlockCaretEnabled()) { if (x - charWidth <= width) return offset + i; } else { if (x - charWidth / 2 <= width) return offset + i; } width += charWidth; } offset += length; tokens = tokens.next; } } }
final void updateMetrics() { Component host = getContainer(); Font f = host.getFont(); metrics = host.getFontMetrics(f); // Metrics for the default font. tabSize = getTabSize() * metrics.charWidth('m'); }