IDEA-161827 use line metrics to align text effects

This commit is contained in:
Sergey Malenkov
2016-10-06 21:31:28 +03:00
parent 66330b5317
commit 132aa8f787
5 changed files with 91 additions and 63 deletions
@@ -830,18 +830,18 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co
// 1. Strikeout effect
if (attributes.isStrikeout() && !attributes.isSearchMatch()) {
EffectPainter.STRIKE_THROUGH.paint(g, offset, textBaseline, fragmentWidth, getCharHeight(g), null);
EffectPainter.STRIKE_THROUGH.paint(g, offset, textBaseline, fragmentWidth, getCharHeight(g), font);
}
// 2. Waved effect
if (attributes.isWaved()) {
if (attributes.getWaveColor() != null) {
g.setColor(attributes.getWaveColor());
}
EffectPainter.WAVE_UNDERSCORE.paint(g, offset, textBaseline + 1, fragmentWidth, Math.max(2, metrics.getDescent()), null);
EffectPainter.WAVE_UNDERSCORE.paint(g, offset, textBaseline + 1, fragmentWidth, Math.max(2, metrics.getDescent()), font);
}
// 3. Underline
if (attributes.isUnderline()) {
EffectPainter.LINE_UNDERSCORE.paint(g, offset, textBaseline, fragmentWidth, metrics.getDescent(), null);
EffectPainter.LINE_UNDERSCORE.paint(g, offset, textBaseline, fragmentWidth, metrics.getDescent(), font);
}
// 4. Bold Dotted Line
if (attributes.isBoldDottedLine()) {
@@ -885,7 +885,7 @@ public class SimpleColoredComponent extends JComponent implements Accessible, Co
g.drawString(text, x1, baseline);
if (((SimpleTextAttributes)info[5]).isStrikeout()) {
EffectPainter.STRIKE_THROUGH.paint(g, x1, baseline, x2 - x1, getCharHeight(g), null);
EffectPainter.STRIKE_THROUGH.paint(g, x1, baseline, x2 - x1, getCharHeight(g), g.getFont());
}
}
return offset;
@@ -15,7 +15,6 @@
*/
package com.intellij.ui.paint;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.JBHiDPIScaledImage;
import com.intellij.util.ui.JBUI;
@@ -24,6 +23,7 @@ import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.WavePainter;
import java.awt.*;
import java.awt.font.LineMetrics;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.concurrent.ConcurrentHashMap;
@@ -31,7 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* @author Sergey.Malenkov
*/
public enum EffectPainter implements RegionPainter<Paint> {
public enum EffectPainter implements RegionPainter<Font> {
/**
* @see com.intellij.openapi.editor.markup.EffectType#LINE_UNDERSCORE
*/
@@ -44,17 +44,15 @@ public enum EffectPainter implements RegionPainter<Paint> {
* @param y text baseline
* @param width text width
* @param height available space under text
* @param paint optional color patterns
* @param font optional font to calculate line metrics
*/
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Paint paint) {
public void paint(Graphics2D g, int x, int y, int width, int height, Font font) {
if (!Registry.is("ide.text.effect.new")) {
if (paint != null) g.setPaint(paint);
g.drawLine(x, y + 1, x + width, y + 1);
}
else if (width > 0 && height > 0) {
if (paint != null) g.setPaint(paint);
drawLineUnderscore(g, x, y, width, height, 1, this);
drawLineUnderscore(g, x, y, width, height, font, 1, this);
}
}
},
@@ -70,18 +68,16 @@ public enum EffectPainter implements RegionPainter<Paint> {
* @param y text baseline
* @param width text width
* @param height available space under text
* @param paint optional color patterns
* @param font optional font to calculate line metrics
*/
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Paint paint) {
public void paint(Graphics2D g, int x, int y, int width, int height, Font font) {
if (!Registry.is("ide.text.effect.new")) {
if (paint != null) g.setPaint(paint);
int h = JBUI.scale(Registry.intValue("editor.bold.underline.height", 2));
g.fillRect(x, y, width, h);
}
else if (width > 0 && height > 0) {
if (paint != null) g.setPaint(paint);
drawLineUnderscore(g, x, y, width, height, 2, this);
drawLineUnderscore(g, x, y, width, height, font, 2, this);
}
}
},
@@ -97,16 +93,12 @@ public enum EffectPainter implements RegionPainter<Paint> {
* @param y text baseline
* @param width text width
* @param height available space under text
* @param paint optional color patterns
* @param font optional font to calculate line metrics
*/
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Paint paint) {
if (!Registry.is("ide.text.effect.new")) {
UIUtil.drawBoldDottedLine(g, x, x + width, SystemInfo.isMac ? y : y + 1, g.getColor(), (Color)paint, false);
}
else if (width > 0 && height > 0) {
if (paint != null) g.setPaint(paint);
drawLineUnderscore(g, x, y, width, height, 2, this);
public void paint(Graphics2D g, int x, int y, int width, int height, Font font) {
if (width > 0 && height > 0) {
drawLineUnderscore(g, x, y, width, height, font, 2, this);
}
}
},
@@ -122,16 +114,15 @@ public enum EffectPainter implements RegionPainter<Paint> {
* @param y text baseline
* @param width text width
* @param height available space under text
* @param paint optional color patterns
* @param font optional font to calculate line metrics
*/
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Paint paint) {
public void paint(Graphics2D g, int x, int y, int width, int height, Font font) {
if (!Registry.is("ide.text.effect.new")) {
if (paint != null) g.setPaint(paint);
WavePainter.forColor(g.getColor()).paint(g, x, x + width, y + height);
}
else if (width > 0 && height > 0) {
Cached.WAVE_UNDERSCORE.paint(g, x, y, width, height, paint);
Cached.WAVE_UNDERSCORE.paint(g, x, y, width, height, null);
}
}
},
@@ -147,13 +138,21 @@ public enum EffectPainter implements RegionPainter<Paint> {
* @param y text baseline
* @param width text width
* @param height text height
* @param paint optional color patterns
* @param font optional font to calculate line metrics
*/
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Paint paint) {
public void paint(Graphics2D g, int x, int y, int width, int height, Font font) {
if (width > 0 && height > 0) {
if (paint != null) g.setPaint(paint);
drawLineCentered(g, x, y - height, width, height, 1, this);
if (!Registry.is("ide.text.effect.new.metrics")) {
drawLineCentered(g, x, y - height, width, height, 1, this);
}
else {
if (font == null) font = g.getFont();
LineMetrics metrics = font.getLineMetrics("", g.getFontRenderContext());
int offset = (int)(0.5 - metrics.getStrikethroughOffset());
int thickness = Math.max(1, (int)(0.5 + metrics.getStrikethroughThickness()));
drawLine(g, x, y - offset, width, thickness, this);
}
}
}
};
@@ -162,16 +161,28 @@ public enum EffectPainter implements RegionPainter<Paint> {
return height > 7 && Registry.is("ide.text.effect.new.scale") ? height >> 1 : 3;
}
private static void drawLineUnderscore(Graphics2D g, int x, int y, int width, int height, int thickness, EffectPainter painter) {
if (height > 3) {
int max = getMaxHeight(height);
y += height - max;
height = max;
if (thickness > 1 && height > 3) {
thickness = JBUI.scale(thickness);
private static void drawLineUnderscore(Graphics2D g, int x, int y, int width, int height, Font font, int thickness,
EffectPainter painter) {
if (width > 0 && height > 0) {
if (Registry.is("ide.text.effect.new.metrics")) {
if (font == null) font = g.getFont();
LineMetrics metrics = font.getLineMetrics("", g.getFontRenderContext());
int offset = Math.max(1, (int)(0.5 + metrics.getUnderlineOffset()));
thickness = Math.max(thickness, (int)(0.5 + thickness * metrics.getUnderlineThickness()));
drawLine(g, x, y + offset, width, thickness, painter);
}
else {
if (height > 3) {
int max = getMaxHeight(height);
y += height - max;
height = max;
if (thickness > 1 && height > 3) {
thickness = JBUI.scale(thickness);
}
}
drawLineCentered(g, x, y, width, height, thickness, painter);
}
}
drawLineCentered(g, x, y, width, height, thickness, painter);
}
private static void drawLineCentered(Graphics2D g, int x, int y, int width, int height, int thickness, EffectPainter painter) {
@@ -180,6 +191,10 @@ public enum EffectPainter implements RegionPainter<Paint> {
y += offset - (offset >> 1);
height = thickness;
}
drawLine(g, x, y, width, height, painter);
}
private static void drawLine(Graphics2D g, int x, int y, int width, int height, EffectPainter painter) {
if (painter == BOLD_DOTTED_UNDERSCORE) {
int dx = (x % height + height) % height;
int w = width + dx;
@@ -2456,21 +2456,26 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
if (attributes != null && attributes.getEffectColor() != null) {
int y = visibleLineToY(visibleStartLine) + getAscent() + 1;
g.setColor(attributes.getEffectColor());
if (attributes.getEffectType() == EffectType.WAVE_UNDERSCORE) {
EffectPainter.WAVE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(), attributes.getEffectColor());
EffectPainter.WAVE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (attributes.getEffectType() == EffectType.BOLD_DOTTED_LINE) {
g.setColor(getBackgroundColor(attributes));
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(), attributes.getEffectColor());
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (attributes.getEffectType() == EffectType.STRIKEOUT) {
EffectPainter.STRIKE_THROUGH.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getCharHeight(), attributes.getEffectColor());
EffectPainter.STRIKE_THROUGH.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getCharHeight(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (attributes.getEffectType() == EffectType.BOLD_LINE_UNDERSCORE) {
EffectPainter.BOLD_LINE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(), attributes.getEffectColor());
EffectPainter.BOLD_LINE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (attributes.getEffectType() != EffectType.BOXED) {
EffectPainter.LINE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(), attributes.getEffectColor());
EffectPainter.LINE_UNDERSCORE.paint((Graphics2D)g, end.x, y - 1, charWidth - 1, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
}
}
@@ -3568,6 +3573,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (effectColor != null) {
final Color savedColor = g.getColor();
g.setColor(effectColor);
// myBorderEffect.flushIfCantProlong(g, this, effectType, effectColor);
int xEnd = x;
@@ -3583,25 +3589,26 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
if (effectType == EffectType.LINE_UNDERSCORE) {
EffectPainter.LINE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(), effectColor);
g.setColor(savedColor);
EffectPainter.LINE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.BOLD_LINE_UNDERSCORE) {
EffectPainter.BOLD_LINE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(), effectColor);
g.setColor(savedColor);
EffectPainter.BOLD_LINE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.STRIKEOUT) {
EffectPainter.STRIKE_THROUGH.paint((Graphics2D)g, xStart, y, xEnd - xStart, getCharHeight(), effectColor);
g.setColor(savedColor);
EffectPainter.STRIKE_THROUGH.paint((Graphics2D)g, xStart, y, xEnd - xStart, getCharHeight(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.WAVE_UNDERSCORE) {
EffectPainter.WAVE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(), effectColor);
g.setColor(savedColor);
EffectPainter.WAVE_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.BOLD_DOTTED_LINE) {
g.setColor(getBackgroundColor());
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(), effectColor);
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint((Graphics2D)g, xStart, y, xEnd - xStart, getDescent(),
getColorsScheme().getFont(EditorFontType.PLAIN));
}
g.setColor(savedColor);
}
return x;
@@ -431,26 +431,30 @@ class EditorPainter implements TextDrawingCallback {
}
private void paintTextEffect(Graphics2D g, float xFrom, float xTo, int y, Color effectColor, EffectType effectType, boolean allowBorder) {
g.setColor(effectColor);
int xStart = (int)xFrom;
int xEnd = (int)xTo;
if (effectType == EffectType.LINE_UNDERSCORE) {
EffectPainter.LINE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(), effectColor);
EffectPainter.LINE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(),
myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.BOLD_LINE_UNDERSCORE) {
EffectPainter.BOLD_LINE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(), effectColor);
EffectPainter.BOLD_LINE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(),
myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.STRIKEOUT) {
EffectPainter.STRIKE_THROUGH.paint(g, xStart, y, xEnd - xStart, myView.getCharHeight(), effectColor);
EffectPainter.STRIKE_THROUGH.paint(g, xStart, y, xEnd - xStart, myView.getCharHeight(),
myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.WAVE_UNDERSCORE) {
EffectPainter.WAVE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(), effectColor);
EffectPainter.WAVE_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(),
myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (effectType == EffectType.BOLD_DOTTED_LINE) {
g.setColor(myEditor.getBackgroundColor());
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(), effectColor);
EffectPainter.BOLD_DOTTED_UNDERSCORE.paint(g, xStart, y, xEnd - xStart, myView.getDescent(),
myEditor.getColorsScheme().getFont(EditorFontType.PLAIN));
}
else if (allowBorder && (effectType == EffectType.BOXED || effectType == EffectType.ROUNDED_BOX)) {
g.setColor(effectColor);
drawSimpleBorder(g, xStart, xEnd - 1, y - myView.getAscent(), effectType == EffectType.ROUNDED_BOX);
}
}
@@ -830,6 +830,8 @@ ide.text.effect.new=true
ide.text.effect.new.description=Enables new effect painter for text
ide.text.effect.new.scale=true
ide.text.effect.new.scale.description=Enables scalable effect painter for text
ide.text.effect.new.metrics=true
ide.text.effect.new.metrics.description=Use line metrics to calculate text offset in the effect painter
ide.intellij.laf.win10.ui=false
ide.intellij.laf.win10.ui.description=Enables Windows 10 look