Changeset 18684 in josm


Ignore:
Timestamp:
2023-03-07T17:15:04+01:00 (21 months ago)
Author:
taylor.smock
Message:

Fix #22770: High precision scroll inputs may cause zoom events in the ImageDisplay

This is caused by the mouse wheel rotation being 0 (MouseWheelEvent#getWheelRotation )
which then caused the image viewer to perform a zoom event.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java

    r18605 r18684  
    365365                currentVisibleRect.width = (int) (currentVisibleRect.width * ZOOM_STEP.get());
    366366                currentVisibleRect.height = (int) (currentVisibleRect.height * ZOOM_STEP.get());
    367             } else {
     367            } else if (rotation < 0) {
    368368                currentVisibleRect.width = (int) (currentVisibleRect.width / ZOOM_STEP.get());
    369369                currentVisibleRect.height = (int) (currentVisibleRect.height / ZOOM_STEP.get());
    370             }
     370            } // else rotation == 0, which can happen with some modern trackpads (see #22770)
    371371
    372372            // Check that the zoom doesn't exceed MAX_ZOOM:1
  • trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplayTest.java

    r18037 r18684  
    22package org.openstreetmap.josm.gui.layer.geoimage;
    33
     4import static org.junit.jupiter.api.Assertions.assertAll;
     5import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    46import static org.junit.jupiter.api.Assertions.assertEquals;
     7import static org.junit.jupiter.api.Assertions.assertNotEquals;
    58
    69import java.awt.Dimension;
    710import java.awt.Graphics2D;
    811import java.awt.Rectangle;
     12import java.awt.event.MouseWheelEvent;
     13import java.awt.event.MouseWheelListener;
    914import java.awt.image.BufferedImage;
     15import java.io.IOException;
     16import java.lang.reflect.Field;
    1017import java.nio.file.DirectoryStream;
    1118import java.nio.file.Files;
    1219import java.nio.file.Path;
    1320import java.nio.file.Paths;
     21import java.util.function.IntFunction;
     22import java.util.function.Supplier;
     23
     24import javax.swing.JPanel;
    1425
    1526import org.junit.jupiter.api.Disabled;
     
    1829import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
    1930import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
     31import org.openstreetmap.josm.tools.ReflectionUtils;
    2032
    2133/**
     
    6173        }
    6274    }
     75
     76    /**
     77     * Non-regression test for #22770 which occurs when a high resolution trackpad does not have a full mouse wheel event
     78     */
     79    @Test
     80    void testNonRegression22770() {
     81        final ImageDisplay imageDisplay = new ImageDisplay(new ImageryFilterSettings());
     82        final Field visRectField = assertDoesNotThrow(() -> ImageDisplay.class.getDeclaredField("visibleRect"));
     83        final Field wheelListenerField = assertDoesNotThrow(() -> ImageDisplay.class.getDeclaredField("imgMouseListener"));
     84        ReflectionUtils.setObjectsAccessible(wheelListenerField, visRectField);
     85        final Supplier<VisRect> visRectSupplier = () -> new VisRect((VisRect) assertDoesNotThrow(() -> visRectField.get(imageDisplay)));
     86        final MouseWheelListener listener = (MouseWheelListener) assertDoesNotThrow(() -> wheelListenerField.get(imageDisplay));
     87        final IntFunction<MouseWheelEvent> mouseEventProvider = wheelRotation -> new MouseWheelEvent(new JPanel(), 0, 0, 0,
     88                320, 240, 320, 240, 0, false,
     89                MouseWheelEvent.WHEEL_UNIT_SCROLL, wheelRotation, wheelRotation, wheelRotation);
     90        imageDisplay.setSize(640, 480);
     91        imageDisplay.setImage0(new TestImageEntry(640, 480)).run();
     92        final VisRect initialVisibleRect = visRectSupplier.get();
     93        assertEquals(640, initialVisibleRect.width);
     94        assertEquals(480, initialVisibleRect.height);
     95        // First, check that zoom in works
     96        listener.mouseWheelMoved(mouseEventProvider.apply(-1));
     97        assertNotEquals(initialVisibleRect, imageDisplay.getVisibleRect());
     98        final VisRect zoomedInVisRect = visRectSupplier.get();
     99        // If this fails, check to make certain that geoimage.zoom-step-factor defaults haven't changed
     100        assertAll(() -> assertEquals(426, zoomedInVisRect.width),
     101                () -> assertEquals(320, zoomedInVisRect.height));
     102        // Now check that a zoom event with no wheel rotation does not cause movement
     103        listener.mouseWheelMoved(mouseEventProvider.apply(0));
     104        final VisRect noZoomVisRect = visRectSupplier.get();
     105        assertAll(() -> assertEquals(426, noZoomVisRect.width),
     106                () -> assertEquals(320, noZoomVisRect.height));
     107
     108        // Finally zoom out
     109        listener.mouseWheelMoved(mouseEventProvider.apply(1));
     110        final VisRect zoomOutVisRect = visRectSupplier.get();
     111        assertAll(() -> assertEquals(640, zoomOutVisRect.width),
     112                () -> assertEquals(480, zoomOutVisRect.height));
     113    }
     114
     115    private static class TestImageEntry extends ImageEntry {
     116        private final int width;
     117        private final int height;
     118        TestImageEntry(int width, int height) {
     119            this.width = width;
     120            this.height = height;
     121        }
     122
     123        @Override
     124        public int getWidth() {
     125            return this.width;
     126        }
     127
     128        @Override
     129        public int getHeight() {
     130            return this.height;
     131        }
     132
     133        @Override
     134        public BufferedImage read(Dimension target) throws IOException {
     135            return new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB);
     136        }
     137    }
    63138}
Note: See TracChangeset for help on using the changeset viewer.