decorate origin usage differently to fix IDEA-161015 Suggest UI to visually indicate the current usage in 'Show Usages' popup

This commit is contained in:
Alexey Kudravtsev
2018-05-16 17:54:58 +03:00
parent 0f881f4f3b
commit 4e134ca378
4 changed files with 106 additions and 76 deletions
@@ -18,10 +18,12 @@ package com.intellij.openapi.editor.colors;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.ui.ColorUtil;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.List;
public abstract class EditorColorsManager {
@@ -81,4 +83,9 @@ public abstract class EditorColorsManager {
public EditorColorsScheme getSchemeForCurrentUITheme() {
return getGlobalScheme();
}
public boolean isDarkEditor() {
Color bg = getGlobalScheme().getDefaultBackground();
return ColorUtil.isDark(bg);
}
}
@@ -16,10 +16,13 @@
package com.intellij.find.actions;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.VfsPresentationUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.ui.GuiUtils;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
@@ -44,8 +47,6 @@ import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.util.concurrent.atomic.AtomicInteger;
import static com.intellij.openapi.vfs.newvfs.VfsPresentationUtil.getFileBackgroundColor;
/**
* @author cdr
*/
@@ -71,18 +72,20 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer {
Color panelBackground = isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor;
Color panelForeground = isSelected ? fg : list.getForeground();
SimpleColoredComponent textChunks = new SimpleColoredComponent();
if (usageNode == null || usageNode instanceof ShowUsagesAction.StringNode) {
SimpleColoredComponent textChunks = new SimpleColoredComponent();
textChunks.append(ObjectUtils.notNull(value, "").toString(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list);
}
if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) {
SimpleColoredComponent textChunks = new SimpleColoredComponent();
textChunks.append("...<");
textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
textChunks.append(">...");
return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list);
}
if (usage == ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) {
SimpleColoredComponent textChunks = new SimpleColoredComponent();
textChunks.append("...<");
textChunks.append(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
textChunks.append(">...");
@@ -105,48 +108,64 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer {
panel.setBackground(panelBackground);
panel.setForeground(panelForeground);
// greying the current usage you originated your "find usages" from is turned off by @nik orders
boolean isEnabled = true;//!myUsageView.isOriginUsage(usage);
if (!isEnabled) {
fg = UIUtil.getLabelDisabledForeground();
// greying the current usage the "find usages" was originated from
boolean isOriginUsage = myUsageView.isOriginUsage(usage);
if (isOriginUsage) {
panel.setBackground(slightlyDifferentBackground(panelBackground));
if (fileBgColor != null) {
fileBgColor = slightlyDifferentBackground(fileBgColor);
}
bg = slightlyDifferentBackground(bg);
}
if (column == 0) {
appendGroupText(list, (GroupNode)usageNode.getParent(), panel, fileBgColor, isSelected);
appendGroupText(list, (GroupNode)usageNode.getParent(), panel, fileBgColor, isSelected, isOriginUsage);
}
else {
if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR && usage != ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) {
UsagePresentation presentation = usage.getPresentation();
TextChunk[] text = presentation.getText();
SimpleColoredComponent textChunks = new SimpleColoredComponent();
UsagePresentation presentation = usage.getPresentation();
TextChunk[] text = presentation.getText();
if (lineNumberColumn) { // line number
if (text.length != 0) {
TextChunk chunk = text[0];
textChunks.append(chunk.getText(), getAttributes(isSelected, fileBgColor, bg, fg, chunk));
}
}
else if (column == 2) {
Icon icon = presentation.getIcon();
textChunks.setIcon(icon == null ? EmptyIcon.ICON_16 : icon);
textChunks.append("").appendTextPadding(JBUI.scale(16 + 5));
for (int i = 1; i < text.length; i++) {
TextChunk chunk = text[i];
textChunks.append(chunk.getText(), getAttributes(isSelected, fileBgColor, bg, fg, chunk));
}
}
else {
assert false : column;
if (lineNumberColumn) { // line number
if (text.length != 0) {
TextChunk chunk = text[0];
textChunks.append(chunk.getText(), getAttributes(isSelected, fileBgColor, bg, fg, chunk));
}
}
else if (column == 2) {
Icon icon = presentation.getIcon();
textChunks.setIcon(icon == null ? EmptyIcon.ICON_16 : icon);
textChunks.append("").appendTextPadding(JBUI.scale(16 + 5));
for (int i = 1; i < text.length; i++) {
TextChunk chunk = text[i];
textChunks.append(chunk.getText(), getAttributes(isSelected, fileBgColor, bg, fg, chunk));
}
}
else {
assert false : column;
}
SpeedSearchUtil.applySpeedSearchHighlighting(list, textChunks, false, isSelected);
panel.add(textChunks);
if (isOriginUsage && column == 2) {
SimpleColoredComponent origin = new SimpleColoredComponent();
origin.setIconTextGap(JBUI.scale(5)); // for this particular icon it looks better
origin.setIcon(AllIcons.General.ComboArrowLeftPassive);
origin.append("Current");
panel.add(origin);
}
}
if (!isEnabled) {
GuiUtils.enableChildren(panel, false);
}
return panel;
}
@NotNull
private static Color slightlyDifferentBackground(@NotNull Color back) {
// dunno, under the dark theme the "brighter,1" doesn't look bright enough so we use 3
return EditorColorsManager.getInstance().isDarkEditor() ? ColorUtil.brighter(back, 3) : ColorUtil.darker(back, 1);
}
@NotNull
private static SimpleTextAttributes getAttributes(boolean isSelected, Color fileBgColor, Color bg, Color fg, @NotNull TextChunk chunk) {
SimpleTextAttributes background = chunk.getSimpleAttributesIgnoreBackground();
@@ -173,8 +192,6 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer {
}
g.translate(-offset, 0);
//if (column == columnModel.getColumnCount()-1) {
//}
setSize(getWidth()+offset, getHeight()); // should increase the column width so that selection background will be visible even after offset translation
super.doPaint(g);
@@ -222,18 +239,23 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer {
VirtualFile virtualFile = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() : null;
if (virtualFile != null) {
Project project = myUsageView.getProject();
Color color = getFileBackgroundColor(project, virtualFile);
Color color = VfsPresentationUtil.getFileBackgroundColor(project, virtualFile);
if (color != null) fileBgColor = color;
}
}
return fileBgColor;
}
private void appendGroupText(JTable table, final GroupNode node, JPanel panel, Color fileBgColor, boolean isSelected) {
private void appendGroupText(@NotNull JTable table,
final GroupNode node,
@NotNull JPanel panel,
Color fileBgColor,
boolean isSelected,
boolean isOriginUsage) {
UsageGroup group = node == null ? null : node.getGroup();
if (group == null) return;
GroupNode parentGroup = (GroupNode)node.getParent();
appendGroupText(table, parentGroup, panel, fileBgColor, isSelected);
appendGroupText(table, parentGroup, panel, fileBgColor, isSelected, isOriginUsage);
if (node.canNavigateToSource()) {
SimpleColoredComponent renderer = new SimpleColoredComponent();
renderer.setIcon(group.getIcon(false));
@@ -57,28 +57,30 @@ public class ColorUtil {
};
}
@NotNull
public static Color softer(@NotNull Color color) {
if (color.getBlue() > 220 && color.getRed() > 220 && color.getGreen() > 220) return color;
final float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
return Color.getHSBColor(hsb[0], 0.6f * hsb[1], hsb[2]);
}
@NotNull
public static Color darker(@NotNull Color color, int tones) {
final float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
float brightness = hsb[2];
for (int i = 0; i < tones; i++) {
brightness = Math.max(0, brightness / 1.1F);
if (brightness == 0) break;
}
return Color.getHSBColor(hsb[0], hsb[1], brightness);
return hackBrightness(color, tones, 1 / 1.1F);
}
@NotNull
public static Color brighter(@NotNull Color color, int tones) {
return hackBrightness(color, tones, 1.1F);
}
@NotNull
private static Color hackBrightness(@NotNull Color color, int howMuch, float hackValue) {
final float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
float brightness = hsb[2];
for (int i = 0; i < tones; i++) {
brightness = Math.min(1, brightness * 1.1F);
if (brightness == 1) break;
for (int i = 0; i < howMuch; i++) {
brightness = Math.min(1, Math.max(0, brightness * hackValue));
if (brightness == 0 || brightness == 1) break;
}
return Color.getHSBColor(hsb[0], hsb[1], brightness);
}
@@ -105,6 +107,7 @@ public class ColorUtil {
return Color.getHSBColor(hsb[0], saturation, hsb[2]);
}
@NotNull
public static Color dimmer(@NotNull Color color) {
float[] rgb = color.getRGBColorComponents(null);
@@ -118,19 +121,21 @@ public class ColorUtil {
return n > 255 ? 255 : n < 0 ? 0 : n;
}
public static Color shift(Color c, double d) {
@NotNull
public static Color shift(@NotNull Color c, double d) {
return new Color(shift(c.getRed(), d), shift(c.getGreen(), d), shift(c.getBlue(), d), c.getAlpha());
}
public static Color withAlpha(Color c, double a) {
@NotNull
public static Color withAlpha(@NotNull Color c, double a) {
return toAlpha(c, (int)(255 * a));
}
public static Color srcOver(Color c, Color b) {
@NotNull
static Color srcOver(@NotNull Color c, @NotNull Color b) {
float [] rgba = new float[4];
float [] brgba = new float[4];
rgba = c.getRGBComponents(rgba);
float[] brgba = new float[4];
brgba = b.getRGBComponents(brgba);
float dsta = 1.0f - rgba[3];
// Applying SrcOver rule
@@ -139,22 +144,21 @@ public class ColorUtil {
rgba[2]*rgba[3] + dsta*brgba[2], 1.0f);
}
public static Color withPreAlpha(Color c, double a) {
@NotNull
public static Color withPreAlpha(@NotNull Color c, double a) {
float [] rgba = new float[4];
rgba = withAlpha(c, a).getRGBComponents(rgba);
return new Color(rgba[0]*rgba[3], rgba[1]*rgba[3], rgba[2]*rgba[3], 1.0f);
}
public static Color toAlpha(Color color, int a) {
Color c = color != null ? color : Color.black;
@NotNull
public static Color toAlpha(@Nullable Color color, int a) {
Color c = color == null ? Color.black : color;
return new Color(c.getRed(), c.getGreen(), c.getBlue(), a);
}
public static Color withAlphaAdjustingDarkness(Color c, double d) {
return shift(withAlpha(c, d), d);
}
@NotNull
public static String toHex(@NotNull final Color c) {
final String R = Integer.toHexString(c.getRed());
final String G = Integer.toHexString(c.getGreen());
@@ -162,6 +166,7 @@ public class ColorUtil {
return (R.length() < 2 ? "0" : "") + R + (G.length() < 2 ? "0" : "") + G + (B.length() < 2 ? "0" : "") + B;
}
@NotNull
public static String toHtmlColor(@NotNull final Color c) {
return "#"+toHex(c);
}
@@ -176,7 +181,8 @@ public class ColorUtil {
* @param str hex string
* @return Color object
*/
public static Color fromHex(String str) {
@NotNull
public static Color fromHex(@NotNull String str) {
str = StringUtil.trimStart(str, "#");
if (str.length() == 3) {
return new Color(
@@ -193,7 +199,7 @@ public class ColorUtil {
}
@Nullable
public static Color fromHex(String str, @Nullable Color defaultValue) {
public static Color fromHex(@NotNull String str, @Nullable Color defaultValue) {
try {
return fromHex(str);
}
@@ -218,9 +224,9 @@ public class ColorUtil {
* @param c color to check
* @return dark or not
*/
public static boolean isDark(@NotNull final Color c) {
public static boolean isDark(@NotNull Color c) {
// based on perceptional luminosity, see
return (1 - (0.299 * c.getRed() + 0.587 * c.getGreen() + 0.114 * c.getBlue()) / 255) >= 0.5;
return 1 - (0.299 * c.getRed() + 0.587 * c.getGreen() + 0.114 * c.getBlue()) / 255 >= 0.5;
}
@NotNull
@@ -142,23 +142,18 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
return -1;
}
private static boolean isDarkEditor() {
Color bg = EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground();
return ColorUtil.isDark(bg);
}
public static TextAttributes getNormalAttributes() {
private static TextAttributes getNormalAttributes() {
TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES);
if (attributes == null || attributes.getForegroundColor() == null) {
return new TextAttributes(new JBColor(() -> isDarkEditor() ? new Color(0x3d8065) : Gray._135), null, null, null, Font.ITALIC);
return new TextAttributes(new JBColor(() -> EditorColorsManager.getInstance().isDarkEditor() ? new Color(0x3d8065) : Gray._135), null, null, null, Font.ITALIC);
}
return attributes;
}
public static TextAttributes getChangedAttributes() {
private static TextAttributes getChangedAttributes() {
TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES_MODIFIED);
if (attributes == null || attributes.getForegroundColor() == null) {
return new TextAttributes(new JBColor(() -> isDarkEditor() ? new Color(0xa1830a) : new Color(0xca8021)), null, null, null, Font.ITALIC);
return new TextAttributes(new JBColor(() -> EditorColorsManager.getInstance().isDarkEditor() ? new Color(0xa1830a) : new Color(0xca8021)), null, null, null, Font.ITALIC);
}
return attributes;
}
@@ -167,7 +162,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(DebuggerColors.INLINED_VALUES_EXECUTION_LINE);
if (attributes == null || attributes.getForegroundColor() == null) {
//noinspection UseJBColor
return new TextAttributes(isDarkEditor() ? new Color(255, 235, 9) : new Color(0, 255, 86), null, null, null, Font.ITALIC);
return new TextAttributes(EditorColorsManager.getInstance().isDarkEditor() ? new Color(255, 235, 9) : new Color(0, 255, 86), null, null, null, Font.ITALIC);
}
return attributes;
}
@@ -205,7 +200,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
private String old;
private int valueNodeHashCode;
public VariableValue(String actual, String old, int valueNodeHashCode) {
VariableValue(String actual, String old, int valueNodeHashCode) {
this.actual = actual;
this.old = old;
this.valueNodeHashCode = valueNodeHashCode;
@@ -215,7 +210,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
return old != null && !StringUtil.equals(actual, old);
}
public void produceChangedParts(List<LineExtensionInfo> result) {
void produceChangedParts(List<? super LineExtensionInfo> result) {
if (isArray(actual) && isArray(old)) {
List<String> actualParts = getArrayParts(actual);
List<String> oldParts = getArrayParts(old);
@@ -248,7 +243,7 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
private static class VariableText {
final List<LineExtensionInfo> infos = new ArrayList<>();
int length = 0;
int length;
void add(LineExtensionInfo info) {
infos.add(info);