Vuo  2.1.2
VuoInputEditorPoint4d.cc
Go to the documentation of this file.
1 
10 #include "VuoInputEditorPoint4d.hh"
11 
16 {
17  return new VuoInputEditorPoint4d();
18 }
19 
23 QLabel* makeLabel(const char* text)
24 {
25  QLabel* label = new QLabel(text);
26  label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
27  return label;
28 }
29 
33 VuoDoubleSpinBox* VuoInputEditorPoint4d::initSpinBox(coord whichCoord, QDialog& dialog, double initialValue)
34 {
35  VuoDoubleSpinBox* spin = new VuoDoubleSpinBox(&dialog, 7);
36  const int decimalPrecision = DBL_MAX_10_EXP + DBL_DIG;
37  spin->setDecimals(decimalPrecision);
38  spin->setFixedWidth(100);
39  spin->setButtonMinimum(suggestedMinForCoord[whichCoord]);
40  spin->setButtonMaximum(suggestedMaxForCoord[whichCoord]);
41  spin->setSingleStep(suggestedStepForCoord[whichCoord]);
42  spin->setValue(initialValue);
43  return spin;
44 }
45 
49 QSlider* VuoInputEditorPoint4d::initSlider(coord whichCoord, QDialog& dialog, double initialValue)
50 {
51  double min = suggestedMinForCoord[whichCoord];
52  double max = suggestedMaxForCoord[whichCoord];
53  double step = suggestedStepForCoord[whichCoord];
54  double range = max - min;
55 
56  QSlider* slider = new QSlider(&dialog);
57  // slider->setAttribute(Qt::WA_MacSmallSize);
58  slider->setOrientation(Qt::Horizontal);
59  slider->setFocusPolicy(Qt::NoFocus);
60  slider->setMinimum(0);
61  slider->setMaximum(slider->width());
62  slider->setSingleStep( fmax(1, step * (slider->maximum() - slider->minimum()) / range ) );
63  slider->setValue( VuoDoubleSpinBox::doubleToSlider(slider->minimum(), slider->maximum(), min, max, initialValue) );
64  return slider;
65 }
66 
71 void VuoInputEditorPoint4d::setUpDialog(QDialog &dialog, json_object *originalValue, json_object *details)
72 {
73  current = VuoPoint4d_makeFromJson(originalValue);
74 
75  const double max_dbl = std::numeric_limits<double>::max();
76 
77  VuoPoint4d suggestedMin = VuoPoint4d_make(-max_dbl, -max_dbl, -max_dbl, -max_dbl);
78  VuoPoint4d suggestedMax = VuoPoint4d_make( max_dbl, max_dbl, max_dbl, max_dbl);
79  VuoPoint4d suggestedStep = VuoPoint4d_make(1.0, 1.0, 1.0, 1.0);
80 
81  bool hasMinMax = true;
82  bool tabCycleForward = true;
83 
84  // Parse supported port annotations from the port's "details" JSON object:
85  if (details)
86  {
87  json_object *forwardTabTraversal = NULL;
88  if (json_object_object_get_ex(details, "forwardTabTraversal", &forwardTabTraversal))
89  tabCycleForward = json_object_get_boolean(forwardTabTraversal);
90 
91  // "suggestedMin"
92  json_object *suggestedMinValue = NULL;
93  if (json_object_object_get_ex(details, "suggestedMin", &suggestedMinValue))
94  suggestedMin = VuoPoint4d_makeFromJson(suggestedMinValue);
95  else
96  hasMinMax = false;
97 
98  // "suggestedMax"
99  json_object *suggestedMaxValue = NULL;
100  if (json_object_object_get_ex(details, "suggestedMax", &suggestedMaxValue))
101  suggestedMax = VuoPoint4d_makeFromJson(suggestedMaxValue);
102  else
103  hasMinMax = false;
104 
105  // "suggestedStep"
106  if (hasMinMax)
107  suggestedStep = VuoPoint4d_make((suggestedMax.x - suggestedMin.x)/10.,
108  (suggestedMax.y - suggestedMin.y)/10.,
109  (suggestedMax.z - suggestedMin.z)/10.,
110  (suggestedMax.w - suggestedMin.w)/10.);
111  json_object *suggestedStepValue = NULL;
112  if (json_object_object_get_ex(details, "suggestedStep", &suggestedStepValue))
113  suggestedStep = VuoPoint4d_makeFromJson(suggestedStepValue);
114  }
115 
116  suggestedMinForCoord[coord_x] = suggestedMin.x;
117  suggestedMinForCoord[coord_y] = suggestedMin.y;
118  suggestedMinForCoord[coord_z] = suggestedMin.z;
119  suggestedMinForCoord[coord_w] = suggestedMin.w;
120 
121  suggestedMaxForCoord[coord_x] = suggestedMax.x;
122  suggestedMaxForCoord[coord_y] = suggestedMax.y;
123  suggestedMaxForCoord[coord_z] = suggestedMax.z;
124  suggestedMaxForCoord[coord_w] = suggestedMax.w;
125 
126  suggestedStepForCoord[coord_x] = suggestedStep.x;
127  suggestedStepForCoord[coord_y] = suggestedStep.y;
128  suggestedStepForCoord[coord_z] = suggestedStep.z;
129  suggestedStepForCoord[coord_w] = suggestedStep.w;
130 
131  spinboxForCoord[coord_x] = initSpinBox(coord_x, dialog, current.x);
132  spinboxForCoord[coord_y] = initSpinBox(coord_y, dialog, current.y);
133  spinboxForCoord[coord_z] = initSpinBox(coord_z, dialog, current.z);
134  spinboxForCoord[coord_w] = initSpinBox(coord_w, dialog, current.w);
135 
136  connect(spinboxForCoord[coord_x], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
137  connect(spinboxForCoord[coord_y], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
138  connect(spinboxForCoord[coord_z], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
139  connect(spinboxForCoord[coord_w], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
140 
141  if(hasMinMax)
142  {
143  sliderForCoord[coord_x] = initSlider(coord_x, dialog, current.x);
144  sliderForCoord[coord_y] = initSlider(coord_y, dialog, current.y);
145  sliderForCoord[coord_z] = initSlider(coord_z, dialog, current.z);
146  sliderForCoord[coord_w] = initSlider(coord_w, dialog, current.w);
147 
148  connect(sliderForCoord[coord_x], &QSlider::valueChanged, this, &VuoInputEditorPoint4d::onSliderUpdate);
149  connect(sliderForCoord[coord_y], &QSlider::valueChanged, this, &VuoInputEditorPoint4d::onSliderUpdate);
150  connect(sliderForCoord[coord_z], &QSlider::valueChanged, this, &VuoInputEditorPoint4d::onSliderUpdate);
151  connect(sliderForCoord[coord_w], &QSlider::valueChanged, this, &VuoInputEditorPoint4d::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, 16, 4);
162  layout->setSpacing(4);
163 
164  int row = 0;
165 
166  layout->addWidget(makeLabel("X"), row, 0, Qt::AlignHCenter);
167  layout->addWidget(spinboxForCoord[coord_x], row++, 1);
168  if(hasMinMax) layout->addWidget(sliderForCoord[coord_x], row++, 1);
169 
170  layout->addWidget(makeLabel("Y"), row, 0, Qt::AlignHCenter);
171  layout->addWidget(spinboxForCoord[coord_y], row++, 1);
172  if(hasMinMax) layout->addWidget(sliderForCoord[coord_y], row++, 1);
173 
174  layout->addWidget(makeLabel("Z"), row, 0, Qt::AlignHCenter);
175  layout->addWidget(spinboxForCoord[coord_z], row++, 1);
176  if(hasMinMax) layout->addWidget(sliderForCoord[coord_z], row++, 1);
177 
178  layout->addWidget(makeLabel("W"), row, 0, Qt::AlignHCenter);
179  layout->addWidget(spinboxForCoord[coord_w], row++, 1);
180  if(hasMinMax) layout->addWidget(sliderForCoord[coord_w], row++, 1);
181 
182  // forces dialog to min acceptable size
183  dialog.setMaximumWidth(1);
184  dialog.setMaximumHeight(1);
185 
186  dialog.adjustSize();
187 
188  // Layout details
189  setFirstWidgetInTabOrder(spinboxForCoord[coord_x]);
190  setLastWidgetInTabOrder(spinboxForCoord[coord_w]);
191 
192  // Return focus to the topmost line edit by default, or to the bottommost
193  // line edit if tab-cycling backwards.
194  // To be handled properly for https://b33p.net/kosada/node/6365 .
195  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_w])->setFocus();
196  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_w])->selectAll();
197 }
198 
199 bool VuoInputEditorPoint4d::getCoordFromQObject(QObject* sender, VuoInputEditorPoint4d::coord* whichCoord)
200 {
201  if(sender == spinboxForCoord[coord_x] || sender == sliderForCoord[coord_x])
202  *whichCoord = coord_x;
203  else if(sender == spinboxForCoord[coord_y] || sender == sliderForCoord[coord_y])
204  *whichCoord = coord_y;
205  else if(sender == spinboxForCoord[coord_z] || sender == sliderForCoord[coord_z])
206  *whichCoord = coord_z;
207  else if(sender == spinboxForCoord[coord_w] || sender == sliderForCoord[coord_w])
208  *whichCoord = coord_w;
209  else
210  return false;
211 
212  return true;
213 }
214 
215 void VuoInputEditorPoint4d::setCoord(coord c, double value)
216 {
217  if(c == coord_x)
218  current.x = value;
219  else if(c == coord_y)
220  current.y = value;
221  else if(c == coord_z)
222  current.z = value;
223  else if(c == coord_w)
224  current.w = value;
225 }
226 
230 void VuoInputEditorPoint4d::onSliderUpdate(int sliderValue)
231 {
232  coord whichCoord;
233 
234  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
235  return;
236 
237  QSlider *targetSlider = sliderForCoord[whichCoord];
238 
239  double value = VuoDoubleSpinBox::sliderToDouble(targetSlider->minimum(),
240  targetSlider->maximum(),
241  suggestedMinForCoord[whichCoord],
242  suggestedMaxForCoord[whichCoord],
243  sliderValue);
244  setCoord(whichCoord, value);
245 
246  // disconnect before setting spinbox value otherwise onSpinboxUpdate is called and the whole thing just cycles
247  disconnect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
248  spinboxForCoord[whichCoord]->setValue( value );
249  connect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint4d::onSpinboxUpdate);
250 
251  spinboxForCoord[whichCoord]->setFocus();
252  spinboxForCoord[whichCoord]->selectAll();
253 
254  emit valueChanged( getAcceptedValue() );
255 }
256 
260 void VuoInputEditorPoint4d::onSpinboxUpdate(QString spinboxValue)
261 {
262  coord whichCoord;
263 
264  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
265  return;
266 
267  double value = QLocale().toDouble(spinboxValue);
268  setCoord(whichCoord, value);
269 
270  QSlider *targetSlider = sliderForCoord[whichCoord];
271 
272  if(targetSlider != NULL)
273  {
274  int sliderValue = VuoDoubleSpinBox::doubleToSlider(targetSlider->minimum(), targetSlider->maximum(), suggestedMinForCoord[whichCoord], suggestedMaxForCoord[whichCoord], value);
275  disconnect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint4d::onSliderUpdate);
276  targetSlider->setValue( sliderValue );
277  connect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint4d::onSliderUpdate);
278  }
279 
280  emitValueChanged();
281 }
282 
287 {
288  return VuoPoint4d_getJson(current);
289 }
290 
294 void VuoInputEditorPoint4d::emitValueChanged()
295 {
297 }