diff --git a/panel/tests/widgets/test_slider.py b/panel/tests/widgets/test_slider.py index 0a3f28c9ab..7c0aa4fae6 100644 --- a/panel/tests/widgets/test_slider.py +++ b/panel/tests/widgets/test_slider.py @@ -602,3 +602,116 @@ def test_editable_rangeslider_bounds( slider.value = val_update except Exception: assert fail_update + + +@pytest.mark.parametrize( + "editableslider,fixed_start,fixed_end", + [ + (EditableFloatSlider, 5, 10), + (EditableIntSlider, 5, 10), + ], +) +def test_editable_slider_fixed_novalue(editableslider, fixed_start, fixed_end): + slider = editableslider( + fixed_start=fixed_start, fixed_end=fixed_end, + ) + assert slider.value == fixed_start + + slider = editableslider(fixed_start=fixed_start) + assert slider.value == fixed_start + + slider = editableslider(fixed_end=fixed_end) + assert slider.value == fixed_end - 1 + + +def test_editable_rangeslider_fixed_novalue(): + fixed_start, fixed_end, step = 5, 10, 0.01 + slider = EditableRangeSlider( + fixed_start=fixed_start, fixed_end=fixed_end, + ) + assert slider.value == (fixed_start, fixed_end) + + slider = EditableRangeSlider(fixed_start=fixed_start) + assert slider.value == (fixed_start, fixed_start + 1) + + slider = EditableRangeSlider(fixed_start=fixed_start, step=step) + assert slider.value == (fixed_start, fixed_start + step) + + slider = EditableRangeSlider(fixed_end=fixed_end) + assert slider.value == (fixed_end - 1, fixed_end) + + slider = EditableRangeSlider(fixed_end=fixed_end, step=step) + assert slider.value == (fixed_end - step, fixed_end) + +@pytest.mark.parametrize( + "editableslider", + [EditableFloatSlider, EditableIntSlider, EditableRangeSlider], +) +def test_editable_fixed_nosoftbounds_fixed_start_end(editableslider): + start, end = 8, 9 + fixed_start, fixed_end = 5, 10 + + slider = editableslider( + fixed_start=fixed_start, fixed_end=fixed_end, + ) + assert slider.start == fixed_start + assert slider.end == fixed_end + + slider = editableslider( + fixed_start=fixed_start, fixed_end=fixed_end, + start=start, end=end, + ) + assert slider.start == start + assert slider.end == end + + +@pytest.mark.parametrize( + "editableslider", + [EditableFloatSlider, EditableIntSlider, EditableRangeSlider], +) +def test_editable_fixed_nosoftbounds_fixed_start(editableslider): + start, _ = 8, 9 + fixed_start, _ = 5, 10 + step = 2 + + slider = editableslider(fixed_start=fixed_start) + assert slider.start == fixed_start + assert slider.end == fixed_start + 1 + + slider = editableslider(fixed_start=fixed_start, step=step) + assert slider.start == fixed_start + assert slider.end == fixed_start + step + + slider = editableslider(fixed_start=fixed_start, start=start) + assert slider.start == start + assert slider.end == start + 1 + + slider = editableslider(fixed_start=fixed_start, start=start, step=step) + assert slider.start == start + assert slider.end == start + step + + + +@pytest.mark.parametrize( + "editableslider", + [EditableFloatSlider, EditableIntSlider, EditableRangeSlider], +) +def test_editable_fixed_nosoftbounds_fixed_end(editableslider): + _, end = 8, 9 + _, fixed_end = 5, 10 + step = 2 + slider = editableslider(fixed_end=fixed_end) + assert slider.start == fixed_end - 1 + assert slider.end == fixed_end + + slider = editableslider(fixed_end=fixed_end, step=step) + assert slider.start == fixed_end - step + assert slider.end == fixed_end + + slider = editableslider(fixed_end=fixed_end, end=end) + assert slider.start == end - 1 + assert slider.end == end + + slider = editableslider(fixed_end=fixed_end, end=end, step=step) + assert slider.start == end - step + assert slider.end == end diff --git a/panel/widgets/slider.py b/panel/widgets/slider.py index a624ee0fc5..76388017e2 100644 --- a/panel/widgets/slider.py +++ b/panel/widgets/slider.py @@ -787,6 +787,7 @@ class _EditableContinuousSlider(CompositeWidget): def __init__(self, **params): if not 'width' in params and not 'sizing_mode' in params: params['width'] = 300 + self._validate_init_bounds(params) super().__init__(**params) self._label = StaticText(margin=0, align='end') self._slider = self._slider_widget( @@ -816,6 +817,38 @@ def __init__(self, **params): self._update_value() self._update_bounds() + def _validate_init_bounds(self, params): + """ + This updates the default value, start and end + if outside the fixed_start and fixed_end + """ + start, end = None, None + if "start" not in params: + if "fixed_start" in params: + start = params["fixed_start"] + elif "end" in params: + start = params.get("end") - params.get("step", 1) + elif "fixed_end" in params: + start = params.get("fixed_end") - params.get("step", 1) + + if "end" not in params: + if "fixed_end" in params: + end = params["fixed_end"] + elif "start" in params: + end = params["start"] + params.get("step", 1) + elif "fixed_start" in params: + end = params["fixed_start"] + params.get("step", 1) + + if start is not None: + params["start"] = start + if end is not None: + params["end"] = end + + if "value" not in params and "start" in params: + params["value"] = params["start"] + if "value" not in params and "end" in params: + params["value"] = params["end"] + @param.depends('width', 'height', 'sizing_mode', watch=True) def _update_layout(self): self._value_edit.sizing_mode = self.sizing_mode @@ -977,6 +1010,7 @@ class EditableRangeSlider(CompositeWidget, _SliderBase): def __init__(self, **params): if not 'width' in params and not 'sizing_mode' in params: params['width'] = 300 + self._validate_init_bounds(params) super().__init__(**params) self._label = StaticText(margin=0, align='end') self._slider = RangeSlider(margin=(0, 0, 5, 0), show_value=False) @@ -1026,6 +1060,42 @@ def __init__(self, **params): self._update_value() self._update_bounds() + def _validate_init_bounds(self, params): + """ + This updates the default value, start and end + if outside the fixed_start and fixed_end + """ + start, end = None, None + if "start" not in params: + if "fixed_start" in params: + start = params["fixed_start"] + elif "end" in params: + start = params.get("end") - params.get("step", 1) + elif "fixed_end" in params: + start = params.get("fixed_end") - params.get("step", 1) + + if "end" not in params: + if "fixed_end" in params: + end = params["fixed_end"] + elif "start" in params: + end = params["start"] + params.get("step", 1) + elif "fixed_start" in params: + end = params["fixed_start"] + params.get("step", 1) + + if start is not None: + params["start"] = start + if end is not None: + params["end"] = end + + if "value" not in params and "start" in params: + start = params["start"] + end = params.get("end", start + params.get("step", 1)) + params["value"] = (start, end) + if "value" not in params and "end" in params: + end = params["end"] + start = params.get("start", end - params.get("step", 1)) + params["value"] = (start, end) + @param.depends('editable', watch=True) def _update_editable(self): self._start_edit.disabled = not self.editable[0]