IJPL-182732 diff: Synchronize hover and activation areas for vcs markers

IJ-MR-159564


(cherry picked from commit a8e7e5b214fdc8e89b92802b6dddf7cd0d996eaa)

IJ-MR-160717

GitOrigin-RevId: a1656f4e34c0e0b3d9bc9a5a6c2d42c93cd152a7
This commit is contained in:
Aleksandr Krasilnikov
2025-04-05 11:22:54 +02:00
committed by intellij-monorepo-bot
parent 5e532e6a5a
commit ed1c987b68
4 changed files with 90 additions and 31 deletions

View File

@@ -2139,8 +2139,8 @@ f:com.intellij.openapi.diff.LineStatusMarkerDrawUtil
- s:getSelectedRanges(java.util.List,com.intellij.openapi.editor.Editor,I):java.util.List
- s:isInsideMarkerArea(java.awt.event.MouseEvent):Z
- s:isRangeHovered(com.intellij.openapi.editor.Editor,I,I,I,I):Z
- s:paintChangedLines(java.awt.Graphics2D,com.intellij.openapi.editor.Editor,java.util.List,I):V
- s:paintChangedLines(java.awt.Graphics2D,com.intellij.openapi.editor.Editor,java.util.List,com.intellij.openapi.diff.LineStatusMarkerColorScheme,I):V
- s:paintChangedLines(java.awt.Graphics2D,com.intellij.openapi.editor.Editor,java.util.List,I,Z):V
- s:paintChangedLines(java.awt.Graphics2D,com.intellij.openapi.editor.Editor,java.util.List,com.intellij.openapi.diff.LineStatusMarkerColorScheme,I,Z):V
- s:paintDefault(com.intellij.openapi.editor.Editor,java.awt.Graphics,java.util.List,com.intellij.openapi.vcs.ex.VisibleRangeMerger$FlagsProvider,I):V
- s:paintDefault(com.intellij.openapi.editor.Editor,java.awt.Graphics,java.util.List,com.intellij.openapi.vcs.ex.VisibleRangeMerger$FlagsProvider,com.intellij.openapi.diff.LineStatusMarkerColorScheme,I):V
- s:paintRange(java.awt.Graphics,com.intellij.openapi.editor.Editor,com.intellij.openapi.vcs.ex.Range,I,Z):V

View File

@@ -20,6 +20,7 @@ import com.intellij.ui.scale.JBUIScale;
import com.intellij.util.IntPair;
import com.intellij.util.ui.JBUI;
import kotlin.Unit;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,27 +45,36 @@ public final class LineStatusMarkerDrawUtil {
List<Range> result = new ArrayList<>();
for (ChangesBlock<Unit> block : blocks) {
ChangedLines<Unit> firstChange = block.changes.get(0);
ChangedLines<Unit> lastChange = block.changes.get(block.changes.size() - 1);
int startY = firstChange.y1;
int endY = lastChange.y2;
// "empty" range for deleted block
if (firstChange.y1 == firstChange.y2) {
startY -= triangleGap;
}
if (lastChange.y1 == lastChange.y2) {
endY += triangleGap;
}
if (startY <= y && endY > y) {
if (isBlockUnderY(block, y, triangleGap)) {
result.addAll(block.ranges);
}
}
return result;
}
private static boolean isBlockUnderY(ChangesBlock<?> block, int y, int triangleGap) {
if (y == -1) return false;
ChangedLines<?> firstChange = block.changes.get(0);
ChangedLines<?> lastChange = block.changes.get(block.changes.size() - 1);
int startY = firstChange.y1;
int endY = lastChange.y2;
// "empty" range for deleted block
if (firstChange.y1 == firstChange.y2) {
startY -= triangleGap;
}
if (lastChange.y1 == lastChange.y2) {
endY += triangleGap;
}
if (startY <= y && endY > y) {
return true;
}
return false;
}
public static Rectangle calcBounds(@NotNull List<? extends Range> ranges, @NotNull Editor editor, int lineNum) {
int yStart = editor.visualLineToY(lineNum);
Rectangle clip = new Rectangle(0, yStart, 0, editor.getLineHeight());
@@ -98,23 +108,59 @@ public final class LineStatusMarkerDrawUtil {
@NotNull LineStatusMarkerColorScheme colorScheme,
int framingBorder) {
List<ChangesBlock<DefaultLineFlags>> blocks = VisibleRangeMerger.merge(editor, ranges, flagsProvider, g.getClipBounds());
for (ChangesBlock<DefaultLineFlags> block : blocks) {
paintChangedLines((Graphics2D)g, editor, block.changes, colorScheme, framingBorder);
EditorGutterComponentEx gutterComponentEx = ((EditorEx)editor).getGutterComponentEx();
GroupedBlocks groupedBlocks = groupBlocks(editor, gutterComponentEx, blocks);
for (ChangesBlock<DefaultLineFlags> block : groupedBlocks.unhoveredBlocks()) {
paintChangedLines((Graphics2D)g, editor, block.changes, colorScheme, framingBorder, false);
}
for (ChangesBlock<DefaultLineFlags> block : groupedBlocks.hoveredBlocks()) {
paintChangedLines((Graphics2D)g, editor, block.changes, colorScheme, framingBorder, true);
}
}
@ApiStatus.Internal
public static @NotNull LineStatusMarkerDrawUtil.GroupedBlocks groupBlocks(@NotNull Editor editor,
EditorGutterComponentEx gutterComponentEx,
List<ChangesBlock<DefaultLineFlags>> blocks) {
List<ChangesBlock<DefaultLineFlags>> hoveredBlocks = new ArrayList<>();
List<ChangesBlock<DefaultLineFlags>> unhoveredBlocks = new ArrayList<>();
int triangleGap = getTriangleAimGap(editor);
int y = gutterComponentEx.getHoveredFreeMarkersY();
for (ChangesBlock<DefaultLineFlags> block : blocks) {
if (isBlockUnderY(block, y, triangleGap)) {
hoveredBlocks.add(block);
}
else {
unhoveredBlocks.add(block);
}
}
GroupedBlocks groupedBlocks = new GroupedBlocks(hoveredBlocks, unhoveredBlocks);
return groupedBlocks;
}
@ApiStatus.Internal
public record GroupedBlocks(List<ChangesBlock<DefaultLineFlags>> hoveredBlocks, List<ChangesBlock<DefaultLineFlags>> unhoveredBlocks) {
}
public static void paintChangedLines(@NotNull Graphics2D g,
@NotNull Editor editor,
@NotNull List<? extends ChangedLines<DefaultLineFlags>> block,
int framingBorder) {
paintChangedLines(g, editor, block, LineStatusMarkerColorScheme.DEFAULT, framingBorder);
int framingBorder,
boolean isHovered) {
paintChangedLines(g, editor, block, LineStatusMarkerColorScheme.DEFAULT, framingBorder, isHovered);
}
public static void paintChangedLines(@NotNull Graphics2D g,
@NotNull Editor editor,
@NotNull List<? extends ChangedLines<DefaultLineFlags>> block,
@NotNull LineStatusMarkerColorScheme colorScheme,
int framingBorder) {
int framingBorder,
boolean isHovered) {
Color borderColor = LineStatusMarkerColorScheme.DEFAULT.getBorderColor(editor);
EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
Color gutterBackgroundColor = gutter.getBackground();
@@ -141,13 +187,8 @@ public final class LineStatusMarkerDrawUtil {
int start = change.y1;
int end = change.y2;
Color gutterColor = colorScheme.getColor(editor, change.type);
int line = gutter.getHoveredFreeMarkersLine();
if (isRangeHovered(editor, line, x, start, end)) {
paintRect(g, gutterColor, null, x - getHoveredMarkerExtraWidth(), start, endX, end);
}
else {
paintRect(g, gutterColor, null, x, start, endX, end);
}
int x1 = isHovered ? x - getHoveredMarkerExtraWidth() : x;
paintRect(g, gutterColor, null, x1, start, endX, end);
}
}
@@ -196,7 +237,7 @@ public final class LineStatusMarkerDrawUtil {
List<ChangesBlock<DefaultLineFlags>> blocks = VisibleRangeMerger.merge(editor, Collections.singletonList(range), flagsProvider,
g.getClipBounds());
for (ChangesBlock<DefaultLineFlags> block : blocks) {
paintChangedLines((Graphics2D)g, editor, block.changes, framingBorder);
paintChangedLines((Graphics2D)g, editor, block.changes, framingBorder, false);
}
}

View File

@@ -129,6 +129,14 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit
return -1;
}
/**
* @return y coordinate of the last mouse cursor point on the gutter's free markers area or -1 if the point is not on the area.
*/
@ApiStatus.Internal
public int getHoveredFreeMarkersY() {
return -1;
}
@ApiStatus.Internal
public int getLineNumberAreaOffset() {
return 0;

View File

@@ -216,6 +216,7 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx
private boolean myHovered = false;
private final @NotNull EventDispatcher<EditorGutterListener> myEditorGutterListeners = EventDispatcher.create(EditorGutterListener.class);
private int myHoveredFreeMarkersLine = -1;
private int myHoveredFreeMarkersY = -1;
private @Nullable GutterIconRenderer myCurrentHoveringGutterRenderer;
EditorGutterComponentImpl(@NotNull EditorImpl editor) {
@@ -2080,16 +2081,20 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx
int x = convertX(point.x);
int hoveredLine;
int hoveredY;
if (x >= getExtraLineMarkerFreePaintersAreaOffset() &&
x <= getExtraLineMarkerFreePaintersAreaOffset() + getExtraRightFreePaintersAreaWidth()) {
hoveredLine = getEditor().xyToLogicalPosition(point).line;
hoveredY = point.y;
}
else {
hoveredLine = -1;
hoveredY = -1;
}
if (myHoveredFreeMarkersLine != hoveredLine) {
if (myHoveredFreeMarkersLine != hoveredLine || myHoveredFreeMarkersY != hoveredY) {
myHoveredFreeMarkersLine = hoveredLine;
myHoveredFreeMarkersY = hoveredY;
repaint();
}
}
@@ -2964,6 +2969,11 @@ final class EditorGutterComponentImpl extends EditorGutterComponentEx
return myHoveredFreeMarkersLine;
}
@Override
public int getHoveredFreeMarkersY() {
return myHoveredFreeMarkersY;
}
@Override
public @NotNull UiInspectorInfo getUiInspectorContext(@NotNull MouseEvent event) {
List<PropertyBean> result = new ArrayList<>();