Skip to content

Commit

Permalink
Merge pull request #5647 from ales-erjavec/color-gradient-selection-c…
Browse files Browse the repository at this point in the history
…enter-spin

[FIX] HeatMap: Color gradient center value edit
  • Loading branch information
markotoplak authored Nov 5, 2021
2 parents 67c247f + adc9fbb commit 3634e37
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 28 deletions.
48 changes: 28 additions & 20 deletions Orange/widgets/utils/colorgradientselection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

from AnyQt.QtCore import Qt, QSize, QAbstractItemModel, Property
from AnyQt.QtWidgets import (
QWidget, QSlider, QFormLayout, QComboBox, QStyle,
QHBoxLayout, QLineEdit, QLabel)
QWidget, QSlider, QFormLayout, QComboBox, QStyle, QHBoxLayout, QLabel,
QSizePolicy
)
from AnyQt.QtCore import Signal
from AnyQt.QtGui import QFontMetrics, QDoubleValidator

from orangewidget.gui import Slider

from Orange.widgets.utils import itemmodels, colorpalettes
from Orange.widgets.utils.spinbox import DoubleSpinBox, DBL_MIN, DBL_MAX


class ColorGradientSelection(QWidget):
Expand Down Expand Up @@ -49,19 +50,23 @@ def __init__(self, *args, thresholds=(0.0, 1.0), center=None, **kwargs):
self.gradient_cb.currentIndexChanged.connect(self.currentIndexChanged)

if center is not None:
def __on_center_changed():
self.__center = float(self.center_edit.text() or "0")
self.centerChanged.emit(self.__center)
def on_center_spin_value_changed(value):
if self.__center != value:
self.__center = value
self.centerChanged.emit(self.__center)

self.center_box = QWidget()
center_layout = QHBoxLayout()
self.center_box.setLayout(center_layout)
width = QFontMetrics(self.font()).boundingRect("9999999").width()
self.center_edit = QLineEdit(
text=f"{self.__center}",
maximumWidth=width, placeholderText="0", alignment=Qt.AlignRight)
self.center_edit.setValidator(QDoubleValidator())
self.center_edit.editingFinished.connect(__on_center_changed)
self.center_edit = DoubleSpinBox(
value=self.__center,
minimum=DBL_MIN, maximum=DBL_MAX, minimumStep=0.01,
minimumContentsLenght=8,
stepType=DoubleSpinBox.AdaptiveDecimalStepType,
keyboardTracking=False,
sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
)
self.center_edit.valueChanged.connect(on_center_spin_value_changed)
center_layout.setContentsMargins(0, 0, 0, 0)
center_layout.addStretch(1)
center_layout.addWidget(QLabel("Centered at"))
Expand Down Expand Up @@ -140,14 +145,6 @@ def thresholdHigh(self) -> float:
def setThresholdHigh(self, high: float) -> None:
self.setThresholds(min(self.__threshold_low, high), high)

def center(self) -> float:
return self.__center

def setCenter(self, center: float) -> None:
self.__center = center
self.center_edit.setText(f"{center}")
self.centerChanged.emit(center)

thresholdHigh_ = Property(
float, thresholdLow, setThresholdLow, notify=thresholdsChanged)

Expand Down Expand Up @@ -194,6 +191,17 @@ def __update_center_visibility(self):
isinstance(palette, colorpalettes.Palette)
and palette.flags & palette.Flags.Diverging != 0)

def center(self) -> float:
return self.__center

def setCenter(self, center: float) -> None:
if self.__center != center:
self.__center = center
self.center_edit.setValue(center)
self.centerChanged.emit(center)

center_ = Property(float, center, setCenter, notify=centerChanged)


def clip(a, amin, amax):
return min(max(a, amin), amax)
47 changes: 44 additions & 3 deletions Orange/widgets/utils/spinbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import numpy as np

from AnyQt.QtCore import QLocale
from AnyQt.QtWidgets import QDoubleSpinBox
from AnyQt.QtCore import QLocale, QSize
from AnyQt.QtWidgets import QDoubleSpinBox, QStyle, QStyleOptionSpinBox

DBL_MIN = float(np.finfo(float).min)
DBL_MAX = float(np.finfo(float).max)
Expand All @@ -16,9 +16,11 @@ class DoubleSpinBox(QDoubleSpinBox):
"""
A QDoubleSpinSubclass with non-fixed decimal precision/rounding.
"""
def __init__(self, parent=None, decimals=-1, minimumStep=1e-5, **kwargs):
def __init__(self, parent=None, decimals=-1, minimumStep=1e-5,
minimumContentsLenght=-1, **kwargs):
self.__decimals = decimals
self.__minimumStep = minimumStep
self.__minimumContentsLength = minimumContentsLenght
stepType = kwargs.pop("stepType", DoubleSpinBox.DefaultStepType)
super().__init__(parent, **kwargs)
if decimals < 0:
Expand Down Expand Up @@ -107,3 +109,42 @@ def setStepType(self, stepType):

def stepType(self):
return self.__stepType

def setMinimumContentsLength(self, characters: int):
self.__minimumContentsLength = characters
self.updateGeometry()

def minimumContentsLength(self):
return self.__minimumContentsLength

def sizeHint(self) -> QSize:
if self.minimumContentsLength() < 0:
return super().sizeHint()
self.ensurePolished()
fm = self.fontMetrics()
template = "X" * self.minimumContentsLength()
template += "."
if self.prefix():
template = self.prefix() + " " + template
if self.suffix():
template = template + self.suffix()
if self.minimum() < 0.0:
template = "-" + template
if self.specialValueText():
templates = [template, self.specialValueText()]
else:
templates = [template]
height = self.lineEdit().sizeHint().height()
width = max(map(fm.horizontalAdvance, templates))
width += 2 # cursor blinking space
hint = QSize(width, height)
opt = QStyleOptionSpinBox()
self.initStyleOption(opt)
sh = self.style().sizeFromContents(QStyle.CT_SpinBox, opt, hint, self)
return sh

def minimumSizeHint(self) -> QSize:
if self.minimumContentsLength() < 0:
return super().minimumSizeHint()
else:
return self.sizeHint()
12 changes: 7 additions & 5 deletions Orange/widgets/utils/tests/test_colorgradientselection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import numpy as np

from AnyQt.QtTest import QSignalSpy
from AnyQt.QtTest import QSignalSpy, QTest
from AnyQt.QtCore import Qt, QStringListModel, QModelIndex

from Orange.widgets.utils import itemmodels
Expand Down Expand Up @@ -105,7 +105,9 @@ def test_center_visibility(self):
def test_center_changed(self):
w = ColorGradientSelection(center=42)
changed = QSignalSpy(w.centerChanged)
w.center_edit.setText("41")
w.center_edit.editingFinished.emit()
self.assertEqual(w.center(), 41)
self.assertEqual(list(changed), [[41]])
ledit = w.center_edit.lineEdit()
ledit.selectAll()
QTest.keyClicks(ledit, "41")
QTest.keyClick(ledit, Qt.Key_Return)
self.assertEqual(w.center(), 41.0)
self.assertEqual(list(changed), [[41.0]])

0 comments on commit 3634e37

Please sign in to comment.