1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/gui/interface_group.h"
24 #include "nel/gui/interface_property.h"
25 #include "nel/gui/view_renderer.h"
26 #include "nel/gui/widget_manager.h"
27 #include "nel/gui/db_manager.h"
28 #include "nel/gui/interface_link.h"
29 #include "nel/misc/xml_auto_ptr.h"
30 #include "nel/gui/lua_ihm.h"
31 #include "nel/gui/lua_ihm.h"
32 #include "nel/misc/mem_stream.h"
36 using namespace NLMISC
;
44 bool CInterfaceElement::editorMode
= false;
45 std::vector
< CInterfaceElement::IDeletionWatcher
* > CInterfaceElement::deletionWatchers
;
47 // ------------------------------------------------------------------------------------------------
48 CInterfaceElement::~CInterfaceElement()
50 if (_Links
) // remove any link that point to that element
52 for(TLinkVect::iterator it
= _Links
->begin(); it
!= _Links
->end(); ++it
)
54 (*it
)->removeTarget(this);
61 notifyDeletionWatchers();
63 _Parent
->onWidgetDeleted( this );
67 // ------------------------------------------------------------------------------------------------
68 void CInterfaceElement::parseError(CInterfaceGroup
* parentGroup
, const char *reason
)
70 string tmp
= string("cannot parse view:")+getId()+", parent:"+parentGroup
->getId();
73 nlinfo("reason : %s", reason
);
77 void CInterfaceElement::setIdRecurse(const std::string
&newID
)
79 std::string baseId
= _Parent
? _Parent
->getId() : "ui";
80 setId(baseId
+ ":" + newID
);
83 // ------------------------------------------------------------------------------------------------
84 std::string
CInterfaceElement::getShortId() const
86 std::string::size_type last
= _Id
.find_last_of(':');
87 if (last
!= std::string::npos
)
89 return _Id
.substr(last
+ 1);
94 std::string
CInterfaceElement::stripId( const std::string
&fullId
)
96 std::string id
= fullId
;
97 std::string::size_type i
= id
.find_last_of( ':' );
98 if( i
!= std::string::npos
)
99 id
= id
.substr( i
+ 1, id
.size() - 1 );
103 std::string
CInterfaceElement::getProperty( const std::string
&name
) const
107 return stripId( getId() );
110 if( name
== "active" )
120 return NLMISC::toString( getX() );
125 return NLMISC::toString( getY() );
130 return NLMISC::toString( getW() );
135 return NLMISC::toString( getH() );
138 if( name
== "posref" )
141 posref
+= HotSpotToString( getPosRef() );
145 if( name
== "parentposref" )
147 std::string parentPosRef
;
148 parentPosRef
= HotSpotToString( getParentPosRef() );
152 if( name
== "sizeref" )
154 return getSizeRefAsString( _SizeRef
, _SizeDivW
, _SizeDivH
);
156 if( name
== "posparent" )
163 if( name
== "sizeparent" )
170 if( name
== "global_color" )
172 return toString( _ModulateGlobalColor
);
175 if( name
== "render_layer" )
177 return toString( _RenderLayer
);
180 if( name
== "avoid_resize_parent" )
182 return toString( _AvoidResizeParent
);
186 nlwarning( "Invalid property '%s' queried for widget '%s'", name
.c_str(), _Id
.c_str() );
191 void CInterfaceElement::setProperty( const std::string
&name
, const std::string
&value
)
195 setIdRecurse( stripId( value
) );
199 if( name
== "active" )
202 if( fromString( value
, b
) )
210 if( fromString( value
, x
) )
218 if( fromString( value
, y
) )
226 if( fromString( value
, w
) )
234 if( fromString( value
, h
) )
239 if( name
== "posref" )
241 _PosRef
= convertHotSpot( value
.c_str() );
245 if( name
== "parentposref" )
247 _ParentPosRef
= convertHotSpot( value
.c_str() );
250 if( name
== "sizeref" )
252 parseSizeRef( value
.c_str() );
255 if( name
== "posparent" )
257 setPosParent( value
);
261 if( name
== "sizeparent" )
263 setSizeParent( value
);
267 if( name
== "global_color" )
270 if( fromString( value
, b
) )
271 setModulateGlobalColor( b
);
275 if( name
== "render_layer" )
278 if( fromString( value
, l
) )
283 if( name
== "avoid_resize_parent" )
286 if( fromString( value
, b
) )
287 setAvoidResizeParent( b
);
291 nlwarning( "Tried to set invalid property '%s' for widget '%s'", name
.c_str(), _Id
.c_str() );
294 xmlNodePtr
CInterfaceElement::serialize( xmlNodePtr parentNode
, const char *type
) const
296 xmlNodePtr node
= xmlNewNode( NULL
, BAD_CAST type
);
300 xmlAddChild( parentNode
, node
);
302 xmlNewProp( node
, BAD_CAST
"id", BAD_CAST
stripId( getId() ).c_str() );
303 xmlNewProp( node
, BAD_CAST
"active", BAD_CAST
toString( _Active
).c_str() );
304 xmlNewProp( node
, BAD_CAST
"x", BAD_CAST
toString( _X
).c_str() );
305 xmlNewProp( node
, BAD_CAST
"y", BAD_CAST
toString( _Y
).c_str() );
306 xmlNewProp( node
, BAD_CAST
"w", BAD_CAST
toString( _W
).c_str() );
307 xmlNewProp( node
, BAD_CAST
"h", BAD_CAST
toString( _H
).c_str() );
308 xmlNewProp( node
, BAD_CAST
"posref", BAD_CAST
HotSpotCoupleToString( _ParentPosRef
, _PosRef
).c_str() );
312 xmlNewProp( node
, BAD_CAST
"posparent", BAD_CAST pp
.c_str() );
313 xmlNewProp( node
, BAD_CAST
"sizeref", BAD_CAST
getSizeRefAsString().c_str() );
315 xmlNewProp( node
, BAD_CAST
"sizeparent", BAD_CAST pp
.c_str() );
317 xmlNewProp( node
, BAD_CAST
"global_color", BAD_CAST
toString( _ModulateGlobalColor
).c_str() );
318 xmlNewProp( node
, BAD_CAST
"render_layer", BAD_CAST
toString( _RenderLayer
).c_str() );
319 xmlNewProp( node
, BAD_CAST
"avoid_resize_parent", BAD_CAST
toString( _AvoidResizeParent
).c_str() );
324 // ------------------------------------------------------------------------------------------------
325 bool CInterfaceElement::parse(xmlNodePtr cur
, CInterfaceGroup
* parentGroup
)
327 // parse the basic properties
328 CXMLAutoPtr
ptr((const char*) xmlGetProp( cur
, (xmlChar
*)"id" ));
333 _Id
= ( (CInterfaceElement
*)parentGroup
)->_Id
;
339 _Id
+= ":"+ string((const char*)ptr
);
343 nlinfo(" error no id in an element");
347 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"active" );
351 _Active
= convertBool(ptr
);
354 _Parent
= parentGroup
;
356 // parse location. If these properties are not specified, set them to 0
357 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"x" );
359 if (ptr
) fromString((const char*)ptr
, _X
);
361 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"y" );
363 if (ptr
) fromString((const char*)ptr
, _Y
);
365 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"w" );
367 if (parentGroup
!= NULL
)
368 _W
= parentGroup
->getW();
369 if (ptr
) fromString((const char*)ptr
, _W
);
371 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"h" );
373 if (parentGroup
!= NULL
)
374 _H
= parentGroup
->getH();
375 if (ptr
) fromString((const char*)ptr
, _H
);
378 // ptr = (char*) xmlGetProp( cur, (xmlChar*)"snap" );
381 // fromString((const char*)ptr, _Snap);
384 // parseError(parentGroup, "snap must be > 0" );
388 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*) "posref" );
389 _ParentPosRef
= Hotspot_BL
;
390 _PosRef
= Hotspot_BL
;
393 convertHotSpotCouple(ptr
.getDatas(), _ParentPosRef
, _PosRef
);
396 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"posparent" );
399 parsePosParent( (const char*)ptr
);
402 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"sizeparent" );
405 parseSizeParent( (const char*)ptr
);
408 ptr
= (char*) xmlGetProp (cur
, (xmlChar
*)"sizeref");
414 parseSizeRef(ptr
.getDatas());
419 ptr
= (char*) xmlGetProp (cur
, (xmlChar
*)"global_color");
422 _ModulateGlobalColor
= convertBool(ptr
);
425 ptr
= (char*) xmlGetProp (cur
, (xmlChar
*)"render_layer");
426 if(ptr
) fromString((const char*)ptr
, _RenderLayer
);
428 ptr
= (char*) xmlGetProp (cur
, (xmlChar
*)"avoid_resize_parent");
429 if(ptr
) _AvoidResizeParent
= convertBool(ptr
);
435 // ------------------------------------------------------------------------------------------------
436 void CInterfaceElement::setSizeRef(const std::string
&sizeref
)
438 parseSizeRef(sizeref
.c_str());
441 // ------------------------------------------------------------------------------------------------
442 std::string
CInterfaceElement::getSizeRefAsString() const
444 return getSizeRefAsString( _SizeRef
, _SizeDivW
, _SizeDivH
);
447 std::string
CInterfaceElement::getSizeRefAsString( const sint32
&sizeRef
, const sint32
&sizeDivW
, sint32
const &sizeDivH
) const
450 if( ( sizeRef
& 1 ) != 0 )
454 s
+= toString( sizeDivW
);
457 if( ( _SizeRef
& 2 ) != 0 )
461 s
+= toString( sizeDivH
);
467 // ------------------------------------------------------------------------------------------------
468 void CInterfaceElement::parseSizeRef(const char *sizeRefStr
)
470 parseSizeRef(sizeRefStr
, _SizeRef
, _SizeDivW
, _SizeDivH
);
474 // ------------------------------------------------------------------------------------------------
475 void CInterfaceElement::parseSizeRef(const char *sizeRefStr
, sint32
&sizeRef
, sint32
&sizeDivW
, sint32
&sizeDivH
)
477 nlassert(sizeRefStr
);
483 const char *seekPtr
= sizeRefStr
;
484 while (*seekPtr
!= 0)
486 if ((*seekPtr
=='w')||(*seekPtr
=='W'))
492 if ((*seekPtr
=='h')||(*seekPtr
=='H'))
498 if ((*seekPtr
>='1')&&(*seekPtr
<='9'))
503 sizeDivW
= *seekPtr
-'0';
505 sizeDivH
= *seekPtr
-'0';
513 // ------------------------------------------------------------------------------------------------
514 sint32
CInterfaceElement::getInnerWidth() const
516 return _WReal
- _MarginLeft
;
519 // ------------------------------------------------------------------------------------------------
520 void CInterfaceElement::updateCoords()
527 CInterfaceElement
*el
= NULL
;
531 if (_ParentPos
!= NULL
)
539 _XReal
+= el
->_XReal
;
540 _YReal
+= el
->_YReal
;
542 THotSpot hsParent
= _ParentPosRef
;
543 if (hsParent
& Hotspot_Mx
)
544 _YReal
+= el
->_HReal
/2;
545 if (hsParent
& Hotspot_Tx
)
546 _YReal
+= el
->_HReal
;
547 if (hsParent
& Hotspot_xM
)
548 _XReal
+= el
->_WReal
/2;
549 if (hsParent
& Hotspot_xR
)
550 _XReal
+= el
->_WReal
;
554 if (_ParentSize
!= NULL
)
560 if (_ParentPos
!= NULL
)
570 _WReal
+= _SizeDivW
* el
->_WReal
/ 10;
573 _HReal
+= _SizeDivH
* el
->_HReal
/ 10;
575 THotSpot hs
= _PosRef
;
587 // ------------------------------------------------------------------------------------------------
588 void CInterfaceElement::getCorner(sint32
&px
, sint32
&py
, THotSpot hs
)
592 if (hs
& 1) px
+= _WReal
;
593 if (hs
& 2) px
+= _WReal
>> 1;
594 if (hs
& 8) py
+= _HReal
;
595 if (hs
& 16) py
+= _HReal
>> 1;
598 // ------------------------------------------------------------------------------------------------
599 void CInterfaceElement::move (sint32 dx
, sint32 dy
)
608 // ------------------------------------------------------------------------------------------------
609 /*void CInterfaceElement::resizeBR (sint32 sizeW, sint32 sizeH)
612 THotSpot hs = _PosRef;
614 sint32 dw = sizeW - _W;
615 sint32 dh = sizeH - _H;
620 if (hs&8) // is top ?
622 sint32 newH = dh + _H;
627 if (hs&32) // is bottom ?
629 sint32 newH = dh + _H;
636 if (hs&1) // is right ?
638 sint32 newW = dw + _W;
644 if (hs&4) // is left ?
646 sint32 newW = dw + _W;
652 // DO NOT TREAT THE MIDDLE HOTSPOT CASE
658 // ------------------------------------------------------------------------------------------------
659 /*void CInterfaceElement::snapSize()
665 _W = _W - (_W % snap);
666 _H = _H - (_H % snap);
671 // ------------------------------------------------------------------------------------------------
672 void CInterfaceElement::setW (sint32 w
)
675 // sint32 snap = _Snap;
676 // nlassert(snap > 0);
679 // _W = _W - (_W % snap);
684 // ------------------------------------------------------------------------------------------------
685 void CInterfaceElement::setH (sint32 h
)
688 // sint32 snap = _Snap;
689 // nlassert(snap > 0);
692 // _H = _H - (_H % snap);
697 // ------------------------------------------------------------------------------------------------
698 CInterfaceGroup
* CInterfaceElement::getRootWindow ()
702 if (_Parent
->getParent() == NULL
)
703 return dynamic_cast<CInterfaceGroup
*>(this);
704 return _Parent
->getRootWindow();
707 // ------------------------------------------------------------------------------------------------
708 uint
CInterfaceElement::getParentDepth() const
711 CInterfaceGroup
*parent
= _Parent
;
714 parent
= parent
->getParent();
720 // ------------------------------------------------------------------------------------------------
721 bool CInterfaceElement::isActiveThroughParents() const
727 // is it the root window?
728 if (_Parent
->getParent() == NULL
)
729 // yes and getActive() is true => the element is visible!
732 return _Parent
->isActiveThroughParents();
735 // ------------------------------------------------------------------------------------------------
736 void CInterfaceElement::relativeSInt64Read (CInterfaceProperty
&rIP
, const string
&prop
, const char *val
,
737 const string
&defVal
)
741 rIP
.readSInt64 (defVal
.c_str(), _Id
+":"+prop
);
745 if ( isdigit(*val
) || *val
=='-')
747 rIP
.readSInt64 (val
, _Id
+":"+prop
);
754 if (NLGUI::CDBManager::getInstance()->getDbProp(val
+decal
, false) != NULL
)
756 rIP
.readSInt64 (val
+decal
, _Id
+":"+prop
);
762 CInterfaceElement
*pIEL
= this;
766 sTmp
= pIEL
->getId()+":"+string(val
+decal
);
767 if (NLGUI::CDBManager::getInstance()->getDbProp(sTmp
, false) != NULL
)
769 rIP
.readSInt64 (sTmp
.c_str(), _Id
+":"+prop
);
772 pIEL
= pIEL
->getParent();
775 rIP
.readSInt64 (val
+decal
, _Id
+":"+prop
);
781 // ------------------------------------------------------------------------------------------------
782 void CInterfaceElement::relativeSInt32Read (CInterfaceProperty
&rIP
, const string
&prop
, const char *val
,
783 const string
&defVal
)
787 rIP
.readSInt32 (defVal
.c_str(), _Id
+":"+prop
);
791 if ( isdigit(*val
) || *val
=='-')
793 rIP
.readSInt32 (val
, _Id
+":"+prop
);
800 if (NLGUI::CDBManager::getInstance()->getDbProp(val
+decal
, false) != NULL
)
802 rIP
.readSInt32 (val
+decal
, _Id
+":"+prop
);
808 CInterfaceElement
*pIEL
= this;
812 sTmp
= pIEL
->getId()+":"+string(val
+decal
);
813 if (NLGUI::CDBManager::getInstance()->getDbProp(sTmp
, false) != NULL
)
815 rIP
.readSInt32 (sTmp
.c_str(), _Id
+":"+prop
);
818 pIEL
= pIEL
->getParent();
821 rIP
.readSInt32 (val
+decal
, _Id
+":"+prop
);
827 // ------------------------------------------------------------------------------------------------
828 void CInterfaceElement::relativeBoolRead (CInterfaceProperty
&rIP
, const string
&prop
, const char *val
,
829 const string
&defVal
)
833 rIP
.readBool (defVal
.c_str(), _Id
+":"+prop
);
840 if (NLGUI::CDBManager::getInstance()->getDbProp(val
+decal
, false) != NULL
)
842 rIP
.readBool (val
+decal
, _Id
+":"+prop
);
848 CInterfaceElement
*pIEL
= this;
852 sTmp
= pIEL
->getId()+":"+string(val
+decal
);
853 if (NLGUI::CDBManager::getInstance()->getDbProp(sTmp
, false) != NULL
)
855 rIP
.readBool (sTmp
.c_str(), _Id
+":"+prop
);
858 pIEL
= pIEL
->getParent();
861 rIP
.readBool (val
+decal
, _Id
+":"+prop
);
867 // ------------------------------------------------------------------------------------------------
868 void CInterfaceElement::relativeRGBARead(CInterfaceProperty
&rIP
,const std::string
&prop
,const char *val
,const std::string
&defVal
)
872 rIP
.readRGBA (defVal
.c_str(), _Id
+":"+prop
);
876 if ( isdigit(*val
) || *val
=='-')
878 rIP
.readRGBA (val
, _Id
+":"+prop
);
885 if (NLGUI::CDBManager::getInstance()->getDbProp(val
+decal
, false) != NULL
)
887 rIP
.readRGBA (val
+decal
, _Id
+":"+prop
);
893 CInterfaceElement
*pIEL
= this;
897 sTmp
= pIEL
->getId()+":"+string(val
+decal
);
898 if (NLGUI::CDBManager::getInstance()->getDbProp(sTmp
, false) != NULL
)
900 rIP
.readRGBA (sTmp
.c_str(), _Id
+":"+prop
);
903 pIEL
= pIEL
->getParent();
906 rIP
.readRGBA (val
+decal
, _Id
+":"+prop
);
911 std::string
CInterfaceElement::HotSpotToString( THotSpot spot
)
949 std::string
CInterfaceElement::HotSpotCoupleToString( THotSpot parentPosRef
, THotSpot posRef
)
952 hs
= HotSpotToString( parentPosRef
);
954 hs
+= HotSpotToString( posRef
);
959 // ------------------------------------------------------------------------------------------------
960 THotSpot
CInterfaceElement::convertHotSpot (const char *ptr
)
962 if ( !strnicmp(ptr
,"TL",2) )
966 else if ( !strnicmp(ptr
,"TM",2) )
970 else if ( !strnicmp(ptr
,"TR",2) )
974 else if ( !strnicmp(ptr
,"ML",2) )
978 else if ( !strnicmp(ptr
,"MM",2) )
982 else if ( !strnicmp(ptr
,"MR",2) )
986 else if ( !strnicmp(ptr
,"BL",2) )
990 else if ( !strnicmp(ptr
,"BM",2) )
994 else if ( !strnicmp(ptr
,"BR",2) )
1002 // ------------------------------------------------------------------------------------------------
1003 void CInterfaceElement::convertHotSpotCouple (const char *ptr
, THotSpot
&parentPosRef
, THotSpot
&posRef
)
1007 // *** first hotspot
1008 // skip any space or tab
1009 while(*ptr
=='\t' || *ptr
==' ')
1012 parentPosRef
= convertHotSpot (ptr
);
1014 // *** second hotspot
1015 // must be at least 2 letter and a space
1016 nlassert(strlen(ptr
)>=3);
1018 // skip any space or tab
1019 while(*ptr
=='\t' || *ptr
==' ')
1022 posRef
= convertHotSpot (ptr
);
1025 // ------------------------------------------------------------------------------------------------
1026 NLMISC::CRGBA
CInterfaceElement::convertColor (const char *ptr
)
1028 return NLMISC::CRGBA::stringToRGBA(ptr
);
1031 // ------------------------------------------------------------------------------------------------
1032 bool CInterfaceElement::convertBool (const char *ptr
)
1034 return NLMISC::toBool(ptr
);
1037 // ------------------------------------------------------------------------------------------------
1038 NLMISC::CVector
CInterfaceElement::convertVector (const char *ptr
)
1040 float x
= 0.0f
, y
= 0.0f
, z
= 0.0f
;
1041 sscanf (ptr
, "%f %f %f", &x
, &y
, &z
);
1042 return CVector(x
,y
,z
);
1045 // ------------------------------------------------------------------------------------------------
1046 void CInterfaceElement::convertPixelsOrRatio(const char *ptr
, sint32
&pixels
, float &ratio
)
1048 std::string value
= ptr
;
1051 if (value
[value
.size() - 1] == '%')
1053 value
.resize(value
.size() - 1);
1054 fromString(value
, ratio
);
1056 clamp(ratio
, 0.f
, 1.f
);
1060 fromString(value
, pixels
);
1066 // ------------------------------------------------------------------------------------------------
1067 void CInterfaceElement::addLink(CInterfaceLink
*link
)
1069 nlassert(link
!= NULL
);
1072 _Links
= new TLinkVect
;
1074 TLinkSmartPtr
linkPtr(link
);
1075 TLinkVect::const_iterator it
= std::find(_Links
->begin(), _Links
->end(), linkPtr
);
1076 if (it
!= _Links
->end())
1078 // Link already appened : this can be the case when a link has several targets property that belong to the same element, in this case, one single ptr in the vector is enough.
1079 // nlwarning("Link added twice");
1083 _Links
->push_back(linkPtr
);
1088 // ------------------------------------------------------------------------------------------------
1089 void CInterfaceElement::removeLink(CInterfaceLink
*link
)
1091 nlassert(link
!= NULL
);
1094 nlwarning("No link added");
1097 TLinkVect::iterator it
= std::find(_Links
->begin(), _Links
->end(), TLinkSmartPtr(link
));
1098 if (it
== _Links
->end())
1100 nlwarning("Unknown link");
1103 _Links
->erase(it
); // kill the smart ptr, maybe deleting the link.
1104 if (_Links
->empty())
1112 // ------------------------------------------------------------------------------------------------
1113 CInterfaceElement
* CInterfaceElement::getMasterGroup() const
1115 if(getParent()==NULL
)
1116 return const_cast<CInterfaceElement
*>(this);
1118 return getParent()->getMasterGroup();
1121 // ------------------------------------------------------------------------------------------------
1122 CInterfaceGroup
* CInterfaceElement::getParentContainer()
1124 CInterfaceElement
*parent
= this;
1127 CInterfaceGroup
*gc
= dynamic_cast< CInterfaceGroup
* >( parent
);
1128 if( ( gc
!= NULL
) && gc
->isGroupContainer() )
1131 parent
= parent
->getParent();
1136 // ------------------------------------------------------------------------------------------------
1137 bool CInterfaceElement::isIn(sint x
, sint y
) const
1139 return (x
>= _XReal
) &&
1140 (x
< (_XReal
+ _WReal
))&&
1142 (y
<= (_YReal
+ _HReal
));
1145 // ------------------------------------------------------------------------------------------------
1146 bool CInterfaceElement::isIn(sint x
, sint y
, uint width
, uint height
) const
1148 return (x
+ (sint
) width
) >= _XReal
&&
1149 (y
+ (sint
) height
) > _YReal
&&
1150 x
< (_XReal
+ _WReal
) &&
1151 y
<= (_YReal
+ _HReal
);
1154 // ------------------------------------------------------------------------------------------------
1155 bool CInterfaceElement::isIn(const CInterfaceElement
&other
) const
1157 return isIn(other
._XReal
, other
._YReal
, other
._WReal
, other
._HReal
);
1160 // ------------------------------------------------------------------------------------------------
1161 void CInterfaceElement::setActive (bool state
)
1163 if (_Active
!= state
)
1167 // force invalidate CViewText/CGroupTable inner elements
1168 invalidateContent();
1173 // ***************************************************************************
1174 void CInterfaceElement::invalidateCoords(uint8 numPass
)
1176 // Get the "Root Group" ie the 1st son of the master group of us (eg "ui:interface:rootgroup" )
1177 CInterfaceGroup
*parent
= getParent();
1178 // if our parent is NULL, then we are the master group (error!)
1181 // if our grandfather is NULL, then our father is the Master Group => we are the "Root group"
1182 if(parent
->getParent()==NULL
)
1184 parent
= dynamic_cast<CInterfaceGroup
*>(this);
1188 // parent is the root group when is grandFather is NULL
1189 while( parent
->getParent()->getParent()!=NULL
)
1191 parent
= parent
->getParent();
1195 // invalidate the "root group"
1198 uint8
&val
= static_cast<CInterfaceElement
*>(parent
)->_InvalidCoords
;
1199 val
= max(val
, numPass
);
1204 // ***************************************************************************
1205 void CInterfaceElement::checkCoords()
1209 // ***************************************************************************
1210 bool CInterfaceElement::isSonOf(const CInterfaceElement
*other
) const
1212 const CInterfaceElement
*currElem
= this;
1215 if (currElem
== other
) return true;
1216 currElem
= currElem
->_Parent
;
1222 // ***************************************************************************
1223 void CInterfaceElement::resetInvalidCoords()
1228 // ***************************************************************************
1229 void CInterfaceElement::updateAllLinks()
1233 for(TLinkVect::iterator it
= _Links
->begin(); it
!= _Links
->end(); ++it
)
1240 // ***************************************************************************
1241 void CInterfaceElement::copyOptionFrom(const CInterfaceElement
&other
)
1243 _Active
= other
._Active
;
1244 _InvalidCoords
= other
._InvalidCoords
;
1245 _XReal
= other
._XReal
;
1246 _YReal
= other
._YReal
;
1247 _WReal
= other
._WReal
;
1248 _HReal
= other
._HReal
;
1251 _XReal
= other
._XReal
;
1252 _YReal
= other
._YReal
;
1253 _PosRef
= other
._PosRef
;
1254 _ParentPosRef
= other
._ParentPosRef
;
1255 _SizeRef
= other
._SizeRef
;
1256 _SizeDivW
= other
._SizeDivW
;
1257 _SizeDivH
= other
._SizeDivH
;
1258 _ModulateGlobalColor
= other
._ModulateGlobalColor
;
1259 _RenderLayer
= other
._RenderLayer
;
1263 // ***************************************************************************
1264 void CInterfaceElement::center()
1267 CViewRenderer
&vr
= *CViewRenderer::getInstance();
1269 vr
.getScreenSize(sw
, sh
);
1270 setX(sw
/ 2 - getWReal() / 2);
1271 setY(sh
/ 2 + getHReal() / 2);
1274 // ***************************************************************************
1275 void CInterfaceElement::renderWiredQuads(TRenderWired type
, const std::string
&uiFilter
)
1277 CCtrlBase
*ctrlBase
= dynamic_cast<CCtrlBase
*>(this);
1278 CInterfaceGroup
*groupBase
= dynamic_cast<CInterfaceGroup
*>(this);
1280 ((type
== RenderView
) && (ctrlBase
==NULL
) && (groupBase
==NULL
)) ||
1281 ((type
== RenderCtrl
) && (ctrlBase
!=NULL
) && (groupBase
==NULL
)) ||
1282 ((type
== RenderGroup
) && (ctrlBase
!=NULL
) && (groupBase
!=NULL
)))
1284 if (!_Active
) return;
1285 // if there is an uiFilter, the end of _Id must match it
1286 if (!uiFilter
.empty() && (uiFilter
.size()>_Id
.size() ||
1287 _Id
.compare(_Id
.size()-uiFilter
.size(),string::npos
,uiFilter
)!=0)
1290 CViewRenderer
&vr
= *CViewRenderer::getInstance();
1291 vr
.drawWiredQuad(_XReal
, _YReal
, _WReal
, _HReal
);
1292 drawHotSpot(_PosRef
, CRGBA::Red
);
1293 if (_Parent
) _Parent
->drawHotSpot(_ParentPosRef
, CRGBA::Blue
);
1297 // ***************************************************************************
1298 void CInterfaceElement::drawHotSpot(THotSpot hs
, CRGBA col
)
1300 const sint32 radius
= 2;
1303 if (hs
& Hotspot_Bx
)
1305 py
= _YReal
+ radius
;
1307 else if (hs
& Hotspot_Mx
)
1309 py
= _YReal
+ _HReal
/ 2;
1313 py
= _YReal
+ _HReal
- radius
;
1316 if (hs
& Hotspot_xL
)
1318 px
= _XReal
+ radius
;
1320 else if (hs
& Hotspot_xM
)
1322 px
= _XReal
+ _WReal
/ 2;
1326 px
= _XReal
+ _WReal
- radius
;
1328 CViewRenderer
&vr
= *CViewRenderer::getInstance();
1329 vr
.drawFilledQuad(px
- radius
, py
- radius
, radius
* 2, radius
* 2, col
);
1333 void CInterfaceElement::drawHighlight()
1335 CViewRenderer::getInstance()->drawWiredQuad( _XReal
, _YReal
, _WReal
, _HReal
);
1338 // ***************************************************************************
1339 void CInterfaceElement::invalidateContent()
1341 CInterfaceElement
*elm
= this;
1345 elm
->onInvalidateContent();
1348 elm
= elm
->getParent();
1352 // ***************************************************************************
1353 void CInterfaceElement::visit(CInterfaceElementVisitor
*visitor
)
1356 visitor
->visit(this);
1359 // ***************************************************************************
1360 void CInterfaceElement::serialConfig(NLMISC::IStream
&f
)
1364 throw NLMISC::ENewerStream(f
);
1369 // ***************************************************************************
1370 void CInterfaceElement::onFrameUpdateWindowPos(sint dx
, sint dy
)
1376 // ***************************************************************************
1377 void CInterfaceElement::dummySet(sint32
/* value */)
1379 nlwarning("Element can't be written.");
1382 // ***************************************************************************
1383 void CInterfaceElement::dummySet(const std::string
&/* value */)
1385 nlwarning("Element can't be written.");
1388 // ***************************************************************************
1389 int CInterfaceElement::luaUpdateCoords(CLuaState
&ls
)
1391 CLuaIHM::checkArgCount(ls
, "updateCoords", 0);
1396 // ***************************************************************************
1397 int CInterfaceElement::luaInvalidateCoords(CLuaState
&ls
)
1399 CLuaIHM::checkArgCount(ls
, "updateCoords", 0);
1404 // ***************************************************************************
1405 int CInterfaceElement::luaInvalidateContent(CLuaState
&ls
)
1407 CLuaIHM::checkArgCount(ls
, "invalidateContent", 0);
1408 invalidateContent();
1412 // ***************************************************************************
1413 int CInterfaceElement::luaCenter(CLuaState
&ls
)
1415 CLuaIHM::checkArgCount(ls
, "center", 0);
1420 // ***************************************************************************
1421 int CInterfaceElement::luaSetPosRef(CLuaState
&ls
)
1423 CLuaIHM::checkArgCount(ls
, "setPosRef", 1);
1424 CLuaIHM::check(ls
, ls
.isString(1), "setPosRef() requires a string in param 1");
1427 THotSpot newParentPosRef
, newPosRef
;
1428 convertHotSpotCouple(ls
.toString(1), newParentPosRef
, newPosRef
);
1430 // if different from current, set,a nd invalidate coords
1431 if(newParentPosRef
!=getParentPosRef() || newPosRef
!=getPosRef())
1433 setParentPosRef(newParentPosRef
);
1434 setPosRef(newPosRef
);
1441 // ***************************************************************************
1442 int CInterfaceElement::luaSetParentPos(CLuaState
&ls
)
1444 CLuaIHM::checkArgCount(ls
, "setParentPos", 1);
1445 CInterfaceElement
*ie
= CLuaIHM::getUIOnStack(ls
, 1);
1455 // ***************************************************************************
1456 CInterfaceElement
*CInterfaceElement::clone()
1458 NLMISC::CMemStream dupStream
;
1459 nlassert(!dupStream
.isReading());
1460 CInterfaceGroup
*oldParent
= _Parent
;
1462 CInterfaceElement
*oldParentPos
= _ParentPos
;
1463 CInterfaceElement
*oldParentSize
= _ParentSize
;
1464 if (_ParentPos
== oldParent
) _ParentPos
= NULL
;
1465 if (_ParentSize
== oldParent
) _ParentSize
= NULL
;
1466 CInterfaceElement
*begunThisCloneWarHas
= NULL
;
1469 if (dupStream
.isReading())
1473 CInterfaceElement
*self
= this;
1474 dupStream
.serialPolyPtr(self
);
1475 std::vector
<uint8
> datas(dupStream
.length());
1476 std::copy(dupStream
.buffer(), dupStream
.buffer() + dupStream
.length(), datas
.begin());
1477 dupStream
.resetPtrTable();
1479 dupStream
.fill(&datas
[0], (uint32
)datas
.size());
1480 dupStream
.serialPolyPtr(begunThisCloneWarHas
);
1482 catch(const NLMISC::EStream
&)
1484 // no-op -> caller has to handle the failure because NULL will be returned
1487 _Parent
= oldParent
;
1488 _ParentPos
= oldParentPos
;
1489 _ParentSize
= oldParentSize
;
1491 return begunThisCloneWarHas
;
1494 // ***************************************************************************
1495 void CInterfaceElement::serial(NLMISC::IStream
&f
)
1497 f
.serialPolyPtr(_Parent
);
1500 f
.serial(_InvalidCoords
);
1501 f
.serial(_XReal
, _YReal
, _WReal
, _HReal
);
1502 f
.serial(_X
, _Y
, _W
, _H
);
1503 f
.serialEnum(_PosRef
);
1504 f
.serialEnum(_ParentPosRef
);
1505 _ParentPos
.serialPolyPtr(f
);
1507 f
.serial(_SizeDivW
, _SizeDivH
);
1508 _ParentSize
.serialPolyPtr(f
);
1509 f
.serial(_ModulateGlobalColor
);
1510 f
.serial(_RenderLayer
);
1511 f
.serial(_AvoidResizeParent
);
1512 nlassert(_Links
== NULL
); // not supported
1516 // ***************************************************************************
1517 void CInterfaceElement::serialAH(NLMISC::IStream
&f
, IActionHandler
*&ah
)
1523 ah
= CAHManager::getInstance()->getActionHandler(ahName
);
1527 ahName
= CAHManager::getInstance()->getActionHandlerName(ah
);
1533 bool CInterfaceElement::isInGroup( CInterfaceGroup
*group
)
1535 CInterfaceGroup
*parent
= getParent();
1536 while( parent
!= NULL
)
1538 if( parent
== group
)
1541 parent
= parent
->getParent();
1546 void CInterfaceElement::parsePosParent( const std::string
&id
)
1548 CInterfaceElement
*p
= getParent();
1550 if( ( id
== "parent" ) || ( id
.empty() ) )
1559 ppId
= p
->getId() + ":" + id
;
1561 ppId
= std::string( "ui:" ) + id
;
1563 CWidgetManager::getInstance()->getParser()->addParentPositionAssociation( this, ppId
);
1566 void CInterfaceElement::setPosParent( const std::string
&id
)
1568 // Parent or empty id simply means the group parent
1569 if( ( id
== "parent" ) || ( id
.empty() ) )
1571 setParentPos( getParent() );
1575 CInterfaceElement
*pp
= NULL
;
1577 // Check if it's a short Id
1578 std::string::size_type idx
= id
.find( "ui:" );
1579 if( idx
== std::string::npos
)
1581 // If it is, find the widget in the parent group and set as posparent
1582 CInterfaceGroup
*p
= getParent();
1585 pp
= p
->findFromShortId( id
);
1590 // If it is not, find using the widgetmanager
1591 // TODO: refactor, shouldn't use a singleton
1592 pp
= CWidgetManager::getInstance()->getElementFromId( id
);
1600 void CInterfaceElement::getPosParent( std::string
&id
) const
1603 // If there's no pos parent set, then the parent group is the pos parent
1604 if( getParentPos() == NULL
)
1610 // If pos parent and parent are the same then ofc the parent group is the pos parent...
1611 CInterfaceElement
*p
= getParent();
1612 if( getParentPos() == p
)
1618 // If parent is in the same group, use the short id
1620 if( p
->isInGroup( getParent() ) )
1622 id
= p
->getShortId();
1626 // Otherwise use the full id
1630 void CInterfaceElement::parseSizeParent( const std::string
&id
)
1632 CInterfaceElement
*p
= getParent();
1634 if( ( id
== "parent" ) || ( id
.empty() ) )
1643 spId
= p
->getId() + ":" + id
;
1645 spId
= std::string( "ui:" ) + id
;
1647 CWidgetManager::getInstance()->getParser()->addParentSizeAssociation( this, spId
);
1650 void CInterfaceElement::setSizeParent( const std::string
&id
)
1652 // Parent or empty id simply means the group parent
1653 if( ( id
== "parent" ) || ( id
.empty() ) )
1655 setParentSize( getParent() );
1659 CInterfaceElement
*pp
= NULL
;
1661 // Check if it's a short Id
1662 std::string::size_type idx
= id
.find( "ui:" );
1663 if( idx
== std::string::npos
)
1665 // If it is, find the widget in the parent group and set as posparent
1666 CInterfaceGroup
*p
= getParent();
1669 pp
= p
->findFromShortId( id
);
1674 // If it is not, find using the widgetmanager
1675 // TODO: refactor, shouldn't use a singleton
1676 pp
= CWidgetManager::getInstance()->getElementFromId( id
);
1680 setParentSize( pp
);
1683 void CInterfaceElement::getSizeParent( std::string
&id
) const
1685 CInterfaceElement
*p
= getParentSize();
1687 // If there's no parent set then the size parent is the parent
1694 // If the size parent is the same as the group parent, then the size parent is the parent ofc
1695 if( p
== getParent() )
1701 // If the size parent is in the parent group, use the short Id
1702 if( p
->isInGroup( getParent() ) )
1704 id
= p
->getShortId();
1708 // Otherwise use the full Id
1712 void CInterfaceElement::registerDeletionWatcher( IDeletionWatcher
*watcher
)
1714 std::vector
< IDeletionWatcher
* >::iterator itr
1715 = std::find( deletionWatchers
.begin(), deletionWatchers
.end(), watcher
);
1716 // Already registered
1717 if( itr
!= deletionWatchers
.end() )
1719 deletionWatchers
.push_back( watcher
);
1722 void CInterfaceElement::unregisterDeletionWatcher( IDeletionWatcher
*watcher
)
1724 std::vector
< IDeletionWatcher
* >::iterator itr
1725 = std::find( deletionWatchers
.begin(), deletionWatchers
.end(), watcher
);
1727 if( itr
== deletionWatchers
.end() )
1729 deletionWatchers
.erase( itr
);
1732 void CInterfaceElement::notifyDeletionWatchers()
1734 std::vector
< IDeletionWatcher
* >::iterator itr
= deletionWatchers
.begin();
1735 while( itr
!= deletionWatchers
.end() )
1737 (*itr
)->onDeleted( _Id
);
1742 void CInterfaceElement::getHSCoords( const THotSpot
&hs
, sint32
&x
, sint32
&y
) const
1747 if( ( hs
& Hotspot_Mx
) != 0 )
1750 if( ( hs
& Hotspot_Tx
) != 0 )
1754 if( ( hs
& Hotspot_xM
) != 0 )
1757 if( ( hs
& Hotspot_xR
) != 0 )
1761 void CInterfaceElement::getClosestHotSpot( const CInterfaceElement
*other
, THotSpot
&hs
)
1763 /// Iterate over the following hotspots, calculate the distance and store the closest
1766 static THotSpot hslist
[] =
1775 int c
= sizeof( hslist
) / sizeof( THotSpot
);
1777 int x
,y
,ox
,oy
,vx
,vy
;
1779 float closestd
= 9999999.0f
;
1780 THotSpot closestHS
= Hotspot_TR
;
1782 for( int i
= 0; i
< c
; i
++ )
1784 other
->getHSCoords( hslist
[ i
], ox
, oy
);
1785 getHSCoords( hslist
[ i
], x
, y
);
1787 // Make a vector between the two hotspots
1792 d
= sqrt( pow( vx
, 2.0f
) + pow( vy
, 2.0f
) );
1794 // If these hotspots are the closest, store the hotspot
1798 closestHS
= hslist
[ i
];
1805 void CInterfaceElement::alignTo( CInterfaceElement
*other
)
1810 // Check which hotspot is the closest
1812 other
->getClosestHotSpot( this, hs
);
1814 // Get the hotspot coordinates
1815 sint32 x
, y
, ox
, oy
;
1816 getHSCoords( hs
, x
, y
);
1817 other
->getHSCoords( hs
, ox
, oy
);
1819 // Calculate the difference between the hotspot we found and our current position,
1823 // This difference is our offset, so we remain in the same position
1828 setParentPosRef( hs
);
1833 void CInterfaceElement::onWidgetDeleted( CInterfaceElement
*e
)
1835 if( e
== getParentPos() )
1836 setParentPos( NULL
);
1837 if( e
== getParentSize() )
1838 setParentSize( NULL
);
1841 CStringMapper
* CStringShared::_UIStringMapper
= NULL
;
1844 void CStringShared::createStringMapper()
1846 if( _UIStringMapper
== NULL
)
1847 _UIStringMapper
= CStringMapper::createLocalMapper();
1850 void CStringShared::deleteStringMapper()
1852 delete _UIStringMapper
;