PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/fltk/src/Fl_Tree_Item.cxx

http://luafltk.googlecode.com/
C++ | 730 lines | 506 code | 39 blank | 185 comment | 154 complexity | 34e78031679b3cdbbdc51def0723cc67 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-3.0, 0BSD
  1. //
  2. // "$Id: Fl_Tree_Item.cxx 7627 2010-06-03 15:46:59Z greg.ercolano $"
  3. //
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <FL/Fl_Widget.H>
  8. #include <FL/Fl_Tree_Item.H>
  9. #include <FL/Fl_Tree_Prefs.H>
  10. //////////////////////
  11. // Fl_Tree_Item.cxx
  12. //////////////////////
  13. //
  14. // Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
  15. // Copyright (C) 2009 by Greg Ercolano.
  16. //
  17. // This library is free software; you can redistribute it and/or
  18. // modify it under the terms of the GNU Library General Public
  19. // License as published by the Free Software Foundation; either
  20. // version 2 of the License, or (at your option) any later version.
  21. //
  22. // This library is distributed in the hope that it will be useful,
  23. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  25. // Library General Public License for more details.
  26. //
  27. // You should have received a copy of the GNU Library General Public
  28. // License along with this library; if not, write to the Free Software
  29. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  30. // USA.
  31. //
  32. // Was the last event inside the specified xywh?
  33. static int event_inside(const int xywh[4]) {
  34. return(Fl::event_inside(xywh[0],xywh[1],xywh[2],xywh[3]));
  35. }
  36. /// Constructor.
  37. /// Makes a new instance of Fl_Tree_Item using defaults from 'prefs'.
  38. ///
  39. Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) {
  40. _label = 0;
  41. _labelfont = prefs.labelfont();
  42. _labelsize = prefs.labelsize();
  43. _labelfgcolor = prefs.fgcolor();
  44. _labelbgcolor = prefs.bgcolor();
  45. _widget = 0;
  46. _open = 1;
  47. _visible = 1;
  48. _active = 1;
  49. _selected = 0;
  50. _xywh[0] = 0;
  51. _xywh[1] = 0;
  52. _xywh[2] = 0;
  53. _xywh[3] = 0;
  54. _collapse_xywh[0] = 0;
  55. _collapse_xywh[1] = 0;
  56. _collapse_xywh[2] = 0;
  57. _collapse_xywh[3] = 0;
  58. _label_xywh[0] = 0;
  59. _label_xywh[1] = 0;
  60. _label_xywh[2] = 0;
  61. _label_xywh[3] = 0;
  62. _usericon = 0;
  63. _userdata = 0;
  64. _parent = 0;
  65. }
  66. // DTOR
  67. Fl_Tree_Item::~Fl_Tree_Item() {
  68. if ( _label ) {
  69. free((void*)_label);
  70. _label = 0;
  71. }
  72. _widget = 0; // Fl_Group will handle destruction
  73. _usericon = 0; // user handled allocation
  74. //_children.clear(); // array's destructor handles itself
  75. }
  76. /// Copy constructor.
  77. Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) {
  78. _label = o->label() ? strdup(o->label()) : 0;
  79. _labelfont = o->labelfont();
  80. _labelsize = o->labelsize();
  81. _labelfgcolor = o->labelfgcolor();
  82. _labelbgcolor = o->labelbgcolor();
  83. _widget = o->widget();
  84. _open = o->_open;
  85. _visible = o->_visible;
  86. _active = o->_active;
  87. _selected = o->_selected;
  88. _xywh[0] = o->_xywh[0];
  89. _xywh[1] = o->_xywh[1];
  90. _xywh[2] = o->_xywh[2];
  91. _xywh[3] = o->_xywh[3];
  92. _collapse_xywh[0] = o->_collapse_xywh[0];
  93. _collapse_xywh[1] = o->_collapse_xywh[1];
  94. _collapse_xywh[2] = o->_collapse_xywh[2];
  95. _collapse_xywh[3] = o->_collapse_xywh[3];
  96. _label_xywh[0] = o->_label_xywh[0];
  97. _label_xywh[1] = o->_label_xywh[1];
  98. _label_xywh[2] = o->_label_xywh[2];
  99. _label_xywh[3] = o->_label_xywh[3];
  100. _usericon = o->usericon();
  101. _userdata = o->user_data();
  102. _parent = o->_parent;
  103. }
  104. /// Print the tree as 'ascii art' to stdout.
  105. /// Used mainly for debugging.
  106. ///
  107. void Fl_Tree_Item::show_self(const char *indent) const {
  108. if ( label() ) {
  109. printf("%s-%s (%d children, this=%p, parent=%p depth=%d)\n",
  110. indent,label(),children(),(void*)this, (void*)_parent, depth());
  111. }
  112. if ( children() ) {
  113. char *i2 = (char*)malloc(strlen(indent) + 2);
  114. strcpy(i2, indent);
  115. strcat(i2, " |");
  116. for ( int t=0; t<children(); t++ ) {
  117. child(t)->show_self(i2);
  118. }
  119. }
  120. fflush(stdout);
  121. }
  122. /// Set the label. Makes a copy of the name.
  123. void Fl_Tree_Item::label(const char *name) {
  124. if ( _label ) { free((void*)_label); _label = 0; }
  125. _label = name ? strdup(name) : 0;
  126. }
  127. /// Return the label.
  128. const char *Fl_Tree_Item::label() const {
  129. return(_label);
  130. }
  131. /// Return child item for the specified 'index'.
  132. const Fl_Tree_Item *Fl_Tree_Item::child(int index) const {
  133. return(_children[index]);
  134. }
  135. /// Clear all the children for this item.
  136. void Fl_Tree_Item::clear_children() {
  137. _children.clear();
  138. }
  139. /// Return the index of the immediate child of this item that has the label 'name'.
  140. ///
  141. /// \returns index of found item, or -1 if not found.
  142. ///
  143. int Fl_Tree_Item::find_child(const char *name) {
  144. if ( name ) {
  145. for ( int t=0; t<children(); t++ ) {
  146. if ( child(t)->label() ) {
  147. if ( strcmp(child(t)->label(), name) == 0 ) {
  148. return(t);
  149. }
  150. }
  151. }
  152. }
  153. return(-1);
  154. }
  155. /// Find item by descending array of names.
  156. /// Only Fl_Tree should need this method.
  157. ///
  158. /// \returns item, or 0 if not found
  159. ///
  160. const Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) const {
  161. for ( int t=0; t<children(); t++ ) {
  162. if ( child(t)->label() ) {
  163. if ( strcmp(child(t)->label(), *arr) == 0 ) { // match?
  164. if ( *(arr+1) ) { // more in arr? descend
  165. return(_children[t]->find_item(arr+1));
  166. } else { // end of arr? done
  167. return(_children[t]);
  168. }
  169. }
  170. }
  171. }
  172. return(0);
  173. }
  174. /// Find item by by descending array of names.
  175. /// Only Fl_Tree should need this method.
  176. ///
  177. /// \returns item, or 0 if not found
  178. ///
  179. Fl_Tree_Item *Fl_Tree_Item::find_item(char **arr) {
  180. for ( int t=0; t<children(); t++ ) {
  181. if ( child(t)->label() ) {
  182. if ( strcmp(child(t)->label(), *arr) == 0 ) { // match?
  183. if ( *(arr+1) ) { // more in arr? descend
  184. return(_children[t]->find_item(arr+1));
  185. } else { // end of arr? done
  186. return(_children[t]);
  187. }
  188. }
  189. }
  190. }
  191. return(0);
  192. }
  193. /// Find the index number for the specified 'item'
  194. /// in the current item's list of children.
  195. ///
  196. /// \returns the index, or -1 if not found.
  197. ///
  198. int Fl_Tree_Item::find_child(Fl_Tree_Item *item) {
  199. for ( int t=0; t<children(); t++ ) {
  200. if ( item == child(t) ) {
  201. return(t);
  202. }
  203. }
  204. return(-1);
  205. }
  206. /// Add a new child to this item with the name 'new_label', with defaults from 'prefs'.
  207. /// An internally managed copy is made of the label string.
  208. /// Adds the item based on the value of prefs.sortorder().
  209. ///
  210. Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_label) {
  211. Fl_Tree_Item *item = new Fl_Tree_Item(prefs);
  212. item->label(new_label);
  213. item->_parent = this;
  214. switch ( prefs.sortorder() ) {
  215. case FL_TREE_SORT_NONE: {
  216. _children.add(item);
  217. return(item);
  218. }
  219. case FL_TREE_SORT_ASCENDING: {
  220. for ( int t=0; t<_children.total(); t++ ) {
  221. Fl_Tree_Item *c = _children[t];
  222. if ( c->label() && strcmp(c->label(), new_label) > 0 ) {
  223. _children.insert(t, item);
  224. return(item);
  225. }
  226. }
  227. _children.add(item);
  228. return(item);
  229. }
  230. case FL_TREE_SORT_DESCENDING: {
  231. for ( int t=0; t<_children.total(); t++ ) {
  232. Fl_Tree_Item *c = _children[t];
  233. if ( c->label() && strcmp(c->label(), new_label) < 0 ) {
  234. _children.insert(t, item);
  235. return(item);
  236. }
  237. }
  238. _children.add(item);
  239. return(item);
  240. }
  241. }
  242. return(item);
  243. }
  244. /// Descend into the path specified by \p arr, and add a new child there.
  245. /// Should be used only by Fl_Tree's internals.
  246. /// Adds the item based on the value of prefs.sortorder().
  247. /// \returns the item added.
  248. ///
  249. Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) {
  250. int t = find_child(*arr);
  251. Fl_Tree_Item *item;
  252. if ( t == -1 ) {
  253. item = (Fl_Tree_Item*)add(prefs, *arr);
  254. } else {
  255. item = (Fl_Tree_Item*)child(t);
  256. }
  257. if ( *(arr+1) ) { // descend?
  258. return(item->add(prefs, arr+1));
  259. } else {
  260. return(item); // end? done
  261. }
  262. }
  263. /// Insert a new item into current item's children at a specified position.
  264. /// \returns the new item inserted.
  265. ///
  266. Fl_Tree_Item *Fl_Tree_Item::insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos) {
  267. Fl_Tree_Item *item = new Fl_Tree_Item(prefs);
  268. item->label(new_label);
  269. item->_parent = this;
  270. _children.insert(pos, item);
  271. return(item);
  272. }
  273. /// Insert a new item above this item.
  274. /// \returns the new item inserted, or 0 if an error occurred.
  275. ///
  276. Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char *new_label) {
  277. Fl_Tree_Item *p = _parent;
  278. if ( ! p ) return(0);
  279. // Walk our parent's children to find ourself
  280. for ( int t=0; t<p->children(); t++ ) {
  281. Fl_Tree_Item *c = p->child(t);
  282. if ( this == c ) {
  283. return(p->insert(prefs, new_label, t));
  284. }
  285. }
  286. return(0);
  287. }
  288. /// Remove child by item.
  289. /// \returns 0 if removed, -1 if item not an immediate child.
  290. ///
  291. int Fl_Tree_Item::remove_child(Fl_Tree_Item *item) {
  292. for ( int t=0; t<children(); t++ ) {
  293. if ( child(t) == item ) {
  294. item->clear_children();
  295. _children.remove(t);
  296. return(0);
  297. }
  298. }
  299. return(-1);
  300. }
  301. /// Remove immediate child (and its children) by its label 'name'.
  302. /// \returns 0 if removed, -1 if not found.
  303. ///
  304. int Fl_Tree_Item::remove_child(const char *name) {
  305. for ( int t=0; t<children(); t++ ) {
  306. if ( child(t)->label() ) {
  307. if ( strcmp(child(t)->label(), name) == 0 ) {
  308. _children.remove(t);
  309. return(0);
  310. }
  311. }
  312. }
  313. return(-1);
  314. }
  315. /// Swap two of our children, given two child index values.
  316. /// Use this eg. for sorting.
  317. ///
  318. /// This method is FAST, and does not involve lookups.
  319. ///
  320. /// No range checking is done on either index value.
  321. ///
  322. /// \returns
  323. /// - 0 : OK
  324. /// - -1 : failed: 'a' or 'b' is not our immediate child
  325. ///
  326. void Fl_Tree_Item::swap_children(int ax, int bx) {
  327. _children.swap(ax, bx);
  328. }
  329. /// Swap two of our children, given item pointers.
  330. /// Use this eg. for sorting.
  331. ///
  332. /// This method is SLOW because it involves linear lookups.
  333. /// For speed, use swap_children(int,int) instead.
  334. ///
  335. /// \returns
  336. /// - 0 : OK
  337. /// - -1 : failed: 'a' or 'b' is not our immediate child
  338. ///
  339. int Fl_Tree_Item::swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b) {
  340. int ax = -1, bx = -1;
  341. for ( int t=0; t<children(); t++ ) { // find index for a and b
  342. if ( _children[t] == a ) { ax = t; if ( bx != -1 ) break; else continue; }
  343. if ( _children[t] == b ) { bx = t; if ( ax != -1 ) break; else continue; }
  344. }
  345. if ( ax == -1 || bx == -1 ) return(-1); // not found? fail
  346. swap_children(ax,bx);
  347. return(0);
  348. }
  349. /// Internal: Horizontal connector line based on preference settings.
  350. void Fl_Tree_Item::draw_horizontal_connector(int x1, int x2, int y, const Fl_Tree_Prefs &prefs) {
  351. fl_color(prefs.connectorcolor());
  352. switch ( prefs.connectorstyle() ) {
  353. case FL_TREE_CONNECTOR_SOLID:
  354. y |= 1; // force alignment w/dot pattern
  355. fl_line(x1,y,x2,y);
  356. return;
  357. case FL_TREE_CONNECTOR_DOTTED:
  358. {
  359. y |= 1; // force alignment w/dot pattern
  360. for ( int xx=x1; xx<=x2; xx++ ) {
  361. if ( !(xx & 1) ) fl_point(xx, y);
  362. }
  363. }
  364. return;
  365. case FL_TREE_CONNECTOR_NONE:
  366. return;
  367. }
  368. }
  369. /// Internal: Vertical connector line based on preference settings.
  370. void Fl_Tree_Item::draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_Prefs &prefs) {
  371. fl_color(prefs.connectorcolor());
  372. switch ( prefs.connectorstyle() ) {
  373. case FL_TREE_CONNECTOR_SOLID:
  374. y1 |= 1; // force alignment w/dot pattern
  375. y2 |= 1; // force alignment w/dot pattern
  376. fl_line(x,y1,x,y2);
  377. return;
  378. case FL_TREE_CONNECTOR_DOTTED:
  379. {
  380. y1 |= 1; // force alignment w/dot pattern
  381. y2 |= 1; // force alignment w/dot pattern
  382. for ( int yy=y1; yy<=y2; yy++ ) {
  383. if ( yy & 1 ) fl_point(x, yy);
  384. }
  385. }
  386. return;
  387. case FL_TREE_CONNECTOR_NONE:
  388. return;
  389. }
  390. }
  391. /// Find the item that the last event was over.
  392. ///
  393. /// Returns the item if its visible, and mouse is over it.
  394. /// Works even if widget deactivated.
  395. /// Use event_on_collapse_icon() to determine if collapse button was pressed.
  396. ///
  397. /// \returns const visible item under the event if found, or 0 if none.
  398. ///
  399. const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const {
  400. if ( ! _visible ) return(0);
  401. if ( is_root() && !prefs.showroot() ) {
  402. // skip event check if we're root but root not being shown
  403. } else {
  404. // See if event is over us
  405. if ( event_inside(_xywh) ) { // event within this item?
  406. return(this); // found
  407. }
  408. }
  409. if ( is_open() ) { // open? check children of this item
  410. for ( int t=0; t<children(); t++ ) {
  411. const Fl_Tree_Item *item;
  412. if ( ( item = _children[t]->find_clicked(prefs) ) != NULL) { // check child and its descendents
  413. return(item); // found?
  414. }
  415. }
  416. }
  417. return(0);
  418. }
  419. /// Non-const version of the above.
  420. /// Find the item that the last event was over.
  421. ///
  422. /// Returns the item if its visible, and mouse is over it.
  423. /// Works even if widget deactivated.
  424. /// Use event_on_collapse_icon() to determine if collapse button was pressed.
  425. ///
  426. /// \returns the visible item under the event if found, or 0 if none.
  427. ///
  428. Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) {
  429. if ( ! _visible ) return(0);
  430. if ( is_root() && !prefs.showroot() ) {
  431. // skip event check if we're root but root not being shown
  432. } else {
  433. // See if event is over us
  434. if ( event_inside(_xywh) ) { // event within this item?
  435. return(this); // found
  436. }
  437. }
  438. if ( is_open() ) { // open? check children of this item
  439. for ( int t=0; t<children(); t++ ) {
  440. Fl_Tree_Item *item;
  441. if ( ( item = _children[t]->find_clicked(prefs) ) != NULL ) { // check child and its descendents
  442. return(item); // found?
  443. }
  444. }
  445. }
  446. return(0);
  447. }
  448. /// Draw this item and its children.
  449. void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
  450. const Fl_Tree_Prefs &prefs, int lastchild) {
  451. if ( ! _visible ) return;
  452. fl_font(_labelfont, _labelsize);
  453. int H = _labelsize;
  454. if(usericon() && H < usericon()->h()) H = usericon()->h();
  455. H += prefs.linespacing() + fl_descent();
  456. // Colors, fonts
  457. Fl_Color fg = _selected ? prefs.bgcolor() : _labelfgcolor;
  458. Fl_Color bg = _selected ? prefs.selectcolor() : _labelbgcolor;
  459. if ( ! _active ) {
  460. fg = fl_inactive(fg);
  461. if ( _selected ) bg = fl_inactive(bg);
  462. }
  463. // Update the xywh of this item
  464. _xywh[0] = X;
  465. _xywh[1] = Y;
  466. _xywh[2] = W;
  467. _xywh[3] = H;
  468. // Text size
  469. int textw=0, texth=0;
  470. fl_measure(_label, textw, texth, 0);
  471. int textycenter = Y+(H/2);
  472. int &icon_x = _collapse_xywh[0] = X-1;
  473. int &icon_y = _collapse_xywh[1] = textycenter - (prefs.openicon()->h()/2);
  474. int &icon_w = _collapse_xywh[2] = prefs.openicon()->w();
  475. _collapse_xywh[3] = prefs.openicon()->h();
  476. // Horizontal connector values
  477. int hstartx = X+icon_w/2-1;
  478. int hendx = hstartx + prefs.connectorwidth();
  479. int hcenterx = X + icon_w + ((hendx - (X + icon_w)) / 2);
  480. // See if we should draw this item
  481. // If this item is root, and showroot() is disabled, don't draw.
  482. //
  483. char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1;
  484. if ( drawthis ) {
  485. // Draw connectors
  486. if ( prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) {
  487. // Horiz connector between center of icon and text
  488. draw_horizontal_connector(hstartx, hendx, textycenter, prefs);
  489. if ( has_children() && is_open() ) {
  490. // Small vertical line down to children
  491. draw_vertical_connector(hcenterx, textycenter, Y+H, prefs);
  492. }
  493. // Connectors for last child
  494. if ( ! is_root() ) {
  495. if ( lastchild ) {
  496. draw_vertical_connector(hstartx, Y, textycenter, prefs);
  497. } else {
  498. draw_vertical_connector(hstartx, Y, Y+H, prefs);
  499. }
  500. }
  501. }
  502. // Draw collapse icon
  503. if ( has_children() && prefs.showcollapse() ) {
  504. // Draw icon image
  505. if ( is_open() ) {
  506. prefs.closeicon()->draw(icon_x,icon_y);
  507. } else {
  508. prefs.openicon()->draw(icon_x,icon_y);
  509. }
  510. }
  511. // Background for this item
  512. int &bx = _label_xywh[0] = X+(icon_w/2-1+prefs.connectorwidth());
  513. int &by = _label_xywh[1] = Y;
  514. int &bw = _label_xywh[2] = W-(icon_w/2-1+prefs.connectorwidth());
  515. int &bh = _label_xywh[3] = H;
  516. // Draw bg only if different from tree's bg
  517. if ( bg != tree->color() || is_selected() ) {
  518. if ( is_selected() ) {
  519. // Selected? Use selectbox() style
  520. fl_draw_box(prefs.selectbox(), bx, by, bw, bh, bg);
  521. } else {
  522. // Not Selected? use plain filled rectangle
  523. fl_color(bg);
  524. fl_rectf(bx, by, bw, bh);
  525. }
  526. }
  527. // Draw user icon (if any)
  528. int useroff = (icon_w/2-1+prefs.connectorwidth());
  529. if ( usericon() ) {
  530. // Item has user icon? Use it
  531. useroff += prefs.usericonmarginleft();
  532. icon_y = textycenter - (usericon()->h() >> 1);
  533. usericon()->draw(X+useroff,icon_y);
  534. useroff += usericon()->w();
  535. } else if ( prefs.usericon() ) {
  536. // Prefs has user icon? Use it
  537. useroff += prefs.usericonmarginleft();
  538. icon_y = textycenter - (prefs.usericon()->h() >> 1);
  539. prefs.usericon()->draw(X+useroff,icon_y);
  540. useroff += prefs.usericon()->w();
  541. }
  542. useroff += prefs.labelmarginleft();
  543. // Draw label
  544. if ( widget() ) {
  545. // Widget? Draw it
  546. int lx = X+useroff;
  547. int ly = by;
  548. int lw = widget()->w();
  549. int lh = bh;
  550. if ( widget()->x() != lx || widget()->y() != ly ||
  551. widget()->w() != lw || widget()->h() != lh ) {
  552. widget()->resize(lx, ly, lw, lh); // fltk will handle drawing this
  553. }
  554. } else {
  555. // No label widget? Draw text label
  556. if ( _label ) {
  557. fl_color(fg);
  558. fl_draw(_label, X+useroff, Y+H-fl_descent()-1);
  559. }
  560. }
  561. Y += H;
  562. } // end drawthis
  563. // Draw children
  564. if ( has_children() && is_open() ) {
  565. int child_x = drawthis ? // offset children to right,
  566. (hcenterx - (icon_w/2) + 1) : X; // unless didn't drawthis
  567. int child_w = W - (child_x-X);
  568. int child_y_start = Y;
  569. for ( int t=0; t<children(); t++ ) {
  570. int lastchild = ((t+1)==children()) ? 1 : 0;
  571. _children[t]->draw(child_x, Y, child_w, tree, prefs, lastchild);
  572. }
  573. if ( has_children() && is_open() ) {
  574. Y += prefs.openchild_marginbottom(); // offset below open child tree
  575. }
  576. if ( ! lastchild ) {
  577. draw_vertical_connector(hstartx, child_y_start, Y, prefs);
  578. }
  579. }
  580. }
  581. /// Was the event on the 'collapse' button?
  582. ///
  583. int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const {
  584. if ( _visible && _active && has_children() && prefs.showcollapse() ) {
  585. return(event_inside(_collapse_xywh) ? 1 : 0);
  586. } else {
  587. return(0);
  588. }
  589. }
  590. /// Was event on the label()?
  591. ///
  592. int Fl_Tree_Item::event_on_label(const Fl_Tree_Prefs &prefs) const {
  593. if ( _visible && _active ) {
  594. return(event_inside(_label_xywh) ? 1 : 0);
  595. } else {
  596. return(0);
  597. }
  598. }
  599. /// Internal: Show the FLTK widget() for this item and all children.
  600. /// Used by open() to re-show widgets that were hidden by a previous close()
  601. ///
  602. void Fl_Tree_Item::show_widgets() {
  603. if ( _widget ) _widget->show();
  604. if ( is_open() ) {
  605. for ( int t=0; t<_children.total(); t++ ) {
  606. _children[t]->show_widgets();
  607. }
  608. }
  609. }
  610. /// Internal: Hide the FLTK widget() for this item and all children.
  611. /// Used by close() to hide widgets.
  612. ///
  613. void Fl_Tree_Item::hide_widgets() {
  614. if ( _widget ) _widget->hide();
  615. for ( int t=0; t<_children.total(); t++ ) {
  616. _children[t]->hide_widgets();
  617. }
  618. }
  619. /// Open this item and all its children.
  620. void Fl_Tree_Item::open() {
  621. _open = 1;
  622. // Tell children to show() their widgets
  623. for ( int t=0; t<_children.total(); t++ ) {
  624. _children[t]->show_widgets();
  625. }
  626. }
  627. /// Close this item and all its children.
  628. void Fl_Tree_Item::close() {
  629. _open = 0;
  630. // Tell children to hide() their widgets
  631. for ( int t=0; t<_children.total(); t++ ) {
  632. _children[t]->hide_widgets();
  633. }
  634. }
  635. /// Returns how many levels deep this item is in the hierarchy.
  636. ///
  637. /// For instance; root has a depth of zero, and its immediate children
  638. /// would have a depth of 1, and so on.
  639. ///
  640. int Fl_Tree_Item::depth() const {
  641. int count = 0;
  642. const Fl_Tree_Item *item = parent();
  643. while ( item ) {
  644. ++count;
  645. item = item->parent();
  646. }
  647. return(count);
  648. }
  649. /// Return the next item in the tree.
  650. ///
  651. /// This method can be used to walk the tree forward.
  652. /// For an example of how to use this method, see Fl_Tree::first().
  653. ///
  654. /// \returns the next item in the tree, or 0 if there's no more items.
  655. ///
  656. Fl_Tree_Item *Fl_Tree_Item::next() {
  657. Fl_Tree_Item *p, *c = this;
  658. if ( c->has_children() ) {
  659. return(c->child(0));
  660. }
  661. while ( ( p = c->parent() ) != NULL ) { // loop upwards through parents
  662. int t = p->find_child(c); // find our position in parent's children[] array
  663. if ( ++t < p->children() ) // not last child?
  664. return(p->child(t)); // return next child
  665. c = p; // child becomes parent to move up generation
  666. } // loop: moves up to next parent
  667. return(0); // hit root? done
  668. }
  669. /// Return the previous item in the tree.
  670. ///
  671. /// This method can be used to walk the tree backwards.
  672. /// For an example of how to use this method, see Fl_Tree::last().
  673. ///
  674. /// \returns the previous item in the tree, or 0 if there's no item above this one (hit the root).
  675. ///
  676. Fl_Tree_Item *Fl_Tree_Item::prev() {
  677. Fl_Tree_Item *p=parent(); // start with parent
  678. if ( ! p ) return(0); // hit root? done
  679. int t = p->find_child(this); // find our position in parent's children[] array
  680. if ( --t == -1 ) { // are we first child?
  681. return(p); // return immediate parent
  682. }
  683. p = p->child(t); // take parent's previous child
  684. while ( p->has_children() ) { // has children?
  685. p = p->child(p->children()-1); // take last child
  686. }
  687. return(p);
  688. }
  689. //
  690. // End of "$Id: Fl_Tree_Item.cxx 7627 2010-06-03 15:46:59Z greg.ercolano $".
  691. //