Vuo  2.4.0
VuoInputEditorRange.cc
Go to the documentation of this file.
1
11
16{
17 return new VuoInputEditorRange();
18}
19
23QLabel* makeLabel(const char* text)
24{
25 QLabel* label = new QLabel(text);
26 label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
27 return label;
28}
29
33VuoDoubleSpinBox* VuoInputEditorRange::initSpinBox(QDialog& dialog, double initialValue, double min, double max, double step)
34{
35 VuoDoubleSpinBox* spin = new VuoDoubleSpinBox(&dialog, 11);
36 const int decimalPrecision = DBL_MAX_10_EXP + DBL_DIG;
37 spin->setDecimals(decimalPrecision);
38 spin->setButtonMinimum(min);
39 spin->setButtonMaximum(max);
40 spin->setSingleStep(step);
41 spin->setValue(initialValue);
42 spin->setFixedWidth(100);
43 return spin;
44}
45
49QSlider* VuoInputEditorRange::initSlider(QSlider* slider, double initialValue, double min, double max, double step)
50{
51 double range = max - min;
52 slider->setOrientation(Qt::Horizontal);
53 slider->setFocusPolicy(Qt::NoFocus);
54 slider->setMinimum(0);
55 slider->setMaximum(slider->width());
56 slider->setSingleStep( fmax(1, step * (slider->maximum() - slider->minimum()) / range ) );
57 slider->setValue( VuoDoubleSpinBox::doubleToSlider(slider->minimum(), slider->maximum(), min, max, initialValue) );
58 return slider;
59}
60
65void VuoInputEditorRange::setUpDialog(QDialog &dialog, json_object *originalValue, json_object *details)
66{
67 current = VuoRange_makeFromJson(originalValue);
68 lastValue = current;
69
70 const double max_dbl = std::numeric_limits<double>::max();
71
72 suggestedMin = VuoRange_make(-max_dbl, -max_dbl);
73 suggestedMax = VuoRange_make(max_dbl, max_dbl);
74 suggestedStep = VuoRange_make(0.1, 0.1);
75
76 bool hasMinMax = true;
77
78 requireMin = false;
79 requireMax = false;
80
81 // Parse supported port annotations from the port's "details" JSON object:
82 if (details)
83 {
84 // "suggestedMin"
85 json_object *suggestedMinValue = NULL;
86 if (json_object_object_get_ex(details, "suggestedMin", &suggestedMinValue))
87 suggestedMin = VuoRange_makeFromJson(suggestedMinValue);
88 else
89 hasMinMax = false;
90
91 // "suggestedMax"
92 json_object *suggestedMaxValue = NULL;
93 if (json_object_object_get_ex(details, "suggestedMax", &suggestedMaxValue))
94 suggestedMax = VuoRange_makeFromJson(suggestedMaxValue);
95 else
96 hasMinMax = false;
97
98 // "suggestedStep"
99 json_object *suggestedStepValue = NULL;
100 if (json_object_object_get_ex(details, "suggestedStep", &suggestedStepValue))
101 suggestedStep = VuoRange_makeFromJson(suggestedStepValue);
102
103 // requireMin
104 json_object *requireMinValue = NULL;
105 if (json_object_object_get_ex(details, "requireMin", &requireMinValue))
106 requireMin = VuoBoolean_makeFromJson(requireMinValue);
107
108 // requireMax
109 json_object *requireMaxValue = NULL;
110 if (json_object_object_get_ex(details, "requireMax", &requireMaxValue))
111 requireMax = VuoBoolean_makeFromJson(requireMaxValue);
112 }
113
114 spinbox_min = initSpinBox(dialog, current.minimum, suggestedMin.minimum, suggestedMax.minimum, suggestedStep.minimum);
115 {
116 spinbox_min->setMinimum(VuoRange_NoMinimum);
117// spinbox_min->setMaximum(current.maximum);
118 spinbox_min->setMaximum(VuoRange_NoMaximum);
119 spinbox_min->setSpecialValueText("-∞");
120 connect(spinbox_min, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorRange::onSpinboxUpdate);
121 }
122
123 spinbox_max = initSpinBox(dialog, current.maximum, suggestedMin.maximum, suggestedMax.maximum, suggestedStep.maximum);
124 {
125 // QDoubleSpinbox only can show the special string value if value == minimum
126 // So if the max value is VuoRange_NoMaximum temporarily make the min/max both
127 // VuoRange_NoMaximum (DBL_MAX)
128// if(current.maximum == VuoRange_NoMaximum)
129// {
130// spinbox_max->setMinimum(VuoRange_NoMaximum);
131// spinbox_max->setMaximum(VuoRange_NoMaximum);
132// }
133// else
134// {
135// spinbox_max->setMinimum(current.minimum);
136// spinbox_max->setMaximum(VuoRange_NoMaximum);
137// }
138
139 connect(spinbox_max, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorRange::onSpinboxUpdate);
140 }
141
142 if(hasMinMax)
143 {
144 slider_min = new QSlider(&dialog);
145 slider_max = new QSlider(&dialog);
146
147 slider_min = initSlider(slider_min, current.minimum, suggestedMin.minimum, suggestedMax.minimum, suggestedStep.minimum);
148 slider_max = initSlider(slider_max, current.maximum, suggestedMin.maximum, suggestedMax.maximum, suggestedStep.maximum);
149
150 connect(slider_min, &QSlider::valueChanged, this, &VuoInputEditorRange::onSliderUpdate);
151 connect(slider_max, &QSlider::valueChanged, this, &VuoInputEditorRange::onSliderUpdate);
152 }
153
154 // layout dialog
155 QGridLayout* layout = new QGridLayout;
156 dialog.setLayout(layout);
157
158 // left, top, right, bottom
159 // when showing sliders, add a little extra margin on the bottom since QSlider takes up the
160 // entire vertical spacing
161 layout->setContentsMargins(4, 4, 12, 4);
162 layout->setSpacing(4);
163 layout->setHorizontalSpacing(8);
164
165 int row = 0;
166
169 if(!requireMin)
170 {
171 toggle_hasMin = new QCheckBox("Minimum");
172 toggle_hasMin->setChecked( !VuoReal_areEqual(current.minimum, VuoRange_NoMinimum) );
173 toggle_hasMin->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
174 connect(toggle_hasMin, &QCheckBox::stateChanged, this, &VuoInputEditorRange::setHasMinBound);
175 layout->addWidget(toggle_hasMin, row, 0);
176 setHasMinBound(toggle_hasMin->isChecked() ? Qt::Checked : Qt::Unchecked);
177 }
178 else
179 {
180 layout->addWidget(makeLabel("Minimum"), row, 0);
181 }
182
183 spinbox_min->setEnabled(toggle_hasMin == NULL || toggle_hasMin->isChecked());
184 layout->addWidget(spinbox_min, row++, 1);
185
186 if(hasMinMax)
187 {
188 slider_min->setEnabled(toggle_hasMin == NULL || toggle_hasMin->isChecked());
189 layout->addWidget(slider_min, row++, 1);
190 }
192
195 if(!requireMax)
196 {
197 toggle_hasMax = new QCheckBox("Maximum");
198 toggle_hasMax->setChecked( !VuoReal_areEqual(current.maximum, VuoRange_NoMaximum) );
199 toggle_hasMax->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
200 connect(toggle_hasMax, &QCheckBox::stateChanged, this, &VuoInputEditorRange::setHasMaxBound);
201 layout->addWidget(toggle_hasMax, row, 0);
202 setHasMaxBound(toggle_hasMax->isChecked() ? Qt::Checked : Qt::Unchecked);
203 }
204 else
205 {
206 layout->addWidget(makeLabel("Maximum"), row, 0);
207 }
208
209 spinbox_max->setEnabled(toggle_hasMax == NULL || toggle_hasMax->isChecked());
210 layout->addWidget(spinbox_max, row++, 1);
211
212 if(hasMinMax)
213 {
214 slider_max->setEnabled(toggle_hasMax == NULL || toggle_hasMax->isChecked());
215 layout->addWidget(slider_max, row, 1);
216 }
218
219 dialog.setMaximumWidth(1);
220 dialog.setMaximumHeight(1);
221 dialog.adjustSize();
222
223 setFirstWidgetInTabOrder(spinbox_min);
224 setLastWidgetInTabOrder(spinbox_max);
225
226 spinbox_min->setFocus();
227 spinbox_min->selectAll();
228}
229
230void VuoInputEditorRange::setHasMinBound(int state)
231{
232 if(state == Qt::Unchecked)
233 {
234 // had min bound, now we don't
235 lastValue.minimum = current.minimum;
236 current.minimum = VuoRange_NoMinimum;
237 }
238 else
239 {
240 // was unbound, now has bound
241 if( VuoReal_areEqual(VuoRange_NoMinimum, lastValue.minimum) )
242 current.minimum = fmin(fmax(suggestedMin.minimum, 0.), current.maximum);
243 else
244 current.minimum = lastValue.minimum;
245 }
246
247 spinbox_min->setValue(current.minimum);
248
249 spinbox_min->setEnabled(state != Qt::Unchecked);
250 if(slider_min) slider_min->setEnabled(state != Qt::Unchecked);
251}
252
253void VuoInputEditorRange::setHasMaxBound(int state)
254{
255 if(state == Qt::Unchecked)
256 {
257 lastValue.maximum = current.maximum;
258 current.maximum = VuoRange_NoMaximum;
259 spinbox_max->setSpecialValueText("∞");
260 spinbox_max->setMinimum(VuoRange_NoMaximum);
261 spinbox_max->setValue(current.maximum);
262 spinbox_max->setEnabled(false);
263 if(slider_max) slider_max->setEnabled(false);
264 }
265 else
266 {
267 if(lastValue.maximum == VuoRange_NoMaximum)
268 current.maximum = fmax(fmin(suggestedMax.maximum, 1), current.minimum);
269 else
270 current.maximum = lastValue.maximum;
271
272 spinbox_max->setSpecialValueText("");
273 spinbox_max->setMinimum(current.minimum);
274 spinbox_max->setValue(current.maximum);
275 spinbox_max->setEnabled(true);
276 if(slider_max) slider_max->setEnabled(true);
277 }
278}
279
280void VuoInputEditorRange::setMinimumValue(double value)
281{
282 current.minimum = value;
283// spinbox_max->setMinimum(current.minimum);
284}
285
286void VuoInputEditorRange::setMaximumValue(double value)
287{
288 current.maximum = value;
289// spinbox_min->setMaximum(current.maximum);
290}
291
295void VuoInputEditorRange::onSliderUpdate(int sliderValue)
296{
297 if(QObject::sender() == NULL)
298 return;
299
300 bool isMin = (QObject::sender() == spinbox_min || QObject::sender() == slider_min);
301
302 QSlider* slider = isMin ? slider_min : slider_max;
303
304 double val = VuoDoubleSpinBox::sliderToDouble( slider->minimum(),
305 slider->maximum(),
306 isMin ? suggestedMin.minimum : suggestedMin.maximum,
307 isMin ? suggestedMax.minimum : suggestedMax.maximum,
308 sliderValue);
309 if(isMin)
310 setMinimumValue(val);
311 else
312 setMaximumValue(val);
313
314 VuoDoubleSpinBox* spinbox = isMin ? spinbox_min : spinbox_max;
315
316 // disconnect before setting spinbox value otherwise onSpinboxUpdate is called and the whole thing just cycles
317 disconnect(spinbox, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorRange::onSpinboxUpdate);
318 spinbox->setValue( isMin ? current.minimum : current.maximum );
319 connect(spinbox, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorRange::onSpinboxUpdate);
320
321 spinbox->setFocus();
322 spinbox->selectAll();
323
325}
326
330void VuoInputEditorRange::onSpinboxUpdate(double value)
331{
332 if(QObject::sender() == NULL)
333 return;
334
335 bool isMin = (QObject::sender() == spinbox_min || QObject::sender() == slider_min);
336
337 if(isMin)
338 setMinimumValue(value);
339 else
340 setMaximumValue(value);
341
342 QSlider* slider = isMin ? slider_min : slider_max;
343
344 if(slider != NULL)
345 {
346 int sliderValue = VuoDoubleSpinBox::doubleToSlider(
347 slider->minimum(),
348 slider->maximum(),
349 isMin ? suggestedMin.minimum : suggestedMin.maximum,
350 isMin ? suggestedMax.minimum : suggestedMax.maximum,
351 value);
352
353 disconnect(slider, &QSlider::valueChanged, this, &VuoInputEditorRange::onSliderUpdate);
354 slider->setValue( sliderValue );
355 connect(slider, &QSlider::valueChanged, this, &VuoInputEditorRange::onSliderUpdate);
356 }
357
359}
360
365{
366 return VuoRange_getJson(current);
367}