1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
import numpy as np
from ...Qt import QtCore, QtWidgets
from ..Parameter import Parameter
from .basetypes import Emitter, WidgetParameterItem
class SliderParameterItem(WidgetParameterItem):
slider: QtWidgets.QSlider
span: np.ndarray
charSpan: np.ndarray
def __init__(self, param, depth):
# Bind emitter to self to avoid garbage collection
self.emitter = Emitter()
self.sigChanging = self.emitter.sigChanging
self._suffix = None
super().__init__(param, depth)
def updateDisplayLabel(self, value=None):
if value is None:
value = self.param.value()
self.sliderLabel.setText(self.prettyTextValue(self.slider.value()))
value = str(value)
if self._suffix is None:
suffixTxt = ''
else:
suffixTxt = f' {self._suffix}'
self.displayLabel.setText(value + suffixTxt)
def setSuffix(self, suffix):
self._suffix = suffix
# This may be called during widget construction in which case there is no
# displayLabel yet
if hasattr(self, 'displayLabel'):
self.updateDisplayLabel(self.slider.value())
def makeWidget(self):
param = self.param
opts = param.opts
opts.setdefault('limits', [0, 0])
self._suffix = opts.get('suffix')
self.slider = QtWidgets.QSlider()
self.slider.setOrientation(QtCore.Qt.Orientation.Horizontal)
lbl = self.sliderLabel = QtWidgets.QLabel()
lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft)
w = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout()
w.setLayout(layout)
layout.addWidget(lbl)
layout.addWidget(self.slider)
def setValue(v):
self.slider.setValue(self.spanToSliderValue(v))
def getValue():
return self.span[self.slider.value()].item()
self.slider.valueChanged.connect(self.updateDisplayLabel)
def onMove(pos):
self.sigChanging.emit(self, self.span[pos].item())
self.slider.sliderMoved.connect(onMove)
w.setValue = setValue
w.value = getValue
w.sigChanged = self.slider.valueChanged
w.sigChanging = self.sigChanging
self.optsChanged(param, opts)
return w
def spanToSliderValue(self, v):
return int(np.argmin(np.abs(self.span - v)))
def prettyTextValue(self, v):
if self._suffix is None:
suffixTxt = ''
else:
suffixTxt = f' {self._suffix}'
format_ = self.param.opts.get('format', None)
cspan = self.charSpan
if format_ is None:
format_ = f'{{0:>{cspan.dtype.itemsize}}}{suffixTxt}'
return format_.format(cspan[v].decode())
def optsChanged(self, param, opts):
try:
super().optsChanged(param, opts)
except AttributeError:
# This may trigger while building the parameter before the widget is fully constructed.
# This is fine, since errors are from the parent scope which will stabilize after the widget is
# constructed anyway
pass
span = opts.get('span', None)
if span is None:
step = opts.get('step', 1)
start, stop = opts.get('limits', param.opts['limits'])
# Add a bit to 'stop' since python slicing excludes the last value
span = np.arange(start, stop + step, step)
precision = opts.get('precision', 2)
if precision is not None:
span = span.round(precision)
self.span = span
self.charSpan = np.char.array(span)
w = self.slider
w.setMinimum(0)
w.setMaximum(len(span) - 1)
if 'suffix' in opts:
self.setSuffix(opts['suffix'])
def limitsChanged(self, param, limits):
self.optsChanged(param, dict(limits=limits))
class SliderParameter(Parameter):
"""
============== ========================================================
**Options**
limits [start, stop] numbers
step: Defaults to 1, the spacing between each slider tick
span: Instead of limits + step, span can be set to specify
the range of slider options (e.g. np.linspace(-pi, pi, 100))
format: Format string to determine number of decimals to show, etc.
Defaults to display based on span dtype
precision: int number of decimals to keep for float tick spaces
============== ========================================================
"""
itemClass = SliderParameterItem
|