Different Styles in PlainView - Syntax Highlighting?

Hi,

I've managed to extend PlainView and looking at old JEdit code I have the syntax highlighting working for the most part. However, at certain times while typing the cursor starts to get way ahead of the text it's typing. And as I backspace on the line the cursor eventually gets closer to the character the closer it gets to the start of the line.

I'm overridding the "drawUnselectedText()" method in PlainView to do the coloring.

Here's the code, you can see the call to SyntaxUtilities.paintSyntaxLine() which is JEdit's class to do the drawing.

/**

* Renders the given range in the model as normal unselected text. This

* is implemented to paint colors based upon the token-to-color

* translations. To reduce the number of calls to the Graphics object,

* text is batched up until a color change is detected or the entire

* requested range has been reached.

*

* @param g

*the graphics context

* @param x

*the starting X coordinate

* @param y

*the starting Y coordinate

* @param p0

*the beginning position in the model

* @param p1

*the ending position in the model

* @returns the location of the end of the range

* @exception BadLocationException

*if the range is invalid

*/

protectedint drawUnselectedText(Graphics g,int x,int y,int p0,int p1)throws BadLocationException{

System.out.println("p0: " + p0 +" p1: " + p1 +" x: " + x +" y: " + y);

// Get the start of the element

int lineIndex = doc.getDefaultRootElement().getElementIndex(p0);

// Get the element for the line

Element elem = doc.getDefaultRootElement().getElement(lineIndex);

System.out.println("lineIndex: " + lineIndex +" elemStartIDX: " + elem.getStartOffset() +" elemEndIDX: " + elem.getEndOffset());

// Get the line text

doc.getText(p0, p1 - p0, currentLineText);

// If highlighting, mark the tokens

if (marker !=null){

Token t = marker.markTokens(currentLineText, lineIndex);

x = SyntaxUtilities.paintSyntaxLine(currentLineText, t, styles, this, g, x, y, p0, p1);

System.out.println("Painted line at: " + x);

}else{

// No highlighting requested, draw normal text

Font defaultFont = g.getFont();

Color defaultColor = styles[0].getColor();// Default color of text

g.setFont(defaultFont);

g.setColor(defaultColor);

x = Utilities.drawTabbedText(currentLineText, x, y, g, this, p0);

}

// Set the last line processed

lastLine = lineIndex;

return x;

}

Here is the code from the paintSyntaxLine() method:

/**

* Paints the specified line onto the graphics context. Note that this

* method munges the offset and count values of the segment.

*

* @param line

*The line segment

* @param tokens

*The token list for the line

* @param styles

*The syntax style list

* @param expander

*The tab expander used to determine tab stops. May be null

* @param gfx

*The graphics context

* @param x

*The x co-ordinate

* @param y

*The y co-ordinate

* @return The x co-ordinate, plus the width of the painted string

*/

publicstaticint paintSyntaxLine(Segment line, Token tokens, SyntaxStyle[] styles, TabExpander expander, Graphics gfx,int x,int y,int p0,int p1){

Font defaultFont = gfx.getFont();

Color defaultColor = Color.black;

FontMetrics fm = gfx.getFontMetrics(defaultFont);

int offset = 0;

while (tokens !=null && tokens.id != Token.END){

int length = tokens.length;

if (tokens.id == Token.NULL){

if (!defaultColor.equals(gfx.getColor()))

gfx.setColor(defaultColor);

if (!defaultFont.equals(gfx.getFont()))

gfx.setFont(defaultFont);

}else{

styles[tokens.id].setGraphicsFlags(gfx, defaultFont);

//fm = gfx.getFontMetrics();//[tokens.id].getStyledFont(defaultFont);

//FontMetrics dfm = Toolkit.getDefaultToolkit().getFontMetrics(defaultFont);

//System.out.println("Font Info: CharWidth[" + fm.charWidth(line.array[p1])+"], Max Advance[" + fm.getMaxAdvance()+"]");

//System.out.println("Default Font Info: CharWidth[" + dfm.charWidth(line.array[p1])+"], DMax Advance[" + dfm.getMaxAdvance()+"]");

////x = fm.charsWidth(line.array, p0, length);

}

line.count = length;

x = Utilities.drawTabbedText(line, x, y, gfx, expander, p0);

line.offset += length;

offset += length;

tokens = tokens.next;

}

return x;

}

I'm not sure what the problem is..i thought it might be an issue with the View and drawing multiple font styles. Since plain view only deals with a single font color and size. I tried using LabelView but that seems to need a StyledDocument and I had problems when I tried to use DefaultStyledDocument for my syntaxdocument. I was getting strange offset issues when using the Segment class.

Here's what I posted: http://forum.java.sun.com/thread.jspa?threadID=780801

I am using PlainDocument because that seemed to be what everyone was using for a syntax editor..since the structure of the document in a Plain Document is less complex.

I orginally started out using the setCharacterAttributes() method on the DefaultStyledDocument and letting the views draw the text. That all seemed to work except for the "segment offset" issue. And I wasn't sure where the best spot to get the document to redraw subsequent lines in the case of changing a multiline comment, etc.

So, everything I read about others attempts for syntax highlighters seems to use either StyledEditorKit with a fixed language set with custom parsing and using the setCharacterAttributes method. Or they use the plaindocument approach with a custom view..(which no one seems to share the source) or the project just simply uses the JEditTextArea directly (which we can't do in our product).

We don't need multiple fonts per-line.. The document will always use one font face (Arial, Helvetica, etc) but may use different styles per word (bold, italic, etc).

I thought I'd need to use FontMetrics to get the size of the font and such. But there didn't seem to be a difference in measurements based on the style of the font. (i.,e A bold font has the same charWidth('m') size as a regular style.

At least that's what my test program showed..

The other thing I noticed is that when the document is successfully colored and I use the mouse to select a region of text, the style of the text reverts back to normal. I'm sure that's because I only override the drawUnselectedText() method.

Any ideas? Is there anyone who has successfully done this?

Thanks,

- Tim

[8846 byte] By [tmullea] at [2007-10-3 9:21:26]
# 1

Are you using anti-aliasing? I ran into a similar problem, with the caret getting farther out of sync with the letters the farther it got from the left margin, and AA turned out to be the cause (unlike bold and italic styles, AA does affect the size of the text). Try making sure anti-aliasing is not being used (under JDK 5, make sure the "swing.aatext" system property is not set), and see if the problem persists.

Are you really using proportional fonts? I've never even tried that. It probably isn't relevant to your caret-positioning problem, but you might try switching to a monospaced font (I like "Bitstream Vera Sans Mono" the best).

uncle_alicea at 2007-7-15 4:34:55 > top of Java-index,Desktop,Core GUI APIs...
# 2

Hi Uncle_Alice:

I'm running this under jdk 1.4.2 when I see the problem. It appears that JDK 5 works fine regardless of the font face I use. In 1.4.2 if I use a MonoSpaced font it seems to work fine. but fonts like 'Dialog' cause the cursor to run away.

That's why I thought it might be fontmetrics related.

Unfortunately, I need to make sure this all works under both 1.4.2 and 1.5+

Are you able to post or email your view classes? I recall you saying you went down this same path with the Plain and WrappedPlainView.

Thanks again,

- Tim

tmullea at 2007-7-15 4:34:55 > top of Java-index,Desktop,Core GUI APIs...
# 3

I just tried using a proportional font in my editor, and now I'm seeing your runaway-caret problem. Specifically, the caret remains in sync with the text as long as no bold characters are encountered, but it gets noticeably farther out of whack with each bold character it passes. I suspect that, when you measured the charWidth, your FontMetrics object wasn't really based on a bold font, because bold versions of proportional fonts are larger. And of course, the model/view conversion methods assume that the same style of the same font is used throughout the document. I've never had to deal with that problem, since I've always used monospaced fonts by preference, and bold versions of monospaced fonts really are the same size as the non-bold versions. I suggest you do the same, because getting this to work with proportional fonts look like a major hassle.

uncle_alicea at 2007-7-15 4:34:55 > top of Java-index,Desktop,Core GUI APIs...