1 //
2 // "$Id$"
3 //
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <FL/Fl_Tree.H>
10 #include <FL/Fl_Preferences.H>
11 
12 //////////////////////
13 // Fl_Tree.cxx
14 //////////////////////
15 //
16 // Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
17 // Copyright (C) 2009-2010 by Greg Ercolano.
18 //
19 // This library is free software. Distribution and use rights are outlined in
20 // the file "COPYING" which should have been included with this file.  If this
21 // file is missing or damaged, see the license at:
22 //
23 //     http://www.fltk.org/COPYING.php
24 //
25 // Please report all bugs and problems on the following page:
26 //
27 //     http://www.fltk.org/str.php
28 //
29 
30 // INTERNAL: scroller callback (hor+vert scroll)
scroll_cb(Fl_Widget *,void * data)31 static void scroll_cb(Fl_Widget*,void *data) {
32   ((Fl_Tree*)data)->redraw();
33 }
34 
35 // INTERNAL: Parse elements from 'path' into an array of null terminated strings
36 //    Handles escape characters, ignores multiple /'s.
37 //    Path="/aa/bb", returns arr[0]="aa", arr[1]="bb", arr[2]=0.
38 //    Caller must call free_path(arr).
39 //
parse_path(const char * path)40 static char **parse_path(const char *path) {
41   size_t len = strlen(path);
42   char *cp = new char[(len+1)], *word = cp, *s = cp; // freed below or in free_path()
43   char **ap = new char*[(len+1)], **arr = ap;	     // overallocates arr[]
44   while (1) {
45     if (*path =='/' || *path == 0) {		// handle path sep or eos
46       if (word != s) { *s++ = 0; *arr++= word; word = s; }
47       if ( !*path++) break; else continue;	// eos? done, else cont
48     } else if ( *path == '\\' ) {		// handle escape
49       if ( *(++path) ) { *s++ = *path++; } else continue;
50     } else { *s++ = *path++; }			// handle normal char
51   }
52   *arr = 0;
53   if ( arr == ap ) delete[] cp;	// empty arr[]? delete since free_path() can't
54   return ap;
55 }
56 
57 // INTERNAL: Free an array 'arr' returned by parse_path()
free_path(char ** arr)58 static void free_path(char **arr) {
59   if ( arr ) {
60     if ( arr[0] ) { delete[] arr[0]; }	// deletes cp in parse_path
61     delete[] arr;  			// deletes ptr array
62   }
63 }
64 
65 #if 0		/* unused code -- STR #3169 */
66 // INTERNAL: Recursively descend 'item's tree hierarchy
67 //           accumulating total child 'count'
68 //
69 static int find_total_children(Fl_Tree_Item *item, int count=0) {
70   count++;
71   for ( int t=0; t<item->children(); t++ ) {
72     count = find_total_children(item->child(t), count);
73   }
74   return(count);
75 }
76 #endif
77 
78 /// Constructor.
Fl_Tree(int X,int Y,int W,int H,const char * L)79 Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L) {
80 #if FLTK_ABI_VERSION >= 10303
81   _root = new Fl_Tree_Item(this);
82 #else
83   _root = new Fl_Tree_Item(_prefs);
84 #endif
85   _root->parent(0);				// we are root of tree
86   _root->label("ROOT");
87   _item_focus      = 0;
88   _callback_item   = 0;
89   _callback_reason = FL_TREE_REASON_NONE;
90   _scrollbar_size  = 0;				// 0: uses Fl::scrollbar_size()
91 
92 #if FLTK_ABI_VERSION >= 10301
93   // NEW
94   _lastselect       = 0;
95 #else /*FLTK_ABI_VERSION*/
96   // OLD: data initialized static inside handle()
97 #endif /*FLTK_ABI_VERSION*/
98 
99   box(FL_DOWN_BOX);
100   color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR);
101   when(FL_WHEN_CHANGED);
102   int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
103   _vscroll = new Fl_Scrollbar(X+W-scrollsize,Y,scrollsize,H);
104   _vscroll->hide();
105   _vscroll->type(FL_VERTICAL);
106   _vscroll->step(1);
107   _vscroll->callback(scroll_cb, (void*)this);
108 #if FLTK_ABI_VERSION >= 10303
109   _hscroll = new Fl_Scrollbar(X,Y+H-scrollsize,W,scrollsize);
110   _hscroll->hide();
111   _hscroll->type(FL_HORIZONTAL);
112   _hscroll->step(1);
113   _hscroll->callback(scroll_cb, (void*)this);
114   _tox = _tix = X + Fl::box_dx(box());
115   _toy = _tiy = Y + Fl::box_dy(box());
116   _tow = _tiw = W - Fl::box_dw(box());
117   _toh = _tih = H - Fl::box_dh(box());
118   _tree_w = -1;
119   _tree_h = -1;
120 #endif
121   end();
122 }
123 
124 /// Destructor.
~Fl_Tree()125 Fl_Tree::~Fl_Tree() {
126   if ( _root ) { delete _root; _root = 0; }
127 }
128 
129 /// Extend the selection between and including \p 'from' and \p 'to'
130 /// depending on direction \p 'dir', \p 'val', and \p 'visible'.
131 ///
132 /// Efficient: does not walk entire tree; starts with \p 'from' and stops
133 /// at \p 'to' while moving in direction \p 'dir'. Dir must be specified though.
134 #if FLTK_ABI_VERSION >= 10303
135 ///
136 /// If dir cannot be known in advance, such as during SHIFT-click operations,
137 /// the method extend_selection(Fl_Tree_Item*,Fl_Tree_Item*,int,bool)
138 /// should be used.
139 #endif
140 ///
141 /// Handles calling redraw() if anything changed.
142 ///
143 /// \param[in] from Starting item
144 /// \param[in] to   Ending item
145 /// \param[in] dir  Direction to extend selection (FL_Up or FL_Down)
146 /// \param[in] val  0=deselect, 1=select, 2=toggle
147 /// \param[in] visible true=affect only open(), visible items,<br>
148 ///                    false=affect open or closed items (default)
149 /// \returns The number of items whose selection states were changed, if any.
150 /// \version 1.3.3
151 ///
extend_selection_dir(Fl_Tree_Item * from,Fl_Tree_Item * to,int dir,int val,bool visible)152 int Fl_Tree::extend_selection_dir(Fl_Tree_Item *from, Fl_Tree_Item *to,
153 			          int dir, int val, bool visible ) {
154   int changed = 0;
155   for (Fl_Tree_Item *item=from; item; item = next_item(item, dir, visible) ) {
156     switch (val) {
157       case 0:
158 	if ( deselect(item, when()) ) ++changed;
159         break;
160       case 1:
161         if ( select(item, when()) ) ++changed;
162 	break;
163       case 2:
164         select_toggle(item, when());
165 	++changed;	// toggle always involves a change
166 	break;
167     }
168     if ( item==to ) break;
169   }
170   return(changed);
171 }
172 
173 /// Extend a selection between \p 'from' and \p 'to' depending on \p 'visible'.
174 ///
175 /// Similar to the more efficient
176 /// extend_selection_dir(Fl_Tree_Item*,Fl_Tree_Item*,int dir,int val,bool vis)
177 /// method, but direction (up or down) doesn't need to be known.<br>
178 /// We're less efficient because we search the tree for to/from, then operate
179 /// on items in between. The more efficient method avoids the "search",
180 /// but necessitates a direction to be specified to find \p 'to'.<br>
181 /// Used by SHIFT-click to extend a selection between two items inclusive.<br>
182 /// Handles calling redraw() if anything changed.
183 ///
184 /// \param[in] from    Starting item
185 /// \param[in] to      Ending item
186 /// \param[in] val     Select or deselect items (0=deselect, 1=select, 2=toggle)
187 /// \param[in] visible true=affect only open(), visible items,<br>
188 ///                    false=affect open or closed items (default)
189 /// \returns The number of items whose selection states were changed, if any.
190 #if FLTK_ABI_VERSION >= 10303
191 /// \version 1.3.3 ABI feature
extend_selection(Fl_Tree_Item * from,Fl_Tree_Item * to,int val,bool visible)192 int Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to,
193 			      int val, bool visible) {
194 #else
195 /// \note Made public in 1.3.3 ABI
196 // Adding overload if not at least one overload breaks ABI, so avoid
197 // by making a private function until ABI can change..
198 int Fl_Tree::extend_selection__(Fl_Tree_Item *from, Fl_Tree_Item *to,
199 			        int val, bool visible) {
200 #endif
201   int changed = 0;
202   if ( from == to ) {
203     if ( visible && !from->is_visible() ) return(0);	// do nothing
204     switch (val) {
205       case 0:
206         if ( deselect(from, when()) ) ++changed;
207 	break;
208       case 1:
209         if ( select(from, when()) ) ++changed;
210 	break;
211       case 2:
212         select_toggle(from, when());
213 	++changed;		// always changed
214 	break;
215     }
216     return(changed);
217   }
218   char on = 0;
219   for ( Fl_Tree_Item *item = first(); item; item = item->next_visible(_prefs) ) {
220     if ( visible && !item->is_visible() ) continue;
221     if ( on || (item == from) || (item == to) ) {
222       switch (val) {
223 	case 0:
224 	  if ( deselect(item, when()) ) ++changed;
225 	  break;
226 	case 1:
227 	  if ( select(item, when()) ) ++changed;
228 	  break;
229 	case 2:
230 	  select_toggle(item, when());
231 	  ++changed;	// toggle always involves a change
232 	  break;
233       }
234       if ( (item == from) || (item == to) ) {
235         on ^= 1;
236 	if ( !on ) break;	// done
237       }
238     }
239   }
240   return(changed);
241 }
242 
243 #if FLTK_ABI_VERSION >= 10303
244 // not needed, above overload handles this
245 #else
246 /// Extend a selection between \p 'from' and \p 'to'.
247 /// Extends selection for items and all children, visible ('open') or not.
248 /// Walks entire tree from top to bottom looking for \p 'from' and \p 'to'.
249 /// \version 1.3.0
250 ///
251 void Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to) {
252   const int val = 1;		// 0=clr, 1=set, 2=toggle
253   const bool visible = false;	// true=only 'open' items, false='open' or 'closed'
254   extend_selection__(from, to, val, visible);	// use private method until we can release it
255 }
256 #endif
257 
258 /// Standard FLTK event handler for this widget.
259 /// \todo add Fl_Widget_Tracker (see Fl_Browser_.cxx::handle())
260 int Fl_Tree::handle(int e) {
261   if (e == FL_NO_EVENT) return(0);		// XXX: optimize to prevent slow resizes on large trees!
262   int ret = 0;
263   char is_shift   = Fl::event_state() & FL_SHIFT   ? 1 : 0;
264   char is_ctrl    = Fl::event_state() & FL_CTRL    ? 1 : 0;
265   char is_command = Fl::event_state() & FL_COMMAND ? 1 : 0;	// ctrl on win/lin, 'Command' on mac
266 #if FLTK_ABI_VERSION >= 10301
267   // NEW: data inside Fl_Tree
268 #else /*FLTK_ABI_VERSION*/
269   // OLD:
270   static Fl_Tree_Item *_lastselect = 0;		// used to extend selections
271 #endif /*FLTK_ABI_VERSION*/
272   // Developer note: Fl_Browser_::handle() used for reference here..
273   // #include <FL/names.h>	// for event debugging
274   // fprintf(stderr, "DEBUG: %s (%d)\n", fl_eventnames[e], e);
275 
276   if (e == FL_ENTER || e == FL_LEAVE) return(1);
277   switch (e) {
278     case FL_FOCUS: {
279       // FLTK tests if we want focus.
280       //     If a nav key was used to give us focus, and we've got no saved
281       //     focus widget, determine which item gets focus depending on nav key.
282       //
283       if ( ! _item_focus ) {				// no focus established yet?
284 	switch (Fl::event_key()) {			// determine if focus was navigated..
285 	  case FL_Tab: {				// received focus via TAB?
286 	    int updown = is_shift ? FL_Up : FL_Down;	// SHIFT-TAB similar to Up, TAB similar to Down
287 	    set_item_focus(next_visible_item(0, updown));
288 	    break;
289 	  }
290 	  case FL_Left:		// received focus via LEFT or UP?
291 	  case FL_Up: { 	// XK_ISO_Left_Tab
292 	    set_item_focus(next_visible_item(0, FL_Up));
293 	    break;
294 	  }
295 	  case FL_Right: 	// received focus via RIGHT or DOWN?
296 	  case FL_Down:
297 	  default: {
298 	    set_item_focus(next_visible_item(0, FL_Down));
299 	    break;
300 	  }
301 	}
302       }
303       if ( visible_focus() ) redraw();	// draw focus change
304       return(1);
305     }
306     case FL_UNFOCUS: {		// FLTK telling us some other widget took focus.
307       if ( visible_focus() ) redraw();	// draw focus change
308       return(1);
309     }
310     case FL_KEYBOARD: {		// keyboard shortcut
311       // Do shortcuts first or scrollbar will get them...
312       if ( (Fl::focus() == this) &&				// tree has focus?
313            _prefs.selectmode() > FL_TREE_SELECT_NONE ) {	// select mode that supports kb events?
314 	if ( !_item_focus ) {					// no current focus item?
315 	  set_item_focus(first_visible_item());			// use first vis item
316 	  if ( Fl::event_key() == FL_Up ||			// Up or down?
317 	       Fl::event_key() == FL_Down )			// ..if so, already did 'motion'
318 	    return(1);						// ..so just return.
319 	}
320 	if ( _item_focus ) {
321 	  int ekey = Fl::event_key();
322 	  switch (ekey) {
323 	    case FL_Enter:	// ENTER: toggle open/close
324 	    case FL_KP_Enter: {
325 	      open_toggle(_item_focus, when());			// toggle item in focus
326 	      return(1);					// done, we handled key
327 	    }
328 	    case ' ':		// SPACE: change selection state
329 	      switch ( _prefs.selectmode() ) {
330 		case FL_TREE_SELECT_NONE:
331 		  break;					// ignore, let group have shot at event
332 		case FL_TREE_SELECT_SINGLE:
333 		case FL_TREE_SELECT_SINGLE_DRAGGABLE:
334 		  if ( is_ctrl ) {				// CTRL-SPACE: (single mode) toggle
335 		    if ( ! _item_focus->is_selected() ) {
336 		      select_only(_item_focus, when());
337 		    } else {
338 		      deselect_all(0, when());
339 		    }
340 		  } else {
341 		    select_only(_item_focus, when());		// SPACE: (single mode) select only
342 		  }
343 		  _lastselect = _item_focus;
344 	          return(1);					// done, we handled key
345 		case FL_TREE_SELECT_MULTI:
346 		  if ( is_ctrl ) {
347 		    select_toggle(_item_focus, when());		// CTRL-SPACE: (multi mode) toggle selection
348 		  } else {
349 		    select(_item_focus, when());		// SPACE: (multi-mode) select
350 		  }
351 		  _lastselect = _item_focus;
352 	          return(1);					// done, we handled key
353 	      }
354 	      break;
355 	    case FL_Right:  	// RIGHT: open children (if any)
356 	    case FL_Left: {	// LEFT: close children (if any)
357 	      if ( _item_focus ) {
358 		if ( ekey == FL_Right && _item_focus->is_close() ) {
359 		  open(_item_focus);	// open closed item
360 		  ret = 1;
361 		} else if ( ekey == FL_Left && _item_focus->is_open() ) {
362 		  close(_item_focus);	// close open item
363 		  ret = 1;
364 		}
365 		return(1);
366 	      }
367 	      break;
368 	    }
369 	    case FL_Up:		// UP: next item up, or extend selection up
370 	    case FL_Down: {	// DOWN: next item down, or extend selection down
371 	      set_item_focus(next_visible_item(_item_focus, ekey));	// next item up|dn
372 	      if ( _item_focus ) {					// item in focus?
373 	        // Autoscroll
374 		int itemtop = _item_focus->y();
375 		int itembot = _item_focus->y()+_item_focus->h();
376 		if ( itemtop < y() ) { show_item_top(_item_focus); }
377 		if ( itembot > y()+h() ) { show_item_bottom(_item_focus); }
378 		// Extend selection
379 		if ( _prefs.selectmode() == FL_TREE_SELECT_MULTI &&	// multiselect on?
380 		     is_shift &&					// shift key?
381 		     ! _item_focus->is_selected() ) {			// not already selected?
382 		  select(_item_focus, when());				// extend selection..
383 		  _lastselect = _item_focus;
384 		}
385 		return(1);
386 	      }
387 	      break;
388 	    }
389 	    case 'a':
390 	    case 'A': {
391 	      if ( is_command ) {					// ^A (win/linux), Meta-A (mac)
392 		switch ( _prefs.selectmode() ) {
393 		  case FL_TREE_SELECT_NONE:
394 		  case FL_TREE_SELECT_SINGLE:
395 		  case FL_TREE_SELECT_SINGLE_DRAGGABLE:
396 		    break;
397 		  case FL_TREE_SELECT_MULTI:
398 		    // Do a 'select all'
399 	            select_all();
400 		    _lastselect = first_visible_item();
401 		    take_focus();
402 		    return(1);
403 		}
404 	      }
405 	      break;
406 	    }
407 	  }
408 	}
409       }
410       break;
411     }
412   }
413 
414   // Let Fl_Group take a shot at handling the event
415   if (Fl_Group::handle(e)) {
416     return(1);			// handled? don't continue below
417   }
418 
419   // Handle events the child FLTK widgets didn't need
420 
421   // fprintf(stderr, "Fl_Tree::handle(): Event was %s (%d)\n", fl_eventnames[e], e); // DEBUGGING
422   if ( ! _root ) return(ret);
423   static int last_my = 0;
424   switch ( e ) {
425     case FL_PUSH: {		// clicked on tree
426       last_my = Fl::event_y();	// save for dragging direction..
427       if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
428 #if FLTK_ABI_VERSION >= 10303
429       Fl_Tree_Item *item = _root->find_clicked(_prefs, 0);
430 #else
431       Fl_Tree_Item *item = _root->find_clicked(_prefs);
432 #endif
433       if ( !item ) {		// clicked, but not on an item?
434         _lastselect = 0;
435 	switch ( _prefs.selectmode() ) {
436 	  case FL_TREE_SELECT_NONE:
437 	    break;
438 	  case FL_TREE_SELECT_SINGLE:
439 	  case FL_TREE_SELECT_SINGLE_DRAGGABLE:
440 	  case FL_TREE_SELECT_MULTI:
441 	    deselect_all();
442 	    break;
443 	}
444 	break;
445       }
446       set_item_focus(item);			// becomes new focus widget, calls redraw() if needed
447       ret |= 1;					// handled
448       if ( Fl::event_button() == FL_LEFT_MOUSE ) {
449 	if ( item->event_on_collapse_icon(_prefs) ) {	// collapse icon clicked?
450 	  open_toggle(item);				// toggle open (handles redraw)
451 	} else if ( item->event_on_label(_prefs) && 	// label clicked?
452 		 (!item->widget() || !Fl::event_inside(item->widget())) ) {	// not inside widget
453 	  switch ( _prefs.selectmode() ) {
454 	    case FL_TREE_SELECT_NONE:
455 	      break;
456 	    case FL_TREE_SELECT_SINGLE:
457 	    case FL_TREE_SELECT_SINGLE_DRAGGABLE:
458 	      select_only(item, when());		// select only this item (handles redraw)
459 	      _lastselect = item;
460 	      break;
461 	    case FL_TREE_SELECT_MULTI: {
462 	      if ( is_shift ) {			// SHIFT+PUSH?
463 	        if ( _lastselect ) {
464 		  int val = is_ctrl ? 2 : 1;
465 		  bool visible = true;
466 #if FLTK_ABI_VERSION >= 10303
467 	          extend_selection(_lastselect, item, val, visible);
468 #else
469 	          extend_selection__(_lastselect, item, val, visible);
470 #endif
471 	        } else {
472 	          select(item);			// add to selection
473 		}
474 	      } else if ( is_ctrl ) {		// CTRL+PUSH?
475 		select_toggle(item, when());	// toggle selection state
476 	      } else {
477 		select_only(item, when());
478 	      }
479 	      _lastselect = item;
480 	      break;
481 	    }
482 	  }
483 	}
484       }
485       break;
486     }
487     case FL_DRAG: {
488       // Do scrolling first..
489 
490       // Detect up/down dragging
491       int my = Fl::event_y();
492       int dir = (my>last_my) ? FL_Down : FL_Up;
493       last_my = my;
494 
495       // Handle autoscrolling
496       if ( my < y() ) {				// Above top?
497         dir = FL_Up;				// ..going up
498         int p = vposition()-(y()-my);		// ..position above us
499 	if ( p < 0 ) p = 0;			// ..don't go above 0
500         vposition(p);				// ..scroll to new position
501       } else if ( my > (y()+h()) ) {		// Below bottom?
502         dir = FL_Down;				// ..going down
503         int p = vposition()+(my-y()-h());	// ..position below us
504 	if ( p > (int)_vscroll->maximum() )	// ..don't go below bottom
505 	  p = (int)_vscroll->maximum();
506         vposition(p);				// ..scroll to new position
507       }
508 
509       // Now handle the event..
510       //    During drag, only interested in left-mouse operations.
511       //
512       if ( Fl::event_button() != FL_LEFT_MOUSE ) break;
513 #if FLTK_ABI_VERSION >= 10303
514       Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically
515 #else
516       Fl_Tree_Item *item = _root->find_clicked(_prefs); // item we're on, vertically
517 #endif
518       if ( !item ) break;			// not near item? ignore drag event
519       ret |= 1;					// acknowledge event
520       if (_prefs.selectmode() != FL_TREE_SELECT_SINGLE_DRAGGABLE)
521         set_item_focus(item);			// becomes new focus item
522       if (item==_lastselect) break;		// same item as before? avoid reselect
523 
524       // Handle selection behavior
525       switch ( _prefs.selectmode() ) {
526 	case FL_TREE_SELECT_NONE:
527 	  break;				// no selection changes
528 	case FL_TREE_SELECT_SINGLE: {
529 	  select_only(item, when());		// select only this item (handles redraw)
530 	  break;
531 	}
532 	case FL_TREE_SELECT_SINGLE_DRAGGABLE: {
533 	  item = _lastselect; // Keep the source intact
534 	  redraw();
535 	  break;
536 	}
537 	case FL_TREE_SELECT_MULTI: {
538 	  Fl_Tree_Item *from = next_visible_item(_lastselect, dir); // avoid reselecting item
539 	  Fl_Tree_Item *to = item;
540 	  int val = is_ctrl ? 2 : 1;	// toggle_select() or just select()?
541 	  bool visible = true;
542 	  extend_selection_dir(from, to, dir, val, visible);
543 	  break;
544 	}
545       }
546       _lastselect = item;			// save current item for later
547       break;
548     }
549     case FL_RELEASE:
550       if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
551           Fl::event_button() == FL_LEFT_MOUSE) {
552 #if FLTK_ABI_VERSION >= 10303
553         Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically
554 #else
555         Fl_Tree_Item *item = _root->find_clicked(_prefs); // item we're on, vertically
556 #endif
557 
558         if (item && _lastselect && item != _lastselect &&
559             Fl::event_x() >= item->label_x()) {
560           //printf("Would drag '%s' to '%s'\n", _lastselect->label(), item->label());
561           // Are we dropping above or below the target item?
562           const int h = Fl::event_y() - item->y();
563           const int mid = item->h() / 2;
564           const bool before = h < mid;
565           //printf("Dropping %s it\n", before ? "before" : "after");
566 
567           // Do nothing if it would be a no-op
568           if ((before && prev(item) != _lastselect) ||
569               (!before && next(item) != _lastselect)) {
570             Fl_Tree_Item *parent = item->parent();
571 
572             if (parent) {
573               int pos = parent->find_child(item);
574               if (!before)
575                 pos++;
576 
577               // Special case: trying to drop right before a folder
578               if (item->children() && item->is_open() && !before) {
579                 parent = item;
580                 pos = 0;
581               }
582 
583               // If we're moving inside the same parent, use the below/above methods
584               if (_lastselect->parent() == parent) {
585                 if (before) {
586                   _lastselect->move_above(item);
587                 } else {
588                   _lastselect->move_below(item);
589                 }
590               } else {
591                 _lastselect->move_into(parent, pos);
592               }
593 
594               redraw();
595               do_callback_for_item(_lastselect, FL_TREE_REASON_DRAGGED);
596             }
597           }
598         }
599         redraw();
600       } // End single-drag check
601       ret |= 1;
602       break;
603   }
604   return(ret);
605 }
606 
607 #if FLTK_ABI_VERSION >= 10303
608 // nothing
609 #else
610 // Redraw timeout callback
611 // (Only need this hack for old ABI 10302 and older)
612 //
613 static void redraw_soon(void *data) {
614   ((Fl_Tree*)data)->redraw();
615   Fl::remove_timeout(redraw_soon, data);
616 }
617 #endif
618 
619 #if FLTK_ABI_VERSION >= 10303
620 /// Recalculate widget dimensions and scrollbar visibility,
621 /// normally managed automatically.
622 ///
623 /// Low overhead way to update the tree widget's outer/inner dimensions
624 /// and re-determine scrollbar visibility based on these changes without
625 /// recalculating the entire size of the tree data.
626 ///
627 /// Assumes that either the tree's size in _tree_w/_tree_h are correct
628 /// so that scrollbar visibility can be calculated easily, or are both
629 /// zero indicating scrollbar visibility can't be calculated yet.
630 ///
631 /// This method is called when the widget is resize()ed or if the
632 /// scrollbar's sizes are changed (affects tree widget's inner dimensions
633 /// tix/y/w/h), and also used by calc_tree().
634 /// \version 1.3.3 ABI feature
635 ///
636 void Fl_Tree::calc_dimensions() {
637   // Calc tree outer xywh
638   //    Area of the tree widget /outside/ scrollbars
639   //
640   _tox = x() + Fl::box_dx(box());
641   _toy = y() + Fl::box_dy(box());
642   _tow = w() - Fl::box_dw(box());
643   _toh = h() - Fl::box_dh(box());
644 
645   // Scrollbar visiblity + positions
646   //    Calc this ONLY if tree_h and tree_w have been calculated.
647   //    Zero values for these indicate calc in progress, but not done yet.
648   //
649   if ( _tree_h >= 0 && _tree_w >= 0 ) {
650     int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
651     int vshow = _tree_h > _toh ? 1 : 0;
652     int hshow = _tree_w > _tow ? 1 : 0;
653     // See if one scroller's appearance affects the other's visibility
654     if ( hshow && !vshow && (_tree_h > (_toh-scrollsize)) ) vshow = 1;
655     if ( vshow && !hshow && (_tree_w > (_tow-scrollsize)) ) hshow = 1;
656     // vertical scrollbar visibility
657     if ( vshow ) {
658       _vscroll->show();
659       _vscroll->resize(_tox+_tow-scrollsize, _toy,
660 		       scrollsize, h()-Fl::box_dh(box()) - (hshow ? scrollsize : 0));
661     } else {
662       _vscroll->hide();
663       _vscroll->value(0);
664     }
665     // horizontal scrollbar visibility
666     if ( hshow ) {
667       _hscroll->show();
668       _hscroll->resize(_tox, _toy+_toh-scrollsize,
669 		       _tow - (vshow ? scrollsize : 0), scrollsize);
670     } else {
671       _hscroll->hide();
672       _hscroll->value(0);
673     }
674 
675     // Calculate inner dimensions
676     //    The area the tree occupies inside the scrollbars and margins
677     //
678     _tix = _tox;
679     _tiy = _toy;
680     _tiw = _tow - (_vscroll->visible() ? _vscroll->w() : 0);
681     _tih = _toh - (_hscroll->visible() ? _hscroll->h() : 0);
682 
683     // Scrollbar tab sizes
684     _vscroll->slider_size(float(_tih) / float(_tree_h));
685     _vscroll->range(0.0, _tree_h - _tih);
686 
687     _hscroll->slider_size(float(_tiw) / float(_tree_w));
688     _hscroll->range(0.0, _tree_w - _tiw);
689   } else {
690     // Best we can do without knowing tree_h/tree_w
691     _tix = _tox;
692     _tiy = _toy;
693     _tiw = _tow;
694     _tih = _toh;
695   }
696 }
697 
698 /// Recalculates the tree's sizes and scrollbar visibility,
699 /// normally managed automatically.
700 ///
701 /// On return:
702 ///
703 ///	- _tree_w will be the overall pixel width of the entire viewable tree
704 ///	- _tree_h will be the overall pixel height ""
705 ///     - scrollbar visibility and pan sizes are updated
706 ///     - internal _tix/_tiy/_tiw/_tih dimensions are updated
707 ///
708 /// _tree_w/_tree_h include the tree's margins (e.g. marginleft()),
709 /// whether items are open or closed, label contents and font sizes, etc.
710 ///
711 /// The tree hierarchy's size is managed separately from the widget's
712 /// size as an optimization; this way resize() on the widget doesn't
713 /// involve recalculating the tree's hierarchy needlessly, as widget
714 /// size has no bearing on the tree hierarchy.
715 ///
716 /// The tree hierarchy's size only changes when items are added/removed,
717 /// open/closed, label contents or font sizes changed, margins changed, etc.
718 ///
719 /// This calculation involves walking the *entire* tree from top to bottom,
720 /// potentially a slow calculation if the tree has many items (potentially
721 /// hundreds of thousands), and should therefore be called sparingly.
722 ///
723 /// For this reason, recalc_tree() is used as a way to /schedule/
724 /// calculation when changes affect the tree hierarchy's size.
725 ///
726 /// Apps may want to call this method directly if the app makes changes
727 /// to the tree's geometry, then immediately needs to work with the tree's
728 /// new dimensions before an actual redraw (and recalc) occurs. (This
729 /// use by an app should only rarely be needed)
730 ///
731 void Fl_Tree::calc_tree() {
732   // Set tree width and height to zero, and recalc just _tox/_toy/_tow/_toh for now.
733   _tree_w = _tree_h = -1;
734   calc_dimensions();
735   if ( !_root ) return;
736   // Walk the tree to determine its width and height.
737   // We need this to compute scrollbars..
738   // By the end, 'Y' will be the lowest point on the tree
739   //
740   int X = _tix + _prefs.marginleft() + _hscroll->value();
741   int Y = _tiy + _prefs.margintop()  - _vscroll->value();
742   int W = _tiw;
743   // Adjust root's X/W if connectors off
744   if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) {
745     X -= _prefs.openicon()->w();
746     W += _prefs.openicon()->w();
747   }
748   int xmax = 0, render = 0, ytop = Y;
749   fl_font(_prefs.labelfont(), _prefs.labelsize());
750   _root->draw(X, Y, W, 0, xmax, 1, render);		// descend into tree without drawing (render=0)
751   // Save computed tree width and height
752   _tree_w = _prefs.marginleft() + xmax - X;		// include margin in tree's width
753   _tree_h = _prefs.margintop()  + Y - ytop;		// include margin in tree's height
754   // Calc tree dims again; now that tree_w/tree_h are known, scrollbars are calculated.
755   calc_dimensions();
756 }
757 #endif
758 
759 void Fl_Tree::resize(int X,int Y,int W, int H) {
760   fix_scrollbar_order();
761   Fl_Group::resize(X,Y,W,H);
762 #if FLTK_ABI_VERSION >= 10303
763   calc_dimensions();
764 #endif
765   init_sizes();
766 }
767 
768 #if FLTK_ABI_VERSION >= 10303
769 /// Standard FLTK draw() method, handles drawing the tree widget.
770 void Fl_Tree::draw() {
771   fix_scrollbar_order();
772   // Has tree recalc been scheduled? If so, do it
773   if ( _tree_w == -1 ) calc_tree();
774   else calc_dimensions();
775   // Let group draw box+label but *NOT* children.
776   // We handle drawing children ourselves by calling each item's draw()
777   {
778     // Draw group's bg + label
779     if ( damage() & ~FL_DAMAGE_CHILD) {	// redraw entire widget?
780       Fl_Group::draw_box();
781       Fl_Group::draw_label();
782     }
783     if ( ! _root ) return;
784     // These values are changed during drawing
785     // By end, 'Y' will be the lowest point on the tree
786     int X = _tix + _prefs.marginleft() - _hscroll->value();
787     int Y = _tiy + _prefs.margintop()  - _vscroll->value();
788     int W = _tiw - X + _tix;
789     // Adjust root's X/W if connectors off
790     if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) {
791       X -= _prefs.openicon()->w();
792       W += _prefs.openicon()->w();
793     }
794     // Draw entire tree, starting with root
795     fl_push_clip(_tix,_tiy,_tiw,_tih);
796     {
797       int xmax = 0;
798       fl_font(_prefs.labelfont(), _prefs.labelsize());
799       _root->draw(X, Y, W, 				// descend into tree here to draw it
800 		  (Fl::focus()==this)?_item_focus:0,	// show focus item ONLY if Fl_Tree has focus
801 		  xmax, 1, 1);
802     }
803     fl_pop_clip();
804   }
805   // Draw scrollbars last
806   draw_child(*_vscroll);
807   draw_child(*_hscroll);
808   // That little tile between the scrollbars
809   if ( _vscroll->visible() && _hscroll->visible() ) {
810     fl_color(_vscroll->color());
811     fl_rectf(_hscroll->x()+_hscroll->w(),
812              _vscroll->y()+_vscroll->h(),
813 	     _vscroll->w(),
814 	     _hscroll->h());
815   }
816 
817   // Draw dragging line
818   if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
819       Fl::pushed() == this) {
820 
821     Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically
822     if (item && item != _item_focus) {
823       // Are we dropping above or before the target item?
824       const int h = Fl::event_y() - item->y();
825       const int mid = item->h() / 2;
826       const bool before = h < mid;
827 
828       fl_color(FL_BLACK);
829 
830       int tgt = item->y() + (before ? 0 : item->h());
831       fl_line(item->x(), tgt, item->x() + item->w(), tgt);
832     }
833   }
834 }
835 #else
836 /// Standard FLTK draw() method, handles drawing the tree widget.
837 void Fl_Tree::draw() {
838   int ytoofar = draw_tree();
839 
840   // See if we're scrolled below bottom of tree
841   //   This can happen if someone just closed a large item.
842   //   If so, change scroller as needed.
843   //
844   if ( _vscroll->visible() && ytoofar > 0 ) {
845     int scrollval = _vscroll->value();
846     int ch = h() - Fl::box_dh(box());
847     int range2 = scrollval - ytoofar;
848     int size2 = ch + range2;
849     if ( range2 < 0 ) {
850       _vscroll->value(0);
851       _vscroll->hide();
852     } else {
853       _vscroll->slider_size(float(ch)/float(size2));
854       _vscroll->range(0.0,range2);
855       _vscroll->value(range2);
856     }
857     Fl::add_timeout(.10, redraw_soon, (void*)this);	// use timer to trigger redraw; we can't
858   }
859 
860   // Draw dragging line
861   if (_prefs.selectmode() == FL_TREE_SELECT_SINGLE_DRAGGABLE &&
862       Fl::pushed() == this) {
863 
864     Fl_Tree_Item *item = _root->find_clicked(_prefs); // item we're on, vertically
865     if (item && item != _item_focus) {
866       // Are we dropping above or before the target item?
867       const int h = Fl::event_y() - item->y();
868       const int mid = item->h() / 2;
869       const bool before = h < mid;
870 
871       fl_color(FL_BLACK);
872 
873       int tgt = item->y() + (before ? 0 : item->h());
874       fl_line(item->x(), tgt, item->x() + item->w(), tgt);
875     }
876   }
877 }
878 
879 // This method is undocumented, and has been removed in ABI 1.3.3
880 int Fl_Tree::draw_tree() {
881   int ret = 0;
882   fix_scrollbar_order();
883   // Let group draw box+label but *NOT* children.
884   // We handle drawing children ourselves by calling each item's draw()
885   //
886   int cx = x() + Fl::box_dx(box());
887   int cy = y() + Fl::box_dy(box());
888   int cw = w() - Fl::box_dw(box());
889   int ch = h() - Fl::box_dh(box());
890   {
891     // Handle group's bg
892     if ( damage() & ~FL_DAMAGE_CHILD) {			// redraw entire widget?
893       Fl_Group::draw_box();
894       Fl_Group::draw_label();
895     }
896     if ( ! _root ) return(0);
897     // These values are changed during drawing
898     // By end, 'Y' will be the lowest point on the tree
899     int X = cx + _prefs.marginleft();
900     int Y = cy + _prefs.margintop() - (_vscroll->visible() ? _vscroll->value() : 0);
901     int W = cw - _prefs.marginleft();			// - _prefs.marginright();
902     // Adjust root's X/W if connectors off
903     if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) {
904       X -= _prefs.openicon()->w();
905       W += _prefs.openicon()->w();
906     }
907     int Ysave = Y;
908     fl_push_clip(cx,cy,cw,ch);
909     {
910       fl_font(_prefs.labelfont(), _prefs.labelsize());
911       _root->draw(X, Y, W, this,
912 		  (Fl::focus()==this)?_item_focus:0,	// show focus item ONLY if Fl_Tree has focus
913 		  _prefs);
914     }
915     fl_pop_clip();
916 
917     // Show vertical scrollbar?
918     {
919 #if FLTK_ABI_VERSION >= 10301
920       // NEW
921       int SY = Y + _prefs.marginbottom();
922 #else /*FLTK_ABI_VERSION*/
923       // OLD
924       int SY = Y;
925 #endif /*FLTK_ABI_VERSION*/
926       int ydiff = (SY+_prefs.margintop())-Ysave;		// ydiff=size of tree
927       int ytoofar = (cy+ch) - SY;				// ytoofar -- if >0, scrolled beyond bottom
928       if ( ytoofar > 0 ) ydiff += ytoofar;
929       if ( Ysave<cy || ydiff>ch || int(_vscroll->value())>1 ) {
930 	_vscroll->visible();
931 	int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
932 	int sx = x()+w()-Fl::box_dx(box())-scrollsize;
933 	int sy = y()+Fl::box_dy(box());
934 	int sw = scrollsize;
935 	int sh = h()-Fl::box_dh(box());
936 	_vscroll->show();
937 	_vscroll->resize(sx,sy,sw,sh);
938 	_vscroll->slider_size(float(ch)/float(ydiff));
939 	_vscroll->range(0.0,ydiff-ch);
940 	ret = ytoofar;
941       } else {
942 	_vscroll->Fl_Slider::value(0);
943 	_vscroll->hide();
944 	ret = 0;
945       }
946     }
947   }
948   draw_child(*_vscroll);	// draw scroll last
949   return(ret);
950 }
951 #endif
952 
953 /// Print the tree as 'ascii art' to stdout.
954 /// Used mainly for debugging.
955 /// \todo should be const
956 /// \version 1.3.0
957 ///
958 void Fl_Tree::show_self() {
959   if ( ! _root ) return;
960   _root->show_self();
961 }
962 
963 /// Set the label for the root item to \p 'new_label'.
964 ///
965 /// Makes an internally managed copy of 'new_label'.
966 ///
967 void Fl_Tree::root_label(const char *new_label) {
968   if ( ! _root ) return;
969   _root->label(new_label);
970 }
971 
972 /// Returns the root item.
973 Fl_Tree_Item* Fl_Tree::root() {
974   return(_root);
975 }
976 
977 /// Sets the root item to \p 'newitem'.
978 ///
979 /// If a root item already exists, clear() is called first to clear it
980 /// before replacing it with newitem.
981 ///
982 #if FLTK_ABI_VERSION >= 10303
983 /// Use this to install a custom item (derived from Fl_Tree_Item) as the root
984 /// of the tree. This allows the derived class to implement custom drawing
985 /// by overriding Fl_Tree_Item::draw_item_content().
986 ///
987 #endif
988 /// \version 1.3.3
989 ///
990 void Fl_Tree::root(Fl_Tree_Item *newitem) {
991   if ( _root ) clear();
992   _root = newitem;
993 }
994 
995 /// Adds a new item, given a menu style \p 'path'.
996 /// Any parent nodes that don't already exist are created automatically.
997 /// Adds the item based on the value of sortorder().
998 /// If \p 'item' is NULL, a new item is created.
999 ///
1000 /// To specify items or submenus that contain slashes ('/' or '\')
1001 /// use an escape character to protect them, e.g.
1002 /// \code
1003 ///     tree->add("/Holidays/Photos/12\\/25\\/2010");         // Adds item "12/25/2010"
1004 ///     tree->add("/Pathnames/c:\\\\Program Files\\\\MyApp"); // Adds item "c:\Program Files\MyApp"
1005 /// \endcode
1006 /// \param[in] path The path to the item, e.g. "Flintstone/Fred".
1007 /// \param[in] item The new item to be added.
1008 ///                 If NULL, a new item is created with
1009 ///                 a name that is the last element in \p 'path'.
1010 /// \returns The new item added, or 0 on error.
1011 /// \version 1.3.3
1012 ///
1013 Fl_Tree_Item* Fl_Tree::add(const char *path, Fl_Tree_Item *item) {
1014   // Tree has no root? make one
1015   if ( ! _root ) {
1016 #if FLTK_ABI_VERSION >= 10303
1017     _root = new Fl_Tree_Item(this);
1018 #else
1019     _root = new Fl_Tree_Item(_prefs);
1020 #endif
1021     _root->parent(0);
1022     _root->label("ROOT");
1023   }
1024   // Find parent item via path
1025   char **arr = parse_path(path);
1026   item = _root->add(_prefs, arr, item);
1027   free_path(arr);
1028   return(item);
1029 }
1030 
1031 #if FLTK_ABI_VERSION >= 10303
1032 // do nothing here: add(path,item) where item defaults to 0 takes its place
1033 #else
1034 /// Adds a new item given a menu style \p 'path'.
1035 /// Same as calling add(path, NULL);
1036 /// \param[in] path The path to the item to be created, e.g. "Flintstone/Fred".
1037 /// \returns The new item added, or 0 on error.
1038 /// \see add(const char*,Fl_Tree_Item*)
1039 /// \version 1.3.0 release
1040 ///
1041 Fl_Tree_Item* Fl_Tree::add(const char *path) {
1042   return add(path, 0);
1043 }
1044 #endif
1045 
1046 /// Add a new child item labeled \p 'name' to the specified \p 'parent_item'.
1047 ///
1048 /// \param[in] parent_item The parent item the new child item will be added to.
1049 ///                        Must not be NULL.
1050 /// \param[in] name The label for the new item
1051 /// \returns The new item added.
1052 /// \version 1.3.0 release
1053 ///
1054 Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *parent_item, const char *name) {
1055   return(parent_item->add(_prefs, name));
1056 }
1057 
1058 /// Inserts a new item \p 'name' above the specified Fl_Tree_Item \p 'above'.
1059 /// Example:
1060 /// \code
1061 /// tree->add("Aaa/000");       // "000" is index 0 in Aaa's children
1062 /// tree->add("Aaa/111");       // "111" is index 1 in Aaa's children
1063 /// tree->add("Aaa/222");       // "222" is index 2 in Aaa's children
1064 /// ..
1065 /// // How to use insert_above() to insert a new item above Aaa/222
1066 /// Fl_Tree_Item *item = tree->find_item("Aaa/222");  // get item Aaa/222
1067 /// if (item) tree->insert_above(item, "New item");   // insert new item above it
1068 /// \endcode
1069 ///
1070 /// \param[in] above -- the item above which to insert the new item. Must not be NULL.
1071 /// \param[in] name -- the name of the new item
1072 /// \returns The new item added, or 0 if 'above' could not be found.
1073 /// \see insert()
1074 ///
1075 Fl_Tree_Item* Fl_Tree::insert_above(Fl_Tree_Item *above, const char *name) {
1076   return(above->insert_above(_prefs, name));
1077 }
1078 
1079 /// Insert a new item \p 'name' into \p 'item's children at position \p 'pos'.
1080 ///
1081 /// If \p pos is out of range the new item is
1082 ///  - prepended if \p pos \< 0 or
1083 ///  - appended  if \p pos \> item->children().
1084 ///
1085 /// Note: \p pos == children() is not considered out of range: the item is
1086 /// appended to the child list.
1087 /// Example:
1088 /// \code
1089 /// tree->add("Aaa/000");       // "000" is index 0 in Aaa's children
1090 /// tree->add("Aaa/111");       // "111" is index 1 in Aaa's children
1091 /// tree->add("Aaa/222");       // "222" is index 2 in Aaa's children
1092 /// ..
1093 /// // How to use insert() to insert a new item between Aaa/111 + Aaa/222
1094 /// Fl_Tree_Item *item = tree->find_item("Aaa");  // get parent item Aaa
1095 /// if (item) tree->insert(item, "New item", 2);  // insert as a child of Aaa at index #2
1096 /// \endcode
1097 ///
1098 /// \param[in] item The existing item to insert new child into. Must not be NULL.
1099 /// \param[in] name The label for the new item
1100 /// \param[in] pos The position of the new item in the child list
1101 /// \returns The new item added.
1102 /// \see insert_above()
1103 ///
1104 Fl_Tree_Item* Fl_Tree::insert(Fl_Tree_Item *item, const char *name, int pos) {
1105   return(item->insert(_prefs, name, pos));
1106 }
1107 
1108 /// Remove the specified \p 'item' from the tree.
1109 /// \p item may not be NULL.
1110 /// If it has children, all those are removed too.
1111 /// If item being removed has focus, no item will have focus.
1112 /// \returns 0 if done, -1 if 'item' not found.
1113 ///
1114 int Fl_Tree::remove(Fl_Tree_Item *item) {
1115   // Item being removed is focus item? zero focus
1116   if ( item == _item_focus ) _item_focus = 0;
1117 #if FLTK_ABI_VERSION >= 10301
1118   if ( item == _lastselect ) _lastselect = 0;
1119 #endif /*FLTK_ABI_VERSION*/
1120   if ( item == _root ) {
1121     clear();
1122   } else {
1123     Fl_Tree_Item *parent = item->parent();	// find item's parent
1124     if ( ! parent ) return(-1);
1125     parent->remove_child(item);			// remove child + children
1126   }
1127   return(0);
1128 }
1129 
1130 /// Clear the entire tree's children, including the root.
1131 /// The tree will be left completely empty.
1132 ///
1133 void Fl_Tree::clear() {
1134   if ( ! _root ) return;
1135   _root->clear_children();
1136   delete _root; _root = 0;
1137   _item_focus = 0;
1138 #if FLTK_ABI_VERSION >= 10301
1139   _lastselect = 0;
1140 #endif /*FLTK_ABI_VERSION*/
1141 }
1142 
1143 /// Clear all the children for \p 'item'.
1144 /// Item may not be NULL.
1145 ///
1146 void Fl_Tree::clear_children(Fl_Tree_Item *item) {
1147   if ( item->has_children() ) {
1148     item->clear_children();
1149     redraw();				// redraw only if there were children to clear
1150   }
1151 }
1152 
1153 /// Find the item, given a menu style path, e.g. "/Parent/Child/item".
1154 /// There is both a const and non-const version of this method.
1155 /// Const version allows pure const methods to use this method
1156 /// to do lookups without causing compiler errors.
1157 ///
1158 /// To specify items or submenus that contain slashes ('/' or '\')
1159 /// use an escape character to protect them, e.g.
1160 ///
1161 /// \code
1162 ///     tree->add("/Holidays/Photos/12\\/25\\/2010");         // Adds item "12/25/2010"
1163 ///     tree->add("/Pathnames/c:\\\\Program Files\\\\MyApp"); // Adds item "c:\Program Files\MyApp"
1164 /// \endcode
1165 ///
1166 /// \param[in] path -- the tree item's pathname to be found (e.g. "Flintstones/Fred")
1167 /// \returns The item, or NULL if not found.
1168 /// \see item_pathname()
1169 ///
1170 const Fl_Tree_Item *Fl_Tree::find_item(const char *path) const {
1171   if ( ! _root ) return(NULL);
1172   char **arr = parse_path(path);
1173   const Fl_Tree_Item *item = _root->find_item(arr);
1174   free_path(arr);
1175   return(item);
1176 }
1177 
1178 /// Non-const version of Fl_Tree::find_item(const char *path) const
1179 Fl_Tree_Item *Fl_Tree::find_item(const char *path) {
1180   // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
1181   return(const_cast<Fl_Tree_Item*>(
1182 	 static_cast<const Fl_Tree&>(*this).find_item(path)));
1183 }
1184 
1185 // Handle safe 'reverse string concatenation'.
1186 //   In the following we build the pathname from right-to-left,
1187 //   since we start at the child and work our way up to the root.
1188 //
1189 #define SAFE_RCAT(c) { \
1190   slen += 1; if ( slen >= pathnamelen ) { pathname[0] = '\0'; return(-2); } \
1191   *s-- = c; \
1192   }
1193 
1194 /// Return \p 'pathname' of size \p 'pathnamelen' for the specified \p 'item'.
1195 ///
1196 /// If \p 'item' is NULL, root() is used.<br>
1197 /// The tree's root will be included in the pathname if showroot() is on.<br>
1198 /// Menu items or submenus that contain slashes ('/' or '\') in their names
1199 /// will be escaped with a backslash. This is symmetrical with the add()
1200 /// function which uses the same escape pattern to set names.
1201 ///
1202 /// \param[out] pathname The string to use to return the pathname
1203 /// \param[in] pathnamelen The maximum length of the string (including NULL). Must not be zero.
1204 /// \param[in] item The item whose pathname is to be returned.
1205 /// \returns
1206 ///	-   0 : OK (\p pathname returns the item's pathname)
1207 ///	-  -1 : item not found (pathname="")
1208 ///	-  -2 : pathname not large enough (pathname="")
1209 /// \see find_item()
1210 ///
1211 int Fl_Tree::item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item *item) const {
1212   pathname[0] = '\0';
1213   item = item ? item : _root;
1214   if ( !item ) return(-1);
1215   // Build pathname starting at end
1216   char *s = (pathname+pathnamelen-1);
1217   int slen = 0;			// length of string compiled so far (including NULL)
1218   SAFE_RCAT('\0');
1219   while ( item ) {
1220     if ( item->is_root() && showroot() == 0 ) break;		// don't include root in path if showroot() off
1221     // Find name of current item
1222     const char *name = item->label() ? item->label() : "???";	// name for this item
1223     int len = (int) strlen(name);
1224     // Add name to end of pathname[]
1225     for ( --len; len>=0; len-- ) {
1226       SAFE_RCAT(name[len]);					// rcat name of item
1227       if ( name[len] == '/' || name[len] == '\\' ) {
1228         SAFE_RCAT('\\');					// escape front or back slashes within name
1229       }
1230     }
1231     SAFE_RCAT('/');						// rcat leading slash
1232     item = item->parent();					// move up tree (NULL==root)
1233   }
1234   if ( *(++s) == '/' ) { ++s; --slen; }				// leave off leading slash from pathname
1235   if ( s != pathname ) memmove(pathname, s, slen);	// Shift down right-aligned string
1236   return(0);
1237 }
1238 
1239 #if FLTK_ABI_VERSION >= 10303
1240 /// Find the item that was last clicked on.
1241 /// You should use callback_item() instead, which is fast,
1242 /// and is meant to be used within a callback to determine the item clicked.
1243 ///
1244 /// This method walks the entire tree looking for the first item that is
1245 /// under the mouse. (The value of the \p 'yonly' flag affects whether
1246 /// both x and y events are checked, or just y)
1247 ///
1248 /// Use this method /only/ if you've subclassed Fl_Tree, and are receiving
1249 /// events before Fl_Tree has been able to process and update callback_item().
1250 ///
1251 /// \param[in] yonly -- 0: check both event's X and Y values.
1252 ///                  -- 1: only check event's Y value, don't care about X.
1253 /// \returns The item clicked, or NULL if no item was under the current event.
1254 /// \version 1.3.0
1255 /// \version 1.3.3 ABI feature: added yonly parameter
1256 ///
1257 const Fl_Tree_Item* Fl_Tree::find_clicked(int yonly) const {
1258   if ( ! _root ) return(NULL);
1259   return(_root->find_clicked(_prefs, yonly));
1260 }
1261 
1262 /// Non-const version of Fl_Tree::find_clicked(int yonly) const.
1263 Fl_Tree_Item *Fl_Tree::find_clicked(int yonly) {
1264   // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
1265   return(const_cast<Fl_Tree_Item*>(
1266 	 static_cast<const Fl_Tree&>(*this).find_clicked(yonly)));
1267 }
1268 #else
1269 /// Find the item that was last clicked on.
1270 /// You should use callback_item() instead, which is fast,
1271 /// and is meant to be used within a callback to determine the item clicked.
1272 ///
1273 /// This method walks the entire tree looking for the first item that is
1274 /// under the mouse, i.e. at Fl::event_x() / Fl::event_y().
1275 ///
1276 /// Use this method /only/ if you've subclassed Fl_Tree, and are receiving
1277 /// events before Fl_Tree has been able to process and update callback_item().
1278 ///
1279 /// \returns The item clicked, or NULL if no item was under the current event.
1280 /// \version 1.3.0
1281 ///
1282 const Fl_Tree_Item* Fl_Tree::find_clicked() const {
1283   if ( ! _root ) return(NULL);
1284   return(_root->find_clicked(_prefs));
1285 }
1286 
1287 /// Non-const version of Fl_Tree::find_clicked() const.
1288 /// \version 1.3.0
1289 Fl_Tree_Item *Fl_Tree::find_clicked() {
1290   // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
1291   return(const_cast<Fl_Tree_Item*>(
1292 	 static_cast<const Fl_Tree&>(*this).find_clicked()));
1293 }
1294 #endif
1295 
1296 /// Set the item that was last clicked.
1297 /// Should only be used by subclasses needing to change this value.
1298 /// Normally Fl_Tree manages this value.
1299 ///
1300 /// \deprecated in 1.3.3 ABI -- use callback_item() instead.
1301 ///
1302 void Fl_Tree::item_clicked(Fl_Tree_Item* item) {
1303   _callback_item = item;
1304 }
1305 
1306 /// Return the item that was last clicked.
1307 ///
1308 /// Valid only from within the callback().
1309 ///
1310 /// \returns The item clicked, or 0 if none.
1311 ///          0 may also be used to indicate several items were clicked/changed.
1312 /// \deprecated in 1.3.3 ABI -- use callback_item() instead.
1313 ///
1314 Fl_Tree_Item* Fl_Tree::item_clicked() {
1315   return(_callback_item);
1316 }
1317 
1318 /// Returns next open(), visible item above (\p dir==FL_Up)
1319 /// or below (\p dir==FL_Down) the specified \p 'item', or 0 if no more items.
1320 ///
1321 /// If \p 'item' is 0, returns last() if \p 'dir' is FL_Up,
1322 /// or first() if \p dir is FL_Down.
1323 ///
1324 /// \code
1325 /// // Walk down the tree (forwards)
1326 /// for ( Fl_Tree_Item *i=tree->first_visible_item(); i; i=tree->next_visible_item(i, FL_Down) )
1327 ///     printf("Item: %s\n", i->label());
1328 ///
1329 /// // Walk up the tree (backwards)
1330 /// for ( Fl_Tree_Item *i=tree->last_visible_item(); i; i=tree->next_visible_item(i, FL_Up) )
1331 ///     printf("Item: %s\n", i->label());
1332 /// \endcode
1333 /// \param[in] item The item above/below which we'll find the next visible item
1334 /// \param[in] dir  The direction to search. Can be FL_Up or FL_Down.
1335 /// \returns The item found, or 0 if there's no visible items above/below the specified \p item.
1336 /// \version 1.3.3
1337 ///
1338 Fl_Tree_Item *Fl_Tree::next_visible_item(Fl_Tree_Item *item, int dir) {
1339   return next_item(item, dir, true);
1340 }
1341 
1342 /// Returns the first item in the tree, or 0 if none.
1343 ///
1344 /// Use this to walk the tree in the forward direction, e.g.
1345 /// \code
1346 /// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) )
1347 ///     printf("Item: %s\n", item->label());
1348 /// \endcode
1349 ///
1350 /// \returns First item in tree, or 0 if none (tree empty).
1351 /// \see first(), next(), last(), prev()
1352 ///
1353 Fl_Tree_Item* Fl_Tree::first() {
1354   return(_root);				// first item always root
1355 }
1356 
1357 /// Returns the first open(), visible item in the tree, or 0 if none.
1358 /// \deprecated in 1.3.3 ABI -- use first_visible_item() instead.
1359 ///
1360 Fl_Tree_Item* Fl_Tree::first_visible() {
1361   return(first_visible_item());
1362 }
1363 
1364 /// Returns the first open(), visible item in the tree, or 0 if none.
1365 /// \returns First visible item in tree, or 0 if none.
1366 /// \see first_visible_item(), last_visible_item(), next_visible_item()
1367 /// \version 1.3.3
1368 ///
1369 Fl_Tree_Item* Fl_Tree::first_visible_item() {
1370   Fl_Tree_Item *i = showroot() ? first() : next(first());
1371   while ( i ) {
1372     if ( i->visible() ) return(i);
1373     i = next(i);
1374   }
1375   return(0);
1376 }
1377 
1378 /// Return the next item after \p 'item', or 0 if no more items.
1379 ///
1380 /// Use this code to walk the entire tree:
1381 /// \code
1382 /// for ( Fl_Tree_Item *i = tree->first(); i; i = tree->next(i) )
1383 ///     printf("Item: %s\n", i->label());
1384 /// \endcode
1385 ///
1386 /// \param[in] item The item to use to find the next item. If NULL, returns 0.
1387 /// \returns Next item in tree, or 0 if at last item.
1388 ///
1389 /// \see first(), next(), last(), prev()
1390 ///
1391 Fl_Tree_Item *Fl_Tree::next(Fl_Tree_Item *item) {
1392   if ( ! item ) return(0);
1393   return(item->next());
1394 }
1395 
1396 /// Return the previous item before \p 'item', or 0 if no more items.
1397 ///
1398 /// This can be used to walk the tree in reverse, e.g.
1399 /// \code
1400 /// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->prev(item) )
1401 ///     printf("Item: %s\n", item->label());
1402 /// \endcode
1403 ///
1404 /// \param[in] item The item to use to find the previous item. If NULL, returns 0.
1405 /// \returns Previous item in tree, or 0 if at first item.
1406 ///
1407 /// \see first(), next(), last(), prev()
1408 ///
1409 Fl_Tree_Item *Fl_Tree::prev(Fl_Tree_Item *item) {
1410   if ( ! item ) return(0);
1411   return(item->prev());
1412 }
1413 
1414 /// Returns the last item in the tree.
1415 ///
1416 /// This can be used to walk the tree in reverse, e.g.
1417 ///
1418 /// \code
1419 /// for ( Fl_Tree_Item *item = tree->last(); item; item = tree->prev() )
1420 ///     printf("Item: %s\n", item->label());
1421 /// \endcode
1422 ///
1423 /// \returns Last item in the tree, or 0 if none (tree empty).
1424 /// \see first(), next(), last(), prev()
1425 ///
1426 Fl_Tree_Item* Fl_Tree::last() {
1427   if ( ! _root ) return(0);
1428   Fl_Tree_Item *item = _root;
1429   while ( item->has_children() ) {
1430     item = item->child(item->children()-1);
1431   }
1432   return(item);
1433 }
1434 
1435 /// Returns the last open(), visible item in the tree.
1436 /// \deprecated in 1.3.3 -- use last_visible_item() instead.
1437 ///
1438 Fl_Tree_Item* Fl_Tree::last_visible() {
1439   return(last_visible_item());
1440 }
1441 
1442 /// Returns the last open(), visible item in the tree.
1443 /// \returns Last visible item in the tree, or 0 if none.
1444 /// \see first_visible_item(), last_visible_item(), next_visible_item()
1445 /// \version 1.3.3
1446 ///
1447 Fl_Tree_Item* Fl_Tree::last_visible_item() {
1448   Fl_Tree_Item *item = last();
1449   while ( item ) {
1450     if ( item->visible() ) {
1451       if ( item == _root && !showroot() ) {
1452         return(0);
1453       } else {
1454         return(item);
1455       }
1456     }
1457     item = prev(item);
1458   }
1459   return(item);
1460 }
1461 
1462 /// Returns the first selected item in the tree.
1463 ///
1464 /// Use this to walk the tree from top to bottom
1465 /// looking for all the selected items, e.g.
1466 ///
1467 /// \code
1468 /// // Walk tree forward, from top to bottom
1469 /// for ( Fl_Tree_Item *i=tree->first_selected_item(); i; i=tree->next_selected_item(i) )
1470 ///     printf("Selected item: %s\n", i->label());
1471 /// \endcode
1472 ///
1473 /// \returns The first selected item, or 0 if none.
1474 /// \see first_selected_item(), last_selected_item(), next_selected_item()
1475 ///
1476 Fl_Tree_Item *Fl_Tree::first_selected_item() {
1477   return(next_selected_item(0));
1478 }
1479 
1480 #if FLTK_ABI_VERSION >= 10303
1481 // nothing
1482 #else
1483 /// Returns the next selected item after \p 'item'.
1484 /// If \p item is 0, search starts at the first item (root).
1485 ///
1486 /// This is a convenience method; equivalent to next_selected_item(item, FL_Down);
1487 ///
1488 /// Use this to walk the tree forward (downward) looking for all the selected items, e.g.
1489 /// \code
1490 /// for ( Fl_Tree_Item *i = tree->first_selected_item(); i; i = tree->next_selected_item(i) )
1491 ///     printf("Selected item: %s\n", i->label());
1492 /// \endcode
1493 ///
1494 /// \param[in] item The item to use to find the next selected item. If NULL, first() is used.
1495 /// \returns The next selected item, or 0 if there are no more selected items.
1496 /// \see first_selected_item(), last_selected_item(), next_selected_item()
1497 ///
1498 Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item) {
1499   return(next_selected_item(item, FL_Down));
1500 }
1501 #endif
1502 
1503 /// Returns the last selected item in the tree.
1504 ///
1505 /// Use this to walk the tree in reverse from bottom to top
1506 /// looking for all the selected items, e.g.
1507 ///
1508 /// \code
1509 /// // Walk tree in reverse, from bottom to top
1510 /// for ( Fl_Tree_Item *i=tree->last_selected_item(); i; i=tree->next_selected_item(i, FL_Up) )
1511 ///     printf("Selected item: %s\n", i->label());
1512 /// \endcode
1513 ///
1514 /// \returns The last selected item, or 0 if none.
1515 /// \see first_selected_item(), last_selected_item(), next_selected_item()
1516 /// \version 1.3.3
1517 ///
1518 Fl_Tree_Item *Fl_Tree::last_selected_item() {
1519   return(next_selected_item(0, FL_Up));
1520 }
1521 
1522 /// Returns next item after \p 'item' in direction \p 'dir'
1523 /// depending on \p 'visible'.
1524 ///
1525 /// Next item will be above (if dir==FL_Up) or below (if dir==FL_Down).
1526 /// If \p 'visible' is true, only items whose parents are open() will be returned.
1527 /// If \p 'visible' is false, even items whose parents are close()ed will be returned.
1528 ///
1529 /// If \p item is 0, the return value will be the result of this truth table:
1530 /// <PRE>
1531 ///                        visible=true           visible=false
1532 ///                        -------------------    -------------
1533 ///          dir=FL_Up:    last_visible_item()    last()
1534 ///        dir=FL_Down:    first_visible_item()   first()
1535 /// </PRE>
1536 ///
1537 /// \par Example use:
1538 /// \code
1539 /// // Walk down the tree showing open(), visible items
1540 /// for ( Fl_Tree_Item *i=tree->first_visible_item(); i; i=tree->next_item(i, FL_Down, true) )
1541 ///     printf("Item: %s\n", i->label());
1542 ///
1543 /// // Walk up the tree showing open(), visible items
1544 /// for ( Fl_Tree_Item *i=tree->last_visible_item(); i; i=tree->next_item(i, FL_Up, true) )
1545 ///     printf("Item: %s\n", i->label());
1546 ///
1547 /// // Walk down the tree showing all items (open or closed)
1548 /// for ( Fl_Tree_Item *i=tree->first(); i; i=tree->next_item(i, FL_Down, false) )
1549 ///     printf("Item: %s\n", i->label());
1550 ///
1551 /// // Walk up the tree showing all items (open or closed)
1552 /// for ( Fl_Tree_Item *i=tree->last(); i; i=tree->next_item(i, FL_Up, false) )
1553 ///     printf("Item: %s\n", i->label());
1554 /// \endcode
1555 ///
1556 /// \param[in] item    The item to use to find the next item. If NULL, returns 0.
1557 /// \param[in] dir     Can be FL_Up or FL_Down (default=FL_Down or 'next')
1558 /// \param[in] visible true=return only open(), visible items,<br>
1559 ///                    false=return open or closed items (default)
1560 /// \returns Next item in tree in the direction and visibility specified,
1561 ///          or 0 if no more items of specified visibility in that direction.
1562 /// \see first(), last(), next(),<BR>
1563 ///      first_visible_item(), last_visible_item(), next_visible_item(),<BR>
1564 ///      first_selected_item(), last_selected_item(), next_selected_item()
1565 /// \version 1.3.3
1566 ///
1567 Fl_Tree_Item *Fl_Tree::next_item(Fl_Tree_Item *item, int dir, bool visible) {
1568   if ( ! item ) {					// no start item?
1569     if ( visible ) {
1570 	item = ( dir == FL_Up ) ? last_visible_item() : // wrap to bottom
1571 				  first_visible_item();	// wrap to top
1572     } else {
1573 	item = ( dir == FL_Up ) ? last() :		// wrap to bottom
1574 				  first();		// wrap to top
1575     }
1576     if ( ! item ) return(0);
1577     if ( item->visible_r() ) return(item);		// return first/last visible item
1578   }
1579   switch (dir) {
1580     case FL_Up:
1581       if ( visible ) return(item->prev_visible(_prefs));
1582       else           return(item->prev());
1583     case FL_Down:
1584       if ( visible ) return(item->next_visible(_prefs));
1585       else           return(item->next());
1586   }
1587   return(0);		// unknown dir
1588 }
1589 
1590 /// Returns the next selected item above or below \p 'item', depending on \p 'dir'.
1591 /// If \p 'item' is 0, search starts at either first() or last(), depending on \p 'dir':
1592 /// first() if \p 'dir' is FL_Down (default), last() if \p 'dir' is FL_Up.
1593 ///
1594 /// Use this to walk the tree looking for all the selected items, e.g.
1595 /// \code
1596 /// // Walk down the tree (forwards)
1597 /// for ( Fl_Tree_Item *i=tree->first_selected_item(); i; i=tree->next_selected_item(i, FL_Down) )
1598 ///     printf("Item: %s\n", i->label());
1599 ///
1600 /// // Walk up the tree (backwards)
1601 /// for ( Fl_Tree_Item *i=tree->last_selected_item(); i; i=tree->next_selected_item(i, FL_Up) )
1602 ///     printf("Item: %s\n", i->label());
1603 /// \endcode
1604 ///
1605 /// \param[in] item The item above or below which we'll find the next selected item.
1606 ///                 If NULL, first() is used if FL_Down, last() if FL_Up.
1607 ///                 (default=NULL)
1608 /// \param[in] dir  The direction to go.
1609 ///                 FL_Up for moving up the tree,
1610 ///                 FL_Down for down the tree (default)
1611 /// \returns The next selected item, or 0 if there are no more selected items.
1612 /// \see first_selected_item(), last_selected_item(), next_selected_item()
1613 /// \version 1.3.3
1614 ///
1615 Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item, int dir) {
1616   switch (dir) {
1617     case FL_Down:
1618       if ( ! item ) {
1619 	if ( ! (item = first()) ) return(0);
1620 	if ( item->is_selected() ) return(item);
1621       }
1622       while ( (item = item->next()) )
1623 	if ( item->is_selected() )
1624 	  return(item);
1625       return(0);
1626     case FL_Up:
1627       if ( ! item ) {
1628 	if ( ! (item = last()) ) return(0);
1629 	if ( item->is_selected() ) return(item);
1630       }
1631       while ( (item = item->prev()) )
1632 	if ( item->is_selected() )
1633 	  return(item);
1634       return(0);
1635   }
1636   return(0);
1637 }
1638 
1639 #if FLTK_ABI_VERSION >= 10303		/* reason for this: Fl_Tree_Item_Array::manage_item_destroy() */
1640 /// Returns the currently selected items as an array of \p 'ret_items'.
1641 ///
1642 /// Example:
1643 /// \code
1644 ///   // Get selected items as an array
1645 ///   Fl_Tree_Item_Array items;
1646 ///   tree->get_selected_items(items);
1647 ///   // Manipulate the returned array
1648 ///   for ( int t=0; t<items.total(); t++ ) {
1649 ///       Fl_Tree_Item &item = items[t];
1650 ///       ..do stuff with each selected item..
1651 ///   }
1652 /// \endcode
1653 ///
1654 /// \param[out] ret_items The returned array of selected items.
1655 /// \returns The number of items in the returned array.
1656 /// \see first_selected_item(), next_selected_item()
1657 /// \version 1.3.3 ABI feature
1658 ///
1659 int Fl_Tree::get_selected_items(Fl_Tree_Item_Array &ret_items) {
1660   ret_items.clear();
1661   for ( Fl_Tree_Item *i=first_selected_item(); i; i=next_selected_item(i) ) {
1662     ret_items.add(i);
1663   }
1664   return ret_items.total();
1665 }
1666 #endif
1667 
1668 /// Open the specified \p 'item'.
1669 ///
1670 /// This causes the item's children (if any) to be shown.<br>
1671 /// Invokes the callback depending on the value of optional
1672 /// parameter \p 'docallback'.<br>
1673 /// Handles calling redraw() if anything changed.
1674 ///
1675 /// The callback can use callback_item() and callback_reason() respectively to determine
1676 /// the item changed and the reason the callback was called.
1677 ///
1678 /// \param[in] item -- the item to be opened. Must not be NULL.
1679 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1680 ///     -   0 - callback() is not invoked
1681 ///     -   1 - callback() is invoked if item changed (default),
1682 ///             callback_reason() will be FL_TREE_REASON_OPENED
1683 /// \returns
1684 ///     -   1 -- item was opened
1685 ///     -   0 -- item was already open, no change
1686 ///
1687 /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
1688 ///
1689 int Fl_Tree::open(Fl_Tree_Item *item, int docallback) {
1690   if ( item->is_open() ) return(0);
1691   item->open();		// handles recalc_tree()
1692   redraw();
1693   if ( docallback ) {
1694     do_callback_for_item(item, FL_TREE_REASON_OPENED);
1695   }
1696   return(1);
1697 }
1698 
1699 /// Opens the item specified by \p 'path'.
1700 ///
1701 /// This causes the item's children (if any) to be shown.<br>
1702 /// Invokes the callback depending on the value of optional
1703 /// parameter \p 'docallback'.<br>
1704 /// Handles calling redraw() if anything changed.
1705 ///
1706 /// Items or submenus that themselves contain slashes ('/' or '\')
1707 /// should be escaped, e.g. open("Holidays/12\\/25\\/2010").
1708 ///
1709 /// The callback can use callback_item() and callback_reason() respectively to determine
1710 /// the item changed and the reason the callback was called.
1711 ///
1712 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
1713 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1714 ///     -   0 - callback() is not invoked
1715 ///     -   1 - callback() is invoked if item changed (default),
1716 ///             callback_reason() will be FL_TREE_REASON_OPENED
1717 /// \returns
1718 ///     -   1 -- OK: item opened
1719 ///     -   0 -- OK: item was already open, no change
1720 ///     -  -1 -- ERROR: item was not found
1721 /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
1722 ///
1723 int Fl_Tree::open(const char *path, int docallback) {
1724   Fl_Tree_Item *item = find_item(path);
1725   if ( ! item ) return(-1);
1726   return(open(item, docallback));		// handles recalc_tree()
1727 }
1728 
1729 /// Toggle the open state of \p 'item'.
1730 ///
1731 /// Invokes the callback depending on the value of optional
1732 /// parameter \p 'docallback'.<br>
1733 /// Handles calling redraw() if anything changed.
1734 ///
1735 /// The callback can use callback_item() and callback_reason() respectively to determine
1736 /// the item changed and the reason the callback was called.
1737 ///
1738 /// \param[in] item -- the item whose open state is to be toggled. Must not be NULL.
1739 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1740 ///     -   0 - callback() is not invoked
1741 ///     -   1 - callback() is invoked (default), callback_reason() will be either
1742 ///             FL_TREE_REASON_OPENED or FL_TREE_REASON_CLOSED
1743 ///
1744 /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
1745 ///
1746 void Fl_Tree::open_toggle(Fl_Tree_Item *item, int docallback) {
1747   if ( item->is_open() ) {
1748     close(item, docallback);		// handles recalc_tree()
1749   } else {
1750     open(item, docallback);		// handles recalc_tree()
1751   }
1752 }
1753 
1754 /// Closes the specified \p 'item'.
1755 ///
1756 /// Invokes the callback depending on the value of optional
1757 /// parameter \p 'docallback'.<br>
1758 /// Handles calling redraw() if anything changed.
1759 ///
1760 /// The callback can use callback_item() and callback_reason() respectively to determine
1761 /// the item changed and the reason the callback was called.
1762 ///
1763 /// \param[in] item -- the item to be closed. Must not be NULL.
1764 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1765 ///     -   0 - callback() is not invoked
1766 ///     -   1 - callback() is invoked if item changed (default),
1767 ///             callback_reason() will be FL_TREE_REASON_CLOSED
1768 /// \returns
1769 ///     -   1 -- item was closed
1770 ///     -   0 -- item was already closed, no change
1771 /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
1772 ///
1773 int Fl_Tree::close(Fl_Tree_Item *item, int docallback) {
1774   if ( item->is_close() ) return(0);
1775   item->close();		// handles recalc_tree()
1776   redraw();
1777   if ( docallback ) {
1778     do_callback_for_item(item, FL_TREE_REASON_CLOSED);
1779   }
1780   return(1);
1781 }
1782 
1783 /// Closes the item specified by \p 'path'.
1784 ///
1785 /// Invokes the callback depending on the value of optional
1786 /// parameter \p 'docallback'.<br>
1787 /// Handles calling redraw() if anything changed.
1788 ///
1789 /// Items or submenus that themselves contain slashes ('/' or '\')
1790 /// should be escaped, e.g. close("Holidays/12\\/25\\/2010").
1791 ///
1792 /// The callback can use callback_item() and callback_reason() respectively to determine
1793 /// the item changed and the reason the callback was called.
1794 ///
1795 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
1796 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1797 ///     -   0 - callback() is not invoked
1798 ///     -   1 - callback() is invoked if item changed (default),
1799 ///             callback_reason() will be FL_TREE_REASON_CLOSED
1800 /// \returns
1801 ///     -   1 -- OK: item closed
1802 ///     -   0 -- OK: item was already closed, no change
1803 ///     -  -1 -- ERROR: item was not found
1804 /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
1805 ///
1806 int Fl_Tree::close(const char *path, int docallback) {
1807   Fl_Tree_Item *item = find_item(path);
1808   if ( ! item ) return(-1);
1809   return(close(item, docallback));		// handles recalc_tree()
1810 }
1811 
1812 /// See if \p 'item' is open.
1813 ///
1814 /// Items that are 'open' are themselves not necessarily visible;
1815 /// one of the item's parents might be closed.
1816 ///
1817 /// \param[in] item -- the item to be tested. Must not be NULL.
1818 /// \returns
1819 ///     -  1 : item is open
1820 ///     -  0 : item is closed
1821 ///
1822 int Fl_Tree::is_open(Fl_Tree_Item *item) const {
1823   return(item->is_open()?1:0);
1824 }
1825 
1826 /// See if item specified by \p 'path' is open.
1827 ///
1828 /// Items or submenus that themselves contain slashes ('/' or '\')
1829 /// should be escaped, e.g. is_open("Holidays/12\\/25\\/2010").
1830 ///
1831 /// Items that are 'open' are themselves not necessarily visible;
1832 /// one of the item's parents might be closed.
1833 ///
1834 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
1835 /// \returns
1836 ///     -    1 - OK: item is open
1837 ///     -    0 - OK: item is closed
1838 ///     -   -1 - ERROR: item was not found
1839 /// \see Fl_Tree_Item::visible_r()
1840 ///
1841 int Fl_Tree::is_open(const char *path) const {
1842   const Fl_Tree_Item *item = find_item(path);
1843   if ( ! item ) return(-1);
1844   return(item->is_open()?1:0);
1845 }
1846 
1847 /// See if the specified \p 'item' is closed.
1848 ///
1849 /// \param[in] item -- the item to be tested. Must not be NULL.
1850 /// \returns
1851 ///     -   1 : item is closed
1852 ///     -   0 : item is open
1853 ///
1854 int Fl_Tree::is_close(Fl_Tree_Item *item) const {
1855   return(item->is_close());
1856 }
1857 
1858 /// See if item specified by \p 'path' is closed.
1859 ///
1860 /// Items or submenus that themselves contain slashes ('/' or '\')
1861 /// should be escaped, e.g. is_close("Holidays/12\\/25\\/2010").
1862 ///
1863 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
1864 /// \returns
1865 ///     -   1 - OK: item is closed
1866 ///     -   0 - OK: item is open
1867 ///     -  -1 - ERROR: item was not found
1868 ///
1869 int Fl_Tree::is_close(const char *path) const {
1870   const Fl_Tree_Item *item = find_item(path);
1871   if ( ! item ) return(-1);
1872   return(item->is_close()?1:0);
1873 }
1874 
1875 /// Select the specified \p 'item'. Use 'deselect()' to deselect it.
1876 ///
1877 /// Invokes the callback depending on the value of optional parameter \p docallback.<br>
1878 /// Handles calling redraw() if anything changed.
1879 ///
1880 /// The callback can use callback_item() and callback_reason() respectively to determine
1881 /// the item changed and the reason the callback was called.
1882 ///
1883 /// \param[in] item -- the item to be selected. Must not be NULL.
1884 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1885 ///     -   0 - the callback() is not invoked
1886 ///     -   1 - the callback() is invoked if item changed state,
1887 ///             callback_reason() will be FL_TREE_REASON_SELECTED
1888 /// \returns
1889 ///     -   1 - item's state was changed
1890 ///     -   0 - item was already selected, no change was made
1891 ///
1892 int Fl_Tree::select(Fl_Tree_Item *item, int docallback) {
1893   int alreadySelected = item->is_selected();
1894   if ( !alreadySelected ) {
1895     item->select();
1896     set_changed();
1897     if ( docallback ) {
1898       do_callback_for_item(item, FL_TREE_REASON_SELECTED);
1899     }
1900     redraw();
1901     return(1);
1902   }
1903 #if FLTK_ABI_VERSION >= 10301
1904   // NEW
1905   if ( alreadySelected ) {
1906     if ( (item_reselect_mode() == FL_TREE_SELECTABLE_ALWAYS) && docallback ) {
1907       do_callback_for_item(item, FL_TREE_REASON_RESELECTED);
1908     }
1909   }
1910 #endif /*FLTK_ABI_VERSION*/
1911   return(0);
1912 }
1913 
1914 /// Select the item specified by \p 'path'.
1915 ///
1916 /// Invokes the callback depending on the value of optional
1917 /// parameter \p 'docallback'.<br>
1918 /// Handles calling redraw() if anything changed.
1919 ///
1920 /// Items or submenus that themselves contain slashes ('/' or '\')
1921 /// should be escaped, e.g. select("Holidays/12\\/25\\/2010").
1922 ///
1923 /// The callback can use callback_item() and callback_reason() respectively to determine
1924 /// the item changed and the reason the callback was called.
1925 ///
1926 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
1927 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1928 ///     -   0 - the callback() is not invoked
1929 ///     -   1 - the callback() is invoked if item changed state (default),
1930 ///             callback_reason() will be FL_TREE_REASON_SELECTED
1931 /// \returns
1932 ///     -   1 : OK: item's state was changed
1933 ///     -   0 : OK: item was already selected, no change was made
1934 ///     -  -1 : ERROR: item was not found
1935 ///
1936 int Fl_Tree::select(const char *path, int docallback) {
1937   Fl_Tree_Item *item = find_item(path);
1938   if ( ! item ) return(-1);
1939   return(select(item, docallback));
1940 }
1941 
1942 /// Toggle the select state of the specified \p 'item'.
1943 ///
1944 /// Invokes the callback depending on the value of optional
1945 /// parameter \p 'docallback'.<br>
1946 /// Handles calling redraw() if anything changed.
1947 ///
1948 /// The callback can use callback_item() and callback_reason() respectively to determine
1949 /// the item changed and the reason the callback was called.
1950 ///
1951 /// \param[in] item -- the item to be selected. Must not be NULL.
1952 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1953 ///     -   0 - the callback() is not invoked
1954 ///     -   1 - the callback() is invoked (default), callback_reason() will be
1955 ///             either FL_TREE_REASON_SELECTED or FL_TREE_REASON_DESELECTED
1956 ///
1957 void Fl_Tree::select_toggle(Fl_Tree_Item *item, int docallback) {
1958   item->select_toggle();
1959   set_changed();
1960   if ( docallback ) {
1961     do_callback_for_item(item, item->is_selected() ? FL_TREE_REASON_SELECTED
1962 						   : FL_TREE_REASON_DESELECTED);
1963   }
1964   redraw();
1965 }
1966 
1967 /// Deselect the specified \p item.
1968 ///
1969 /// Invokes the callback depending on the value of optional
1970 /// parameter \p 'docallback'.<br>
1971 /// Handles calling redraw() if anything changed.
1972 ///
1973 /// The callback can use callback_item() and callback_reason() respectively to determine
1974 /// the item changed and the reason the callback was called.
1975 ///
1976 /// \param[in] item -- the item to be deselected. Must not be NULL.
1977 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
1978 ///     -   0 - the callback() is not invoked
1979 ///     -   1 - the callback() is invoked if item changed state (default),
1980 ///             callback_reason() will be FL_TREE_REASON_DESELECTED
1981 /// \returns
1982 ///     -   0 - item was already deselected, no change was made
1983 ///     -   1 - item's state was changed
1984 ///
1985 int Fl_Tree::deselect(Fl_Tree_Item *item, int docallback) {
1986   if ( item->is_selected() ) {
1987     item->deselect();
1988     set_changed();
1989     if ( docallback ) {
1990       do_callback_for_item(item, FL_TREE_REASON_DESELECTED);
1991     }
1992     redraw();
1993     return(1);
1994   }
1995   return(0);
1996 }
1997 
1998 /// Deselect an item specified by \p 'path'.
1999 ///
2000 /// Invokes the callback depending on the value of optional
2001 /// parameter \p 'docallback'.<br>
2002 /// Handles calling redraw() if anything changed.
2003 ///
2004 /// Items or submenus that themselves contain slashes ('/' or '\')
2005 /// should be escaped, e.g. deselect("Holidays/12\\/25\\/2010").
2006 ///
2007 /// The callback can use callback_item() and callback_reason() respectively to determine
2008 /// the item changed and the reason the callback was called.
2009 ///
2010 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
2011 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
2012 ///     -   0 - the callback() is not invoked
2013 ///     -   1 - the callback() is invoked if item changed state (default),
2014 ///             callback_reason() will be FL_TREE_REASON_DESELECTED
2015 ///  \returns
2016 ///     -   1 - OK: item's state was changed
2017 ///     -   0 - OK: item was already deselected, no change was made
2018 ///     -  -1 - ERROR: item was not found
2019 ///
2020 int Fl_Tree::deselect(const char *path, int docallback) {
2021   Fl_Tree_Item *item = find_item(path);
2022   if ( ! item ) return(-1);
2023   return(deselect(item, docallback));
2024 }
2025 
2026 /// Deselect \p 'item' and all its children.
2027 ///
2028 /// If item is NULL, first() is used.<br>
2029 /// Invokes the callback depending on the value of optional
2030 /// parameter \p 'docallback'.<br>
2031 /// Handles calling redraw() if anything changed.
2032 ///
2033 /// The callback can use callback_item() and callback_reason() respectively to determine
2034 /// the item changed and the reason the callback was called.
2035 ///
2036 /// \param[in] item The item that will be deselected (along with all its children).
2037 ///                 If NULL, first() is used.
2038 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
2039 ///     -   0 - the callback() is not invoked
2040 ///     -   1 - the callback() is invoked for each item that changed state (default),
2041 ///             callback_reason() will be FL_TREE_REASON_DESELECTED
2042 /// \returns Count of how many items were actually changed to the deselected state.
2043 ///
2044 int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) {
2045   item = item ? item : first();			// NULL? use first()
2046   if ( ! item ) return(0);
2047   int count = 0;
2048   // Deselect item
2049   if ( item->is_selected() )
2050     if ( deselect(item, docallback) )
2051       ++count;
2052   // Deselect its children
2053   for ( int t=0; t<item->children(); t++ ) {
2054     count += deselect_all(item->child(t), docallback);	// recurse
2055   }
2056   return(count);
2057 }
2058 
2059 /// Select only the specified item, deselecting all others that might be selected.
2060 ///
2061 /// If \p 'selitem' is 0, first() is used.<br>
2062 /// Invokes the callback depending on the value of optional
2063 /// parameter \p 'docallback'.<br>
2064 /// Handles calling redraw() if anything changed.
2065 ///
2066 /// The callback can use callback_item() and callback_reason() respectively to determine
2067 /// the item changed and the reason the callback was called.
2068 ///
2069 /// \param[in] selitem The item to be selected. If NULL, first() is used.
2070 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
2071 ///     -   0 - the callback() is not invoked
2072 ///     -   1 - the callback() is invoked for each item that changed state (default),
2073 ///             callback_reason() will be either FL_TREE_REASON_SELECTED or
2074 ///             FL_TREE_REASON_DESELECTED
2075 /// \returns The number of items whose selection states were changed, if any.
2076 ///
2077 int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) {
2078   selitem = selitem ? selitem : first();	// NULL? use first()
2079   if ( ! selitem ) return(0);
2080   int changed = 0;
2081   // Deselect everything first.
2082   //    Prevents callbacks from seeing more than one item selected.
2083   //
2084   for ( Fl_Tree_Item *item = first(); item; item = item->next() ) {
2085     if ( item == selitem ) continue;		// don't do anything to selitem yet..
2086     if ( item->is_selected() ) {
2087       deselect(item, docallback);
2088       ++changed;
2089     }
2090   }
2091 #if FLTK_ABI_VERSION >= 10301
2092   // Should we 'reselect' item if already selected?
2093   if ( selitem->is_selected() && (item_reselect_mode()==FL_TREE_SELECTABLE_ALWAYS) ) {
2094     // Selection unchanged, so no ++changed
2095     select(selitem, docallback);			// do callback with reason=reselect
2096   } else if ( !selitem->is_selected() ) {
2097     // Item was not already selected, select and indicate changed
2098     select(selitem, docallback);
2099     ++changed;
2100   }
2101 #else
2102   if ( !selitem->is_selected() ) {
2103     // All items deselected, now select the one we want
2104     select(selitem, docallback);
2105     ++changed;
2106   }
2107 #endif
2108   return(changed);
2109 }
2110 
2111 /// Select \p 'item' and all its children.
2112 ///
2113 /// If item is NULL, first() is used.<br>
2114 /// Invokes the callback depending on the value of optional
2115 /// parameter \p 'docallback'.<br>
2116 /// Handles calling redraw() if anything changed.
2117 ///
2118 /// The callback can use callback_item() and callback_reason() respectively to determine
2119 /// the item changed and the reason the callback was called.
2120 ///
2121 /// \param[in] item The item that will be selected (along with all its children).
2122 ///            If NULL, first() is used.
2123 /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
2124 ///     -   0 - the callback() is not invoked
2125 ///     -   1 - the callback() is invoked for each item that changed state (default),
2126 ///             callback_reason() will be FL_TREE_REASON_SELECTED
2127 /// \returns Count of how many items were actually changed to the selected state.
2128 ///
2129 int Fl_Tree::select_all(Fl_Tree_Item *item, int docallback) {
2130   item = item ? item : first();			// NULL? use first()
2131   if ( ! item ) return(0);
2132   int count = 0;
2133   // Select item
2134   if ( !item->is_selected() )
2135     if ( select(item, docallback) )
2136       ++count;
2137   // Select its children
2138   for ( int t=0; t<item->children(); t++ ) {
2139     count += select_all(item->child(t), docallback);	// recurse
2140   }
2141   return(count);
2142 }
2143 
2144 /// Get the item that currently has keyboard focus.
2145 Fl_Tree_Item* Fl_Tree::get_item_focus() const {
2146   return(_item_focus);
2147 }
2148 
2149 /// Set the item that currently should have keyboard focus.
2150 ///
2151 /// Handles calling redraw() to update the focus box (if it is visible).
2152 ///
2153 /// \param[in] item The item that should take focus. If NULL, none will have focus.
2154 ///
2155 void Fl_Tree::set_item_focus(Fl_Tree_Item *item) {
2156   if ( _item_focus != item ) {		// changed?
2157     _item_focus = item;			// update
2158     if ( visible_focus() ) redraw();	// redraw to update focus box
2159   }
2160 }
2161 
2162 /// See if the specified \p 'item' is selected.
2163 ///
2164 /// \param[in] item -- the item to be tested. Must not be NULL.
2165 ///
2166 /// \return
2167 ///     -   1 : item selected
2168 ///     -   0 : item deselected
2169 ///
2170 int Fl_Tree::is_selected(Fl_Tree_Item *item) const {
2171   return(item->is_selected()?1:0);
2172 }
2173 
2174 /// See if item specified by \p 'path' is selected.
2175 ///
2176 /// Items or submenus that themselves contain slashes ('/' or '\')
2177 /// should be escaped, e.g. is_selected("Holidays/12\\/25\\/2010").
2178 ///
2179 /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
2180 /// \returns
2181 ///     -   1 : item selected
2182 ///     -   0 : item deselected
2183 ///     -  -1 : item was not found
2184 ///
2185 int Fl_Tree::is_selected(const char *path) {
2186   Fl_Tree_Item *item = find_item(path);
2187   if ( ! item ) return(-1);
2188   return(is_selected(item));
2189 }
2190 
2191 /// Get the default label fontsize used for creating new items.
2192 Fl_Fontsize Fl_Tree::item_labelsize() const {
2193   return(_prefs.labelsize());
2194 }
2195 
2196 /// Set the default label font size used for creating new items.
2197 /// To change the font size on a per-item basis, use Fl_Tree_Item::labelsize(Fl_Fontsize)
2198 ///
2199 void Fl_Tree::item_labelsize(Fl_Fontsize val) {
2200   _prefs.labelsize(val);
2201 }
2202 
2203 /// Get the default font face used for creating new items.
2204 Fl_Font Fl_Tree::item_labelfont() const {
2205   return(_prefs.labelfont());
2206 }
2207 
2208 /// Set the default font face used for creating new items.
2209 /// To change the font face on a per-item basis, use Fl_Tree_Item::labelfont(Fl_Font)
2210 ///
2211 void Fl_Tree::item_labelfont(Fl_Font val) {
2212   _prefs.labelfont(val);
2213 }
2214 
2215 /// Get the default label foreground color used for creating new items.
2216 Fl_Color Fl_Tree::item_labelfgcolor(void) const {
2217   return(_prefs.labelfgcolor());
2218 }
2219 
2220 /// Set the default label foreground color used for creating new items.
2221 /// To change the foreground color on a per-item basis, use Fl_Tree_Item::labelfgcolor(Fl_Color)
2222 ///
2223 void Fl_Tree::item_labelfgcolor(Fl_Color val) {
2224   _prefs.labelfgcolor(val);
2225 }
2226 
2227 /// Get the default label background color used for creating new items.
2228 /// If the color is 0xffffffff, it is 'transparent'.
2229 Fl_Color Fl_Tree::item_labelbgcolor(void) const {
2230   return(_prefs.labelbgcolor());
2231 }
2232 
2233 /// Set the default label background color used for creating new items.
2234 /// A special case is made for color 0xffffffff (default) which is treated as 'transparent'.
2235 /// To change the background color on a per-item basis, use Fl_Tree_Item::labelbgcolor(Fl_Color)
2236 ///
2237 void Fl_Tree::item_labelbgcolor(Fl_Color val) {
2238   _prefs.labelbgcolor(val);
2239 }
2240 
2241 /// Get the connector color used for tree connection lines.
2242 Fl_Color Fl_Tree::connectorcolor() const {
2243   return(_prefs.connectorcolor());
2244 }
2245 
2246 /// Set the connector color used for tree connection lines.
2247 void Fl_Tree::connectorcolor(Fl_Color val) {
2248   _prefs.connectorcolor(val);
2249 }
2250 
2251 /// Get the amount of white space (in pixels) that should appear
2252 /// between the widget's left border and the tree's contents.
2253 ///
2254 int Fl_Tree::marginleft() const {
2255   return(_prefs.marginleft());
2256 }
2257 
2258 /// Set the amount of white space (in pixels) that should appear
2259 /// between the widget's left border and the left side of the tree's contents.
2260 ///
2261 void Fl_Tree::marginleft(int val) {
2262   _prefs.marginleft(val);
2263   redraw();
2264   recalc_tree();
2265 }
2266 
2267 /// Get the amount of white space (in pixels) that should appear
2268 /// between the widget's top border and the top of the tree's contents.
2269 ///
2270 int Fl_Tree::margintop() const {
2271   return(_prefs.margintop());
2272 }
2273 
2274 /// Sets the amount of white space (in pixels) that should appear
2275 /// between the widget's top border and the top of the tree's contents.
2276 ///
2277 void Fl_Tree::margintop(int val) {
2278   _prefs.margintop(val);
2279   redraw();
2280   recalc_tree();
2281 }
2282 
2283 #if FLTK_ABI_VERSION >= 10301
2284 /// Get the amount of white space (in pixels) that should appear
2285 /// below the last visible item when the vertical scroller is scrolled to the bottom.
2286 ///
2287 int Fl_Tree::marginbottom() const {
2288   return(_prefs.marginbottom());
2289 }
2290 
2291 /// Sets the amount of white space (in pixels) that should appear
2292 /// below the last visible item when the vertical scroller is scrolled to the bottom.
2293 ///
2294 void Fl_Tree::marginbottom(int val) {
2295   _prefs.marginbottom(val);
2296   redraw();
2297   recalc_tree();
2298 }
2299 #endif /*FLTK_ABI_VERSION*/
2300 
2301 /// Get the amount of white space (in pixels) that should appear
2302 /// between items in the tree.
2303 ///
2304 int Fl_Tree::linespacing() const {
2305   return(_prefs.linespacing());
2306 }
2307 
2308 /// Sets the amount of white space (in pixels) that should appear
2309 /// between items in the tree.
2310 ///
2311 void Fl_Tree::linespacing(int val) {
2312   _prefs.linespacing(val);
2313   redraw();
2314   recalc_tree();
2315 }
2316 
2317 /// Get the amount of white space (in pixels) that should appear
2318 /// below an open child tree's contents.
2319 ///
2320 int Fl_Tree::openchild_marginbottom() const {
2321   return(_prefs.openchild_marginbottom());
2322 }
2323 
2324 /// Set the amount of white space (in pixels) that should appear
2325 /// below an open child tree's contents.
2326 ///
2327 void Fl_Tree::openchild_marginbottom(int val) {
2328   _prefs.openchild_marginbottom(val);
2329   redraw();
2330   recalc_tree();
2331 }
2332 
2333 /// Get the amount of white space (in pixels) that should appear
2334 /// to the left of the usericon.
2335 int Fl_Tree::usericonmarginleft() const {
2336   return(_prefs.usericonmarginleft());
2337 }
2338 
2339 /// Set the amount of white space (in pixels) that should appear
2340 /// to the left of the usericon.
2341 void Fl_Tree::usericonmarginleft(int val) {
2342   _prefs.usericonmarginleft(val);
2343   redraw();
2344   recalc_tree();
2345 }
2346 
2347 /// Get the amount of white space (in pixels) that should appear
2348 /// to the left of the label text.
2349 int Fl_Tree::labelmarginleft() const {
2350   return(_prefs.labelmarginleft());
2351 }
2352 
2353 /// Set the amount of white space (in pixels) that should appear
2354 /// to the left of the label text.
2355 void Fl_Tree::labelmarginleft(int val) {
2356   _prefs.labelmarginleft(val);
2357   redraw();
2358   recalc_tree();
2359 }
2360 
2361 #if FLTK_ABI_VERSION >= 10301
2362 /// Get the amount of white space (in pixels) that should appear
2363 /// to the left of the child fltk widget (if any).
2364 int Fl_Tree::widgetmarginleft() const {
2365   return(_prefs.widgetmarginleft());
2366 }
2367 
2368 /// Set the amount of white space (in pixels) that should appear
2369 /// to the left of the child fltk widget (if any).
2370 void Fl_Tree::widgetmarginleft(int val) {
2371   _prefs.widgetmarginleft(val);
2372   redraw();
2373   recalc_tree();
2374 }
2375 #endif /*FLTK_ABI_VERSION*/
2376 
2377 /// Gets the width of the horizontal connection lines (in pixels)
2378 /// that appear to the left of each tree item's label.
2379 ///
2380 int Fl_Tree::connectorwidth() const {
2381   return(_prefs.connectorwidth());
2382 }
2383 
2384 /// Sets the width of the horizontal connection lines (in pixels)
2385 /// that appear to the left of each tree item's label.
2386 ///
2387 void Fl_Tree::connectorwidth(int val) {
2388   _prefs.connectorwidth(val);
2389   redraw();
2390   recalc_tree();
2391 }
2392 
2393 /// Returns the Fl_Image being used as the default user icon for all
2394 /// newly created items.
2395 /// Returns zero if no icon has been set, which is the default.
2396 ///
2397 Fl_Image* Fl_Tree::usericon() const {
2398   return(_prefs.usericon());
2399 }
2400 
2401 /// Sets the Fl_Image to be used as the default user icon for all
2402 /// newly created items.
2403 ///
2404 /// If you want to specify user icons on a per-item basis,
2405 /// use Fl_Tree_Item::usericon() instead.
2406 ///
2407 /// \param[in] val -- The new image to be used, or
2408 ///                   zero to disable user icons.
2409 ///
2410 void Fl_Tree::usericon(Fl_Image *val) {
2411   _prefs.usericon(val);
2412   redraw();
2413   recalc_tree();
2414 }
2415 
2416 /// Returns the icon to be used as the 'open' icon.
2417 /// If none was set, the internal default is returned,
2418 /// a simple '[+]' icon.
2419 ///
2420 Fl_Image* Fl_Tree::openicon() const {
2421   return(_prefs.openicon());
2422 }
2423 
2424 /// Sets the icon to be used as the 'open' icon.
2425 /// This overrides the built in default '[+]' icon.
2426 ///
2427 /// \param[in] val -- The new image, or zero to use the default [+] icon.
2428 ///
2429 void Fl_Tree::openicon(Fl_Image *val) {
2430   _prefs.openicon(val);
2431   redraw();
2432   recalc_tree();
2433 }
2434 
2435 /// Returns the icon to be used as the 'close' icon.
2436 /// If none was set, the internal default is returned,
2437 /// a simple '[-]' icon.
2438 ///
2439 Fl_Image* Fl_Tree::closeicon() const {
2440   return(_prefs.closeicon());
2441 }
2442 
2443 /// Sets the icon to be used as the 'close' icon.
2444 /// This overrides the built in default '[-]' icon.
2445 ///
2446 /// \param[in] val -- The new image, or zero to use the default [-] icon.
2447 ///
2448 void Fl_Tree::closeicon(Fl_Image *val) {
2449   _prefs.closeicon(val);
2450   redraw();
2451   recalc_tree();
2452 }
2453 
2454 /// Returns 1 if the collapse icon is enabled, 0 if not.
2455 /// \see showcollapse(int)
2456 int Fl_Tree::showcollapse() const {
2457   return(_prefs.showcollapse());
2458 }
2459 
2460 /// Set if we should show the collapse icon or not.
2461 /// If collapse icons are disabled, the user will not be able
2462 /// to interactively collapse items in the tree, unless the application
2463 /// provides some other means via open() and close().
2464 ///
2465 /// \param[in] val 1: shows collapse icons (default),\n
2466 ///                0: hides collapse icons.
2467 ///
2468 void Fl_Tree::showcollapse(int val) {
2469   _prefs.showcollapse(val);
2470   redraw();
2471   recalc_tree();
2472 }
2473 
2474 /// Returns 1 if the root item is to be shown, or 0 if not.
2475 int Fl_Tree::showroot() const {
2476   return(_prefs.showroot());
2477 }
2478 
2479 /// Set if the root item should be shown or not.
2480 /// \param[in] val 1 -- show the root item (default)\n
2481 ///                0 -- hide the root item.
2482 ///
2483 void Fl_Tree::showroot(int val) {
2484   _prefs.showroot(val);
2485   redraw();
2486   recalc_tree();
2487 }
2488 
2489 /// Returns the line drawing style for inter-connecting items.
2490 Fl_Tree_Connector Fl_Tree::connectorstyle() const {
2491   return(_prefs.connectorstyle());
2492 }
2493 
2494 /// Sets the line drawing style for inter-connecting items.
2495 ///     See ::Fl_Tree_Connector for possible values.
2496 ///
2497 void Fl_Tree::connectorstyle(Fl_Tree_Connector val) {
2498   _prefs.connectorstyle(val);
2499   redraw();
2500 }
2501 
2502 /// Set the default sort order used when items are added to the tree.
2503 ///     See ::Fl_Tree_Sort for possible values.
2504 ///
2505 Fl_Tree_Sort Fl_Tree::sortorder() const {
2506   return(_prefs.sortorder());
2507 }
2508 
2509 /// Gets the sort order used to add items to the tree.
2510 void Fl_Tree::sortorder(Fl_Tree_Sort val) {
2511   _prefs.sortorder(val);
2512   // no redraw().. only affects new add()itions
2513 }
2514 
2515 /// Sets the style of box used to draw selected items.
2516 /// This is an fltk ::Fl_Boxtype.
2517 /// The default is influenced by FLTK's current Fl::scheme()
2518 ///
2519 Fl_Boxtype Fl_Tree::selectbox() const {
2520   return(_prefs.selectbox());
2521 }
2522 
2523 /// Gets the style of box used to draw selected items.
2524 /// This is an fltk ::Fl_Boxtype.
2525 /// The default is influenced by FLTK's current Fl::scheme()
2526 ///
2527 void Fl_Tree::selectbox(Fl_Boxtype val) {
2528   _prefs.selectbox(val);
2529   redraw();
2530 }
2531 
2532 /// Gets the tree's current selection mode.
2533 /// See ::Fl_Tree_Select for possible values.
2534 ///
2535 Fl_Tree_Select Fl_Tree::selectmode() const {
2536   return(_prefs.selectmode());
2537 }
2538 
2539 /// Sets the tree's selection mode.
2540 /// See ::Fl_Tree_Select for possible values.
2541 ///
2542 void Fl_Tree::selectmode(Fl_Tree_Select val) {
2543   _prefs.selectmode(val);
2544 }
2545 
2546 #if FLTK_ABI_VERSION >= 10301
2547 /// Returns the current item re/selection mode.
2548 /// \version 1.3.1 ABI feature
2549 ///
2550 Fl_Tree_Item_Reselect_Mode Fl_Tree::item_reselect_mode() const {
2551   return(_prefs.item_reselect_mode());
2552 }
2553 
2554 /// Sets the item re/selection mode.
2555 /// See ::Fl_Tree_Item_Reselect_Mode for possible values.
2556 /// \version 1.3.1 ABI feature
2557 ///
2558 void Fl_Tree::item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode) {
2559   _prefs.item_reselect_mode(mode);
2560 }
2561 
2562 /// Get the 'item draw mode' used for the tree.
2563 /// \version 1.3.1 ABI feature
2564 ///
2565 Fl_Tree_Item_Draw_Mode Fl_Tree::item_draw_mode() const {
2566   return(_prefs.item_draw_mode());
2567 }
2568 
2569 /// Set the 'item draw mode' used for the tree to \p 'mode'.
2570 ///
2571 /// This affects how items in the tree are drawn,
2572 /// such as when a widget() is defined.
2573 /// See ::Fl_Tree_Item_Draw_Mode for possible values.
2574 /// \version 1.3.1 ABI feature
2575 ///
2576 void Fl_Tree::item_draw_mode(Fl_Tree_Item_Draw_Mode mode) {
2577   _prefs.item_draw_mode(mode);
2578 }
2579 
2580 /// Set the 'item draw mode' used for the tree to integer \p 'mode'.
2581 ///
2582 /// This affects how items in the tree are drawn,
2583 /// such as when a widget() is defined.
2584 /// See ::Fl_Tree_Item_Draw_Mode for possible values.
2585 /// \version 1.3.1 ABI feature
2586 ///
2587 void Fl_Tree::item_draw_mode(int mode) {
2588   _prefs.item_draw_mode(Fl_Tree_Item_Draw_Mode(mode));
2589 }
2590 #endif
2591 
2592 /// See if \p 'item' is currently displayed on-screen (visible within the widget).
2593 ///
2594 /// This can be used to detect if the item is scrolled off-screen.
2595 /// Checks to see if the item's vertical position is within the top and bottom
2596 /// edges of the display window. This does NOT take into account the hide() / show()
2597 /// or open() / close() status of the item.
2598 ///
2599 /// \param[in] item The item to be checked. If NULL, first() is used.
2600 /// \returns 1 if displayed, 0 if scrolled off screen or no items are in tree.
2601 ///
2602 int Fl_Tree::displayed(Fl_Tree_Item *item) {
2603   item = item ? item : first();
2604   if (!item) return(0);
2605   return( (item->y() >= y()) && (item->y() <= (y()+h()-item->h())) ? 1 : 0);
2606 }
2607 
2608 /// Adjust the vertical scrollbar so that \p 'item' is visible
2609 /// \p 'yoff' pixels from the top of the Fl_Tree widget's display.
2610 ///
2611 /// For instance, yoff=0 will position the item at the top.
2612 ///
2613 /// If yoff is larger than the vertical scrollbar's limit,
2614 /// the value will be clipped. So if yoff=100, but scrollbar's max
2615 /// is 50, then 50 will be used.
2616 ///
2617 /// \param[in] item The item to be shown. If NULL, first() is used.
2618 /// \param[in] yoff The pixel offset from the top for the displayed position.
2619 ///
2620 /// \see show_item_top(), show_item_middle(), show_item_bottom()
2621 ///
2622 void Fl_Tree::show_item(Fl_Tree_Item *item, int yoff) {
2623   item = item ? item : first();
2624   if (!item) return;
2625   int newval = item->y() - y() - yoff + (int)_vscroll->value();
2626   if ( newval < _vscroll->minimum() ) newval = (int)_vscroll->minimum();
2627   if ( newval > _vscroll->maximum() ) newval = (int)_vscroll->maximum();
2628   _vscroll->value(newval);
2629   redraw();
2630 }
2631 
2632 /// Adjust the vertical scrollbar to show \p 'item' at the top
2633 /// of the display IF it is currently off-screen (for instance show_item_top()).
2634 /// If it is already on-screen, no change is made.
2635 ///
2636 /// \param[in] item The item to be shown. If NULL, first() is used.
2637 ///
2638 /// \see show_item_top(), show_item_middle(), show_item_bottom()
2639 ///
2640 void Fl_Tree::show_item(Fl_Tree_Item *item) {
2641   item = item ? item : first();
2642   if (!item) return;
2643   if ( displayed(item) ) return;
2644   show_item_top(item);
2645 }
2646 
2647 /// Adjust the vertical scrollbar so that \p 'item' is at the top of the display.
2648 ///
2649 /// \param[in] item The item to be shown. If NULL, first() is used.
2650 ///
2651 void Fl_Tree::show_item_top(Fl_Tree_Item *item) {
2652   item = item ? item : first();
2653   if (item) show_item(item, 0);
2654 }
2655 
2656 /// Adjust the vertical scrollbar so that \p 'item' is in the middle of the display.
2657 ///
2658 /// \param[in] item The item to be shown. If NULL, first() is used.
2659 ///
2660 void Fl_Tree::show_item_middle(Fl_Tree_Item *item) {
2661   item = item ? item : first();
2662 #if FLTK_ABI_VERSION >= 10303
2663   if (item) show_item(item, (_tih/2)-(item->h()/2));
2664 #else
2665   if (item) show_item(item, (h()/2)-(item->h()/2));
2666 #endif
2667 }
2668 
2669 /// Adjust the vertical scrollbar so that \p 'item' is at the bottom of the display.
2670 ///
2671 /// \param[in] item The item to be shown. If NULL, first() is used.
2672 ///
2673 void Fl_Tree::show_item_bottom(Fl_Tree_Item *item) {
2674   item = item ? item : first();
2675 #if FLTK_ABI_VERSION >= 10303
2676   if (item) show_item(item, _tih-item->h());
2677 #else
2678   if (item) show_item(item, h()-item->h());
2679 #endif
2680 }
2681 
2682 /// Displays \p 'item', scrolling the tree as necessary.
2683 /// \param[in] item The item to be displayed. If NULL, first() is used.
2684 ///
2685 void Fl_Tree::display(Fl_Tree_Item *item) {
2686   item = item ? item : first();
2687   if (item) show_item_middle(item);
2688 }
2689 
2690 /// Returns the vertical scroll position as a pixel offset.
2691 /// The position returned is how many pixels of the tree are scrolled off the top edge
2692 /// of the screen.
2693 /// \see vposition(int), hposition(), hposition(int)
2694 ///
2695 int Fl_Tree::vposition() const {
2696   return((int)_vscroll->value());
2697 }
2698 
2699 /// Sets the vertical scroll offset to position \p 'pos'.
2700 /// The position is how many pixels of the tree are scrolled off the top edge
2701 /// of the screen.
2702 /// \param[in] pos The vertical position (in pixels) to scroll the tree to.
2703 /// \see vposition(), hposition(), hposition(int)
2704 ///
2705 void Fl_Tree::vposition(int pos) {
2706   if (pos < 0) pos = 0;
2707   if (pos > _vscroll->maximum()) pos = (int)_vscroll->maximum();
2708   if (pos == _vscroll->value()) return;
2709   _vscroll->value(pos);
2710   redraw();
2711 }
2712 
2713 /// Returns the horizontal scroll position as a pixel offset.
2714 /// The position returned is how many pixels of the tree are scrolled off the left edge
2715 /// of the screen.
2716 /// \see hposition(int), vposition(), vposition(int)
2717 /// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective.
2718 ///
2719 int Fl_Tree::hposition() const {
2720 #if FLTK_ABI_VERSION >= 10303
2721   return((int)_hscroll->value());
2722 #else
2723   return(0);
2724 #endif
2725 }
2726 
2727 /// Sets the horizontal scroll offset to position \p 'pos'.
2728 /// The position is how many pixels of the tree are scrolled off the left edge
2729 /// of the screen.
2730 /// \param[in] pos The vertical position (in pixels) to scroll the tree to.
2731 /// \see hposition(), vposition(), vposition(int)
2732 /// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective.
2733 ///
2734 void Fl_Tree::hposition(int pos) {
2735 #if FLTK_ABI_VERSION >= 10303
2736   if (pos < 0) pos = 0;
2737   if (pos > _hscroll->maximum()) pos = (int)_hscroll->maximum();
2738   if (pos == _hscroll->value()) return;
2739   _hscroll->value(pos);
2740   redraw();
2741 #endif
2742 }
2743 
2744 /// See if widget \p 'w' is one of the Fl_Tree widget's scrollbars.
2745 /// Use this to skip over the scrollbars when walking the child() array. Example:
2746 /// \code
2747 /// for ( int i=0; i<tree->children(); i++ ) {    // walk children
2748 ///     Fl_Widget *w = tree->child(i);
2749 ///     if ( tree->is_scrollbar(w) ) continue;    // skip scrollbars
2750 ///     ..do work here..
2751 /// }
2752 /// \endcode
2753 /// \param[in] w Widget to test
2754 /// \returns 1 if \p w is a scrollbar, 0 if not.
2755 /// \todo should be const
2756 ///
2757 int Fl_Tree::is_scrollbar(Fl_Widget *w) {
2758 #if FLTK_ABI_VERSION >= 10303
2759   return( (w==_vscroll || w==_hscroll) ? 1 : 0 );
2760 #else
2761   return( (w==_vscroll) ? 1 : 0 );
2762 #endif
2763 }
2764 
2765 /// Gets the default size of scrollbars' troughs for this widget
2766 /// in pixels.
2767 ///
2768 /// If this value is zero (default), this widget will use the global
2769 /// Fl::scrollbar_size() value as the scrollbar's width.
2770 ///
2771 /// \returns Scrollbar size in pixels, or 0 if the global Fl::scrollbar_size() is being used.
2772 /// \see Fl::scrollbar_size(int)
2773 ///
2774 int Fl_Tree::scrollbar_size() const {
2775   return(_scrollbar_size);
2776 }
2777 
2778 /// Sets the pixel size of the scrollbars' troughs to \p 'size'
2779 /// for this widget, in pixels.
2780 ///
2781 /// Normally you should not need this method, and should use the global
2782 /// Fl::scrollbar_size(int) instead to manage the size of ALL
2783 /// your widgets' scrollbars. This ensures your application
2784 /// has a consistent UI, and is the default behavior. Normally
2785 /// this is what you want.
2786 ///
2787 /// Only use this method if you really need to override just THIS
2788 /// instance of the widget's scrollbar size. (This need should be rare.)
2789 ///
2790 /// Setting \p size to the special value of 0 causes the widget to
2791 /// track the global Fl::scrollbar_size(), which is the default.
2792 ///
2793 /// \param[in] size Sets the scrollbar size in pixels.\n
2794 ///                 If 0 (default), scrollbar size tracks the global Fl::scrollbar_size()
2795 /// \see Fl::scrollbar_size()
2796 ///
2797 void Fl_Tree::scrollbar_size(int size) {
2798   _scrollbar_size = size;
2799   int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
2800   if ( _vscroll->w() != scrollsize ) {
2801     _vscroll->resize(x()+w()-scrollsize, h(), scrollsize, _vscroll->h());
2802   }
2803 #if FLTK_ABI_VERSION >= 10303
2804   if ( _hscroll->h() != scrollsize ) {
2805     _hscroll->resize(x(), y()+h()-scrollsize, _hscroll->w(), scrollsize);
2806   }
2807   // Changing scrollbar size affects _tiw/_tih + may affect scrollbar visibility
2808   calc_dimensions();
2809 #endif
2810 }
2811 
2812 /// See if the vertical scrollbar is currently visible.
2813 /// \returns 1 if scrollbar visible, 0 if not.
2814 ///
2815 int Fl_Tree::is_vscroll_visible() const {
2816   return(_vscroll->visible() ? 1 : 0);
2817 }
2818 
2819 /// See if the horizontal scrollbar is currently visible.
2820 /// \returns 1 if scrollbar visible, 0 if not.
2821 /// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective.
2822 ///
2823 int Fl_Tree::is_hscroll_visible() const {
2824 #if FLTK_ABI_VERSION >= 10303
2825   return(_hscroll->visible() ? 1 : 0);
2826 #else
2827   return 0;
2828 #endif
2829 }
2830 
2831 /// Do the callback for the specified \p 'item' using \p 'reason',
2832 /// setting the callback_item() and callback_reason().
2833 ///
2834 void Fl_Tree::do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) {
2835   callback_reason(reason);
2836   callback_item(item);
2837   do_callback((Fl_Widget*)this, user_data());
2838 }
2839 
2840 /// Sets the item that was changed for this callback.
2841 /// Used internally to pass the item that invoked the callback.
2842 ///
2843 void Fl_Tree::callback_item(Fl_Tree_Item* item) {
2844   _callback_item = item;
2845 }
2846 
2847 /// Gets the item that caused the callback.
2848 /// The callback() can use this value to see which item changed.
2849 ///
2850 Fl_Tree_Item* Fl_Tree::callback_item() {
2851   return(_callback_item);
2852 }
2853 
2854 /// Sets the reason for this callback.
2855 ///    Used internally to pass the reason the callback was invoked.
2856 ///
2857 void Fl_Tree::callback_reason(Fl_Tree_Reason reason) {
2858   _callback_reason = reason;
2859 }
2860 
2861 /// Gets the reason for this callback.
2862 ///
2863 /// The callback() can use this value to see why it was called. Example:
2864 /// \code
2865 ///     void MyTreeCallback(Fl_Widget *w, void *userdata) {
2866 ///         Fl_Tree *tree = (Fl_Tree*)w;
2867 ///         Fl_Tree_Item *item = tree->callback_item();    // the item changed (can be NULL if more than one item was changed!)
2868 ///         switch ( tree->callback_reason() ) {           // reason callback was invoked
2869 ///             case     FL_TREE_REASON_OPENED: ..item was opened..
2870 ///             case     FL_TREE_REASON_CLOSED: ..item was closed..
2871 ///             case   FL_TREE_REASON_SELECTED: ..item was selected..
2872 ///             case FL_TREE_REASON_RESELECTED: ..item was reselected (double-clicked, etc)..
2873 ///             case FL_TREE_REASON_DESELECTED: ..item was deselected..
2874 ///         }
2875 ///     }
2876 /// \endcode
2877 ///
2878 /// \see item_reselect_mode() -- enables FL_TREE_REASON_RESELECTED events
2879 ///
2880 Fl_Tree_Reason Fl_Tree::callback_reason() const {
2881   return(_callback_reason);
2882 }
2883 
2884 /**
2885  * Read a preferences database into the tree widget.
2886  * A preferences database is a hierarchical collection of data which can be
2887  * directly loaded into the tree view for inspection.
2888  * \param[in] prefs the Fl_Preferences database
2889  */
2890 void Fl_Tree::load(Fl_Preferences &prefs) {
2891   int i, j, n, pn = (int) strlen(prefs.path());
2892   char *p;
2893   const char *path = prefs.path();
2894   if (strcmp(path, ".")==0)
2895     path += 1; // root path is empty
2896   else
2897     path += 2; // child path starts with "./"
2898   n = prefs.groups();
2899   for (i=0; i<n; i++) {
2900     Fl_Preferences prefsChild(prefs, i);
2901     add(prefsChild.path()+2); // children always start with "./"
2902     load(prefsChild);
2903   }
2904   n = prefs.entries();
2905   for (i=0; i<n; i++) {
2906     // We must remove all fwd slashes in the key and value strings. Replace with backslash.
2907     char *key = strdup(prefs.entry(i));
2908     int kn = (int) strlen(key);
2909     for (j=0; j<kn; j++) {
2910       if (key[j]=='/') key[j]='\\';
2911     }
2912     char *val;  prefs.get(key, val, "");
2913     int vn = (int) strlen(val);
2914     for (j=0; j<vn; j++) {
2915       if (val[j]=='/') val[j]='\\';
2916     }
2917     if (vn<40) {
2918       size_t sze = pn + strlen(key) + vn;
2919       p = (char*)malloc(sze+5);
2920       sprintf(p, "%s/%s = %s", path, key, val);
2921     } else {
2922       size_t sze = pn + strlen(key) + 40;
2923       p = (char*)malloc(sze+5);
2924       sprintf(p, "%s/%s = %.40s...", path, key, val);
2925     }
2926     add(p[0]=='/'?p+1:p);
2927     free(p);
2928     free(val);
2929     free(key);
2930   }
2931 }
2932 
2933 /// Ensure the scrollbars are the last children
2934 void Fl_Tree::fix_scrollbar_order() {
2935   Fl_Widget** a = (Fl_Widget**)array();
2936   if (a[children()-1] != _vscroll) {
2937     int i,j;
2938 #if FLTK_ABI_VERSION >= 10303
2939     for (i = j = 0; j < children(); j++) {
2940       if (a[j] != _vscroll && a[j] != _hscroll ) a[i++] = a[j];
2941     }
2942     a[i++] = _hscroll;
2943     a[i++] = _vscroll;
2944 #else
2945     for (i = j = 0; j < children(); j++) {
2946       if (a[j] != _vscroll) a[i++] = a[j];
2947     }
2948     a[i++] = _vscroll;
2949 #endif
2950   }
2951 }
2952 
2953 /// Schedule tree to recalc the entire tree size.
2954 /// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective.
2955 ///
2956 void Fl_Tree::recalc_tree() {
2957 #if FLTK_ABI_VERSION >= 10303
2958   _tree_w = _tree_h = -1;
2959 #endif
2960 }
2961 
2962 //
2963 // End of "$Id$".
2964 //
2965