diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 39b2e139ba5b..1bbd27b56f3d 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -182,7 +182,16 @@ public class JBScrollPane extends SmoothScrollPane { JScrollPane pane = (JScrollPane)source; if (pane.isWheelScrollingEnabled()) { JScrollBar bar = event.isShiftDown() ? pane.getHorizontalScrollBar() : pane.getVerticalScrollBar(); - if (bar != null && bar.isVisible()) oldListener.mouseWheelMoved(event); + if (bar != null && bar.isVisible()) { + boolean isUnitScroll = MouseWheelEvent.WHEEL_UNIT_SCROLL == event.getScrollType(); + JViewport viewport = pane.getViewport(); + if (isUnitScroll && viewport instanceof JBViewport && isPreciseRotationSupported()) { + ((JBViewport)viewport).updateViewPosition(event.isShiftDown(), 10 * event.getPreciseWheelRotation()); + } + else { + oldListener.mouseWheelMoved(event); + } + } } } } @@ -735,7 +744,7 @@ public class JBScrollPane extends SmoothScrollPane { if (event.isConsumed()) return false; // any rotation expected (forward or backward) boolean ignore = event.getWheelRotation() == 0; - if (ignore && isPreciseRotationSupported()) { + if (ignore && (isPreciseRotationSupported() || isTrueSmoothScrollingEnabled())) { double rotation = event.getPreciseWheelRotation(); double delta = MouseWheelEventEx.getScrollingDelta(event); ignore = (rotation == 0.0D || !Double.isFinite(rotation)) && (delta == 0.0D || !Double.isFinite(delta)); @@ -743,8 +752,15 @@ public class JBScrollPane extends SmoothScrollPane { return !ignore && 0 == (SCROLL_MODIFIERS & event.getModifiers()); } - private static boolean isPreciseRotationSupported() { - return isTrueSmoothScrollingEnabled(); + /** + * Indicates whether the smooth scrolling is supported by any means. + * + * @deprecated will be removed after fixing a blit-scrolling + */ + @Deprecated + @SuppressWarnings("DeprecatedIsStillUsed") + public static boolean isPreciseRotationSupported() { + return Registry.is("ide.scroll.precise"); } private static final int SCROLL_MODIFIERS = // event modifiers allowed during scrolling diff --git a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java index 50ff75a45f3b..9367626dfd9f 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBViewport.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBViewport.java @@ -79,6 +79,10 @@ public class JBViewport extends JViewport implements ZoomableViewport { private volatile boolean myBackgroundRequested; // avoid cyclic references + private boolean myUpdateViewPosition; // avoid cyclic references + private double myViewX; + private double myViewY; + public JBViewport() { addContainerListener(new ContainerListener() { @Override @@ -107,9 +111,42 @@ public class JBViewport extends JViewport implements ZoomableViewport { checkScrollingCapabilities(); } + if (myUpdateViewPosition) return; + myViewX = p.x; + myViewY = p.y; super.setViewPosition(p); } + /** + * Updates a view position directly without using a corresponding scroll bar. + * + * @param horizontal {@code true} for horizontal scrolling, {@code false} for vertical scrolling + * @param preciseValue precise wheel rotation in pixels for the specified direction + */ + void updateViewPosition(boolean horizontal, double preciseValue) { + int x = (int)myViewX; + int y = (int)myViewY; + if (horizontal) { + int old = x; + myViewX = Math.max(0, myViewX + preciseValue); + x = (int)myViewX; + if (x == old) return; // nothing changed + } + else { + int old = y; + myViewY = Math.max(0, myViewY + preciseValue); + y = (int)myViewY; + if (y == old) return; // nothing changed + } + try { + myUpdateViewPosition = true; + super.setViewPosition(new Point(x, y)); + } + finally { + myUpdateViewPosition = false; + } + } + // A heuristic to detect whether this viewport belongs to the "Event Log" tool window (which we use for output) private boolean isInsideLogToolWindow() { Container parent1 = getParent(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 56feac12d9c8..809934e6468c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -507,7 +507,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myPanel = new JPanel(); // JBScrollPane.Layout relies on "opaque" property directly (instead of "editor.transparent.scrollbar") - if (SystemProperties.isTrueSmoothScrollingEnabled() && !IdeBackgroundUtil.isBackgroundImageSet(project)) { + boolean opaque = JBScrollPane.isPreciseRotationSupported() || SystemProperties.isTrueSmoothScrollingEnabled(); + if (opaque && !IdeBackgroundUtil.isBackgroundImageSet(project)) { //Do not set opaque to false if a scroll bar is opaque (System Preferences / Show scroll bars / Always) myVerticalScrollBar.setOpaque(true); myScrollPane.getHorizontalScrollBar().setOpaque(true); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index 96d541e5bd91..5e031a0fd515 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -54,6 +54,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.impl.IdeBackgroundUtil; import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Alarm; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; @@ -487,7 +488,8 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark This helps to improve scrolling performance and to reduce CPU usage (especially if drawing is compute-intensive). When there's a background image, blit-acceleration cannot be used (because of the static overlay). */ - return !(SystemProperties.isTrueSmoothScrollingEnabled() && !IdeBackgroundUtil.isBackgroundImageSet(myEditor.getProject())) && + boolean opaque = JBScrollPane.isPreciseRotationSupported() || SystemProperties.isTrueSmoothScrollingEnabled(); + return !(opaque && !IdeBackgroundUtil.isBackgroundImageSet(myEditor.getProject())) && Registry.is("editor.transparent.scrollbar", false) && EditorUtil.isRealFileEditor(myEditor); } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 77783b6fbbf6..01631afc4bff 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -118,6 +118,9 @@ ide.splitter.mouseZone=6 ide.autoscroll.from.source.delay=100 ide.autoscroll.from.source.delay.description=Delay before performing the AutoscrollFromSource action +ide.scroll.precise=false +ide.scroll.precise.description=Use precise wheel rotation (may decrease scrolling performance). + ide.scroll.default.unit.increment=false ide.scroll.default.unit.increment.description=Use default unit increment from Java (may decrease scrolling performance).