diff --git a/docs/changelog.rst b/docs/changelog.rst index 32530ba3..db3b8c33 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,8 @@ New features ~~~~~~~~~~~~ - Added ``MPLWidget`` as a widget containing just a Matplotlib canvas without any association with a napari viewer. +- Added text to each widget indicating how many layers need to be selected + for the widget to plot something. Visual improvements ~~~~~~~~~~~~~~~~~~~ diff --git a/src/napari_matplotlib/base.py b/src/napari_matplotlib/base.py index 25b10ee7..3282cb77 100644 --- a/src/napari_matplotlib/base.py +++ b/src/napari_matplotlib/base.py @@ -10,7 +10,7 @@ ) from matplotlib.figure import Figure from qtpy.QtGui import QIcon -from qtpy.QtWidgets import QVBoxLayout, QWidget +from qtpy.QtWidgets import QLabel, QVBoxLayout, QWidget from .util import Interval, from_napari_css_get_size_of @@ -133,6 +133,11 @@ class NapariMPLWidget(BaseNapariMPLWidget): for creating and working with the Matplotlib figure and any axes. """ + #: Number of layers taken as input + n_layers_input = Interval(None, None) + #: Type of layer taken as input + input_layer_types: Tuple[napari.layers.Layer, ...] = (napari.layers.Layer,) + def __init__( self, napari_viewer: napari.viewer.Viewer, @@ -144,10 +149,9 @@ def __init__( self._setup_callbacks() self.layers: List[napari.layers.Layer] = [] - #: Number of layers taken as input - n_layers_input = Interval(None, None) - #: Type of layer taken as input - input_layer_types: Tuple[napari.layers.Layer, ...] = (napari.layers.Layer,) + helper_text = self.n_layers_input._helper_text + if helper_text is not None: + self.layout().insertWidget(0, QLabel(helper_text)) @property def n_selected_layers(self) -> int: diff --git a/src/napari_matplotlib/tests/test_util.py b/src/napari_matplotlib/tests/test_util.py index b8ebaff4..c0e664ed 100644 --- a/src/napari_matplotlib/tests/test_util.py +++ b/src/napari_matplotlib/tests/test_util.py @@ -16,6 +16,23 @@ def test_interval(): "string" in interval # type: ignore +@pytest.mark.parametrize( + "lower, upper, text", + [ + (None, None, None), + (1, None, "Select at least 1 layer to generate plot"), + (4, None, "Select at least 4 layers to generate plot"), + (None, 1, "Select at most 1 layer to generate plot"), + (None, 5939, "Select at most 5939 layers to generate plot"), + (1, 1, "Select 1 layer to generate plot"), + (2, 2, "Select 2 layers to generate plot"), + (1, 2, "Select between 1 and 2 layers to generate plot"), + ], +) +def test_interval_helper_text(lower, upper, text): + assert Interval(lower, upper)._helper_text == text + + def test_get_size_from_css(mocker): """Test getting the max-width and max-height from something in css""" test_css = """ diff --git a/src/napari_matplotlib/util.py b/src/napari_matplotlib/util.py index 17965caf..2aa15ddd 100644 --- a/src/napari_matplotlib/util.py +++ b/src/napari_matplotlib/util.py @@ -46,6 +46,35 @@ def __contains__(self, val: int) -> bool: return False return True + @property + def _helper_text(self) -> Optional[str]: + """ + Helper text for widgets. + """ + if self.lower is None and self.upper is None: + helper_text = None + elif self.lower is not None and self.upper is None: + helper_text = ( + f"Select at least {self.lower} layers to generate plot" + ) + elif self.lower is None and self.upper is not None: + helper_text = ( + f"Select at most {self.upper} layers to generate plot" + ) + elif self.lower == self.upper: + helper_text = f"Select {self.lower} layers to generate plot" + + else: + helper_text = ( + f"Select between {self.lower} and " + f"{self.upper} layers to generate plot" + ) + + if helper_text is not None: + helper_text = helper_text.replace("1 layers", "1 layer") + + return helper_text + def _has_id(nodes: List[tinycss2.ast.Node], id_name: str) -> bool: """