Repository: napari/napari

Issue:
bug in contrast slider popup when dtype is a signed integer
## 🐛 Bug

I noticed a few issues with the contrast limits popup widget:

1.) The "full range" button appears for signed integer dtype, but the button [only has any effect on unsigned integer inputs](https://github.com/napari/napari/blob/eb9ef90f5de9858523da5a02ab7044427911410c/napari/layers/intensity_mixin.py#L43-L51). Here is the slider I see for signed integer data:

![contrast_slider_signed_bug](https://user-images.githubusercontent.com/6528957/154597556-38549ee3-2639-4b0f-8f16-f971c61f84cb.png)

2.) The button sizes are also a bit too small and the text appears a bit truncated (also visible in image above). Do others also see this?

3.) I have a question about the desired behavior of the "reset" button. Currently it always resets based on the data range. However, if the user had provided `contrast_limits` as a kwarg when adding the layer, should it instead reset to those?

I can make a small PR to fix issues 1 and 2, but need some feedback regarding desired behavior for item 3.

## To Reproduce

Steps to reproduce the behavior:

1. add a signed integer layer via the console

```Python
import numpy as np
x = np.arange(256*256, dtype=int).reshape(256, 256)
viewer.add_layer(x)
```

2. right click on the contrast limits slider

## Expected behavior

No "full range" button should be shown and text on the buttons should be fully legible.

## Environment

 - Please copy and paste the information at napari info option in help menubar here:

 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->



Discussion:

Resolving patch:
diff --git a/napari/_qt/layer_controls/qt_image_controls_base.py b/napari/_qt/layer_controls/qt_image_controls_base.py
--- a/napari/_qt/layer_controls/qt_image_controls_base.py
+++ b/napari/_qt/layer_controls/qt_image_controls_base.py
@@ -235,7 +235,7 @@ def reset():
         reset_btn = QPushButton("reset")
         reset_btn.setObjectName("reset_clims_button")
         reset_btn.setToolTip(trans._("autoscale contrast to data range"))
-        reset_btn.setFixedWidth(40)
+        reset_btn.setFixedWidth(45)
         reset_btn.clicked.connect(reset)
         self._layout.addWidget(reset_btn, alignment=Qt.AlignBottom)
 
@@ -248,7 +248,7 @@ def reset():
             range_btn.setToolTip(
                 trans._("set contrast range to full bit-depth")
             )
-            range_btn.setFixedWidth(65)
+            range_btn.setFixedWidth(75)
             range_btn.clicked.connect(layer.reset_contrast_limits_range)
             self._layout.addWidget(range_btn, alignment=Qt.AlignBottom)
 
diff --git a/napari/layers/intensity_mixin.py b/napari/layers/intensity_mixin.py
--- a/napari/layers/intensity_mixin.py
+++ b/napari/layers/intensity_mixin.py
@@ -43,10 +43,10 @@ def reset_contrast_limits(self: 'Image', mode=None):
     def reset_contrast_limits_range(self):
         """Scale contrast limits range to data type.
 
-        Currently, this only does something if the data type is an unsigned
-        integer... otherwise it's unclear what the full range should be.
+        Currently, this only does something if the data type is an integer...
+        otherwise it's unclear what the full range should be.
         """
-        if np.issubdtype(self.dtype, np.unsignedinteger):
+        if np.issubdtype(self.dtype, np.integer):
             info = np.iinfo(self.dtype)
             self.contrast_limits_range = (info.min, info.max)
 


Test patch:
diff --git a/napari/_qt/layer_controls/_tests/test_qt_image_base_layer_.py b/napari/_qt/layer_controls/_tests/test_qt_image_base_layer_.py
--- a/napari/_qt/layer_controls/_tests/test_qt_image_base_layer_.py
+++ b/napari/_qt/layer_controls/_tests/test_qt_image_base_layer_.py
@@ -59,7 +59,9 @@ def test_changing_model_updates_view(qtbot, layer):
 
 
 @patch.object(QRangeSliderPopup, 'show')
-@pytest.mark.parametrize('layer', [Image(_IMAGE), Surface(_SURF)])
+@pytest.mark.parametrize(
+    'layer', [Image(_IMAGE), Image(_IMAGE.astype(np.int32)), Surface(_SURF)]
+)
 def test_range_popup_clim_buttons(mock_show, qtbot, layer):
     """The buttons in the clim_popup should adjust the contrast limits value"""
     qtctrl = QtBaseImageControls(layer)
@@ -79,15 +81,16 @@ def test_range_popup_clim_buttons(mock_show, qtbot, layer):
     rangebtn = qtctrl.clim_popup.findChild(
         QPushButton, "full_clim_range_button"
     )
-    # the data we created above was uint16 for Image, and float for Surface
+    # data in this test is uint16 or int32 for Image, and float for Surface.
     # Surface will not have a "full range button"
     if np.issubdtype(layer.dtype, np.integer):
+        info = np.iinfo(layer.dtype)
         rangebtn.click()
         qtbot.wait(20)
-        assert tuple(layer.contrast_limits_range) == (0, 2**16 - 1)
+        assert tuple(layer.contrast_limits_range) == (info.min, info.max)
         min_ = qtctrl.contrastLimitsSlider.minimum()
         max_ = qtctrl.contrastLimitsSlider.maximum()
-        assert (min_, max_) == (0, 2**16 - 1)
+        assert (min_, max_) == (info.min, info.max)
     else:
         assert rangebtn is None