I was wondering if there is a straightforward way to display line numbers with StyledText
text field - even if lines are wrapped. I'm using it in my application and if content gets to big, some line numbers would be nice.
Thank you.
I was wondering if there is a straightforward way to display line numbers with StyledText
text field - even if lines are wrapped. I'm using it in my application and if content gets to big, some line numbers would be nice.
Thank you.
The key is org.eclipse.swt.custom.Bullet. It's basically a symbol (or in our case a number) you can add to the beginning of a line.
//text is your StyledText
text.addLineStyleListener(new LineStyleListener()
{
public void lineGetStyle(LineStyleEvent e)
{
//Set the line number
e.bulletIndex = text.getLineAtOffset(e.lineOffset);
//Set the style, 12 pixles wide for each digit
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, Integer.toString(text.getLineCount()+1).length()*12);
//Create and set the bullet
e.bullet = new Bullet(ST.BULLET_NUMBER,style);
}
});
This is my working implementation.
styledText.addLineStyleListener(new LineStyleListener() {
@Override
public void lineGetStyle(LineStyleEvent event) {
// Using ST.BULLET_NUMBER sometimes results in weird alignment.
//event.bulletIndex = styledText.getLineAtOffset(event.lineOffset);
StyleRange styleRange = new StyleRange();
styleRange.foreground = Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
int maxLine = styledText.getLineCount();
int bulletLength = Integer.toString(maxLine).length();
// Width of number character is half the height in monospaced font, add 1 character width for right padding.
int bulletWidth = (bulletLength + 1) * styledText.getLineHeight() / 2;
styleRange.metrics = new GlyphMetrics(0, 0, bulletWidth);
event.bullet = new Bullet(ST.BULLET_TEXT, styleRange);
// getLineAtOffset() returns a zero-based line index.
int bulletLine = styledText.getLineAtOffset(event.lineOffset) + 1;
event.bullet.text = String.format("%" + bulletLength + "s", bulletLine);
}
});
styledText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
// For line number redrawing.
styledText.redraw();
}
});
Note that the possible overhead of syntax highlighting recalculation when calling redraw() is likely to be acceptable, because lineGetStyle() are only called with lines currently on screen.
I believe that using a LineStyleListener should work. Something along the lines of:
styledText.addLineStyleListener(
new LineStyleListener() {
@Override
public void lineGetStyle(LineStyleEvent event) {
String line = event.lineText;
int lineNumber = event.lineOffset;
// Do stuff to add line numbers
}
}
);
This is a way to use bullets that updates the numbers when the content changes:
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
int maxLine = text.getLineCount();
int lineCountWidth = Math.max(String.valueOf(maxLine).length(), 3);
StyleRange style = new StyleRange();
style.metrics = new GlyphMetrics(0, 0, lineCountWidth * 8 + 5);
Bullet bullet = new Bullet(ST.BULLET_NUMBER, style);
text.setLineBullet(0, text.getLineCount(), null);
text.setLineBullet(0, text.getLineCount(), bullet);
}
});
As a side-note for colouring the line numbers:
Device device = Display.getCurrent();
style.background = new Color(device, LINE_NUMBER_BG);
style.foreground = new Color(device, LINE_NUMBER_FG);
where LINE_NUMBER_BG
and LINE_NUMBER_FG
might be a RGB object such as:
final RGB LINE_NUMBER_BG = new RBG(160, 80, 0); // brown
final RGB LINE_NUMBER_FG = new RGB(255, 255, 255); // white