diff --git a/images/dialogs/layerlist/visibility.png b/images/dialogs/layerlist/visibility.png
new file mode 100644
index 0000000..dd019e8
Binary files /dev/null and b/images/dialogs/layerlist/visibility.png differ
diff --git a/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
index af5f61c..793abfb 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
@@ -7,6 +7,7 @@ import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Font;
+import java.awt.GridBagLayout;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
@@ -18,11 +19,13 @@ import java.beans.PropertyChangeListener;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
 import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultListSelectionModel;
 import javax.swing.ImageIcon;
@@ -30,6 +33,7 @@ import javax.swing.JCheckBox;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
 import javax.swing.JMenuItem;
+import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JSlider;
 import javax.swing.JTable;
@@ -66,6 +70,7 @@ import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.InputMapUtils;
 import org.openstreetmap.josm.tools.MultikeyActionsHandler;
@@ -263,17 +268,10 @@ public class LayerListDialog extends ToggleDialog {
         MultikeyActionsHandler.getInstance().addAction(showHideLayerAction);
         adaptTo(showHideLayerAction, selectionModel);
 
-        // -- layer opacity action
-        LayerOpacityAction layerOpacityAction = new LayerOpacityAction(model);
-        adaptTo(layerOpacityAction, selectionModel);
-        SideButton opacityButton = new SideButton(layerOpacityAction, false);
-        layerOpacityAction.setCorrespondingSideButton(opacityButton);
-
-        // -- layer gamma action
-        LayerGammaAction layerGammaAction = new LayerGammaAction(model);
-        adaptTo(layerGammaAction, selectionModel);
-        SideButton gammaButton = new SideButton(layerGammaAction, false);
-        layerGammaAction.setCorrespondingSideButton(gammaButton);
+        LayerVisibilityAction visibilityAction = new LayerVisibilityAction(model);
+        adaptTo(visibilityAction, selectionModel);
+        SideButton visibilityButton = new SideButton(visibilityAction, false);
+        visibilityAction.setCorrespondingSideButton(visibilityButton);
 
         // -- delete layer action
         DeleteLayerAction deleteLayerAction = new DeleteLayerAction();
@@ -300,9 +298,7 @@ public class LayerListDialog extends ToggleDialog {
                 new SideButton(moveUpAction, false),
                 new SideButton(moveDownAction, false),
                 new SideButton(activateLayerAction, false),
-                new SideButton(showHideLayerAction, false),
-                opacityButton,
-                gammaButton,
+                visibilityButton,
                 new SideButton(deleteLayerAction, false)
         ));
 
@@ -605,10 +601,10 @@ public class LayerListDialog extends ToggleDialog {
         }
 
         /**
-         * Creates a {@link ShowHideLayerAction} which will toggle the visibility of the currently selected layers
+         * Creates a {@link LayerOpacityAction} which will toggle the visibility of layers
          * @param model layer list model
          */
-        public LayerOpacityAction(LayerListModel model) {
+        private LayerOpacityAction(LayerListModel model) {
             super(model, tr("Opacity"), 100);
             putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
@@ -616,37 +612,17 @@ public class LayerListDialog extends ToggleDialog {
 
         @Override
         protected void setValue(double value) {
-            if (!isEnabled()) return;
-            if (layer != null) {
-                layer.setOpacity(value);
-            } else {
-                for (Layer l : model.getSelectedLayers()) {
-                    l.setOpacity(value);
-                }
-            }
+            layer.setOpacity(value);
         }
 
         @Override
         protected double getValue() {
-            if (layer != null)
-                return layer.getOpacity();
-            else {
-                double opacity = 0;
-                List<Layer> layers = model.getSelectedLayers();
-                for (Layer l : layers) {
-                    opacity += l.getOpacity();
-                }
-                return opacity / layers.size();
-            }
+            return layer.getOpacity();
         }
 
         @Override
         public void updateEnabledState() {
-            if (layer == null) {
-                setEnabled(!model.getSelectedLayers().isEmpty());
-            } else {
-                setEnabled(true);
-            }
+            setEnabled(true);
         }
 
         @Override
@@ -656,40 +632,184 @@ public class LayerListDialog extends ToggleDialog {
     }
 
     /**
-     * Action which allows to change the gamma of one imagery layer.
+     * This is a menu that includes all settings for the layer visibility. It combines gamma/opacity sliders and the visible-checkbox.
+     *
+     * @author Michael Zangl
      */
-    public static final class LayerGammaAction extends AbstractLayerPropertySliderAction {
+    public static final class LayerVisibilityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
+        protected static final int SLIDER_STEPS = 100;
+        private static final double MAX_GAMMA_FACTOR = 2;
+        private final LayerListModel model;
+        private final JPopupMenu popup;
+        private JSlider opacitySlider;
+        private JSlider gammaSlider;
+        private SideButton sideButton;
+        private JCheckBox visibilityCheckbox;
 
         /**
-         * Constructs a new {@code LayerGammaAction}.
-         * @param model layer list model
+         * Creates a new {@link LayerVisibilityAction}
+         * @param model The list to get the selection from.
          */
-        public LayerGammaAction(LayerListModel model) {
-            super(model, tr("Gamma"), 50);
-            putValue(SHORT_DESCRIPTION, tr("Adjust gamma value of the layer."));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "gamma"));
+        public LayerVisibilityAction(LayerListModel model) {
+            this.model = model;
+            popup = new JPopupMenu();
+
+            // just to add a border
+            JPanel content = new JPanel();
+            popup.add(content);
+            content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+            content.setLayout(new GridBagLayout());
+
+            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "visibility"));
+            putValue(SHORT_DESCRIPTION, tr("Change visibility of the selected layer."));
+
+            visibilityCheckbox = new JCheckBox(tr("Show layer"));
+            visibilityCheckbox.addChangeListener(new ChangeListener() {
+                @Override
+                public void stateChanged(ChangeEvent e) {
+                    setVisible(visibilityCheckbox.isSelected());
+                }
+            });
+            content.add(visibilityCheckbox, GBC.eop());
+
+            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "transparency")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
+            content.add(new JLabel(tr("Opacity")), GBC.eol());
+            opacitySlider = new JSlider(JSlider.HORIZONTAL);
+            opacitySlider.setMaximum(SLIDER_STEPS);
+            opacitySlider.addChangeListener(new ChangeListener() {
+                @Override
+                public void stateChanged(ChangeEvent e) {
+                    setOpacityValue(readOpacityValue(), opacitySlider.getValueIsAdjusting());
+                }
+            });
+            opacitySlider.setToolTipText(tr("Adjust opacity of the layer."));
+            content.add(opacitySlider, GBC.eop());
+
+            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "gamma")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
+            content.add(new JLabel(tr("Gamma")), GBC.eol());
+            gammaSlider = new JSlider(JSlider.HORIZONTAL);
+            gammaSlider.setMaximum(SLIDER_STEPS);
+            gammaSlider.addChangeListener(new ChangeListener() {
+                @Override
+                public void stateChanged(ChangeEvent e) {
+                    setGammaValue(readGammaValue());
+                }
+            });
+            gammaSlider.setToolTipText(tr("Adjust gamma value of the layer."));
+            content.add(gammaSlider, GBC.eol());
         }
 
-        @Override
-        protected void setValue(double value) {
+        protected double readOpacityValue() {
+            return (double) opacitySlider.getValue() / SLIDER_STEPS;
+        }
+
+        protected double readGammaValue() {
+            return (double) gammaSlider.getValue() / SLIDER_STEPS * MAX_GAMMA_FACTOR;
+        }
+
+        protected void setVisible(boolean visible) {
+            for (Layer l : model.getSelectedLayers()) {
+                l.setVisible(visible);
+            }
+            updateValues();
+        }
+
+        protected void setOpacityValue(double value, boolean adjusting) {
+            if (value <= 0 && !adjusting) {
+                setVisible(false);
+            } else {
+                for (Layer l : model.getSelectedLayers()) {
+                    l.setOpacity(value);
+                }
+            }
+        }
+
+        protected void setGammaValue(double value) {
             for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
                 imageryLayer.setGamma(value);
             }
         }
 
         @Override
-        protected double getValue() {
-            return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma();
+        public void actionPerformed(ActionEvent e) {
+            updateValues();
+            if (e.getSource() == sideButton) {
+                popup.show(sideButton, 0, sideButton.getHeight());
+            } else {
+                // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
+                // In that case, show it in the middle of screen (because opacityButton is not visible)
+                popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
+            }
         }
 
-        @Override
-        public void updateEnabledState() {
-            setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty());
+        protected void updateValues() {
+            List<Layer> layers = model.getSelectedLayers();
+
+            visibilityCheckbox.setEnabled(!layers.isEmpty());
+            boolean allVisible = true;
+            boolean allHidden = true;
+            for (Layer l : layers) {
+                allVisible &= l.isVisible();
+                allHidden &= !l.isVisible();
+            }
+            // TODO: Indicate tristate.
+            visibilityCheckbox.setSelected(allVisible && !allHidden);
+
+            updateOpacitySlider(layers, allHidden);
+
+            updateGammaSlider(layers, allHidden);
+        }
+
+        private void updateGammaSlider(List<Layer> layers, boolean allHidden) {
+            Collection<ImageryLayer> gammaLayers = Utils.filteredCollection(layers, ImageryLayer.class);
+            if (gammaLayers.isEmpty() || allHidden) {
+                gammaSlider.setEnabled(false);
+            } else {
+                gammaSlider.setEnabled(true);
+                double gamma = gammaLayers.iterator().next().getGamma();
+                gammaSlider.setValue((int) (gamma * SLIDER_STEPS / MAX_GAMMA_FACTOR));
+            }
+        }
+
+        private void updateOpacitySlider(List<Layer> layers, boolean allHidden) {
+            if (layers.isEmpty() || allHidden) {
+                opacitySlider.setEnabled(false);
+            } else {
+                opacitySlider.setEnabled(true);
+                double opacity = 0;
+                for (Layer l : layers) {
+                    opacity += l.getOpacity();
+                }
+                opacity /= layers.size();
+                if (opacity == 0) {
+                    opacity = 1;
+                    setOpacityValue(opacity, false);
+                }
+                opacitySlider.setValue((int) (opacity * SLIDER_STEPS));
+            }
         }
 
         @Override
         public boolean supportLayers(List<Layer> layers) {
-            return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty();
+            return !layers.isEmpty();
+        }
+
+        @Override
+        public Component createMenuComponent() {
+            return new JMenuItem(this);
+        }
+
+        @Override
+        public void updateEnabledState() {
+            setEnabled(!model.getSelectedLayers().isEmpty());
+        }
+
+        /**
+         * Sets the corresponding side button.
+         * @param sideButton the corresponding side button
+         */
+        void setCorrespondingSideButton(SideButton sideButton) {
+            this.sideButton = sideButton;
         }
     }
 
diff --git a/src/org/openstreetmap/josm/gui/layer/Layer.java b/src/org/openstreetmap/josm/gui/layer/Layer.java
index 26842aa..d8fdd5c 100644
--- a/src/org/openstreetmap/josm/gui/layer/Layer.java
+++ b/src/org/openstreetmap/josm/gui/layer/Layer.java
@@ -360,10 +360,19 @@ public abstract class Layer implements Destroyable, MapViewPaintable, Projection
         return visible && opacity != 0;
     }
 
+    /**
+     * Gets the opacity of the layer, in range 0...1
+     * @return The opacity
+     */
     public double getOpacity() {
         return opacity;
     }
 
+    /**
+     * Sets the opacity of the layer, in range 0...1
+     * @param opacity The opacity
+     * @throws IllegalArgumentException if the opacity is out of range
+     */
     public void setOpacity(double opacity) {
         if (!(opacity >= 0 && opacity <= 1))
             throw new IllegalArgumentException("Opacity value must be between 0 and 1");
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java
index 74100c7..33b7e6f 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java
@@ -2,15 +2,16 @@
 package org.openstreetmap.josm.gui.dialogs;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerGammaAction;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerOpacityAction;
+import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerVisibilityAction;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.gui.layer.TMSLayerTest;
 
@@ -28,28 +29,69 @@ public class LayerListDialogTest {
     }
 
     /**
-     * Unit test of {@link LayerGammaAction} class.
+     * Unit test of {@link LayerVisibilityAction} class.
      */
     @Test
-    public void testLayerGammaAction() {
+    public void testLayerVisibilityAction() {
         TMSLayer layer = TMSLayerTest.createTmsLayer();
         try {
-            Main.map.mapView.addLayer(layer);
             LayerListModel model = LayerListDialog.getInstance().getModel();
-            LayerGammaAction action = new LayerGammaAction(model);
+            LayerVisibilityAction action = new LayerVisibilityAction(model);
+            action.updateEnabledState();
+            assertFalse(action.isEnabled());
+
+            Main.map.mapView.addLayer(layer);
             action.updateEnabledState();
             assertTrue(action.isEnabled());
             assertTrue(action.supportLayers(model.getSelectedLayers()));
-            assertEquals(1.0, action.getValue(), 1e-15);
-            action.setValue(0.5);
-            assertEquals(0.5, action.getValue(), 1e-15);
+
+            // now check values
+            action.updateValues();
+            assertEquals(1.0, action.readOpacityValue(), 1e-15);
+            assertEquals(1.0, action.readGammaValue(), 1e-15);
+
+            action.setOpacityValue(.5, false);
+            action.setGammaValue(1.5);
+            action.updateValues();
+
+            assertEquals(0.5, action.readOpacityValue(), 1e-15);
+            assertEquals(1.5, action.readGammaValue(), 1e-15);
+
+            action.setVisible(false);
+            action.updateValues();
+            assertFalse(layer.isVisible());
+
+            action.setVisible(true);
+            action.updateValues();
+            assertTrue(layer.isVisible());
+
+            // layer stays visible during adjust
+            action.setOpacityValue(0, true);
+            assertEquals(0, layer.getOpacity(), 1e-15);
+            layer.setOpacity(.1); // to make layer.isVisible work
+            assertTrue(layer.isVisible());
+            layer.setOpacity(0);
+
+            action.setOpacityValue(0, false);
+            assertEquals(0, layer.getOpacity(), 1e-15);
+            layer.setOpacity(.1); // to make layer.isVisible work
+            assertFalse(layer.isVisible());
+            layer.setOpacity(0);
+            action.updateValues();
+
+            // Opacity reset when it was 0 and user set layer to visible.
+            action.setVisible(true);
+            action.updateValues();
+            assertEquals(1.0, action.readOpacityValue(), 1e-15);
+            assertEquals(1.0, layer.getOpacity(), 1e-15);
+
         } finally {
             Main.map.mapView.removeLayer(layer);
         }
     }
 
     /**
-     * Unit test of {@link LayerOpacityAction} class.
+     * Unit test of {@link LayerOpacityAction} class for single layer.
      */
     @Test
     public void testLayerOpacityAction() {
@@ -57,7 +99,7 @@ public class LayerListDialogTest {
         try {
             Main.map.mapView.addLayer(layer);
             LayerListModel model = LayerListDialog.getInstance().getModel();
-            LayerOpacityAction action = new LayerOpacityAction(model);
+            LayerOpacityAction action = new LayerOpacityAction(model, layer);
             action.updateEnabledState();
             assertTrue(action.isEnabled());
             assertTrue(action.supportLayers(model.getSelectedLayers()));
