GCC Code Coverage Report


Directory: ./
File: src/node-property.cpp
Date: 2025-04-14 11:18:00
Exec Total Coverage
Lines: 63 357 17.6%
Branches: 50 776 6.4%

Line Branch Exec Source
1 // Copyright (c) 2018, Joseph Mirabel
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4 // This file is part of gepetto-viewer.
5 // gepetto-viewer is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 //
10 // gepetto-viewer is distributed in the hope that it will be
11 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Lesser Public License for more details. You should have
14 // received a copy of the GNU Lesser General Public License along with
15 // gepetto-viewer. If not, see <http://www.gnu.org/licenses/>.
16
17 #include <gepetto/viewer/node-property.h>
18
19 #include <QCheckBox>
20 #include <QColorDialog>
21 #include <QComboBox>
22 #include <QDebug>
23 #include <QDoubleSpinBox>
24 #include <QFormLayout>
25 #include <QLabel>
26 #include <QLineEdit>
27 #include <QPushButton>
28 #include <gepetto/gui/dialog/configuration.hh>
29 #include <sstream>
30
31 namespace gepetto {
32 namespace viewer {
33 struct Initializer {
34 1 Initializer() {
35 1 qRegisterMetaType<osgVector2>("osgVector2");
36 1 qRegisterMetaType<osgVector3>("osgVector3");
37 1 qRegisterMetaType<osgVector4>("osgVector4");
38 1 qRegisterMetaType<Configuration>("Configuration");
39 1 }
40 };
41
42 static Initializer initializer;
43
44 template <typename T>
45 ✗ inline bool invalidType(const std::string& name, T) {
46 ✗ throw std::invalid_argument("Property " + name + " is not of type " +
47 details::property_type<T>::to_string());
48 }
49
50
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 Property::Property(const std::string& name) : QObject(NULL), name_(name) {
51
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 setObjectName(QString::fromStdString(name));
52 14 }
53
54 template <typename T>
55 8 bool check_if_value_changed(Property& prop, const T& v) {
56
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
8 if (!prop.hasReadAccess()) return true;
57 8 T current;
58
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
8 if (!prop.get(current)) return true;
59 8 return current != v;
60 }
61
62 ✗ inline QColor qColor(const osgVector4& v) {
63 ✗ return QColor::fromRgbF((qreal)v[0], (qreal)v[1], (qreal)v[2], (qreal)v[3]);
64 }
65
66 #define SET_IMPLEMENTATION(v, emit2) \
67 if (!check_if_value_changed(*this, v)) return true; \
68 if (impl_set(v)) { \
69 emit valueChanged(v); \
70 emit2; \
71 return true; \
72 } \
73 return false
74
75 ✗ bool Property::set(void) {
76 ✗ bool b = impl_set();
77 ✗ if (b) {
78 ✗ emit valueChanged();
79 }
80 ✗ return b;
81 }
82 ✗ bool Property::set(const bool& v) { SET_IMPLEMENTATION(v, ); }
83 ✗ bool Property::set(const int& v) { SET_IMPLEMENTATION(v, ); }
84 ✗ bool Property::set(const float& v) {
85 ✗ SET_IMPLEMENTATION(v, emit valueChanged(static_cast<double>(v)));
86 }
87 ✗ bool Property::set(const std::string& v) {
88 ✗ SET_IMPLEMENTATION(v, emit valueChanged(QString::fromStdString(v)));
89 }
90 ✗ bool Property::set(const osgVector2& v) { SET_IMPLEMENTATION(v, ); }
91 ✗ bool Property::set(const osgVector3& v) { SET_IMPLEMENTATION(v, ); }
92 ✗ bool Property::set(const osgVector4& v) {
93 ✗ SET_IMPLEMENTATION(v, emit valueChanged(qColor(v)));
94 }
95
3/4
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
4 bool Property::set(const Configuration& v) { SET_IMPLEMENTATION(v, ); }
96
97 ✗ bool Property::get(void) { return impl_get(); }
98 ✗ bool Property::get(bool& v) { return impl_get(v); }
99 ✗ bool Property::get(int& v) { return impl_get(v); }
100 ✗ bool Property::get(float& v) { return impl_get(v); }
101 ✗ bool Property::get(std::string& v) { return impl_get(v); }
102 ✗ bool Property::get(osgVector2& v) { return impl_get(v); }
103 ✗ bool Property::get(osgVector3& v) { return impl_get(v); }
104 ✗ bool Property::get(osgVector4& v) { return impl_get(v); }
105 4 bool Property::get(Configuration& v) { return impl_get(v); }
106
107 ✗ bool Property::impl_set(void) {
108 ✗ throw std::invalid_argument("Property " + name_ + " is not of type void.");
109 }
110 ✗ bool Property::impl_set(const bool& v) { return invalidType(name_, v); }
111 ✗ bool Property::impl_set(const int& v) { return invalidType(name_, v); }
112 ✗ bool Property::impl_set(const float& v) { return invalidType(name_, v); }
113 ✗ bool Property::impl_set(const std::string& v) { return invalidType(name_, v); }
114 ✗ bool Property::impl_set(const osgVector2& v) { return invalidType(name_, v); }
115 ✗ bool Property::impl_set(const osgVector3& v) { return invalidType(name_, v); }
116 ✗ bool Property::impl_set(const osgVector4& v) { return invalidType(name_, v); }
117 ✗ bool Property::impl_set(const Configuration& v) {
118 ✗ return invalidType(name_, v);
119 }
120
121 ✗ bool Property::impl_get(void) {
122 ✗ throw std::invalid_argument("Property " + name_ + " is not of type void.");
123 }
124 ✗ bool Property::impl_get(bool& v) { return invalidType(name_, v); }
125 ✗ bool Property::impl_get(int& v) { return invalidType(name_, v); }
126 ✗ bool Property::impl_get(float& v) { return invalidType(name_, v); }
127 ✗ bool Property::impl_get(std::string& v) { return invalidType(name_, v); }
128 ✗ bool Property::impl_get(osgVector2& v) { return invalidType(name_, v); }
129 ✗ bool Property::impl_get(osgVector3& v) { return invalidType(name_, v); }
130 ✗ bool Property::impl_get(osgVector4& v) { return invalidType(name_, v); }
131 ✗ bool Property::impl_get(Configuration& v) { return invalidType(name_, v); }
132
133 ✗ bool Property::set(const double& v) { return set(static_cast<float>(v)); }
134
135 ✗ bool Property::get(double& v) {
136 ✗ float _v = static_cast<float>(v);
137 ✗ bool res = get(_v);
138 ✗ v = static_cast<double>(_v);
139 ✗ return res;
140 }
141
142 ✗ bool Property::set(const QString& v) { return set(v.toStdString()); }
143
144 ✗ bool Property::get(QString& v) {
145 ✗ std::string _v = v.toStdString();
146 ✗ bool res = get(_v);
147 ✗ v = QString::fromStdString(_v);
148 ✗ return res;
149 }
150
151 ✗ bool Property::set(const QColor& v) {
152 ✗ return set(osgVector4((float)v.redF(), (float)v.greenF(), (float)v.blueF(),
153 ✗ (float)v.alphaF()));
154 }
155
156 ✗ bool Property::get(QColor& v) {
157 ✗ osgVector4 _v((float)v.redF(), (float)v.greenF(), (float)v.blueF(),
158 ✗ (float)v.alphaF());
159 ✗ bool res = get(_v);
160 ✗ v = qColor(_v);
161 ✗ return res;
162 }
163
164 ✗ QWidget* VoidProperty::guiEditor() {
165 QString toolTip(
166 "Python:\n"
167 ✗ " gui.callVoidProperty(nodeName,\"%1\")");
168 ✗ QPushButton* button = new QPushButton(objectName());
169 ✗ button->setToolTip(toolTip.arg(objectName()));
170 ✗ QObject::connect(button, &QAbstractButton::clicked, [this]() { get(); });
171 ✗ return button;
172 }
173
174 namespace details {
175 template <typename Scalar, typename QtScalar, typename QtSpinBox>
176 ✗ inline void setSpinBoxRange(const Property* prop, QtSpinBox* sb) {
177 ✗ const Range<Scalar>* range = dynamic_cast<const Range<Scalar>*>(prop);
178 ✗ if (range) {
179 ✗ if (range->hasMin()) sb->setMinimum(static_cast<QtScalar>(range->min));
180 ✗ if (range->hasMax()) sb->setMaximum(static_cast<QtScalar>(range->max));
181 ✗ sb->setSingleStep(static_cast<QtScalar>(range->step));
182 #if QT_VERSION > QT_VERSION_CHECK(5, 12, 0)
183 ✗ if (range->adaptiveDecimal)
184 ✗ sb->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
185 #endif
186 }
187 }
188
189 template <>
190 ✗ QWidget* buildEditor<bool>(Property* prop) {
191 QString toolTip(
192 "Python:\n"
193 " gui.getBoolProperty(nodeName,\"%1\")\n"
194 ✗ " gui.setBoolProperty(nodeName,\"%1\",boolean)");
195 ✗ QCheckBox* cb = new QCheckBox;
196 ✗ cb->setToolTip(toolTip.arg(prop->objectName()));
197 bool value;
198 ✗ /* bool success = */ prop->get(value);
199 ✗ cb->setChecked(value);
200 ✗ if (prop->hasWriteAccess()) {
201 ✗ prop->connect(cb, SIGNAL(toggled(bool)), SLOT(set(bool)),
202 Qt::DirectConnection);
203 ✗ cb->connect(prop, SIGNAL(valueChanged(bool)), SLOT(setChecked(bool)),
204 Qt::DirectConnection);
205 } else
206 ✗ cb->setEnabled(false);
207 ✗ return cb;
208 }
209
210 template <>
211 ✗ QWidget* buildEditor<std::string>(Property* prop) {
212 QString toolTip(
213 "Python:\n"
214 " gui.getStringProperty(nodeName,\"%1\")\n"
215 ✗ " gui.setStringProperty(nodeName,\"%1\",str)");
216 ✗ QLineEdit* le = new QLineEdit;
217 ✗ le->setToolTip(toolTip.arg(prop->objectName()));
218 ✗ std::string value;
219 ✗ /* bool success = */ prop->get(value);
220 ✗ le->setText(QString::fromStdString(value));
221 ✗ if (prop->hasWriteAccess()) {
222 ✗ prop->connect(le, SIGNAL(textChanged(QString)), SLOT(set(QString)),
223 Qt::DirectConnection);
224 ✗ le->connect(prop, SIGNAL(valueChanged(QString)), SLOT(setText(QString)),
225 Qt::DirectConnection);
226 } else
227 ✗ le->setReadOnly(true);
228 ✗ return le;
229 }
230
231 template <>
232 ✗ QWidget* buildEditor<float>(Property* prop) {
233 QString toolTip(
234 "Python:\n"
235 " gui.getFloatProperty(nodeName,\"%1\")\n"
236 ✗ " gui.setFloatProperty(nodeName,\"%1\",float)");
237 ✗ QDoubleSpinBox* dsb = new QDoubleSpinBox;
238 ✗ dsb->setObjectName(prop->objectName());
239 ✗ dsb->setToolTip(toolTip.arg(prop->objectName()));
240 float value;
241 ✗ /* bool success = */ prop->get(value);
242 ✗ dsb->setValue(value);
243 ✗ if (prop->hasWriteAccess()) {
244 ✗ prop->connect(dsb, SIGNAL(valueChanged(double)), SLOT(set(double)),
245 Qt::DirectConnection);
246 ✗ dsb->connect(prop, SIGNAL(valueChanged(double)), SLOT(setValue(double)),
247 Qt::DirectConnection);
248 } else
249 ✗ dsb->setEnabled(false);
250 ✗ setSpinBoxRange<float, double>(prop, dsb);
251 ✗ dsb->setDecimals(15);
252 ✗ return dsb;
253 }
254
255 template <>
256 ✗ QWidget* buildEditor<int>(Property* prop) {
257 QString toolTip(
258 "Python:\n"
259 " gui.getIntProperty(nodeName,\"%1\")\n"
260 ✗ " gui.setIntProperty(nodeName,\"%1\",int)");
261 ✗ QSpinBox* dsb = new QSpinBox;
262 ✗ dsb->setToolTip(toolTip.arg(prop->objectName()));
263 int value;
264 ✗ /* bool success = */ prop->get(value);
265 ✗ dsb->setValue(value);
266 ✗ if (prop->hasWriteAccess()) {
267 ✗ prop->connect(dsb, SIGNAL(valueChanged(int)), SLOT(set(int)),
268 Qt::DirectConnection);
269 ✗ dsb->connect(prop, SIGNAL(valueChanged(int)), SLOT(setValue(int)),
270 Qt::DirectConnection);
271 } else
272 ✗ dsb->setEnabled(false);
273 ✗ setSpinBoxRange<int, int>(prop, dsb);
274 ✗ return dsb;
275 }
276
277 template <typename VectorType>
278 struct traits {};
279 template <>
280 struct traits<osgVector2> {
281 typedef gui::Vector2Dialog Dialog_t;
282 };
283 template <>
284 struct traits<osgVector3> {
285 typedef gui::Vector3Dialog Dialog_t;
286 };
287 template <>
288 struct traits<osgVector4> {
289 typedef gui::Vector4Dialog Dialog_t;
290 };
291
292 template <typename VectorType>
293 ✗ QWidget* buildVectorNEditor(const QString& name, int N, Property* prop) {
294 typedef typename traits<VectorType>::Dialog_t Dialog_t;
295 ✗ QString toolTip(
296 "Python:\n"
297 " gui.getVector3Property(nodeName,\"%1\")\n"
298 " gui.setVector3Property(nodeName,\"%1\",int)");
299 ✗ QPushButton* button = new QPushButton("Set value");
300 ✗ button->setToolTip(toolTip.arg(name));
301
302 /// Vector3 dialog should be opened in a different place
303 ✗ Dialog_t* cfgDialog = new Dialog_t(prop);
304 ✗ cfgDialog->setValueFromProperty(prop);
305 ✗ switch (N) {
306 ✗ case 2:
307 ✗ prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector2)),
308 SLOT(set(osgVector2)), Qt::DirectConnection);
309 ✗ cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector2)),
310 SLOT(set(osgVector2)), Qt::DirectConnection);
311 ✗ break;
312 ✗ case 3:
313 ✗ prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector3)),
314 SLOT(set(osgVector3)), Qt::DirectConnection);
315 ✗ cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector3)),
316 SLOT(set(osgVector3)), Qt::DirectConnection);
317 ✗ break;
318 ✗ case 4:
319 ✗ prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector4)),
320 SLOT(set(osgVector4)), Qt::DirectConnection);
321 ✗ cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector4)),
322 SLOT(set(osgVector4)), Qt::DirectConnection);
323 ✗ break;
324 ✗ default:
325 ✗ break;
326 }
327 ✗ cfgDialog->setProperty("propertyName", name);
328 ✗ cfgDialog->connect(button, SIGNAL(clicked()), SLOT(show()));
329
330 ✗ return button;
331 }
332
333 template <>
334 ✗ QWidget* buildEditor<osgVector2>(Property* prop) {
335 ✗ if (!prop->hasWriteAccess()) return NULL;
336 ✗ return buildVectorNEditor<osgVector2>(prop->objectName(), 2, prop);
337 }
338
339 template <>
340 ✗ QWidget* buildEditor<osgVector3>(Property* prop) {
341 ✗ if (!prop->hasWriteAccess()) return NULL;
342 ✗ return buildVectorNEditor<osgVector3>(prop->objectName(), 3, prop);
343 }
344
345 ✗ QWidget* buildColorEditor(QString& name, Property* prop) {
346 QString toolTip(
347 "Python:\n"
348 " gui.getColorProperty(nodeName,\"%1\")\n"
349 ✗ " gui.setColorProperty(nodeName,\"%1\",int)");
350 ✗ QColor color;
351 ✗ /* bool success = */ prop->get(color);
352
353 ✗ QPushButton* button = new QPushButton("Select color");
354 ✗ button->setToolTip(toolTip.arg(name));
355 // Set icon for current color value
356
357 /// Color dialog should be opened in a different place
358 ✗ QColorDialog* colorDialog = new QColorDialog(color, button);
359 ✗ colorDialog->setOption(QColorDialog::ShowAlphaChannel, true);
360 ✗ colorDialog->setOption(QColorDialog::NoButtons, true);
361
362 ✗ colorDialog->setProperty("propertyName", name);
363 ✗ colorDialog->connect(button, SIGNAL(clicked()), SLOT(open()));
364
365 ✗ prop->connect(colorDialog, SIGNAL(currentColorChanged(QColor)),
366 SLOT(set(QColor)), Qt::DirectConnection);
367 #if __cplusplus >= 201103L and (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
368 ✗ QObject::connect(prop, QOverload<const QColor&>::of(&Property::valueChanged),
369 colorDialog, &QColorDialog::setCurrentColor,
370 // SLOT(set(QColor)),
371 Qt::DirectConnection);
372 #endif
373
374 ✗ return button;
375 }
376
377 template <>
378 ✗ QWidget* buildEditor<osgVector4>(Property* prop) {
379 ✗ if (!prop->hasWriteAccess()) return NULL;
380
381 ✗ QString name(prop->objectName());
382 ✗ if (name.contains("color", Qt::CaseInsensitive))
383 ✗ return buildColorEditor(name, prop);
384
385 ✗ return buildVectorNEditor<osgVector4>(prop->objectName(), 4, prop);
386 }
387
388 template <>
389 ✗ QWidget* buildEditor<Configuration>(Property* prop) {
390 // We could use buildVectorNEditor. The only bad point is that tooltip
391 // which will say setVector3Property instead of setConfigurationProperty...
392 ✗ if (!prop->hasWriteAccess()) return NULL;
393
394 ✗ QString name(QString::fromStdString(prop->name()));
395 ✗ QPushButton* button = new QPushButton("Set transform");
396
397 /// Color dialog should be opened in a different place
398 ✗ gui::ConfigurationDialog* cfgDialog = new gui::ConfigurationDialog(prop);
399 ✗ cfgDialog->setValueFromProperty(prop);
400 ✗ prop->connect(cfgDialog, SIGNAL(valueChanged(Configuration)),
401 SLOT(set(Configuration)), Qt::DirectConnection);
402 ✗ cfgDialog->connect(prop, SIGNAL(valueChanged(Configuration)),
403 SLOT(set(Configuration)), Qt::DirectConnection);
404
405 ✗ cfgDialog->setProperty("propertyName", name);
406 ✗ cfgDialog->connect(button, SIGNAL(clicked()), SLOT(show()));
407
408 ✗ return button;
409 }
410 } // namespace details
411
412 ✗ int MetaEnum::from_string(const std::string& s) {
413 ✗ for (std::size_t i = 0; i < names.size(); ++i)
414 ✗ if (s == names[i]) return values[i];
415 ✗ throw std::invalid_argument("Unknown name of enum (" + type + "): " + s);
416 }
417 ✗ std::string MetaEnum::to_string(const int& v) {
418 ✗ for (std::size_t i = 0; i < names.size(); ++i)
419 ✗ if (v == values[i]) return names[i];
420 ✗ throw std::invalid_argument("Unknown enum value (" + type + ")");
421 }
422
423 1 MetaEnum* visibilityModeEnum() {
424
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum vm;
425
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (vm.type.size() == 0) {
426 1 vm.type = "VisibilityMode";
427
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("ON");
428
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(VISIBILITY_ON);
429
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("ALWAYS_ON_TOP");
430
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(ALWAYS_ON_TOP);
431
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("OFF");
432
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(VISIBILITY_OFF);
433 }
434 1 return &vm;
435 }
436 1 MetaEnum* wireFrameModeEnum() {
437
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum wm;
438
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (wm.type.size() == 0) {
439 1 wm.type = "VisibilityMode";
440
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("FILL");
441
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(FILL);
442
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("WIREFRAME");
443
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(WIREFRAME);
444
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("FILL_AND_WIREFRAME");
445
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(FILL_AND_WIREFRAME);
446 }
447 1 return &wm;
448 }
449 1 MetaEnum* lightingModeEnum() {
450
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum lm;
451
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (lm.type.size() == 0) {
452 1 lm.type = "LightingMode";
453
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 lm.names.push_back("ON");
454
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lm.values.push_back(LIGHT_INFLUENCE_ON);
455
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 lm.names.push_back("OFF");
456
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lm.values.push_back(LIGHT_INFLUENCE_OFF);
457 }
458 1 return &lm;
459 }
460 ✗ MetaEnum* glImmediateModeEnum() {
461 ✗ static MetaEnum lm;
462 ✗ if (lm.type.size() == 0) {
463 ✗ lm.type = "GLImmediateMode";
464 ✗ lm.names.push_back("GL_LINES");
465 ✗ lm.values.push_back(GL_LINES);
466 ✗ lm.names.push_back("GL_POINTS");
467 ✗ lm.values.push_back(GL_POINTS);
468 ✗ lm.names.push_back("GL_LINE_STRIP");
469 ✗ lm.values.push_back(GL_LINE_STRIP);
470 ✗ lm.names.push_back("GL_LINE_LOOP");
471 ✗ lm.values.push_back(GL_LINE_LOOP);
472 ✗ lm.names.push_back("GL_POLYGON");
473 ✗ lm.values.push_back(GL_POLYGON);
474 ✗ lm.names.push_back("GL_QUADS");
475 ✗ lm.values.push_back(GL_QUADS);
476 ✗ lm.names.push_back("GL_QUAD_STRIP");
477 ✗ lm.values.push_back(GL_QUAD_STRIP);
478 ✗ lm.names.push_back("GL_TRIANGLE_STRIP");
479 ✗ lm.values.push_back(GL_TRIANGLE_STRIP);
480 ✗ lm.names.push_back("GL_TRIANGLES");
481 ✗ lm.values.push_back(GL_TRIANGLES);
482 ✗ lm.names.push_back("GL_TRIANGLE_FAN");
483 ✗ lm.values.push_back(GL_TRIANGLE_FAN);
484 }
485 ✗ return &lm;
486 }
487
488 ✗ bool EnumProperty::impl_set(const int& value) {
489 ✗ const MetaEnum& me = *metaEnum();
490 ✗ for (std::size_t i = 0; i < me.values.size(); ++i)
491 ✗ if (me.values[i] == value) return IntProperty::impl_set(value);
492 ✗ std::ostringstream oss;
493 ✗ oss << "Invalid value " << value << " for enum " << me.type
494 << ". "
495 ✗ "Possible values are ";
496 ✗ for (std::size_t i = 0; i < me.values.size(); ++i)
497 ✗ oss << me.names[i] << " (" << me.values[i] << "), ";
498 ✗ throw std::invalid_argument(oss.str());
499 return false;
500 }
501
502 ✗ bool EnumProperty::impl_set(const std::string& value) {
503 ✗ const MetaEnum& me = *metaEnum();
504 ✗ for (std::size_t i = 0; i < me.names.size(); ++i)
505 ✗ if (me.names[i] == value) return IntProperty::impl_set(me.values[i]);
506 ✗ std::ostringstream oss;
507 ✗ oss << "Invalid value " << value << " for enum " << me.type
508 << ". "
509 ✗ "Possible values are ";
510 ✗ for (std::size_t i = 0; i < me.values.size(); ++i)
511 ✗ oss << me.names[i] << " (" << me.values[i] << "), ";
512 ✗ throw std::invalid_argument(oss.str());
513 return false;
514 }
515
516 ✗ bool EnumProperty::impl_get(int& v) { return IntProperty::impl_get(v); }
517
518 ✗ bool EnumProperty::impl_get(std::string& str) {
519 int value;
520 ✗ if (!IntProperty::impl_get(value)) return false;
521 ✗ const MetaEnum& me = *metaEnum();
522 ✗ for (std::size_t i = 0; i < me.names.size(); ++i)
523 ✗ if (me.values[i] == value) {
524 ✗ str = me.names[i];
525 ✗ return true;
526 }
527 ✗ return false;
528 }
529
530 ✗ QWidget* EnumProperty::guiEditor() {
531 QString toolTip(
532 "Python:\n"
533 "As an integer:\n"
534 " gui.getIntProperty(nodeName,\"%1\")\n"
535 " gui.setIntProperty(nodeName,\"%1\",int)\n"
536 "or as a string:\n"
537 " gui.getStringProperty(nodeName,\"%1\")\n"
538 ✗ " gui.setStringProperty(nodeName,\"%1\",string)");
539
540 ✗ QComboBox* cb = new QComboBox;
541 ✗ cb->setToolTip(toolTip.arg(name().c_str()));
542 ✗ std::string value;
543 ✗ /* bool success = */ get(value);
544 ✗ for (unsigned i = 0; i < metaEnum_->values.size(); ++i) {
545 ✗ cb->addItem(metaEnum_->names[i].c_str(), metaEnum_->values[i]);
546 ✗ if (value == metaEnum_->names[i]) cb->setCurrentIndex(i);
547 }
548 ✗ if (hasWriteAccess()) {
549 ✗ connect(cb, SIGNAL(currentTextChanged(QString)), SLOT(set(QString)),
550 Qt::DirectConnection);
551 // On Qt4, the combo box will not be updated.
552 #if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0))
553 ✗ cb->connect(this, SIGNAL(valueChanged(QString)),
554 SLOT(setCurrentText(QString)), Qt::DirectConnection);
555 #endif
556 } else
557 ✗ cb->setEnabled(false);
558 ✗ return cb;
559 }
560
561 ✗ Property* Properties::property(const std::string& name) const {
562 ✗ PropertyMap_t::const_iterator _prop = properties_.find(name);
563 ✗ if (_prop == properties_.end())
564 ✗ throw std::invalid_argument("Unknown property " + name);
565 ✗ return _prop->second.p;
566 }
567
568 ✗ bool Properties::hasProperty(const std::string& name) const {
569 ✗ PropertyMap_t::const_iterator _prop = properties_.find(name);
570 ✗ return (_prop != properties_.end());
571 }
572
573 12 void Properties::addProperty(const PropertyPtr_t& prop) {
574 12 addProperty(prop->name(), prop);
575 12 }
576
577 12 void Properties::addProperty(const std::string& name,
578 const PropertyPtr_t& prop) {
579 12 Wrapper wrapped(prop);
580 std::pair<PropertyMap_t::iterator, bool> res =
581
2/4
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
12 properties_.insert(std::make_pair(name, Wrapper(prop)));
582
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (!res.second) res.first->second = prop;
583 12 }
584
585 2 void Properties::addProperty(Property* prop) {
586 2 addProperty(prop->name(), prop);
587 2 }
588
589 2 void Properties::addProperty(const std::string& name, Property* prop) {
590 2 Wrapper wrapped(prop);
591 std::pair<PropertyMap_t::iterator, bool> res =
592
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 properties_.insert(std::make_pair(name, Wrapper(prop)));
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!res.second) res.first->second = prop;
594 2 }
595
596 ✗ void addPropertyEditor(QFormLayout* l, const std::string& _name,
597 Property* prop) {
598 ✗ QString name(QString::fromStdString(_name));
599 ✗ QWidget* field = prop->guiEditor();
600 ✗ if (field != NULL) {
601 ✗ QLabel* label(new QLabel(name + ':'));
602 ✗ label->setToolTip(field->toolTip());
603 ✗ field->setProperty("propertyName", name);
604 ✗ l->addRow(label, field);
605 } else {
606 ✗ qDebug() << "Unhandled property" << name << "of type"
607 << prop->type().c_str() << ".";
608 }
609 }
610
611 ✗ QWidget* Properties::guiEditor() {
612 ✗ QWidget* editor = new QWidget;
613 ✗ QFormLayout* l = new QFormLayout(editor);
614
615 ✗ for (PropertyMap_t::const_iterator _prop = properties_.begin();
616 ✗ _prop != properties_.end(); ++_prop) {
617 ✗ if (!_prop->second->hasReadAccess()) continue;
618 ✗ addPropertyEditor(l, _prop->first, _prop->second.p);
619 }
620 ✗ return editor;
621 }
622 } /* namespace viewer */
623
624 } /* namespace gepetto */
625