Skip to content

Commit

Permalink
Fix bobbylight#534, bobbylight#106 Customizable token painting
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbylight committed Feb 17, 2024
1 parent 79ddef3 commit b1e8364
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
*
* @author Robert Futrell
* @version 1.0
* @see VisibleWhitespaceTokenPainter
*/
class DefaultTokenPainter implements TokenPainter {
public class DefaultTokenPainter implements TokenPainter {

/**
* Rectangle used for filling token backgrounds.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* This library is distributed under a modified BSD license. See the included
* LICENSE file for details.
*/
package org.fife.ui.rsyntaxtextarea;


/**
* Standard implementation of a token painter factory.
*
* @author Robert Futrell
* @version 1.0
* @see DefaultTokenPainter
* @see VisibleWhitespaceTokenPainter
*/
public class DefaultTokenPainterFactory implements TokenPainterFactory {


@Override
public TokenPainter getTokenPainter(RSyntaxTextArea textArea) {
return textArea.isWhitespaceVisible() ? new VisibleWhitespaceTokenPainter() :
new DefaultTokenPainter();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
* <li>Protobuf files
* <li>Python
* <li>Ruby
* <li>Rust
* <li>SAS
* <li>Scala
* <li>SQL
Expand Down Expand Up @@ -324,6 +325,9 @@ public class RSyntaxTextArea extends RTextArea implements SyntaxConstants {

private boolean insertPairedCharacters;

private TokenPainterFactory tokenPainterFactory;


/**
* Constructor.
*/
Expand Down Expand Up @@ -797,6 +801,17 @@ protected RTextAreaUI createRTextAreaUI() {
}


/**
* Called whenever whitespace visibility changes. Returns the
* token painter to use for this text area.
*
* @return The token painter to use.
*/
protected TokenPainter createTokenPainter() {
return tokenPainterFactory.getTokenPainter(this);
}


/**
* If the caret is on a bracket, this method finds the matching bracket,
* and if it exists, highlights it.
Expand Down Expand Up @@ -2018,7 +2033,8 @@ protected void init() {
super.init();
metricsNeverRefreshed = true;

tokenPainter = new DefaultTokenPainter();
tokenPainterFactory = new DefaultTokenPainterFactory();
tokenPainter = tokenPainterFactory.getTokenPainter(this);

// NOTE: Our actions are created here instead of in a static block
// so they are only created when the first RTextArea is instantiated,
Expand Down Expand Up @@ -3190,6 +3206,18 @@ public void setTabLineColor(Color c) {
}


/**
* Sets the token painter factory to use.
*
* @param tpf The new token painter factory. This should not
* be {@code null}.
*/
public void setTokenPainterFactory(TokenPainterFactory tpf) {
tokenPainterFactory = tpf;
tokenPainter = createTokenPainter();
}


/**
* Sets whether "focusable" tool tips are used instead of standard ones.
* Focusable tool tips are tool tips that the user can click on,
Expand Down Expand Up @@ -3238,8 +3266,7 @@ public void setUseSelectedTextColor(boolean use) {
public void setWhitespaceVisible(boolean visible) {
if (whitespaceVisible!=visible) {
this.whitespaceVisible = visible;
tokenPainter = visible ? new VisibleWhitespaceTokenPainter() :
new DefaultTokenPainter();
tokenPainter = createTokenPainter();
repaint();
firePropertyChange(VISIBLE_WHITESPACE_PROPERTY, !visible, visible);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* @author Robert Futrell
* @version 1.0
*/
interface TokenPainter {
public interface TokenPainter {


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* This library is distributed under a modified BSD license. See the included
* LICENSE file for details.
*/
package org.fife.ui.rsyntaxtextarea;


/**
* Returns the {@link TokenPainter} to use for a text area.
*
* @author Robert Futrell
* @version 1.0
*/
public interface TokenPainterFactory {


/**
* Returns the text area to use.
*
* @param textArea The text area.
* @return The token painter.
*/
TokenPainter getTokenPainter(RSyntaxTextArea textArea);


}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@
*
* @author Robert Futrell
* @version 1.0
* @see DefaultTokenPainter
*/
class VisibleWhitespaceTokenPainter extends DefaultTokenPainter {
public class VisibleWhitespaceTokenPainter extends DefaultTokenPainter {


@Override
Expand Down Expand Up @@ -77,9 +78,9 @@ protected float paintImpl(Token token, Graphics2D g, float x, float y,

// Fill in background.
nextX = x+fm.charsWidth(text, flushIndex,flushLen);
float nextNextX = e.nextTabStop(nextX, 0);
float nextTabStop = e.nextTabStop(nextX, 0);
if (bg!=null) {
paintBackground(x,y, nextNextX-x,height, g,
paintBackground(x,y, nextTabStop-x,height, g,
ascent, host, bg);
}
g.setColor(fg);
Expand All @@ -91,15 +92,8 @@ protected float paintImpl(Token token, Graphics2D g, float x, float y,
}
flushIndex = i + 1;

// Draw an arrow representing the tab.
int halfHeight = height / 2;
int quarterHeight = halfHeight / 2;
int ymid = (int)y - ascent + halfHeight;
g.drawLine((int)nextX,ymid, (int)nextNextX,ymid);
g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid-quarterHeight);
g.drawLine((int)nextNextX,ymid, (int)nextNextX-4,ymid+quarterHeight);

x = nextNextX;
paintTabText(g, nextX, y, nextTabStop, ascent, height);
x = nextTabStop;
break;

case ' ':
Expand Down Expand Up @@ -130,10 +124,7 @@ protected float paintImpl(Token token, Graphics2D g, float x, float y,
flushLen = 0;
}

// Paint a dot representing the space.
int dotX = (int)(nextX - width/2f); // "2.0f" for FindBugs
int dotY = (int)(y - ascent + height/2f); // Ditto
g.drawLine(dotX, dotY, dotX, dotY);
paintSpaceText(g, nextX, y, ascent, width, height);
flushIndex = i + 1;
x = nextX;
break;
Expand Down Expand Up @@ -179,4 +170,45 @@ protected float paintImpl(Token token, Graphics2D g, float x, float y,
}


/**
* Draws the textual indication of a space, i.e. a single dot. The
* background has already been filled in properly, and the foreground
* color properly set.
*
* @param g The graphics context.
* @param x The x-value at which to paint.
* @param y The y-value of the current line.
* @param ascent The ascent of the current font.
* @param width The width of the space character.
* @param height The height of the current line of text being painted.
*/
protected void paintSpaceText(Graphics2D g, float x, float y, int ascent,
int width, int height) {
int dotX = (int)(x - width/2f);
int dotY = (int)(y - ascent + height/2f);
g.drawLine(dotX, dotY, dotX, dotY);
}


/**
* Draws the text representing a tab. The background has already been
* filled in if necessary, and the foreground color properly set.
*
* @param g The graphics context.
* @param x The x-value at which to paint.
* @param y The y-value of the current line.
* @param nextTabStop Where the next tab stop would start.
* @param ascent The ascent of the current font.
* @param height The height of the line of text being painted.
*/
protected void paintTabText(Graphics2D g, float x, float y,
float nextTabStop, int ascent, int height) {
int x2 = (int)nextTabStop - 3;
if (x2 >= (int)x) {
int halfHeight = height / 2;
int ymid = (int) y - ascent + halfHeight;
g.drawLine((int) x, ymid, x2, ymid);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This library is distributed under a modified BSD license. See the included
* LICENSE file for details.
*/
package org.fife.ui.rsyntaxtextarea;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


/**
* Unit tests for the {@link DefaultTokenPainterFactory} class.
*
* @author Robert Futrell
* @version 1.0
*/
class DefaultTokenPainterFactoryTest extends AbstractRSyntaxTextAreaTest {

private RSyntaxTextArea textArea;
private DefaultTokenPainterFactory factory;


@BeforeEach
void setUp() {
textArea = createTextArea();
factory = new DefaultTokenPainterFactory();
}


@Test
void testGetTokenPainter_dontShowWhitespace() {
Assertions.assertEquals(DefaultTokenPainter.class,
factory.getTokenPainter(textArea).getClass());
}


@Test
void testGetTokenPainter_showWhitespace() {
textArea.setWhitespaceVisible(true);
Assertions.assertEquals(VisibleWhitespaceTokenPainter.class,
factory.getTokenPainter(textArea).getClass());
}
}

0 comments on commit b1e8364

Please sign in to comment.