Vuo  2.0.0
VuoInputEditorPoint2d.cc
Go to the documentation of this file.
1 
10 #include "VuoInputEditorPoint2d.hh"
11 
16 {
17  return new VuoInputEditorPoint2d();
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* VuoInputEditorPoint2d::initSpinBox(coord whichCoord, QDialog& dialog, double initialValue)
34 {
35  VuoDoubleSpinBox* spin = new VuoDoubleSpinBox(&dialog, 7);
36  const int decimalPrecision = FLT_MAX_10_EXP + FLT_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* VuoInputEditorPoint2d::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->setOrientation(Qt::Horizontal);
58  slider->setFocusPolicy(Qt::NoFocus);
59  slider->setMinimum(0);
60  slider->setMaximum(slider->width());
61  slider->setSingleStep( fmax(1, step * (slider->maximum() - slider->minimum()) / range ) );
62  slider->setValue( VuoDoubleSpinBox::doubleToSlider(slider->minimum(), slider->maximum(), min, max, initialValue) );
63  return slider;
64 }
65 
70 void VuoInputEditorPoint2d::setUpDialog(QDialog &dialog, json_object *originalValue, json_object *details)
71 {
72  current = VuoPoint2d_makeFromJson(originalValue);
73 
74  const double max_dbl = std::numeric_limits<double>::max();
75 
76  VuoPoint2d suggestedMin = VuoPoint2d_make(-max_dbl, -max_dbl);
77  VuoPoint2d suggestedMax = VuoPoint2d_make( max_dbl, max_dbl);
78  VuoPoint2d suggestedStep = VuoPoint2d_make(1.0, 1.0);
79 
80  bool hasMinMax = true;
81  bool tabCycleForward = true;
82 
83  // Parse supported port annotations from the port's "details" JSON object:
84  if (details)
85  {
86  json_object *forwardTabTraversal = NULL;
87  if (json_object_object_get_ex(details, "forwardTabTraversal", &forwardTabTraversal))
88  tabCycleForward = json_object_get_boolean(forwardTabTraversal);
89 
90  // "suggestedMin"
91  json_object *suggestedMinValue = NULL;
92  if (json_object_object_get_ex(details, "suggestedMin", &suggestedMinValue))
93  suggestedMin = VuoPoint2d_makeFromJson(suggestedMinValue);
94  else
95  hasMinMax = false;
96 
97  // "suggestedMax"
98  json_object *suggestedMaxValue = NULL;
99  if (json_object_object_get_ex(details, "suggestedMax", &suggestedMaxValue))
100  suggestedMax = VuoPoint2d_makeFromJson(suggestedMaxValue);
101  else
102  hasMinMax = false;
103 
104  // "suggestedStep"
105  if (hasMinMax)
106  suggestedStep = VuoPoint2d_make((suggestedMax.x - suggestedMin.x)/10.,
107  (suggestedMax.y - suggestedMin.y)/10.);
108  json_object *suggestedStepValue = NULL;
109  if (json_object_object_get_ex(details, "suggestedStep", &suggestedStepValue))
110  suggestedStep = VuoPoint2d_makeFromJson(suggestedStepValue);
111  }
112 
113  suggestedMinForCoord[coord_x] = suggestedMin.x;
114  suggestedMinForCoord[coord_y] = suggestedMin.y;
115  suggestedMaxForCoord[coord_x] = suggestedMax.x;
116  suggestedMaxForCoord[coord_y] = suggestedMax.y;
117  suggestedStepForCoord[coord_x] = suggestedStep.x;
118  suggestedStepForCoord[coord_y] = suggestedStep.y;
119 
120  spinboxForCoord[coord_x] = initSpinBox(coord_x, dialog, current.x);
121  spinboxForCoord[coord_y] = initSpinBox(coord_y, dialog, current.y);
122  connect(spinboxForCoord[coord_x], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint2d::onSpinboxUpdate);
123  connect(spinboxForCoord[coord_y], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint2d::onSpinboxUpdate);
124 
125  if(hasMinMax)
126  {
127  sliderForCoord[coord_x] = initSlider(coord_x, dialog, current.x);
128  sliderForCoord[coord_y] = initSlider(coord_y, dialog, current.y);
129  connect(sliderForCoord[coord_x], &QSlider::valueChanged, this, &VuoInputEditorPoint2d::onSliderUpdate);
130  connect(sliderForCoord[coord_y], &QSlider::valueChanged, this, &VuoInputEditorPoint2d::onSliderUpdate);
131  }
132 
133  // layout dialog
134  QGridLayout* layout = new QGridLayout;
135  dialog.setLayout(layout);
136 
137  // left, top, right, bottom
138  // when showing sliders, add a little extra margin on the bottom since QSlider takes up the
139  // entire vertical spacing
140  layout->setContentsMargins(4, 4, 16, 4);
141  layout->setSpacing(4);
142 
143  int row = 0;
144 
145  layout->addWidget(makeLabel("X"), row, 0, Qt::AlignHCenter);
146  layout->addWidget(spinboxForCoord[coord_x], row++, 1);
147  if(hasMinMax) layout->addWidget(sliderForCoord[coord_x], row++, 1);
148 
149  layout->addWidget(makeLabel("Y"), row, 0, Qt::AlignHCenter);
150  layout->addWidget(spinboxForCoord[coord_y], row++, 1);
151  if(hasMinMax) layout->addWidget(sliderForCoord[coord_y], row++, 1);
152 
153  dialog.setMaximumWidth(1);
154  dialog.setMaximumHeight(1);
155 
156  dialog.adjustSize();
157 
158  // Layout details
159  setFirstWidgetInTabOrder(spinboxForCoord[coord_x]);
160  setLastWidgetInTabOrder(spinboxForCoord[coord_y]);
161 
162  // Return focus to the topmost line edit by default, or to the bottommost
163  // line edit if tab-cycling backwards.
164  // To be handled properly for https://b33p.net/kosada/node/6365 .
165  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_y])->setFocus();
166  (tabCycleForward ? spinboxForCoord[coord_x] : spinboxForCoord[coord_y])->selectAll();
167 }
168 
169 bool VuoInputEditorPoint2d::getCoordFromQObject(QObject* sender, VuoInputEditorPoint2d::coord* whichCoord)
170 {
171  if(sender == spinboxForCoord[coord_x] || sender == sliderForCoord[coord_x])
172  *whichCoord = coord_x;
173  else if(sender == spinboxForCoord[coord_y] || sender == sliderForCoord[coord_y])
174  *whichCoord = coord_y;
175  else
176  return false;
177 
178  return true;
179 }
180 
181 void VuoInputEditorPoint2d::setCoord(coord c, double value)
182 {
183  if(c == coord_x)
184  current.x = value;
185  else if(c == coord_y)
186  current.y = value;
187 }
188 
192 void VuoInputEditorPoint2d::onSliderUpdate(int sliderValue)
193 {
194  coord whichCoord;
195 
196  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
197  return;
198 
199  QSlider *targetSlider = sliderForCoord[whichCoord];
200 
201  double value = VuoDoubleSpinBox::sliderToDouble(targetSlider->minimum(),
202  targetSlider->maximum(),
203  suggestedMinForCoord[whichCoord],
204  suggestedMaxForCoord[whichCoord],
205  sliderValue);
206  setCoord(whichCoord, value);
207 
208  // disconnect before setting spinbox value otherwise onSpinboxUpdate is called and the whole thing just cycles
209  disconnect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint2d::onSpinboxUpdate);
210  spinboxForCoord[whichCoord]->setValue( value );
211  connect(spinboxForCoord[whichCoord], static_cast<void (QDoubleSpinBox::*)(const QString &)>(&QDoubleSpinBox::valueChanged), this, &VuoInputEditorPoint2d::onSpinboxUpdate);
212 
213  spinboxForCoord[whichCoord]->setFocus();
214  spinboxForCoord[whichCoord]->selectAll();
215 
216  emit valueChanged( getAcceptedValue() );
217 }
218 
222 void VuoInputEditorPoint2d::onSpinboxUpdate(QString spinboxValue)
223 {
224  coord whichCoord;
225 
226  if(!getCoordFromQObject(QObject::sender(), &whichCoord))
227  return;
228 
229  double value = QLocale().toDouble(spinboxValue);
230  setCoord(whichCoord, value);
231 
232  QSlider *targetSlider = sliderForCoord[whichCoord];
233 
234  if(targetSlider != NULL)
235  {
236  int sliderValue = VuoDoubleSpinBox::doubleToSlider(targetSlider->minimum(), targetSlider->maximum(), suggestedMinForCoord[whichCoord], suggestedMaxForCoord[whichCoord], value);
237  disconnect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint2d::onSliderUpdate);
238  targetSlider->setValue( sliderValue );
239  connect(targetSlider, &QSlider::valueChanged, this, &VuoInputEditorPoint2d::onSliderUpdate);
240  }
241 
242  emitValueChanged();
243 }
244 
249 {
250  return VuoPoint2d_getJson(current);
251 }
252 
256 void VuoInputEditorPoint2d::emitValueChanged()
257 {
259 }