From e2d879c8a3fa5efc84602214a9ce5eaa990b8049 Mon Sep 17 00:00:00 2001 From: k-dominik Date: Wed, 21 Aug 2024 11:58:44 +0200 Subject: [PATCH 1/3] Add more valueRangeWidget tests --- tests/valueRangeWidget_test.py | 55 +++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/tests/valueRangeWidget_test.py b/tests/valueRangeWidget_test.py index 5ca48100..466e09da 100644 --- a/tests/valueRangeWidget_test.py +++ b/tests/valueRangeWidget_test.py @@ -3,13 +3,17 @@ from volumina.widgets.valueRangeWidget import ValueRangeWidget -@pytest.mark.parametrize("dtype", [numpy.float32, numpy.float64, float]) -def test_floating_range(qtbot, dtype): - """repro of https://github.com/ilastik/ilastik/issues/2542""" +@pytest.fixture +def vrwidget(qtbot): vrwidget = ValueRangeWidget() qtbot.addWidget(vrwidget) vrwidget.show() + return vrwidget + +@pytest.mark.parametrize("dtype", [numpy.float32, numpy.float64, float]) +def test_floating_range(vrwidget, qtbot, dtype): + """repro of https://github.com/ilastik/ilastik/issues/2542""" with qtbot.waitExposed(vrwidget): vrwidget.setDType(dtype) @@ -19,14 +23,49 @@ def test_floating_range(qtbot, dtype): @pytest.mark.parametrize("dtype", [numpy.int8, numpy.uint8, numpy.int16, numpy.uint16, numpy.int32, numpy.uint32, int]) -def test_integer_range(qtbot, dtype): - vrwidget = ValueRangeWidget() - qtbot.addWidget(vrwidget) - vrwidget.show() - +def test_integer_range(vrwidget, qtbot, dtype): with qtbot.waitExposed(vrwidget): vrwidget.setDType(dtype) minmax = vrwidget.getValues() minmax_expected = numpy.iinfo(dtype).min, numpy.iinfo(dtype).max numpy.testing.assert_array_equal(minmax, minmax_expected) + + +def test_setBlank(vrwidget, qtbot): + with qtbot.waitExposed(vrwidget): + vrwidget.setBlank() + + assert vrwidget._blank == True + assert vrwidget.minBox.specialValueText() == "--" + assert vrwidget.maxBox.specialValueText() == "--" + + +def test_onChangedMinBox(vrwidget, qtbot): + """Test behavior of max box being incremented if user adds the same value into min""" + with qtbot.waitExposed(vrwidget): + vrwidget.setDType(int) + vrwidget.setLimits(0, 10) + vrwidget.maxBox.setValue(5) + vrwidget.minBox.setValue(5) + assert int(vrwidget.minBox.value()) == 5 + assert int(vrwidget.maxBox.value()) == 6 + + +def test_onChangedMaxBox(vrwidget, qtbot): + """Test behavior of min box being decremented if user adds the same value into max""" + with qtbot.waitExposed(vrwidget): + vrwidget.setDType(int) + vrwidget.setLimits(0, 10) + vrwidget.minBox.setValue(5) + vrwidget.maxBox.setValue(5) + assert int(vrwidget.maxBox.value()) == 5 + assert int(vrwidget.minBox.value()) == 4 + + +def test_setValues(vrwidget, qtbot): + with qtbot.waitExposed(vrwidget): + vrwidget.setDType(int) + vrwidget.setValues(2, 8) + assert int(vrwidget.minBox.value()) == 2 + assert int(vrwidget.maxBox.value()) == 8 From 42984bfa1f36c99c7adf8d311b11df39c84141a1 Mon Sep 17 00:00:00 2001 From: k-dominik Date: Wed, 21 Aug 2024 12:05:28 +0200 Subject: [PATCH 2/3] removed validation code in ValueRangeWidget, fixed display in dark mode the widgets themselves already enforce the `softlimits` via `onChangedMaxBox` and `onChangedMinBox`. Dtype limits are already enforced via `spinbox.setRange`. That code also removed a line which would set the background color explicitly - without it, it looks fine in both, light and dark mode. --- volumina/widgets/valueRangeWidget.py | 53 ++-------------------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/volumina/widgets/valueRangeWidget.py b/volumina/widgets/valueRangeWidget.py index ea2a1a85..2fc5b6b0 100644 --- a/volumina/widgets/valueRangeWidget.py +++ b/volumina/widgets/valueRangeWidget.py @@ -1,9 +1,7 @@ -from __future__ import print_function - ############################################################################### # volumina: volume slicing and editing library # -# Copyright (C) 2011-2014, the ilastik developers +# Copyright (C) 2011-2024, the ilastik developers # # # This program is free software; you can redistribute it and/or @@ -34,20 +32,18 @@ QSpacerItem, QSizePolicy, ) -from PyQt5.QtCore import QRegExp, Qt, QTimer, pyqtSignal +from PyQt5.QtCore import Qt, pyqtSignal from PyQt5 import uic import numpy class ValueRangeWidget(QWidget): - changedSignal = pyqtSignal() def __init__(self, parent=None, dtype=numpy.float32): super(ValueRangeWidget, self).__init__(parent) self._blank = False self._initUic() - self.allValid = True self.minBox.setButtonSymbols(QDoubleSpinBox.NoButtons) self.maxBox.setButtonSymbols(QDoubleSpinBox.NoButtons) self.minBox.setKeyboardTracking(False) @@ -76,8 +72,6 @@ def setDType(self, dtype): box.setSingleStep(1) box.setRange(dtypeInfo.min, dtypeInfo.max) - # box.setRange(typeLimits[0],typeLimits[1]) - self.setLimits(dtypeInfo.min, dtypeInfo.max) def setBlank(self): @@ -92,7 +86,6 @@ def onChangedMinBox(self, val): self.maxBox.setValue(val + self.maxBox.singleStep()) if val < self.softLimits[0]: self.minBox.setValue(self.softLimits[0]) - self.validateRange() self.changedSignal.emit() def onChangedMaxBox(self, val): @@ -100,49 +93,14 @@ def onChangedMaxBox(self, val): self.maxBox.setValue(self.softLimits[1]) if self.maxBox.value() <= self.minBox.value(): self.minBox.setValue(self.maxBox.value() - self.minBox.singleStep()) - self.validateRange() - # self.printLimits() self.changedSignal.emit() - def printLimits(self): - print(self.softLimits) - - def validateRange(self): - validCheck = [True, True] - if self.minBox.value() < self.softLimits[0]: - validCheck[0] = False - if self.maxBox.value() <= self.softLimits[0]: - validCheck[1] = False - if self.minBox.value() >= self.softLimits[1]: - validCheck[0] = False - if self.maxBox.value() > self.softLimits[1]: - validCheck[1] = False - # if not self.maxBox.value() > self.minBox.value(): - # validCheck[1] = False - - for i, box in enumerate(self.boxes): - if self._blank or validCheck[i]: - box.setStyleSheet("QDoubleSpinBox {background-color: white;}") - # self.setBackgroundColor("white", [i]) - # box.setButtonSymbols(QDoubleSpinBox.NoButtons) - else: - self.setBackgroundColor("red", [i]) - # box.setStyleSheet("QDoubleSpinBox {background-color: red;}") - # box.setButtonSymbols(QDoubleSpinBox.UpDownArrows) - - self.allValid = all(validCheck) - - def setBackgroundColor(self, color, boxnumber=[0, 1]): - for i in boxnumber: - self.boxes[i].setStyleSheet("QDoubleSpinBox {background-color: %s}" % color) - def setLimits(self, _min, _max): if _min + self.minBox.singleStep() > _max: raise RuntimeError("limits have to differ") self.softLimits = [_min, _max] if not self._blank: self.setValues(_min, _max) - self.validateRange() def setValues(self, val1, val2): self._blank = False @@ -163,10 +121,6 @@ def getValues(self): def getLimits(self): return self.softLimits - def makeValid(self): - if not self.maxBox.value() > self.minBox.value(): - self.maxBox.setValue(self.minBox.value() + self.maxBox.singleStep()) - def _initUic(self): p = os.path.split(__file__)[0] + "/" if p == "/": @@ -244,13 +198,12 @@ def focusInEvent(self, QFocusEvent): if __name__ == "__main__": from PyQt5.QtWidgets import QApplication - import vigra, numpy + import numpy app = QApplication(list()) d = ValueRangeWidget() d.setDType(numpy.uint8) - d.makeValid() d.setLimits(20, 40) d.show() app.exec_() From 2818aee0612ee3efe160aa39a82b7836dcc8634d Mon Sep 17 00:00:00 2001 From: k-dominik Date: Wed, 21 Aug 2024 12:10:05 +0200 Subject: [PATCH 3/3] Fix dispay of AxisOrderWidget in dark mode plus some black autoformatting for long lines --- volumina/widgets/dataExportOptionsDlg.py | 38 +++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/volumina/widgets/dataExportOptionsDlg.py b/volumina/widgets/dataExportOptionsDlg.py index 446594d5..2b172d68 100644 --- a/volumina/widgets/dataExportOptionsDlg.py +++ b/volumina/widgets/dataExportOptionsDlg.py @@ -231,12 +231,36 @@ def _handleConvertDtypeChecked(): self.convertDtypeCheckbox.toggled.connect(_handleConvertDtypeChecked) dtypes = [ - ("integer 8-bit", "uint8", "Stores data as integers. More bits per value increase precision but require more storage and processing time."), - ("integer 16-bit", "uint16", "Stores data as integers. More bits per value increase precision but require more storage and processing time."), - ("integer 32-bit", "uint32", "Stores data as integers. More bits per value increase precision but require more storage and processing time."), - ("integer 64-bit", "uint64", "Stores data as integers. More bits per value increase precision but require more storage and processing time."), - ("floating-point 32-bit", "float32", "Stores data as numbers with a decimal point. More bits per value increase precision but require more storage and processing time."), - ("floating-point 64-bit", "float64", "Stores data as numbers with a decimal point. More bits per value increase precision but require more storage and processing time."), + ( + "integer 8-bit", + "uint8", + "Stores data as integers. More bits per value increase precision but require more storage and processing time.", + ), + ( + "integer 16-bit", + "uint16", + "Stores data as integers. More bits per value increase precision but require more storage and processing time.", + ), + ( + "integer 32-bit", + "uint32", + "Stores data as integers. More bits per value increase precision but require more storage and processing time.", + ), + ( + "integer 64-bit", + "uint64", + "Stores data as integers. More bits per value increase precision but require more storage and processing time.", + ), + ( + "floating-point 32-bit", + "float32", + "Stores data as numbers with a decimal point. More bits per value increase precision but require more storage and processing time.", + ), + ( + "floating-point 64-bit", + "float64", + "Stores data as numbers with a decimal point. More bits per value increase precision but require more storage and processing time.", + ), ] for i, (name, dtype, tooltip) in enumerate(dtypes): @@ -394,7 +418,7 @@ def _updateAxisOrderColor(self, allow_intermediate): if invalidAxes: self.outputAxisOrderEdit.setStyleSheet("QLineEdit {background-color: red}") else: - self.outputAxisOrderEdit.setStyleSheet("QLineEdit {background-color: white}") + self.outputAxisOrderEdit.setStyleSheet("QLineEdit {background-color: palette(base)}") class _AxisOrderEventFilter(QObject): def __init__(self, parent):