From 16787dbae78cc8216709483c2b33bb6f3de2f65c Mon Sep 17 00:00:00 2001 From: alisterburt Date: Wed, 21 Jun 2023 11:04:34 +0100 Subject: [PATCH 1/4] proof of concept --- src/superqt/sliders/_labeled.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/superqt/sliders/_labeled.py b/src/superqt/sliders/_labeled.py index a2d45f07..f7a10e7a 100644 --- a/src/superqt/sliders/_labeled.py +++ b/src/superqt/sliders/_labeled.py @@ -150,6 +150,9 @@ def __init__(self, *args, **kwargs) -> None: def _setValue(self, value: float): """Convert the value from float to int before setting the slider value.""" + value = int(value) + if self._slider.maximum() < value: + self._slider.setMaximum(value) self._slider.setValue(int(value)) def _rename_signals(self): From 8f83091fb94154aa6c7dd579ab4a902b2d74659c Mon Sep 17 00:00:00 2001 From: alisterburt Date: Wed, 21 Jun 2023 11:06:42 +0100 Subject: [PATCH 2/4] add minimum support --- src/superqt/sliders/_labeled.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/superqt/sliders/_labeled.py b/src/superqt/sliders/_labeled.py index f7a10e7a..b1aa656b 100644 --- a/src/superqt/sliders/_labeled.py +++ b/src/superqt/sliders/_labeled.py @@ -153,6 +153,8 @@ def _setValue(self, value: float): value = int(value) if self._slider.maximum() < value: self._slider.setMaximum(value) + elif self._slider.minimum() > value: + self._slider.setMinimum(value) self._slider.setValue(int(value)) def _rename_signals(self): From 0599a915759b7988b08e163cf960b2c285218c19 Mon Sep 17 00:00:00 2001 From: alisterburt Date: Wed, 21 Jun 2023 16:34:35 +0100 Subject: [PATCH 3/4] broken, but not sure why yet --- src/superqt/sliders/_labeled.py | 26 +++++++++++---- tests/test_sliders/test_labeled_slider.py | 40 +++++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/superqt/sliders/_labeled.py b/src/superqt/sliders/_labeled.py index b1aa656b..b995569a 100644 --- a/src/superqt/sliders/_labeled.py +++ b/src/superqt/sliders/_labeled.py @@ -155,7 +155,7 @@ def _setValue(self, value: float): self._slider.setMaximum(value) elif self._slider.minimum() > value: self._slider.setMinimum(value) - self._slider.setValue(int(value)) + self._slider.setValue(value) def _rename_signals(self): # for subclasses @@ -214,6 +214,10 @@ def setEdgeLabelMode(self, opt: EdgeLabelMode) -> None: QApplication.processEvents() + def setLabelSpinBoxRange(self, min: int, max: int): + """Change valid label values independently of slider range.""" + self._label.setRange(int(min), int(max)) + class QLabeledDoubleSlider(QLabeledSlider): _slider_class = QDoubleSlider @@ -227,9 +231,17 @@ def __init__(self, *args, **kwargs) -> None: self.setDecimals(2) def _setValue(self, value: float): - """Convert the value from float to int before setting the slider value.""" + """Override method in the subclass which converts float to int.""" + if self._slider.maximum() < value: + self._slider.setMaximum(value) + elif self._slider.minimum() > value: + self._slider.setMinimum(value) self._slider.setValue(value) + def setLabelSpinBoxRange(self, min: float, max: float): + """Change valid label values independently of slider range.""" + self._label.setRange(min, max) + def _rename_signals(self): self.valueChanged = self._fvalueChanged self.sliderMoved = self._fsliderMoved @@ -420,9 +432,9 @@ def _on_range_changed(self, min, max): self._max_label.setValue(max) self._reposition_labels() - # def setValue(self, value) -> None: - # super().setValue(value) - # self.sliderChange(QSlider.SliderValueChange) + def setValue(self, value) -> None: + super().setValue(value) + self.sliderChange(QSlider.SliderValueChange) def setRange(self, min, max) -> None: self._on_range_changed(min, max) @@ -579,8 +591,8 @@ def setMode(self, opt: EdgeLabelMode): with contextlib.suppress(Exception): self._slider.rangeChanged.disconnect(self.setRange) else: - self.setMinimum(self._slider.minimum()) - self.setMaximum(self._slider.maximum()) + self.setMinimum(min(self._slider.minimum(), self.minimum())) + self.setMaximum(max(self._slider.maximum(), self.maximum())) self._slider.rangeChanged.connect(self.setRange) self._update_size() diff --git a/tests/test_sliders/test_labeled_slider.py b/tests/test_sliders/test_labeled_slider.py index 25525e06..5367b34d 100644 --- a/tests/test_sliders/test_labeled_slider.py +++ b/tests/test_sliders/test_labeled_slider.py @@ -85,3 +85,43 @@ def test_editing_float(qtbot): slider._label.setValue(0.5) slider._label.editingFinished.emit() assert slider.value() == 0.5 + + +@pytest.mark.parametrize("cls", [QLabeledSlider, QLabeledDoubleSlider]) +def test_extended_label_spinbox_range(cls, qtbot): + slider = cls() + mock = Mock() + qtbot.addWidget(slider) + slider.setRange(0, 10) + slider.rangeChanged.connect(mock) + assert slider._label.minimum() == 0 + assert slider._label.maximum() == 10 + assert slider.minimum() == 0 + assert slider.maximum() == 10 + + # changing slider value without changing spinbox range should return a clipped value + # slider._label.setValue(20) + # slider._label.editingFinished.emit() # simulate editing the label manually + # qtbot.wait(20) + # assert slider.value() == 10 + # assert slider.maximum() == 10 + + # after changing label range, setting the label to a value outside the range should + # update the slider min/max as appropriate + slider.setLabelSpinBoxRange(-10, 20) + + with qtbot.waitSignal(slider.rangeChanged): + slider._label.setValue(15) + assert slider._label.minimum() == -10 + slider._label.editingFinished.emit() # simulate editing the label manually + assert slider._label.minimum() == -10 + assert slider.value() == 15 + assert slider.minimum() == 0 # unchanged + assert slider.maximum() == 15 # changed + + with qtbot.waitSignal(slider.rangeChanged): + slider._label.setValue(-5) + slider._label.editingFinished.emit() # simulate editing the label manually + assert slider.value() == -5 + assert slider.minimum() == -5 # changed + assert slider.maximum() == 15 # unchanged From 52d63ed68f6fcaaf0b4faab0254c41171b9b311c Mon Sep 17 00:00:00 2001 From: alisterburt Date: Wed, 21 Jun 2023 16:35:48 +0100 Subject: [PATCH 4/4] reverse accidental change --- src/superqt/sliders/_labeled.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/superqt/sliders/_labeled.py b/src/superqt/sliders/_labeled.py index b995569a..13275542 100644 --- a/src/superqt/sliders/_labeled.py +++ b/src/superqt/sliders/_labeled.py @@ -432,9 +432,9 @@ def _on_range_changed(self, min, max): self._max_label.setValue(max) self._reposition_labels() - def setValue(self, value) -> None: - super().setValue(value) - self.sliderChange(QSlider.SliderValueChange) + # def setValue(self, value) -> None: + # super().setValue(value) + # self.sliderChange(QSlider.SliderValueChange) def setRange(self, min, max) -> None: self._on_range_changed(min, max)