Changeset 10011 in josm


Ignore:
Timestamp:
2016-03-19T00:34:41+01:00 (9 years ago)
Author:
Don-vip
Message:

fix #12642 - New layer filter (opacity/gamma) dialog (patch by michael2402, modified)

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    r9975 r10011  
    88import java.awt.Dimension;
    99import java.awt.Font;
     10import java.awt.GridBagLayout;
    1011import java.awt.Point;
    1112import java.awt.Rectangle;
     
    1920import java.util.ArrayList;
    2021import java.util.Arrays;
     22import java.util.Collection;
    2123import java.util.Collections;
    2224import java.util.List;
     
    2426
    2527import javax.swing.AbstractAction;
     28import javax.swing.BorderFactory;
    2629import javax.swing.DefaultCellEditor;
    2730import javax.swing.DefaultListSelectionModel;
     
    3134import javax.swing.JLabel;
    3235import javax.swing.JMenuItem;
     36import javax.swing.JPanel;
    3337import javax.swing.JPopupMenu;
    3438import javax.swing.JSlider;
     
    6771import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
    6872import org.openstreetmap.josm.tools.CheckParameterUtil;
     73import org.openstreetmap.josm.tools.GBC;
    6974import org.openstreetmap.josm.tools.ImageProvider;
    7075import org.openstreetmap.josm.tools.InputMapUtils;
     
    264269        adaptTo(showHideLayerAction, selectionModel);
    265270
    266         // -- layer opacity action
    267         LayerOpacityAction layerOpacityAction = new LayerOpacityAction(model);
    268         adaptTo(layerOpacityAction, selectionModel);
    269         SideButton opacityButton = new SideButton(layerOpacityAction, false);
    270         layerOpacityAction.setCorrespondingSideButton(opacityButton);
    271 
    272         // -- layer gamma action
    273         LayerGammaAction layerGammaAction = new LayerGammaAction(model);
    274         adaptTo(layerGammaAction, selectionModel);
    275         SideButton gammaButton = new SideButton(layerGammaAction, false);
    276         layerGammaAction.setCorrespondingSideButton(gammaButton);
     271        LayerVisibilityAction visibilityAction = new LayerVisibilityAction(model);
     272        adaptTo(visibilityAction, selectionModel);
     273        SideButton visibilityButton = new SideButton(visibilityAction, false);
     274        visibilityAction.setCorrespondingSideButton(visibilityButton);
    277275
    278276        // -- delete layer action
     
    301299                new SideButton(moveDownAction, false),
    302300                new SideButton(activateLayerAction, false),
    303                 new SideButton(showHideLayerAction, false),
    304                 opacityButton,
    305                 gammaButton,
     301                visibilityButton,
    306302                new SideButton(deleteLayerAction, false)
    307303        ));
     
    529525
    530526    /**
    531      * Abstract action which allows to adjust a double value using a slider
    532      */
    533     public abstract static class AbstractLayerPropertySliderAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
    534         protected final LayerListModel model;
    535         protected final JPopupMenu popup;
    536         protected final JSlider slider;
    537         private final double factor;
     527     * This is a menu that includes all settings for the layer visibility. It combines gamma/opacity sliders and the visible-checkbox.
     528     *
     529     * @author Michael Zangl
     530     */
     531    public static final class LayerVisibilityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
     532        protected static final int SLIDER_STEPS = 100;
     533        private static final double MAX_GAMMA_FACTOR = 2;
     534        private final LayerListModel model;
     535        private final JPopupMenu popup;
     536        private JSlider opacitySlider;
     537        private JSlider gammaSlider;
    538538        private SideButton sideButton;
    539 
    540         protected AbstractLayerPropertySliderAction(LayerListModel model, String name, final double factor) {
    541             super(name);
     539        private JCheckBox visibilityCheckbox;
     540
     541        /**
     542         * Creates a new {@link LayerVisibilityAction}
     543         * @param model The list to get the selection from.
     544         */
     545        public LayerVisibilityAction(LayerListModel model) {
    542546            this.model = model;
    543             this.factor = factor;
    544             updateEnabledState();
    545 
    546547            popup = new JPopupMenu();
    547             slider = new JSlider(JSlider.VERTICAL);
    548             slider.addChangeListener(new ChangeListener() {
     548
     549            // just to add a border
     550            JPanel content = new JPanel();
     551            popup.add(content);
     552            content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
     553            content.setLayout(new GridBagLayout());
     554
     555            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "visibility"));
     556            putValue(SHORT_DESCRIPTION, tr("Change visibility of the selected layer."));
     557
     558            visibilityCheckbox = new JCheckBox(tr("Show layer"));
     559            visibilityCheckbox.addChangeListener(new ChangeListener() {
    549560                @Override
    550561                public void stateChanged(ChangeEvent e) {
    551                     setValue(slider.getValue() / factor);
     562                    setVisible(visibilityCheckbox.isSelected());
    552563                }
    553564            });
    554             popup.add(slider);
    555         }
    556 
    557         protected abstract void setValue(double value);
    558 
    559         protected abstract double getValue();
    560 
    561         /**
    562          * Sets the corresponding side button.
    563          * @param sideButton the corresponding side button
    564          */
    565         final void setCorrespondingSideButton(SideButton sideButton) {
    566             this.sideButton = sideButton;
     565            content.add(visibilityCheckbox, GBC.eop());
     566
     567            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "transparency")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
     568            content.add(new JLabel(tr("Opacity")), GBC.eol());
     569            opacitySlider = new JSlider(JSlider.HORIZONTAL);
     570            opacitySlider.setMaximum(SLIDER_STEPS);
     571            opacitySlider.addChangeListener(new ChangeListener() {
     572                @Override
     573                public void stateChanged(ChangeEvent e) {
     574                    setOpacityValue(readOpacityValue(), opacitySlider.getValueIsAdjusting());
     575                }
     576            });
     577            opacitySlider.setToolTipText(tr("Adjust opacity of the layer."));
     578            content.add(opacitySlider, GBC.eop());
     579
     580            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "gamma")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
     581            content.add(new JLabel(tr("Gamma")), GBC.eol());
     582            gammaSlider = new JSlider(JSlider.HORIZONTAL);
     583            gammaSlider.setMaximum(SLIDER_STEPS);
     584            gammaSlider.addChangeListener(new ChangeListener() {
     585                @Override
     586                public void stateChanged(ChangeEvent e) {
     587                    setGammaValue(readGammaValue());
     588                }
     589            });
     590            gammaSlider.setToolTipText(tr("Adjust gamma value of the layer."));
     591            content.add(gammaSlider, GBC.eol());
     592        }
     593
     594        protected double readOpacityValue() {
     595            return (double) opacitySlider.getValue() / SLIDER_STEPS;
     596        }
     597
     598        protected double readGammaValue() {
     599            return (double) gammaSlider.getValue() / SLIDER_STEPS * MAX_GAMMA_FACTOR;
     600        }
     601
     602        protected void setVisible(boolean visible) {
     603            for (Layer l : model.getSelectedLayers()) {
     604                l.setVisible(visible);
     605            }
     606            updateValues();
     607        }
     608
     609        protected void setOpacityValue(double value, boolean adjusting) {
     610            if (value <= 0 && !adjusting) {
     611                setVisible(false);
     612            } else {
     613                for (Layer l : model.getSelectedLayers()) {
     614                    l.setOpacity(value);
     615                }
     616            }
     617        }
     618
     619        protected void setGammaValue(double value) {
     620            for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
     621                imageryLayer.setGamma(value);
     622            }
    567623        }
    568624
    569625        @Override
    570626        public void actionPerformed(ActionEvent e) {
    571             slider.setValue((int) (getValue() * factor));
     627            updateValues();
    572628            if (e.getSource() == sideButton) {
    573629                popup.show(sideButton, 0, sideButton.getHeight());
     
    579635        }
    580636
     637        protected void updateValues() {
     638            List<Layer> layers = model.getSelectedLayers();
     639
     640            visibilityCheckbox.setEnabled(!layers.isEmpty());
     641            boolean allVisible = true;
     642            boolean allHidden = true;
     643            for (Layer l : layers) {
     644                allVisible &= l.isVisible();
     645                allHidden &= !l.isVisible();
     646            }
     647            // TODO: Indicate tristate.
     648            visibilityCheckbox.setSelected(allVisible && !allHidden);
     649
     650            updateOpacitySlider(layers, allHidden);
     651
     652            updateGammaSlider(layers, allHidden);
     653        }
     654
     655        private void updateGammaSlider(List<Layer> layers, boolean allHidden) {
     656            Collection<ImageryLayer> gammaLayers = Utils.filteredCollection(layers, ImageryLayer.class);
     657            if (gammaLayers.isEmpty() || allHidden) {
     658                gammaSlider.setEnabled(false);
     659            } else {
     660                gammaSlider.setEnabled(true);
     661                double gamma = gammaLayers.iterator().next().getGamma();
     662                gammaSlider.setValue((int) (gamma * SLIDER_STEPS / MAX_GAMMA_FACTOR));
     663            }
     664        }
     665
     666        private void updateOpacitySlider(List<Layer> layers, boolean allHidden) {
     667            if (layers.isEmpty() || allHidden) {
     668                opacitySlider.setEnabled(false);
     669            } else {
     670                opacitySlider.setEnabled(true);
     671                double opacity = 0;
     672                for (Layer l : layers) {
     673                    opacity += l.getOpacity();
     674                }
     675                opacity /= layers.size();
     676                if (opacity == 0) {
     677                    opacity = 1;
     678                    setOpacityValue(opacity, false);
     679                }
     680                opacitySlider.setValue((int) (opacity * SLIDER_STEPS));
     681            }
     682        }
     683
     684        @Override
     685        public boolean supportLayers(List<Layer> layers) {
     686            return !layers.isEmpty();
     687        }
     688
    581689        @Override
    582690        public Component createMenuComponent() {
    583691            return new JMenuItem(this);
    584692        }
    585     }
    586 
    587     /**
    588      * Action which allows to change the opacity of one or more layers.
    589      */
    590     public static final class LayerOpacityAction extends AbstractLayerPropertySliderAction {
    591         private transient Layer layer;
    592 
    593         /**
    594          * Creates a {@link LayerOpacityAction} which allows to change the opacity of one or more layers.
    595          *
    596          * @param model layer list model
    597          * @param layer  the layer. Must not be null.
    598          * @throws IllegalArgumentException if layer is null
    599          */
    600         public LayerOpacityAction(LayerListModel model, Layer layer) {
    601             this(model);
    602             CheckParameterUtil.ensureParameterNotNull(layer, "layer");
    603             this.layer = layer;
    604             updateEnabledState();
    605         }
    606 
    607         /**
    608          * Creates a {@link ShowHideLayerAction} which will toggle the visibility of the currently selected layers
    609          * @param model layer list model
    610          */
    611         public LayerOpacityAction(LayerListModel model) {
    612             super(model, tr("Opacity"), 100);
    613             putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
    614             putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
    615         }
    616 
    617         @Override
    618         protected void setValue(double value) {
    619             if (!isEnabled()) return;
    620             if (layer != null) {
    621                 layer.setOpacity(value);
    622             } else {
    623                 for (Layer l : model.getSelectedLayers()) {
    624                     l.setOpacity(value);
    625                 }
    626             }
    627         }
    628 
    629         @Override
    630         protected double getValue() {
    631             if (layer != null)
    632                 return layer.getOpacity();
    633             else {
    634                 double opacity = 0;
    635                 List<Layer> layers = model.getSelectedLayers();
    636                 for (Layer l : layers) {
    637                     opacity += l.getOpacity();
    638                 }
    639                 return opacity / layers.size();
    640             }
    641         }
    642693
    643694        @Override
    644695        public void updateEnabledState() {
    645             if (layer == null) {
    646                 setEnabled(!model.getSelectedLayers().isEmpty());
    647             } else {
    648                 setEnabled(true);
    649             }
    650         }
    651 
    652         @Override
    653         public boolean supportLayers(List<Layer> layers) {
    654             return true;
    655         }
    656     }
    657 
    658     /**
    659      * Action which allows to change the gamma of one imagery layer.
    660      */
    661     public static final class LayerGammaAction extends AbstractLayerPropertySliderAction {
    662 
    663         /**
    664          * Constructs a new {@code LayerGammaAction}.
    665          * @param model layer list model
    666          */
    667         public LayerGammaAction(LayerListModel model) {
    668             super(model, tr("Gamma"), 50);
    669             putValue(SHORT_DESCRIPTION, tr("Adjust gamma value of the layer."));
    670             putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "gamma"));
    671         }
    672 
    673         @Override
    674         protected void setValue(double value) {
    675             for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
    676                 imageryLayer.setGamma(value);
    677             }
    678         }
    679 
    680         @Override
    681         protected double getValue() {
    682             return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma();
    683         }
    684 
    685         @Override
    686         public void updateEnabledState() {
    687             setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty());
    688         }
    689 
    690         @Override
    691         public boolean supportLayers(List<Layer> layers) {
    692             return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty();
     696            setEnabled(!model.getSelectedLayers().isEmpty());
     697        }
     698
     699        /**
     700         * Sets the corresponding side button.
     701         * @param sideButton the corresponding side button
     702         */
     703        void setCorrespondingSideButton(SideButton sideButton) {
     704            this.sideButton = sideButton;
    693705        }
    694706    }
  • trunk/src/org/openstreetmap/josm/gui/layer/Layer.java

    r10008 r10011  
    361361    }
    362362
     363    /**
     364     * Gets the opacity of the layer, in range 0...1
     365     * @return The opacity
     366     */
    363367    public double getOpacity() {
    364368        return opacity;
    365369    }
    366370
     371    /**
     372     * Sets the opacity of the layer, in range 0...1
     373     * @param opacity The opacity
     374     * @throws IllegalArgumentException if the opacity is out of range
     375     */
    367376    public void setOpacity(double opacity) {
    368377        if (!(opacity >= 0 && opacity <= 1))
  • trunk/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java

    r9926 r10011  
    33
    44import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertFalse;
    56import static org.junit.Assert.assertTrue;
    67
     
    910import org.openstreetmap.josm.JOSMFixture;
    1011import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerGammaAction;
    1212import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel;
    13 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerOpacityAction;
     13import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerVisibilityAction;
    1414import org.openstreetmap.josm.gui.layer.TMSLayer;
    1515import org.openstreetmap.josm.gui.layer.TMSLayerTest;
     
    2929
    3030    /**
    31      * Unit test of {@link LayerGammaAction} class.
     31     * Unit test of {@link LayerVisibilityAction} class.
    3232     */
    3333    @Test
    34     public void testLayerGammaAction() {
     34    public void testLayerVisibilityAction() {
    3535        TMSLayer layer = TMSLayerTest.createTmsLayer();
    3636        try {
     37            LayerListModel model = LayerListDialog.getInstance().getModel();
     38            LayerVisibilityAction action = new LayerVisibilityAction(model);
     39            action.updateEnabledState();
     40            assertFalse(action.isEnabled());
     41
    3742            Main.map.mapView.addLayer(layer);
    38             LayerListModel model = LayerListDialog.getInstance().getModel();
    39             LayerGammaAction action = new LayerGammaAction(model);
    4043            action.updateEnabledState();
    4144            assertTrue(action.isEnabled());
    4245            assertTrue(action.supportLayers(model.getSelectedLayers()));
    43             assertEquals(1.0, action.getValue(), 1e-15);
    44             action.setValue(0.5);
    45             assertEquals(0.5, action.getValue(), 1e-15);
    46         } finally {
    47             Main.map.mapView.removeLayer(layer);
    48         }
    49     }
    5046
    51     /**
    52      * Unit test of {@link LayerOpacityAction} class.
    53      */
    54     @Test
    55     public void testLayerOpacityAction() {
    56         TMSLayer layer = TMSLayerTest.createTmsLayer();
    57         try {
    58             Main.map.mapView.addLayer(layer);
    59             LayerListModel model = LayerListDialog.getInstance().getModel();
    60             LayerOpacityAction action = new LayerOpacityAction(model);
    61             action.updateEnabledState();
    62             assertTrue(action.isEnabled());
    63             assertTrue(action.supportLayers(model.getSelectedLayers()));
    64             assertEquals(1.0, action.getValue(), 1e-15);
    65             action.setValue(0.5);
    66             assertEquals(0.5, action.getValue(), 1e-15);
     47            // now check values
     48            action.updateValues();
     49            assertEquals(1.0, action.readOpacityValue(), 1e-15);
     50            assertEquals(1.0, action.readGammaValue(), 1e-15);
     51
     52            action.setOpacityValue(.5, false);
     53            action.setGammaValue(1.5);
     54            action.updateValues();
     55
     56            assertEquals(0.5, action.readOpacityValue(), 1e-15);
     57            assertEquals(1.5, action.readGammaValue(), 1e-15);
     58
     59            action.setVisible(false);
     60            action.updateValues();
     61            assertFalse(layer.isVisible());
     62
     63            action.setVisible(true);
     64            action.updateValues();
     65            assertTrue(layer.isVisible());
     66
     67            // layer stays visible during adjust
     68            action.setOpacityValue(0, true);
     69            assertEquals(0, layer.getOpacity(), 1e-15);
     70            layer.setOpacity(.1); // to make layer.isVisible work
     71            assertTrue(layer.isVisible());
     72            layer.setOpacity(0);
     73
     74            action.setOpacityValue(0, false);
     75            assertEquals(0, layer.getOpacity(), 1e-15);
     76            layer.setOpacity(.1); // to make layer.isVisible work
     77            assertFalse(layer.isVisible());
     78            layer.setOpacity(0);
     79            action.updateValues();
     80
     81            // Opacity reset when it was 0 and user set layer to visible.
     82            action.setVisible(true);
     83            action.updateValues();
     84            assertEquals(1.0, action.readOpacityValue(), 1e-15);
     85            assertEquals(1.0, layer.getOpacity(), 1e-15);
     86
    6787        } finally {
    6888            Main.map.mapView.removeLayer(layer);
Note: See TracChangeset for help on using the changeset viewer.