001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005
006import java.awt.Dimension;
007
008import javax.swing.JSlider;
009import javax.swing.UIManager;
010import javax.swing.event.ChangeEvent;
011import javax.swing.event.ChangeListener;
012
013import org.openstreetmap.josm.gui.help.Helpful;
014import org.openstreetmap.josm.gui.NavigatableComponent.ZoomChangeListener;
015
016/**
017 * This is the slider used in the top left corner of the map view. It allows the user to select the scale
018 */
019class MapSlider extends JSlider implements ZoomChangeListener, ChangeListener, Helpful {
020
021    private static final double ZOOM_STEP = 1.1;
022    private final MapView mv;
023    private boolean preventChange;
024    private int lastValue;
025
026    MapSlider(MapView mv) {
027        super(0, 160);
028        setOpaque(false);
029        this.mv = mv;
030        NavigatableComponent.addZoomChangeListener(this);
031        addChangeListener(this);
032        // Call this manually once so it gets setup correctly
033        zoomChanged();
034        int w = UIManager.getDefaults().getInt("Slider.thumbWidth") + 150;
035        setPreferredSize(new Dimension(w, 27));
036    }
037
038    @Override
039    public void zoomChanged() {
040        double maxScale = this.mv.getMaxScale();
041        int zoom = (int) Math.round(Math.log(maxScale/mv.getScale())/Math.log(ZOOM_STEP));
042        preventChange = true;
043        setValue(zoom);
044        lastValue = zoom;
045        preventChange = false;
046    }
047
048    @Override
049    public void stateChanged(ChangeEvent e) {
050        if (preventChange) return;
051
052        if (!getModel().getValueIsAdjusting() && mv.getNativeScaleLayer() != null) {
053            if (getValue() < lastValue) {
054                mv.zoomOut();
055            } else if (getValue() > lastValue) {
056                mv.zoomIn();
057            }
058        } else {
059            double maxScale = this.mv.getMaxScale();
060            double scale = maxScale/Math.pow(ZOOM_STEP, getValue());
061            double snapped = mv.scaleFloor(scale);
062            mv.zoomTo(this.mv.getCenter(), snapped);
063        }
064        zoomChanged();
065    }
066
067    @Override
068    public String helpTopic() {
069        return ht("/MapView/Slider");
070    }
071}