📄 textareapainter.java
字号:
*/ public void addExtension(TextAreaExtension extension) { extensionMgr.addExtension(DEFAULT_LAYER,extension); repaint(); } //}}} //{{{ addExtension() method /** * Adds a text area extension, which can perform custom painting and * tool tip handling. * @param layer The layer to add the extension to. Note that more than * extension can share the same layer. * @param extension The extension * @since jEdit 4.0pre4 */ public void addExtension(int layer, TextAreaExtension extension) { extensionMgr.addExtension(layer,extension); repaint(); } //}}} //{{{ removeExtension() method /** * Removes a text area extension. It will no longer be asked to * perform custom painting and tool tip handling. * @param extension The extension * @since jEdit 4.0pre4 */ public void removeExtension(TextAreaExtension extension) { extensionMgr.removeExtension(extension); repaint(); } //}}} //{{{ getExtensions() method /** * Returns an array of registered text area extensions. Useful for * debugging purposes. * @since jEdit 4.1pre5 */ public TextAreaExtension[] getExtensions() { 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(); textArea.propertiesChanged(); } //}}} //{{{ 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(Debug.PAINT_TIMER && lastInvalid - firstInvalid >= 1) Log.log(Log.DEBUG,this,"repainting " + (lastInvalid - firstInvalid) + " lines"); int y = (clipRect.y - clipRect.y % height); extensionMgr.paintScreenLineRange(textArea,gfx, firstInvalid,lastInvalid,y,height); textArea.updateMaxHorizontalScrollWidth(); textArea.displayManager._notifyScreenLineChanges(); } //}}} //{{{ 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(); } //}}} //{{{ Package-private members //{{{ Instance variables /* package-private since they are accessed by inner classes and we * want this to be fast */ JEditTextArea textArea; SyntaxStyle[] styles; Color caretColor; Color selectionColor; Color multipleSelectionColor; Color lineHighlightColor; Color structureHighlightColor; Color eolMarkerColor; Color wrapGuideColor; SyntaxStyle[] foldLineStyle; boolean blockCaret; boolean lineHighlight; boolean structureHighlight; boolean eolMarkers; boolean wrapGuide; boolean antiAlias; boolean fracFontMetrics; // should try to use this as little as possible. FontMetrics fm; //}}} //{{{ TextAreaPainter constructor /** * Creates a new painter. Do not create instances of this class * directly. */ TextAreaPainter(JEditTextArea textArea) { enableEvents(AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); this.textArea = textArea; fonts = new HashMap(); extensionMgr = new ExtensionManager(); setAutoscrolls(true); setOpaque(true); setRequestFocusEnabled(false); setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); fontRenderContext = new FontRenderContext(null,false,false); addExtension(LINE_BACKGROUND_LAYER,new PaintLineBackground()); addExtension(SELECTION_LAYER,new PaintSelection()); addExtension(WRAP_GUIDE_LAYER,new PaintWrapGuide()); addExtension(BRACKET_HIGHLIGHT_LAYER,new StructureMatcher .Highlight(textArea)); addExtension(TEXT_LAYER,new PaintText()); caretExtension = new PaintCaret(); } //}}} //}}} //{{{ Private members //{{{ Instance variables private ExtensionManager extensionMgr; private PaintCaret caretExtension; private RenderingHints renderingHints; private FontRenderContext fontRenderContext; private HashMap fonts; //}}} //{{{ 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); } //}}} //{{{ getCharWidth() method private int getCharWidth(Font font) { Integer returnValue = (Integer)fonts.get(font); if(returnValue == null) { int minWidth = Integer.MAX_VALUE; int maxWidth = Integer.MIN_VALUE; FontMetrics fm = getFontMetrics(font); int[] widths = fm.getWidths(); for(int i = 0; i < widths.length; i++) { int width = widths[i]; if(width == 0 || !font.canDisplay((char)i)) continue; minWidth = Math.min(width,minWidth); maxWidth = Math.max(width,maxWidth); } String str = "iwiwiwiau1234"; double width1 = font.createGlyphVector(textArea.getPainter() .getFontRenderContext(),str).getLogicalBounds() .getWidth(); double width2 = str.length() * maxWidth; if(minWidth == maxWidth && width1 == width2) { Log.log(Log.DEBUG,this,"Using monospaced font optimization: " + font); returnValue = new Integer(maxWidth); } else { Log.log(Log.DEBUG,this,"Not using monospaced font optimization: " + font); Log.log(Log.DEBUG,this,"Minimum width = " + minWidth + ", maximum width = " + maxWidth); returnValue = new Integer(0); } fonts.put(font,returnValue); } return returnValue.intValue(); } //}}} //}}} //{{{ Inner classes //{{{ PaintLineBackground class class PaintLineBackground extends TextAreaExtension { //{{{ 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(); //{{{ Paint line highlight and collapsed fold highlight boolean collapsedFold = (physicalLine < buffer.getLineCount() - 1 && buffer.isFoldStart(physicalLine) && !textArea.displayManager .isLineVisible(physicalLine + 1)); SyntaxStyle foldLineStyle = null; if(collapsedFold) { int level = buffer.getFoldLevel(physicalLine + 1); if(buffer.getFoldHandler() instanceof IndentFoldHandler) level = Math.max(1,level / buffer.getIndentSize()); if(level > 3) level = 0; foldLineStyle = TextAreaPainter.this.foldLineStyle[level]; } int caret = textArea.getCaretPosition(); boolean paintLineHighlight = isLineHighlightEnabled() && caret >= start && caret < end && textArea.selection.size() == 0; Color bgColor; 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()); } //}}} //{{{ Paint token backgrounds ChunkCache.LineInfo lineInfo = textArea.chunkCache .getLineInfo(screenLine); if(lineInfo.chunks != null) { float baseLine = y + fm.getHeight() - fm.getLeading() - fm.getDescent(); Chunk.paintChunkBackgrounds( lineInfo.chunks,gfx, textArea.getHorizontalOffset(), baseLine); } //}}} } //}}} } //}}} //{{{ 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(textArea.isMultipleSelectionEnabled() ? getMultipleSelectionColor() : getSelectionColor()); for(int i = textArea.selection.size() - 1; i >= 0; i--) { paintSelection(gfx,screenLine,physicalLine,y, (Selection)textArea.selection.get(i)); } } //}}} //{{{ paintSelection() method private void paintSelection(Graphics2D gfx, int screenLine, int physicalLine, int y, Selection s) { int[] selectionStartAndEnd = textArea.getSelectionStartAndEnd( screenLine,physicalLine,s); if(selectionStartAndEnd == null) return; int x1 = selectionStartAndEnd[0]; int x2 = selectionStartAndEnd[1]; gfx.fillRect(x1,y,x2 - x1,fm.getHeight()); } //}}} } //}}} //{{{ PaintWrapGuide class class PaintWrapGuide extends TextAreaExtension { public void paintScreenLineRange(Graphics2D gfx, int firstLine, int lastLine, int[] physicalLines, int[] start, int[] end, int y, int lineHeight) { if(textArea.getDisplayManager().wrapMargin != 0 && isWrapGuidePainted()) { gfx.setColor(getWrapGuideColor()); int x = textArea.getHorizontalOffset() + textArea.getDisplayManager() .wrapMargin; gfx.drawLine(x,y,x,y + (lastLine - firstLine + 1) * lineHeight); } } public String getToolTipText(int x, int y) { if(textArea.getDisplayManager().wrapMargin != 0 && isWrapGuidePainted()) { int wrapGuidePos = textArea.getDisplayManager().wrapMargin + textArea.getHorizontalOffset(); if(Math.abs(x - wrapGuidePos) < 5) { return String.valueOf(textArea.getBuffer() .getProperty("maxLineLen")); } } return null; } } //}}} //{{{ PaintText class class PaintText extends TextAreaExtension { public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { ChunkCache.LineInfo lineInfo = textArea.chunkCache .getLineInfo(screenLine); Font defaultFont = getFont(); Color defaultColor = getForeground(); gfx.setFont(defaultFont); gfx.setColor(defaultColor); int x = textArea.getHorizontalOffset(); int originalX = x; float baseLine = y + fm.getHeight() - fm.getLeading() - fm.getDescent(); if(lineInfo.chunks != null) { x += Chunk.paintChunkList(lineInfo.chunks, gfx,textArea.getHorizontalOffset(), baseLine,!Debug.DISABLE_GLYPH_VECTOR); } Buffer buffer = textArea.getBuffer(); if(!lineInfo.lastSubregion) { gfx.setFont(defaultFont); gfx.setColor(eolMarkerColor); gfx.drawString(":",Math.max(x, textArea.getHorizontalOffset() + textArea.getDisplayManager().wrapMargin + textArea.charWidth), baseLine); x += textArea.charWidth; } else if(physicalLine < buffer.getLineCount() - 1 && buffer.isFoldStart(physicalLine) && !textArea.displayManager .isLineVisible(physicalLine + 1)) { int level = buffer.getFoldLevel(physicalLine + 1); if(buffer.getFoldHandler() instanceof IndentFoldHandler) level = Math.max(1,level / buffer.getIndentSize()); if(level > 3) level = 0; SyntaxStyle foldLineStyle = TextAreaPainter.this.foldLineStyle[level]; Font font = foldLineStyle.getFont(); gfx.setFont(font); gfx.setColor(foldLineStyle.getForegroundColor()); int nextLine; int nextScreenLine = screenLine + 1; if(nextScreenLine < textArea.getVisibleLines()) { nextLine = textArea.chunkCache.getLineInfo(nextScreenLine) .physicalLine; } else { nextLine = textArea.displayManager .getNextVisibleLine(physicalLine); } if(nextLine == -1) nextLine = textArea.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; } lineInfo.width = (x - originalX); } } //}}} //{{{ PaintCaret class class PaintCaret extends TextAreaExtension { public void paintValidLine(Graphics2D gfx, int screenLine, int physicalLine, int start, int end, int y) { 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(textArea.isOverwriteEnabled()) { gfx.drawLine(caretX,y + height - 1, caretX + textArea.charWidth,y + height - 1); } else if(blockCaret) gfx.drawRect(caretX,y,textArea.charWidth - 1,height - 1); else gfx.drawLine(caretX,y,caretX,y + height - 1); } } //}}} //}}}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -