📄 textareapainter.java
字号:
{ return extensionMgr.getExtensions(); } //}}} //{{{ getToolTipText() method /** * Returns the tool tip to display at the specified location. * @param evt The mouse event */ public String getToolTipText(MouseEvent evt) { if(!textArea.getBuffer().isLoaded()) return null; return extensionMgr.getToolTipText(evt.getX(),evt.getY()); } //}}} //{{{ getFontMetrics() method /** * Returns the font metrics used by this component. */ public FontMetrics getFontMetrics() { return fm; } //}}} //{{{ setFont() method /** * Sets the font for this component. This is overridden to update the * cached font metrics and to recalculate which lines are visible. * @param font The font */ public void setFont(Font font) { super.setFont(font); fm = getFontMetrics(font); textArea.recalculateVisibleLines(); } //}}} //{{{ paintComponent() method /** * Repaints the text. * @param g The graphics context */ public void paintComponent(Graphics _gfx) { Graphics2D gfx = (Graphics2D)_gfx; gfx.setRenderingHints(renderingHints); fontRenderContext = gfx.getFontRenderContext(); Rectangle clipRect = gfx.getClipBounds(); gfx.setColor(getBackground()); gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height); Buffer buffer = textArea.getBuffer(); if(!buffer.isLoaded()) return; int x = textArea.getHorizontalOffset(); int height = fm.getHeight(); int firstInvalid = clipRect.y / height; // Because the clipRect's height is usually an even multiple // of the font height, we subtract 1 from it, otherwise one // too many lines will always be painted. int lastInvalid = (clipRect.y + clipRect.height - 1) / height; //if(lastInvalid - firstInvalid > 1) // System.err.println("repainting " + (lastInvalid - firstInvalid) + " lines"); textArea.chunkCache.updateChunksUpTo(lastInvalid); int y = (clipRect.y - clipRect.y % height); try { boolean updateMaxHorizontalScrollWidth = false; for(int line = firstInvalid; line <= lastInvalid; line++) { ChunkCache.LineInfo lineInfo = textArea.chunkCache .getLineInfo(line); if(!lineInfo.chunksValid) System.err.println("text area painter: not valid"); lineInfo.width = paintLine(gfx,buffer,lineInfo,line,x,y) - x; if(lineInfo.width > textArea.maxHorizontalScrollWidth) updateMaxHorizontalScrollWidth = true; y += height; } if(buffer.isNextLineRequested()) { //System.err.println("next line requested"); int h = clipRect.y + clipRect.height; textArea.chunkCache.invalidateChunksFrom(lastInvalid + 1); repaint(0,h,getWidth(),getHeight() - h); } if(updateMaxHorizontalScrollWidth) textArea.updateMaxHorizontalScrollWidth(); } catch(Exception e) { Log.log(Log.ERROR,this,"Error repainting line" + " range {" + firstInvalid + "," + lastInvalid + "}:"); Log.log(Log.ERROR,this,e); } if(textArea.timing) { textArea.timing = false; System.err.println(System.currentTimeMillis() - textArea.time); } } //}}} //{{{ nextTabStop() method /** * Implementation of TabExpander interface. Returns next tab stop after * a specified point. * @param x The x co-ordinate * @param tabOffset Ignored * @return The next tab stop after <i>x</i> */ public float nextTabStop(float x, int tabOffset) { int ntabs = (int)(x / textArea.tabSize); return (ntabs + 1) * textArea.tabSize; } //}}} //{{{ getPreferredSize() method /** * Returns the painter's preferred size. */ public Dimension getPreferredSize() { Dimension dim = new Dimension(); char[] foo = new char[80]; for(int i = 0; i < foo.length; i++) foo[i] = ' '; dim.width = (int)(getFont().getStringBounds(foo,0,foo.length, fontRenderContext).getWidth()); dim.height = fm.getHeight() * 25; return dim; } //}}} //{{{ getMinimumSize() method /** * Returns the painter's minimum size. */ public Dimension getMinimumSize() { return getPreferredSize(); } //}}} //{{{ Private members //{{{ Instance variables private JEditTextArea textArea; private SyntaxStyle[] styles; private Color caretColor; private Color selectionColor; private Color lineHighlightColor; private Color bracketHighlightColor; private Color eolMarkerColor; private Color wrapGuideColor; private SyntaxStyle foldLineStyle; private boolean blockCaret; private boolean lineHighlight; private boolean bracketHighlight; private boolean eolMarkers; private boolean wrapGuide; private boolean antiAlias; private boolean fracFontMetrics; // should try to use this as little as possible. private FontMetrics fm; private ExtensionManager extensionMgr; // we keep a reference to this to obtain the background color and // collapsed fold state of the last painted line private PaintLineBackground lineBackground; private RenderingHints renderingHints; private FontRenderContext fontRenderContext; //}}} //{{{ updateRenderingHints() method private void updateRenderingHints() { HashMap hints = new HashMap(); if(antiAlias) { hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); } else { hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); } hints.put(RenderingHints.KEY_FRACTIONALMETRICS, fracFontMetrics ? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF); renderingHints = new RenderingHints(hints); fontRenderContext = new FontRenderContext(null,antiAlias, fracFontMetrics); } //}}} //{{{ paintLine() method private int paintLine(Graphics2D gfx, Buffer buffer, ChunkCache.LineInfo lineInfo, int screenLine, int x, int y) { int physicalLine = lineInfo.physicalLine; if(physicalLine == -1) extensionMgr.paintInvalidLine(gfx,screenLine,y); else { int start = textArea.getScreenLineStartOffset(screenLine); int end = textArea.getScreenLineEndOffset(screenLine); extensionMgr.paintValidLine(gfx,screenLine,physicalLine, start,end,y); Font defaultFont = getFont(); Color defaultColor = getForeground(); gfx.setFont(defaultFont); gfx.setColor(defaultColor); float baseLine = y + fm.getHeight() - fm.getLeading() - fm.getDescent(); if(lineInfo.chunks != null) { buffer.getLineText(physicalLine,textArea.lineSegment); x += Chunk.paintChunkList(textArea.lineSegment, lineInfo.chunks,gfx,x,baseLine, lineBackground.bgColor,true); } if(!lineInfo.lastSubregion) { gfx.setFont(defaultFont); gfx.setColor(eolMarkerColor); gfx.drawString(":",Math.max(x, textArea.getHorizontalOffset() + textArea.wrapMargin + textArea.charWidth), baseLine); x += textArea.charWidth; } else if(lineBackground.collapsedFold) { Font font = foldLineStyle.getFont(); gfx.setFont(font); gfx.setColor(foldLineStyle.getForegroundColor()); int nextLine = textArea.getFoldVisibilityManager() .getNextVisibleLine(physicalLine); if(nextLine == -1) nextLine = buffer.getLineCount(); int count = nextLine - physicalLine - 1; String str = " [" + count + " lines]"; float width = (float)font.getStringBounds( str,fontRenderContext).getWidth(); gfx.drawString(str,x,baseLine); x += width; } else if(eolMarkers) { gfx.setFont(defaultFont); gfx.setColor(eolMarkerColor); gfx.drawString(".",x,baseLine); x += textArea.charWidth; } paintCaret(gfx,physicalLine,start,end,y,lineBackground.bgColor); } return x; } //}}} //{{{ paintCaret() method private void paintCaret(Graphics2D gfx, int physicalLine, int start, int end, int y, Color bgColor) { if(!textArea.isCaretVisible()) return; int caret = textArea.getCaretPosition(); if(caret < start || caret >= end) return; int offset = caret - textArea.getLineStartOffset(physicalLine); textArea.offsetToXY(physicalLine,offset,textArea.returnValue); int caretX = textArea.returnValue.x; int height = fm.getHeight(); gfx.setColor(caretColor); if(blockCaret) { // Workaround for bug in Graphics2D in JDK1.4 under // Windows; calling setPaintMode() does not reset // graphics mode. Graphics2D blockgfx = (Graphics2D)gfx.create(); blockgfx.setXORMode(bgColor); if(textArea.isOverwriteEnabled()) { blockgfx.fillRect(caretX,y + height - height / 3, textArea.charWidth,height / 3); } else blockgfx.fillRect(caretX,y,textArea.charWidth,height); blockgfx.dispose(); } else { if(textArea.isOverwriteEnabled()) { gfx.drawLine(caretX,y + height - 1, caretX + textArea.charWidth,y + height - 1); } else gfx.drawLine(caretX,y,caretX,y + height - 1); } } //}}} //}}} //{{{ PaintLineBackground class class PaintLineBackground extends TextAreaExtension { boolean collapsedFold; Color bgColor; //{{{ paintValidLine() method public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { // minimise access$ methods JEditTextArea textArea = TextAreaPainter.this.textArea; Buffer buffer = textArea.getBuffer(); collapsedFold = (physicalLine < buffer.getLineCount() - 1 && buffer.isFoldStart(physicalLine) && !textArea.getFoldVisibilityManager() .isLineVisible(physicalLine + 1)); int caret = textArea.getCaretPosition(); boolean paintLineHighlight = isLineHighlightEnabled() && caret >= start && caret < end && textArea.selection.size() == 0; if(paintLineHighlight) bgColor = lineHighlightColor; else if(collapsedFold) { bgColor = foldLineStyle.getBackgroundColor(); if(bgColor == null) bgColor = getBackground(); } else bgColor = getBackground(); if(paintLineHighlight || collapsedFold) { gfx.setColor(bgColor); gfx.fillRect(0,y,getWidth(),fm.getHeight()); } } //}}} } //}}} //{{{ PaintSelection class class PaintSelection extends TextAreaExtension { //{{{ paintValidLine() method public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { if(textArea.selection.size() == 0) return; gfx.setColor(getSelectionColor()); for(int i = textArea.selection.size() - 1; i >= 0; i--) { paintSelection(gfx,screenLine, physicalLine,start,end,y, (Selection)textArea.selection .get(i)); } } //}}} //{{{ paintSelection() method private void paintSelection(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y, Selection s) { if(end <= s.start || start > s.end) return; int selStartScreenLine = textArea.getScreenLineOfOffset(s.start); int selEndScreenLine = textArea.getScreenLineOfOffset(s.end); Buffer buffer = textArea.getBuffer(); int lineStart = buffer.getLineStartOffset(physicalLine); int x1, x2; if(s instanceof Selection.Rect) { start -= lineStart; end -= lineStart; Selection.Rect rect = (Selection.Rect)s; int _start = rect.getStartColumn(buffer); int _end = rect.getEndColumn(buffer); int lineLen = buffer.getLineLength(physicalLine); int[] total = new int[1]; int rectStart = buffer.getOffsetOfVirtualColumn( physicalLine,_start,total); if(rectStart == -1) { x1 = (_start - total[0]) * textArea.charWidth; rectStart = lineLen; } else x1 = 0; int rectEnd = buffer.getOffsetOfVirtualColumn( physicalLine,_end,total); if(rectEnd == -1) { x2 = (_end - total[0]) * textArea.charWidth; rectEnd = lineLen; } else x2 = 0; if(end <= rectStart || start > rectEnd) return; x1 = (rectStart < start ? 0 : x1 + textArea.offsetToXY(physicalLine,rectStart,textArea.returnValue).x); x2 = (rectEnd > end ? getWidth() : x2 + textArea.offsetToXY(physicalLine,rectEnd,textArea.returnValue).x); } else if(selStartScreenLine == selEndScreenLine && selStartScreenLine != -1) { x1 = textArea.offsetToXY(physicalLine, s.start - lineStart,textArea.returnValue).x; x2 = textArea.offsetToXY(physicalLine, s.end - lineStart,textArea.returnValue).x; } else if(screenLine == selStartScreenLine) { x1 = textArea.offsetToXY(physicalLine, s.start - lineStart,textArea.returnValue).x; x2 = getWidth(); } else if(screenLine == selEndScreenLine) { x1 = 0; x2 = textArea.offsetToXY(physicalLine, s.end - lineStart,textArea.returnValue).x; } else { x1 = 0; x2 = getWidth(); } if(x1 < 0) x1 = 0; if(x2 < 0) x2 = 0; if(x1 == x2) x2++; gfx.fillRect(x1,y,x2 - x1,fm.getHeight()); } //}}} } //}}} //{{{ WrapGuide class class WrapGuide extends TextAreaExtension { public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { paintInvalidLine(gfx,screenLine,y); } public void paintInvalidLine(Graphics2D gfx, int screenLine, int y) { if(!textArea.wrapToWidth && textArea.wrapMargin != 0 && isWrapGuidePainted()) { gfx.setColor(getWrapGuideColor()); int x = textArea.getHorizontalOffset() + textArea.wrapMargin; gfx.drawLine(x,y,x,y + fm.getHeight()); } } public String getToolTipText(int x, int y) { if(!textArea.wrapToWidth && textArea.wrapMargin != 0 && isWrapGuidePainted()) { int wrapGuidePos = textArea.wrapMargin + textArea.getHorizontalOffset(); if(Math.abs(x - wrapGuidePos) < 5) { return String.valueOf(textArea.getBuffer() .getProperty("maxLineLen")); } } return null; } } //}}} //{{{ BracketHighlight class class BracketHighlight extends TextAreaExtension { public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { if(!isBracketHighlightEnabled() || !textArea.isBracketHighlightVisible()) return; int bracketLine = textArea.getBracketLine(); int bracketOffset = textArea.getBracketPosition(); if(bracketLine == -1 || bracketOffset == -1) return; int bracketLineStart = textArea.getLineStartOffset(bracketLine); if(bracketOffset + bracketLineStart < start || bracketOffset + bracketLineStart >= end) return; textArea.offsetToXY(bracketLine,bracketOffset,textArea.returnValue); gfx.setColor(getBracketHighlightColor()); // Hack!!! Since there is no fast way to get the character // from the bracket matching routine, we use ( since all // brackets probably have the same width anyway gfx.drawRect(textArea.returnValue.x,y,(int)gfx.getFont().getStringBounds( "(",getFontRenderContext()).getWidth() - 1, fm.getHeight() - 1); } } //}}}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -