All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.swing.plaf.util.SmoothScrollPaneUI Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2000-2016 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.
 */
/* This file is based in part on the commit
 * https://github.com/JetBrains/intellij-community/commit/34b9dfd0585937c3731e06a89554d1dc86f7f235
 * from 2016-12-14 in the IntelliJ IDEA Community Edition repository, as referenced by Pavel Fatin
 * on the AWT Dev mailing list on 2017-01-04
 * ( http://mail.openjdk.java.net/pipermail/awt-dev/2017-January/012507.html ), and retrieved on
 * 2018-09-17. The source files in question are as follows:
 *   com.intellij.ui.components.SmoothScrollPane (author Pavel Fatin)
 *   com.intellij.ui.components.JBScrollPane
 *
 * The original code has been modified by Eirik Bakke ([email protected]) for standalone use outside
 * the IntelliJ IDE. In particular, we use here a custom ScrollPaneUI implementation instead of the
 * original approach of accessing the mouseScrollListener by reflection.
 *
 * The complete license header for the original files (identical for both files) is included above.
 * The NOTICE file is pasted in licenseinfo.xml.
 */
package org.netbeans.swing.plaf.util;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollPaneUI;

/**
 * Scroll pane UI that can handle high-precision mouse wheel events. Although Java 7 introduced
 * {@link MouseWheelEvent#getPreciseWheelRotation()} method, {@link BasicScrollPaneUI} does not yet
 * use it, which causes the following problems on Windows:
 *
 * 
    *
  • When the user has configured a wheel scroll speed higher than "1 line per notch" in the * Windows control panel, the NetBeans editor (and other scroll panes) can only be scrolled in * large discrete jumps. This happens both with a trackpad and an external mouse. Setting the * scroll speed to "1 line per notch" is an undesirable workaround, as it makes scrolling slow * on every application on the machine, including smooth-scrolling ones such as Chrome. *
  • When scrolling in code completion and documentation popups, the editor underneath scrolls * as well, due to {@code BasicScrollPaneUI} not disposing the event correctly when * {@MouseWheelEvent.getWheelRotation()} returns zero (e.g. with * {@code preciseWheelRotation=0.25}). *
* *

Tested on Java 8 and Java 10.0.2 on Windows 10 on a Lenovo X1 Carbon 6th generation laptop, * with both the trackpad and an external USB mouse. * * @see BasicScrollPaneUI.Handler#mouseWheelMoved(MouseWheelEvent) * @see javax.swing.plaf.basic.BasicScrollBarUI#scrollByUnits */ public class SmoothScrollPaneUI extends BasicScrollPaneUI { private static final double EPSILON = 1e-5d; private SmoothScrollPaneUI() { } // Will be called reflectively by the UI manager. public static ComponentUI createUI(JComponent x) { return new SmoothScrollPaneUI(); } @Override protected MouseWheelListener createMouseWheelListener() { final MouseWheelListener delegate = super.createMouseWheelListener(); return new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent evt) { handleMouseWheelEvent(evt, delegate); } }; } private void handleMouseWheelEvent(MouseWheelEvent evt, MouseWheelListener delegate) { if (scrollpane.isWheelScrollingEnabled() && evt.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) { mouseWheelMoved(evt); evt.consume(); } else { delegate.mouseWheelMoved(evt); } } private void mouseWheelMoved(MouseWheelEvent e) { /* The code in this method is taken directly from Pavel Fatin's original IntelliJ patch. Some formatting changes have been applied. */ /* The shift modifier will be enabled for horizontal touchbar scroll events, even when the actual shift key is not pressed, on both Windows and MacOS (though not on Java 8 on Windows). */ JScrollBar scrollbar = e.isShiftDown() ? scrollpane.getHorizontalScrollBar() : scrollpane.getVerticalScrollBar(); int orientation = scrollbar.getOrientation(); JViewport viewport = scrollpane.getViewport(); if (viewport == null || !(viewport.getView() instanceof Scrollable)) { return; } Scrollable view = (Scrollable) viewport.getView(); double rotation = e.getPreciseWheelRotation(); /* Use (0, 0) view position to obtain constant unit increment (which might otherwise be variable on smaller-than-unit scrolling). */ Rectangle r = new Rectangle(new Point(0, 0), viewport.getViewSize()); int unitIncrement = view.getScrollableUnitIncrement(r, orientation, 1); double delta = rotation * e.getScrollAmount() * unitIncrement; boolean limitDelta = Math.abs(rotation) < 1.0d + EPSILON; int blockIncrement = view.getScrollableBlockIncrement(r, orientation, 1); double adjustedDelta = limitDelta ? Math.max(-(double) blockIncrement, Math.min(delta, (double) blockIncrement)) : delta; int value = scrollbar.getValue(); int newValue = Math.max(scrollbar.getMinimum(), Math.min((int) Math.round(value + adjustedDelta), scrollbar.getMaximum())); if (newValue != value) { scrollbar.setValue(newValue); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy