1 ///@file 2 /// Interface for 2D Canvas elements 3 // 4 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com> 5 // 6 // This library is free software; you can redistribute it and/or 7 // modify it under the terms of the GNU Library General Public 8 // License as published by the Free Software Foundation; either 9 // version 2 of the License, or (at your option) any later version. 10 // 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 // Library General Public License for more details. 15 // 16 // You should have received a copy of the GNU Library General Public 17 // License along with this library; if not, write to the Free Software 18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 20 #ifndef CANVAS_ELEMENT_HXX_ 21 #define CANVAS_ELEMENT_HXX_ 22 23 #include <simgear/canvas/canvas_fwd.hxx> 24 #include <simgear/canvas/CanvasEvent.hxx> 25 #include <simgear/props/PropertyBasedElement.hxx> 26 #include <simgear/misc/stdint.hxx> // for uint32_t 27 #include <simgear/std/type_traits.hxx> 28 29 #include <osg/BoundingBox> 30 #include <osg/MatrixTransform> 31 32 namespace osg 33 { 34 class Drawable; 35 } 36 37 namespace simgear 38 { 39 namespace canvas 40 { 41 42 /** 43 * Base class for Elements displayed inside a Canvas. 44 */ 45 class Element: 46 public PropertyBasedElement 47 { 48 public: 49 using SceneGroupWeakPtr = osg::observer_ptr<osg::MatrixTransform>; 50 51 /** 52 * Store pointer to window as user data 53 */ 54 class OSGUserData: 55 public osg::Referenced 56 { 57 public: 58 ElementPtr element; 59 OSGUserData(ElementPtr element); 60 }; 61 62 typedef std::function<bool(Element&, const SGPropertyNode*)> 63 StyleSetterFunc; 64 typedef std::function<void(Element&, const SGPropertyNode*)> 65 StyleSetterFuncUnchecked; 66 struct StyleSetter: 67 public SGReferenced 68 { 69 StyleSetterFunc func; 70 SGSharedPtr<StyleSetter> next; 71 }; 72 struct StyleInfo 73 { 74 StyleSetter setter; ///< Function(s) for setting this style 75 std::string type; ///< Interpolation type 76 bool inheritable; ///< Whether children can inherit this style from 77 /// their parents 78 }; 79 80 /** 81 * Coordinate reference frame (eg. "clip" property) 82 */ 83 enum ReferenceFrame 84 { 85 GLOBAL, ///< Global coordinates 86 PARENT, ///< Coordinates relative to parent coordinate frame 87 LOCAL ///< Coordinates relative to local coordinates (parent 88 /// coordinates with local transformations applied) 89 }; 90 91 /** 92 * 93 */ 94 virtual ~Element() = 0; 95 void onDestroy() override; 96 97 ElementPtr getParent() const; 98 CanvasWeakPtr getCanvas() const; 99 100 /** 101 * Called every frame to update internal state 102 * 103 * @param dt Frame time in seconds 104 */ 105 void update(double dt) override; 106 107 bool addEventListener(const std::string& type, const EventListener& cb); 108 virtual void clearEventListener(); 109 110 /// Get (keyboard) input focus. 111 void setFocus(); 112 113 virtual bool accept(EventVisitor& visitor); 114 virtual bool ascend(EventVisitor& visitor); 115 virtual bool traverse(EventVisitor& visitor); 116 117 /// Get the number of event handlers for the given type 118 size_t numEventHandler(int type) const; 119 120 virtual bool handleEvent(const EventPtr& event); 121 bool dispatchEvent(const EventPtr& event); 122 123 /** 124 * 125 * @param global_pos Position in global (canvas) coordinate frame 126 * @param parent_pos Position in parent coordinate frame 127 * @param local_pos Position in local (element) coordinate frame 128 */ 129 virtual bool hitBound( const osg::Vec2f& global_pos, 130 const osg::Vec2f& parent_pos, 131 const osg::Vec2f& local_pos ) const; 132 133 /** 134 * Set visibility of the element. 135 */ 136 virtual void setVisible(bool visible); 137 138 /** 139 * Get whether the element is visible or hidden. 140 */ 141 virtual bool isVisible() const; 142 143 /** 144 * Get the according group in the OSG scene graph 145 */ 146 // TODO ref_ptr 147 osg::MatrixTransform* getSceneGroup() const; 148 149 /** 150 * Transform position to local coordinages. 151 */ 152 osg::Vec2f posToLocal(const osg::Vec2f& pos) const; 153 154 void childAdded(SGPropertyNode* parent, SGPropertyNode* child) override; 155 void childRemoved(SGPropertyNode* parent, SGPropertyNode* child) override; 156 void valueChanged(SGPropertyNode* child) override; 157 158 virtual bool setStyle( const SGPropertyNode* child, 159 const StyleInfo* style_info = 0 ); 160 161 /** 162 * Set clipping shape 163 * 164 * @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported 165 * @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip 166 */ 167 void setClip(const std::string& clip); 168 169 /** 170 * Clipping coordinates reference frame 171 */ 172 void setClipFrame(ReferenceFrame rf); 173 174 /** 175 * 176 */ 177 void setRotation(unsigned int index, double r); 178 179 /** 180 * 181 */ 182 void setTranslation(unsigned int index, double x, double y); 183 184 /** 185 * 186 * 187 */ 188 void setTransformEnabled(unsigned int index, bool enabled); 189 190 /** 191 * Get bounding box (may not be as tight as bounding box returned by 192 * #getTightBoundingBox) 193 */ 194 osg::BoundingBox getBoundingBox() const; 195 196 /** 197 * Get tight bounding box (child points are transformed to elements 198 * coordinate space before calculating the bounding box). 199 */ 200 osg::BoundingBox getTightBoundingBox() const; 201 202 /** 203 * Get bounding box with children/drawables transformed by passed matrix 204 */ 205 virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; 206 207 /** 208 * Get the transformation matrix (product of all transforms) 209 */ 210 osg::Matrix getMatrix() const; 211 212 /** 213 * Create an canvas Element 214 * 215 * @tparam Derived Type of element (needs to derive from Element) 216 */ 217 template<typename Derived> 218 static 219 std::enable_if_t< 220 std::is_base_of<Element, Derived>::value, 221 ElementPtr 222 > create(const CanvasWeakPtr & canvas,const SGPropertyNode_ptr & node,const Style & style=Style (),Element * parent=NULL)223 create( const CanvasWeakPtr& canvas, 224 const SGPropertyNode_ptr& node, 225 const Style& style = Style(), 226 Element* parent = NULL ) 227 { 228 return ElementPtr( new Derived(canvas, node, style, parent) ); 229 } 230 231 protected: 232 233 enum Attributes 234 { 235 TRANSFORM = 1, 236 BLEND_FUNC = TRANSFORM << 1, 237 LAST_ATTRIBUTE = BLEND_FUNC << 1 238 }; 239 240 enum TransformType 241 { 242 TT_NONE, 243 TT_MATRIX, 244 TT_TRANSLATE, 245 TT_ROTATE, 246 TT_SCALE 247 }; 248 249 class RelativeScissor; 250 251 CanvasWeakPtr _canvas; 252 ElementWeakPtr _parent; 253 254 mutable uint32_t _attributes_dirty = 0; 255 256 SceneGroupWeakPtr _scene_group; 257 std::vector<TransformType> _transform_types; 258 259 Style _style; 260 RelativeScissor *_scissor = nullptr; 261 262 typedef std::vector<EventListener> Listener; 263 typedef std::map<int, Listener> ListenerMap; 264 265 ListenerMap _listener; 266 267 typedef std::map<std::string, StyleInfo> StyleSetters; 268 static StyleSetters _style_setters; 269 270 static void staticInit(); 271 272 Element( const CanvasWeakPtr& canvas, 273 const SGPropertyNode_ptr& node, 274 const Style& parent_style, 275 ElementWeakPtr parent ); 276 277 /** 278 * Returns false on first call and true on any successive call. Use to 279 * perform initialization tasks which are only required once per element 280 * type. 281 * 282 * @tparam Derived (Derived) class type 283 */ 284 template<class Derived> isInit()285 static bool isInit() 286 { 287 static bool is_init = false; 288 if( is_init ) 289 return true; 290 291 is_init = true; 292 return false; 293 } 294 295 /** 296 * Register a function for setting a style specified by the given property 297 * 298 * @param name Property name 299 * @param type Interpolation type 300 * @param setter Setter function 301 * @param inheritable If this style propagates to child elements 302 * 303 * @tparam T1 Type of value used to retrieve value from property 304 * node 305 * @tparam T2 Type of value the setter function expects 306 * @tparam Derived Type of class the setter can be applied to 307 * 308 * @note T1 needs to be convertible to T2 309 */ 310 template< 311 typename T1, 312 typename T2, 313 class Derived 314 > 315 static 316 StyleSetter addStyle(const std::string & name,const std::string & type,const std::function<void (Derived &,T2)> & setter,bool inheritable=true)317 addStyle( const std::string& name, 318 const std::string& type, 319 const std::function<void (Derived&, T2)>& setter, 320 bool inheritable = true ) 321 { 322 StyleInfo& style_info = _style_setters[ name ]; 323 if( !type.empty() ) 324 { 325 if( !style_info.type.empty() && type != style_info.type ) 326 SG_LOG 327 ( 328 SG_GENERAL, 329 SG_WARN, 330 "changing animation type for '" << name << "': " 331 << style_info.type << " -> " << type 332 ); 333 334 style_info.type = type; 335 } 336 // TODO check if changed? 337 style_info.inheritable = inheritable; 338 339 StyleSetter* style = &style_info.setter; 340 while( style->next ) 341 style = style->next; 342 if( style->func ) 343 style = style->next = new StyleSetter; 344 345 style->func = std::bind(&type_match<Derived>::call, 346 std::placeholders::_1, 347 std::placeholders::_2, 348 bindStyleSetter<T1>(name, setter)); 349 return *style; 350 } 351 352 template< 353 typename T, 354 class Derived 355 > 356 static 357 StyleSetter addStyle(const std::string & name,const std::string & type,const std::function<void (Derived &,T)> & setter,bool inheritable=true)358 addStyle( const std::string& name, 359 const std::string& type, 360 const std::function<void (Derived&, T)>& setter, 361 bool inheritable = true ) 362 { 363 return addStyle<T, T>(name, type, setter, inheritable); 364 } 365 366 template< 367 typename T, 368 class Derived 369 > 370 static 371 StyleSetter addStyle(const std::string & name,const std::string & type,void (Derived::* setter)(T),bool inheritable=true)372 addStyle( const std::string& name, 373 const std::string& type, 374 void (Derived::*setter)(T), 375 bool inheritable = true ) 376 { 377 return addStyle<T, T> 378 ( 379 name, 380 type, 381 std::function<void (Derived&, T)>(setter), 382 inheritable 383 ); 384 } 385 386 template< 387 typename T1, 388 typename T2, 389 class Derived 390 > 391 static 392 StyleSetterFunc addStyle(const std::string & name,const std::string & type,void (Derived::* setter)(T2),bool inheritable=true)393 addStyle( const std::string& name, 394 const std::string& type, 395 void (Derived::*setter)(T2), 396 bool inheritable = true ) 397 { 398 return addStyle<T1> 399 ( 400 name, 401 type, 402 std::function<void (Derived&, T2)>(setter), 403 inheritable 404 ); 405 } 406 407 template< 408 class Derived 409 > 410 static 411 StyleSetter addStyle(const std::string & name,const std::string & type,void (Derived::* setter)(const std::string &),bool inheritable=true)412 addStyle( const std::string& name, 413 const std::string& type, 414 void (Derived::*setter)(const std::string&), 415 bool inheritable = true ) 416 { 417 return addStyle<const char*, const std::string&> 418 ( 419 name, 420 type, 421 std::function<void (Derived&, const std::string&)>(setter), 422 inheritable 423 ); 424 } 425 426 template< 427 typename T, 428 class Derived, 429 class Other, 430 class OtherRef 431 > 432 static 433 StyleSetter addStyle(const std::string & name,const std::string & type,void (Other::* setter)(T),OtherRef Derived::* instance_ref,bool inheritable=true)434 addStyle( const std::string& name, 435 const std::string& type, 436 void (Other::*setter)(T), 437 OtherRef Derived::*instance_ref, 438 bool inheritable = true ) 439 { 440 return addStyle<T, T> 441 ( 442 name, 443 type, 444 bindOther(setter, instance_ref), 445 inheritable 446 ); 447 } 448 449 template< 450 typename T1, 451 typename T2, 452 class Derived, 453 class Other, 454 class OtherRef 455 > 456 static 457 StyleSetter addStyle(const std::string & name,const std::string & type,void (Other::* setter)(T2),OtherRef Derived::* instance_ref,bool inheritable=true)458 addStyle( const std::string& name, 459 const std::string& type, 460 void (Other::*setter)(T2), 461 OtherRef Derived::*instance_ref, 462 bool inheritable = true ) 463 { 464 return addStyle<T1> 465 ( 466 name, 467 type, 468 bindOther(setter, instance_ref), 469 inheritable 470 ); 471 } 472 473 template< 474 typename T1, 475 typename T2, 476 class Derived, 477 class Other, 478 class OtherRef 479 > 480 static 481 StyleSetter addStyle(const std::string & name,const std::string & type,const std::function<void (Other &,T2)> & setter,OtherRef Derived::* instance_ref,bool inheritable=true)482 addStyle( const std::string& name, 483 const std::string& type, 484 const std::function<void (Other&, T2)>& setter, 485 OtherRef Derived::*instance_ref, 486 bool inheritable = true ) 487 { 488 return addStyle<T1> 489 ( 490 name, 491 type, 492 bindOther(setter, instance_ref), 493 inheritable 494 ); 495 } 496 497 template< 498 class Derived, 499 class Other, 500 class OtherRef 501 > 502 static 503 StyleSetter addStyle(const std::string & name,const std::string & type,void (Other::* setter)(const std::string &),OtherRef Derived::* instance_ref,bool inheritable=true)504 addStyle( const std::string& name, 505 const std::string& type, 506 void (Other::*setter)(const std::string&), 507 OtherRef Derived::*instance_ref, 508 bool inheritable = true ) 509 { 510 return addStyle<const char*, const std::string&> 511 ( 512 name, 513 type, 514 std::function<void (Other&, const std::string&)>(setter), 515 instance_ref, 516 inheritable 517 ); 518 } 519 520 template<typename T, class Derived, class Other, class OtherRef> 521 static 522 std::function<void (Derived&, T)> bindOther(void (Other::* setter)(T),OtherRef Derived::* instance_ref)523 bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref ) 524 { 525 return std::bind(setter, 526 std::bind(instance_ref, std::placeholders::_1), 527 std::placeholders::_2); 528 } 529 530 template<typename T, class Derived, class Other, class OtherRef> 531 static 532 std::function<void (Derived&, T)> bindOther(const std::function<void (Other &,T)> & setter,OtherRef Derived::* instance_ref)533 bindOther( const std::function<void (Other&, T)>& setter, 534 OtherRef Derived::*instance_ref ) 535 { 536 return std::bind(setter, 537 std::bind(&reference_from_pointer<Other, OtherRef>, 538 std::bind(instance_ref, std::placeholders::_1)), 539 std::placeholders::_2); 540 } 541 542 template<typename T1, typename T2, class Derived> 543 static 544 StyleSetterFuncUnchecked bindStyleSetter(const std::string & name,const std::function<void (Derived &,T2)> & setter)545 bindStyleSetter( const std::string& name, 546 const std::function<void (Derived&, T2)>& setter ) 547 { 548 return std::bind(setter, 549 // We will only call setters with Derived instances, so we can safely 550 // cast here. 551 std::bind(&derived_cast<Derived>, std::placeholders::_1), 552 std::bind(&getValue<T1>, std::placeholders::_2)); 553 } 554 555 bool isStyleEmpty(const SGPropertyNode* child) const; 556 bool canApplyStyle(const SGPropertyNode* child) const; 557 bool setStyleImpl( const SGPropertyNode* child, 558 const StyleInfo* style_info = 0 ); 559 560 const StyleInfo* getStyleInfo(const std::string& name) const; 561 const StyleSetter* getStyleSetter(const std::string& name) const; 562 const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const; 563 childAdded(SGPropertyNode * child)564 virtual void childAdded(SGPropertyNode * child) {} childRemoved(SGPropertyNode * child)565 virtual void childRemoved(SGPropertyNode * child){} childChanged(SGPropertyNode * child)566 virtual void childChanged(SGPropertyNode * child){} 567 568 void setDrawable(osg::Drawable* drawable); 569 570 /** 571 * Get stateset of drawable if available or use transform otherwise 572 */ 573 virtual osg::StateSet* getOrCreateStateSet(); 574 575 void setupStyle(); 576 577 void updateMatrix() const; 578 579 virtual void updateImpl(double dt); 580 581 private: 582 583 osg::ref_ptr<osg::Drawable> _drawable; 584 585 Element(const Element&) = delete; 586 587 template<class Derived> derived_cast(Element & el)588 static Derived& derived_cast(Element& el) 589 { 590 return static_cast<Derived&>(el); 591 } 592 593 template<class T, class SharedPtr> reference_from_pointer(const SharedPtr & p)594 static T& reference_from_pointer(const SharedPtr& p) 595 { 596 return *get_pointer(p); 597 } 598 599 /** 600 * Helper to call a function only of the element type can be converted to 601 * the required type. 602 * 603 * @return Whether the function has been called 604 */ 605 template<class Derived> 606 struct type_match 607 { callsimgear::canvas::Element::type_match608 static bool call( Element& el, 609 const SGPropertyNode* prop, 610 const StyleSetterFuncUnchecked& func ) 611 { 612 Derived* d = dynamic_cast<Derived*>(&el); 613 if( !d ) 614 return false; 615 func(*d, prop); 616 return true; 617 } 618 }; 619 }; 620 621 } // namespace canvas 622 623 template<> 624 struct enum_traits<canvas::Element::ReferenceFrame> 625 { namesimgear::enum_traits626 static const char* name() 627 { 628 return "canvas::Element::ReferenceFrame"; 629 } 630 defValsimgear::enum_traits631 static canvas::Element::ReferenceFrame defVal() 632 { 633 return canvas::Element::GLOBAL; 634 } 635 validatesimgear::enum_traits636 static bool validate(int frame) 637 { 638 return frame >= canvas::Element::GLOBAL 639 && frame <= canvas::Element::LOCAL; 640 } 641 }; 642 643 } // namespace simgear 644 645 #endif /* CANVAS_ELEMENT_HXX_ */ 646