/* LanguageTool, a natural language style checker
* Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package org.languagetool.gui;
import javax.swing.text.*;
import java.awt.*;
/**
* Wavy underline painter.
* @since 3.3
*/
class HighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
private static final BasicStroke OO_STROKE1 = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, new float[]{3.0f, 5.0f}, 2);
private static final BasicStroke OO_STROKE2 = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, new float[]{1.0f, 3.0f}, 3);
private static final BasicStroke OO_STROKE3 = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, new float[]{3.0f, 5.0f}, 6);
private static final BasicStroke ZIGZAG_STROKE1 = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, new float[]{1.0f, 1.0f}, 0);
private final Color underlineColor;
private final Color backgroundColor;
HighlightPainter(Color backgroundColor, Color underlineColor) {
super(backgroundColor);
this.backgroundColor = backgroundColor;
this.underlineColor = underlineColor;
}
@Override
public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view) {
if (backgroundColor != null) {
super.paintLayer(g, offs0, offs1, bounds, c, view);
}
Rectangle rect;
if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
if (bounds instanceof Rectangle) {
rect = (Rectangle) bounds;
} else {
rect = bounds.getBounds();
}
} else {
try {
Shape shape = view.modelToView(offs0, Position.Bias.Forward, offs1, Position.Bias.Backward, bounds);
rect = shape instanceof Rectangle ? (Rectangle) shape : shape.getBounds();
} catch (BadLocationException e) {
rect = null;
}
}
if (rect != null) {
Color color = underlineColor;
if (color == null) {
g.setColor(c.getSelectionColor());
} else {
g.setColor(color);
}
rect.width = Math.max(rect.width, 1);
int descent = c.getFontMetrics(c.getFont()).getDescent();
if (descent > 3) {
drawCurvedLine(g, rect);
} else if (descent > 2) {
drawCurvedLine(g, rect);
} else {
drawLine(g, rect);
}
}
return rect;
}
private void drawCurvedLine(Graphics g, Rectangle rect) {
int x1 = rect.x;
int x2 = rect.x + rect.width;
int y = rect.y + rect.height;
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(OO_STROKE1);
g2.drawLine(x1, y - 1, x2, y - 1);
g2.setStroke(OO_STROKE2);
g2.drawLine(x1, y - 2, x2, y - 2);
g2.setStroke(OO_STROKE3);
g2.drawLine(x1, y - 3, x2, y - 3);
}
private void drawLine(Graphics g, Rectangle rect) {
int x1 = rect.x;
int x2 = rect.x + rect.width;
int y = rect.y + rect.height;
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(ZIGZAG_STROKE1);
g2.drawLine(x1, y - 1, x2, y - 1);
}
}