GCC Code Coverage Report


Directory: ./
File: include/gepetto/viewer/node-property.h
Date: 2024-12-20 15:53:58
Exec Total Coverage
Lines: 65 138 47.1%
Branches: 22 95 23.2%

Line Branch Exec Source
1 // Copyright (c) 2017, LAAS-CNRS
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4 // This file is part of hpp-core.
5 // hpp-core 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 // hpp-core 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 // hpp-core. If not, see <http://www.gnu.org/licenses/>.
16
17 #ifndef GEPETTO_VIEWER_NODE_PROPERTY_HH
18 #define GEPETTO_VIEWER_NODE_PROPERTY_HH
19
20 #include <iostream>
21 #include <map>
22
23 #ifndef Q_MOC_RUN
24 #include <boost/bind.hpp>
25 #include <boost/function.hpp>
26 #include <boost/mpl/if.hpp>
27 #endif
28
29 #include <gepetto/viewer/config-osg.h>
30 #include <gepetto/viewer/fwd.h>
31
32 #include <QObject>
33
34 class QWidget;
35
36 namespace gepetto {
37 namespace viewer {
38
39 class Property;
40 template <typename T>
41 class PropertyTpl;
42 template <typename T, typename RangeT = T>
43 class RangedPropertyTpl;
44
45 /// \cond
46 namespace details {
47 template <typename T>
48 struct property_type {};
49 template <typename T>
50 struct property_type<const T> : property_type<T> {};
51 template <typename T>
52 struct property_type<T&> : property_type<T> {};
53 template <>
54 struct property_type<void> {
55 static inline std::string to_string() { return "void"; }
56 };
57 template <>
58 struct property_type<bool> {
59 static inline std::string to_string() { return "bool"; }
60 };
61 template <>
62 struct property_type<int> {
63 static inline std::string to_string() { return "int"; }
64 };
65 template <>
66 struct property_type<float> {
67 static inline std::string to_string() { return "float"; }
68 };
69 template <>
70 struct property_type<std::string> {
71 static inline std::string to_string() { return "string"; }
72 };
73 template <>
74 struct property_type<osgVector2> {
75 static inline std::string to_string() { return "osgVector2"; }
76 };
77 template <>
78 struct property_type<osgVector3> {
79 static inline std::string to_string() { return "osgVector3"; }
80 };
81 template <>
82 struct property_type<osgVector4> {
83 static inline std::string to_string() { return "osgVector4"; }
84 };
85 template <>
86 struct property_type<Configuration> {
87 static inline std::string to_string() { return "Configuration"; }
88 };
89
90 template <typename T>
91 QWidget* buildEditor(Property* /*property*/) {
92 return NULL;
93 }
94 template <>
95 QWidget* buildEditor<bool>(Property* property);
96 template <>
97 QWidget* buildEditor<int>(Property* property);
98 template <>
99 QWidget* buildEditor<float>(Property* property);
100 template <>
101 QWidget* buildEditor<std::string>(Property* property);
102 template <>
103 QWidget* buildEditor<osgVector2>(Property* property);
104 template <>
105 QWidget* buildEditor<osgVector3>(Property* property);
106 template <>
107 QWidget* buildEditor<osgVector4>(Property* property);
108 template <>
109 QWidget* buildEditor<Configuration>(Property* property);
110 } // namespace details
111 /// \endcond
112
113 /// Abstract base class for runtime properties of Node.
114 class Property : public QObject {
115 Q_OBJECT
116
117 public slots:
118 bool set(void);
119 bool set(const bool& v);
120 bool set(const int& v);
121 bool set(const float& v);
122 bool set(const std::string& v);
123 bool set(const osgVector2& v);
124 bool set(const osgVector3& v);
125 bool set(const osgVector4& v);
126 bool set(const Configuration& v);
127
128 // Provide slots to convert from double to float.
129 bool set(const double& v);
130
131 // Provide slots to convert from QString to std::string.
132 bool set(const QString& v);
133
134 // Provide slots to convert from QColor to osgVector4.
135 bool set(const QColor& v);
136
137 public:
138 bool get(void);
139 bool get(bool& v);
140 bool get(int& v);
141 bool get(float& v);
142 bool get(std::string& v);
143 bool get(osgVector2& v);
144 bool get(osgVector3& v);
145 bool get(osgVector4& v);
146 bool get(Configuration& v);
147
148 // Provide slots to convert from double to float.
149 bool get(double& v);
150 // Provide slots to convert from QString to std::string.
151 bool get(QString& v);
152 // Provide slots to convert from QColor to osgVector4.
153 bool get(QColor& v);
154
155 signals:
156 void valueChanged(void);
157 void valueChanged(const bool& v);
158 void valueChanged(const int& v);
159 void valueChanged(const float& v);
160 void valueChanged(const std::string& v);
161 void valueChanged(const osgVector2& v);
162 void valueChanged(const osgVector3& v);
163 void valueChanged(const osgVector4& v);
164 void valueChanged(const Configuration& v);
165
166 // Provide slots to convert from double to float.
167 void valueChanged(const double& v);
168 // Provide slots to convert from QString to std::string
169 void valueChanged(const QString& v);
170 // Provide slots to convert from QColor to osgVector4
171 void valueChanged(const QColor& v);
172
173 public:
174 virtual bool hasReadAccess() const = 0;
175 virtual bool hasWriteAccess() const = 0;
176
177 virtual std::string type() = 0;
178
179 14 const std::string& name() const { return name_; }
180
181 /// \return NULL is this property is not editable, otherwise it returns
182 /// a valid new QWidget.
183 virtual QWidget* guiEditor() { return NULL; }
184
185 protected:
186 virtual bool impl_set(void);
187 virtual bool impl_set(const bool& v);
188 virtual bool impl_set(const int& v);
189 virtual bool impl_set(const float& v);
190 virtual bool impl_set(const std::string& v);
191 virtual bool impl_set(const osgVector2& v);
192 virtual bool impl_set(const osgVector3& v);
193 virtual bool impl_set(const osgVector4& v);
194 virtual bool impl_set(const Configuration& v);
195
196 virtual bool impl_get(void);
197 virtual bool impl_get(bool& v);
198 virtual bool impl_get(int& v);
199 virtual bool impl_get(float& v);
200 virtual bool impl_get(std::string& v);
201 virtual bool impl_get(osgVector2& v);
202 virtual bool impl_get(osgVector3& v);
203 virtual bool impl_get(osgVector4& v);
204 virtual bool impl_get(Configuration& v);
205
206 protected:
207 Property(const std::string& name);
208
209 28 virtual ~Property() {}
210
211 const std::string name_;
212
213 inline void invalidGet() const {
214 throw std::logic_error("Cannot read property " + name_ + ".");
215 }
216 inline void invalidSet() const {
217 throw std::logic_error("Cannot write property " + name_ + ".");
218 }
219 };
220
221 class VoidProperty : public Property {
222 public:
223 typedef boost::function<void(void)> Function_t;
224 typedef shared_ptr<VoidProperty> Ptr_t;
225
226 static Ptr_t create(const std::string& name, const Function_t& f) {
227 return Ptr_t(new VoidProperty(name, f));
228 }
229 virtual std::string type() {
230 return details::property_type<void>::to_string();
231 }
232
233 template <typename Obj, typename ReturnType>
234 static inline Function_t memberFunction(Obj* obj,
235 ReturnType (Obj::*mem_func)()) {
236 return boost::bind(mem_func, obj);
237 }
238 template <typename Obj, typename ReturnType>
239 static inline Function_t memberFunction(Obj* obj,
240 ReturnType (Obj::*mem_func)() const) {
241 return boost::bind(mem_func, obj);
242 }
243
244 VoidProperty(const std::string& name, const Function_t& f)
245 : Property(name), function_(f) {}
246
247 virtual ~VoidProperty() {}
248
249 bool hasReadAccess() const { return (bool)function_; }
250 bool hasWriteAccess() const { return hasReadAccess(); }
251
252 const Function_t& function() const { return function_; }
253 void function(const Function_t& f) { function_ = f; }
254
255 QWidget* guiEditor();
256
257 protected:
258 bool impl_get(void) {
259 if (!hasReadAccess()) {
260 invalidGet();
261 return false;
262 }
263 function_();
264 return true;
265 }
266 bool impl_set(void) { return get(); }
267
268 private:
269 Function_t function_;
270 };
271
272 template <typename T>
273 class PropertyTpl : public Property {
274 public:
275 typedef boost::function<void(const T&)> Setter_t;
276 typedef boost::function<T(void)> Getter_t;
277 typedef shared_ptr<PropertyTpl> Ptr_t;
278
279 5 static Ptr_t create(const std::string& name, const Getter_t& g,
280 const Setter_t& s) {
281
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 return Ptr_t(new PropertyTpl(name, g, s));
282 }
283 1 static Ptr_t create(const std::string& name, const Getter_t& g) {
284
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 return Ptr_t(new PropertyTpl(name, g, Setter_t()));
285 }
286 1 static Ptr_t create(const std::string& name, const Setter_t& s) {
287
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 return Ptr_t(new PropertyTpl(name, Getter_t(), s));
288 }
289
290 virtual std::string type() { return details::property_type<T>::to_string(); }
291
292 template <typename Obj>
293 1 static inline Getter_t getterFromMemberFunction(Obj* obj,
294 const T& (Obj::*mem_func)()
295 const) {
296 1 return boost::bind(mem_func, obj);
297 }
298 template <typename Obj>
299 2 static inline Getter_t getterFromMemberFunction(Obj* obj,
300 T (Obj::*mem_func)() const) {
301 2 return boost::bind(mem_func, obj);
302 }
303 template <typename Obj>
304 2 static inline Setter_t setterFromMemberFunction(
305 Obj* obj, void (Obj::*mem_func)(const T&)) {
306 2 return boost::bind(mem_func, obj, _1);
307 }
308 template <typename Obj>
309 static inline Setter_t setterFromMemberFunction(Obj* obj,
310 void (Obj::*mem_func)(T)) {
311 return boost::bind(mem_func, obj, _1);
312 }
313
314 template <typename Obj, typename RetType>
315 static Ptr_t create(const std::string& name, Obj* obj,
316 RetType (Obj::*mem_get)() const,
317 void (Obj::*mem_set)(const T&)) {
318 return create(name, Getter_t(boost::bind(mem_get, obj)),
319 Setter_t(boost::bind(mem_set, obj, _1)));
320 }
321 template <typename Obj, typename RetType>
322 2 static Ptr_t create(const std::string& name, Obj* obj,
323 RetType (Obj::*mem_get)() const,
324 void (Obj::*mem_set)(T)) {
325
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 return create(name, Getter_t(boost::bind(mem_get, obj)),
326
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
6 Setter_t(boost::bind(mem_set, obj, _1)));
327 }
328 template <typename Obj, typename RetType>
329 1 static Ptr_t createRO(const std::string& name, Obj* obj,
330 RetType (Obj::*mem_get)() const) {
331
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 return create(name, Getter_t(boost::bind(mem_get, obj)));
332 }
333 template <typename Obj>
334 1 static Ptr_t createWO(const std::string& name, Obj* obj,
335 void (Obj::*mem_set)(const T&)) {
336
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 return create(name, Setter_t(boost::bind(mem_set, obj, _1)));
337 }
338 template <typename Obj, typename RetType>
339 static Ptr_t createWO(const std::string& name, Obj* obj,
340 void (Obj::*mem_set)(T)) {
341 return create(name, Setter_t(boost::bind(mem_set, obj, _1)));
342 }
343
344 23 PropertyTpl(const std::string& name, const Getter_t& g, const Setter_t& s)
345
2/4
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
23 : Property(name), getter_(g), setter_(s) {}
346
347 38 virtual ~PropertyTpl() {}
348
349 bool hasReadAccess() const { return (bool)getter_; }
350 bool hasWriteAccess() const { return (bool)setter_; }
351
352 const Getter_t& getter() const { return getter_; }
353 void getter(const Getter_t& g) { getter_ = g; }
354
355 const Setter_t& setter() const { return setter_; }
356 void setter(const Setter_t& s) { setter_ = s; }
357
358 virtual QWidget* guiEditor() { return details::buildEditor<T>(this); }
359
360 protected:
361 virtual bool impl_set(const T& value) {
362 if (!hasWriteAccess()) {
363 invalidSet();
364 return false;
365 }
366 setter_(value);
367 return true;
368 }
369 virtual bool impl_get(T& value) {
370 if (!hasReadAccess()) {
371 invalidGet();
372 return false;
373 }
374 value = getter_();
375 return true;
376 }
377
378 private:
379 Getter_t getter_;
380 Setter_t setter_;
381 };
382
383 template <typename Scalar>
384 struct Range {
385 Scalar min, max, step;
386 bool adaptiveDecimal;
387
388 2 Range()
389 :
390 #if __cplusplus >= 201103L
391 2 min(std::numeric_limits<Scalar>::lowest()),
392 #else
393 min(std::numeric_limits<Scalar>::quiet_NaN()),
394 #endif
395 2 max(std::numeric_limits<Scalar>::max()),
396 2 step(static_cast<Scalar>(1)),
397 2 adaptiveDecimal(false) {
398 2 }
399
400 #if __cplusplus >= 201103L
401 inline bool hasMin() const {
402 return min > std::numeric_limits<Scalar>::lowest();
403 }
404 #else
405 inline bool hasMin() const { return min == min; }
406 #endif
407 inline bool hasMax() const {
408 return max < std::numeric_limits<Scalar>::max();
409 }
410 inline bool hasRange() const { return hasMin() && hasMax(); }
411
412 void setRange(const Scalar& minimum, const Scalar& maximum) {
413 min = minimum;
414 max = maximum;
415 }
416 1 void setRange(const Scalar& minimum, const Scalar& maximum,
417 const Scalar& _step) {
418 1 min = minimum;
419 1 max = maximum;
420 1 step = _step;
421 1 }
422 };
423
424 template <typename T, typename RangeT>
425 class RangedPropertyTpl : public PropertyTpl<T>, public Range<RangeT> {
426 public:
427 typedef boost::function<void(const T&)> Setter_t;
428 typedef boost::function<T(void)> Getter_t;
429 typedef shared_ptr<RangedPropertyTpl> Ptr_t;
430
431 1 static Ptr_t create(const std::string& name, const Getter_t& g,
432 const Setter_t& s) {
433
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return Ptr_t(new RangedPropertyTpl(name, g, s));
434 }
435 static Ptr_t create(const std::string& name, const Getter_t& g) {
436 return Ptr_t(new RangedPropertyTpl(name, g, Setter_t()));
437 }
438 static Ptr_t create(const std::string& name, const Setter_t& s) {
439 return Ptr_t(new RangedPropertyTpl(name, Getter_t(), s));
440 }
441
442 template <typename Obj, typename RetType>
443 1 static Ptr_t create(const std::string& name, Obj* obj,
444 RetType (Obj::*mem_get)() const,
445 void (Obj::*mem_set)(const T&)) {
446
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 return create(name, Getter_t(boost::bind(mem_get, obj)),
447
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
3 Setter_t(boost::bind(mem_set, obj, _1)));
448 }
449 template <typename Obj, typename RetType>
450 static Ptr_t create(const std::string& name, Obj* obj,
451 RetType (Obj::*mem_get)() const,
452 void (Obj::*mem_set)(T)) {
453 return create(name, Getter_t(boost::bind(mem_get, obj)),
454 Setter_t(boost::bind(mem_set, obj, _1)));
455 }
456 template <typename Obj, typename RetType>
457 static Ptr_t createRO(const std::string& name, Obj* obj,
458 RetType (Obj::*mem_get)() const) {
459 return create(name, Getter_t(boost::bind(mem_get, obj)));
460 }
461 template <typename Obj>
462 static Ptr_t createWO(const std::string& name, Obj* obj,
463 void (Obj::*mem_set)(const T&)) {
464 return create(name, Setter_t(boost::bind(mem_set, obj, _1)));
465 }
466 template <typename Obj, typename RetType>
467 static Ptr_t createWO(const std::string& name, Obj* obj,
468 void (Obj::*mem_set)(T)) {
469 return create(name, Setter_t(boost::bind(mem_set, obj, _1)));
470 }
471
472 1 RangedPropertyTpl(const std::string& name, const Getter_t& g,
473 const Setter_t& s)
474 1 : PropertyTpl<T>(name, g, s) {}
475
476 4 virtual ~RangedPropertyTpl() {}
477 };
478
479 template <typename T>
480 class StoredPropertyTpl : public Property {
481 public:
482 typedef boost::function<void()> Callback_t;
483 typedef shared_ptr<StoredPropertyTpl> Ptr_t;
484
485 static Ptr_t create(const std::string& name) {
486 return Ptr_t(new StoredPropertyTpl(name));
487 }
488
489 virtual std::string type() { return details::property_type<T>::to_string(); }
490
491 4 StoredPropertyTpl(const std::string& name) : Property(name) {}
492
493 4 virtual ~StoredPropertyTpl() {}
494
495 8 bool hasReadAccess() const { return true; }
496 bool hasWriteAccess() const { return true; }
497
498 virtual QWidget* guiEditor() { return details::buildEditor<T>(this); }
499
500 1 const Callback_t& callback() const { return callback_; }
501 4 void callback(const Callback_t& s) { callback_ = s; }
502
503 T value;
504
505 protected:
506 6 bool impl_set(const T& v) {
507
2/5
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 bool c(callback_ && value != v);
508 6 value = v;
509
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 if (c) callback_();
510 6 return true;
511 }
512 4 bool impl_get(T& v) {
513 8 v = value;
514 8 return true;
515 }
516
517 Callback_t callback_;
518 };
519
520 template <typename T, typename RangeT>
521 class RangedStoredPropertyTpl : public StoredPropertyTpl<T>,
522 public Range<RangeT> {
523 public:
524 typedef shared_ptr<RangedStoredPropertyTpl> Ptr_t;
525
526 static Ptr_t create(const std::string& name) {
527 return Ptr_t(new RangedStoredPropertyTpl(name));
528 }
529
530 1 RangedStoredPropertyTpl(const std::string& name)
531 1 : StoredPropertyTpl<T>(name) {}
532
533 2 virtual ~RangedStoredPropertyTpl() {}
534 };
535
536 typedef PropertyTpl<bool> BoolProperty;
537 typedef PropertyTpl<int> IntProperty;
538 typedef PropertyTpl<float> FloatProperty;
539 typedef PropertyTpl<std::string> StringProperty;
540 typedef PropertyTpl<osgVector2> Vector2Property;
541 typedef PropertyTpl<osgVector3> Vector3Property;
542 typedef PropertyTpl<osgVector4> Vector4Property;
543 typedef PropertyTpl<Configuration> ConfigurationProperty;
544
545 typedef RangedPropertyTpl<int> RangedIntProperty;
546 typedef RangedPropertyTpl<float> RangedFloatProperty;
547 typedef RangedPropertyTpl<osgVector2, float> RangedVector2Property;
548 typedef RangedPropertyTpl<osgVector3, float> RangedVector3Property;
549 typedef RangedPropertyTpl<osgVector4, float> RangedVector4Property;
550 typedef RangedPropertyTpl<Configuration, float> RangedConfigurationProperty;
551
552 /// Conversion between integer and enum name at runtime.
553 struct MetaEnum {
554 std::string type;
555 std::vector<std::string> names;
556 std::vector<int> values;
557
558 int from_string(const std::string& s);
559 std::string to_string(const int& v);
560 };
561
562 MetaEnum* visibilityModeEnum();
563 MetaEnum* wireFrameModeEnum();
564 MetaEnum* lightingModeEnum();
565 MetaEnum* glImmediateModeEnum();
566
567 class EnumProperty : public IntProperty {
568 public:
569 using IntProperty::Getter_t;
570 using IntProperty::Setter_t;
571 typedef shared_ptr<EnumProperty> Ptr_t;
572
573 4 static Ptr_t create(const std::string& name, const MetaEnum* type,
574 const Getter_t& g, const Setter_t& s) {
575
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 return Ptr_t(new EnumProperty(name, type, g, s));
576 }
577 virtual std::string type() { return "enum"; }
578 const MetaEnum* metaEnum() const { return metaEnum_; }
579
580 4 EnumProperty(const std::string& name, const MetaEnum* type, const Getter_t& g,
581 const Setter_t& s)
582 4 : IntProperty(name, g, s), metaEnum_(type) {}
583
584 virtual QWidget* guiEditor();
585
586 protected:
587 /// Set the enum property.
588 /// It also checks that \c value is a valid enum.
589 bool impl_set(const int& value);
590
591 /// Set the enum property from a string.
592 /// It also checks that \c value is a valid enum.
593 bool impl_set(const std::string& value);
594
595 /// Get the enum property as an integer
596 bool impl_get(int& v);
597
598 /// Get the enum property as a string
599 bool impl_get(std::string& v);
600
601 private:
602 const MetaEnum* metaEnum_;
603 };
604
605 class Properties {
606 public:
607 struct Wrapper {
608 Property* p;
609 PropertyPtr_t lock;
610 4 Wrapper(Property* p) : p(p) {}
611 25 Wrapper(PropertyPtr_t p) : p(p.get()), lock(p) {}
612 Property* operator->() const { return p; }
613 };
614 typedef std::map<std::string, Wrapper> PropertyMap_t;
615
616 protected:
617 PropertyMap_t properties_;
618
619 /// Called when a property is modified.
620 virtual void setDirty(bool dirty = true) = 0;
621
622 public:
623 /// Access a property
624 /// \note do not use this to set the property value as it won't set
625 /// the current node as dirty.
626 Property* property(const std::string& name) const;
627
628 bool callVoidProperty(const std::string& name) const {
629 return property(name)->get();
630 }
631
632 template <typename T>
633 bool getProperty(const std::string& name, T& value) const {
634 return property(name)->get(value);
635 }
636
637 /// Set a property and set this object as dirty.
638 template <typename T>
639 bool setProperty(const std::string& name, const T& value) {
640 bool res = property(name)->set(value);
641 if (res) this->setDirty();
642 return res;
643 }
644
645 bool hasProperty(const std::string& name) const;
646
647 const PropertyMap_t& properties() const { return properties_; }
648
649 /// Add a property and take ownership.
650 void addProperty(const PropertyPtr_t& prop);
651
652 /// Add a property and take ownership.
653 void addProperty(const std::string& name, const PropertyPtr_t& prop);
654
655 /// Add a property and leave ownership.
656 void addProperty(Property* prop);
657
658 /// Add a property and leave ownership.
659 void addProperty(const std::string& name, Property* prop);
660
661 QWidget* guiEditor();
662 };
663
664 } /* namespace viewer */
665 } /* namespace gepetto */
666
667 #endif /* GEPETTO_VIEWER_NODE_PROPERTY_HH */
668