Ticket #13814: smooth-scrolling.diff

File smooth-scrolling.diff, 9.5 KB (added by Perry <perry@…>, 9 months ago)

smooth scrolling

  • src/org/openstreetmap/josm/gui/MapMover.java

     
    2020import org.openstreetmap.josm.actions.mapmode.SelectAction;
    2121import org.openstreetmap.josm.data.coor.EastNorth;
    2222import org.openstreetmap.josm.data.preferences.BooleanProperty;
     23import org.openstreetmap.josm.data.preferences.DoubleProperty;
    2324import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
    2425import org.openstreetmap.josm.gui.layer.Layer;
    2526import org.openstreetmap.josm.spi.preferences.Config;
     
    4243     * Zoom wheel is reversed.
    4344     */
    4445    public static final BooleanProperty PROP_ZOOM_REVERSE_WHEEL = new BooleanProperty("zoom.reverse-wheel", false);
     46    public static final BooleanProperty PROP_ZOOM_SMOOTH_SCROLL = new BooleanProperty("zoom.smooth-scroll", false);
     47    public static final DoubleProperty PROP_ZOOM_SCROLL_SENSITIVITY = new DoubleProperty("zoom.scroll-sensitivity", 1.0);
    4548
    4649    static {
    4750        new JMapViewerUpdater();
     
    253256     */
    254257    @Override
    255258    public void mouseWheelMoved(MouseWheelEvent e) {
    256         int rotation = Boolean.TRUE.equals(PROP_ZOOM_REVERSE_WHEEL.get()) ? -e.getWheelRotation() : e.getWheelRotation();
    257         nc.zoomManyTimes(e.getX(), e.getY(), rotation);
     259        double scrollAmount = Boolean.TRUE.equals(PROP_ZOOM_SMOOTH_SCROLL.get())
     260                ? e.getScrollAmount() * e.getPreciseWheelRotation()
     261                : e.getWheelRotation();
     262        scrollAmount *= PROP_ZOOM_SCROLL_SENSITIVITY.get();
     263        if (Boolean.TRUE.equals(PROP_ZOOM_REVERSE_WHEEL.get())) {
     264            scrollAmount *= -1;
     265        }
     266        nc.zoomManyTimes(e.getX(), e.getY(), scrollAmount);
    258267    }
    259268
    260269    /**
  • src/org/openstreetmap/josm/gui/NavigatableComponent.java

     
    317317    /**
    318318     * Get a new scale that is zoomed in/out a number of times
    319319     * from previous scale and snapped to selected native scale layer.
    320      * @param times count of zoom operations, negative means zoom in
     320     * @param amount how much to zoom, negative means zoom in
    321321     * @return new scale
    322322     */
    323     public double scaleZoomManyTimes(int times) {
    324         if (nativeScaleLayer != null) {
     323    public double scaleZoomManyTimes(double amount) {
     324        // Ignore native scale if smooth scrolling
     325        if (nativeScaleLayer != null && Boolean.FALSE.equals(MapMover.PROP_ZOOM_SMOOTH_SCROLL.get())) {
    325326            ScaleList scaleList = nativeScaleLayer.getNativeScales();
    326327            if (scaleList != null) {
    327328                if (Boolean.TRUE.equals(PROP_ZOOM_INTERMEDIATE_STEPS.get())) {
    328329                    scaleList = scaleList.withIntermediateSteps(PROP_ZOOM_RATIO.get());
    329330                }
    330                 Scale s = scaleList.scaleZoomTimes(getScale(), PROP_ZOOM_RATIO.get(), times);
     331                Scale s = scaleList.scaleZoomTimes(getScale(), PROP_ZOOM_RATIO.get(), (int) Math.ceil(amount));
    331332                return s != null ? s.getScale() : 0;
    332333            }
    333334        }
    334         return getScale() * Math.pow(PROP_ZOOM_RATIO.get(), times);
     335        // It turns out with smooth scrolling this factor still feels nice
     336        return getScale() * Math.pow(PROP_ZOOM_RATIO.get(), amount);
    335337    }
    336338
    337339    /**
     
    363365     * @return new scale
    364366     */
    365367    public double scaleSnap(double scale, boolean floor) {
    366         if (nativeScaleLayer != null) {
     368        // Ignore native scale if smooth scrolling
     369        if (nativeScaleLayer != null && Boolean.FALSE.equals(MapMover.PROP_ZOOM_SMOOTH_SCROLL.get())) {
    367370            ScaleList scaleList = nativeScaleLayer.getNativeScales();
    368371            if (scaleList != null) {
    369372                if (Boolean.TRUE.equals(PROP_ZOOM_INTERMEDIATE_STEPS.get())) {
     
    880883        }
    881884    }
    882885
    883     public void zoomManyTimes(double x, double y, int times) {
     886    public void zoomManyTimes(double x, double y, double amount) {
    884887        double oldScale = getScale();
    885         double newScale = scaleZoomManyTimes(times);
     888        double newScale = scaleZoomManyTimes(amount);
    886889        zoomToFactor(x, y, newScale / oldScale);
    887890    }
    888891
  • src/org/openstreetmap/josm/gui/preferences/display/LafPreference.java

     
    9999    private final JCheckBox dialogGeometry = new JCheckBox(tr("Remember dialog geometries"));
    100100    private final JCheckBox nativeFileChoosers = new JCheckBox(tr("Use native file choosers (nicer, but do not support file filters)"));
    101101    private final JCheckBox zoomReverseWheel = new JCheckBox(tr("Reverse zoom with mouse wheel"));
     102    private final JCheckBox zoomSmooth = new JCheckBox(tr("Use smooth scroll zooming"));
    102103    private final JCheckBox zoomIntermediateSteps = new JCheckBox(tr("Intermediate steps between native resolutions"));
    103104    private JSpinner spinZoomRatio;
     105    private JSpinner spinScrollSensitivity;
    104106
    105107    @Override
    106108    public void addGui(PreferenceTabbedPane gui) {
     
    213215        zoomReverseWheel.setSelected(MapMover.PROP_ZOOM_REVERSE_WHEEL.get());
    214216        panel.add(zoomReverseWheel, GBC.eop().insets(20, 0, 0, 0));
    215217
     218        zoomSmooth.setToolTipText(tr("Check to zoom in by continuous amounts instead of discrete steps"));
     219        zoomSmooth.setSelected(MapMover.PROP_ZOOM_SMOOTH_SCROLL.get());
     220        panel.add(zoomSmooth, GBC.eop().insets(20, 0, 0, 0));
     221
    216222        zoomIntermediateSteps.setToolTipText(
    217223                tr("Divide intervals between native resolution levels to smaller steps if they are much larger than zoom ratio"));
    218224        zoomIntermediateSteps.setSelected(NavigatableComponent.PROP_ZOOM_INTERMEDIATE_STEPS.get());
     
    221227
    222228        panel.add(Box.createVerticalGlue(), GBC.eol().insets(0, 10, 0, 0));
    223229
     230        double sensitivity = MapMover.PROP_ZOOM_SCROLL_SENSITIVITY.get();
     231        spinScrollSensitivity = new JSpinner(new SpinnerNumberModel(sensitivity, 0.01, 2.0, 0.01));
     232        var zoomSensitivityToolTipText = tr("Higher values means faster zooming from scrolling");
     233        addSpinner(spinScrollSensitivity, tr("Zoom sensitivity"), zoomSensitivityToolTipText, 3);
     234
    224235        double logZoomLevel = Math.log(2) / Math.log(NavigatableComponent.PROP_ZOOM_RATIO.get());
    225236        logZoomLevel = Math.max(1, logZoomLevel);
    226237        logZoomLevel = Math.min(5, logZoomLevel);
    227         JLabel labelZoomRatio = new JLabel(tr("Zoom steps to get double scale"));
    228238        spinZoomRatio = new JSpinner(new SpinnerNumberModel(logZoomLevel, 1, 10, 1));
    229         Component spinZoomRatioEditor = spinZoomRatio.getEditor();
    230         JFormattedTextField jftf = ((JSpinner.DefaultEditor) spinZoomRatioEditor).getTextField();
    231         jftf.setColumns(2);
    232         String zoomRatioToolTipText = tr("Higher value means more steps needed, therefore zoom steps will be smaller");
    233         spinZoomRatio.setToolTipText(zoomRatioToolTipText);
    234         labelZoomRatio.setToolTipText(zoomRatioToolTipText);
    235         labelZoomRatio.setLabelFor(spinZoomRatio);
    236         panel.add(labelZoomRatio, GBC.std().insets(20, 0, 0, 0));
    237         panel.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
    238         panel.add(spinZoomRatio, GBC.eol());
     239        String labelZoomRatio = tr("Zoom steps to get double scale");
     240        String zoomRatioToolTipText = tr("Higher value means more steps needed, therefore zoom steps will be " +
     241                "smaller. Also slows down smooth scrolling");
     242        addSpinner(spinZoomRatio, labelZoomRatio, zoomRatioToolTipText, 2);
    239243
    240244        JScrollPane scrollpane = panel.getVerticalScrollPane();
    241245        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
     
    242246        gui.getDisplayPreference().addSubTab(this, tr("Look and Feel"), scrollpane);
    243247    }
    244248
     249    private void addSpinner(JSpinner spinner, String labelText, String tooltip, int columns) {
     250        ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(columns);
     251        var label = new JLabel(labelText);
     252        spinner.setToolTipText(tooltip);
     253        label.setToolTipText(tooltip);
     254        label.setLabelFor(spinner);
     255
     256        panel.add(label, GBC.std().insets(20, 0, 0, 0));
     257        panel.add(GBC.glue(5, 0), GBC.std().fill(GBC.HORIZONTAL));
     258        panel.add(spinner, GBC.eol());
     259    }
     260
    245261    @Override
    246262    public boolean ok() {
    247263        boolean mod = false;
     
    259275        WindowGeometry.GUI_GEOMETRY_ENABLED.put(dialogGeometry.isSelected());
    260276        Config.getPref().putBoolean(FileChooserManager.PROP_USE_NATIVE_FILE_DIALOG.getKey(), nativeFileChoosers.isSelected());
    261277        MapMover.PROP_ZOOM_REVERSE_WHEEL.put(zoomReverseWheel.isSelected());
     278        MapMover.PROP_ZOOM_SMOOTH_SCROLL.put(zoomSmooth.isSelected());
    262279        NavigatableComponent.PROP_ZOOM_INTERMEDIATE_STEPS.put(zoomIntermediateSteps.isSelected());
    263280        NavigatableComponent.PROP_ZOOM_RATIO.put(Math.pow(2, 1/(double) spinZoomRatio.getModel().getValue()));
     281        MapMover.PROP_ZOOM_SCROLL_SENSITIVITY.put((double) spinScrollSensitivity.getValue());
    264282        mod |= LAF.put(((LookAndFeelInfo) lafCombo.getSelectedItem()).getClassName());
    265283        return mod;
    266284    }