CGUITreeView.cpp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. // This file is part of the "Irrlicht Engine".
  2. // written by Reinhard Ostermeier, reinhard@nospam.r-ostermeier.de
  3. // expaned by burningwater
  4. #include "CGUITreeView.h"
  5. #ifdef _IRR_COMPILE_WITH_GUI_
  6. #include "IGUISkin.h"
  7. #include "IGUIEnvironment.h"
  8. #include "IVideoDriver.h"
  9. #include "IGUIFont.h"
  10. #include "CGUIScrollBar.h"
  11. #include "os.h"
  12. namespace irr
  13. {
  14. namespace gui
  15. {
  16. CGUITreeViewNode::CGUITreeViewNode( CGUITreeView* owner, CGUITreeViewNode* parent )
  17. : Owner(owner), Parent(parent), ImageIndex(-1), SelectedImageIndex(-1),
  18. Data(0), Data2(0), Expanded(false)
  19. {
  20. #ifdef _DEBUG
  21. setDebugName( "CGUITreeView" );
  22. #endif
  23. }
  24. CGUITreeViewNode::~CGUITreeViewNode()
  25. {
  26. if( Owner && this == Owner->getSelected() )
  27. {
  28. setSelected( false );
  29. }
  30. clearChildren();
  31. if( Data2 )
  32. {
  33. Data2->drop();
  34. }
  35. }
  36. IGUITreeView* CGUITreeViewNode::getOwner() const
  37. {
  38. return Owner;
  39. }
  40. IGUITreeViewNode* CGUITreeViewNode::getParent() const
  41. {
  42. return Parent;
  43. }
  44. void CGUITreeViewNode::setText( const wchar_t* text )
  45. {
  46. Text = text;
  47. }
  48. void CGUITreeViewNode::setIcon( const wchar_t* icon )
  49. {
  50. Icon = icon;
  51. }
  52. void CGUITreeViewNode::clearChildren()
  53. {
  54. core::list<CGUITreeViewNode*>::Iterator it;
  55. for( it = Children.begin(); it != Children.end(); it++ )
  56. {
  57. ( *it )->drop();
  58. }
  59. Children.clear();
  60. }
  61. IGUITreeViewNode* CGUITreeViewNode::addChildBack(
  62. const wchar_t* text,
  63. const wchar_t* icon /*= 0*/,
  64. s32 imageIndex /*= -1*/,
  65. s32 selectedImageIndex /*= -1*/,
  66. void* data /*= 0*/,
  67. IReferenceCounted* data2 /*= 0*/ )
  68. {
  69. CGUITreeViewNode* newChild = new CGUITreeViewNode( Owner, this );
  70. Children.push_back( newChild );
  71. newChild->Text = text;
  72. newChild->Icon = icon;
  73. newChild->ImageIndex = imageIndex;
  74. newChild->SelectedImageIndex = selectedImageIndex;
  75. newChild->Data = data;
  76. newChild->Data2 = data2;
  77. if( data2 )
  78. {
  79. data2->grab();
  80. }
  81. return newChild;
  82. }
  83. IGUITreeViewNode* CGUITreeViewNode::addChildFront(
  84. const wchar_t* text,
  85. const wchar_t* icon /*= 0*/,
  86. s32 imageIndex /*= -1*/,
  87. s32 selectedImageIndex /*= -1*/,
  88. void* data /*= 0*/,
  89. IReferenceCounted* data2 /*= 0*/ )
  90. {
  91. CGUITreeViewNode* newChild = new CGUITreeViewNode( Owner, this );
  92. Children.push_front( newChild );
  93. newChild->Text = text;
  94. newChild->Icon = icon;
  95. newChild->ImageIndex = imageIndex;
  96. newChild->SelectedImageIndex = selectedImageIndex;
  97. newChild->Data = data;
  98. newChild->Data2 = data2;
  99. if( data2 )
  100. {
  101. data2->grab();
  102. }
  103. return newChild;
  104. }
  105. IGUITreeViewNode* CGUITreeViewNode::insertChildAfter(
  106. IGUITreeViewNode* other,
  107. const wchar_t* text,
  108. const wchar_t* icon /*= 0*/,
  109. s32 imageIndex /*= -1*/,
  110. s32 selectedImageIndex /*= -1*/,
  111. void* data /*= 0*/,
  112. IReferenceCounted* data2/* = 0*/ )
  113. {
  114. core::list<CGUITreeViewNode*>::Iterator itOther;
  115. CGUITreeViewNode* newChild = 0;
  116. for( itOther = Children.begin(); itOther != Children.end(); itOther++ )
  117. {
  118. if( other == *itOther )
  119. {
  120. newChild = new CGUITreeViewNode( Owner, this );
  121. newChild->Text = text;
  122. newChild->Icon = icon;
  123. newChild->ImageIndex = imageIndex;
  124. newChild->SelectedImageIndex = selectedImageIndex;
  125. newChild->Data = data;
  126. newChild->Data2 = data2;
  127. if( data2 )
  128. {
  129. data2->grab();
  130. }
  131. Children.insert_after( itOther, newChild );
  132. break;
  133. }
  134. }
  135. return newChild;
  136. }
  137. IGUITreeViewNode* CGUITreeViewNode::insertChildBefore(
  138. IGUITreeViewNode* other,
  139. const wchar_t* text,
  140. const wchar_t* icon /*= 0*/,
  141. s32 imageIndex /*= -1*/,
  142. s32 selectedImageIndex /*= -1*/,
  143. void* data /*= 0*/,
  144. IReferenceCounted* data2/* = 0*/ )
  145. {
  146. core::list<CGUITreeViewNode*>::Iterator itOther;
  147. CGUITreeViewNode* newChild = 0;
  148. for( itOther = Children.begin(); itOther != Children.end(); itOther++ )
  149. {
  150. if( other == *itOther )
  151. {
  152. newChild = new CGUITreeViewNode( Owner, this );
  153. newChild->Text = text;
  154. newChild->Icon = icon;
  155. newChild->ImageIndex = imageIndex;
  156. newChild->SelectedImageIndex = selectedImageIndex;
  157. newChild->Data = data;
  158. newChild->Data2 = data2;
  159. if( data2 )
  160. {
  161. data2->grab();
  162. }
  163. Children.insert_before( itOther, newChild );
  164. break;
  165. }
  166. }
  167. return newChild;
  168. }
  169. IGUITreeViewNode* CGUITreeViewNode::getFirstChild() const
  170. {
  171. if( Children.empty() )
  172. {
  173. return 0;
  174. }
  175. else
  176. {
  177. return *( Children.begin() );
  178. }
  179. }
  180. IGUITreeViewNode* CGUITreeViewNode::getLastChild() const
  181. {
  182. if( Children.empty() )
  183. {
  184. return 0;
  185. }
  186. else
  187. {
  188. return *( Children.getLast() );
  189. }
  190. }
  191. IGUITreeViewNode* CGUITreeViewNode::getPrevSibling() const
  192. {
  193. core::list<CGUITreeViewNode*>::Iterator itThis;
  194. core::list<CGUITreeViewNode*>::Iterator itOther;
  195. CGUITreeViewNode* other = 0;
  196. if( Parent )
  197. {
  198. for( itThis = Parent->Children.begin(); itThis != Parent->Children.end(); itThis++ )
  199. {
  200. if( this == *itThis )
  201. {
  202. if( itThis != Parent->Children.begin() )
  203. {
  204. other = *itOther;
  205. }
  206. break;
  207. }
  208. itOther = itThis;
  209. }
  210. }
  211. return other;
  212. }
  213. IGUITreeViewNode* CGUITreeViewNode::getNextSibling() const
  214. {
  215. core::list<CGUITreeViewNode*>::Iterator itThis;
  216. CGUITreeViewNode* other = 0;
  217. if( Parent )
  218. {
  219. for( itThis = Parent->Children.begin(); itThis != Parent->Children.end(); itThis++ )
  220. {
  221. if( this == *itThis )
  222. {
  223. if( itThis != Parent->Children.getLast() )
  224. {
  225. other = *( ++itThis );
  226. }
  227. break;
  228. }
  229. }
  230. }
  231. return other;
  232. }
  233. IGUITreeViewNode* CGUITreeViewNode::getNextVisible() const
  234. {
  235. IGUITreeViewNode* next = 0;
  236. IGUITreeViewNode* node = 0;
  237. node = const_cast<CGUITreeViewNode*>( this );
  238. if( node->getExpanded() && node->hasChildren() )
  239. {
  240. next = node->getFirstChild();
  241. }
  242. else
  243. {
  244. next = node->getNextSibling();
  245. }
  246. while( !next && node->getParent() )
  247. {
  248. next = node->getParent()->getNextSibling();
  249. if( !next )
  250. {
  251. node = node->getParent();
  252. }
  253. }
  254. return next;
  255. }
  256. bool CGUITreeViewNode::deleteChild( IGUITreeViewNode* child )
  257. {
  258. core::list<CGUITreeViewNode*>::Iterator itChild;
  259. bool deleted = false;
  260. for( itChild = Children.begin(); itChild != Children.end(); itChild++ )
  261. {
  262. if( child == *itChild )
  263. {
  264. child->drop();
  265. Children.erase( itChild );
  266. deleted = true;
  267. break;
  268. }
  269. }
  270. return deleted;
  271. }
  272. bool CGUITreeViewNode::moveChildUp( IGUITreeViewNode* child )
  273. {
  274. core::list<CGUITreeViewNode*>::Iterator itChild;
  275. core::list<CGUITreeViewNode*>::Iterator itOther;
  276. CGUITreeViewNode* nodeTmp;
  277. bool moved = false;
  278. for( itChild = Children.begin(); itChild != Children.end(); itChild++ )
  279. {
  280. if( child == *itChild )
  281. {
  282. if( itChild != Children.begin() )
  283. {
  284. nodeTmp = *itChild;
  285. *itChild = *itOther;
  286. *itOther = nodeTmp;
  287. moved = true;
  288. }
  289. break;
  290. }
  291. itOther = itChild;
  292. }
  293. return moved;
  294. }
  295. bool CGUITreeViewNode::moveChildDown( IGUITreeViewNode* child )
  296. {
  297. core::list<CGUITreeViewNode*>::Iterator itChild;
  298. core::list<CGUITreeViewNode*>::Iterator itOther;
  299. CGUITreeViewNode* nodeTmp;
  300. bool moved = false;
  301. for( itChild = Children.begin(); itChild != Children.end(); itChild++ )
  302. {
  303. if( child == *itChild )
  304. {
  305. if( itChild != Children.getLast() )
  306. {
  307. itOther = itChild;
  308. ++itOther;
  309. nodeTmp = *itChild;
  310. *itChild = *itOther;
  311. *itOther = nodeTmp;
  312. moved = true;
  313. }
  314. break;
  315. }
  316. }
  317. return moved;
  318. }
  319. void CGUITreeViewNode::setExpanded( bool expanded )
  320. {
  321. Expanded = expanded;
  322. }
  323. void CGUITreeViewNode::setSelected( bool selected )
  324. {
  325. if( Owner )
  326. {
  327. if( selected )
  328. {
  329. Owner->Selected = this;
  330. }
  331. else
  332. {
  333. if( Owner->Selected == this )
  334. {
  335. Owner->Selected = 0;
  336. }
  337. }
  338. }
  339. }
  340. bool CGUITreeViewNode::getSelected() const
  341. {
  342. if( Owner )
  343. {
  344. return Owner->Selected == (IGUITreeViewNode*)this;
  345. }
  346. else
  347. {
  348. return false;
  349. }
  350. }
  351. bool CGUITreeViewNode::isRoot() const
  352. {
  353. return ( Owner && ( this == Owner->Root ) );
  354. }
  355. s32 CGUITreeViewNode::getLevel() const
  356. {
  357. if( Parent )
  358. {
  359. return Parent->getLevel() + 1;
  360. }
  361. else
  362. {
  363. return 0;
  364. }
  365. }
  366. bool CGUITreeViewNode::isVisible() const
  367. {
  368. if( Parent )
  369. {
  370. return Parent->getExpanded() && Parent->isVisible();
  371. }
  372. else
  373. {
  374. return true;
  375. }
  376. }
  377. //! constructor
  378. CGUITreeView::CGUITreeView(IGUIEnvironment* environment, IGUIElement* parent,
  379. s32 id, core::rect<s32> rectangle, bool clip,
  380. bool drawBack,bool scrollBarVertical, bool scrollBarHorizontal)
  381. : IGUITreeView( environment, parent, id, rectangle ),
  382. Root(0), Selected(0),
  383. ItemHeight( 0 ),
  384. IndentWidth( 0 ),
  385. TotalItemHeight( 0 ),
  386. TotalItemWidth ( 0 ),
  387. Font( 0 ),
  388. IconFont( 0 ),
  389. ScrollBarH( 0 ),
  390. ScrollBarV( 0 ),
  391. ImageList( 0 ),
  392. LastEventNode( 0 ),
  393. LinesVisible( true ),
  394. Selecting( false ),
  395. Clip( clip ),
  396. DrawBack( drawBack ),
  397. ImageLeftOfIcon( true )
  398. {
  399. #ifdef _DEBUG
  400. setDebugName( "CGUITreeView" );
  401. #endif
  402. IGUISkin* skin = Environment->getSkin();
  403. s32 s = skin->getSize( EGDS_SCROLLBAR_SIZE );
  404. if ( scrollBarVertical )
  405. {
  406. ScrollBarV = new CGUIScrollBar( false, Environment, this, 0,
  407. core::rect<s32>( RelativeRect.getWidth() - s,
  408. 0,
  409. RelativeRect.getWidth(),
  410. RelativeRect.getHeight() - (scrollBarHorizontal ? s : 0 )
  411. ),
  412. !clip );
  413. ScrollBarV->drop();
  414. ScrollBarV->setSubElement(true);
  415. ScrollBarV->setPos( 0 );
  416. ScrollBarV->grab();
  417. }
  418. if ( scrollBarHorizontal )
  419. {
  420. ScrollBarH = new CGUIScrollBar( true, Environment, this, 1,
  421. core::rect<s32>( 0, RelativeRect.getHeight() - s, RelativeRect.getWidth() - s, RelativeRect.getHeight() ),
  422. !clip );
  423. ScrollBarH->drop();
  424. ScrollBarH->setSubElement(true);
  425. ScrollBarH->setPos( 0 );
  426. ScrollBarH->grab();
  427. }
  428. Root = new CGUITreeViewNode( this, 0 );
  429. Root->Expanded = true;
  430. recalculateItemHeight();
  431. }
  432. //! destructor
  433. CGUITreeView::~CGUITreeView()
  434. {
  435. if( ScrollBarV )
  436. {
  437. ScrollBarV->drop();
  438. }
  439. if( ScrollBarH )
  440. {
  441. ScrollBarH->drop();
  442. }
  443. if( Font )
  444. {
  445. Font->drop();
  446. }
  447. if( IconFont )
  448. {
  449. IconFont->drop();
  450. }
  451. if( ImageList )
  452. {
  453. ImageList->drop();
  454. }
  455. if( Root )
  456. {
  457. Root->drop();
  458. }
  459. }
  460. void CGUITreeView::recalculateItemHeight()
  461. {
  462. IGUISkin* skin = Environment->getSkin();
  463. IGUITreeViewNode* node;
  464. if( Font != skin->getFont() )
  465. {
  466. if( Font )
  467. {
  468. Font->drop();
  469. }
  470. Font = skin->getFont();
  471. ItemHeight = 0;
  472. if( Font )
  473. {
  474. ItemHeight = Font->getDimension( L"A" ).Height + 4;
  475. Font->grab();
  476. }
  477. if( IconFont )
  478. {
  479. s32 height = IconFont->getDimension( L" " ).Height;
  480. if( height > ItemHeight )
  481. {
  482. ItemHeight = height;
  483. }
  484. }
  485. if( ImageList )
  486. {
  487. if( ImageList->getImageSize().Height + 1 > ItemHeight )
  488. {
  489. ItemHeight = ImageList->getImageSize().Height + 1;
  490. }
  491. }
  492. }
  493. IndentWidth = ItemHeight;
  494. if( IndentWidth < 9 )
  495. {
  496. IndentWidth = 9;
  497. }
  498. else if( IndentWidth > 15 )
  499. {
  500. IndentWidth = 15;
  501. }
  502. else
  503. {
  504. if( ( ( IndentWidth >> 1 ) << 1 ) - IndentWidth == 0 )
  505. {
  506. --IndentWidth;
  507. }
  508. }
  509. TotalItemHeight = 0;
  510. TotalItemWidth = AbsoluteRect.getWidth() * 2;
  511. node = Root->getFirstChild();
  512. while( node )
  513. {
  514. TotalItemHeight += ItemHeight;
  515. node = node->getNextVisible();
  516. }
  517. if ( ScrollBarV )
  518. ScrollBarV->setMax( core::max_(0,TotalItemHeight - AbsoluteRect.getHeight()) );
  519. if ( ScrollBarH )
  520. ScrollBarH->setMax( core::max_(0, TotalItemWidth - AbsoluteRect.getWidth()) );
  521. }
  522. //! called if an event happened.
  523. bool CGUITreeView::OnEvent( const SEvent &event )
  524. {
  525. if ( isEnabled() )
  526. {
  527. switch( event.EventType )
  528. {
  529. case EET_GUI_EVENT:
  530. switch( event.GUIEvent.EventType )
  531. {
  532. case gui::EGET_SCROLL_BAR_CHANGED:
  533. if( event.GUIEvent.Caller == ScrollBarV || event.GUIEvent.Caller == ScrollBarH )
  534. {
  535. //s32 pos = ( ( gui::IGUIScrollBar* )event.GUIEvent.Caller )->getPos();
  536. return true;
  537. }
  538. break;
  539. case gui::EGET_ELEMENT_FOCUS_LOST:
  540. {
  541. Selecting = false;
  542. return false;
  543. }
  544. break;
  545. default:
  546. break;
  547. }
  548. break;
  549. case EET_MOUSE_INPUT_EVENT:
  550. {
  551. core::position2d<s32> p( event.MouseInput.X, event.MouseInput.Y );
  552. switch( event.MouseInput.Event )
  553. {
  554. case EMIE_MOUSE_WHEEL:
  555. if ( ScrollBarV )
  556. ScrollBarV->setPos( ScrollBarV->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1) * -10 );
  557. return true;
  558. break;
  559. case EMIE_LMOUSE_PRESSED_DOWN:
  560. if (Environment->hasFocus(this) && !AbsoluteClippingRect.isPointInside(p) )
  561. {
  562. Environment->removeFocus(this);
  563. return false;
  564. }
  565. if( Environment->hasFocus( this ) &&
  566. ( ( ScrollBarV && ScrollBarV->getAbsolutePosition().isPointInside( p ) && ScrollBarV->OnEvent( event ) ) ||
  567. ( ScrollBarH && ScrollBarH->getAbsolutePosition().isPointInside( p ) && ScrollBarH->OnEvent( event ) )
  568. )
  569. )
  570. {
  571. return true;
  572. }
  573. Selecting = true;
  574. Environment->setFocus( this );
  575. return true;
  576. break;
  577. case EMIE_LMOUSE_LEFT_UP:
  578. if( Environment->hasFocus( this ) &&
  579. ( ( ScrollBarV && ScrollBarV->getAbsolutePosition().isPointInside( p ) && ScrollBarV->OnEvent( event ) ) ||
  580. ( ScrollBarH && ScrollBarH->getAbsolutePosition().isPointInside( p ) && ScrollBarH->OnEvent( event ) )
  581. )
  582. )
  583. {
  584. return true;
  585. }
  586. Selecting = false;
  587. Environment->removeFocus( this );
  588. mouseAction( event.MouseInput.X, event.MouseInput.Y );
  589. return true;
  590. break;
  591. case EMIE_MOUSE_MOVED:
  592. if( Selecting )
  593. {
  594. if( getAbsolutePosition().isPointInside( p ) )
  595. {
  596. mouseAction( event.MouseInput.X, event.MouseInput.Y, true );
  597. return true;
  598. }
  599. }
  600. break;
  601. default:
  602. break;
  603. }
  604. }
  605. break;
  606. default:
  607. break;
  608. }
  609. }
  610. return Parent ? Parent->OnEvent( event ) : false;
  611. }
  612. /*!
  613. */
  614. void CGUITreeView::mouseAction( s32 xpos, s32 ypos, bool onlyHover /*= false*/ )
  615. {
  616. IGUITreeViewNode* oldSelected = Selected;
  617. IGUITreeViewNode* hitNode = 0;
  618. s32 selIdx=-1;
  619. s32 n;
  620. IGUITreeViewNode* node;
  621. SEvent event;
  622. event.EventType = EET_GUI_EVENT;
  623. event.GUIEvent.Caller = this;
  624. event.GUIEvent.Element = 0;
  625. xpos -= AbsoluteRect.UpperLeftCorner.X;
  626. ypos -= AbsoluteRect.UpperLeftCorner.Y;
  627. // find new selected item.
  628. if( ItemHeight != 0 && ScrollBarV )
  629. {
  630. selIdx = ( ( ypos - 1 ) + ScrollBarV->getPos() ) / ItemHeight;
  631. }
  632. hitNode = 0;
  633. node = Root->getFirstChild();
  634. n = 0;
  635. while( node )
  636. {
  637. if( selIdx == n )
  638. {
  639. hitNode = node;
  640. break;
  641. }
  642. node = node->getNextVisible();
  643. ++n;
  644. }
  645. if( hitNode && xpos > hitNode->getLevel() * IndentWidth )
  646. {
  647. Selected = hitNode;
  648. }
  649. if( hitNode && !onlyHover
  650. && xpos < hitNode->getLevel() * IndentWidth
  651. && xpos > ( hitNode->getLevel() - 1 ) * IndentWidth
  652. && hitNode->hasChildren() )
  653. {
  654. hitNode->setExpanded( !hitNode->getExpanded() );
  655. // post expand/collaps news
  656. if( hitNode->getExpanded() )
  657. {
  658. event.GUIEvent.EventType = EGET_TREEVIEW_NODE_EXPAND;
  659. }
  660. else
  661. {
  662. event.GUIEvent.EventType = EGET_TREEVIEW_NODE_COLLAPS;
  663. }
  664. LastEventNode = hitNode;
  665. Parent->OnEvent( event );
  666. LastEventNode = 0;
  667. }
  668. if( Selected && !Selected->isVisible() )
  669. {
  670. Selected = 0;
  671. }
  672. // post selection news
  673. if( Parent && !onlyHover && Selected != oldSelected )
  674. {
  675. if( oldSelected )
  676. {
  677. event.GUIEvent.EventType = EGET_TREEVIEW_NODE_DESELECT;
  678. LastEventNode = oldSelected;
  679. Parent->OnEvent( event );
  680. LastEventNode = 0;
  681. }
  682. if( Selected )
  683. {
  684. event.GUIEvent.EventType = EGET_TREEVIEW_NODE_SELECT;
  685. LastEventNode = Selected;
  686. Parent->OnEvent( event );
  687. LastEventNode = 0;
  688. }
  689. }
  690. }
  691. //! draws the element and its children
  692. void CGUITreeView::draw()
  693. {
  694. if( !IsVisible )
  695. {
  696. return;
  697. }
  698. recalculateItemHeight(); // if the font changed
  699. IGUISkin* skin = Environment->getSkin();
  700. irr::video::IVideoDriver* driver = Environment->getVideoDriver();
  701. core::rect<s32>* clipRect = 0;
  702. if( Clip )
  703. {
  704. clipRect = &AbsoluteClippingRect;
  705. }
  706. // draw background
  707. core::rect<s32> frameRect( AbsoluteRect );
  708. if( DrawBack )
  709. {
  710. driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect,
  711. clipRect );
  712. }
  713. // draw the border
  714. frameRect.LowerRightCorner.Y = frameRect.UpperLeftCorner.Y + 1;
  715. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), frameRect,
  716. clipRect );
  717. frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
  718. frameRect.LowerRightCorner.X = frameRect.UpperLeftCorner.X + 1;
  719. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), frameRect,
  720. clipRect );
  721. frameRect = AbsoluteRect;
  722. frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - 1;
  723. driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect,
  724. clipRect );
  725. frameRect = AbsoluteRect;
  726. frameRect.UpperLeftCorner.Y = AbsoluteRect.LowerRightCorner.Y - 1;
  727. frameRect.LowerRightCorner.Y = AbsoluteRect.LowerRightCorner.Y;
  728. driver->draw2DRectangle( skin->getColor( EGDC_3D_HIGH_LIGHT ), frameRect,
  729. clipRect );
  730. // draw items
  731. core::rect<s32> clientClip( AbsoluteRect );
  732. clientClip.UpperLeftCorner.Y += 1;
  733. clientClip.UpperLeftCorner.X += 1;
  734. clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X;
  735. clientClip.LowerRightCorner.Y -= 1;
  736. if ( ScrollBarV )
  737. clientClip.LowerRightCorner.X -= skin->getSize( EGDS_SCROLLBAR_SIZE );
  738. if ( ScrollBarH )
  739. clientClip.LowerRightCorner.Y -= skin->getSize( EGDS_SCROLLBAR_SIZE );
  740. if( clipRect )
  741. {
  742. clientClip.clipAgainst( *clipRect );
  743. }
  744. frameRect = AbsoluteRect;
  745. frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize( EGDS_SCROLLBAR_SIZE );
  746. frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight;
  747. if ( ScrollBarV )
  748. {
  749. frameRect.UpperLeftCorner.Y -= ScrollBarV->getPos();
  750. frameRect.LowerRightCorner.Y -= ScrollBarV->getPos();
  751. }
  752. if ( ScrollBarH )
  753. {
  754. frameRect.UpperLeftCorner.X -= ScrollBarH->getPos();
  755. frameRect.LowerRightCorner.X -= ScrollBarH->getPos();
  756. }
  757. IGUITreeViewNode* node = Root->getFirstChild();
  758. while( node )
  759. {
  760. frameRect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X + 1 + node->getLevel() * IndentWidth;
  761. if( frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y
  762. && frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y )
  763. {
  764. if( node == Selected )
  765. {
  766. driver->draw2DRectangle( skin->getColor( EGDC_HIGH_LIGHT ), frameRect, &clientClip );
  767. }
  768. if( node->hasChildren() )
  769. {
  770. core::rect<s32> rc;
  771. core::rect<s32> expanderRect;
  772. expanderRect.UpperLeftCorner.X = frameRect.UpperLeftCorner.X - IndentWidth + 2;
  773. expanderRect.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y + ( ( frameRect.getHeight() - ( IndentWidth - 4 ) ) >> 1 );
  774. expanderRect.LowerRightCorner.X = expanderRect.UpperLeftCorner.X + IndentWidth - 4;
  775. expanderRect.LowerRightCorner.Y = expanderRect.UpperLeftCorner.Y + IndentWidth - 4;
  776. // box upper line
  777. rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X;
  778. rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y;
  779. rc.LowerRightCorner.X = expanderRect.LowerRightCorner.X;
  780. rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1;
  781. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  782. clipRect );
  783. // box left line
  784. rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X;
  785. rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y;
  786. rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1;
  787. rc.LowerRightCorner.Y = expanderRect.LowerRightCorner.Y;
  788. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  789. clipRect );
  790. // box right line
  791. rc.UpperLeftCorner.X = expanderRect.LowerRightCorner.X - 1;
  792. rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y;
  793. rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1;
  794. rc.LowerRightCorner.Y = expanderRect.LowerRightCorner.Y;
  795. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  796. clipRect );
  797. // box bottom line
  798. rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X;
  799. rc.UpperLeftCorner.Y = expanderRect.LowerRightCorner.Y - 1;
  800. rc.LowerRightCorner.X = expanderRect.LowerRightCorner.X;
  801. rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1;
  802. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  803. clipRect );
  804. // horizontal '-' line
  805. rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X + 2;
  806. rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y + ( expanderRect.getHeight() >> 1 );
  807. rc.LowerRightCorner.X = rc.UpperLeftCorner.X + expanderRect.getWidth() - 4;
  808. rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1;
  809. driver->draw2DRectangle( skin->getColor( EGDC_BUTTON_TEXT ), rc,
  810. clipRect );
  811. if( !node->getExpanded() )
  812. {
  813. // vertical '+' line
  814. rc.UpperLeftCorner.X = expanderRect.UpperLeftCorner.X + ( expanderRect.getWidth() >> 1 );
  815. rc.UpperLeftCorner.Y = expanderRect.UpperLeftCorner.Y + 2;
  816. rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1;
  817. rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + expanderRect.getHeight() - 4;
  818. driver->draw2DRectangle( skin->getColor( EGDC_BUTTON_TEXT ), rc,
  819. clipRect );
  820. }
  821. }
  822. core::rect<s32> textRect = frameRect;
  823. if( Font )
  824. {
  825. EGUI_DEFAULT_COLOR textCol = EGDC_GRAY_TEXT;
  826. if ( isEnabled() )
  827. textCol = ( node == Selected ) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT;
  828. s32 iconWidth = 0;
  829. for( s32 n = 0; n < 2; ++n )
  830. {
  831. s32 index = node->getImageIndex();
  832. if( ( ImageList && index >= 0 )
  833. && ( ( ImageLeftOfIcon && n == 0 )
  834. || ( !ImageLeftOfIcon && n == 1 ) ) )
  835. {
  836. index = node->getSelectedImageIndex();
  837. if( node != Selected || index < 0 )
  838. {
  839. index = node->getImageIndex();
  840. }
  841. ImageList->draw(
  842. index,
  843. core::position2d<s32>(
  844. textRect.UpperLeftCorner.X,
  845. textRect.UpperLeftCorner.Y + ( ( textRect.getHeight() - ImageList->getImageSize().Height ) >> 1 ) ),
  846. &clientClip );
  847. iconWidth += ImageList->getImageSize().Width + 3;
  848. textRect.UpperLeftCorner.X += ImageList->getImageSize().Width + 3;
  849. }
  850. else if( ( IconFont && reinterpret_cast<CGUITreeViewNode*>( node )->Icon.size() )
  851. && ( ( ImageLeftOfIcon && n == 1 )
  852. || ( !ImageLeftOfIcon && n == 0 ) ) )
  853. {
  854. IconFont->draw( node->getIcon(), textRect, skin->getColor(textCol), false, true, &clientClip );
  855. iconWidth += IconFont->getDimension( node->getIcon() ).Width + 3;
  856. textRect.UpperLeftCorner.X += IconFont->getDimension( node->getIcon() ).Width + 3;
  857. }
  858. }
  859. Font->draw( node->getText(), textRect, skin->getColor(textCol), false, true, &clientClip );
  860. textRect.UpperLeftCorner.X -= iconWidth;
  861. }
  862. // draw the lines if neccessary
  863. if( LinesVisible )
  864. {
  865. core::rect<s32> rc;
  866. // horizontal line
  867. rc.UpperLeftCorner.X = frameRect.UpperLeftCorner.X - IndentWidth - ( IndentWidth >> 1 ) - 1;
  868. rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y + ( ( frameRect.getHeight() ) >> 1 );
  869. if( node->hasChildren() )
  870. {
  871. rc.LowerRightCorner.X = frameRect.UpperLeftCorner.X - IndentWidth;
  872. }
  873. else
  874. {
  875. rc.LowerRightCorner.X = frameRect.UpperLeftCorner.X - 2;
  876. }
  877. rc.LowerRightCorner.Y = rc.UpperLeftCorner.Y + 1;
  878. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  879. clipRect );
  880. if( node->getParent() != Root )
  881. {
  882. // vertical line
  883. if( node == node->getParent()->getFirstChild() )
  884. {
  885. rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( ( frameRect.getHeight() - IndentWidth ) >> 1 );
  886. }
  887. else
  888. {
  889. rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( frameRect.getHeight() >> 1 );
  890. }
  891. rc.LowerRightCorner.X = rc.UpperLeftCorner.X + 1;
  892. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  893. clipRect );
  894. // the vertical lines of all parents
  895. IGUITreeViewNode* nodeTmp = node->getParent();
  896. rc.UpperLeftCorner.Y = frameRect.UpperLeftCorner.Y - ( frameRect.getHeight() >> 1 );
  897. for( s32 n = 0; n < node->getLevel() - 2; ++n )
  898. {
  899. rc.UpperLeftCorner.X -= IndentWidth;
  900. rc.LowerRightCorner.X -= IndentWidth;
  901. if( nodeTmp != nodeTmp->getParent()->getLastChild() )
  902. {
  903. driver->draw2DRectangle( skin->getColor( EGDC_3D_SHADOW ), rc,
  904. clipRect );
  905. }
  906. nodeTmp = nodeTmp->getParent();
  907. }
  908. }
  909. }
  910. }
  911. frameRect.UpperLeftCorner.Y += ItemHeight;
  912. frameRect.LowerRightCorner.Y += ItemHeight;
  913. node = node->getNextVisible();
  914. }
  915. IGUIElement::draw();
  916. }
  917. //! Sets the font which should be used as icon font. This font is set to the Irrlicht engine
  918. //! built-in-font by default. Icons can be displayed in front of every list item.
  919. //! An icon is a string, displayed with the icon font. When using the build-in-font of the
  920. //! Irrlicht engine as icon font, the icon strings defined in GUIIcons.h can be used.
  921. void CGUITreeView::setIconFont( IGUIFont* font )
  922. {
  923. s32 height;
  924. if ( font )
  925. font->grab();
  926. if ( IconFont )
  927. {
  928. IconFont->drop();
  929. }
  930. IconFont = font;
  931. if( IconFont )
  932. {
  933. height = IconFont->getDimension( L" " ).Height;
  934. if( height > ItemHeight )
  935. {
  936. ItemHeight = height;
  937. }
  938. }
  939. }
  940. //! Sets the image list which should be used for the image and selected image of every node.
  941. //! The default is 0 (no images).
  942. void CGUITreeView::setImageList( IGUIImageList* imageList )
  943. {
  944. if (imageList )
  945. imageList->grab();
  946. if( ImageList )
  947. {
  948. ImageList->drop();
  949. }
  950. ImageList = imageList;
  951. if( ImageList )
  952. {
  953. if( ImageList->getImageSize().Height + 1 > ItemHeight )
  954. {
  955. ItemHeight = ImageList->getImageSize().Height + 1;
  956. }
  957. }
  958. }
  959. } // end namespace gui
  960. } // end namespace irr
  961. #endif // _IRR_COMPILE_WITH_GUI_