Vuo  2.0.0
VuoInputEditorPoint3d.cc
Go to the documentation of this file.
1 
10 #include "VuoInputEditorPoint3d.hh"
11 
16 {
17  return new VuoInputEditorPoint3d();
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* VuoInputEditorPoint3d::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* VuoInputEditorPoint3d::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 VuoInputEditorPoint3d::setUpDialog(QDialog &dialog, json_object *originalValue, json_object *details)
72 {
73  current = VuoPoint3d_makeFromJson(originalValue);
74 
75  const double max_dbl = std::numeric_limits<double>::max();
76 
77  VuoPoint3d suggestedMin = VuoPoint3d_make(-max_dbl, -max_dbl, -max_dbl);
78  VuoPoint3d suggestedMax = VuoPoint3d_make( max_dbl, max_dbl, max_dbl);
79  VuoPoint3d suggestedStep = VuoPoint3d_make(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 = VuoPoint3d_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 = VuoPoint3d_makeFromJson(suggestedMaxValue);
102  else
103  hasMinMax = false;
104 
105  // "suggestedStep"
106  if (hasMinMax)
107  suggestedStep = VuoPoint3d_make((suggestedMax.x - suggestedMin.x)/10.,
108  (suggestedMax.y - suggestedMin.y)/10.,
109  (suggestedMax.z - suggestedMin.z)/10.);
110  json_object *suggestedStepValue = NULL;
111  if (json_object_object_get_ex(details, "suggestedStep", &suggestedStepValue))
112  suggestedStep = VuoPoint3d_makeFromJson(suggestedStepValue);
113  }
114 
115  suggestedMinForCoord[coord_x] = suggestedMin.x;
116  suggestedMinForCoord[coord_y] = suggestedMin.y;
117  suggestedMinForCoord[coord_z] = suggestedMin.z;
118 
119  suggestedMaxForCoord[coord_x] = suggestedMax.x;
120  suggestedMaxForCoord[coord_y] = suggestedMax.y;
121  suggestedMaxForCoord[coord_z] = suggestedMax.z;
122 
123  suggestedStepForCoord[coord_x] = suggestedStep.x;
124  suggestedStepForCoord[coord_y] = suggestedStep.y;
125  suggestedStepForCoord[coord_z] = suggestedStep.z;
126 
127  spinboxForCoord[coord_x] = initSpinBox(coord_x, dialog, current.x);
128  spinboxForCoord[coord_y] = initSpinBox(coord_y, dialog, current.y);
129  spinboxForCoord[coord_z] = initSpinBox(coord_z, dialog, current.z);
130 
131  connect(spinboxForCoord[coord_x], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint3d::onSpinboxUpdate);
132  connect(spinboxForCoord[coord_y], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint3d::onSpinboxUpdate);
133  connect(spinboxForCoord[coord_z], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint3d::onSpinboxUpdate);
134 
135  if(hasMinMax)
136  {
137  sliderForCoord[coord_x] = initSlider(coord_x, dialog, current.x);
138  sliderForCoord[coord_y] = initSlider(coord_y, dialog, current.y);
139  sliderForCoord[coord_z] = initSlider(coord_z, dialog, current.z);
140 
141  connect(sliderForCoord[coord_x], &QSlider::valueChanged, this, &VuoInputEditorPoint3d::onSliderUpdate);
142  connect(sliderForCoord[coord_y], &QSlider::valueChanged, this, &VuoInputEditorPoint3d::onSliderUpdate);
143  connect(sliderForCoord[coord_z], &QSlider::valueChanged, this, &VuoInputEditorPoint3d::onSliderUpdate);
144  }
145 
146  // layout dialog
147  QGridLayout* layout = new QGridLayout;
148  dialog.setLayout(layout);
149 
150  // left, top, right, bottom
151  // when showing sliders, add a little extra margin on the bottom since QSlider takes up the
152  // entire vertical spacing
153  layout->setContentsMargins(4, 4, 16, 4);
154  layout->setSpacing(4);
155 
156  int row = 0;
157 
158  layout->addWidget(makeLabel("X"), row, 0, Qt::AlignHCenter);
159  layout->addWidget(spinboxForCoord[coord_x], row++, 1);
160  if(hasMinMax) layout->addWidget(sliderForCoord[coord_x], row++, 1);
161 
162  layout->addWidget(makeLabel("Y"), row, 0, Qt::AlignHCenter);
163  layout->addWidget(spinboxForCoord[coord_y], row++, 1);
164  if(hasMinMax) layout->addWidget(sliderForCoord[coord_y], row++, 1);
165 
166  layout->addWidget(makeLabel("Z"), row, 0, Qt::AlignHCenter);
167  layout->addWidget(spinboxForCoord[coord_z], row++, 1);
168  if(hasMinMax) layout->addWidget(sliderForCoord[coord_z], row++, 1);
169 
170  // forces dialog to min acceptable size
171  dialog.setMaximumWidth(1);
172  dialog.setMaximumHeight(1);
173 
174  dialog.adjustSize();
175 
176  // Layout details
177  setFirstWidgetInTabOrder(spinboxForCoord[coord_x]);
178  setLastWidgetInTabOrder(spinboxForCoord[coord_z]);
179 
180  // Return focus to the topmost line edit by default, or to the bottommost
181  // line edit if tab-cycling backwards.
182  // To be handled properly for https://b33p.net/kosada/node/6365 .
183  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_z])->setFocus();
184  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_z])->selectAll();
185 }
186 
187 bool VuoInputEditorPoint3d::getCoordFromQObject(QObject* sender, VuoInputEditorPoint3d::coord* whichCoord)
188 {
189  if(sender == spinboxForCoord[coord_x] || sender == sliderForCoord[coord_x])
190  *whichCoord = coord_x;
191  else if(sender == spinboxForCoord[coord_y] || sender == sliderForCoord[coord_y])
192  *whichCoord = coord_y;
193  else if(sender == spinboxForCoord[coord_z] || sender == sliderForCoord[coord_z])
194  *whichCoord = coord_z;
195  else
196  return false;
197 
198  return true;
199 }
200 
201 void VuoInputEditorPoint3d::setCoord(coord c, double value)
202 {
203  if(c == coord_x)
204  current.x = value;
205  else if(c == coord_y)
206  current.y = value;
207  else if(c == coord_z)
208  current.z = value;
209 }
210 
214 void VuoInputEditorPoint3d::onSliderUpdate(int sliderValue)
215 {
216  coord whichCoord;
217 
218  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
219  return;
220 
221  QSlider *targetSlider = sliderForCoord[whichCoord];
222 
223  double value = VuoDoubleSpinBox::sliderToDouble(targetSlider->minimum(),
224  targetSlider->maximum(),
225  suggestedMinForCoord[whichCoord],
226  suggestedMaxForCoord[whichCoord],
227  sliderValue);
228  setCoord(whichCoord, value);
229 
230  // disconnect before setting spinbox value otherwise onSpinboxUpdate is called and the whole thing just cycles
231  disconnect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint3d::onSpinboxUpdate);
232  spinboxForCoord[whichCoord]->setValue( value );
233  connect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint3d::onSpinboxUpdate);
234 
235  spinboxForCoord[whichCoord]->setFocus();
236  spinboxForCoord[whichCoord]->selectAll();
237 
238  emit valueChanged( getAcceptedValue() );
239 }
240 
244 void VuoInputEditorPoint3d::onSpinboxUpdate(QString spinboxValue)
245 {
246  coord whichCoord;
247 
248  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
249  return;
250 
251  double value = QLocale().toDouble(spinboxValue);
252  setCoord(whichCoord, value);
253 
254  QSlider *targetSlider = sliderForCoord[whichCoord];
255 
256  if(targetSlider != NULL)
257  {
258  int sliderValue = VuoDoubleSpinBox::doubleToSlider(targetSlider->minimum(), targetSlider->maximum(), suggestedMinForCoord[whichCoord], suggestedMaxForCoord[whichCoord], value);
259  disconnect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint3d::onSliderUpdate);
260  targetSlider->setValue( sliderValue );
261  connect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint3d::onSliderUpdate);
262  }
263 
264  emitValueChanged();
265 }
266 
271 {
272  return VuoPoint3d_getJson(current);
273 }
274 
278 void VuoInputEditorPoint3d::emitValueChanged()
279 {
281 }