Code
class RoundedSelectionHighlightPainter extends DefaultHighlightPainter {
protected RoundedSelectionHighlightPainter() {
super(null);
}
@Override public void paint(
Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int rgba = c.getSelectionColor().getRGB() & 0xFF_FF_FF | (64 << 24);
g2.setColor(new Color(rgba, true));
try {
Area area = getLinesArea(c, offs0, offs1);
for (Area a : GeomUtils.singularization(area)) {
List<Point2D> lst = GeomUtils.convertAreaToPoint2DList(a);
GeomUtils.flatteningStepsOnRightSide(lst, 3d * 2d);
g2.fill(GeomUtils.convertRoundedPath(lst, 3d));
}
} catch (BadLocationException ex) {
// can't render
Logger.getGlobal().severe(ex::getMessage);
}
g2.dispose();
}
private static Area getLinesArea(JTextComponent c, int offs0, int offs1)
throws BadLocationException {
TextUI mapper = c.getUI();
Area area = new Area();
int cur = offs0;
do {
int startOffset = Utilities.getRowStart(c, cur);
int endOffset = Utilities.getRowEnd(c, cur);
Rectangle p0 = mapper.modelToView(c, Math.max(startOffset, offs0));
Rectangle p1 = mapper.modelToView(c, Math.min(endOffset, offs1));
if (offs1 > endOffset) {
p1.width += 6;
}
addRectToArea(area, p0.union(p1));
cur = endOffset + 1;
} while (cur < offs1);
return area;
}
private static void addRectToArea(Area area, Rectangle rect) {
area.add(new Area(rect));
}
}
class RoundedSelectionCaret extends DefaultCaret {
@Override protected HighlightPainter getSelectionPainter() {
return new RoundedSelectionHighlightPainter();
}
@SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel")
@Override protected synchronized void damage(Rectangle r) {
JTextComponent c = getComponent();
int startOffset = c.getSelectionStart();
int endOffset = c.getSelectionEnd();
if (startOffset == endOffset) {
super.damage(r);
} else {
TextUI mapper = c.getUI();
try {
Rectangle p0 = mapper.modelToView(c, startOffset);
Rectangle p1 = mapper.modelToView(c, endOffset);
int h = (int) (p1.getMaxY() - p0.getMinY());
c.repaint(new Rectangle(0, p0.y, c.getWidth(), h));
} catch (BadLocationException ex) {
UIManager.getLookAndFeel().provideErrorFeedback(c);
}
}
}
}
References