Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / gui / group_list.cpp
blob8f7336d280339a2c7712ddaea6c49c98b77691dd
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
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/>.
21 #include "stdpch.h"
22 #include "nel/gui/group_list.h"
24 #include "nel/gui/interface_element.h"
25 #include "nel/gui/view_bitmap.h"
26 #include "nel/gui/view_text_id.h"
27 #include "nel/gui/group_container_base.h"
28 #include "nel/gui/lua_ihm.h"
29 #include "nel/misc/xml_auto_ptr.h"
30 #include "nel/gui/widget_manager.h"
31 #include "nel/gui/view_pointer_base.h"
32 #include "nel/misc/i18n.h"
34 using namespace std;
35 using namespace NLMISC;
37 #ifdef DEBUG_NEW
38 #define new DEBUG_NEW
39 #endif
41 NLMISC_REGISTER_OBJECT(CViewBase, CGroupList, std::string, "list");
43 namespace NLGUI
46 // ----------------------------------------------------------------------------
47 CGroupList::CGroupList(const TCtorParam &param)
48 : CInterfaceGroup(param),
49 _Templ(TCtorParam())
51 _IdCounter = 0;
52 _MaxElements = 1024;
53 _AddElt = Bottom;
54 _Align = Left;
55 _Space = 0;
56 _DynamicDisplaySize = false;
57 _MinW= 0;
58 _MinH= 0;
59 _Over = false;
60 _OverColor = CRGBA(255, 255, 255, 32);
61 _OverElt = -1;
62 _IsGroupList = true;
63 _TextId = 0;
66 // ----------------------------------------------------------------------------
67 void CGroupList::addChild (CViewBase* child, bool deleteOnRemove)
69 if (!child)
71 nlwarning("<CGroupList::addChild> : tried to add a NULL view");
72 return;
75 // Make sure there's room for the element
76 if ((sint32)_Elements.size() == _MaxElements)
78 removeHead();
81 // add child at last index
82 addChildAtIndex(child, (uint)_Elements.size(), deleteOnRemove);
83 if (_Elements.size() >= 2)
85 setOrder((uint)_Elements.size() - 1, getOrder((uint)_Elements.size() - 2) + 1);
89 // ----------------------------------------------------------------------------
90 CGroupList::~CGroupList()
92 deleteAllChildren();
95 // ----------------------------------------------------------------------------
96 // Set Hotspot of the first element in reference to the group
97 void CGroupList::setHSGroup (CViewBase *child, EAlign addElt, EAlign align)
99 switch (addElt)
101 case Bottom:
102 if (align == Left)
104 child->_ParentPosRef = Hotspot_TL;
105 child->_PosRef = Hotspot_TL;
107 else // align == Right
109 child->_ParentPosRef = Hotspot_TR;
110 child->_PosRef = Hotspot_TR;
112 break;
113 case Left:
114 if (align == Top)
116 child->_ParentPosRef = Hotspot_TR;
117 child->_PosRef = Hotspot_TR;
119 else // align == Bottom
121 child->_ParentPosRef = Hotspot_BR;
122 child->_PosRef = Hotspot_BR;
124 break;
125 case Top:
126 if (align == Left)
128 child->_ParentPosRef = Hotspot_BL;
129 child->_PosRef = Hotspot_BL;
131 else // align == Right
133 child->_ParentPosRef = Hotspot_BR;
134 child->_PosRef = Hotspot_BR;
136 break;
137 case Right:
138 if (align == Top)
140 child->_ParentPosRef = Hotspot_TL;
141 child->_PosRef = Hotspot_TL;
143 else // align == Bottom
145 child->_ParentPosRef = Hotspot_BL;
146 child->_PosRef = Hotspot_BL;
148 break;
149 default:
150 nlassert(false);
151 break;
155 // ----------------------------------------------------------------------------
156 /** align an element towards its parent in the group
158 void CGroupList::setHSParent(CViewBase *view, EAlign addElt, EAlign /* align */, uint space)
160 if ((addElt == Top) || (addElt == Bottom))
162 if (addElt == Bottom)
164 if (_Align == Left)
165 view->_ParentPosRef = Hotspot_BL;
166 else // align == Right
167 view->_ParentPosRef = Hotspot_BR;
168 //view->_Y = -abs((sint32)space);
169 view->_Y = - (sint32)space;
171 else if (addElt == Top)
173 if (_Align == Left)
174 view->_ParentPosRef = Hotspot_TL;
175 else // align == Right
176 view->_ParentPosRef = Hotspot_TR;
177 // view->_Y = abs((sint32)space);
178 view->_Y = (sint32)space;
181 else
183 if (addElt == Left)
185 if (_Align == Top)
186 view->_ParentPosRef = Hotspot_TL;
187 else // align == Bottom
188 view->_ParentPosRef = Hotspot_BL;
189 //view->_X = -abs((sint32)space);
190 view->_X = -(sint32)space;
192 else if (addElt == Right)
194 if (_Align == Top)
195 view->_ParentPosRef = Hotspot_TR;
196 else // align == Bottom
197 view->_ParentPosRef = Hotspot_BR;
198 //view->_X = abs((sint32)space);
199 view->_X = (sint32)space;
204 std::string CGroupList::getProperty( const std::string &name ) const
206 if( name == "maxelements" )
208 return toString( _MaxElements );
211 if( name == "addelt" )
213 switch( _AddElt )
215 case Top:
216 return "T";
218 case Left:
219 return "L";
221 case Right:
222 return "R";
224 case Bottom:
225 return "B";
228 nlassert(false);
231 if( name == "align" )
233 switch( _Align )
235 case Top:
236 return "T";
238 case Left:
239 return "L";
241 case Right:
242 return "R";
244 case Bottom:
245 return "B";
248 nlassert(false);
251 if( name == "space" )
253 return toString( _Space );
256 if( name == "over" )
258 return toString( _Over );
261 if( name == "dynamic_display_size" )
263 return toString( _DynamicDisplaySize );
266 if( name == "col_over" )
268 return toString( _OverColor );
271 if( name == "hardtext" )
273 return _HardText;
276 if( name == "textid" )
278 return toString( _TextId );
281 return CInterfaceGroup::getProperty( name );
284 void CGroupList::setProperty( const std::string &name, const std::string &value )
286 if( name == "maxelements" )
288 sint32 i;
289 if( fromString( value, i ) )
290 _MaxElements = i;
291 return;
294 if( name == "addelt" )
296 if( value == "T" )
297 _AddElt = Top;
298 else
299 if( value == "L" )
300 _AddElt = Left;
301 else
302 if( value == "R" )
303 _AddElt = Right;
304 else
305 if( value == "B" )
306 _AddElt = Bottom;
308 setupSizes();
309 return;
312 if( name == "align" )
314 if( value == "T" )
315 _Align = Top;
316 else
317 if( value == "L" )
318 _Align = Left;
319 else
320 if( value == "R" )
321 _Align = Right;
322 else
323 if( value == "B" )
324 _Align = Bottom;
326 return;
329 if( name == "space" )
331 sint32 i;
332 if( fromString( value, i ) )
333 _Space = i;
334 return;
337 if( name == "over" )
339 bool b;
340 if( fromString( value, b ) )
341 _Over = b;
342 return;
345 if( name == "dynamic_display_size" )
347 bool b;
348 if( fromString( value, b ) )
349 _DynamicDisplaySize = b;
350 return;
353 if( name == "col_over" )
355 CRGBA c;
356 if( fromString( value, c ) )
357 _OverColor = c;
358 return;
361 if( name == "hardtext" )
363 _HardText = value;
364 _TextId = 0;
365 onTextChanged();
366 return;
369 if( name == "textid" )
371 uint32 i;
372 if( fromString( value, i ) )
373 _TextId = i;
374 _HardText.clear();
375 onTextChanged();
376 return;
379 CInterfaceGroup::setProperty( name, value );
383 xmlNodePtr CGroupList::serialize( xmlNodePtr parentNode, const char *type ) const
385 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
386 if( node == NULL )
387 return NULL;
389 xmlSetProp( node, BAD_CAST "type", BAD_CAST "list" );
390 xmlSetProp( node, BAD_CAST "maxelements", BAD_CAST toString( _MaxElements ).c_str() );
392 std::string addelt;
393 std::string align;
395 switch( _AddElt )
397 case Top:
398 addelt = "T";
399 break;
401 case Left:
402 addelt = "L";
403 break;
405 case Right:
406 addelt = "R";
407 break;
409 default:
410 addelt = "B";
411 break;
414 switch( _Align )
416 case Top:
417 align = "T";
418 break;
420 case Left:
421 align = "L";
422 break;
424 case Right:
425 align = "R";
426 break;
428 default:
429 align = "B";
430 break;
433 xmlSetProp( node, BAD_CAST "addelt", BAD_CAST addelt.c_str() );
434 xmlSetProp( node, BAD_CAST "align", BAD_CAST align.c_str() );
435 xmlSetProp( node, BAD_CAST "space", BAD_CAST toString( _Space ).c_str() );
436 xmlSetProp( node, BAD_CAST "over", BAD_CAST toString( _Over ).c_str() );
437 xmlSetProp( node, BAD_CAST "dynamic_display_size", BAD_CAST toString( _DynamicDisplaySize ).c_str() );
438 xmlSetProp( node, BAD_CAST "col_over", BAD_CAST toString( _OverColor ).c_str() );
439 xmlSetProp( node, BAD_CAST "hardtext", BAD_CAST _HardText.c_str() );
440 xmlSetProp( node, BAD_CAST "textid", BAD_CAST toString( _TextId ).c_str() );
442 return node;
445 // ----------------------------------------------------------------------------
446 bool CGroupList::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup)
448 if (!CInterfaceGroup::parse(cur, parentGroup))
449 return false;
451 // Parse location. If these properties are not specified, set them to 0
453 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"maxelements" ));
454 _MaxElements = 1024;
455 if (ptr)
457 if (!fromString((const char*)ptr, _MaxElements))
459 nlwarning("<CGroupList::parse> Can't parse the 'maxelements' field ");
463 ptr = (char*) xmlGetProp( cur, (xmlChar*)"addelt" );
464 _AddElt = Bottom;
465 if (ptr)
467 if (stricmp(ptr, "B") == 0)
468 _AddElt = Bottom;
469 else if (stricmp(ptr, "T") == 0)
470 _AddElt = Top;
471 else if (stricmp(ptr, "L") == 0)
472 _AddElt = Left;
473 else if (stricmp(ptr, "R") == 0)
474 _AddElt = Right;
477 ptr = (char*) xmlGetProp( cur, (xmlChar*)"align" );
478 _Align = Left;
479 if (ptr)
481 if (stricmp(ptr, "B") == 0)
482 _Align = Bottom;
483 else if (stricmp(ptr, "T") == 0)
484 _Align = Top;
485 else if (stricmp(ptr, "L") == 0)
486 _Align = Left;
487 else if (stricmp(ptr, "R") == 0)
488 _Align = Right;
491 ptr = (char*) xmlGetProp( cur, (xmlChar*)"space" );
492 _Space = 0;
493 if (ptr)
494 fromString((const char*)ptr, _Space);
496 setupSizes();
498 ptr = (char*) xmlGetProp( cur, (xmlChar*)"over" );
499 _Over = false;
500 if (ptr) _Over = convertBool(ptr);
502 ptr = (char*) xmlGetProp( cur, (xmlChar*)"dynamic_display_size" );
503 _DynamicDisplaySize = false;
504 if (ptr) _DynamicDisplaySize = convertBool(ptr);
506 ptr = (char*) xmlGetProp( cur, (xmlChar*)"col_over" );
507 _OverColor = CRGBA(255, 255, 255, 32);
508 if (ptr) _OverColor = convertColor(ptr);
511 // TEMPLATE TEXT SETUP
513 // justification parameters
514 _Templ.parseTextOptions (cur);
516 // initial text
517 ptr = (char*) xmlGetProp( cur, (xmlChar*)"hardtext" );
518 if (ptr)
520 _HardText = std::string( (const char*)ptr );
521 const char *propPtr = ptr;
522 if (NLMISC::startsWith(propPtr, "ui"))
523 addTextChild(CI18N::get(propPtr));
524 else
525 addTextChild(propPtr);
527 else
529 ptr = (char*) xmlGetProp( cur, (xmlChar*)"textid" );
530 if (ptr)
532 fromString((const char*)ptr, _TextId );
533 addTextChildID( _TextId );
537 return true;
542 // ----------------------------------------------------------------------------
543 void CGroupList::addTextChild(const std::string& line, bool multiLine /*= true*/)
545 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
546 CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
547 view->setSerializable( false );
548 view->_Parent = this;
549 view->setMultiLine (multiLine);
550 view->setTextMode(_Templ.getTextMode());
551 if (multiLine) view->setMultiLineSpace (_Space);
552 view->setText (line);
553 // Herit global-coloring
554 view->setModulateGlobalColor(getModulateGlobalColor());
555 addChild(view);
556 invalidateCoords();
561 // ----------------------------------------------------------------------------
562 void CGroupList::addTextChild(const std::string& line, const CRGBA& textColor, bool multiLine /*= true*/)
564 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
565 CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
566 view->setSerializable( false );
567 view->_Parent = this;
568 view->setMultiLine (multiLine);
569 if (multiLine) view->setMultiLineSpace (_Space);
570 view->setText (line);
571 view->setColor (textColor);
572 // Herit global-coloring
573 view->setModulateGlobalColor(getModulateGlobalColor());
574 addChild(view);
575 invalidateCoords();
578 // ----------------------------------------------------------------------------
579 void CGroupList::addTextChildID (uint32 nID, bool multiLine)
581 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
582 CViewTextID *view= new CViewTextID (elid, nID, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
583 view->setSerializable( false );
584 view->_Parent = this;
585 view->setMultiLine (multiLine);
586 if (multiLine) view->setMultiLineSpace (_Space);
587 // Herit global-coloring
588 view->setModulateGlobalColor(getModulateGlobalColor());
589 addChild (view);
590 invalidateCoords();
593 // ----------------------------------------------------------------------------
594 void CGroupList::addTextChildID(const std::string &dbPath, bool multiLine /*=true*/)
596 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
597 CViewTextID *view= new CViewTextID (elid, dbPath, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
598 view->setSerializable( false );
599 view->_Parent = this;
600 view->setMultiLine (multiLine);
601 if (multiLine) view->setMultiLineSpace (_Space);
602 // Herit global-coloring
603 view->setModulateGlobalColor(getModulateGlobalColor());
604 addChild (view);
605 invalidateCoords();
608 // ----------------------------------------------------------------------------
609 bool CGroupList::delChild (CViewBase* childToDel, bool noWarning, bool forceDontDelete)
611 // Look for child
612 uint posChildToDel = 0;
613 for (posChildToDel = 0; posChildToDel < _Elements.size(); ++posChildToDel)
615 CElementInfo rEI = _Elements[posChildToDel];
616 if (rEI.Element == childToDel)
617 break;
620 if (posChildToDel == _Elements.size())
622 if (!noWarning)
623 nlwarning("Can't del child %s, it does not exist in the list", childToDel->getId().c_str());
624 return false;
626 return delChild(posChildToDel, forceDontDelete);
629 // ----------------------------------------------------------------------------
630 bool CGroupList::delChild(uint posChildToDel, bool forceDontDelete)
632 if (posChildToDel >= (uint) _Elements.size())
634 nlwarning("<CGroupList::delChild> bad index");
635 return false;
638 CViewBase* childToDel = _Elements[posChildToDel].Element;
640 childToDel->_Parent = NULL;
642 bool elementMustBeDeleted = _Elements[posChildToDel].EltDeleteOnRemove && !forceDontDelete;
643 _Elements.erase (_Elements.begin()+posChildToDel);
644 // Remove from drawing
645 if (dynamic_cast<CInterfaceGroup *>(childToDel)) delGroup(static_cast<CInterfaceGroup *>(childToDel), !elementMustBeDeleted);
646 else if (dynamic_cast<CCtrlBase *>(childToDel)) delCtrl(static_cast<CCtrlBase *>(childToDel), !elementMustBeDeleted);
647 else delView(childToDel, !elementMustBeDeleted);
649 // Bind the new first element
650 if (posChildToDel < _Elements.size())
652 CViewBase *pVB = _Elements[posChildToDel].Element;
653 if (posChildToDel == 0)
655 pVB->_ParentPos = NULL;
656 setHSGroup (pVB, _AddElt, _Align);
657 if ((_AddElt == Top) || (_AddElt == Bottom))
658 pVB->setY (0);
659 else
660 pVB->setX (0);
662 else
663 pVB->_ParentPos = _Elements[posChildToDel-1].Element;
665 return true;
668 // ----------------------------------------------------------------------------
669 void CGroupList::removeHead ()
671 if (_Elements.empty())
673 nlwarning("<CGroupList::removeHead> Can't remove head, list is empty");
674 return;
676 delChild (_Elements.begin()->Element);
677 /*CViewBase *pVB = _Elements.begin()->Element;
678 if ((_AddElt == Top) || (_AddElt == Bottom))
680 sint32 shift = _H - (pVB->getH() + _Space);
681 _H = shift;
683 else
685 sint32 shift = _W - (pVB->getW() + _Space);
686 _W = shift;
689 bool FirstElementMustBeDeleted = _Elements.begin()->EltDeleteOnRemove;
690 if (FirstElementMustBeDeleted)
691 delete pVB;
692 _Elements.erase (_Elements.begin());
693 // Remove from drawing
694 for (vector<CInterfaceGroup*>::iterator itg = _ChildrenGroups.begin(); itg != _ChildrenGroups.end(); itg++)
695 if(*itg == pVB)
697 _ChildrenGroups.erase (itg);
698 break;
700 for (vector<CCtrlBase*>::iterator itc = _Controls.begin(); itc != _Controls.end(); itc++)
701 if(*itc == pVB)
703 _Controls.erase (itc);
704 break;
706 for (vector<CViewBase*>::iterator itv = _Views.begin(); itv != _Views.end(); itv++)
707 if(*itv == pVB)
709 _Views.erase (itv);
710 break;
712 delEltOrder (pVB);
714 // Bind the new first element
715 pVB = _Elements.begin()->Element;
716 pVB->_ParentPos = NULL;
717 setHSGroup (pVB, _AddElt, _Align);
718 if ((_AddElt == Top) || (_AddElt == Bottom))
719 pVB->setY (0);
720 else
721 pVB->setX (0);*/
724 // ----------------------------------------------------------------------------
725 void CGroupList::setTextTemplate(const CViewText& templ)
727 _Templ = templ;
731 // ----------------------------------------------------------------------------
732 void CGroupList::updateCoords()
734 if (!_Active) return;
735 // Handle if elements are not active
736 for (sint32 i = 0; i < ((sint32)_Elements.size()-1); ++i)
738 if (_Elements[i].Element->getActive())
739 setHSParent(_Elements[i+1].Element, _AddElt, _Align, _Space);
740 else
741 setHSParent(_Elements[i+1].Element, _AddElt, _Align, 0);
744 CInterfaceGroup::updateCoords();
746 EAlign addElt = _AddElt;
747 if ((addElt == Top) || (addElt == Bottom))
749 // Calculate size
750 sint32 newH = 0;
751 bool bFirst = true;
753 for (uint32 i = 0; i < _Elements.size(); ++i)
754 if (_Elements[i].Element->getActive())
756 newH += _Elements[i].Element->getH();
757 if (!bFirst)
758 newH += _Space;
759 bFirst = false;
761 _H = max(newH, _MinH);
762 if (_DynamicDisplaySize)
764 _MaxW = _W;
765 _MaxH = _H;
767 if (_H < _MaxH) setOfsY(0);
769 // if width is not from parent, then ensure minimum size
770 if ((_SizeRef & 1) == 0) _W = max(_W, _MinW);
772 else
774 sint32 newW = 0;
775 bool bFirst = true;
777 for (uint32 i = 0; i < _Elements.size(); ++i)
778 if (_Elements[i].Element->getActive())
780 newW += _Elements[i].Element->getW();
781 if (!bFirst)
782 newW += _Space;
783 bFirst = false;
785 _W = max(newW, _MinW);
786 if (_DynamicDisplaySize)
788 _MaxW = _W;
789 _MaxH = _H;
791 if (_W < _MaxW) setOfsX(0);
793 // if height is not from parent, then ensure minimum size
794 if ((_SizeRef & 2) == 0) _H = max(_H, _MinH);
797 CInterfaceElement::updateCoords();
800 // ----------------------------------------------------------------------------
801 void CGroupList::draw ()
803 // TEMP TEMP
804 //CViewRenderer &rVR = *CViewRenderer::getInstance();
805 //rVR.drawRotFlipBitmap _RenderLayer, (_XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0, 255, 0, 255) );
806 if (_Over)
808 CViewRenderer &rVR = *CViewRenderer::getInstance();
810 if (CWidgetManager::getInstance()->getModalWindow() == NULL)
812 sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
813 sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
815 CInterfaceGroup *pIG = CWidgetManager::getInstance()->getWindowUnder(x, y);
816 CInterfaceGroup *pParent = this;
817 bool bFound = false;
818 while (pParent != NULL)
820 if (pParent == pIG)
822 bFound = true;
823 break;
825 pParent = pParent->getParent();
828 sint32 clipx, clipy, clipw, cliph;
829 getClip(clipx, clipy, clipw, cliph);
830 if ((x < clipx) ||
831 (x > (clipx + clipw)) ||
832 (y < clipy) ||
833 (y > (clipy + cliph)) || !bFound)
835 _OverElt = -1;
837 else
839 for (uint32 i = 0; i < _Elements.size(); ++i)
840 if (_Elements[i].Element->getActive())
842 CViewBase *pVB = _Elements[i].Element;
843 if ((x >= pVB->getXReal()) &&
844 (x < (pVB->getXReal() + pVB->getWReal()))&&
845 (y >= pVB->getYReal()) &&
846 (y < (pVB->getYReal() + pVB->getHReal())))
848 _OverElt = i;
854 if (_OverElt != -1)
856 // Find the first container
857 CInterfaceGroup *pIG = _Parent;
858 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(pIG);
859 while (pIG != NULL)
861 pIG = pIG->_Parent;
862 if (pIG == NULL) break;
863 if (dynamic_cast<CGroupContainerBase*>(pIG) != NULL)
864 pGC = dynamic_cast<CGroupContainerBase*>(pIG);
867 bool bDisplayOverSelection = true;
868 if (pGC != NULL)
870 if (pGC->isGrayed())
871 bDisplayOverSelection = false;
874 if (bDisplayOverSelection)
876 CViewBase *pVB = _Elements[_OverElt].Element;
877 CRGBA col = _OverColor;
878 if(getModulateGlobalColor())
880 col.modulateFromColor (_OverColor, CWidgetManager::getInstance()->getGlobalColorForContent());
882 else
884 col= _OverColor;
885 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
887 rVR.drawRotFlipBitmap (_RenderLayer, pVB->getXReal(), pVB->getYReal(),
888 pVB->getWReal(), pVB->getHReal(), 0, false, rVR.getBlankTextureId(),
889 col );
895 CInterfaceGroup::draw ();
898 // ----------------------------------------------------------------------------
899 bool CGroupList::handleEvent (const NLGUI::CEventDescriptor& event)
901 if (!_Active)
902 return false;
904 bool bReturn = CInterfaceGroup::handleEvent(event);
906 if (event.getType() == NLGUI::CEventDescriptor::mouse)
908 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
910 _OverElt = -1;
911 if (!isIn(eventDesc.getX(), eventDesc.getY()))
912 return false;
914 for (uint32 i = 0; i < _Elements.size(); ++i)
915 if (_Elements[i].Element->getActive())
917 CViewBase *pVB = _Elements[i].Element;
918 if ((eventDesc.getX() >= pVB->getXReal()) &&
919 (eventDesc.getX() < (pVB->getXReal() + pVB->getWReal()))&&
920 (eventDesc.getY() >= pVB->getYReal()) &&
921 (eventDesc.getY() < (pVB->getYReal() + pVB->getHReal())))
923 _OverElt = i;
928 return bReturn;
933 // predicate to remove a view from the list of element
934 struct CRemoveViewPred
936 bool operator()(const CGroupList::CElementInfo &info) const { return dynamic_cast<CViewBase *>(info.Element) != NULL; }
939 // predicate to remove a ctrl from the list of element
940 struct CRemoveCtrlPred
942 bool operator()(const CGroupList::CElementInfo &info) const { return dynamic_cast<CCtrlBase *>(info.Element) != NULL; }
945 // predicate to remove a group from the list of element
946 struct CRemoveGroupPred
948 bool operator()(const CGroupList::CElementInfo &info) const { return dynamic_cast<CInterfaceGroup *>(info.Element) != NULL; }
952 // ----------------------------------------------------------------------------
953 void CGroupList::clearViews()
955 _IdCounter = 0;
956 // remove views from the list of elements
957 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveViewPred()), _Elements.end());
958 CInterfaceGroup::clearViews();
959 updateCoords();
962 // ----------------------------------------------------------------------------
963 void CGroupList::clearControls()
965 _IdCounter = 0;
966 // remove views from the list of elements
967 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveCtrlPred()), _Elements.end());
968 CInterfaceGroup::clearControls();
969 updateCoords();
972 // ----------------------------------------------------------------------------
973 void CGroupList::clearGroups()
975 _IdCounter = 0;
976 // remove views from the list of elements
977 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveGroupPred()), _Elements.end());
978 CInterfaceGroup::clearGroups();
979 updateCoords();
982 // ----------------------------------------------------------------------------
983 void CGroupList::forceSizeW (sint32 newSizeW)
985 _W = newSizeW;
986 for (uint32 i = 0; i < _Elements.size(); ++i)
988 _Elements[i].Element->setW (_W);
989 _Elements[i].Element->CInterfaceElement::updateCoords();
993 // ----------------------------------------------------------------------------
994 void CGroupList::forceSizeH (sint32 newSizeH)
996 _H = newSizeH;
997 for (uint32 i = 0; i < _Elements.size(); ++i)
999 _Elements[i].Element->setH (_H);
1000 _Elements[i].Element->CInterfaceElement::updateCoords();
1004 // ----------------------------------------------------------------------------
1005 void CGroupList::setMinW(sint32 minW)
1007 _MinW= minW;
1008 invalidateCoords();
1011 // ----------------------------------------------------------------------------
1012 void CGroupList::setMinH(sint32 minH)
1014 _MinH= minH;
1015 invalidateCoords();
1018 // ----------------------------------------------------------------------------
1019 bool CGroupList::addChildAtIndex(CViewBase *child, uint index, bool deleteOnRemove /*=true*/)
1021 if (!child)
1023 nlwarning("<CGroupList::addChild> : tried to add a NULL view");
1024 return false;
1026 if (index > _Elements.size())
1028 return false;
1030 child->_Parent = this;
1031 child->_ParentPos = NULL;
1032 child->_X = 0;
1033 child->_Y = 0;
1034 child->_RenderLayer = this->_RenderLayer;
1035 // Can't have sizeref on the coordinate corresponding to alignement
1036 switch(_AddElt)
1038 case Top:
1039 case Bottom:
1040 child->_SizeRef &= 1; // sizeref on w is permitted
1041 break;
1042 case Left:
1043 case Right:
1044 child->_SizeRef &= 2; // sizeref on h is permitted
1045 break;
1046 default:
1047 nlwarning("<CGroupList::addChild> bad align");
1048 child->_SizeRef = 0;
1049 break;
1052 child->_SizeDivW = 10;
1053 child->_SizeDivH = 10;
1055 // Position the element according to the list alignement
1056 setHSGroup (child, _AddElt, _Align);
1058 // update coords of the element (it may use child_resize_h or w)
1059 //child->updateCoords();
1060 child->invalidateCoords();
1062 // Update size
1063 if ((_AddElt == Top) || (_AddElt == Bottom))
1065 // update the list size
1066 sint32 newH = _H + child->getH();
1067 if (!_Elements.empty())
1068 newH += _Space;
1069 _H = newH;
1071 if ((_SizeRef&1) == 0) // No parent size reference in W
1073 sint32 newW = max (_W, child->getW());
1074 _W = newW;
1077 else
1079 // Update the list coords
1080 sint32 newW = _W + child->getW();
1081 if (!_Elements.empty())
1082 newW += _Space;
1083 _W = newW;
1085 if ((_SizeRef&2) == 0) // No parent size reference in H
1087 sint32 newH = max (_H, child->getH());
1088 _H = newH;
1092 CElementInfo ei;
1093 ei.Element = child;
1094 ei.EltDeleteOnRemove = deleteOnRemove;
1095 ei.Order = 0;
1097 if (index != 0)
1099 // update alignement
1100 setHSParent(child, _AddElt, _Align, _Space);
1101 child->_ParentPos = _Elements[index - 1].Element;
1103 _Elements.insert(_Elements.begin() + index, ei);
1104 // link next element to this one
1105 if (index < _Elements.size() - 1)
1107 _Elements[index + 1].Element->_ParentPos = child;
1108 setHSParent(_Elements[index + 1].Element, _AddElt, _Align, _Space);
1111 // Add this element for drawing
1113 child->setSerializable( false );
1114 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(child);
1115 if (pIG != NULL)
1117 addGroup (pIG, (sint) index);
1118 return true;
1120 CCtrlBase *pCB = dynamic_cast<CCtrlBase*>(child);
1121 if (pCB != NULL)
1123 addCtrl (pCB, (sint) index);
1124 return true;
1126 CViewBase *pVB = dynamic_cast<CViewBase*>(child);
1127 if (pVB != NULL)
1129 addView (pVB, (sint) index);
1130 return true;
1132 nlstop;
1133 return false;
1135 return false;
1138 // ----------------------------------------------------------------------------
1139 sint32 CGroupList::getElementIndex(CViewBase* child) const
1141 for(uint k = 0; k < _Elements.size(); ++k)
1143 if (_Elements[k].Element == child) return k;
1145 return -1;
1148 // ----------------------------------------------------------------------------
1149 int CGroupList::luaGetElementIndex(CLuaState &ls)
1151 CLuaIHM::checkArgCount(ls, "getElementIndex", 1);
1152 CViewBase * viewBase = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1153 ls.push(getElementIndex(viewBase));
1154 return 1;
1157 // ----------------------------------------------------------------------------
1158 void CGroupList::swapChildren(uint index1, uint index2)
1160 if (index1 >= _Elements.size()
1161 || index2 >= _Elements.size())
1163 nlwarning("<CGroupList::swapChildren> bad indexes");
1164 return;
1166 // prevent elements from being deleted
1167 bool oldMustDelete1 = _Elements[index1].EltDeleteOnRemove;
1168 bool oldMustDelete2 = _Elements[index2].EltDeleteOnRemove;
1170 uint order1 = _Elements[index1].Order;
1171 uint order2 = _Elements[index2].Order;
1173 _Elements[index1].EltDeleteOnRemove = false;
1174 _Elements[index2].EltDeleteOnRemove = false;
1176 CViewBase *v1 = _Elements[index1].Element;
1177 CViewBase *v2 = _Elements[index2].Element;
1180 if (index1 < index2)
1182 delChild(index2);
1183 delChild(index1);
1184 addChildAtIndex(v2, index1, oldMustDelete2);
1185 setOrder(index1, order2);
1186 addChildAtIndex(v1, index2, oldMustDelete1);
1187 setOrder(index2, order1);
1189 else
1191 delChild(index1);
1192 delChild(index2);
1193 addChildAtIndex(v1, index2, oldMustDelete1);
1194 setOrder(index2, order1);
1195 addChildAtIndex(v2, index1, oldMustDelete2);
1196 setOrder(index1, order2);
1200 // ----------------------------------------------------------------------------
1201 int CGroupList::luaUpChild(CLuaState &ls)
1203 CLuaIHM::checkArgCount(ls, "upChild", 1);
1204 CViewBase * viewBase = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1205 sint32 indexUpChild = getElementIndex(viewBase);
1206 if(indexUpChild > 0)
1208 swapChildren(indexUpChild, indexUpChild-1);
1210 return 0;
1213 // ----------------------------------------------------------------------------
1214 int CGroupList::luaDownChild(CLuaState &ls)
1216 CLuaIHM::checkArgCount(ls, "downChild", 1);
1217 CViewBase * viewBase = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1218 sint32 indexDownChild = getElementIndex(viewBase);
1219 if(indexDownChild < (sint32) (_Elements.size()-1))
1221 swapChildren(indexDownChild, indexDownChild+1);
1223 return 0;
1226 // ----------------------------------------------------------------------------
1227 int CGroupList::luaGetChild(CLuaState &ls)
1229 const char *funcName = "getChild";
1230 CLuaIHM::checkArgCount(ls, funcName, 1);
1231 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
1232 sint index = (sint) ls.toInteger(1);
1233 if(index < 0 || index >= (sint) _Elements.size())
1235 CLuaIHM::fails(ls, "getChild : trying to access element %d in list '%s', which has %d elements",
1236 index, getId().c_str(), (int) _Elements.size());
1238 CLuaIHM::pushUIOnStack(ls, getChild((uint) index));
1239 return 1;
1242 // ----------------------------------------------------------------------------
1243 void CGroupList::deleteAllChildren()
1245 uint numChildren = getNbElement();
1246 for(uint k = 0; k < numChildren; ++k)
1248 delChild(numChildren - 1 - k); // delete in reverse order to avoid unnecessary vector copies
1252 // ----------------------------------------------------------------------------
1253 uint CGroupList::getNumActiveChildren() const
1255 uint numChildren = 0;
1256 for(uint k = 0; k < _Elements.size(); ++k)
1258 if (_Elements[k].Element->getActive()) ++numChildren;
1260 return numChildren;
1263 // ----------------------------------------------------------------------------
1264 void CGroupList::setDelOnRemove(uint index, bool delOnRemove)
1266 if (index >= _Elements.size())
1268 nlwarning("bad index");
1269 return;
1271 _Elements[index].EltDeleteOnRemove = delOnRemove;
1274 // ----------------------------------------------------------------------------
1275 bool CGroupList::getDelOnRemove(uint index) const
1277 if (index >= _Elements.size())
1279 nlwarning("bad index");
1280 return false;
1282 return _Elements[index].EltDeleteOnRemove;
1286 // ----------------------------------------------------------------------------
1287 int CGroupList::luaAddTextChild(CLuaState &ls)
1289 const char *funcName = "addTextChild";
1290 CLuaIHM::checkArgCount(ls, funcName, 1);
1291 #ifdef RYZOM_LUA_UCSTRING
1292 ucstring text; // Compatibility
1293 if(CLuaIHM::pop(ls, text))
1295 addTextChild(text.toUtf8());
1297 #else
1298 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1299 addTextChild(ls.toString(1));
1300 #endif
1301 return 0;
1304 // ----------------------------------------------------------------------------
1305 int CGroupList::luaAddColoredTextChild(CLuaState &ls)
1307 const char *funcName = "addColoredTextChild";
1308 CLuaIHM::checkArgCount(ls, funcName, 5);
1309 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1310 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TNUMBER);
1311 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TNUMBER);
1312 CLuaIHM::checkArgType(ls, funcName, 4, LUA_TNUMBER);
1313 CLuaIHM::checkArgType(ls, funcName, 5, LUA_TNUMBER);
1314 string text = ls.toString(1);
1316 uint r = (uint) ls.toInteger(2);
1317 uint g = (uint) ls.toInteger(3);
1318 uint b = (uint) ls.toInteger(4);
1319 uint a = (uint) ls.toInteger(5);
1321 addTextChild(text, CRGBA(r, g, b, a));
1323 return 0;
1326 // ----------------------------------------------------------------------------
1327 int CGroupList::luaAddChild(CLuaState &ls)
1329 const char *funcName = "addChild";
1330 CLuaIHM::checkArgCount(ls, funcName, 1);
1331 CViewBase *vb = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1332 if (!vb)
1334 CLuaIHM::fails(ls, "%s requires a view, group or control", funcName);
1336 else
1338 addChild(vb);
1340 return 0;
1343 // ----------------------------------------------------------------------------
1344 int CGroupList::luaAddChildAtIndex(CLuaState &ls)
1346 const char *funcName = "addChildAtIndex";
1347 CLuaIHM::checkArgCount(ls, funcName, 2);
1348 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TNUMBER);
1349 CViewBase *vb = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1350 if (!vb)
1352 CLuaIHM::fails(ls, "%s requires a view, group or control", funcName);
1354 else
1356 addChildAtIndex(vb, (uint) ls.toInteger(2));
1358 return 0;
1361 // ----------------------------------------------------------------------------
1362 int CGroupList::luaDetachChild(CLuaState &ls)
1364 const char *funcName = "detachChild";
1365 CLuaIHM::checkArgCount(ls, funcName, 1);
1366 CViewBase *vb = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1367 if (!vb)
1369 nlwarning("%s requires a view, group or control", funcName);
1370 ls.push(false);
1372 else
1374 ls.push(delChild(vb, false, true));
1376 return 1;
1379 // ----------------------------------------------------------------------------
1380 int CGroupList::luaDelChild(CLuaState &ls)
1382 CLuaIHM::checkArgCount(ls, "CGroupList::delChild", 1);
1383 CViewBase *vb = dynamic_cast<CViewBase *>(CLuaIHM::getUIOnStack(ls, 1));
1384 if (vb) delChild(vb);
1385 updateCoords();
1386 return 0;
1391 // ----------------------------------------------------------------------------
1392 int CGroupList::luaClear(CLuaState &ls)
1394 CLuaIHM::checkArgCount(ls, "clear", 0);
1395 deleteAllChildren();
1396 return 0;
1399 void CGroupList::setupSizes()
1401 _GroupSizeRef = _SizeRef;
1402 if ((_AddElt == Top) || (_AddElt == Bottom))
1404 setMaxW (_W);
1405 setMaxH(_H);
1406 _H = 0;
1407 _SizeRef = _SizeRef & (~2);
1409 else
1411 setMaxW (_W);
1412 setMaxH (_H);
1413 _W = 0;
1414 _SizeRef = _SizeRef & (~1);
1418 void CGroupList::onTextChanged()
1420 if( _Elements.empty() )
1421 return;
1423 CElementInfo &e = _Elements[ 0 ];
1425 CViewText *t = dynamic_cast< CViewText* >( e.Element );
1426 if( t != NULL )
1428 t->setText( _HardText );
1429 return;
1431 else
1433 CViewTextID *ti = dynamic_cast< CViewTextID* >( e.Element );
1434 if( ti != NULL )
1436 ti->setTextId( _TextId );