|
|
@ -9,24 +9,37 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
package com.fr.design.gui.syntax.ui.rsyntaxtextarea; |
|
|
|
package com.fr.design.gui.syntax.ui.rsyntaxtextarea; |
|
|
|
|
|
|
|
|
|
|
|
import java.awt.*; |
|
|
|
|
|
|
|
import javax.swing.event.*; |
|
|
|
|
|
|
|
import javax.swing.text.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold; |
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold; |
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager; |
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import javax.swing.event.DocumentEvent; |
|
|
|
|
|
|
|
import javax.swing.text.BadLocationException; |
|
|
|
|
|
|
|
import javax.swing.text.Element; |
|
|
|
|
|
|
|
import javax.swing.text.PlainDocument; |
|
|
|
|
|
|
|
import javax.swing.text.Position; |
|
|
|
|
|
|
|
import javax.swing.text.TabExpander; |
|
|
|
|
|
|
|
import javax.swing.text.View; |
|
|
|
|
|
|
|
import javax.swing.text.ViewFactory; |
|
|
|
|
|
|
|
import java.awt.Color; |
|
|
|
|
|
|
|
import java.awt.Component; |
|
|
|
|
|
|
|
import java.awt.Font; |
|
|
|
|
|
|
|
import java.awt.FontMetrics; |
|
|
|
|
|
|
|
import java.awt.Graphics; |
|
|
|
|
|
|
|
import java.awt.Graphics2D; |
|
|
|
|
|
|
|
import java.awt.Rectangle; |
|
|
|
|
|
|
|
import java.awt.Shape; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* The <code>javax.swing.text.View</code> object used by {@link RSyntaxTextArea} |
|
|
|
* The <code>javax.swing.text.View</code> object used by {@link RSyntaxTextArea} |
|
|
|
* when word wrap is disabled. It implements syntax highlighting for |
|
|
|
* when word wrap is disabled. It implements syntax highlighting for |
|
|
|
* programming languages using the colors and font styles specified by the |
|
|
|
* programming languages using the colors and font styles specified by the |
|
|
|
* <code>RSyntaxTextArea</code>.<p> |
|
|
|
* <code>RSyntaxTextArea</code>.<p> |
|
|
|
* |
|
|
|
* <p> |
|
|
|
* You don't really have to do anything to use this class, as |
|
|
|
* You don't really have to do anything to use this class, as |
|
|
|
* {@link RSyntaxTextAreaUI} automatically sets the text area's view to be |
|
|
|
* {@link RSyntaxTextAreaUI} automatically sets the text area's view to be |
|
|
|
* an instance of this class if word wrap is disabled.<p> |
|
|
|
* an instance of this class if word wrap is disabled.<p> |
|
|
|
* |
|
|
|
* <p> |
|
|
|
* The tokens that specify how to paint the syntax-highlighted text are gleaned |
|
|
|
* The tokens that specify how to paint the syntax-highlighted text are gleaned |
|
|
|
* from the text area's {@link RSyntaxDocument}. |
|
|
|
* from the text area's {@link RSyntaxDocument}. |
|
|
|
* |
|
|
|
* |
|
|
@ -105,7 +118,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
tabSize = getTabSize() * metrics.charWidth(' '); |
|
|
|
tabSize = getTabSize() * metrics.charWidth(' '); |
|
|
|
Element lines = getElement(); |
|
|
|
Element lines = getElement(); |
|
|
|
int n = lines.getElementCount(); |
|
|
|
int n = lines.getElementCount(); |
|
|
|
for (int i=0; i<n; i++) { |
|
|
|
for (int i = 0; i < n; i++) { |
|
|
|
Element line = lines.getElement(i); |
|
|
|
Element line = lines.getElement(i); |
|
|
|
float w = getLineWidth(i); |
|
|
|
float w = getLineWidth(i); |
|
|
|
if (w > longLineWidth) { |
|
|
|
if (w > longLineWidth) { |
|
|
@ -149,8 +162,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
if ((area0 != null) && (area1 != null)) { |
|
|
|
if ((area0 != null) && (area1 != null)) { |
|
|
|
Rectangle dmg = area0.union(area1); // damage.
|
|
|
|
Rectangle dmg = area0.union(area1); // damage.
|
|
|
|
host.repaint(dmg.x, dmg.y, dmg.width, dmg.height); |
|
|
|
host.repaint(dmg.x, dmg.y, dmg.width, dmg.height); |
|
|
|
} |
|
|
|
} else |
|
|
|
else |
|
|
|
|
|
|
|
host.repaint(); |
|
|
|
host.repaint(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -174,8 +186,8 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
|
|
|
|
|
|
|
|
float nextX = x; // The x-value at the end of our text.
|
|
|
|
float nextX = x; // The x-value at the end of our text.
|
|
|
|
|
|
|
|
|
|
|
|
while (token!=null && token.isPaintable() && nextX<clipEnd) { |
|
|
|
while (token != null && token.isPaintable() && nextX < clipEnd) { |
|
|
|
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); |
|
|
|
nextX = painter.paint(token, g, nextX, y, host, this, clipStart); |
|
|
|
token = token.getNextToken(); |
|
|
|
token = token.getNextToken(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -212,15 +224,15 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
|
|
|
|
|
|
|
|
float nextX = x; // The x-value at the end of our text.
|
|
|
|
float nextX = x; // The x-value at the end of our text.
|
|
|
|
|
|
|
|
|
|
|
|
while (token!=null && token.isPaintable() && nextX<clipEnd) { |
|
|
|
while (token != null && token.isPaintable() && nextX < clipEnd) { |
|
|
|
|
|
|
|
|
|
|
|
// Selection starts in this token
|
|
|
|
// Selection starts in this token
|
|
|
|
if (token.containsPosition(selStart)) { |
|
|
|
if (token.containsPosition(selStart)) { |
|
|
|
|
|
|
|
|
|
|
|
if (selStart>token.getOffset()) { |
|
|
|
if (selStart > token.getOffset()) { |
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.textCount = selStart - tempToken.getOffset(); |
|
|
|
tempToken.textCount = selStart - tempToken.getOffset(); |
|
|
|
nextX = painter.paint(tempToken,g,nextX,y,host, this, clipStart); |
|
|
|
nextX = painter.paint(tempToken, g, nextX, y, host, this, clipStart); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.makeStartAt(selStart); |
|
|
|
tempToken.makeStartAt(selStart); |
|
|
|
// Clone required since token and tempToken must be
|
|
|
|
// Clone required since token and tempToken must be
|
|
|
@ -229,20 +241,19 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int tokenLen = token.length(); |
|
|
|
int tokenLen = token.length(); |
|
|
|
int selCount = Math.min(tokenLen, selEnd-token.getOffset()); |
|
|
|
int selCount = Math.min(tokenLen, selEnd - token.getOffset()); |
|
|
|
if (selCount==tokenLen) { |
|
|
|
if (selCount == tokenLen) { |
|
|
|
nextX = painter.paintSelected(token, g, nextX,y, host, |
|
|
|
nextX = painter.paintSelected(token, g, nextX, y, host, |
|
|
|
this, clipStart); |
|
|
|
this, clipStart); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.textCount = selCount; |
|
|
|
tempToken.textCount = selCount; |
|
|
|
nextX = painter.paintSelected(tempToken, g, nextX,y, host, |
|
|
|
nextX = painter.paintSelected(tempToken, g, nextX, y, host, |
|
|
|
this, clipStart); |
|
|
|
this, clipStart); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.makeStartAt(token.getOffset() + selCount); |
|
|
|
tempToken.makeStartAt(token.getOffset() + selCount); |
|
|
|
token = tempToken; |
|
|
|
token = tempToken; |
|
|
|
nextX = painter.paint(token, g, nextX,y, host, this, |
|
|
|
nextX = painter.paint(token, g, nextX, y, host, this, |
|
|
|
clipStart); |
|
|
|
clipStart); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -252,24 +263,24 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
else if (token.containsPosition(selEnd)) { |
|
|
|
else if (token.containsPosition(selEnd)) { |
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.copyFrom(token); |
|
|
|
tempToken.textCount = selEnd - tempToken.getOffset(); |
|
|
|
tempToken.textCount = selEnd - tempToken.getOffset(); |
|
|
|
nextX = painter.paintSelected(tempToken, g, nextX,y, host, this, |
|
|
|
nextX = painter.paintSelected(tempToken, g, nextX, y, host, this, |
|
|
|
clipStart); |
|
|
|
clipStart); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.textCount = token.length(); |
|
|
|
tempToken.makeStartAt(selEnd); |
|
|
|
tempToken.makeStartAt(selEnd); |
|
|
|
token = tempToken; |
|
|
|
token = tempToken; |
|
|
|
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); |
|
|
|
nextX = painter.paint(token, g, nextX, y, host, this, clipStart); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// This token is entirely selected
|
|
|
|
// This token is entirely selected
|
|
|
|
else if (token.getOffset()>=selStart && |
|
|
|
else if (token.getOffset() >= selStart && |
|
|
|
token.getEndOffset()<=selEnd) { |
|
|
|
token.getEndOffset() <= selEnd) { |
|
|
|
nextX = painter.paintSelected(token, g, nextX,y, host, this, |
|
|
|
nextX = painter.paintSelected(token, g, nextX, y, host, this, |
|
|
|
clipStart); |
|
|
|
clipStart); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// This token is entirely unselected
|
|
|
|
// This token is entirely unselected
|
|
|
|
else { |
|
|
|
else { |
|
|
|
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); |
|
|
|
nextX = painter.paint(token, g, nextX, y, host, this, clipStart); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
token = token.getNextToken(); |
|
|
|
token = token.getNextToken(); |
|
|
@ -298,10 +309,10 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
* @return The width of the line. |
|
|
|
* @return The width of the line. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private float getLineWidth(int lineNumber) { |
|
|
|
private float getLineWidth(int lineNumber) { |
|
|
|
Token tokenList = ((RSyntaxDocument)getDocument()). |
|
|
|
Token tokenList = ((RSyntaxDocument) getDocument()). |
|
|
|
getTokenListForLine(lineNumber); |
|
|
|
getTokenListForLine(lineNumber); |
|
|
|
return RSyntaxUtilities.getTokenListWidth(tokenList, |
|
|
|
return RSyntaxUtilities.getTokenListWidth(tokenList, |
|
|
|
(RSyntaxTextArea)getContainer(), |
|
|
|
(RSyntaxTextArea) getContainer(), |
|
|
|
this); |
|
|
|
this); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -320,8 +331,8 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
* SwingConstants.NORTH, or SwingConstants.SOUTH. |
|
|
|
* SwingConstants.NORTH, or SwingConstants.SOUTH. |
|
|
|
* @return the location within the model that best represents the next |
|
|
|
* @return the location within the model that best represents the next |
|
|
|
* location visual position. |
|
|
|
* location visual position. |
|
|
|
* @exception BadLocationException |
|
|
|
* @throws BadLocationException |
|
|
|
* @exception IllegalArgumentException for an invalid direction |
|
|
|
* @throws IllegalArgumentException for an invalid direction |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, |
|
|
|
public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, |
|
|
@ -341,7 +352,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
* Typically the view is told to render into the span |
|
|
|
* Typically the view is told to render into the span |
|
|
|
* that is returned, although there is no guarantee. |
|
|
|
* that is returned, although there is no guarantee. |
|
|
|
* The parent may choose to resize or break the view. |
|
|
|
* The parent may choose to resize or break the view. |
|
|
|
* @exception IllegalArgumentException for an invalid axis |
|
|
|
* @throws IllegalArgumentException for an invalid axis |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public float getPreferredSpan(int axis) { |
|
|
|
public float getPreferredSpan(int axis) { |
|
|
@ -357,13 +368,13 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
// We update lineHeight here as when this method is first
|
|
|
|
// We update lineHeight here as when this method is first
|
|
|
|
// called, lineHeight isn't initialized. If we don't do it
|
|
|
|
// called, lineHeight isn't initialized. If we don't do it
|
|
|
|
// here, we get no vertical scrollbar (as lineHeight==0).
|
|
|
|
// here, we get no vertical scrollbar (as lineHeight==0).
|
|
|
|
lineHeight = host!=null ? host.getLineHeight() : lineHeight; |
|
|
|
lineHeight = host != null ? host.getLineHeight() : lineHeight; |
|
|
|
// return getElement().getElementCount() * lineHeight;
|
|
|
|
// return getElement().getElementCount() * lineHeight;
|
|
|
|
int visibleLineCount = getElement().getElementCount(); |
|
|
|
int visibleLineCount = getElement().getElementCount(); |
|
|
|
if (host.isCodeFoldingEnabled()) { |
|
|
|
if (host.isCodeFoldingEnabled()) { |
|
|
|
visibleLineCount -= host.getFoldManager().getHiddenLineCount(); |
|
|
|
visibleLineCount -= host.getFoldManager().getHiddenLineCount(); |
|
|
|
} |
|
|
|
} |
|
|
|
return visibleLineCount * lineHeight; |
|
|
|
return visibleLineCount * lineHeight; |
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new IllegalArgumentException("Invalid axis: " + axis); |
|
|
|
throw new IllegalArgumentException("Invalid axis: " + axis); |
|
|
|
} |
|
|
|
} |
|
|
@ -378,7 +389,7 @@ return visibleLineCount * lineHeight; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private final int getRhsCorrection() { |
|
|
|
private final int getRhsCorrection() { |
|
|
|
int rhsCorrection = 10; |
|
|
|
int rhsCorrection = 10; |
|
|
|
if (host!=null) { |
|
|
|
if (host != null) { |
|
|
|
rhsCorrection = host.getRightHandSideCorrection(); |
|
|
|
rhsCorrection = host.getRightHandSideCorrection(); |
|
|
|
} |
|
|
|
} |
|
|
|
return rhsCorrection; |
|
|
|
return rhsCorrection; |
|
|
@ -391,7 +402,7 @@ return visibleLineCount * lineHeight; |
|
|
|
* @return The tab size. |
|
|
|
* @return The tab size. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private int getTabSize() { |
|
|
|
private int getTabSize() { |
|
|
|
Integer i = (Integer)getDocument().getProperty( |
|
|
|
Integer i = (Integer) getDocument().getProperty( |
|
|
|
PlainDocument.tabSizeAttribute); |
|
|
|
PlainDocument.tabSizeAttribute); |
|
|
|
int size = (i != null) ? i.intValue() : 5; |
|
|
|
int size = (i != null) ? i.intValue() : 5; |
|
|
|
return size; |
|
|
|
return size; |
|
|
@ -411,22 +422,21 @@ return visibleLineCount * lineHeight; |
|
|
|
* the document, <code>null</code> is returned. |
|
|
|
* the document, <code>null</code> is returned. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Token getTokenListForPhysicalLineAbove(int offset) { |
|
|
|
public Token getTokenListForPhysicalLineAbove(int offset) { |
|
|
|
RSyntaxDocument document = (RSyntaxDocument)getDocument(); |
|
|
|
RSyntaxDocument document = (RSyntaxDocument) getDocument(); |
|
|
|
Element map = document.getDefaultRootElement(); |
|
|
|
Element map = document.getDefaultRootElement(); |
|
|
|
int line = map.getElementIndex(offset); |
|
|
|
int line = map.getElementIndex(offset); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
if (fm==null) { |
|
|
|
if (fm == null) { |
|
|
|
line--; |
|
|
|
line--; |
|
|
|
if (line>=0) { |
|
|
|
if (line >= 0) { |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
line = fm.getVisibleLineAbove(line); |
|
|
|
line = fm.getVisibleLineAbove(line); |
|
|
|
if (line>=0) { |
|
|
|
if (line >= 0) { |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// int line = map.getElementIndex(offset) - 1;
|
|
|
|
// int line = map.getElementIndex(offset) - 1;
|
|
|
|
// if (line>=0)
|
|
|
|
// if (line>=0)
|
|
|
|
// return document.getTokenListForLine(line);
|
|
|
|
// return document.getTokenListForLine(line);
|
|
|
@ -447,22 +457,21 @@ else { |
|
|
|
* line in the document, <code>null</code> is returned. |
|
|
|
* line in the document, <code>null</code> is returned. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Token getTokenListForPhysicalLineBelow(int offset) { |
|
|
|
public Token getTokenListForPhysicalLineBelow(int offset) { |
|
|
|
RSyntaxDocument document = (RSyntaxDocument)getDocument(); |
|
|
|
RSyntaxDocument document = (RSyntaxDocument) getDocument(); |
|
|
|
Element map = document.getDefaultRootElement(); |
|
|
|
Element map = document.getDefaultRootElement(); |
|
|
|
int lineCount = map.getElementCount(); |
|
|
|
int lineCount = map.getElementCount(); |
|
|
|
int line = map.getElementIndex(offset); |
|
|
|
int line = map.getElementIndex(offset); |
|
|
|
if (!host.isCodeFoldingEnabled()) { |
|
|
|
if (!host.isCodeFoldingEnabled()) { |
|
|
|
if (line<lineCount-1) { |
|
|
|
if (line < lineCount - 1) { |
|
|
|
return document.getTokenListForLine(line+1); |
|
|
|
return document.getTokenListForLine(line + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
line = fm.getVisibleLineBelow(line); |
|
|
|
line = fm.getVisibleLineBelow(line); |
|
|
|
if (line>=0 && line<lineCount) { |
|
|
|
if (line >= 0 && line < lineCount) { |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
return document.getTokenListForLine(line); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// int line = map.getElementIndex(offset);
|
|
|
|
// int line = map.getElementIndex(offset);
|
|
|
|
// int lineCount = map.getElementCount();
|
|
|
|
// int lineCount = map.getElementCount();
|
|
|
|
// if (line<lineCount-1)
|
|
|
|
// if (line<lineCount-1)
|
|
|
@ -500,13 +509,13 @@ else { |
|
|
|
// NOTE: lineHeight is not initially set here, leading to the
|
|
|
|
// NOTE: lineHeight is not initially set here, leading to the
|
|
|
|
// current line not being highlighted when a document is first
|
|
|
|
// current line not being highlighted when a document is first
|
|
|
|
// opened. So, we set it here just in case.
|
|
|
|
// opened. So, we set it here just in case.
|
|
|
|
lineHeight = host!=null ? host.getLineHeight() : lineHeight; |
|
|
|
lineHeight = host != null ? host.getLineHeight() : lineHeight; |
|
|
|
if (host.isCodeFoldingEnabled()) { |
|
|
|
if (host != null && host.isCodeFoldingEnabled()) { |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
int hiddenCount = fm.getHiddenLineCountAbove(line); |
|
|
|
int hiddenCount = fm.getHiddenLineCountAbove(line); |
|
|
|
line -= hiddenCount; |
|
|
|
line -= hiddenCount; |
|
|
|
} |
|
|
|
} |
|
|
|
r = new Rectangle(alloc.x, alloc.y + line*lineHeight, |
|
|
|
r = new Rectangle(alloc.x, alloc.y + line * lineHeight, |
|
|
|
alloc.width, lineHeight); |
|
|
|
alloc.width, lineHeight); |
|
|
|
} |
|
|
|
} |
|
|
|
return r; |
|
|
|
return r; |
|
|
@ -520,7 +529,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* @param pos the position to convert >= 0 |
|
|
|
* @param pos the position to convert >= 0 |
|
|
|
* @param a the allocated region to render into |
|
|
|
* @param a the allocated region to render into |
|
|
|
* @return the bounding box of the given position |
|
|
|
* @return the bounding box of the given position |
|
|
|
* @exception BadLocationException if the given position does not |
|
|
|
* @throws BadLocationException if the given position does not |
|
|
|
* represent a valid location in the associated document |
|
|
|
* represent a valid location in the associated document |
|
|
|
* @see View#modelToView |
|
|
|
* @see View#modelToView |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -530,7 +539,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
|
|
|
|
|
|
|
|
// line coordinates
|
|
|
|
// line coordinates
|
|
|
|
Element map = getElement(); |
|
|
|
Element map = getElement(); |
|
|
|
RSyntaxDocument doc = (RSyntaxDocument)getDocument(); |
|
|
|
RSyntaxDocument doc = (RSyntaxDocument) getDocument(); |
|
|
|
int lineIndex = map.getElementIndex(pos); |
|
|
|
int lineIndex = map.getElementIndex(pos); |
|
|
|
Token tokenList = doc.getTokenListForLine(lineIndex); |
|
|
|
Token tokenList = doc.getTokenListForLine(lineIndex); |
|
|
|
Rectangle lineArea = lineToRect(a, lineIndex); |
|
|
|
Rectangle lineArea = lineToRect(a, lineIndex); |
|
|
@ -542,7 +551,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
// We use this method instead as it returns the actual bounding box,
|
|
|
|
// We use this method instead as it returns the actual bounding box,
|
|
|
|
// not just the x-coordinate.
|
|
|
|
// not just the x-coordinate.
|
|
|
|
lineArea = tokenList.listOffsetToView( |
|
|
|
lineArea = tokenList.listOffsetToView( |
|
|
|
(RSyntaxTextArea)getContainer(), this, pos, |
|
|
|
(RSyntaxTextArea) getContainer(), this, pos, |
|
|
|
tabBase, lineArea); |
|
|
|
tabBase, lineArea); |
|
|
|
|
|
|
|
|
|
|
|
return lineArea; |
|
|
|
return lineArea; |
|
|
@ -554,7 +563,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* Provides a mapping, for a given region, from the document model |
|
|
|
* Provides a mapping, for a given region, from the document model |
|
|
|
* coordinate space to the view coordinate space. The specified region is |
|
|
|
* coordinate space to the view coordinate space. The specified region is |
|
|
|
* created as a union of the first and last character positions.<p> |
|
|
|
* created as a union of the first and last character positions.<p> |
|
|
|
* |
|
|
|
* <p> |
|
|
|
* This is implemented to subtract the width of the second character, as |
|
|
|
* This is implemented to subtract the width of the second character, as |
|
|
|
* this view's <code>modelToView</code> actually returns the width of the |
|
|
|
* this view's <code>modelToView</code> actually returns the width of the |
|
|
|
* character instead of "1" or "0" like the View implementations in |
|
|
|
* character instead of "1" or "0" like the View implementations in |
|
|
@ -578,9 +587,9 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* @param a the area of the view, which encompasses the requested region |
|
|
|
* @param a the area of the view, which encompasses the requested region |
|
|
|
* @return the bounding box which is a union of the region specified |
|
|
|
* @return the bounding box which is a union of the region specified |
|
|
|
* by the first and last character positions |
|
|
|
* by the first and last character positions |
|
|
|
* @exception BadLocationException if the given position does |
|
|
|
* @throws BadLocationException if the given position does |
|
|
|
* not represent a valid location in the associated document |
|
|
|
* not represent a valid location in the associated document |
|
|
|
* @exception IllegalArgumentException if <code>b0</code> or |
|
|
|
* @throws IllegalArgumentException if <code>b0</code> or |
|
|
|
* <code>b1</code> are not one of the |
|
|
|
* <code>b1</code> are not one of the |
|
|
|
* legal <code>Position.Bias</code> values listed above |
|
|
|
* legal <code>Position.Bias</code> values listed above |
|
|
|
* @see View#viewToModel |
|
|
|
* @see View#viewToModel |
|
|
@ -592,7 +601,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
|
|
|
|
|
|
|
|
Shape s0 = modelToView(p0, a, b0); |
|
|
|
Shape s0 = modelToView(p0, a, b0); |
|
|
|
Shape s1; |
|
|
|
Shape s1; |
|
|
|
if (p1 ==getEndOffset()) { |
|
|
|
if (p1 == getEndOffset()) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
s1 = modelToView(p1, a, b1); |
|
|
|
s1 = modelToView(p1, a, b1); |
|
|
|
} catch (BadLocationException ble) { |
|
|
|
} catch (BadLocationException ble) { |
|
|
@ -600,20 +609,19 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
} |
|
|
|
} |
|
|
|
if (s1 == null) { |
|
|
|
if (s1 == null) { |
|
|
|
// Assume extends left to right.
|
|
|
|
// Assume extends left to right.
|
|
|
|
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : |
|
|
|
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : |
|
|
|
a.getBounds(); |
|
|
|
a.getBounds(); |
|
|
|
s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y, |
|
|
|
s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y, |
|
|
|
1, alloc.height); |
|
|
|
1, alloc.height); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
s1 = modelToView(p1, a, b1); |
|
|
|
s1 = modelToView(p1, a, b1); |
|
|
|
} |
|
|
|
} |
|
|
|
Rectangle r0 = s0 instanceof Rectangle ? (Rectangle)s0 : s0.getBounds(); |
|
|
|
Rectangle r0 = s0 instanceof Rectangle ? (Rectangle) s0 : s0.getBounds(); |
|
|
|
Rectangle r1 = s1 instanceof Rectangle ? (Rectangle)s1 : s1.getBounds(); |
|
|
|
Rectangle r1 = s1 instanceof Rectangle ? (Rectangle) s1 : s1.getBounds(); |
|
|
|
if (r0.y != r1.y) { |
|
|
|
if (r0.y != r1.y) { |
|
|
|
// If it spans lines, force it to be the width of the view.
|
|
|
|
// If it spans lines, force it to be the width of the view.
|
|
|
|
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : |
|
|
|
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : |
|
|
|
a.getBounds(); |
|
|
|
a.getBounds(); |
|
|
|
r0.x = alloc.x; |
|
|
|
r0.x = alloc.x; |
|
|
|
r0.width = alloc.width; |
|
|
|
r0.width = alloc.width; |
|
|
@ -627,7 +635,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
// this, one character too many is highlighted thanks to our
|
|
|
|
// this, one character too many is highlighted thanks to our
|
|
|
|
// modelToView() implementation returning the actual width of the
|
|
|
|
// modelToView() implementation returning the actual width of the
|
|
|
|
// character requested!
|
|
|
|
// character requested!
|
|
|
|
if (p1>p0) r0.width -= r1.width; |
|
|
|
if (p1 > p0) r0.width -= r1.width; |
|
|
|
|
|
|
|
|
|
|
|
return r0; |
|
|
|
return r0; |
|
|
|
|
|
|
|
|
|
|
@ -647,7 +655,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
public float nextTabStop(float x, int tabOffset) { |
|
|
|
public float nextTabStop(float x, int tabOffset) { |
|
|
|
if (tabSize == 0) |
|
|
|
if (tabSize == 0) |
|
|
|
return x; |
|
|
|
return x; |
|
|
|
int ntabs = (((int)x) - tabBase) / tabSize; |
|
|
|
int ntabs = (((int) x) - tabBase) / tabSize; |
|
|
|
return tabBase + ((ntabs + 1) * tabSize); |
|
|
|
return tabBase + ((ntabs + 1) * tabSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -662,12 +670,12 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void paint(Graphics g, Shape a) { |
|
|
|
public void paint(Graphics g, Shape a) { |
|
|
|
|
|
|
|
|
|
|
|
RSyntaxDocument document = (RSyntaxDocument)getDocument(); |
|
|
|
RSyntaxDocument document = (RSyntaxDocument) getDocument(); |
|
|
|
|
|
|
|
|
|
|
|
Rectangle alloc = a.getBounds(); |
|
|
|
Rectangle alloc = a.getBounds(); |
|
|
|
|
|
|
|
|
|
|
|
tabBase = alloc.x; |
|
|
|
tabBase = alloc.x; |
|
|
|
host = (RSyntaxTextArea)getContainer(); |
|
|
|
host = (RSyntaxTextArea) getContainer(); |
|
|
|
|
|
|
|
|
|
|
|
Rectangle clip = g.getClipBounds(); |
|
|
|
Rectangle clip = g.getClipBounds(); |
|
|
|
// An attempt to speed things up for files with long lines. Note that
|
|
|
|
// An attempt to speed things up for files with long lines. Note that
|
|
|
@ -695,52 +703,51 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
boolean useSelectedTextColor = host.getUseSelectedTextColor(); |
|
|
|
boolean useSelectedTextColor = host.getUseSelectedTextColor(); |
|
|
|
|
|
|
|
|
|
|
|
RSyntaxTextAreaHighlighter h = |
|
|
|
RSyntaxTextAreaHighlighter h = |
|
|
|
(RSyntaxTextAreaHighlighter)host.getHighlighter(); |
|
|
|
(RSyntaxTextAreaHighlighter) host.getHighlighter(); |
|
|
|
|
|
|
|
|
|
|
|
Graphics2D g2d = (Graphics2D)g; |
|
|
|
Graphics2D g2d = (Graphics2D) g; |
|
|
|
Token token; |
|
|
|
Token token; |
|
|
|
//System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1));
|
|
|
|
//System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1));
|
|
|
|
|
|
|
|
|
|
|
|
TokenPainter painter = host.getTokenPainter(); |
|
|
|
TokenPainter painter = host.getTokenPainter(); |
|
|
|
int line = linesAbove; |
|
|
|
int line = linesAbove; |
|
|
|
//int count = 0;
|
|
|
|
//int count = 0;
|
|
|
|
while (y<clip.y+clip.height+ascent && line<lineCount) { |
|
|
|
while (y < clip.y + clip.height + ascent && line < lineCount) { |
|
|
|
|
|
|
|
|
|
|
|
Fold fold = fm.getFoldForLine(line); |
|
|
|
Fold fold = fm.getFoldForLine(line); |
|
|
|
Element lineElement = map.getElement(line); |
|
|
|
Element lineElement = map.getElement(line); |
|
|
|
int startOffset = lineElement.getStartOffset(); |
|
|
|
int startOffset = lineElement.getStartOffset(); |
|
|
|
//int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 :
|
|
|
|
//int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 :
|
|
|
|
// lineElement.getEndOffset()-1);
|
|
|
|
// lineElement.getEndOffset()-1);
|
|
|
|
int endOffset = lineElement.getEndOffset()-1; // Why always "-1"?
|
|
|
|
int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"?
|
|
|
|
h.paintLayeredHighlights(g2d, startOffset, endOffset, |
|
|
|
h.paintLayeredHighlights(g2d, startOffset, endOffset, |
|
|
|
a, host, this); |
|
|
|
a, host, this); |
|
|
|
|
|
|
|
|
|
|
|
// Paint a line of text.
|
|
|
|
// Paint a line of text.
|
|
|
|
token = document.getTokenListForLine(line); |
|
|
|
token = document.getTokenListForLine(line); |
|
|
|
if (!useSelectedTextColor || selStart==selEnd || |
|
|
|
if (!useSelectedTextColor || selStart == selEnd || |
|
|
|
(startOffset>=selEnd || endOffset<selStart)) { |
|
|
|
(startOffset >= selEnd || endOffset < selStart)) { |
|
|
|
drawLine(painter, token, g2d, x,y); |
|
|
|
drawLine(painter, token, g2d, x, y); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
//System.out.println("Drawing line with selection: " + line);
|
|
|
|
//System.out.println("Drawing line with selection: " + line);
|
|
|
|
drawLineWithSelection(painter,token,g2d, x,y, selStart, selEnd); |
|
|
|
drawLineWithSelection(painter, token, g2d, x, y, selStart, selEnd); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fold!=null && fold.isCollapsed()) { |
|
|
|
if (fold != null && fold.isCollapsed()) { |
|
|
|
|
|
|
|
|
|
|
|
// Visible indicator of collapsed lines
|
|
|
|
// Visible indicator of collapsed lines
|
|
|
|
Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); |
|
|
|
Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); |
|
|
|
if (c!=null) { |
|
|
|
if (c != null) { |
|
|
|
g.setColor(c); |
|
|
|
g.setColor(c); |
|
|
|
g.drawLine(x,y+lineHeight-ascent-1, |
|
|
|
g.drawLine(x, y + lineHeight - ascent - 1, |
|
|
|
alloc.width,y+lineHeight-ascent-1); |
|
|
|
alloc.width, y + lineHeight - ascent - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Skip to next line to paint, taking extra care for lines with
|
|
|
|
// Skip to next line to paint, taking extra care for lines with
|
|
|
|
// block ends and begins together, e.g. "} else {"
|
|
|
|
// block ends and begins together, e.g. "} else {"
|
|
|
|
do { |
|
|
|
do { |
|
|
|
int hiddenLineCount = fold.getLineCount(); |
|
|
|
int hiddenLineCount = fold.getLineCount(); |
|
|
|
if (hiddenLineCount==0) { |
|
|
|
if (hiddenLineCount == 0) { |
|
|
|
// Fold parser identified a zero-line fold region.
|
|
|
|
// Fold parser identified a zero-line fold region.
|
|
|
|
// This is really a bug, but we'll be graceful here
|
|
|
|
// This is really a bug, but we'll be graceful here
|
|
|
|
// and avoid an infinite loop.
|
|
|
|
// and avoid an infinite loop.
|
|
|
@ -748,7 +755,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
} |
|
|
|
} |
|
|
|
line += hiddenLineCount; |
|
|
|
line += hiddenLineCount; |
|
|
|
fold = fm.getFoldForLine(line); |
|
|
|
fold = fm.getFoldForLine(line); |
|
|
|
} while (fold!=null && fold.isCollapsed()); |
|
|
|
} while (fold != null && fold.isCollapsed()); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -824,7 +831,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
if (added != null) { |
|
|
|
if (added != null) { |
|
|
|
int addedAt = ec.getIndex(); // FIXME: Is this correct?????
|
|
|
|
int addedAt = ec.getIndex(); // FIXME: Is this correct?????
|
|
|
|
for (int i = 0; i < added.length; i++) |
|
|
|
for (int i = 0; i < added.length; i++) |
|
|
|
possiblyUpdateLongLine(added[i], addedAt+i); |
|
|
|
possiblyUpdateLongLine(added[i], addedAt + i); |
|
|
|
} |
|
|
|
} |
|
|
|
if (removed != null) { |
|
|
|
if (removed != null) { |
|
|
|
for (int i = 0; i < removed.length; i++) { |
|
|
|
for (int i = 0; i < removed.length; i++) { |
|
|
@ -841,14 +848,12 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
|
|
|
|
|
|
|
|
// This occurs when syntax highlighting only changes on lines
|
|
|
|
// This occurs when syntax highlighting only changes on lines
|
|
|
|
// (i.e. beginning a multiline comment).
|
|
|
|
// (i.e. beginning a multiline comment).
|
|
|
|
else if (changes.getType()==DocumentEvent.EventType.CHANGE) { |
|
|
|
else if (changes.getType() == DocumentEvent.EventType.CHANGE) { |
|
|
|
//System.err.println("Updating the damage due to a CHANGE event...");
|
|
|
|
//System.err.println("Updating the damage due to a CHANGE event...");
|
|
|
|
int startLine = changes.getOffset(); |
|
|
|
int startLine = changes.getOffset(); |
|
|
|
int endLine = changes.getLength(); |
|
|
|
int endLine = changes.getLength(); |
|
|
|
damageLineRange(startLine,endLine, a, host); |
|
|
|
damageLineRange(startLine, endLine, a, host); |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
Element map = getElement(); |
|
|
|
Element map = getElement(); |
|
|
|
int line = map.getElementIndex(changes.getOffset()); |
|
|
|
int line = map.getElementIndex(changes.getOffset()); |
|
|
|
damageLineRange(line, line, a, host); |
|
|
|
damageLineRange(line, line, a, host); |
|
|
@ -861,14 +866,12 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
// because it has gotten longer.
|
|
|
|
// because it has gotten longer.
|
|
|
|
longLineWidth = getLineWidth(line); |
|
|
|
longLineWidth = getLineWidth(line); |
|
|
|
preferenceChanged(null, true, false); |
|
|
|
preferenceChanged(null, true, false); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
|
|
|
|
// If long line gets updated, update the status bars too.
|
|
|
|
// If long line gets updated, update the status bars too.
|
|
|
|
if (possiblyUpdateLongLine(e, line)) |
|
|
|
if (possiblyUpdateLongLine(e, line)) |
|
|
|
preferenceChanged(null, true, false); |
|
|
|
preferenceChanged(null, true, false); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (changes.getType() == DocumentEvent.EventType.REMOVE) { |
|
|
|
else if (changes.getType() == DocumentEvent.EventType.REMOVE) { |
|
|
|
|
|
|
|
if (map.getElement(line) == longLine) { |
|
|
|
if (map.getElement(line) == longLine) { |
|
|
|
// removed from longest line... recalc
|
|
|
|
// removed from longest line... recalc
|
|
|
|
longLineWidth = -1; // Must do this!
|
|
|
|
longLineWidth = -1; // Must do this!
|
|
|
@ -884,7 +887,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* Checks to see if the font metrics and longest line are up-to-date. |
|
|
|
* Checks to see if the font metrics and longest line are up-to-date. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private void updateMetrics() { |
|
|
|
private void updateMetrics() { |
|
|
|
host = (RSyntaxTextArea)getContainer(); |
|
|
|
host = (RSyntaxTextArea) getContainer(); |
|
|
|
Font f = host.getFont(); |
|
|
|
Font f = host.getFont(); |
|
|
|
if (font != f) { |
|
|
|
if (font != f) { |
|
|
|
// The font changed, we need to recalculate the longest line!
|
|
|
|
// The font changed, we need to recalculate the longest line!
|
|
|
@ -910,7 +913,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
bias[0] = Position.Bias.Forward; |
|
|
|
bias[0] = Position.Bias.Forward; |
|
|
|
|
|
|
|
|
|
|
|
Rectangle alloc = a.getBounds(); |
|
|
|
Rectangle alloc = a.getBounds(); |
|
|
|
RSyntaxDocument doc = (RSyntaxDocument)getDocument(); |
|
|
|
RSyntaxDocument doc = (RSyntaxDocument) getDocument(); |
|
|
|
int x = (int) fx; |
|
|
|
int x = (int) fx; |
|
|
|
int y = (int) fy; |
|
|
|
int y = (int) fy; |
|
|
|
|
|
|
|
|
|
|
@ -936,9 +939,9 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
|
|
|
|
|
|
|
|
Element map = doc.getDefaultRootElement(); |
|
|
|
Element map = doc.getDefaultRootElement(); |
|
|
|
int lineIndex = Math.abs((y - alloc.y) / lineHeight);//metrics.getHeight() );
|
|
|
|
int lineIndex = Math.abs((y - alloc.y) / lineHeight);//metrics.getHeight() );
|
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
//System.out.print("--- " + lineIndex);
|
|
|
|
//System.out.print("--- " + lineIndex);
|
|
|
|
lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); |
|
|
|
lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); |
|
|
|
//System.out.println(" => " + lineIndex);
|
|
|
|
//System.out.println(" => " + lineIndex);
|
|
|
|
if (lineIndex >= map.getElementCount()) { |
|
|
|
if (lineIndex >= map.getElementCount()) { |
|
|
|
return host.getLastVisibleOffset(); |
|
|
|
return host.getLastVisibleOffset(); |
|
|
@ -960,9 +963,9 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); |
|
|
|
Token tokenList = doc.getTokenListForLine(lineIndex); |
|
|
|
Token tokenList = doc.getTokenListForLine(lineIndex); |
|
|
|
tabBase = alloc.x; |
|
|
|
tabBase = alloc.x; |
|
|
|
int offs = tokenList.getListOffset( |
|
|
|
int offs = tokenList.getListOffset( |
|
|
|
(RSyntaxTextArea)getContainer(), |
|
|
|
(RSyntaxTextArea) getContainer(), |
|
|
|
this, tabBase, x); |
|
|
|
this, tabBase, x); |
|
|
|
return offs!=-1 ? offs : p0; |
|
|
|
return offs != -1 ? offs : p0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} // End of else.
|
|
|
|
} // End of else.
|
|
|
@ -981,11 +984,13 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); |
|
|
|
// NOTE: lineHeight is not initially set here, leading to the
|
|
|
|
// NOTE: lineHeight is not initially set here, leading to the
|
|
|
|
// current line not being highlighted when a document is first
|
|
|
|
// current line not being highlighted when a document is first
|
|
|
|
// opened. So, we set it here just in case.
|
|
|
|
// opened. So, we set it here just in case.
|
|
|
|
lineHeight = host!=null ? host.getLineHeight() : lineHeight; |
|
|
|
lineHeight = host != null ? host.getLineHeight() : lineHeight; |
|
|
|
|
|
|
|
if (host != null) { |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
if (!fm.isLineHidden(line)) { |
|
|
|
if (!fm.isLineHidden(line)) { |
|
|
|
line -= fm.getHiddenLineCountAbove(line); |
|
|
|
line -= fm.getHiddenLineCountAbove(line); |
|
|
|
return alloc.y + line*lineHeight; |
|
|
|
return alloc.y + line * lineHeight; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|