From b17e8c141305a5ad05f199fda01ca66a446d07ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20M=C3=BCller?= Date: Thu, 12 Dec 2024 18:56:05 +0100 Subject: [PATCH] fix: filter range control not updating limits, displaying value 100 (close #183) --- CHANGELOG | 3 + shapeout2/gui/widgets/qrangeslider.py | 10 ++- shapeout2/gui/widgets/rangecontrol.py | 102 +++++++++++++++++--------- 3 files changed, 78 insertions(+), 37 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c20467b..c3200d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2.20.0 + - fix: filter range control not updating limits, displaying value "100" (#183) + - fix: filter range control not updating handles when resized 2.19.1 - fix: "buyukurganci-2022" was not actually the default viscosity model - ref: remove distutils dependency diff --git a/shapeout2/gui/widgets/qrangeslider.py b/shapeout2/gui/widgets/qrangeslider.py index c4a6c09..3af5153 100644 --- a/shapeout2/gui/widgets/qrangeslider.py +++ b/shapeout2/gui/widgets/qrangeslider.py @@ -168,6 +168,14 @@ def __init__(self, parent=None, *args, **kwargs): self.setEnd(self._INT_NUM) self.setDrawValues(False) + @QtCore.pyqtSlot(object) + def resizeEvent(self, event): + # The geometry changed and `self.width` is different now. Adjust + # the entire range slider to reflect the new values. + self.setStart(self.start()) + self.setEnd(self.end()) + super(QRangeSlider, self).resizeEvent(event) + def min(self): return getattr(self, '__min', None) @@ -221,7 +229,7 @@ def setDrawValues(self, draw): setattr(self, '__drawValues', draw) def getRange(self): - return (self.start(), self.end()) + return self.start(), self.end() def setRange(self, start, end): self.setStart(start) diff --git a/shapeout2/gui/widgets/rangecontrol.py b/shapeout2/gui/widgets/rangecontrol.py index 6f3afb3..d68e7bb 100644 --- a/shapeout2/gui/widgets/rangecontrol.py +++ b/shapeout2/gui/widgets/rangecontrol.py @@ -75,13 +75,7 @@ def __getstate__(self): def __setstate__(self, state): self.checkBox.setChecked(state["active"]) - self.doubleSpinBox_min.blockSignals(True) - self.doubleSpinBox_max.blockSignals(True) - self.doubleSpinBox_min.setValue(state["start"]) - self.doubleSpinBox_max.setValue(state["end"]) - self.doubleSpinBox_min.blockSignals(False) - self.doubleSpinBox_max.blockSignals(False) - self.map_spin_values_to_range_slider() + self.setSpinRange(state["start"], state["end"]) def check_boundary(self, old_value): """Make sure boundaries are properly set in the UI @@ -98,42 +92,47 @@ def check_boundary(self, old_value): return new_value @QtCore.pyqtSlot(float, float) - def map_spin_values_to_range_slider(self, vmin=None, vmax=None): + def map_spin_values_to_range_slider(self): + """Read values from spin controls and update the slider UI""" + # spin values + smin = self.doubleSpinBox_min.value() + smax = self.doubleSpinBox_max.value() # limits lmin = self.minimum lmax = self.maximum - # spin values - if vmin is None: - vmin = self.doubleSpinBox_min.value() - if vmax is None: - vmax = self.doubleSpinBox_max.value() - # range slider limits + assert lmin <= smin + assert lmax >= smax + # current range slider limits [a.u.] rmin = self.range_slider.min() rmax = self.range_slider.max() - # compute values - dr = rmax - rmin - dl = lmax - lmin - if dl * dr == 0: + # ranges for translating to handle widths + dr = rmax - rmin # handle range + dl = lmax - lmin # value range + # range slider handles (not the limits) + if dl == 0: hmin = hmax = 0 else: - hmin = rmin + (vmin - lmin) / dl * dr - hmax = rmax - (lmax - vmax) / dl * dr + hmin = rmin + (smin - lmin) * dr / dl + hmax = rmax - (lmax - smax) * dr / dl if hmin < rmin: hmin = 0 if hmax > rmax: hmax = self.range_slider._INT_NUM - self.range_slider.blockSignals(True) - self.range_slider.setRange(hmin, hmax) - self.range_slider.blockSignals(False) + # make range selection stick tight to edges if hmin < 10: hmin = 0 if hmin > self.range_slider._INT_NUM - 10: hmax = self.range_slider._INT_NUM + + self.range_slider.update() + self.range_slider.blockSignals(True) + self.range_slider.setRange(hmin, hmax) + self.range_slider.blockSignals(False) return hmin, hmax @QtCore.pyqtSlot(int, int) - def map_range_slider_to_spin_values(self, hmin=None, hmax=None): + def map_range_slider_to_spin_values(self): """Return the respective value of the current range Range limits are defined by @@ -147,25 +146,18 @@ def map_range_slider_to_spin_values(self, hmin=None, hmax=None): rmin = self.range_slider.min() rmax = self.range_slider.max() # range slider handles - if hmin is None: - hmin = self.range_slider.start() - if hmax is None: - hmax = self.range_slider.end() + hmin = self.range_slider.start() + hmax = self.range_slider.end() # compute values dr = rmax - rmin dl = lmax - lmin - vmin = lmin + (hmin - rmin) / dr * dl - vmax = lmax - (rmax - hmax) / dr * dl + vmin = lmin + (hmin - rmin) * dl / dr + vmax = lmax - (rmax - hmax) * dl / dr vmin = self.check_boundary(vmin) vmax = self.check_boundary(vmax) - self.doubleSpinBox_min.blockSignals(True) - self.doubleSpinBox_max.blockSignals(True) - self.doubleSpinBox_min.setValue(vmin) - self.doubleSpinBox_max.setValue(vmax) - self.doubleSpinBox_min.blockSignals(False) - self.doubleSpinBox_max.blockSignals(False) + self.setSpinRange(vmin, vmax) return vmin, vmax def is_active(self): @@ -221,6 +213,9 @@ def setLimits(self, vmin, vmax, hard_limit=False): limit of the spin controls is larger, giving the user a broader range. """ + if vmin == vmax: + return + self.minimum = vmin self.maximum = vmax @@ -277,3 +272,38 @@ def setSpinLimits(self, vmin, vmax): self.doubleSpinBox_max.setDecimals(dec) self.doubleSpinBox_min.setSingleStep(10**-dec) self.doubleSpinBox_max.setSingleStep(10**-dec) + + def setSpinRange(self, vmin, vmax): + """Set values of left and right spin controls (not the limits) + + Extends the range if necessary + """ + limits_changed = False + + if vmin < self.minimum: + limit_min = np.floor(vmin) + limits_changed = True + else: + limit_min = self.minimum + + if vmax > self.maximum: + limit_max = np.ceil(vmax) + limits_changed = True + else: + limit_max = self.maximum + + if limits_changed: + self.setLimits(limit_min, limit_max) + + self.doubleSpinBox_min.blockSignals(True) + self.doubleSpinBox_max.blockSignals(True) + self.doubleSpinBox_min.setValue(vmin) + self.doubleSpinBox_max.setValue(vmax) + self.doubleSpinBox_min.blockSignals(False) + self.doubleSpinBox_max.blockSignals(False) + + self.range_slider.blockSignals(True) + self.map_spin_values_to_range_slider() + self.range_slider.blockSignals(False) + + self.range_changed.emit(vmin, vmax)