Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / group_tree.cpp
blob2fecc005deaeda67f58f6fb92206650a723a56bf
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/>.
22 #include "stdpch.h"
23 #include "nel/gui/group_tree.h"
24 #include "nel/gui/interface_element.h"
25 #include "nel/gui/view_bitmap.h"
26 #include "nel/gui/view_text.h"
27 #include "nel/gui/group_container_base.h"
28 #include "nel/gui/action_handler.h"
29 #include "nel/gui/lua_ihm.h"
30 #include "nel/misc/i_xml.h"
31 #include "nel/misc/i18n.h"
32 #include "nel/misc/xml_auto_ptr.h"
33 #include "nel/gui/widget_manager.h"
34 #include "nel/gui/view_renderer.h"
35 #include "nel/gui/view_pointer_base.h"
37 using namespace std;
38 using namespace NLMISC;
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 namespace NLGUI
47 // ----------------------------------------------------------------------------
48 // SNode
49 // ----------------------------------------------------------------------------
50 // TestYoyo
51 //uint SNodeCount= 0;
52 // ----------------------------------------------------------------------------
53 CGroupTree::SNode::SNode()
55 Opened = false;
56 Father = NULL;
57 FontSize = -1;
58 YDecal = 0;
59 DisplayText = true;
60 Template = NULL;
61 Show= true;
62 NodeAddedCallback = NULL;
63 Color = CRGBA::White;
64 ParentTree = NULL;
65 LastVisibleSon = NULL;
66 // TestYoyo
67 //nlinfo("SNode(): %8x, c%d", this, SNodeCount++);
70 // ----------------------------------------------------------------------------
71 void CGroupTree::SNode::updateLastVisibleSon()
73 LastVisibleSon = NULL;
74 if (!Show || !Opened) return;
75 for (sint sonIndex = (sint)Children.size() - 1; sonIndex >= 0; -- sonIndex)
77 if (Children[sonIndex]->Show)
79 LastVisibleSon = Children[sonIndex];
80 break;
83 for(uint k = 0; k < Children.size(); ++k)
85 Children[k]->updateLastVisibleSon();
89 // ----------------------------------------------------------------------------
90 CGroupTree::SNode::~SNode()
92 makeOrphan();
93 // IMPORTANT : must delete in reverse order because "makeOrphan" is called when deleting sons, thus changing vector size...
94 for (sint i = (sint)Children.size() - 1; i >= 0; --i)
95 delete Children[i];
96 Children.clear();
97 // TestYoyo
98 //nlinfo("~SNode(): %8x, c%d", this, --SNodeCount);
101 void CGroupTree::SNode::setParentTree(CGroupTree *parent)
103 ParentTree = parent;
104 for (uint k = 0; k < Children.size(); ++k)
106 Children[k]->setParentTree(parent);
110 void CGroupTree::SNode::setFather(SNode *father)
112 Father = father;
113 setParentTree(father ? father->ParentTree : NULL);
117 CGroupTree::SNode *CGroupTree::SNode::getNodeFromId(const std::string &id)
119 if (Id == id) return this;
120 // breadth first
121 for (uint k = 0; k < Children.size(); ++k)
123 if (Children[k]->Id == id)
125 return Children[k];
128 for (uint k = 0; k < Children.size(); ++k)
130 SNode *found = Children[k]->getNodeFromId(id);
131 if (found) return found;
133 return NULL;
137 void CGroupTree::SNode::makeOrphan()
139 if (ParentTree)
141 ParentTree->forceRebuild();
142 setParentTree(NULL);
145 if (Template != NULL)
147 if (Template->getParent())
149 // don't delete because may want to keep it. NB: deleted by smartptr at dtor
150 Template->getParent()->delGroup(Template, true);
154 if (Father)
156 Father->detachChild(this);
157 Father = NULL;
161 // ----------------------------------------------------------------------------
162 struct CNodeSorter
164 bool operator()(const CGroupTree::SNode *lhs, const CGroupTree::SNode *rhs) const
166 return lhs->Text < rhs->Text;
170 // ----------------------------------------------------------------------------
171 void CGroupTree::SNode::sort()
173 std::sort(Children.begin(), Children.end(), CNodeSorter());
174 for(uint k = 0; k < Children.size(); ++k)
176 Children[k]->sort();
181 // ----------------------------------------------------------------------------
182 struct CNodeSorterByBitmap
184 bool operator()(const CGroupTree::SNode *lhs, const CGroupTree::SNode *rhs) const
186 if (lhs->Bitmap != rhs->Bitmap) return lhs->Bitmap < rhs->Bitmap;
187 return lhs->Text < rhs->Text;
191 // ----------------------------------------------------------------------------
192 void CGroupTree::SNode::sortByBitmap()
194 std::sort(Children.begin(), Children.end(), CNodeSorterByBitmap());
195 for(uint k = 0; k < Children.size(); ++k)
197 Children[k]->sortByBitmap();
201 // ----------------------------------------------------------------------------
202 void CGroupTree::SNode::addChild (SNode *pNode)
204 if(!pNode) return;
205 pNode->makeOrphan();
206 Children.push_back(pNode);
207 pNode->setFather(this);
210 // ----------------------------------------------------------------------------
211 void CGroupTree::SNode::addChildSorted(SNode *pNode)
213 if (!pNode) return;
214 pNode->makeOrphan();
215 std::vector<SNode*>::iterator it = std::lower_bound(Children.begin(), Children.end(), pNode, CNodeSorter());
216 Children.insert(it, pNode);
217 pNode->setFather(this);
220 // ----------------------------------------------------------------------------
221 void CGroupTree::SNode::addChildSortedByBitmap(SNode *pNode)
223 if (!pNode) return;
224 pNode->makeOrphan();
225 std::vector<SNode*>::iterator it = std::lower_bound(Children.begin(), Children.end(), pNode, CNodeSorterByBitmap());
226 Children.insert(it, pNode);
227 pNode->setFather(this);
230 // ----------------------------------------------------------------------------
231 bool CGroupTree::SNode::isChild(SNode *pNode) const
233 return std::find(Children.begin(), Children.end(), pNode) != Children.end();
236 // ----------------------------------------------------------------------------
237 void CGroupTree::SNode::detachChild(SNode *pNode)
239 nlassert(pNode);
240 nlassert(isChild(pNode));
241 Children.erase(std::remove(Children.begin(), Children.end(), pNode), Children.end());
242 pNode->setFather(NULL);
245 // ----------------------------------------------------------------------------
246 void CGroupTree::SNode::deleteChild(SNode *pNode)
248 delete pNode;
251 // ----------------------------------------------------------------------------
252 void CGroupTree::SNode::addChildFront (SNode *pNode)
254 if(!pNode) return;
255 pNode->makeOrphan();
256 Children.insert(Children.begin(), pNode);
257 pNode->setFather(this);
260 // ----------------------------------------------------------------------------
261 void CGroupTree::SNode::addChildAtIndex(SNode *pNode, sint index)
263 if(!pNode) return;
264 if (index < 0 || index > (sint) Children.size())
266 nlwarning("<CGroupTree::SNode::addChildAtIndex> bad index %d (%d elements in the vector)", index, Children.size());
267 return;
269 pNode->makeOrphan();
270 if (pNode->Father)
272 pNode->Father->detachChild(pNode);
274 Children.insert(Children.begin() + index, pNode);
275 pNode->setFather(this);
278 // ----------------------------------------------------------------------------
279 void CGroupTree::SNode::openAll()
281 Opened = true;
282 for (uint i = 0; i < Children.size(); ++i)
283 Children[i]->openAll();
286 // ----------------------------------------------------------------------------
287 void CGroupTree::SNode::closeAll()
289 Opened = false;
290 for (uint i = 0; i < Children.size(); ++i)
291 Children[i]->closeAll();
294 // ----------------------------------------------------------------------------
295 bool CGroupTree::SNode::parse (xmlNodePtr cur, CGroupTree * parentGroup)
297 if (stricmp((char*)cur->name, "node") == 0)
299 CXMLAutoPtr id((const char*) xmlGetProp (cur, (xmlChar*)"id"));
300 if (id)
301 Id = (const char*)id;
302 else
303 Id = toString(parentGroup->getIdNumber());
305 CXMLAutoPtr name((const char*) xmlGetProp (cur, (xmlChar*)"name"));
307 if (name)
309 const char *ptrName = (const char*)name;
310 if (NLMISC::startsWith(ptrName, "ui"))
311 Text = CI18N::get(ptrName);
312 else
313 Text = ptrName;
316 CXMLAutoPtr color((const char*) xmlGetProp (cur, (xmlChar*)"color"));
317 if (color)
319 Color = convertColor(color);
322 CXMLAutoPtr open((const char*) xmlGetProp (cur, (xmlChar*)"opened"));
323 if (open) Opened = convertBool(open);
325 CXMLAutoPtr show((const char*) xmlGetProp (cur, (xmlChar*)"show"));
326 if (open) Show = convertBool(show);
328 CXMLAutoPtr ah((const char*) xmlGetProp (cur, (xmlChar*)"handler"));
329 if (ah) AHName = (const char*)ah;
330 CXMLAutoPtr cond((const char*) xmlGetProp (cur, (xmlChar*)"cond"));
331 if (cond) AHCond = (const char*)cond;
332 CXMLAutoPtr params((const char*) xmlGetProp (cur, (xmlChar*)"params"));
333 if (params) AHParams = (const char*)params;
335 CXMLAutoPtr ahRight((const char*) xmlGetProp (cur, (xmlChar*)"handler_right"));
336 if (ahRight) AHNameRight = (const char*)ahRight;
337 CXMLAutoPtr paramsRight((const char*) xmlGetProp (cur, (xmlChar*)"params_right"));
338 if (paramsRight) AHParamsRight = (const char*)paramsRight;
340 CXMLAutoPtr bitmap((const char*) xmlGetProp (cur, (xmlChar*)"bitmap"));
341 if (bitmap) Bitmap = (const char*)bitmap;
343 FontSize = parentGroup->getFontSize();
344 CXMLAutoPtr fs((const char*) xmlGetProp (cur, (xmlChar*)"fontsize"));
345 if (fs) fromString((const char*)fs, FontSize);
347 YDecal = parentGroup->getYDecal();
348 CXMLAutoPtr yDecalPtr((const char*) xmlGetProp (cur, (xmlChar*)"y_decal"));
349 if (yDecalPtr) fromString((const char*)yDecalPtr, YDecal);
352 xmlNodePtr child = cur->children;
354 while (child != NULL)
356 SNode *pNode = new SNode;
357 pNode->parse (child, parentGroup);
358 addChild(pNode);
359 child = child->next;
363 return true;
366 // ----------------------------------------------------------------------------
367 // CGroupTree
368 // ----------------------------------------------------------------------------
370 NLMISC_REGISTER_OBJECT(CViewBase, CGroupTree, std::string, "tree");
372 // ----------------------------------------------------------------------------
373 CGroupTree::CGroupTree(const TCtorParam &param)
374 :CInterfaceGroup(param)
376 _IdGenerator = 0;
377 _XExtend= 0;
378 _BmpW = 14;
379 _BmpH = 14;
380 _FontSize = 12;
381 _YDecal = 0;
382 _MustRebuild = true;
383 _OverColor = CRGBA(255, 255, 255, 128);
384 _OverColorBack = CRGBA(64, 64, 64, 255);
385 _SelectedNode = NULL;
386 _SelectedLine = -1;
387 _SelectedColor = CRGBA(255, 128, 128, 128);
388 _RootNode = NULL;
389 _OverLine = -1;
390 _SelectAncestorOnClose= false;
391 _NavigateOneBranch= false;
393 _ArboOpenFirst= "arbo_open_first.tga";
394 _ArboCloseJustOne= "arbo_close_just_one.tga";
395 _ArboSonWithoutSon= "arbo_son_without_son.tga";
396 _ArboSonLast= "arbo_son_last.tga";
397 _ArboSon= "arbo_son.tga";
398 _ArboLevel= "arbo_level.tga";
400 _RectangleOutlineMode= false;
401 _RectangleX= 0;
402 _RectangleY= 0;
403 _RectangleW= 10;
404 _RectangleH= 10;
405 _RectangleDeltaRL= 0;
407 _AvoidSelectNodeByIdIR= false;
410 // ----------------------------------------------------------------------------
411 CGroupTree::~CGroupTree()
413 removeAll();
414 if (_RootNode != NULL) delete _RootNode;
417 std::string CGroupTree::getProperty( const std::string &name ) const
419 if( name == "col_over" )
421 return toString( _OverColor );
423 else
424 if( name == "col_select" )
426 return toString( _SelectedColor );
428 else
429 if( name == "col_over_back" )
431 return toString( _OverColorBack );
433 else
434 if( name == "fontsize" )
436 return toString( _FontSize );
438 else
439 if( name == "select_ancestor_on_close" )
441 return toString( _SelectAncestorOnClose );
443 else
444 if( name == "navigate_one_branch" )
446 return toString( _NavigateOneBranch );
448 else
449 if( name == "arbo_open_first" )
451 return _ArboOpenFirst;
453 else
454 if( name == "arbo_close_just_one" )
456 return _ArboCloseJustOne;
458 else
459 if( name == "arbo_son_without_son" )
461 return _ArboSonWithoutSon;
463 else
464 if( name == "arbo_son_last" )
466 return _ArboSonLast;
468 else
469 if( name == "arbo_son" )
471 return _ArboSon;
473 else
474 if( name == "arbo_x_extend" )
476 return _ArboXExtend;
478 else
479 if( name == "arbo_level" )
481 return _ArboLevel;
483 if( name == "rectangle_outline" )
485 return toString( _RectangleOutlineMode );
487 else
488 if( name == "rectangle_x" )
490 return toString( _RectangleX );
492 else
493 if( name == "rectangle_y" )
495 return toString( _RectangleY );
497 else
498 if( name == "rectangle_w" )
500 return toString( _RectangleW );
502 else
503 if( name == "rectangle_h" )
505 return toString( _RectangleH );
507 else
508 if( name == "rectangle_drl" )
510 return toString( _RectangleDeltaRL );
512 else
513 return CInterfaceGroup::getProperty( name );
516 void CGroupTree::setProperty( const std::string &name, const std::string &value )
518 if( name == "col_over" )
520 CRGBA c;
521 if( fromString( value, c ) )
522 _OverColor = c;
523 return;
525 else
526 if( name == "col_select" )
528 CRGBA c;
529 if( fromString( value, c ) )
530 _SelectedColor = c;
531 return;
533 else
534 if( name == "col_over_back" )
536 CRGBA c;
537 if( fromString( value, c ) )
538 _OverColorBack = c;
539 return;
541 else
542 if( name == "fontsize" )
544 sint32 i;
545 if( fromString( value, i ) )
546 _FontSize = i;
547 return;
549 else
550 if( name == "select_ancestor_on_close" )
552 bool b;
553 if( fromString( value, b ) )
554 _SelectAncestorOnClose = b;
555 return;
557 else
558 if( name == "navigate_one_branch" )
560 bool b;
561 if( fromString( value, b ) )
562 _NavigateOneBranch = b;
563 return;
565 else
566 if( name == "arbo_open_first" )
568 _ArboOpenFirst = value;
569 setupArbo();
570 return;
572 else
573 if( name == "arbo_close_just_one" )
575 _ArboCloseJustOne = value;
576 return;
578 else
579 if( name == "arbo_son_without_son" )
581 _ArboSonWithoutSon = value;
582 return;
584 else
585 if( name == "arbo_son_last" )
587 _ArboSonLast = value;
588 return;
590 else
591 if( name == "arbo_son" )
593 _ArboSon = value;
594 return;
596 else
597 if( name == "arbo_x_extend" )
599 _ArboXExtend = value;
600 setupArbo();
601 return;
603 else
604 if( name == "arbo_level" )
606 _ArboLevel = value;
607 return;
609 if( name == "rectangle_outline" )
611 bool b;
612 if( fromString( value, b ) )
613 _RectangleOutlineMode = b;
614 return;
616 else
617 if( name == "rectangle_x" )
619 sint32 i;
620 if( fromString( value, i ) )
621 _RectangleX = i;
622 return;
624 else
625 if( name == "rectangle_y" )
627 sint32 i;
628 if( fromString( value, i ) )
629 _RectangleY = i;
630 return;
632 else
633 if( name == "rectangle_w" )
635 sint32 i;
636 if( fromString( value, i ) )
637 _RectangleW = i;
638 return;
640 else
641 if( name == "rectangle_h" )
643 sint32 i;
644 if( fromString( value, i ) )
645 _RectangleH = i;
646 return;
648 else
649 if( name == "rectangle_drl" )
651 sint32 i;
652 if( fromString( value, i ) )
653 _RectangleDeltaRL = i;
654 return;
656 else
657 CInterfaceGroup::setProperty( name, value );
660 xmlNodePtr CGroupTree::serialize( xmlNodePtr parentNode, const char *type ) const
662 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
663 if( node == NULL )
664 return NULL;
666 xmlSetProp( node, BAD_CAST "type", BAD_CAST "tree" );
667 xmlSetProp( node, BAD_CAST "col_over", BAD_CAST toString( _OverColor ).c_str() );
668 xmlSetProp( node, BAD_CAST "col_select", BAD_CAST toString( _SelectedColor ).c_str() );
669 xmlSetProp( node, BAD_CAST "col_over_back", BAD_CAST toString( _OverColorBack ).c_str() );
670 xmlSetProp( node, BAD_CAST "fontsize", BAD_CAST toString( _FontSize ).c_str() );
671 xmlSetProp( node, BAD_CAST "select_ancestor_on_close", BAD_CAST toString( _SelectAncestorOnClose ).c_str() );
672 xmlSetProp( node, BAD_CAST "navigate_one_branch", BAD_CAST toString( _NavigateOneBranch ).c_str() );
673 xmlSetProp( node, BAD_CAST "arbo_open_first", BAD_CAST _ArboOpenFirst.c_str() );
674 xmlSetProp( node, BAD_CAST "arbo_close_just_one", BAD_CAST _ArboCloseJustOne.c_str() );
675 xmlSetProp( node, BAD_CAST "arbo_son_without_son", BAD_CAST _ArboSonWithoutSon.c_str() );
676 xmlSetProp( node, BAD_CAST "arbo_son_last", BAD_CAST _ArboSonLast.c_str() );
677 xmlSetProp( node, BAD_CAST "arbo_son", BAD_CAST _ArboSon.c_str() );
678 xmlSetProp( node, BAD_CAST "arbo_x_extend", BAD_CAST _ArboXExtend.c_str() );
679 xmlSetProp( node, BAD_CAST "arbo_level", BAD_CAST _ArboLevel.c_str() );
680 xmlSetProp( node, BAD_CAST "rectangle_outline", BAD_CAST toString( _RectangleOutlineMode ).c_str() );
681 xmlSetProp( node, BAD_CAST "rectangle_x", BAD_CAST toString( _RectangleX ).c_str() );
682 xmlSetProp( node, BAD_CAST "rectangle_y", BAD_CAST toString( _RectangleY ).c_str() );
683 xmlSetProp( node, BAD_CAST "rectangle_w", BAD_CAST toString( _RectangleW ).c_str() );
684 xmlSetProp( node, BAD_CAST "rectangle_h", BAD_CAST toString( _RectangleH ).c_str() );
685 xmlSetProp( node, BAD_CAST "rectangle_drl", BAD_CAST toString( _RectangleDeltaRL ).c_str() );
687 return node;
690 // ----------------------------------------------------------------------------
691 bool CGroupTree::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup)
693 if (!CInterfaceGroup::parse(cur, parentGroup))
694 return false;
696 CXMLAutoPtr ptr;
698 ptr = (char*) xmlGetProp (cur, (xmlChar*)"col_over");
699 if (ptr) _OverColor = convertColor(ptr);
700 ptr = (char*) xmlGetProp (cur, (xmlChar*)"col_select");
701 if (ptr) _SelectedColor = convertColor(ptr);
702 ptr = (char*) xmlGetProp (cur, (xmlChar*)"col_over_back");
703 if (ptr) _OverColorBack = convertColor(ptr);
705 ptr = (char*) xmlGetProp (cur, (xmlChar*)"fontsize");
706 if (ptr) fromString((const char*)ptr, _FontSize);
707 ptr = (char*) xmlGetProp (cur, (xmlChar*)"select_ancestor_on_close");
708 if (ptr) _SelectAncestorOnClose = convertBool(ptr);
709 ptr = (char*) xmlGetProp (cur, (xmlChar*)"navigate_one_branch");
710 if (ptr) _NavigateOneBranch = convertBool(ptr);
712 // read optional arbo bmps
713 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_open_first");
714 if (ptr) _ArboOpenFirst= (const char*)ptr;
715 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_close_just_one");
716 if (ptr) _ArboCloseJustOne= (const char*)ptr;
717 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_son_without_son");
718 if (ptr) _ArboSonWithoutSon= (const char*)ptr;
719 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_son_last");
720 if (ptr) _ArboSonLast= (const char*)ptr;
721 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_son");
722 if (ptr) _ArboSon= (const char*)ptr;
723 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_level");
724 if (ptr) _ArboLevel= (const char*)ptr;
725 ptr = (char*) xmlGetProp (cur, (xmlChar*)"arbo_x_extend");
726 if (ptr) _ArboXExtend= (const char*)ptr;
728 // Rectangle selection style
729 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_outline");
730 if (ptr) _RectangleOutlineMode= convertBool(ptr);
731 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_x");
732 if (ptr) fromString((const char*)ptr, _RectangleX);
733 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_y");
734 if (ptr) fromString((const char*)ptr, _RectangleY);
735 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_w");
736 if (ptr) fromString((const char*)ptr, _RectangleW);
737 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_h");
738 if (ptr) fromString((const char*)ptr, _RectangleH);
739 ptr = (char*) xmlGetProp (cur, (xmlChar*)"rectangle_drl");
740 if (ptr) fromString((const char*)ptr, _RectangleDeltaRL);
744 _RootNode = new SNode;
745 // bool ok = true;
746 cur = cur->children;
747 while (cur)
749 // Check that this is a camera node
750 if ( stricmp((char*)cur->name, "node") == 0 )
752 SNode *pNode = new SNode;
753 if (!pNode->parse(cur, this))
755 delete pNode;
756 nlwarning("cannot parse node");
758 else
760 _RootNode->addChild(pNode);
763 cur = cur->next;
765 _RootNode->Opened = true;
766 _ResizeFromChildW = _ResizeFromChildH = true;
768 setupArbo();
770 return true;
773 void CGroupTree::setupArbo()
775 CViewRenderer &rVR = *CViewRenderer::getInstance();
776 sint32 id = rVR.getTextureIdFromName(_ArboOpenFirst);
777 if (id != -1)
778 rVR.getTextureSizeFromId(id, _BmpW, _BmpH);
779 sint32 dummy;
780 id = rVR.getTextureIdFromName(_ArboXExtend);
781 if (id != -1)
782 rVR.getTextureSizeFromId(id, _XExtend, dummy);
783 else
784 // if not found, reset, to avoid errors
785 _ArboXExtend.clear();
788 // ----------------------------------------------------------------------------
789 sint32 CGroupTree::getHrcIconXStart(sint32 depth)
791 return depth*(_BmpW+_XExtend);
794 // ----------------------------------------------------------------------------
795 sint32 CGroupTree::getHrcIconXEnd(sint32 depth)
797 return depth*(_BmpW+_XExtend) + _BmpW;
800 // ----------------------------------------------------------------------------
801 void CGroupTree::checkCoords()
803 CInterfaceGroup::checkCoords();
806 // ----------------------------------------------------------------------------
807 void CGroupTree::updateCoords()
809 if (_MustRebuild)
810 rebuild();
811 CInterfaceGroup::updateCoords();
814 // ----------------------------------------------------------------------------
815 void CGroupTree::drawSelection(sint x, sint y, sint w, CRGBA col)
817 CViewRenderer &rVR = *CViewRenderer::getInstance();
819 if(!_RectangleOutlineMode)
821 rVR.drawRotFlipBitmap (_RenderLayer, _XReal+_OffsetX+x, _YReal+_OffsetY+y,
822 w, _BmpH, 0, false, rVR.getBlankTextureId(),
823 col );
825 else
827 // draw the outline
828 x+= _XReal+_OffsetX+_RectangleX;
829 y+= _YReal+_OffsetY+_RectangleY;
830 w= _RectangleW;
831 sint32 h= _RectangleH;
832 sint32 rl= _RenderLayer + _RectangleDeltaRL;
834 rVR.drawRotFlipBitmap (rl, x, y, 1, h, 0, false, rVR.getBlankTextureId(), col );
835 rVR.drawRotFlipBitmap (rl, x+w-1, y, 1, h, 0, false, rVR.getBlankTextureId(), col );
836 rVR.drawRotFlipBitmap (rl, x, y, w, 1, 0, false, rVR.getBlankTextureId(), col );
837 rVR.drawRotFlipBitmap (rl, x, y+h-1, w, 1, 0, false, rVR.getBlankTextureId(), col );
841 // ----------------------------------------------------------------------------
842 CGroupTree::SNode *CGroupTree::getNodeUnderMouse() const
844 if (_OverLine == -1) return NULL;
845 return _Lines[_OverLine].Node;
848 // ----------------------------------------------------------------------------
849 void CGroupTree::draw()
851 // get the clip area
852 sint32 clipx, clipy, clipw, cliph;
853 getClip(clipx, clipy, clipw, cliph);
855 // change the over
856 bool bDisplayOver = true;
858 if (!CWidgetManager::getInstance()->isMouseHandlingEnabled())
860 bDisplayOver = false;
862 else
863 if (CWidgetManager::getInstance()->getModalWindow() == NULL)
865 sint32 x = CWidgetManager::getInstance()->getPointer()->getX();
866 sint32 y = CWidgetManager::getInstance()->getPointer()->getY();
868 CInterfaceGroup *pIG = CWidgetManager::getInstance()->getWindowUnder(x, y);
869 CInterfaceGroup *pParent = this;
870 bool bFound = false;
871 while (pParent != NULL)
873 if (pParent == pIG)
875 bFound = true;
876 break;
878 pParent = pParent->getParent();
881 // if the mouse is not in the clipped area
882 if ((x < clipx) ||
883 (x > (clipx + clipw)) ||
884 (y < clipy) ||
885 (y > (clipy + cliph)) || !bFound)
887 _OverLine = -1;
889 else
891 x = x - _OffsetX;
892 y = y - _OffsetY;
893 for (sint32 i = 0; i < (sint32)_Lines.size(); ++i)
895 if ((y >= (_YReal+(sint32)(_Lines.size()-i-1)*_BmpH)) &&
896 (y < (_YReal+(sint32)(_Lines.size()-i)*_BmpH)))
898 _OverLine = i;
901 if (_OverLine != -1)
903 if (x < _XReal + getHrcIconXEnd(_Lines[_OverLine].Depth))
904 bDisplayOver = false;
909 // some over to display?
910 if ((_OverLine != -1) && bDisplayOver)
912 // Find the first container
913 CInterfaceGroup *pIG = _Parent;
914 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(pIG);
915 while (pIG != NULL)
917 pIG = pIG->getParent();
918 if (pIG == NULL) break;
919 if (dynamic_cast<CGroupContainerBase*>(pIG) != NULL)
920 pGC = dynamic_cast<CGroupContainerBase*>(pIG);
923 // avoid if window grayed
924 if (pGC != NULL)
926 if (pGC->isGrayed())
927 bDisplayOver = false;
930 // Has to display the over?
931 if (bDisplayOver)
933 // !NULL if the text over must displayed across all windows
934 CViewText *viewTextExtend= NULL;
936 // If the line is a simple Text line (not template)
937 if(_Lines[_OverLine].Node && _Lines[_OverLine].Node->DisplayText)
939 // Get the view text
940 viewTextExtend= safe_cast<CViewText*>(_Lines[_OverLine].TextOrTemplate);
941 // If this viewText is not too big, no need
942 if(viewTextExtend->getXReal() + viewTextExtend->getWReal() <= (clipx+clipw) )
943 viewTextExtend= NULL;
946 // draw simple over
947 if(!viewTextExtend)
949 CRGBA col = _OverColor;
950 if(getModulateGlobalColor())
952 col.modulateFromColor (_OverColor, CWidgetManager::getInstance()->getGlobalColorForContent());
954 else
956 col= _OverColor;
957 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
960 drawSelection( getHrcIconXEnd(_Lines[_OverLine].Depth + _Lines[_OverLine].getNumAdditionnalBitmap()), ((sint)_Lines.size()-_OverLine-1)*_BmpH,
961 _WReal-getHrcIconXEnd(_Lines[_OverLine].Depth + _Lines[_OverLine].getNumAdditionnalBitmap()), col);
963 // Draw extended over
964 else
966 CRGBA col = _OverColorBack;
967 // must add the selection color
968 if(_SelectedLine == _OverLine)
970 // simulate alpha blend of the selection bitmap
971 CRGBA sel= _SelectedColor;
972 sel.A= (uint8)((sel.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
973 col.blendFromuiRGBOnly(col, sel, sel.A);
976 // will be drawn over all the interface
977 CWidgetManager::getInstance()->setOverExtendViewText(viewTextExtend, col);
982 // some selection to display
983 if (_SelectedLine != -1)
985 CRGBA col = _SelectedColor;
986 if(getModulateGlobalColor())
988 col.modulateFromColor (_SelectedColor, CWidgetManager::getInstance()->getGlobalColorForContent());
990 else
992 col= _SelectedColor;
993 col.A = (uint8)(((sint32)col.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
996 drawSelection( getHrcIconXEnd(_Lines[_SelectedLine].Depth + _Lines[_SelectedLine].getNumAdditionnalBitmap()), ((sint)_Lines.size()-_SelectedLine-1)*_BmpH,
997 _WReal-getHrcIconXEnd(_Lines[_SelectedLine].Depth + _Lines[_SelectedLine].getNumAdditionnalBitmap()), col );
1000 CInterfaceGroup::draw();
1003 // ----------------------------------------------------------------------------
1004 void CGroupTree::selectLine(uint line, bool runAH /*= true*/)
1006 if(line>=_Lines.size())
1007 return;
1009 if (!_Lines[line].Node)
1011 // just deleted : must wait next draw to know the new line under mouse
1012 return;
1014 if (!_Lines[line].Node->AHName.empty() && runAH)
1016 _CancelNextSelectLine = false;
1018 CAHManager::getInstance()->runActionHandler ( _Lines[line].Node->AHName,
1019 this,
1020 _Lines[line].Node->AHParams );
1022 if (!_CancelNextSelectLine)
1024 _SelectedLine = line;
1025 _SelectedNode = _Lines[line].Node;
1027 CAHManager::getInstance()->runActionHandler ( _Lines[line].Node->AHName,
1028 this,
1029 _Lines[line].Node->AHParams );
1030 _CancelNextSelectLine = false;
1034 // ----------------------------------------------------------------------------
1035 bool CGroupTree::rightButton(uint line)
1037 if(line>=_Lines.size())
1038 return false;
1040 if (!_Lines[_OverLine].Node || _Lines[_OverLine].Node->AHNameRight.empty())
1041 return false;
1043 if (line != (uint) _SelectedLine) selectLine(line, false);
1045 CAHManager::getInstance()->runActionHandler ( _Lines[line].Node->AHNameRight,
1046 this,
1047 _Lines[line].Node->AHParamsRight );
1048 return true;
1053 // ----------------------------------------------------------------------------
1054 const std::string &CGroupTree::getSelectedNodeId() const
1056 if(_SelectedLine>=0 && _SelectedLine<(sint)_Lines.size() && _Lines[_SelectedLine].Node)
1058 return _Lines[_SelectedLine].Node->Id;
1060 else
1062 static string empty;
1063 return empty;
1067 // ----------------------------------------------------------------------------
1068 bool CGroupTree::handleEvent (const NLGUI::CEventDescriptor& event)
1070 if (!_Active) return false;
1071 if (CInterfaceGroup::handleEvent(event)) return true;
1072 // The line must be over (pre-selected)
1073 if (event.getType() == NLGUI::CEventDescriptor::mouse && _OverLine>=0)
1075 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
1077 if (!isIn(eventDesc.getX(), eventDesc.getY()))
1078 return false;
1080 sint32 x = eventDesc.getX() - _OffsetX;
1081 // sint32 y = eventDesc.getY() - _OffsetY;
1082 bool bText = false;
1083 if (x >= (_XReal+getHrcIconXEnd(_Lines[_OverLine].Depth + _Lines[_OverLine].getNumAdditionnalBitmap())))
1084 bText = true;
1085 bool bIcon = false;
1086 if ((x > (_XReal+getHrcIconXStart(_Lines[_OverLine].Depth)-_XExtend)) &&
1087 (x < (_XReal+getHrcIconXEnd(_Lines[_OverLine].Depth + _Lines[_OverLine].getNumAdditionnalBitmap()))))
1088 bIcon = true;
1090 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown)
1092 if (bText)
1094 return rightButton(_OverLine != -1 ? _OverLine : _SelectedLine);
1098 bool toggleOne = (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown);
1099 bool toggleAll = (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown);
1100 if (toggleOne || toggleAll)
1102 // line selection
1103 if (bText)
1105 selectLine(_OverLine);
1107 // close of node
1108 if (bIcon)
1110 SNode *changedNode= _Lines[_OverLine].Node;
1112 if (changedNode)
1114 // if "SelectAncestorOnClose" feature wanted, if it was opened before, and if some node selected
1115 if(_SelectAncestorOnClose && changedNode->Opened && _SelectedNode)
1117 // check that the selected node is a son of the closing node
1118 SNode *parent= _SelectedNode->Father;
1119 while(parent)
1121 if(parent==changedNode)
1123 // Then change selection to this parent first
1124 selectLine(_OverLine);
1125 break;
1127 parent= parent->Father;
1131 // standard hrc
1132 if(!_NavigateOneBranch)
1134 // open/close the node
1135 changedNode->Opened = !changedNode->Opened;
1136 if (toggleAll)
1138 if (changedNode->Opened)
1139 changedNode->openAll();
1140 else
1141 changedNode->closeAll();
1144 // else must close all necessary nodes.
1145 else
1147 if(changedNode->Opened)
1148 changedNode->closeAll();
1149 else
1151 // must closeAll all his brothers first.
1152 if(changedNode->Father)
1154 changedNode->Father->closeAll();
1155 changedNode->Father->Opened= true;
1157 changedNode->Opened= true;
1161 CAHManager::getInstance()->runActionHandler(changedNode->AHNameClose, this, changedNode->AHParamsClose);
1163 forceRebuild();
1165 return true;
1168 return false;
1172 // ----------------------------------------------------------------------------
1173 void CGroupTree::unselect()
1175 _SelectedLine = -1;
1176 _SelectedNode = NULL;
1179 // ----------------------------------------------------------------------------
1180 void CGroupTree::reset()
1182 unselect();
1183 if (_RootNode)
1185 _RootNode->closeAll();
1186 _RootNode->Opened = true;
1188 forceRebuild();
1191 // ----------------------------------------------------------------------------
1192 void CGroupTree::forceRebuild()
1194 _MustRebuild = true;
1195 invalidateCoords();
1198 // ----------------------------------------------------------------------------
1199 void CGroupTree::rebuild()
1201 // Remove all
1202 removeAll();
1204 if (_RootNode)
1205 _RootNode->Opened = true;
1207 // Rebuild all depending on the logic
1208 if(_RootNode)
1209 addTextLine (0, _RootNode);
1211 // Reformating
1212 sint32 sizeH = (sint32)_Lines.size()*_BmpH;
1213 for (uint i = 0; i < _Lines.size(); ++i)
1214 _Lines[i].TextOrTemplate->setY (_Lines[i].Node->YDecal + sizeH - ((1+_Lines[i].TextOrTemplate->getY())*_BmpH));
1215 // Add the hierarchy bitmaps
1216 addHierarchyBitmaps();
1217 // Find if we can display selection
1218 if (_SelectedNode != NULL)
1220 _SelectedLine = -1;
1221 for (uint i = 0; i < _Lines.size(); ++i)
1222 if (_Lines[i].Node == _SelectedNode)
1224 _SelectedLine = i;
1225 break;
1229 // Ok no more need to rebuild all this
1230 _MustRebuild = false;
1233 // ----------------------------------------------------------------------------
1234 void CGroupTree::setRootNode (SNode *pNewRoot)
1236 // reset selection
1237 _SelectedLine= -1;
1238 _SelectedNode= NULL;
1240 CRefPtr<SNode> refPtrNewRoot = pNewRoot;
1241 // clear old
1242 delete _RootNode;
1244 // If the node was deleted
1245 if (pNewRoot && !refPtrNewRoot)
1247 // NB nico : if anyone need that a day, please feel free to modify ...
1248 nlwarning("Trying to set a node that is part of the tree as root node (not supported yet ...)");
1251 // set new (may be NULL)
1252 _RootNode = pNewRoot;
1253 if(pNewRoot)
1254 pNewRoot->setParentTree(this);
1255 rebuild();
1258 // ----------------------------------------------------------------------------
1259 void CGroupTree::removeAll()
1261 // Remove (but not delete) the groups template if any
1262 for(uint i=0;i<_Lines.size();i++)
1264 if (_Lines[i].Node)
1266 if(_Lines[i].Node->Template)
1268 delGroup(_Lines[i].Node->Template, true);
1273 // Clear all lines, but don't delete templates
1274 _Lines.clear();
1276 // Delete all BmpViews and/or all text views
1277 clearViews();
1282 // ----------------------------------------------------------------------------
1283 void CGroupTree::addTextLine (uint8 nDepth, CGroupTree::SNode *pNode)
1285 pNode->setParentTree(this);
1286 if (nDepth > 0)
1288 SLine line;
1289 line.Depth = nDepth-1;
1290 line.Node = pNode;
1291 if (pNode->DisplayText)
1293 CViewText *pVT = new CViewText(TCtorParam());
1294 line.TextOrTemplate = pVT;
1295 pVT->setId("t"+toString(_Lines.size()));
1296 pVT->setText(pNode->Text);
1297 pVT->setColor(pNode->Color);
1298 if(pNode->FontSize==-1)
1299 pVT->setFontSize(_FontSize);
1300 else
1301 pVT->setFontSize(pNode->FontSize);
1303 else
1305 line.TextOrTemplate = pNode->Template;
1307 line.TextOrTemplate->setPosRef (Hotspot_BL);
1308 line.TextOrTemplate->setParentPosRef (Hotspot_BL);
1309 line.TextOrTemplate->setParent (this);
1310 line.TextOrTemplate->setParentPos (NULL);
1311 line.TextOrTemplate->setX (getHrcIconXEnd(nDepth-1 + line.getNumAdditionnalBitmap()));
1312 line.TextOrTemplate->setY ((sint32)_Lines.size());
1313 line.TextOrTemplate->setModulateGlobalColor(this->getModulateGlobalColor());
1314 if (pNode->DisplayText)
1315 addView (line.TextOrTemplate);
1316 else
1317 addGroup ((CInterfaceGroup*)line.TextOrTemplate);
1318 if (pNode->NodeAddedCallback)
1320 pNode->NodeAddedCallback->nodeAdded(pNode, line.TextOrTemplate);
1322 _Lines.push_back(line);
1325 // recurs
1326 if (pNode->Opened)
1328 // **** standard hierarchy display, or if root
1329 if(!_NavigateOneBranch || nDepth==0)
1331 for (uint i = 0; i < pNode->Children.size(); ++i)
1333 // add the branch only if want to show it
1334 if(pNode->Children[i]->Show)
1335 addTextLine (nDepth+1, pNode->Children[i]);
1338 // **** display only the branch navigated
1339 else
1341 // find the first child opened
1342 sint childOpen= -1;
1343 for (uint i = 0; i < pNode->Children.size(); ++i)
1345 // don't take hid ones
1346 if(pNode->Children[i]->Show && pNode->Children[i]->Opened)
1348 childOpen= i;
1349 break;
1353 // If some chidl opened, add just this line
1354 if(childOpen>=0)
1356 addTextLine (nDepth+1, pNode->Children[childOpen]);
1358 // else add all closed, but showable lines
1359 else
1361 for (uint i = 0; i < pNode->Children.size(); ++i)
1363 if(pNode->Children[i]->Show)
1364 addTextLine (nDepth+1, pNode->Children[i]);
1371 // ----------------------------------------------------------------------------
1372 CViewBitmap *CGroupTree::createViewBitmap(uint line, const std::string &idPrefix, const std::string &texture)
1374 CViewBitmap *pVB = new CViewBitmap(TCtorParam());
1375 pVB->setId(idPrefix+toString(_Lines.size())+"_"+toString(_Lines[line].Bmps.size()));
1376 pVB->setParent (this);
1377 pVB->setParentPos (NULL);
1378 pVB->setModulateGlobalColor(this->getModulateGlobalColor());
1379 pVB->setTexture(texture);
1380 return pVB;
1383 // ----------------------------------------------------------------------------
1384 void CGroupTree::addHierarchyBitmaps ()
1386 if (_RootNode) _RootNode->updateLastVisibleSon();
1387 for (uint nLayer = 0; nLayer < 256; nLayer++)
1389 sint32 nCurRootLine = -1;
1390 bool bCurRootLineLast = false;
1391 bool bCurRootLineLastChild = false;
1392 for (uint nLine = 0; nLine < _Lines.size(); nLine++)
1393 if (nLayer <= _Lines[nLine].Depth)
1395 // A Bitmap must be created
1396 CViewBitmap *pVB = createViewBitmap(nLine, "t", "blank.tga");
1397 pVB->setX (getHrcIconXStart(nLayer));
1398 pVB->setY ((sint32)_Lines.size()*_BmpH - ((1+nLine)*_BmpH));
1400 bool bAddBitmap = true;
1401 bool bAddXExtendBitmap = false;
1402 // Choose a bitmap
1403 // Are we on the last depth in the line ?
1404 if (_Lines[nLine].Depth == nLayer)
1406 nCurRootLine = nLine;
1407 if (_Lines[nLine].Node == _Lines[nCurRootLine].Node->Father->LastVisibleSon)
1408 bCurRootLineLast = true;
1409 else
1410 bCurRootLineLast = false;
1411 bCurRootLineLastChild = false;
1413 // do i have some child shown?
1414 bool haveSomeVisibleChild= false;
1415 for(uint k=0;k<_Lines[nLine].Node->Children.size();k++)
1417 if(_Lines[nLine].Node->Children[k]->Show)
1419 haveSomeVisibleChild= true;
1420 break;
1424 // if so
1425 if (haveSomeVisibleChild)
1427 // Yes am I opened ?
1428 if (_Lines[nLine].Node->Opened)
1430 pVB->setTexture(_ArboOpenFirst);
1432 else
1434 // No I am closed
1435 pVB->setTexture(_ArboCloseJustOne);
1438 else
1441 // No child
1442 // If there's a bitmap on this line , left an empty bitmap
1443 if (!_Lines[nLine].Node->Bitmap.empty())
1445 pVB->setTexture("blank.tga"); // create a transparent bitmap to have correct "child_resize_w"
1446 pVB->setColor(CRGBA(0, 0, 0, 0));
1448 else
1450 pVB->setTexture(_ArboSonWithoutSon);
1453 pVB->setTexture(_ArboSonWithoutSon);
1456 // if not the root line, must add Extend Bitmap
1457 if(nLayer)
1458 bAddXExtendBitmap= true;
1460 else
1462 // No we are before the last depth, Do we have any current root ?
1463 if (nCurRootLine != -1)
1465 // Yes, do the current line is child of current root line ?
1466 bool bFound = false;
1467 for (uint i = 0; i < _Lines[nCurRootLine].Node->Children.size(); ++i)
1468 if (_Lines[nLine].Node == _Lines[nCurRootLine].Node->Children[i])
1470 bFound = true;
1471 break;
1473 if (bFound)
1475 // is it the last child ?
1476 bool lastSonDisplay= _Lines[nLine].Node == _Lines[nCurRootLine].Node->LastVisibleSon;
1479 // Special for _NavigateOneBranch mode
1480 if(_NavigateOneBranch)
1482 // if node opened, then his brother are hid! => he behaves like a "last son"
1483 if(_Lines[nLine].Node->Opened)
1484 lastSonDisplay= true;
1487 // if must display like last child
1488 if (lastSonDisplay)
1490 // Yes this is the last child
1491 pVB->setTexture(_ArboSonLast);
1492 bCurRootLineLastChild = true;
1494 else
1496 // No so we have brothers
1497 pVB->setTexture(_ArboSon);
1500 else
1502 // Not found, display a line
1503 pVB->setTexture(_ArboLevel);
1505 // We have to not display a line if we have passed the last child of this root
1506 // We never have to display a line also if we are in _NavigateOneBranch mode
1507 if (bCurRootLineLastChild || _NavigateOneBranch)
1508 bAddBitmap = false;
1513 // Add the bitmap
1514 if (bAddBitmap)
1516 addView (pVB);
1517 _Lines[nLine].Bmps.push_back(pVB);
1519 // if must add the special extend bitmap, and if exist
1520 if(bAddXExtendBitmap && !_ArboXExtend.empty())
1522 CViewBitmap *pVB = createViewBitmap(nLine, "ext_t", _ArboXExtend);
1523 pVB->setX (getHrcIconXStart(nLayer) - _XExtend);
1524 pVB->setY ((sint32)_Lines.size()*_BmpH - ((1+nLine)*_BmpH));
1525 addView (pVB);
1526 _Lines[nLine].Bmps.push_back(pVB);
1529 else
1531 delete pVB;
1535 // add additionnal bitmap for each line
1536 for (uint nLine = 0; nLine < _Lines.size(); nLine++)
1538 if (!_Lines[nLine].Node->Bitmap.empty())
1540 CViewBitmap *pVB = createViewBitmap(nLine, "custom_bm", _Lines[nLine].Node->Bitmap);
1541 pVB->setX (getHrcIconXStart(_Lines[nLine].Depth + 1));
1542 pVB->setY ((sint32)_Lines.size()*_BmpH - ((1+nLine)*_BmpH));
1543 _Lines[nLine].Bmps.push_back(pVB);
1544 addView (pVB);
1549 // ***************************************************************************
1550 CGroupTree::SNode *CGroupTree::selectNodeByIdRecurse(SNode *pNode, const std::string &nodeId)
1552 // select this node?
1553 if(pNode!=_RootNode)
1555 if(pNode->Id == nodeId)
1556 return pNode;
1559 // try with sons
1560 for(uint i=0;i<pNode->Children.size();i++)
1562 SNode *ret= selectNodeByIdRecurse(pNode->Children[i], nodeId);
1563 if(ret)
1564 return ret;
1567 // not found => NULL
1568 return NULL;
1571 // ***************************************************************************
1572 bool CGroupTree::selectNodeById(const std::string &nodeId, bool triggerAH)
1574 SNode *selNode= NULL;
1576 // Avoid infinite recurs
1577 if(_AvoidSelectNodeByIdIR)
1578 return true;
1580 // first find in the hierarchy
1581 selNode= selectNodeByIdRecurse(_RootNode, nodeId);
1583 // if found
1584 if(selNode)
1586 // Opens the hierarchy
1587 SNode *pFather = selNode->Father;
1588 while(pFather != NULL)
1590 pFather->Opened = true;
1591 pFather = pFather->Father;
1594 if (triggerAH)
1596 // runAH may infinite recurs (HTML browse...)
1597 _AvoidSelectNodeByIdIR= true;
1599 // launch the action handler
1600 CAHManager::getInstance()->runActionHandler ( selNode->AHName,
1601 this,
1602 selNode->AHParams );
1605 // runAH may infinite recurs (HTML browse...)
1606 _AvoidSelectNodeByIdIR= false;
1608 // mark as selected
1609 _SelectedNode = selNode;
1611 forceRebuild();
1613 return true;
1615 else
1617 return false;
1621 // ***************************************************************************
1622 class CHandlerTreeReset : public IActionHandler
1624 public:
1625 void execute (CCtrlBase * /* pCaller */, const std::string &sParams)
1627 CGroupTree *pTree = dynamic_cast<CGroupTree*>(CWidgetManager::getInstance()->getElementFromId(sParams));
1628 if (pTree != NULL)
1629 pTree->reset();
1631 protected:
1633 REGISTER_ACTION_HANDLER( CHandlerTreeReset, "tree_reset");
1635 // ***************************************************************************
1636 void CGroupTree::changeNavigateOneBranch(bool newState)
1638 if(newState!=_NavigateOneBranch)
1640 _NavigateOneBranch= newState;
1641 // if new is true, then must reset both open state and selection
1642 if(_NavigateOneBranch)
1644 reset();
1645 // reselect the first line
1646 selectLine(0);
1648 // else just rebuild
1649 else
1651 forceRebuild();
1656 // ***************************************************************************
1657 void CGroupTree::cancelNextSelectLine()
1659 _CancelNextSelectLine = true;
1662 // ***************************************************************************
1663 int CGroupTree::luaGetRootNode(CLuaState &ls)
1665 CLuaIHM::checkArgCount(ls, "getRootNode", 0);
1666 CLuaIHM::pushReflectableOnStack(ls, getRootNode());
1667 return 1;
1670 // ***************************************************************************
1671 int CGroupTree::luaSetRootNode(CLuaState &ls)
1673 CLuaIHM::checkArgCount(ls, "setRootNode", 1);
1674 if (ls.isNil())
1676 setRootNode(NULL);
1677 return 0;
1679 setRootNode(SNode::luaGetNodeOnStack(ls, "CGroupTree::setRootNode"));
1680 return 0;
1684 // ***************************************************************************
1685 int CGroupTree::luaForceRebuild(CLuaState &ls)
1687 CLuaIHM::checkArgCount(ls, "forceRebuild", 0);
1688 forceRebuild();
1689 return 0;
1692 // ***************************************************************************
1693 CGroupTree::SNode *CGroupTree::SNode::luaGetNodeOnStack(CLuaState &ls, const char * /* funcName */)
1695 SNode *node = dynamic_cast<CGroupTree::SNode *>(CLuaIHM::getReflectableOnStack(ls, 1));
1696 CLuaIHM::check(ls, node != NULL, "SNode expected");
1697 return node;
1700 // ***************************************************************************
1701 int CGroupTree::SNode::luaDetachChild(CLuaState &ls)
1703 const char *funcName = "CGroupTree::SNode::luaDetachChild";
1704 CLuaIHM::checkArgCount(ls, funcName, 1);
1705 detachChild(luaGetNodeOnStack(ls, funcName));
1706 return 0;
1709 // ***************************************************************************
1710 int CGroupTree::SNode::luaSort(CLuaState &ls)
1712 const char *funcName = "CGroupTree::SNode::luaSort";
1713 CLuaIHM::checkArgCount(ls, funcName, 0);
1714 sort();
1715 return 0;
1718 // ***************************************************************************
1719 int CGroupTree::SNode::luaSortByBitmap(CLuaState &ls)
1721 const char *funcName = "CGroupTree::SNode::luaSort";
1722 CLuaIHM::checkArgCount(ls, funcName, 0);
1723 sortByBitmap();
1724 return 0;
1727 // ***************************************************************************
1728 int CGroupTree::SNode::luaDeleteChild(CLuaState &ls)
1730 const char *funcName = "CGroupTree::SNode::luaDeleteChild";
1731 CLuaIHM::checkArgCount(ls, funcName, 1);
1732 deleteChild(luaGetNodeOnStack(ls, funcName));
1733 return 0;
1736 // ***************************************************************************
1737 int CGroupTree::SNode::luaAddChild(CLuaState &ls)
1739 const char *funcName = "CGroupTree::SNode::luaAddChild";
1740 CLuaIHM::checkArgCount(ls, funcName, 1);
1741 addChild(luaGetNodeOnStack(ls, funcName));
1742 return 0;
1745 // ***************************************************************************
1746 int CGroupTree::SNode::luaAddChildSorted(CLuaState &ls)
1748 const char *funcName = "CGroupTree::SNode::luaAddChildSorted";
1749 CLuaIHM::checkArgCount(ls, funcName, 1);
1750 addChildSorted(luaGetNodeOnStack(ls, funcName));
1751 return 0;
1754 // ***************************************************************************
1755 int CGroupTree::SNode::luaAddChildSortedByBitmap(CLuaState &ls)
1757 const char *funcName = "CGroupTree::SNode::luaAddChildSortedByBitmap";
1758 CLuaIHM::checkArgCount(ls, funcName, 1);
1759 addChildSorted(luaGetNodeOnStack(ls, funcName));
1760 return 0;
1763 // ***************************************************************************
1764 int CGroupTree::SNode::luaGetNodeFromId(CLuaState &ls)
1766 const char *funcName = "CGroupTree::SNode::luaGetNodeFromId";
1767 CLuaIHM::checkArgCount(ls, funcName, 1);
1768 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1769 SNode *result = getNodeFromId(ls.toString(1));
1770 if (result)
1772 CLuaIHM::pushReflectableOnStack(ls, result);
1774 else
1776 ls.pushNil();
1778 return 1;
1781 // ***************************************************************************
1782 int CGroupTree::SNode::luaGetParentTree(CLuaState &ls)
1784 CLuaIHM::checkArgCount(ls, "getParentTree", 0);
1785 if (ParentTree)
1787 CLuaIHM::pushUIOnStack(ls, ParentTree);
1789 else
1791 ls.pushNil();
1793 return 1;
1796 // ***************************************************************************
1797 int CGroupTree::luaGetNodeUnderMouse(CLuaState &ls)
1799 CLuaIHM::checkArgCount(ls, "getNodeUnderMouse", 0);
1800 SNode *node = getNodeUnderMouse();
1801 if (node)
1803 CLuaIHM::pushReflectableOnStack(ls, node);
1805 else
1807 ls.pushNil();
1809 return 1;
1812 // ***************************************************************************
1813 int CGroupTree::luaCancelNextSelectLine(CLuaState &ls)
1815 CLuaIHM::checkArgCount(ls, "cancelNextSelectLine", 0);
1816 cancelNextSelectLine();
1817 return 0;
1820 // ***************************************************************************
1821 int CGroupTree::SNode::luaAddChildFront(CLuaState &ls)
1823 const char *funcName = "CGroupTree::SNode::luaAddChildFront";
1824 CLuaIHM::checkArgCount(ls, funcName, 1);
1825 addChild(luaGetNodeOnStack(ls, funcName));
1826 return 0;
1829 // ***************************************************************************
1830 int CGroupTree::SNode::luaIsChild(CLuaState &ls)
1832 const char *funcName = "CGroupTree::SNode::luaIsChild";
1833 CLuaIHM::checkArgCount(ls, funcName, 1);
1834 ls.push(isChild(luaGetNodeOnStack(ls, funcName)));
1835 return 1;
1838 // ***************************************************************************
1839 int CGroupTree::SNode::luaAddChildAtIndex(CLuaState &ls)
1841 const char *funcName = "CGroupTree::SNode::luaAddChildAtIndex";
1842 CLuaIHM::checkArgCount(ls, funcName, 2);
1843 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TNUMBER);
1844 addChildAtIndex(luaGetNodeOnStack(ls, funcName), (sint) ls.toInteger(2));
1845 return 0;
1848 // ***************************************************************************
1849 int CGroupTree::SNode::luaGetFather(CLuaState &ls)
1851 const char *funcName = "CGroupTree::SNode::luaGetFather";
1852 CLuaIHM::checkArgCount(ls, funcName, 0);
1853 if(Father)
1854 CLuaIHM::pushReflectableOnStack(ls, Father);
1855 else
1856 ls.pushNil();
1857 return 1;
1860 // ***************************************************************************
1861 int CGroupTree::SNode::luaGetNumChildren(CLuaState &ls)
1863 const char *funcName = "CGroupTree::SNode::luaGetNumChildren";
1864 CLuaIHM::checkArgCount(ls, funcName, 0);
1865 ls.push((uint)Children.size());
1866 return 1;
1869 // ***************************************************************************
1870 int CGroupTree::SNode::luaGetChild(CLuaState &ls)
1872 const char *funcName = "CGroupTree::SNode::luaGetChild";
1873 CLuaIHM::checkArgCount(ls, funcName, 1);
1874 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
1876 sint index = (sint) ls.toInteger(1);
1877 if (index < 0 || index >= (sint) Children.size())
1879 std::string range = Children.empty() ? "<empty>" : toString("[0, %d]", Children.size() - 1);
1880 CLuaIHM::fails(ls, "Bad index of tree node child : %d, range is %s", (int) index, range.c_str());
1882 CLuaIHM::pushReflectableOnStack(ls, Children[index]);
1883 return 1;
1886 // ***************************************************************************
1887 int CGroupTree::SNode::luaCloseAll(CLuaState &ls)
1889 const char *funcName = "CGroupTree::SNode::luaGetFather";
1890 CLuaIHM::checkArgCount(ls, funcName, 0);
1891 closeAll();
1892 return 0;
1895 // ***************************************************************************
1896 int CGroupTree::luaSelectNodeById(CLuaState &ls)
1898 const char *funcName = "selectNodeById";
1899 CLuaIHM::checkArgCount(ls, funcName, 2);
1900 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1901 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TBOOLEAN);
1902 selectNodeById(ls.toString(1), ls.toBoolean(2));
1903 return 0;
1906 // ***************************************************************************
1907 int CGroupTree::luaGetSelectedNodeId(CLuaState &ls)
1909 CLuaIHM::checkArgCount(ls, "getSelectedNodeId", 0);
1910 ls.push(getSelectedNodeId());
1911 return 1;
1914 // ***************************************************************************
1915 int CGroupTree::luaSelectLine(CLuaState &ls)
1917 CLuaIHM::checkArgType(ls, "CGroupTree::selectLine", 1, LUA_TNUMBER);
1918 CLuaIHM::checkArgType(ls, "CGroupTree::selectLine", 2, LUA_TBOOLEAN);
1919 selectLine((uint) ls.toInteger(1), ls.toBoolean(2));
1920 return 0;
1923 // ***************************************************************************
1924 int CGroupTree::luaUnselect(CLuaState &ls)
1926 CLuaIHM::checkArgCount(ls, "unselect", 0);
1927 unselect();
1928 return 0;
1932 // ***************************************************************************
1933 uint CGroupTree::SLine::getNumAdditionnalBitmap() const
1935 if (!Node) return 0;
1936 return Node->getNumBitmap();