[vcs-log] big labels redesign

* no more borders (flat labels);
* 2 variants of label design: round with flags or square underlined;
* improve colors (they do not make my eyes bleed anymore);
* unify hg and git colors;
* rewrite reference painter;
* labels scale with increasing ui font;
* group labels by root in branches panel.
This commit is contained in:
Julia Beliaeva
2015-08-27 17:54:12 +03:00
parent 5dbe3518bf
commit 92a54c928d
13 changed files with 403 additions and 350 deletions
@@ -237,6 +237,7 @@ vcs.showConsole=true
vcs.log.bek.sort=true
vcs.log.bek.sort.disabled=false
vcs.log.linear.bek.sort=false
vcs.log.square.labels=false
vcs.executable.validator.timeout.sec=60
@@ -1,8 +1,5 @@
package com.intellij.vcs.log.printer.idea;
/**
* @author erokhins
*/
public class PrintParameters {
public static final int WIDTH_NODE = 15;
@@ -11,4 +8,5 @@ public class PrintParameters {
public static final float THICK_LINE = 1.5f;
public static final float SELECT_THICK_LINE = 2.5f;
public static final int LABEL_PADDING = 3;
}
@@ -0,0 +1,32 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.vcs.log;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.JBColor;
import java.awt.*;
public class VcsLogStandardColors {
public static class Refs {
public static final Color TIP = new JBColor(new Color(0xedea74), new Color(113, 111, 64));
public static final Color LEAF = new JBColor(new Color(0xf478cc), new Color(0x6e2857));
public static final Color BRANCH = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F));
public static final Color BRANCH_REF = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker());
public static final Color TAG =
new JBColor(ColorUtil.darker(new Color(255, 255, 255), 1), ColorUtil.brighter(new Color(60, 63, 65), 3));
}
}
@@ -23,16 +23,4 @@ public interface VcsLogColorManager {
*/
boolean isMultipleRoots();
/**
* Returns the color of the border drawn around a reference label.
*/
@NotNull
Color getReferenceBorderColor();
/**
* Returns the color of the border separating the thin root indicator drawn at the left of the commit table.
*/
@NotNull
Color getRootIndicatorBorder();
}
@@ -1,9 +1,11 @@
package com.intellij.vcs.log.ui;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.JBColor;
import com.intellij.util.NotNullProducer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -16,15 +18,10 @@ import java.util.List;
* @author Kirill Likhodedov
*/
public class VcsLogColorManagerImpl implements VcsLogColorManager {
private static final Color REF_BORDER = JBColor.GRAY;
private static final Color ROOT_INDICATOR_BORDER = JBColor.LIGHT_GRAY;
private static final Logger LOG = Logger.getInstance(VcsLogColorManagerImpl.class);
private static Color[] ROOT_COLORS = {
JBColor.RED, JBColor.GREEN, JBColor.BLUE,
JBColor.ORANGE, JBColor.CYAN, JBColor.YELLOW,
JBColor.MAGENTA, JBColor.PINK};
private static Color[] ROOT_COLORS =
{JBColor.RED, JBColor.GREEN, JBColor.BLUE, JBColor.ORANGE, JBColor.CYAN, JBColor.YELLOW, JBColor.MAGENTA, JBColor.PINK};
@NotNull private final List<VirtualFile> myRoots;
@@ -56,6 +53,30 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager {
}
}
@NotNull
public static JBColor getBackgroundVersion(@NotNull final Color rootColor) {
return new JBColor(new NotNullProducer<Color>() {
@NotNull
@Override
public Color produce() {
return ColorUtil.mix(rootColor, UIUtil.getTableBackground(), 0.75);
}
});
}
@NotNull
public static JBColor getIndicatorVersion(@NotNull final Color rootColor) {
if (Registry.is("vcs.log.square.labels")) return getBackgroundVersion(rootColor);
return new JBColor(new NotNullProducer<Color>() {
@NotNull
@Override
public Color produce() {
if (UIUtil.isUnderDarcula()) return rootColor;
return ColorUtil.darker(ColorUtil.softer(rootColor), 2);
}
});
}
@Override
public boolean isMultipleRoots() {
return myRoots.size() > 1;
@@ -75,17 +96,4 @@ public class VcsLogColorManagerImpl implements VcsLogColorManager {
private static Color getDefaultRootColor() {
return UIUtil.getTableBackground();
}
@NotNull
@Override
public Color getReferenceBorderColor() {
return REF_BORDER;
}
@NotNull
@Override
public Color getRootIndicatorBorder() {
return ROOT_INDICATOR_BORDER;
}
}
@@ -16,8 +16,9 @@ import com.intellij.vcs.log.data.RefsModel;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.impl.SingletonRefGroup;
import com.intellij.vcs.log.impl.VcsLogUtil;
import com.intellij.vcs.log.ui.VcsLogColorManagerImpl;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
import com.intellij.vcs.log.ui.render.RefPainter;
import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,19 +28,23 @@ import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Panel with branch labels, above the graph.
*/
public class BranchesPanel extends JPanel {
private static final int SMALL_ROOTS_GAP = 3;
private static final int BIG_ROOTS_GAP = 7;
private static final int VERTICAL_SPACE = 3;
private final VcsLogDataHolder myDataHolder;
private final VcsLogUiImpl myUI;
private List<RefGroup> myRefGroups;
private final RefPainter myRefPainter;
private LinkedHashMap<VirtualFile, List<RefGroup>> myRefGroups;
private final ReferencePainter myReferencePainter;
@Nullable private Collection<VirtualFile> myRoots = null;
private Map<Integer, RefGroup> myRefPositions = ContainerUtil.newHashMap();
@@ -48,9 +53,9 @@ public class BranchesPanel extends JPanel {
myDataHolder = dataHolder;
myUI = UI;
myRefGroups = getRefsToDisplayOnPanel(initialRefsModel);
myRefPainter = new RefPainter(myUI.getColorManager(), true);
myReferencePainter = new ReferencePainter(myUI.getColorManager(), true);
setPreferredSize(new Dimension(-1, RefPainter.REF_HEIGHT + UIUtil.DEFAULT_VGAP));
setPreferredSize(new Dimension(-1, myReferencePainter.getHeight(this) + UIUtil.DEFAULT_VGAP + VERTICAL_SPACE));
addMouseListener(new MouseAdapter() {
@Override
@@ -68,7 +73,7 @@ public class BranchesPanel extends JPanel {
myUI.jumpToCommit(ref.getCommitHash());
}
else {
final RefPopupComponent view = new RefPopupComponent(group, myUI, myRefPainter);
final ReferencePopupComponent view = new ReferencePopupComponent(group, myUI, myReferencePainter);
JBPopup popup = view.getPopup();
popup.show(new RelativePoint(BranchesPanel.this, new Point(e.getX(), BranchesPanel.this.getHeight())));
}
@@ -85,6 +90,11 @@ public class BranchesPanel extends JPanel {
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(-1, myReferencePainter.getHeight(this) + 10);
}
@Nullable
private RefGroup findRef(MouseEvent e) {
List<Integer> sortedPositions = Ordering.natural().sortedCopy(myRefPositions.keySet());
@@ -101,16 +111,21 @@ public class BranchesPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
myRefPositions = ContainerUtil.newHashMap();
int paddingX = 0;
for (RefGroup group : myRefGroups) {
// TODO it is assumed here that all refs in a single group belong to a single root
VirtualFile root = group.getRefs().iterator().next().getRoot();
if (myRoots == null || myRoots.contains(root)) {
Color rootIndicatorColor = myUI.getColorManager().getRootColor(root);
Rectangle rectangle = myRefPainter.drawLabel((Graphics2D)g, group.getName(), paddingX, group.getBgColor(), rootIndicatorColor);
paddingX += rectangle.width + UIUtil.DEFAULT_HGAP;
myRefPositions.put(rectangle.x, group);
int paddingX = BIG_ROOTS_GAP;
for (Map.Entry<VirtualFile, List<RefGroup>> entry : myRefGroups.entrySet()) {
VirtualFile root = entry.getKey();
for (RefGroup group : entry.getValue()) {
// it is assumed here that all refs in a single group belong to a single root
if (myRoots == null || myRoots.contains(root)) {
Color rootIndicatorColor = VcsLogColorManagerImpl.getIndicatorVersion(myUI.getColorManager().getRootColor(root));
Rectangle rectangle = myReferencePainter
.paintLabel(group.getName(), g, paddingX, (getHeight() - myReferencePainter.getHeight(this)) / 2 - VERTICAL_SPACE, group.getBgColor(),
rootIndicatorColor);
paddingX += rectangle.width + SMALL_ROOTS_GAP;
myRefPositions.put(rectangle.x, group);
}
}
paddingX += BIG_ROOTS_GAP - SMALL_ROOTS_GAP;
}
}
@@ -120,16 +135,15 @@ public class BranchesPanel extends JPanel {
}
@NotNull
private List<RefGroup> getRefsToDisplayOnPanel(@NotNull VcsLogRefs refsModel) {
private LinkedHashMap<VirtualFile, List<RefGroup>> getRefsToDisplayOnPanel(@NotNull VcsLogRefs refsModel) {
Collection<VcsRef> allRefs = refsModel.getBranches();
List<RefGroup> groups = ContainerUtil.newArrayList();
LinkedHashMap<VirtualFile, List<RefGroup>> groups = ContainerUtil.newLinkedHashMap();
for (Map.Entry<VirtualFile, Collection<VcsRef>> entry : VcsLogUtil.groupRefsByRoot(allRefs).entrySet()) {
VirtualFile root = entry.getKey();
Collection<VcsRef> refs = entry.getValue();
VcsLogProvider provider = myDataHolder.getLogProvider(root);
VcsLogRefManager refManager = provider.getReferenceManager();
groups.addAll(expandExpandableGroups(refManager.group(refs)));
List<RefGroup> list = ContainerUtil.newArrayList();
list.addAll(expandExpandableGroups(myDataHolder.getLogProvider(root).getReferenceManager().group(entry.getValue())));
groups.put(root, list);
}
return groups;
@@ -158,27 +172,22 @@ public class BranchesPanel extends JPanel {
getParent().repaint();
}
private static class RefPopupComponent extends JPanel {
private static class ReferencePopupComponent extends JPanel {
@NotNull private final JBPopup myPopup;
@NotNull private final JBList myList;
@NotNull private final VcsLogUiImpl myUi;
@NotNull private final SingleReferenceComponent myRendererComponent;
@NotNull private final ListCellRenderer myCellRenderer;
private final JBPopup myPopup;
private final JBList myList;
private final VcsLogUiImpl myUi;
private final RefPainter myRefPainter;
private final SingleRefComponent myRendererComponent;
private final ListCellRenderer myCellRenderer;
RefPopupComponent(RefGroup group, VcsLogUiImpl ui, RefPainter refPainter) {
ReferencePopupComponent(@NotNull RefGroup group, @NotNull VcsLogUiImpl ui, @NotNull ReferencePainter referencePainter) {
super(new BorderLayout());
myUi = ui;
myRefPainter = refPainter;
myRendererComponent = new SingleRefComponent(myRefPainter);
myRendererComponent = new SingleReferenceComponent(referencePainter);
myCellRenderer = new ListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
myRendererComponent.setRef((VcsRef)value);
myRendererComponent.setReference((VcsRef)value);
myRendererComponent.setSelected(isSelected);
return myRendererComponent;
}
@@ -256,15 +265,16 @@ public class BranchesPanel extends JPanel {
}
}
private static class SingleRefComponent extends JPanel {
private static class SingleReferenceComponent extends JPanel {
private static final int PADDING_Y = 2;
private static final int PADDING_X = 5;
@NotNull private final ReferencePainter myReferencePainter;
private final RefPainter myRefPainter;
private VcsRef myRef;
@Nullable private VcsRef myReference;
public boolean mySelected;
public SingleRefComponent(RefPainter refPainter) {
myRefPainter = refPainter;
public SingleReferenceComponent(@NotNull ReferencePainter referencePainter) {
myReferencePainter = referencePainter;
}
@Override
@@ -272,23 +282,20 @@ public class BranchesPanel extends JPanel {
g.setColor(mySelected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground());
g.fillRect(0, 0, getWidth(), getHeight());
if (myRef != null) {
myRefPainter.draw((Graphics2D)g, Collections.singletonList(myRef), 0, calcWidth());
if (myReference != null) {
myReferencePainter.paintReference(myReference, g, PADDING_X, PADDING_Y);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(calcWidth(), RefPainter.REF_HEIGHT);
if (myReference == null) return super.getPreferredSize();
Dimension size = myReferencePainter.getSize(myReference, this);
return new Dimension(size.width + 2 * PADDING_X, size.height + 2 * PADDING_Y);
}
private int calcWidth() {
FontMetrics metrics = getFontMetrics(getFont());
return metrics.stringWidth(myRef.getName());
}
public void setRef(@NotNull VcsRef ref) {
myRef = ref;
public void setReference(@NotNull VcsRef reference) {
myReference = reference;
}
public void setSelected(boolean selected) {
@@ -43,7 +43,7 @@ import com.intellij.vcs.log.data.LoadingDetails;
import com.intellij.vcs.log.data.VcsLogDataHolder;
import com.intellij.vcs.log.data.VisiblePack;
import com.intellij.vcs.log.ui.VcsLogColorManager;
import com.intellij.vcs.log.ui.render.RefPainter;
import com.intellij.vcs.log.ui.render.LabelPainters.ReferencePainter;
import com.intellij.vcs.log.ui.tables.GraphTableModel;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
@@ -80,7 +80,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
@NotNull private final VcsLogDataHolder myLogDataHolder;
@NotNull private final VcsLogGraphTable myGraphTable;
@NotNull private final RefsPanel myRefsPanel;
@NotNull private final ReferencesPanel myReferencesPanel;
@NotNull private final DataPanel myCommitDetailsPanel;
@NotNull private final MessagePanel myMessagePanel;
@NotNull private final JScrollPane myScrollPane;
@@ -101,7 +101,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
myColorManager = colorManager;
myDataPack = initialDataPack;
myRefsPanel = new RefsPanel(myColorManager);
myReferencesPanel = new ReferencesPanel(myColorManager);
myCommitDetailsPanel = new DataPanel(logDataHolder.getProject(), logDataHolder.isMultiRoot(), logDataHolder);
myScrollPane = new JBScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
@@ -117,7 +117,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
myScrollPane.setOpaque(false);
myScrollPane.getViewport().setOpaque(false);
myScrollPane.setViewportView(myMainContentPanel);
myMainContentPanel.add(myRefsPanel, "");
myMainContentPanel.add(myReferencesPanel, "");
myMainContentPanel.add(myCommitDetailsPanel, "");
myLoadingPanel = new JBLoadingPanel(new BorderLayout(), logDataHolder, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS) {
@@ -175,13 +175,13 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
if (commitData instanceof LoadingDetails) {
myLoadingPanel.startLoading();
myCommitDetailsPanel.setData(null);
myRefsPanel.setRefs(Collections.<VcsRef>emptyList());
myReferencesPanel.setReferences(Collections.<VcsRef>emptyList());
updateDetailsBorder(null);
}
else {
myLoadingPanel.stopLoading();
myCommitDetailsPanel.setData(commitData);
myRefsPanel.setRefs(sortRefs(commitData.getId(), commitData.getRoot()));
myReferencesPanel.setReferences(sortRefs(commitData.getId(), commitData.getRoot()));
updateDetailsBorder(commitData);
newCommitDetails = commitData;
}
@@ -204,7 +204,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
myMainContentPanel.setBorder(BorderFactory.createEmptyBorder());
}
else {
JBColor color = VcsLogGraphTable.getRootBackgroundColor(data.getRoot(), myColorManager);
Color color = VcsLogGraphTable.getRootBackgroundColor(data.getRoot(), myColorManager);
myMainContentPanel.setBorder(new CompoundBorder(new MatteBorder(0, VcsLogGraphTable.ROOT_INDICATOR_COLORED_WIDTH, 0, 0, color),
new MatteBorder(0, VcsLogGraphTable.ROOT_INDICATOR_WHITE_WIDTH, 0, 0,
new JBColor(new NotNullProducer<Color>() {
@@ -455,25 +455,24 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
}
}
private static class RefsPanel extends JPanel {
private static class ReferencesPanel extends JPanel {
@NotNull private final ReferencePainter myReferencePainter;
@NotNull private List<VcsRef> myReferences;
@NotNull private final RefPainter myRefPainter;
@NotNull private List<VcsRef> myRefs;
RefsPanel(@NotNull VcsLogColorManager colorManager) {
super(new FlowLayout(FlowLayout.LEADING, 0, 2));
myRefPainter = new RefPainter(colorManager, false);
myRefs = Collections.emptyList();
ReferencesPanel(@NotNull VcsLogColorManager colorManager) {
super(new FlowLayout(FlowLayout.LEADING, 5, 2));
myReferencePainter = new ReferencePainter(colorManager, false);
myReferences = Collections.emptyList();
setOpaque(false);
}
void setRefs(@NotNull List<VcsRef> refs) {
void setReferences(@NotNull List<VcsRef> references) {
removeAll();
myRefs = refs;
for (VcsRef ref : refs) {
add(new SingleRefPanel(myRefPainter, ref));
myReferences = references;
for (VcsRef reference : references) {
add(new SingleReferencePanel(myReferencePainter, reference));
}
setVisible(!myRefs.isEmpty());
setVisible(!myReferences.isEmpty());
revalidate();
repaint();
}
@@ -484,19 +483,19 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
}
}
private static class SingleRefPanel extends JPanel {
@NotNull private final RefPainter myRefPainter;
@NotNull private VcsRef myRef;
private static class SingleReferencePanel extends JPanel {
@NotNull private final ReferencePainter myRefPainter;
@NotNull private VcsRef myReference;
SingleRefPanel(@NotNull RefPainter refPainter, @NotNull VcsRef ref) {
myRefPainter = refPainter;
myRef = ref;
SingleReferencePanel(@NotNull ReferencePainter referencePainter, @NotNull VcsRef reference) {
myRefPainter = referencePainter;
myReference = reference;
setOpaque(false);
}
@Override
protected void paintComponent(Graphics g) {
myRefPainter.draw((Graphics2D)g, Collections.singleton(myRef), 0, getWidth());
myRefPainter.paintReference(myReference, g, 0, 0);
}
@Override
@@ -506,8 +505,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
@Override
public Dimension getPreferredSize() {
int width = myRefPainter.getLabelWidth(myRef.getName(), getFontMetrics(RefPainter.DEFAULT_FONT));
return new Dimension(width, RefPainter.REF_HEIGHT + UIUtil.DEFAULT_VGAP);
return myRefPainter.getSize(myReference, this);
}
}
@@ -31,7 +31,6 @@ import com.intellij.ui.*;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.table.JBTable;
import com.intellij.util.Function;
import com.intellij.util.NotNullProducer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.JBUI;
@@ -48,10 +47,10 @@ import com.intellij.vcs.log.printer.idea.GraphCellPainter;
import com.intellij.vcs.log.printer.idea.PositionUtil;
import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter;
import com.intellij.vcs.log.ui.VcsLogColorManager;
import com.intellij.vcs.log.ui.VcsLogColorManagerImpl;
import com.intellij.vcs.log.ui.VcsLogUiImpl;
import com.intellij.vcs.log.ui.render.GraphCommitCell;
import com.intellij.vcs.log.ui.render.GraphCommitCellRender;
import com.intellij.vcs.log.ui.render.RefPainter;
import com.intellij.vcs.log.ui.tables.GraphTableModel;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntProcedure;
@@ -118,7 +117,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
setDefaultRenderer(GraphCommitCell.class, new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, this));
setDefaultRenderer(String.class, new StringCellRenderer());
setRowHeight(RefPainter.REF_HEIGHT);
setRowHeight(22);
setShowHorizontalLines(false);
setIntercellSpacing(JBUI.emptySize());
@@ -410,14 +409,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
public static JBColor getRootBackgroundColor(@NotNull VirtualFile root, @NotNull VcsLogColorManager colorManager) {
final Color rootColor = colorManager.getRootColor(root);
return new JBColor(new NotNullProducer<Color>() {
@NotNull
@Override
public Color produce() {
return ColorUtil.mix(rootColor, UIUtil.getTableBackground(), 0.75);
}
});
return VcsLogColorManagerImpl.getBackgroundVersion(colorManager.getRootColor(root));
}
public void handleAnswer(@Nullable GraphAnswer<Integer> answer, boolean dataCouldChange, @Nullable Selection previousSelection) {
@@ -32,7 +32,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer {
@NotNull private final VcsLogDataHolder myDataHolder;
@NotNull private final GraphCellPainter myPainter;
@NotNull private final VcsLogGraphTable myGraphTable;
@NotNull private final RefPainter myRefPainter;
@NotNull private final LabelPainters.LabelPainter myLabelPainter;
@NotNull private final IssueLinkRenderer myIssueLinkRenderer;
@Nullable private PaintInfo myGraphImage;
@@ -45,12 +45,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer {
myDataHolder = dataHolder;
myPainter = painter;
myGraphTable = table;
myRefPainter = new RefPainter(colorManager, false) {
@Override
protected int getRowHeight() {
return myGraphTable.getRowHeight();
}
};
myLabelPainter = LabelPainters.createPainter(false);
myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this);
}
@@ -59,7 +54,14 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer {
super.paintComponent(g);
if (myRefs != null) {
myRefPainter.drawLabels((Graphics2D)g, collectLabelsForRefs(myRefs), myGraphImage != null ? myGraphImage.getWidth() : 0);
int paddingX = (myGraphImage != null ? myGraphImage.getWidth() : 0) + PrintParameters.LABEL_PADDING;
Map<String, Color> labelsForReferences = collectLabelsForRefs(myRefs);
for (Map.Entry<String, Color> entry : labelsForReferences.entrySet()) {
Dimension size = myLabelPainter.calculateSize(entry.getKey(), g.getFontMetrics());
int paddingY = (myGraphTable.getRowHeight() - size.height) / 2;
myLabelPainter.paintLabel((Graphics2D)g, entry.getKey(), paddingX, paddingY, entry.getValue());
paddingX += size.width + PrintParameters.LABEL_PADDING;
}
}
if (myGraphImage != null) {
@@ -90,7 +92,7 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer {
else {
graphPadding = 0;
}
int textPadding = graphPadding + calcRefsPadding(myRefs);
int textPadding = graphPadding + calculateReferencePadding(myRefs);
setBorder(null);
append("");
@@ -132,8 +134,15 @@ public class GraphCommitCellRender extends ColoredTableCellRenderer {
return getLabelsForRefs(branches, tags);
}
private int calcRefsPadding(@NotNull Collection<VcsRef> refs) {
return myRefPainter.getLabelsWidth(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT));
private int calculateReferencePadding(@NotNull Collection<VcsRef> references) {
if (references.isEmpty()) return 0;
int paddingX = 2 * PrintParameters.LABEL_PADDING;
for (String label : collectLabelsForRefs(references).keySet()) {
Dimension size = myLabelPainter.calculateSize(label, this.getFontMetrics(LabelPainters.getFont()));
paddingX += size.width + PrintParameters.LABEL_PADDING;
}
return paddingX;
}
@NotNull
@@ -0,0 +1,216 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.vcs.log.ui.render;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.ui.VcsLogColorManager;
import com.intellij.vcs.log.ui.VcsLogColorManagerImpl;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
public class LabelPainters {
public static LabelPainter createPainter(boolean paintFlag) {
boolean square = Registry.is("vcs.log.square.labels");
if (paintFlag) {
return square ? new UnderlinedLabelPainter() : new FlagLabelPainter();
}
else {
return new LabelPainter(square);
}
}
public static Font getFont() {
return UIUtil.getLabelFont();
}
public static class ReferencePainter {
@NotNull private final VcsLogColorManager myColorManager;
@NotNull private final LabelPainter myLabelPainter;
public ReferencePainter(@NotNull VcsLogColorManager colorManager, boolean paintRoot) {
myColorManager = colorManager;
myLabelPainter = createPainter(paintRoot && colorManager.isMultipleRoots());
}
public void paintReference(@NotNull VcsRef reference, @NotNull Graphics g, int paddingX, int paddingY) {
myLabelPainter.paintLabel((Graphics2D)g, reference.getName(), paddingX, paddingY, reference.getType().getBackgroundColor(),
VcsLogColorManagerImpl.getIndicatorVersion(myColorManager.getRootColor(reference.getRoot())));
}
public Rectangle paintLabel(@NotNull String text,
@NotNull Graphics g,
int paddingX,
int paddingY,
@NotNull Color color,
@NotNull Color flagColor) {
return myLabelPainter.paintLabel((Graphics2D)g, text, paddingX, paddingY, color, flagColor);
}
public Dimension getSize(@NotNull VcsRef reference, @NotNull JComponent component) {
return myLabelPainter.calculateSize(reference.getName(), component.getFontMetrics(getFont()));
}
public int getHeight(@NotNull JComponent component) {
return myLabelPainter.calculateSize("", component.getFontMetrics(getFont())).height;
}
}
public static class LabelPainter {
protected static final int TEXT_PADDING_X = 5;
protected static final int TOP_TEXT_PADDING = 2;
protected static final int BOTTOM_TEXT_PADDING = 1;
private static final int LABEL_ARC = 5;
private final boolean mySquare;
public LabelPainter(boolean square) {
mySquare = square;
}
protected Rectangle paintLabel(@NotNull Graphics2D g2,
@NotNull String text,
int paddingX,
int paddingY,
int textPadding,
@NotNull Color color) {
g2.setFont(getFont());
g2.setStroke(new BasicStroke(1.5f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fontMetrics = g2.getFontMetrics();
int width = fontMetrics.stringWidth(text) + 2 * TEXT_PADDING_X + textPadding;
int height = fontMetrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING;
g2.setColor(color);
if (mySquare) {
g2.fillRect(paddingX, paddingY, width, height);
}
else {
g2.fill(new RoundRectangle2D.Double(paddingX, paddingY, width, height, LABEL_ARC, LABEL_ARC));
}
g2.setColor(JBColor.BLACK);
int x = paddingX + textPadding + TEXT_PADDING_X;
int y = paddingY + fontMetrics.getHeight() / 2 + TOP_TEXT_PADDING + (fontMetrics.getAscent() - fontMetrics.getDescent()) / 2;
g2.drawString(text, x, y);
return new Rectangle(x, y, width, height);
}
public Rectangle paintLabel(@NotNull Graphics2D g2, @NotNull String text, int paddingX, int paddingY, @NotNull Color color) {
return paintLabel(g2, text, paddingX, paddingY, 0, color);
}
public Rectangle paintLabel(@NotNull Graphics2D g2,
@NotNull String text,
int paddingX,
int paddingY,
@NotNull Color labelColor,
@NotNull Color flagColor) {
return paintLabel(g2, text, paddingX, paddingY, 0, labelColor);
}
public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) {
int width = metrics.stringWidth(text) + 2 * TEXT_PADDING_X;
int height = metrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING;
return new Dimension(width, height);
}
}
public static class FlagLabelPainter extends LabelPainter {
private static final int FLAG_WIDTH = 8;
private static final int FLAG_PADDING = 6;
private static final int FLAG_TOP_INDENT = 2;
public FlagLabelPainter() {
super(false);
}
@Override
public Rectangle paintLabel(@NotNull Graphics2D g2,
@NotNull String text,
int paddingX,
int paddingY,
@NotNull Color labelColor,
@NotNull Color flagColor) {
Rectangle rectangle =
super.paintLabel(g2, text, paddingX, paddingY + FLAG_TOP_INDENT, FLAG_WIDTH + 2 * FLAG_PADDING - TEXT_PADDING_X, labelColor);
g2.setColor(flagColor);
int x0 = paddingX + FLAG_PADDING;
int xMid = x0 + FLAG_WIDTH / 2;
int xRight = x0 + FLAG_WIDTH;
int y0 = paddingY;
int yMid = y0 + 2 * rectangle.height / 3 - 2;
int yBottom = y0 + rectangle.height - 4;
// something like a knight flag
Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5);
g2.fillPolygon(polygon);
return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + FLAG_TOP_INDENT);
}
@Override
public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) {
Dimension size = super.calculateSize(text, metrics);
return new Dimension(size.width + FLAG_WIDTH + 2 * FLAG_PADDING, size.height + FLAG_TOP_INDENT);
}
}
public static class UnderlinedLabelPainter extends LabelPainter {
private static final int LINE_GAP = 1;
private static final int LINE_HEIGHT = 4;
public UnderlinedLabelPainter() {
super(true);
}
@Override
public Rectangle paintLabel(@NotNull Graphics2D g2,
@NotNull String text,
int paddingX,
int paddingY,
@NotNull Color labelColor,
@NotNull Color flagColor) {
Rectangle rectangle = super.paintLabel(g2, text, paddingX, paddingY, 0, labelColor);
g2.setColor(flagColor);
g2.fillRect(paddingX, paddingY + rectangle.height + LINE_GAP, rectangle.width, LINE_HEIGHT);
return new Rectangle(paddingX, paddingY, rectangle.width, rectangle.height + LINE_GAP + LINE_HEIGHT);
}
@Override
public Dimension calculateSize(@NotNull String text, @NotNull FontMetrics metrics) {
Dimension size = super.calculateSize(text, metrics);
return new Dimension(size.width, size.height + LINE_GAP + LINE_HEIGHT);
}
}
}
@@ -1,177 +0,0 @@
package com.intellij.vcs.log.ui.render;
import com.intellij.ui.JBColor;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.ui.VcsLogColorManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.RoundRectangle2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* @author erokhins
*/
public class RefPainter {
private static final int RECTANGLE_X_PADDING = 4;
private static final int RECTANGLE_Y_PADDING = 3;
private static final int REF_PADDING = 13;
private static final int LABEL_PADDING = 3;
private static final int FLAG_WIDTH = 8;
private static final int FLAG_PADDING = 8;
private static final int FLAG_TOP_INDENT = 2;
private static final int ROUND_RADIUS = 5;
public static final Font DEFAULT_FONT = new Font("Arial", Font.PLAIN, 12); // wtf, shouldn't we use ui font?
private static final Color DEFAULT_FONT_COLOR = JBColor.BLACK;
public static final int REF_HEIGHT = 22;
@NotNull private final VcsLogColorManager myColorManager;
private final boolean myDrawMultiRepoIndicator;
public RefPainter(@NotNull VcsLogColorManager manager, boolean drawMultiRepoIndicator) {
myColorManager = manager;
myDrawMultiRepoIndicator = drawMultiRepoIndicator;
}
protected int getRowHeight() {
return REF_HEIGHT;
}
public int getLabelWidth(@NotNull String str, FontMetrics metrics) {
return getHorizontalDimensions(str, 0, metrics).width + LABEL_PADDING;
}
public int getLabelsWidth(@NotNull Collection<String> refs, FontMetrics fontMetrics) {
if (refs.isEmpty()) return 0;
int p = 2 * LABEL_PADDING; // additional padding after all references looks better
for (String ref : refs) {
HorizontalDimensions horizontalDimensions = getHorizontalDimensions(ref, p, fontMetrics);
p += horizontalDimensions.width + LABEL_PADDING;
}
return p;
}
public Map<Integer, VcsRef> draw(@NotNull Graphics2D g2, @NotNull Collection<VcsRef> refs, int startPadding, int maxWidth) {
float currentPadding = startPadding;
setupGraphics(g2);
FontRenderContext renderContext = g2.getFontRenderContext();
Map<Integer, VcsRef> positions = new HashMap<Integer, VcsRef>();
for (VcsRef ref : refs) {
int x =
drawLabel(g2, ref.getName(), (int)currentPadding, ref.getType().getBackgroundColor(), myColorManager.getRootColor(ref.getRoot())).x;
positions.put(x, ref);
currentPadding += paddingStr(ref.getName(), renderContext);
if (maxWidth > 0 && x >= maxWidth) {
break;
}
}
return positions;
}
public void drawLabels(@NotNull Graphics2D g2, @NotNull Map<String, Color> labels, int startPadding) {
int padding = startPadding;
for (Map.Entry<String, Color> entry : labels.entrySet()) {
Rectangle rectangle = drawLabel(g2, entry.getKey(), padding, entry.getValue(), null);
padding += rectangle.width + LABEL_PADDING;
}
}
public Rectangle drawLabel(@NotNull Graphics2D g2,
@NotNull String label,
int paddingX,
@NotNull Color bgColor,
@Nullable Color rootIndicatorColor) {
setupGraphics(g2);
FontMetrics metrics = g2.getFontMetrics();
HorizontalDimensions horizontalDimensions = getHorizontalDimensions(label, paddingX, metrics);
int x = horizontalDimensions.x;
int width = horizontalDimensions.width;
int y = RECTANGLE_Y_PADDING + (getRowHeight() - REF_HEIGHT) / 2;
int height = REF_HEIGHT - 2 * RECTANGLE_Y_PADDING;
RoundRectangle2D rectangle2D = new RoundRectangle2D.Double(x, y, width, height, ROUND_RADIUS, ROUND_RADIUS);
g2.setColor(bgColor);
g2.fill(rectangle2D);
g2.setColor(myColorManager.getReferenceBorderColor());
g2.draw(rectangle2D);
g2.setColor(JBColor.BLACK);
drawText(g2, label, paddingX + flagWidth(), (getRowHeight() - REF_HEIGHT) / 2);
if (rootIndicatorColor != null && myColorManager.isMultipleRoots() && myDrawMultiRepoIndicator) {
drawRootIndicator(g2, paddingX, y, height, rootIndicatorColor);
}
return new Rectangle(x, y, width, height);
}
private void drawRootIndicator(@NotNull Graphics2D g2, int x, int y, int height, @NotNull Color rootIndicatorColor) {
g2.setColor(rootIndicatorColor);
int x0 = x + FLAG_PADDING;
int xMid = x0 + FLAG_WIDTH / 2;
int xRight = x0 + FLAG_WIDTH;
int y0 = y - FLAG_TOP_INDENT;
int yMid = y0 + 2 * height / 3 - 2;
int yBottom = y0 + height - 4;
// something like a knight flag
Polygon polygon = new Polygon(new int[]{x0, xRight, xRight, xMid, x0}, new int[]{y0, y0, yMid, yBottom, yMid}, 5);
g2.fillPolygon(polygon);
g2.setColor(myColorManager.getReferenceBorderColor());
g2.drawPolygon(polygon);
}
private HorizontalDimensions getHorizontalDimensions(String label, int paddingX, FontMetrics metrics) {
int x = paddingX + REF_PADDING / 2 - RECTANGLE_X_PADDING;
int width = metrics.stringWidth(label) + 2 * RECTANGLE_X_PADDING + flagWidth();
return new HorizontalDimensions(x, width);
}
private double paddingStr(@NotNull String str, @NotNull FontRenderContext renderContext) {
return getStringWidth(str, renderContext) + REF_PADDING + flagWidth();
}
private int flagWidth() {
return myColorManager.isMultipleRoots() && myDrawMultiRepoIndicator ? FLAG_WIDTH + FLAG_PADDING : 0;
}
private static double getStringWidth(@NotNull String str, @NotNull FontRenderContext renderContext) {
return DEFAULT_FONT.getStringBounds(str, renderContext).getWidth();
}
private static void drawText(@NotNull Graphics2D g2, @NotNull String str, int paddingX, int paddingY) {
FontMetrics metrics = g2.getFontMetrics();
g2.setColor(DEFAULT_FONT_COLOR);
int x = paddingX + REF_PADDING / 2;
int y = paddingY + REF_HEIGHT / 2 + (metrics.getAscent() - metrics.getDescent()) / 2;
g2.drawString(str, x, y);
}
private static void setupGraphics(Graphics2D g2) {
g2.setFont(DEFAULT_FONT);
g2.setStroke(new BasicStroke(1.5f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
private static class HorizontalDimensions {
private final int x;
private final int width;
private HorizontalDimensions(int x, int width) {
this.x = x;
this.width = width;
}
}
}
@@ -4,15 +4,11 @@ import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.vcs.log.RefGroup;
import com.intellij.vcs.log.VcsLogRefManager;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.VcsRefType;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.impl.SingletonRefGroup;
import com.intellij.vcs.log.impl.VcsLogUtil;
import git4idea.GitBranch;
@@ -31,17 +27,11 @@ import java.util.List;
* @author Kirill Likhodedov
*/
public class GitRefManager implements VcsLogRefManager {
private static final Color HEAD_COLOR = new JBColor(new Color(0xf1ef9e), new Color(113, 111, 64));
private static final Color LOCAL_BRANCH_COLOR = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F));
private static final Color REMOTE_BRANCH_COLOR = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker());
private static final Color TAG_COLOR = JBColor.WHITE;
public static final VcsRefType HEAD = new SimpleRefType(true, HEAD_COLOR, "HEAD");
public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, LOCAL_BRANCH_COLOR, "LOCAL_BRANCH");
public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, REMOTE_BRANCH_COLOR, "REMOTE_BRANCH");
public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR, "TAG");
public static final VcsRefType OTHER = new SimpleRefType(false, TAG_COLOR, "OTHER");
public static final VcsRefType HEAD = new SimpleRefType(true, VcsLogStandardColors.Refs.TIP, "HEAD");
public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH, "LOCAL_BRANCH");
public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH_REF, "REMOTE_BRANCH");
public static final VcsRefType TAG = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG, "TAG");
public static final VcsRefType OTHER = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG, "OTHER");
private static final String MASTER = "master";
private static final String ORIGIN_MASTER = "origin/master";
@@ -262,7 +252,7 @@ public class GitRefManager implements VcsLogRefManager {
@NotNull
@Override
public Color getBgColor() {
return HEAD_COLOR;
return VcsLogStandardColors.Refs.TIP;
}
}
@@ -295,7 +285,7 @@ public class GitRefManager implements VcsLogRefManager {
@NotNull
@Override
public Color getBgColor() {
return REMOTE_BRANCH_COLOR;
return VcsLogStandardColors.Refs.BRANCH_REF;
}
}
@@ -18,10 +18,7 @@ package org.zmlx.hg4idea.log;
import com.intellij.ui.JBColor;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.RefGroup;
import com.intellij.vcs.log.VcsLogRefManager;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.VcsRefType;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.impl.SingletonRefGroup;
import com.intellij.vcs.log.impl.VcsLogUtil;
import org.jetbrains.annotations.NotNull;
@@ -33,25 +30,19 @@ import java.util.Comparator;
import java.util.List;
public class HgRefManager implements VcsLogRefManager {
private static final Color TIP_COLOR = new JBColor(new Color(0xf1ef9e), new Color(113, 111, 64));
private static final Color HEAD_COLOR = new JBColor(new Color(0xF10FA9), new Color(0xF10FA9).darker());
private static final Color BRANCH_COLOR = new JBColor(new Color(0x75eec7), new Color(0x0D6D4F));
private static final Color CLOSED_BRANCH_COLOR = new JBColor(new Color(0xee7f8a), new Color(0xee7f8a).darker());
private static final Color BOOKMARK_COLOR = new JBColor(new Color(0xbcbcfc), new Color(0xbcbcfc).darker().darker());
private static final Color TAG_COLOR = JBColor.WHITE;
private static final Color LOCAL_TAG_COLOR = JBColor.CYAN;
private static final Color MQ_TAG_COLOR = new JBColor(new Color(0x1764ff), new Color(0x1764ff).darker());
public static final VcsRefType TIP = new SimpleRefType(true, TIP_COLOR);
public static final VcsRefType HEAD = new SimpleRefType(true, HEAD_COLOR);
public static final VcsRefType BRANCH = new SimpleRefType(true, BRANCH_COLOR);
public static final VcsRefType TIP = new SimpleRefType(true, VcsLogStandardColors.Refs.TIP);
public static final VcsRefType HEAD = new SimpleRefType(true, VcsLogStandardColors.Refs.LEAF);
public static final VcsRefType BRANCH = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH);
public static final VcsRefType CLOSED_BRANCH = new SimpleRefType(false, CLOSED_BRANCH_COLOR);
public static final VcsRefType BOOKMARK = new SimpleRefType(true, BOOKMARK_COLOR);
public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR);
public static final VcsRefType BOOKMARK = new SimpleRefType(true, VcsLogStandardColors.Refs.BRANCH_REF);
public static final VcsRefType TAG = new SimpleRefType(false, VcsLogStandardColors.Refs.TAG);
public static final VcsRefType LOCAL_TAG = new SimpleRefType(false, LOCAL_TAG_COLOR);
public static final VcsRefType MQ_APPLIED_TAG = new SimpleRefType(false, MQ_TAG_COLOR);
// first has the highest priority
private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(TIP, HEAD, BRANCH, BOOKMARK, TAG);