mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-115799 diff: fix changes painting over scrollbar in 3-way panel
do not eat 100% of CPU due to recursive calls of repaint() (it was not lead to deadlock, so was not fixed all this time).
This commit is contained in:
@@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import com.intellij.util.ui.ButtonlessScrollBarUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -825,7 +826,7 @@ public class EditorWindowImpl extends UserDataHolderBase implements EditorWindow
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
|
||||
public void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
|
||||
myDelegate.registerScrollBarRepaintCallback(callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
|
||||
private Animator myMacScrollbarFadeAnimator;
|
||||
private double myMacScrollbarFadeLevel = 0;
|
||||
private boolean myMacScrollbarHidden;
|
||||
|
||||
|
||||
private ScrollbarRepaintCallback myRepaintCallback;
|
||||
|
||||
protected ButtonlessScrollBarUI() {
|
||||
myAdjustmentListener = new AdjustmentListener() {
|
||||
@@ -264,6 +265,43 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is overridden only to increase the invalid area.
|
||||
* This ensures that whole track will be repainted in case of installed callback
|
||||
*/
|
||||
@Override
|
||||
protected void setThumbBounds(int x, int y, int width, int height) {
|
||||
if (myRepaintCallback == null) {
|
||||
super.setThumbBounds(x, y, width, height);
|
||||
}
|
||||
else {
|
||||
/* If the thumbs bounds haven't changed, we're done.
|
||||
*/
|
||||
if ((thumbRect.x == x) &&
|
||||
(thumbRect.y == y) &&
|
||||
(thumbRect.width == width) &&
|
||||
(thumbRect.height == height)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update thumbRect, and repaint the union of x,y,w,h and
|
||||
* the old thumbRect.
|
||||
*/
|
||||
int minX = Math.min(x, trackRect.x);
|
||||
int minY = Math.min(y, trackRect.y);
|
||||
int maxX = Math.max(x + width, trackRect.x + trackRect.width);
|
||||
int maxY = Math.max(y + height, trackRect.y + trackRect.height);
|
||||
|
||||
thumbRect.setBounds(x, y, width, height);
|
||||
scrollbar.repaint(minX, minY, maxX - minX, maxY - minY);
|
||||
|
||||
// Once there is API to determine the mouse location this will need
|
||||
// to be changed.
|
||||
setThumbRollover(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ModelListener createModelListener() {
|
||||
return new ModelListener() {
|
||||
@@ -615,6 +653,10 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
|
||||
else {
|
||||
g.drawLine(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y);
|
||||
}
|
||||
|
||||
if (myRepaintCallback != null) {
|
||||
myRepaintCallback.call(g);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -774,6 +816,10 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
|
||||
return myMacScrollbarHidden && Registry.is("editor.distraction.free.mode");
|
||||
}
|
||||
|
||||
public void registerRepaintCallback(ScrollbarRepaintCallback callback) {
|
||||
myRepaintCallback = callback;
|
||||
}
|
||||
|
||||
private static class EmptyButton extends JButton {
|
||||
private EmptyButton() {
|
||||
setFocusable(false);
|
||||
@@ -795,4 +841,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
|
||||
return getMaximumSize();
|
||||
}
|
||||
}
|
||||
|
||||
public interface ScrollbarRepaintCallback {
|
||||
void call(Graphics g);
|
||||
}
|
||||
}
|
||||
|
||||
+32
-36
@@ -34,13 +34,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.ScrollBarUI;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The container for an {@link Editor}, which is added then to {@link com.intellij.openapi.diff.impl.util.ThreePanels}.
|
||||
*/
|
||||
public class EditorPlace extends JComponent implements Disposable, EditorEx.RepaintCallback {
|
||||
public class EditorPlace extends JComponent implements Disposable, ButtonlessScrollBarUI.ScrollbarRepaintCallback {
|
||||
private static final Logger LOG = Logger.getInstance(EditorPlace.class);
|
||||
|
||||
@NotNull private final MergePanel2.DiffEditorState myState;
|
||||
@@ -60,49 +60,44 @@ public class EditorPlace extends JComponent implements Disposable, EditorEx.Repa
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
paintThis(g);
|
||||
paintThis(g, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(Graphics g) {
|
||||
repaintScrollbar();
|
||||
paintThis(g, false);
|
||||
}
|
||||
|
||||
private void repaintScrollbar() {
|
||||
if (myEditor == null || myColumn != MergePanelColumn.BASE) {
|
||||
return; // we draw above the scrollbar only in the central column
|
||||
}
|
||||
Component editorComponent = myEditor.getComponent();
|
||||
JScrollBar scrollBar = myEditor.getScrollPane().getVerticalScrollBar();
|
||||
repaint(editorComponent.getWidth() - scrollBar.getWidth(), 0, scrollBar.getWidth(), scrollBar.getHeight());
|
||||
}
|
||||
|
||||
private void paintThis(Graphics g) {
|
||||
if (myEditor != null) {
|
||||
ArrayList<DividerPolygon> polygons = DividerPolygon.createVisiblePolygons(myMergePanel.getSecondEditingSide(), FragmentSide.SIDE1,
|
||||
DiffDivider.MERGE_DIVIDER_POLYGONS_OFFSET);
|
||||
for (DividerPolygon polygon : polygons) {
|
||||
int startY = polygon.getTopLeftY();
|
||||
int endY = polygon.getBottomLeftY();
|
||||
int height = endY - startY;
|
||||
|
||||
if (height == 0) { // draw at least a one-pixel line (e.g. for insertion or deletion), as it is done in highlighters
|
||||
height = 1;
|
||||
}
|
||||
|
||||
drawPolygonAboveScrollBar((Graphics2D)g, startY, height, polygon.getColor(), polygon.isApplied());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawPolygonAboveScrollBar(@NotNull Graphics2D g, int startY, int height, @NotNull Color color, boolean applied) {
|
||||
private void paintThis(Graphics g, boolean paintOnEditor) {
|
||||
if (myEditor == null) return;
|
||||
// painting only above the central scrollbar, because painting on edge scrollbars is not needed, and there are error stripes
|
||||
if (myColumn != MergePanelColumn.BASE) {
|
||||
return;
|
||||
}
|
||||
if (myColumn != MergePanelColumn.BASE) return;
|
||||
|
||||
int offset = paintOnEditor ? DiffDivider.MERGE_DIVIDER_POLYGONS_OFFSET : DiffDivider.MERGE_SCROLL_DIVIDER_POLYGONS_OFFSET;
|
||||
ArrayList<DividerPolygon> polygons = DividerPolygon.createVisiblePolygons(myMergePanel.getSecondEditingSide(), FragmentSide.SIDE1,
|
||||
offset);
|
||||
for (DividerPolygon polygon : polygons) {
|
||||
int startY = polygon.getTopLeftY();
|
||||
int endY = polygon.getBottomLeftY();
|
||||
int height = endY - startY;
|
||||
|
||||
if (height == 0) { // draw at least a one-pixel line (e.g. for insertion or deletion), as it is done in highlighters
|
||||
height = 1;
|
||||
}
|
||||
|
||||
drawPolygonAboveScrollBar((Graphics2D)g, startY, height, polygon.getColor(), polygon.isApplied(), paintOnEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawPolygonAboveScrollBar(@NotNull Graphics2D g,
|
||||
int startY,
|
||||
int height,
|
||||
@NotNull Color color,
|
||||
boolean applied,
|
||||
boolean paintOnEditor) {
|
||||
g.setColor(color);
|
||||
JScrollBar scrollBar = myEditor.getScrollPane().getVerticalScrollBar();
|
||||
int startX = scrollBar.getX();
|
||||
int startX = paintOnEditor ? scrollBar.getX() : 0;
|
||||
int endX = startX + scrollBar.getWidth() - 1;
|
||||
|
||||
Rectangle thumb = calcThumbBounds(scrollBar);
|
||||
@@ -249,6 +244,7 @@ public class EditorPlace extends JComponent implements Disposable, EditorEx.Repa
|
||||
|
||||
public interface EditorListener {
|
||||
void onEditorCreated(EditorPlace place);
|
||||
|
||||
void onEditorReleased(Editor releasedEditor);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.awt.*;
|
||||
|
||||
public class DiffDivider extends JComponent {
|
||||
public static final int MERGE_DIVIDER_POLYGONS_OFFSET = 1;
|
||||
public static final int MERGE_SCROLL_DIVIDER_POLYGONS_OFFSET = 2;
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.util.DiffDivider");
|
||||
private final Editor[] myEditors = new Editor[2];
|
||||
private final FragmentSide myLeftSide;
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ui.ButtonlessScrollBarUI;
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -262,10 +263,5 @@ public interface EditorEx extends Editor {
|
||||
* @param callback callback which will be called from the {@link javax.swing.JComponent#paint(java.awt.Graphics)} method of
|
||||
* the editor vertical scrollbar.
|
||||
*/
|
||||
void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback);
|
||||
|
||||
interface RepaintCallback {
|
||||
void call(Graphics g);
|
||||
}
|
||||
|
||||
void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback);
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
|
||||
public void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
|
||||
myVerticalScrollBar.registerRepaintCallback(callback);
|
||||
}
|
||||
|
||||
@@ -4779,7 +4779,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
class MyScrollBar extends JBScrollBar implements IdeGlassPane.TopComponent {
|
||||
@NonNls private static final String APPLE_LAF_AQUA_SCROLL_BAR_UI_CLASS = "apple.laf.AquaScrollBarUI";
|
||||
private ScrollBarUI myPersistentUI;
|
||||
@Nullable private RepaintCallback myRepaintCallback;
|
||||
|
||||
private MyScrollBar(@JdkConstants.AdjustableOrientation int orientation) {
|
||||
super(orientation);
|
||||
@@ -4804,9 +4803,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
@Override
|
||||
public void paint(@NotNull Graphics g) {
|
||||
super.paint(g);
|
||||
if (myRepaintCallback != null) {
|
||||
myRepaintCallback.call(g);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4877,8 +4873,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
return myEditorComponent.getScrollableBlockIncrement(vr, SwingConstants.VERTICAL, direction);
|
||||
}
|
||||
|
||||
public void registerRepaintCallback(@Nullable RepaintCallback callback) {
|
||||
myRepaintCallback = callback;
|
||||
public void registerRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
|
||||
if (myPersistentUI instanceof ButtonlessScrollBarUI) {
|
||||
((ButtonlessScrollBarUI)myPersistentUI).registerRepaintCallback(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user