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