Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / group_paragraph.cpp
blob3317a0dea41bb38fc2806412c5709301c51b8bd8
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2021 Winch Gate Property Limited
3 //
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>
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/>.
22 #include "stdpch.h"
23 #include "nel/gui/group_paragraph.h"
24 #include "nel/gui/group_html.h"
25 #include "nel/gui/widget_manager.h"
26 #include "nel/gui/interface_element.h"
27 #include "nel/gui/view_pointer_base.h"
28 #include "nel/gui/view_bitmap.h"
29 #include "nel/gui/view_text_id.h"
30 #include "nel/gui/group_container.h"
31 #include "nel/misc/i_xml.h"
32 #include "nel/misc/i18n.h"
33 #include "nel/misc/xml_auto_ptr.h"
35 using namespace std;
36 using namespace NLMISC;
38 #ifdef DEBUG_NEW
39 #define new DEBUG_NEW
40 #endif
42 NLMISC_REGISTER_OBJECT(CViewBase, CCtrlLink, std::string, "button_link");
44 namespace NLGUI
47 // ----------------------------------------------------------------------------
48 CGroupParagraph::CGroupParagraph(const TCtorParam &param)
49 : CInterfaceGroup(param),
50 _Templ(TCtorParam())
52 _IdCounter = 0;
53 _AddElt = Bottom;
54 _Align = Left;
55 _Space = 0;
56 _MinW= 0;
57 _MinH= 0;
58 _Over = false;
59 _TempOver = false;
60 _OverColor = CRGBA(255,255,255,32);
61 _OverElt = -1;
62 _LastW = 0;
63 invalidateContent();
64 _TopSpace = 0;
65 _Indent = 0;
66 _FirstViewIndentView = false;
67 _TextId = 0;
68 _TextAlign = AlignLeft;
71 // ----------------------------------------------------------------------------
72 void CGroupParagraph::addChild (CViewBase* child, bool deleteOnRemove)
74 if (!child)
76 nlwarning("<CGroupParagraph::addChild> : tried to add a NULL view");
77 return;
80 // add child at last index
81 addChildAtIndex(child, (uint)_Elements.size(), deleteOnRemove);
82 if (_Elements.size() >= 2)
84 setOrder((uint)_Elements.size() - 1, getOrder((uint)_Elements.size() - 2) + 1);
86 invalidateContent();
89 // ----------------------------------------------------------------------------
90 CGroupParagraph::~CGroupParagraph()
92 deleteAllChildren();
95 // ----------------------------------------------------------------------------
96 // Set Hotspot of the first element in reference to the group
97 /*void CGroupParagraph::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 CGroupParagraph::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(space);
170 else if (addElt == Top)
172 if (_Align == Left)
173 view->_ParentPosRef = Hotspot_TL;
174 else // align == Right
175 view->_ParentPosRef = Hotspot_TR;
176 view->_Y = abs(space);
179 else
181 if (addElt == Left)
183 if (_Align == Top)
184 view->_ParentPosRef = Hotspot_TL;
185 else // align == Bottom
186 view->_ParentPosRef = Hotspot_BL;
187 view->_X = -abs(space);
189 else if (addElt == Right)
191 if (_Align == Top)
192 view->_ParentPosRef = Hotspot_TR;
193 else // align == Bottom
194 view->_ParentPosRef = Hotspot_BR;
195 view->_X = abs(space);
201 std::string CGroupParagraph::getProperty( const std::string &name ) const
203 if( name == "addelt" )
205 switch( _AddElt )
207 case Top:
208 return "T";
210 case Left:
211 return "L";
213 case Right:
214 return "R";
216 case Bottom:
217 return "B";
220 nlassert(false);
222 return "";
224 else
225 if( name == "align" )
227 switch( _Align )
229 case Top:
230 return "T";
232 case Left:
233 return "L";
235 case Right:
236 return "R";
238 case Bottom:
239 return "B";
242 nlassert(false);
244 return "";
246 else
247 if( name == "space" )
249 return toString( _Space );
251 else
252 if( name == "over" )
254 return toString( _Over );
256 else
257 if( name == "col_over" )
259 return toString( _OverColor );
261 else
262 if( name == "hardtext" )
264 return _HardText;
266 else
267 if( name == "textid" )
269 return toString( _TextId );
271 else
272 return CInterfaceGroup::getProperty( name );
275 void CGroupParagraph::setProperty( const std::string &name, const std::string &value )
277 if( name == "addelt" )
279 if( value == "T" )
280 _AddElt = Top;
281 else
282 if( value == "L" )
283 _AddElt = Left;
284 else
285 if( value == "R" )
286 _AddElt = Right;
287 else
288 if( value == "B" )
289 _AddElt = Bottom;
291 setupSizes();
292 return;
294 else
295 if( name == "align" )
297 if( value == "T" )
298 _Align = Top;
299 else
300 if( value == "L" )
301 _Align = Left;
302 else
303 if( value == "R" )
304 _Align = Right;
305 else
306 if( value == "B" )
307 _Align = Bottom;
309 return;
311 else
312 if( name == "space" )
314 sint32 i;
315 if( fromString( value, i ) )
316 _Space = i;
317 return;
319 else
320 if( name == "over" )
322 bool b;
323 if( fromString( value, b ) )
324 _Over = b;
325 return;
327 else
328 if( name == "col_over" )
330 CRGBA c;
331 if( fromString( value, c ) )
332 _OverColor = c;
333 return;
335 if( name == "hardtext" )
337 _HardText = value;
338 _TextId = 0;
339 onTextChanged();
340 return;
342 else
343 if( name == "textid" )
345 uint32 i;
346 if( fromString( value, i ) )
348 _TextId = i;
349 _HardText.clear();
351 onTextChanged();
352 return;
355 else
356 CInterfaceGroup::setProperty( name, value );
360 xmlNodePtr CGroupParagraph::serialize( xmlNodePtr parentNode, const char *type ) const
362 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
363 if( node == NULL )
364 return NULL;
366 std::string addelt;
367 std::string align;
369 switch( _AddElt )
371 case Top:
372 addelt = "T";
373 break;
375 case Left:
376 addelt = "L";
377 break;
379 case Right:
380 addelt = "R";
381 break;
383 default:
384 addelt = "B";
385 break;
388 switch( _Align )
390 case Top:
391 align = "T";
392 break;
394 case Left:
395 align = "L";
396 break;
398 case Right:
399 align = "R";
400 break;
402 default:
403 align = "B";
404 break;
407 xmlSetProp( node, BAD_CAST "addelt", BAD_CAST addelt.c_str() );
408 xmlSetProp( node, BAD_CAST "align", BAD_CAST align.c_str() );
409 xmlSetProp( node, BAD_CAST "space", BAD_CAST toString( _Space ).c_str() );
410 xmlSetProp( node, BAD_CAST "over", BAD_CAST toString( _Over ).c_str() );
411 xmlSetProp( node, BAD_CAST "col_over", BAD_CAST toString( _OverColor ).c_str() );
412 xmlSetProp( node, BAD_CAST "hardtext", BAD_CAST _HardText.c_str() );
413 xmlSetProp( node, BAD_CAST "textid", BAD_CAST toString( _TextId ).c_str() );
415 return node;
418 // ----------------------------------------------------------------------------
419 bool CGroupParagraph::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup)
421 if (!CInterfaceGroup::parse(cur,parentGroup))
422 return false;
424 // Parse location. If these properties are not specified, set them to 0
426 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"addelt" ));
427 _AddElt = Bottom;
428 if (ptr)
430 if (stricmp(ptr,"B") == 0)
431 _AddElt = Bottom;
432 else if (stricmp(ptr,"T") == 0)
433 _AddElt = Top;
434 else if (stricmp(ptr,"L") == 0)
435 _AddElt = Left;
436 else if (stricmp(ptr,"R") == 0)
437 _AddElt = Right;
440 ptr = (char*) xmlGetProp( cur, (xmlChar*)"align" );
441 _Align = Left;
442 if (ptr)
444 if (stricmp(ptr,"B") == 0)
445 _Align = Bottom;
446 else if (stricmp(ptr,"T") == 0)
447 _Align = Top;
448 else if (stricmp(ptr,"L") == 0)
449 _Align = Left;
450 else if (stricmp(ptr,"R") == 0)
451 _Align = Right;
454 setupSizes();
456 ptr = (char*) xmlGetProp( cur, (xmlChar*)"space" );
457 _Space = 0;
458 if (ptr)
459 fromString((const char*)ptr, _Space);
461 ptr = (char*) xmlGetProp( cur, (xmlChar*)"over" );
462 _Over = false;
463 if (ptr) _Over = convertBool(ptr);
465 ptr = (char*) xmlGetProp( cur, (xmlChar*)"col_over" );
466 _OverColor = CRGBA(255,255,255,32);
467 if (ptr) _OverColor = convertColor(ptr);
470 // TEMPLATE TEXT SETUP
472 // justification parameters
473 _Templ.parseTextOptions (cur);
475 // initial text
476 ptr = (char*) xmlGetProp( cur, (xmlChar*)"hardtext" );
477 if (ptr)
479 _HardText = std::string( (const char*)ptr );
480 const char *propPtr = ptr;
481 if (NLMISC::startsWith(propPtr, "ui"))
482 addTextChild(CI18N::get(propPtr));
483 else
484 addTextChild(propPtr);
486 else
488 ptr = (char*) xmlGetProp( cur, (xmlChar*)"textid" );
489 if (ptr)
491 fromString((const char*)ptr, _TextId );
492 addTextChildID( _TextId );
496 return true;
499 // ----------------------------------------------------------------------------
500 void CGroupParagraph::addTextChild(const std::string& line, bool multiLine /*= true*/)
502 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
503 CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
504 view->_Parent = this;
505 view->setMultiLine (multiLine);
506 view->setTextMode(_Templ.getTextMode());
507 if (multiLine) view->setMultiLineSpace (_Space);
508 view->setText (line);
509 // Herit global-coloring
510 view->setModulateGlobalColor(getModulateGlobalColor());
511 addChild (view);
512 invalidateCoords();
517 // ----------------------------------------------------------------------------
518 void CGroupParagraph::addTextChild(const std::string& line, const CRGBA& textColor, bool multiLine /*= true*/)
520 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
521 CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
522 view->_Parent = this;
523 view->setMultiLine (multiLine);
524 if (multiLine) view->setMultiLineSpace (_Space);
525 view->setText (line);
526 view->setColor (textColor);
527 // Herit global-coloring
528 view->setModulateGlobalColor(getModulateGlobalColor());
529 addChild (view);
530 invalidateCoords();
533 // ----------------------------------------------------------------------------
534 void CGroupParagraph::addTextChildID (uint32 nID, bool multiLine)
536 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
537 CViewTextID *view= new CViewTextID (elid, nID, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
538 view->_Parent = this;
539 view->setMultiLine (multiLine);
540 if (multiLine) view->setMultiLineSpace (_Space);
541 // Herit global-coloring
542 view->setModulateGlobalColor(getModulateGlobalColor());
543 addChild (view);
544 invalidateCoords();
547 // ----------------------------------------------------------------------------
548 void CGroupParagraph::addTextChildID(const std::string &dbPath,bool multiLine /*=true*/)
550 const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
551 CViewTextID *view= new CViewTextID (elid, dbPath, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
552 view->_Parent = this;
553 view->setMultiLine (multiLine);
554 if (multiLine) view->setMultiLineSpace (_Space);
555 // Herit global-coloring
556 view->setModulateGlobalColor(getModulateGlobalColor());
557 addChild (view);
558 invalidateCoords();
561 // ----------------------------------------------------------------------------
562 void CGroupParagraph::delChild (CViewBase* childToDel)
564 // Look for child
565 uint posChildToDel = 0;
566 for (posChildToDel = 0; posChildToDel < _Elements.size(); ++posChildToDel)
568 CElementInfo rEI = _Elements[posChildToDel];
569 if (rEI.Element == childToDel)
570 break;
573 if (posChildToDel == _Elements.size())
575 nlwarning("Can't del child %s, it does not exist in the list", childToDel->getId().c_str());
576 return;
578 delChild(posChildToDel);
581 // ----------------------------------------------------------------------------
582 void CGroupParagraph::delChild(uint posChildToDel)
584 if (posChildToDel >= (uint) _Elements.size())
586 nlwarning("<CGroupParagraph::delChild> bad index");
587 return;
590 CViewBase* childToDel = _Elements[posChildToDel].Element;
591 bool ElementMustBeDeleted = _Elements[posChildToDel].EltDeleteOnRemove;
592 _Elements.erase (_Elements.begin()+posChildToDel);
593 // Remove from drawing
594 if (dynamic_cast<CInterfaceGroup *>(childToDel)) delGroup(static_cast<CInterfaceGroup *>(childToDel), !ElementMustBeDeleted);
595 else if (dynamic_cast<CCtrlBase *>(childToDel)) delCtrl(static_cast<CCtrlBase *>(childToDel), !ElementMustBeDeleted);
596 else delView(childToDel, !ElementMustBeDeleted);
598 // Bind the new first element
599 if (posChildToDel < _Elements.size())
601 CViewBase *pVB = _Elements[posChildToDel].Element;
602 if (posChildToDel == 0)
604 pVB->_ParentPos = NULL;
605 // setHSGroup (pVB, _AddElt, _Align);
606 if ((_AddElt == Top) || (_AddElt == Bottom))
607 pVB->setY (0);
608 else
609 pVB->setX (0);
611 else
612 pVB->_ParentPos = _Elements[posChildToDel-1].Element;
616 // ----------------------------------------------------------------------------
617 /*void CGroupParagraph::removeHead ()
619 if (_Elements.empty())
621 nlwarning("<CGroupParagraph::removeHead> Can't remove head, list is empty");
622 return;
624 delChild (_Elements.begin()->Element);*/
625 /*CViewBase *pVB = _Elements.begin()->Element;
626 if ((_AddElt == Top) || (_AddElt == Bottom))
628 sint32 shift = _H - (pVB->getH() + _Space);
629 _H = shift;
631 else
633 sint32 shift = _W - (pVB->getW() + _Space);
634 _W = shift;
637 bool FirstElementMustBeDeleted = _Elements.begin()->EltDeleteOnRemove;
638 if (FirstElementMustBeDeleted)
639 delete pVB;
640 _Elements.erase (_Elements.begin());
641 // Remove from drawing
642 for (vector<CInterfaceGroup*>::iterator itg = _ChildrenGroups.begin(); itg != _ChildrenGroups.end(); itg++)
643 if(*itg == pVB)
645 _ChildrenGroups.erase (itg);
646 break;
648 for (vector<CCtrlBase*>::iterator itc = _Controls.begin(); itc != _Controls.end(); itc++)
649 if(*itc == pVB)
651 _Controls.erase (itc);
652 break;
654 for (vector<CViewBase*>::iterator itv = _Views.begin(); itv != _Views.end(); itv++)
655 if(*itv == pVB)
657 _Views.erase (itv);
658 break;
660 delEltOrder (pVB);
662 // Bind the new first element
663 pVB = _Elements.begin()->Element;
664 pVB->_ParentPos = NULL;
665 setHSGroup (pVB, _AddElt, _Align);
666 if ((_AddElt == Top) || (_AddElt == Bottom))
667 pVB->setY (0);
668 else
669 pVB->setX (0);*/
672 // ----------------------------------------------------------------------------
673 void CGroupParagraph::setTextTemplate(const CViewText& templ)
675 _Templ = templ;
679 // ----------------------------------------------------------------------------
680 void CGroupParagraph::updateCoords()
682 if (_Parent)
684 if (!_ContentValidated)
686 // Update W
687 CInterfaceElement::updateCoords();
689 // Current X and Y
690 sint32 x=_Indent;
691 sint32 y=-(sint32)_TopSpace;
693 // Current W
694 sint width = std::min(getMaxWReal(), getWReal());
696 // For each elements, place them
697 uint firstElementOnLine = 0;
698 const uint elmCount = (uint)_Elements.size();
699 uint i;
700 for (i = 0; i < elmCount+1; ++i)
702 // Force flush for the last element
703 bool changeLine = (i == elmCount);
704 uint lastLineElement = i+1;
706 // Not the end of the element
707 if (i < elmCount)
709 // Active element ?
710 if (_Elements[i].Element->getActive())
712 _Elements[i].Element->updateCoords();
713 // Is a view text ?
714 CViewText *viewText = dynamic_cast<CViewText*>(_Elements[i].Element);
715 if (viewText)
717 // FIXME: this does not work with multiple view text on same line
718 if (_TextAlign == AlignCenter && elmCount == 1)
719 viewText->setTextMode(CViewText::Centered);
721 viewText->setFirstLineX(x + ((i==0)?_FirstViewIndentView:0));
722 viewText->setX(0);
723 viewText->updateTextContext();
725 else
727 _Elements[i].Element->setX(x + ((i==0)?_FirstViewIndentView:0));
729 _Elements[i].Element->setPosRef(Hotspot_TL);
730 _Elements[i].Element->setParentPosRef(Hotspot_TL);
732 // Update coords for this element
733 _Elements[i].Element->updateCoords();
735 // Does we balance the last line height ?
736 if (viewText)
738 if (_TextAlign == AlignCenter && elmCount == 1)
740 sint pad = width - viewText->getWReal();
741 viewText->setX(pad/2);
744 changeLine = viewText->getNumLine() > 1;
745 if (!viewText->getText().empty() && *(viewText->getText().rbegin()) == '\n')
747 changeLine = true;
750 else
752 // If this element is too big for the line, place it next time
753 if ((i!=firstElementOnLine) && ((_Elements[i].Element->getX() + _Elements[i].Element->getW()) > width))
755 lastLineElement--;
756 changeLine = true;
757 i--;
762 // New x coordinate
763 x = _Elements[i].Element->getX() + _Elements[i].Element->getWReal();
766 else
767 lastLineElement = i;
769 // Balance line height
770 if (changeLine)
772 // Eval line height
773 uint j;
774 uint lineHeight = 0;
775 uint multiLineHeight = 0;
776 uint legHeight = 0;
777 uint lastLineWidth = _Indent;
779 for (j=firstElementOnLine; j<lastLineElement; j++)
781 // Is a view text ?
782 uint newHeight;
783 CViewText *viewTextOnLine = dynamic_cast<CViewText*>(_Elements[j].Element);
785 // Element height
786 if (viewTextOnLine)
788 // Height is just under the first line letter
789 newHeight = viewTextOnLine->getFontHeight() - viewTextOnLine->getFontLegHeight();
791 // Leg height for this view
792 legHeight = std::max(legHeight, viewTextOnLine->getFontLegHeight());
794 // Last element is a text multi line
795 if (j==(lastLineElement-1))
797 const uint numLine = viewTextOnLine->getNumLine();
798 if (numLine>1)
800 multiLineHeight = (numLine-2) * viewTextOnLine->getFontHeight() + (numLine-1) * viewTextOnLine->getMultiLineSpace();
801 lastLineWidth = _Indent + viewTextOnLine->getLastLineW ();
805 else
807 newHeight = _Elements[j].Element->getH();
808 CGroupHTMLInputOffset *inputOffset = dynamic_cast<CGroupHTMLInputOffset *>(_Elements[j].Element);
809 if (inputOffset && inputOffset->Offset < 0)
811 newHeight += inputOffset->Offset;
812 legHeight = max(-(inputOffset->Offset), sint32(legHeight));
816 if (lineHeight < newHeight)
817 lineHeight = newHeight;
820 // Repos element on the line
821 for (j=firstElementOnLine; j<lastLineElement; j++)
823 // Is a view text ?
824 uint newHeight;
825 CViewText *viewTextOnLine = dynamic_cast<CViewText*>(_Elements[j].Element);
827 sint32 offsetY=0;
828 CGroupHTMLInputOffset *inputOffset = dynamic_cast<CGroupHTMLInputOffset *>(_Elements[j].Element);
829 if (inputOffset)
830 offsetY = inputOffset->Offset;
831 // Element height
832 if (viewTextOnLine)
833 newHeight = viewTextOnLine->getFontHeight() - viewTextOnLine->getFontLegHeight() - offsetY;
834 else
835 newHeight = _Elements[j].Element->getH();
837 sint32 posY = y-lineHeight+newHeight+offsetY;
838 _Elements[j].Element->setY(posY);
841 if (i < elmCount)
843 nlassert(lastLineElement>0);
844 nlassert(lastLineElement-1<elmCount);
845 x = lastLineWidth;
847 // Next line
848 y -= lineHeight + multiLineHeight + legHeight;
851 // New first element
852 firstElementOnLine = lastLineElement;
856 // Update control view
857 for (i = 0; i<_Links.size(); ++i)
859 // Link
860 CLink &link = _Links[i];
862 // Number of link needed
863 uint links = std::min((uint)3, link.Link->getNumLine());
865 // Number of line..
866 uint j;
867 for (j=0; j<3; j++)
869 if (j<links)
871 // Create the control ?
872 CCtrlLink *ctrl = link.CtrlLink[j];
873 if (ctrl == NULL)
875 // Control button
876 ctrl = new CCtrlLink(CViewBase::TCtorParam());
877 link.CtrlLink[j] = ctrl;
878 ctrl->setId(getId()+":"+"links"+toString(i)+"-"+toString(j));
879 ctrl->setParent (this);
880 ctrl->setParentSize (this);
881 ctrl->setParentPos (this);
882 ctrl->setParentPosRef (Hotspot_TL);
883 ctrl->setPosRef (Hotspot_TL);
884 ctrl->setActive(true);
885 ctrl->setActionOnLeftClick(link.Link->getActionOnLeftClick());
886 ctrl->setParamsOnLeftClick(link.Link->getParamsOnLeftClick());
887 ctrl->setScale(true);
888 addCtrl(ctrl);
891 // Pos the links
892 int x, y, width, height;
893 int fontSize = link.Link->getFontHeight();
894 int fontLineSpace = link.Link->getMultiLineSpace();
896 // X
897 x = (j == 0) ? link.Link->getFirstLineX() : link.Link->getX();
899 // Y
900 if (j < 2)
901 y = link.Link->getY() - (fontSize+fontLineSpace) * j;
902 else
903 y = link.Link->getY() - ((fontSize+fontLineSpace) * (link.Link->getNumLine()-1));
905 // Width
907 // Last line ?
908 if (j == (links-1))
909 width = link.Link->getLastLineW ();
910 else
912 width = link.Link->getW();
914 // First line ?
915 if (j == 0)
916 width -= (link.Link->getFirstLineX() - link.Link->getX());
919 if ((j == 1) && (links==3))
920 height = (fontSize+fontLineSpace)*(link.Link->getNumLine()-2);
921 else
922 height = fontSize;
924 ctrl->setX(x);
925 ctrl->setY(y);
926 ctrl->setW(width);
927 ctrl->setH(height);
929 else
931 if (link.CtrlLink[j])
933 delCtrl (link.CtrlLink[j]);
934 link.CtrlLink[j] = NULL;
941 CInterfaceGroup::updateCoords();
943 // Validated
944 _ContentValidated = true;
947 // ----------------------------------------------------------------------------
948 void CGroupParagraph::checkCoords ()
950 if (_Parent != NULL)
952 sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
953 if (_LastW != (sint) parentWidth)
955 CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
956 if (pCB != NULL)
958 CCtrlResizer *pCR = dynamic_cast<CCtrlResizer*>(pCB);
959 if (pCR != NULL)
961 // We are resizing !!!!
963 else
965 _LastW = parentWidth;
966 invalidateContent();
969 else
971 _LastW = parentWidth;
972 invalidateContent();
976 CInterfaceGroup::checkCoords();
979 // ----------------------------------------------------------------------------
980 void CGroupParagraph::draw ()
982 // TEMP TEMP
983 //CViewRenderer &rVR = *CViewRenderer::getInstance();
984 //rVR.drawRotFlipBitmap _RenderLayer, (_XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0,255,0,255) );
985 if (_Over || _TempOver)
987 CViewRenderer &rVR = *CViewRenderer::getInstance();
989 if (CWidgetManager::getInstance()->getModalWindow() == NULL)
991 sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
992 sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
994 CInterfaceGroup *pIG = CWidgetManager::getInstance()->getWindowUnder(x,y);
995 CInterfaceGroup *pParent = this;
996 bool bFound = false;
997 while (pParent != NULL)
999 if (pParent == pIG)
1001 bFound = true;
1002 break;
1004 pParent = pParent->getParent();
1007 sint32 clipx,clipy,clipw,cliph;
1008 getClip(clipx,clipy,clipw,cliph);
1009 if ((x < clipx) ||
1010 (x > (clipx + clipw)) ||
1011 (y < clipy) ||
1012 (y > (clipy + cliph)) || !bFound)
1014 _OverElt = -1;
1016 else
1018 for (uint32 i = 0; i < _Elements.size(); ++i)
1019 if (_Elements[i].Element->getActive())
1021 CViewBase *pVB = _Elements[i].Element;
1022 if ((x >= pVB->getXReal()) &&
1023 (x < (pVB->getXReal() + pVB->getWReal()))&&
1024 (y >= pVB->getYReal()) &&
1025 (y < (pVB->getYReal() + pVB->getHReal())))
1027 _OverElt = i;
1033 if (_OverElt != -1)
1035 CViewBase *pVB = _Elements[_OverElt].Element;
1036 CRGBA col = _OverColor;
1037 if(getModulateGlobalColor())
1039 col.modulateFromColor (_OverColor, CWidgetManager::getInstance()->getGlobalColorForContent());
1041 else
1043 col= _OverColor;
1044 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
1046 rVR.drawRotFlipBitmap (_RenderLayer, pVB->getXReal(), pVB->getYReal(),
1047 pVB->getWReal(), pVB->getHReal(), 0, false, rVR.getBlankTextureId(),
1048 col );
1053 CInterfaceGroup::draw ();
1056 // ----------------------------------------------------------------------------
1057 bool CGroupParagraph::handleEvent (const NLGUI::CEventDescriptor& event)
1059 if (!_Active)
1060 return false;
1062 bool bReturn = CInterfaceGroup::handleEvent(event);
1064 if (event.getType() == NLGUI::CEventDescriptor::mouse)
1066 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
1068 _OverElt = -1;
1069 if (!isIn(eventDesc.getX(), eventDesc.getY()))
1071 _TempOver = false;
1072 return false;
1075 for (uint32 i = 0; i < _Elements.size(); ++i)
1076 if (_Elements[i].Element->getActive())
1078 CViewBase *pVB = _Elements[i].Element;
1079 if ((eventDesc.getX() >= pVB->getXReal()) &&
1080 (eventDesc.getX() < (pVB->getXReal() + pVB->getWReal()))&&
1081 (eventDesc.getY() >= pVB->getYReal()) &&
1082 (eventDesc.getY() < (pVB->getYReal() + pVB->getHReal())))
1084 _OverElt = i;
1089 return bReturn;
1094 // predicate to remove a view from the list of element
1095 struct CRemoveViewPred
1097 bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast<CViewBase *>(info.Element) != NULL; }
1100 // predicate to remove a ctrl from the list of element
1101 struct CRemoveCtrlPred
1103 bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast<CCtrlBase *>(info.Element) != NULL; }
1106 // predicate to remove a group from the list of element
1107 struct CRemoveGroupPred
1109 bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast<CInterfaceGroup *>(info.Element) != NULL; }
1113 // ----------------------------------------------------------------------------
1114 void CGroupParagraph::clearViews()
1116 _IdCounter = 0;
1117 // remove views from the list of elements
1118 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveViewPred()), _Elements.end());
1119 CInterfaceGroup::clearViews();
1120 updateCoords();
1123 // ----------------------------------------------------------------------------
1124 void CGroupParagraph::clearControls()
1126 _IdCounter = 0;
1127 // remove views from the list of elements
1128 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveCtrlPred()), _Elements.end());
1129 CInterfaceGroup::clearControls();
1130 updateCoords();
1133 // ----------------------------------------------------------------------------
1134 void CGroupParagraph::clearGroups()
1136 _IdCounter = 0;
1137 // remove views from the list of elements
1138 _Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveGroupPred()), _Elements.end());
1139 CInterfaceGroup::clearGroups();
1140 updateCoords();
1143 // ----------------------------------------------------------------------------
1144 void CGroupParagraph::forceSizeW (sint32 newSizeW)
1146 _W = newSizeW;
1147 for (uint32 i = 0; i < _Elements.size(); ++i)
1149 _Elements[i].Element->setW (_W);
1150 _Elements[i].Element->CInterfaceElement::updateCoords();
1154 // ----------------------------------------------------------------------------
1155 void CGroupParagraph::forceSizeH (sint32 newSizeH)
1157 _H = newSizeH;
1158 for (uint32 i = 0; i < _Elements.size(); ++i)
1160 _Elements[i].Element->setH (_H);
1161 _Elements[i].Element->CInterfaceElement::updateCoords();
1165 // ----------------------------------------------------------------------------
1166 void CGroupParagraph::setMinW(sint32 minW)
1168 _MinW= minW;
1169 invalidateCoords();
1172 // ----------------------------------------------------------------------------
1173 void CGroupParagraph::setMinH(sint32 minH)
1175 _MinH= minH;
1176 invalidateCoords();
1179 // ----------------------------------------------------------------------------
1180 bool CGroupParagraph::addChildAtIndex(CViewBase *child, uint index, bool deleteOnRemove /*=true*/)
1182 if (!child)
1184 nlwarning("<CGroupParagraph::addChild> : tried to add a NULL view");
1185 return false;
1187 if (index > _Elements.size())
1189 return false;
1191 child->_Parent = this;
1192 child->_ParentPos = NULL;
1193 child->_Active = true;
1194 child->_X = 0;
1195 child->_Y = 0;
1196 child->_RenderLayer = this->_RenderLayer;
1197 // Can't have sizeref on the coordinate corresponding to alignement
1198 switch(_AddElt)
1200 case Top:
1201 case Bottom:
1202 child->_SizeRef &= 1; // sizeref on w is permitted
1203 break;
1204 case Left:
1205 case Right:
1206 child->_SizeRef &= 2; // sizeref on h is permitted
1207 break;
1208 default:
1209 nlwarning("<CGroupParagraph::addChild> bad align");
1210 child->_SizeRef = 0;
1211 break;
1214 child->_SizeDivW = 10;
1215 child->_SizeDivH = 10;
1217 // Position the element according to the list alignement
1218 // setHSGroup (child, _AddElt, _Align);
1220 // update coords of the element (it may use child_resize_h or w)
1221 //child->updateCoords();
1222 child->invalidateCoords();
1224 // Update size
1225 if ((_AddElt == Top) || (_AddElt == Bottom))
1227 // update the list size
1228 sint32 newH = _H + child->getH();
1229 if (!_Elements.empty())
1230 newH += _Space;
1231 _H = newH;
1233 if ((_SizeRef&1) == 0) // No parent size reference in W
1235 sint32 newW = max (_W, child->getW());
1236 _W = newW;
1239 else
1241 // Update the list coords
1242 sint32 newW = _W + child->getW();
1243 if (!_Elements.empty())
1244 newW += _Space;
1245 _W = newW;
1247 if ((_SizeRef&2) == 0) // No parent size reference in H
1249 sint32 newH = max (_H, child->getH());
1250 _H = newH;
1254 CElementInfo ei;
1255 ei.Element = child;
1256 ei.EltDeleteOnRemove = deleteOnRemove;
1257 ei.Order = 0;
1259 if (index != 0)
1261 // update alignement
1262 // setHSParent(child, _AddElt, _Align, _Space);
1263 // child->_ParentPos = _Elements[index - 1].Element;
1265 _Elements.insert(_Elements.begin() + index, ei);
1266 // link next element to this one
1267 if (index < _Elements.size() - 1)
1269 // _Elements[index + 1].Element->_ParentPos = child;
1270 // setHSParent(_Elements[index + 1].Element, _AddElt, _Align, _Space);
1273 // Add this element for drawing
1275 CInterfaceGroup *pIG = dynamic_cast<CInterfaceGroup*>(child);
1276 if (pIG != NULL)
1278 addGroup (pIG, (sint) index);
1279 return true;
1281 CCtrlBase *pCB = dynamic_cast<CCtrlBase*>(child);
1282 if (pCB != NULL)
1284 addCtrl (pCB, (sint) index);
1285 return true;
1287 CViewBase *pVB = dynamic_cast<CViewBase*>(child);
1288 if (pVB != NULL)
1290 addView (pVB, (sint) index);
1291 return true;
1293 nlstop;
1294 return false;
1296 return false;
1299 // ----------------------------------------------------------------------------
1300 sint32 CGroupParagraph::getElementIndex(CViewBase* child) const
1302 for(uint k = 0; k < _Elements.size(); ++k)
1304 if (_Elements[k].Element == child) return k;
1306 return -1;
1309 // ----------------------------------------------------------------------------
1310 /*void CGroupParagraph::swapChildren(uint index1, uint index2)
1312 if (index1 >= _Elements.size()
1313 || index2 >= _Elements.size())
1315 nlwarning("<CGroupParagraph::swapChildren> bad indexes");
1316 return;
1318 // prevent elements from being deleted
1319 bool oldMustDelete1 = _Elements[index1].EltDeleteOnRemove;
1320 bool oldMustDelete2 = _Elements[index2].EltDeleteOnRemove;
1322 uint order1 = _Elements[index1].Order;
1323 uint order2 = _Elements[index2].Order;
1325 _Elements[index1].EltDeleteOnRemove = false;
1326 _Elements[index2].EltDeleteOnRemove = false;
1328 CViewBase *v1 = _Elements[index1].Element;
1329 CViewBase *v2 = _Elements[index2].Element;
1332 if (index1 < index2)
1334 delChild(index2);
1335 delChild(index1);
1336 addChildAtIndex(v2, index1, oldMustDelete2);
1337 setOrder(index1, order2);
1338 addChildAtIndex(v1, index2, oldMustDelete1);
1339 setOrder(index2, order1);
1341 else
1343 delChild(index1);
1344 delChild(index2);
1345 addChildAtIndex(v1, index2, oldMustDelete1);
1346 setOrder(index2, order1);
1347 addChildAtIndex(v2, index1, oldMustDelete2);
1348 setOrder(index1, order2);
1352 // ----------------------------------------------------------------------------
1353 void CGroupParagraph::deleteAllChildren()
1355 uint numChildren = getNbElement();
1356 for(uint k = 0; k < numChildren; ++k)
1358 delChild(numChildren - 1 - k); // delete in reverse order to avoid unnecessary vector copies
1362 // ----------------------------------------------------------------------------
1363 uint CGroupParagraph::getNumActiveChildren() const
1365 uint numChildren = 0;
1366 for(uint k = 0; k < _Elements.size(); ++k)
1368 if (_Elements[k].Element->getActive()) ++numChildren;
1370 return numChildren;
1373 // ----------------------------------------------------------------------------
1374 void CGroupParagraph::setDelOnRemove(uint index, bool delOnRemove)
1376 if (index >= _Elements.size())
1378 nlwarning("bad index");
1379 return;
1381 _Elements[index].EltDeleteOnRemove = delOnRemove;
1384 // ----------------------------------------------------------------------------
1385 bool CGroupParagraph::getDelOnRemove(uint index) const
1387 if (index >= _Elements.size())
1389 nlwarning("bad index");
1390 return false;
1392 return _Elements[index].EltDeleteOnRemove;
1395 // ----------------------------------------------------------------------------
1396 void CGroupParagraph::addChildLink (CViewLink* child, bool deleteOnRemove)
1398 // Add the child
1399 addChild (child, deleteOnRemove);
1401 // Add the link
1402 _Links.push_back (CLink(child));
1405 // ----------------------------------------------------------------------------
1406 CGroupParagraph::CLink::CLink (CViewLink *link)
1408 Link = link;
1409 CtrlLink[0] = NULL;
1410 CtrlLink[1] = NULL;
1411 CtrlLink[2] = NULL;
1414 // ----------------------------------------------------------------------------
1415 void CGroupParagraph::onInvalidateContent()
1417 _ContentValidated = false;
1418 invalidateCoords();
1421 // ----------------------------------------------------------------------------
1422 sint32 CGroupParagraph::getMaxUsedW() const
1424 // The paragraph max is the sum of the components max
1425 sint maxWidth = 0;
1426 for (uint k = 0; k < _Elements.size(); ++k)
1428 // Get the child width
1429 maxWidth += _Elements[k].Element->getMaxUsedW();
1431 return maxWidth + _MarginLeft;
1434 // ----------------------------------------------------------------------------
1435 sint32 CGroupParagraph::getMinUsedW() const
1437 // The paragraph min is the max of the components min
1438 sint32 minWidth = 0;
1439 for (uint k = 0; k < _Elements.size(); ++k)
1441 // Get the child width
1442 sint32 width = _Elements[k].Element->getMinUsedW();
1443 if (width > minWidth)
1444 minWidth = width;
1446 return minWidth + _MarginLeft;
1450 void CGroupParagraph::setupSizes()
1452 EAlign addElt = _AddElt;
1453 _GroupSizeRef = _SizeRef;
1454 if ((addElt == Top) || (addElt == Bottom))
1456 setMaxW (_W);
1457 setMaxH(_H);
1458 _H = 0;
1459 _SizeRef = _SizeRef&(~2);
1461 else
1463 setMaxW (_W);
1464 setMaxH (_H);
1465 _W = 0;
1466 _SizeRef = _SizeRef&(~1);
1471 void CGroupParagraph::onTextChanged()
1473 if( _Elements.empty() )
1474 return;
1476 CElementInfo &e = _Elements[ 0 ];
1478 CViewText *t = dynamic_cast< CViewText* >( e.Element );
1479 if( t != NULL )
1481 t->setText( _HardText );
1482 return;
1484 else
1486 CViewTextID *ti = dynamic_cast< CViewTextID* >( e.Element );
1487 if( ti != NULL )
1489 ti->setTextId( _TextId );