Repository: napari/napari

Issue:
Contrast limits slider doesn't update correctly after reset
### 🐛 Bug Report

I am not sure what the root cause is, but I am experiencing that float data with a large range of contrast can cause problems with the contrast slider pop-up. When the range in a single slice is extremely small (e.g. 1E-25 to 4E-25), but the range in the whole array is large (e.g. 1E-25 to 1E25), I constantly need to reset the contrast slider when scrolling through slices, in order to be able to adjust the contrast limits in any one slice. I therefore often open the contrast limits slider pop-up, and hit the 'reset' button. However, after hitting the reset button the slider in the pop-up freezes up and doesn't correctly show the limits in its labels.

### 💡 Steps to Reproduce

```
# imports
import numpy as np
import napari

# create image array
arr = np.arange(1,9,1,dtype=np.float32).reshape((2,2,2))
arr[0,:,:] = arr[0,:,:]*1E-20
arr[1,:,:] = arr[1,:,:]*1E+20

# open the image
viewer, image_layer = napari.imshow(arr)
```

1. Click on 'continuous' auto-contrast.
2. Right-click the contrast limits slider to bring up the contrast limits pop-up.
3. Click the 'reset' button.
4. After clicking the reset button, the slider labels all just show '0', and it is not possible to drag the slider handles.
5. Click in the main window to close the contrast slider pop-up.
6. Again, right-click the contrast limits slider to bring up the contrast limits pop-up.
7. Now the labels show the 'correct' values (0.000000000000... which gets cut off), and it is possible to move the slider handles.
8. Close the pop-up, switch to the second index (1,:,:), and switch back to the first. This 're-sets' the problem. Go back to step 2 and repeat. 

### 💡 Expected Behavior

After hitting the 'reset' button, the slider in the pop-up should update correctly, show the new limits in the labels, and be draggable. 

### 🌎 Environment

napari: 0.5.0a2.dev486+g4d60a7ce
Platform: Windows-10-10.0.19045-SP0
Python: 3.9.18 | packaged by conda-forge | (main, Aug 30 2023, 03:40:31) [MSC v.1929 64 bit (AMD64)]
Qt: 5.15.2
PyQt5: 5.15.10
NumPy: 1.26.2
SciPy: 1.11.4
Dask: 2023.12.0
VisPy: 0.14.1
magicgui: 0.8.0
superqt: 0.6.1
in-n-out: 0.1.9
app-model: 0.2.2
npe2: 0.7.3

OpenGL:
  - GL version:  4.6.0 - Build 27.20.100.9565
  - MAX_TEXTURE_SIZE: 16384

Screens:
  - screen 1: resolution 1920x1200, scale 1.0

Settings path:
  - C:\Users\...\AppData\Local\napari\napari-env_4624f08893c59545bcb98518a8c42a23d61d4ece\settings.yaml

### 💡 Additional Context

Somewhat unrelated, but I would also suggest that it might be an idea to have the reset button for the contrast limits slider somewhere in the main GUI, as it's a bit of a pain to have to constantly open the pop-up to reset when each slice has wildly different contrast limits.         

Finally, we should consider using scientific notation in the contrast limits slider labels when the numbers get very small or large, as its not very helpful to see a cut-off 0.000000000000...


Discussion:
Does setting the auto contrast to a continuous mode does not solve your original problem of reset clicking? 

![obraz](https://github.com/napari/napari/assets/3826210/5ab5c3c8-16fa-4e36-a104-f1c3f27547e7)

@Czaki No, that adjusts the contrast limits, but (apparently) not the contrast limits slider max/min when the new contrast limits are within the old max/min. But if the max/min are something like 1E-25 and 1E25, and the new dynamic range is something like 1E-25 to 2E-25, you need to reset the slider to be able to adjust within that tight dynamic range. Hopefully the reproduction code clarifies what I mean? 
Please describe use case where you need to do such contrast manual alignment. We need to understand it. Adding any new button to the GUI is a really hard decision. The space is limited. 
Sure! The situation would be any where different slices of an Nd array have very different dynamic ranges, and you want to be able to reasonably quickly both scroll through the slices and adjust the contrast limits in any one slice. The idea of adding the reset button (currently found in the contrast limit slider pop-up) to the main GUI is fairly minor QoL matter - a keyboard shortcut to reset the contrast limits slider max/min to the dynamic range of the current slice would work just as well.

All this is not, however, the main point of this bug report. The bug is simply that the contrast limits slider (in the pop-up) does not update correctly when the reset button is clicked.   
> No, that adjusts the contrast limits, but (apparently) not the contrast limits slider max/min when the new contrast limits are within the old max/min.

Ah, OK i get what triggered the issue then. Continuous was working correctly. Maybe it *should* also reset the limits of the slider for some dtypes?
> Ah, OK i get what triggered the issue then. Continuous was working correctly. Maybe it _should_ also reset the limits of the slider for some dtypes?

I rather think that we should switch (or allow to switch) to log sliders. 

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
@@ -254,6 +254,11 @@ def __init__(self, layer: Image, parent=None) -> None:
         def reset():
             layer.reset_contrast_limits()
             layer.contrast_limits_range = layer.contrast_limits
+            decimals_ = range_to_decimals(
+                layer.contrast_limits_range, layer.dtype
+            )
+            self.slider.setDecimals(decimals_)
+            self.slider.setSingleStep(10**-decimals_)
 
         reset_btn = QPushButton("reset")
         reset_btn.setObjectName("reset_clims_button")


Test patch: