1 //
2 // "$Id: Fl_Tree.H 8632 2011-05-04 02:59:50Z greg.ercolano $"
3 //
4 
5 #ifndef FL_TREE_H
6 #define FL_TREE_H
7 
8 #include <FL/Fl.H>
9 #include <FL/Fl_Group.H>
10 #include <FL/Fl_Scrollbar.H>
11 #include <FL/fl_draw.H>
12 
13 #include <FL/Fl_Tree_Item.H>
14 #include <FL/Fl_Tree_Prefs.H>
15 
16 //////////////////////
17 // FL/Fl_Tree.H
18 //////////////////////
19 //
20 // Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
21 // Copyright (C) 2009-2010 by Greg Ercolano.
22 //
23 // This library is free software; you can redistribute it and/or
24 // modify it under the terms of the GNU Library General Public
25 // License as published by the Free Software Foundation; either
26 // version 2 of the License, or (at your option) any later version.
27 //
28 // This library is distributed in the hope that it will be useful,
29 // but WITHOUT ANY WARRANTY; without even the implied warranty of
30 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
31 // Library General Public License for more details.
32 //
33 // You should have received a copy of the GNU Library General Public
34 // License along with this library; if not, write to the Free Software
35 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
36 // USA.
37 //
38 
39 ///
40 /// \file
41 /// \brief This file contains the definitions of the Fl_Tree class
42 ///
43 
44 /// \class Fl_Tree
45 ///
46 /// \brief Tree widget.
47 ///
48 ///     \image html tree-simple.png "Fl_Tree example program"
49 ///     \image latex tree-simple.png "Fl_Tree example program" width=4cm
50 ///
51 /// \code
52 ///     Fl_Tree                                         // Top level widget
53 ///        |--- Fl_Tree_Item                            // Items in the tree
54 ///        |--- Fl_Tree_Prefs                           // Preferences for the tree
55 ///                  |--- Fl_Tree_Connector (enum)      // Connection modes
56 ///                  |--- Fl_Tree_Select (enum)         // Selection modes
57 ///                  |--- Fl_Tree_Sort (enum)           // Sort behavior
58 /// \endcode
59 ///
60 ///     Similar to Fl_Browser, Fl_Tree is a browser of Fl_Tree_Item's, which is arranged
61 ///     in a parented hierarchy, or 'tree'. Subtrees can be expanded or closed. Items can be
62 ///     added, deleted, inserted, sorted and re-ordered.
63 ///
64 ///     The tree items may also contain other FLTK widgets, like buttons, input fields,
65 ///     or even "custom" widgets.
66 ///
67 ///     The callback() is invoked depending on the value of when():
68 ///
69 ///         - FL_WHEN_RELEASE -- callback invoked when left mouse button is released on an item
70 ///         - FL_WHEN_CHANGED -- callback invoked when left mouse changes selection state
71 ///
72 ///     The simple way to define a tree:
73 /// \code
74 ///    #include <FL/Fl_Tree.H>
75 ///    [..]
76 ///    Fl_Tree tree(X,Y,W,H);
77 ///    tree.begin();
78 ///      tree.add("Flintstones/Fred");
79 ///      tree.add("Flintstones/Wilma");
80 ///      tree.add("Flintstones/Pebbles");
81 ///      tree.add("Simpsons/Homer");
82 ///      tree.add("Simpsons/Marge");
83 ///      tree.add("Simpsons/Bart");
84 ///      tree.add("Simpsons/Lisa");
85 ///    tree.end();
86 /// \endcode
87 ///
88 ///     Items can be added with add(),
89 ///     removed with remove(),
90 ///     completely cleared with clear(),
91 ///     inserted with insert() and insert_above(),
92 ///     selected/deselected with select() and deselect(),
93 ///     open/closed with open() and closed().
94 ///     Children of an item can be swapped around with Fl_Tree_Item::swap_children(),
95 ///     sorting can be controlled when items are add()ed via sortorder().
96 ///     You can walk the entire tree with first() and next().
97 ///     You can walk selected items with first_selected_item() and
98 ///     next_selected_item().
99 ///     Items can be found by their pathname using find_item(const char*),
100 ///     and an item's pathname can be found with item_pathname().
101 ///     The selected items' colors are controlled by selection_color() (inherited from Fl_Widget).
102 ///
103 ///     The tree can have different selection behaviors controlled by selectmode().
104 ///
105 ///     FLTK widgets (including custom widgets) can be assigned to tree items via
106 ///     Fl_Tree_Item::widget().
107 ///
108 ///     Icons for individual items can be changed with
109 ///     Fl_Tree_Item::openicon(),
110 ///     Fl_Tree_Item::closeicon(),
111 ///     Fl_Tree_Item::usericon().
112 ///
113 ///     Various default preferences can be globally manipulated via Fl_Tree_Prefs,
114 ///     including colors, margins, icons, connection lines.
115 ///
116 ///     The tree's callback() will be invoked when items change state or are open/closed.
117 ///     when() controls when mouse/keyboard events invoke the callback.
118 ///     callback_item() and callback_reason() can be used to determine the cause of the callback. eg:
119 ///
120 /// \code
121 /// void MyTreeCallback(Fl_Widget *w, void *data) {
122 ///   Fl_Tree      *tree = (Fl_Tree*)w;
123 ///   Fl_Tree_Item *item = (Fl_Tree_Item*)tree->callback_item();	// get selected item
124 ///   switch ( tree->callback_reason() ) {
125 ///     case FL_TREE_REASON_SELECTED: [..]
126 ///     case FL_TREE_REASON_DESELECTED: [..]
127 ///     case FL_TREE_REASON_OPENED: [..]
128 ///     case FL_TREE_REASON_CLOSED: [..]
129 ///   }
130 /// \endcode
131 ///
132 ///     To get the item's full menu pathname, you can use Fl_Tree_Item::item_pathname(), eg:
133 ///
134 /// \code
135 ///   char pathname[256] = "???";
136 ///   tree->item_pathname(pathname, sizeof(pathname), item);		// eg. "Parent/Child/Item"
137 /// \endcode
138 ///
139 ///     To walk all the items of the tree from top to bottom:
140 /// \code
141 /// // Walk all the items in the tree, and print their labels
142 /// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) {
143 ///     printf("Item: %s\n", item->label());
144 /// }
145 /// \endcode
146 ///
147 ///     To recursively walk all the children of a particular item,
148 ///     define a function that uses recursion:
149 ///     \code
150 /// // Find all of the item's children and print an indented report of their labels
151 /// void my_print_all_children(Fl_Tree_Item *item, int indent=0) {
152 ///     for ( int t=0; t<item->children(); t++ ) {
153 ///         printf("%*s Item: %s\n", indent, "", item->child(t)->label());
154 ///         my_print_all_children(item->child(t), indent+4);   // recurse
155 ///     }
156 /// }
157 ///     \endcode
158 ///
159 ///     To change the default label font and color for creating new items:
160 /// \code
161 ///  tree = new Fl_Tree(..);
162 ///  tree->item_labelfont(FL_COURIER);	// Use Courier font for all new items
163 ///  tree->item_labelfgcolor(FL_RED);	// Use red color for labels of all new items
164 ///  [..]
165 ///  // Now create the items in the tree using the above defaults.
166 ///  tree->add("Aaa");
167 ///  tree->add("Bbb");
168 ///  [..]
169 /// \endcode
170 ///
171 ///     To change the font and color of all items in the tree:
172 /// \code
173 /// // Change the font and color of all items currently in the tree
174 /// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) {
175 ///     item->labelfont(FL_COURIER);
176 ///     item->labelcolor(FL_RED);
177 /// }
178 /// \endcode
179 ///
180 ///     The following image shows the tree's various visual elements
181 ///     and the methods that control them:
182 ///
183 ///     \image html tree-elements.png
184 ///     \image latex tree-elements.png "Fl_Tree dimensions" width=6cm
185 ///
186 
187 /// \enum Fl_Tree_Reason
188 /// The reason the callback was invoked.
189 ///
190 enum Fl_Tree_Reason {
191   FL_TREE_REASON_NONE=0,	///< unknown reason
192   FL_TREE_REASON_SELECTED,	///< an item was selected
193   FL_TREE_REASON_DESELECTED,	///< an item was de-selected
194   FL_TREE_REASON_OPENED,	///< an item was opened
195   FL_TREE_REASON_CLOSED		///< an item was closed
196 };
197 
198 
199 class FL_EXPORT Fl_Tree : public Fl_Group {
200   Fl_Tree_Item  *_root;				// can be null!
201   Fl_Tree_Item  *_item_focus;			// item that has focus box
202   Fl_Tree_Item  *_callback_item;		// item invoked during callback (can be NULL)
203   Fl_Tree_Reason _callback_reason;		// reason for the callback
204   Fl_Tree_Prefs  _prefs;			// all the tree's settings
205   int            _scrollbar_size;		// size of scrollbar trough
206 
207 protected:
208   /// Vertical scrollbar
209   Fl_Scrollbar *_vscroll;
210 
211 protected:
212   void item_clicked(Fl_Tree_Item* val);
213   /// Do the callback for the item, setting the item and reason
do_callback_for_item(Fl_Tree_Item * item,Fl_Tree_Reason reason)214   void do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) {
215     callback_reason(reason);
216     callback_item(item);
217     do_callback((Fl_Widget*)this, user_data());
218   }
219   Fl_Tree_Item *next_visible_item(Fl_Tree_Item *start, int dir);
220 
221 public:
222   Fl_Tree(int X, int Y, int W, int H, const char *L=0);
223   ~Fl_Tree();
224   int handle(int e);
225   void draw();
226 
227   ///////////////////////
228   // root methods
229   ///////////////////////
230 
231   /// Set the label for the root item.
232   ///
233   /// Makes an internally managed copy of 'new_label'.
234   ///
root_label(const char * new_label)235   void root_label(const char *new_label) {
236     if ( ! _root ) return;
237     _root->label(new_label);
238   }
239   /// Returns the root item.
root()240   Fl_Tree_Item* root() {
241     return(_root);
242   }
243 
244   ////////////////////////////////
245   // Item creation/removal methods
246   ////////////////////////////////
247   Fl_Tree_Item *add(const char *path);
248   Fl_Tree_Item* add(Fl_Tree_Item *item, const char *name);
249   Fl_Tree_Item *insert_above(Fl_Tree_Item *above, const char *name);
250   Fl_Tree_Item* insert(Fl_Tree_Item *item, const char *name, int pos);
251 
252   /// Remove the specified \p item from the tree.
253   /// \p item may not be NULL.
254   /// If it has children, all those are removed too.
255   /// \returns 0 if done, -1 if 'item' not found.
256   ///
remove(Fl_Tree_Item * item)257   int remove(Fl_Tree_Item *item) {
258     if ( item == _root ) {
259       clear();
260     } else {
261       Fl_Tree_Item *parent = item->parent();		// find item's parent
262       if ( ! parent ) return(-1);
263       parent->remove_child(item);			// remove child + children
264     }
265     return(0);
266   }
267   /// Clear all children from the tree.
268   /// The tree will be left completely empty.
269   ///
clear()270   void clear() {
271     if ( ! _root ) return;
272     _root->clear_children();
273     delete _root; _root = 0;
274   }
275   /// Clear all the children of a particular node in the tree specified by \p item.
276   /// Item may not be NULL.
277   ///
clear_children(Fl_Tree_Item * item)278   void clear_children(Fl_Tree_Item *item) {
279     if ( item->has_children() ) {
280       item->clear_children();
281       redraw();				// redraw only if there were children to clear
282     }
283   }
284 
285   ////////////////////////
286   // Item lookup methods
287   ////////////////////////
288   Fl_Tree_Item *find_item(const char *path);
289   const Fl_Tree_Item *find_item(const char *path) const;
290   int item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item *item) const;
291 
292   const Fl_Tree_Item *find_clicked() const;
293 
294   /// Return the item that was last clicked.
295   ///
296   /// Valid only from within the callback().
297   ///
298   /// Deprecated: use callback_item() instead.
299   ///
300   /// \returns the item clicked, or 0 if none.
301   ///          0 may also be used to indicate several items were clicked/changed.
302   ///
item_clicked()303   Fl_Tree_Item *item_clicked() {
304     return(_callback_item);
305   }
306   Fl_Tree_Item *first();
307   Fl_Tree_Item *next(Fl_Tree_Item *item=0);
308   Fl_Tree_Item *prev(Fl_Tree_Item *item=0);
309   Fl_Tree_Item *last();
310   Fl_Tree_Item *first_selected_item();
311   Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item=0);
312 
313   //////////////////////////
314   // Item open/close methods
315   //////////////////////////
316 
317   /// Open the specified 'item'.
318   /// This causes the item's children (if any) to be shown.
319   /// Handles redrawing if anything was actually changed.
320   /// Invokes the callback depending on the value of optional parameter \p docallback.
321   ///
322   /// The callback can use callback_item() and callback_reason() respectively to determine
323   /// the item changed and the reason the callback was called.
324   ///
325   /// \param[in] item -- the item to be opened. Must not be NULL.
326   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
327   ///     -   0 - callback() is not invoked
328   ///     -   1 - callback() is invoked if item changed,
329   ///             callback_reason() will be FL_TREE_REASON_OPENED
330   /// \returns
331   ///     -   1 -- item was opened
332   ///     -   0 -- item was already open, no change
333   ///
334   /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
335   ///
336   int open(Fl_Tree_Item *item, int docallback=1) {
337     if ( item->is_open() ) return(0);
338     item->open();
339     redraw();
340     if ( docallback ) {
341       do_callback_for_item(item, FL_TREE_REASON_OPENED);
342     }
343     return(1);
344   }
345   /// Opens the item specified by \p path (eg: "Parent/child/item").
346   /// This causes the item's children (if any) to be shown.
347   /// Handles redrawing if anything was actually changed.
348   /// Invokes the callback depending on the value of optional parameter \p docallback.
349   ///
350   /// Items or submenus that themselves contain slashes ('/' or '\')
351   /// should be escaped, e.g. open("Holidays/12\\/25\//2010").
352   ///
353   /// The callback can use callback_item() and callback_reason() respectively to determine
354   /// the item changed and the reason the callback was called.
355   ///
356   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
357   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
358   ///     -   0 - callback() is not invoked
359   ///     -   1 - callback() is invoked if item changed,
360   ///             callback_reason() will be FL_TREE_REASON_OPENED
361   /// \returns
362   ///     -   1 -- OK: item opened
363   ///     -   0 -- OK: item was already open, no change
364   ///     -  -1 -- ERROR: item was not found
365   ///
366   /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
367   ///
368   int open(const char *path, int docallback=1) {
369     Fl_Tree_Item *item = find_item(path);
370     if ( ! item ) return(-1);
371     return(open(item, docallback));
372   }
373   /// Toggle the open state of \p item.
374   /// Handles redrawing if anything was actually changed.
375   /// Invokes the callback depending on the value of optional parameter \p docallback.
376   ///
377   /// The callback can use callback_item() and callback_reason() respectively to determine
378   /// the item changed and the reason the callback was called.
379   ///
380   /// \param[in] item -- the item whose open state is to be toggled. Must not be NULL.
381   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
382   ///     -   0 - callback() is not invoked
383   ///     -   1 - callback() is invoked, callback_reason() will be either
384   ///             FL_TREE_REASON_OPENED or FL_TREE_REASON_CLOSED
385   ///
386   /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
387   ///
388   void open_toggle(Fl_Tree_Item *item, int docallback=1) {
389     if ( item->is_open() ) {
390       close(item, docallback);
391     } else {
392       open(item, docallback);
393     }
394   }
395   /// Closes the specified \p item.
396   /// Handles redrawing if anything was actually changed.
397   /// Invokes the callback depending on the value of optional parameter \p docallback.
398   ///
399   /// The callback can use callback_item() and callback_reason() respectively to determine
400   /// the item changed and the reason the callback was called.
401   ///
402   /// \param[in] item -- the item to be closed. Must not be NULL.
403   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
404   ///     -   0 - callback() is not invoked
405   ///     -   1 - callback() is invoked if item changed,
406   ///             callback_reason() will be FL_TREE_REASON_CLOSED
407   /// \returns
408   ///     -   1 -- item was closed
409   ///     -   0 -- item was already closed, no change
410   ///
411   /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
412   ///
413   int close(Fl_Tree_Item *item, int docallback=1) {
414     if ( item->is_close() ) return(0);
415     item->close();
416     redraw();
417     if ( docallback ) {
418       do_callback_for_item(item, FL_TREE_REASON_CLOSED);
419     }
420     return(1);
421   }
422   /// Closes the item specified by \p path, eg: "Parent/child/item".
423   /// Handles redrawing if anything was actually changed.
424   /// Invokes the callback depending on the value of optional parameter \p docallback.
425   ///
426   /// Items or submenus that themselves contain slashes ('/' or '\')
427   /// should be escaped, e.g. close("Holidays/12\\/25\//2010").
428   ///
429   /// The callback can use callback_item() and callback_reason() respectively to determine
430   /// the item changed and the reason the callback was called.
431   ///
432   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
433   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
434   ///     -   0 - callback() is not invoked
435   ///     -   1 - callback() is invoked if item changed,
436   ///             callback_reason() will be FL_TREE_REASON_CLOSED
437   /// \returns
438   ///     -   1 -- OK: item closed
439   ///     -   0 -- OK: item was already closed, no change
440   ///     -  -1 -- ERROR: item was not found
441   ///
442   /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason()
443   ///
444   int close(const char *path, int docallback=1) {
445     Fl_Tree_Item *item = find_item(path);
446     if ( ! item ) return(-1);
447     return(close(item, docallback));
448   }
449   /// See if \p item is open.
450   ///
451   /// Items that are 'open' are themselves not necessarily visible;
452   /// one of the item's parents might be closed.
453   ///
454   /// \param[in] item -- the item to be tested. Must not be NULL.
455   /// \returns
456   ///     -  1 : item is open
457   ///     -  0 : item is closed
458   ///
is_open(Fl_Tree_Item * item)459   int is_open(Fl_Tree_Item *item) const {
460     return(item->is_open()?1:0);
461   }
462   /// See if item specified by \p path (eg: "Parent/child/item") is open.
463   ///
464   /// Items or submenus that themselves contain slashes ('/' or '\')
465   /// should be escaped, e.g. is_open("Holidays/12\\/25\//2010").
466   ///
467   /// Items that are 'open' are themselves not necessarily visible;
468   /// one of the item's parents might be closed.
469   ///
470   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
471   /// \returns
472   ///     -    1 - OK: item is open
473   ///     -    0 - OK: item is closed
474   ///     -   -1 - ERROR: item was not found
475   ///
is_open(const char * path)476   int is_open(const char *path) const {
477     const Fl_Tree_Item *item = find_item(path);
478     if ( ! item ) return(-1);
479     return(item->is_open()?1:0);
480   }
481   /// See if the specified \p item is closed.
482   ///
483   /// \param[in] item -- the item to be tested. Must not be NULL.
484   /// \returns
485   ///     -   1 : item is open
486   ///     -   0 : item is closed
487   ///
is_close(Fl_Tree_Item * item)488   int is_close(Fl_Tree_Item *item) const {
489     return(item->is_close());
490   }
491   /// See if item specified by \p path (eg: "Parent/child/item") is closed.
492   ///
493   /// Items or submenus that themselves contain slashes ('/' or '\')
494   /// should be escaped, e.g. is_close("Holidays/12\\/25\//2010").
495   ///
496   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
497   /// \returns
498   ///     -   1 - OK: item is closed
499   ///     -   0 - OK: item is open
500   ///     -  -1 - ERROR: item was not found
501   ///
is_close(const char * path)502   int is_close(const char *path) const {
503     const Fl_Tree_Item *item = find_item(path);
504     if ( ! item ) return(-1);
505     return(item->is_close()?1:0);
506   }
507 
508   /// Select the specified \p item. Use 'deselect()' to de-select it.
509   /// Handles redrawing if anything was actually changed.
510   /// Invokes the callback depending on the value of optional parameter \p docallback.
511   ///
512   /// The callback can use callback_item() and callback_reason() respectively to determine
513   /// the item changed and the reason the callback was called.
514   ///
515   /// \param[in] item -- the item to be selected. Must not be NULL.
516   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
517   ///     -   0 - the callback() is not invoked
518   ///     -   1 - the callback() is invoked if item changed state,
519   ///             callback_reason() will be FL_TREE_REASON_SELECTED
520   /// \returns
521   ///     -   1 - item's state was changed
522   ///     -   0 - item was already selected, no change was made
523   ///
524   int select(Fl_Tree_Item *item, int docallback=1) {
525     if ( ! item->is_selected() ) {
526       item->select();
527       set_changed();
528       if ( docallback ) {
529         do_callback_for_item(item, FL_TREE_REASON_SELECTED);
530       }
531       redraw();
532       return(1);
533     }
534     return(0);
535   }
536   /// Select the item specified by \p path (eg: "Parent/child/item").
537   /// Handles redrawing if anything was actually changed.
538   /// Invokes the callback depending on the value of optional parameter \p docallback.
539   ///
540   /// Items or submenus that themselves contain slashes ('/' or '\')
541   /// should be escaped, e.g. select("Holidays/12\\/25\//2010").
542   ///
543   /// The callback can use callback_item() and callback_reason() respectively to determine
544   /// the item changed and the reason the callback was called.
545   ///
546   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
547   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
548   ///     -   0 - the callback() is not invoked
549   ///     -   1 - the callback() is invoked if item changed state,
550   ///             callback_reason() will be FL_TREE_REASON_SELECTED
551   /// \returns
552   ///     -   1 : OK: item's state was changed
553   ///     -   0 : OK: item was already selected, no change was made
554   ///     -  -1 : ERROR: item was not found
555   ///
556   int select(const char *path, int docallback=1) {
557     Fl_Tree_Item *item = find_item(path);
558     if ( ! item ) return(-1);
559     return(select(item, docallback));
560   }
561   /// Toggle the select state of the specified \p item.
562   /// Handles redrawing if anything was actually changed.
563   /// Invokes the callback depending on the value of optional parameter \p docallback.
564   ///
565   /// The callback can use callback_item() and callback_reason() respectively to determine
566   /// the item changed and the reason the callback was called.
567   ///
568   /// \param[in] item -- the item to be selected. Must not be NULL.
569   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
570   ///     -   0 - the callback() is not invoked
571   ///     -   1 - the callback() is invoked, callback_reason() will be
572   ///             either FL_TREE_REASON_SELECTED or FL_TREE_REASON_DESELECTED
573   ///
574   void select_toggle(Fl_Tree_Item *item, int docallback=1) {
575     item->select_toggle();
576     set_changed();
577     if ( docallback ) {
578       do_callback_for_item(item, item->is_selected() ? FL_TREE_REASON_SELECTED
579                                                      : FL_TREE_REASON_DESELECTED);
580     }
581     redraw();
582   }
583   /// De-select the specified \p item.
584   /// Handles redrawing if anything was actually changed.
585   /// Invokes the callback depending on the value of optional parameter \p docallback.
586   ///
587   /// The callback can use callback_item() and callback_reason() respectively to determine
588   /// the item changed and the reason the callback was called.
589   ///
590   /// \param[in] item -- the item to be selected. Must not be NULL.
591   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
592   ///     -   0 - the callback() is not invoked
593   ///     -   1 - the callback() is invoked if item changed state,
594   ///             callback_reason() will be FL_TREE_REASON_DESELECTED
595   /// \returns
596   ///     -   0 - item was already deselected, no change was made
597   ///     -   1 - item's state was changed
598   ///
599   int deselect(Fl_Tree_Item *item, int docallback=1) {
600     if ( item->is_selected() ) {
601       item->deselect();
602       set_changed();
603       if ( docallback ) {
604         do_callback_for_item(item, FL_TREE_REASON_DESELECTED);
605       }
606       redraw();
607       return(1);
608     }
609     return(0);
610   }
611   /// Deselect an item specified by \p path (eg: "Parent/child/item").
612   /// Handles redrawing if anything was actually changed.
613   /// Invokes the callback depending on the value of optional parameter \p docallback.
614   ///
615   /// Items or submenus that themselves contain slashes ('/' or '\')
616   /// should be escaped, e.g. deselect("Holidays/12\\/25\//2010").
617   ///
618   /// The callback can use callback_item() and callback_reason() respectively to determine
619   /// the item changed and the reason the callback was called.
620   ///
621   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
622   /// \param[in] docallback -- A flag that determines if the callback() is invoked or not:
623   ///     -   0 - the callback() is not invoked
624   ///     -   1 - the callback() is invoked if item changed state,
625   ///             callback_reason() will be FL_TREE_REASON_DESELECTED
626   ///  \returns
627   ///     -   1 - OK: item's state was changed
628   ///     -   0 - OK: item was already deselected, no change was made
629   ///     -  -1 - ERROR: item was not found
630   ///
631   int deselect(const char *path, int docallback=1) {
632     Fl_Tree_Item *item = find_item(path);
633     if ( ! item ) return(-1);
634     return(deselect(item, docallback));
635   }
636 
637   int deselect_all(Fl_Tree_Item *item=0, int docallback=1);
638   int select_only(Fl_Tree_Item *selitem, int docallback=1);
639   int select_all(Fl_Tree_Item *item=0, int docallback=1);
640   void set_item_focus(Fl_Tree_Item *o);
641 
642   /// See if the specified \p item is selected.
643   ///
644   /// \param[in] item -- the item to be tested. Must not be NULL.
645   ///
646   /// \return
647   ///     -   1 : item selected
648   ///     -   0 : item deselected
649   ///
is_selected(Fl_Tree_Item * item)650   int is_selected(Fl_Tree_Item *item) const {
651     return(item->is_selected()?1:0);
652   }
653   /// See if item specified by \p path (eg: "Parent/child/item") is selected.
654   ///
655   /// Items or submenus that themselves contain slashes ('/' or '\')
656   /// should be escaped, e.g. is_selected("Holidays/12\\/25\//2010").
657   ///
658   /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
659   /// \returns
660   ///     -   1 : item selected
661   ///     -   0 : item deselected
662   ///     -  -1 : item was not found
663   ///
is_selected(const char * path)664   int is_selected(const char *path) {
665     Fl_Tree_Item *item = find_item(path);
666     if ( ! item ) return(-1);
667     return(is_selected(item));
668   }
669   /// Print the tree as 'ascii art' to stdout.
670   /// Used mainly for debugging.
671   ///
show_self()672   void show_self() {
673     if ( ! _root ) return;
674     _root->show_self();
675   }
676 
677   /////////////////////////////////
678   // Item attribute related methods
679   /////////////////////////////////
680 
681   /// Get the default label fontsize used for creating new items.
item_labelsize()682   Fl_Fontsize item_labelsize() const {
683     return(_prefs.labelsize());
684   }
685   /// Set the default label font size used for creating new items.
686   /// To change the font size on a per-item basis, use Fl_Tree_Item::labelsize(Fl_Fontsize)
687   ///
item_labelsize(Fl_Fontsize val)688   void item_labelsize(Fl_Fontsize val) {
689     _prefs.labelsize(val);
690   }
691   /// Get the default font face used for creating new items.
item_labelfont()692   Fl_Font item_labelfont() const {
693     return(_prefs.labelfont());
694   }
695   /// Set the default font face used for creating new items.
696   /// To change the font face on a per-item basis, use Fl_Tree_Item::labelfont(Fl_Font)
697   ///
item_labelfont(Fl_Font val)698   void item_labelfont(Fl_Font val) {
699     _prefs.labelfont(val);
700   }
701   /// Get the default label foreground color used for creating new items.
item_labelfgcolor(void)702   Fl_Color item_labelfgcolor(void) const {
703     return(_prefs.labelfgcolor());
704   }
705   /// Set the default label foreground color used for creating new items.
706   /// To change the foreground color on a per-item basis, use Fl_Tree_Item::labelfgcolor(Fl_Color)
707   ///
item_labelfgcolor(Fl_Color val)708   void item_labelfgcolor(Fl_Color val) {
709     _prefs.labelfgcolor(val);
710   }
711   /// Get the default label background color used for creating new items.
item_labelbgcolor(void)712   Fl_Color item_labelbgcolor(void) const {
713     return(_prefs.labelbgcolor());
714   }
715   /// Set the default label background color used for creating new items.
716   /// To change the background color on a per-item basis, use Fl_Tree_Item::labelbgcolor(Fl_Color)
717   ///
item_labelbgcolor(Fl_Color val)718   void item_labelbgcolor(Fl_Color val) {
719     _prefs.labelbgcolor(val);
720   }
721   /// Get the connector color used for tree connection lines.
connectorcolor()722   Fl_Color connectorcolor() const {
723     return(_prefs.connectorcolor());
724   }
725   /// Set the connector color used for tree connection lines.
connectorcolor(Fl_Color val)726   void connectorcolor(Fl_Color val) {
727     _prefs.connectorcolor(val);
728   }
729   /// Get the amount of white space (in pixels) that should appear
730   /// between the widget's left border and the tree's contents.
731   ///
marginleft()732   int marginleft() const {
733     return(_prefs.marginleft());
734   }
735   /// Set the amount of white space (in pixels) that should appear
736   /// between the widget's left border and the left side of the tree's contents.
737   ///
marginleft(int val)738   void marginleft(int val) {
739     _prefs.marginleft(val);
740     redraw();
741   }
742   /// Get the amount of white space (in pixels) that should appear
743   /// between the widget's top border and the top of the tree's contents.
744   ///
margintop()745   int margintop() const {
746     return(_prefs.margintop());
747   }
748   /// Sets the amount of white space (in pixels) that should appear
749   /// between the widget's top border and the top of the tree's contents.
750   ///
margintop(int val)751   void margintop(int val) {
752     _prefs.margintop(val);
753     redraw();
754   }
755   /// Get the amount of white space (in pixels) that should appear
756   /// below an open child tree's contents.
757   ///
openchild_marginbottom()758   int openchild_marginbottom() const {
759     return(_prefs.openchild_marginbottom());
760   }
761   /// Set the amount of white space (in pixels) that should appear
762   /// below an open child tree's contents.
763   ///
openchild_marginbottom(int val)764   void openchild_marginbottom(int val) {
765     _prefs.openchild_marginbottom(val);
766     redraw();
767   }
768   /// Gets the width of the horizontal connection lines (in pixels)
769   /// that appear to the left of each tree item's label.
770   ///
connectorwidth()771   int connectorwidth() const {
772     return(_prefs.connectorwidth());
773   }
774   /// Sets the width of the horizontal connection lines (in pixels)
775   /// that appear to the left of each tree item's label.
776   ///
connectorwidth(int val)777   void connectorwidth(int val) {
778     _prefs.connectorwidth(val);
779     redraw();
780   }
781   /// Returns the Fl_Image being used as the default user icon for all
782   /// newly created items.
783   /// Returns zero if no icon has been set, which is the default.
784   ///
usericon()785   Fl_Image *usericon() const {
786     return(_prefs.usericon());
787   }
788   /// Sets the Fl_Image to be used as the default user icon for all
789   /// newly created items.
790   ///
791   /// If you want to specify user icons on a per-item basis,
792   /// use Fl_Tree_Item::usericon() instead.
793   ///
794   /// \param[in] val -- The new image to be used, or
795   ///                   zero to disable user icons.
796   ///
usericon(Fl_Image * val)797   void usericon(Fl_Image *val) {
798     _prefs.usericon(val);
799     redraw();
800   }
801   /// Returns the icon to be used as the 'open' icon.
802   /// If none was set, the internal default is returned,
803   /// a simple '[+]' icon.
804   ///
openicon()805   Fl_Image *openicon() const {
806     return(_prefs.openicon());
807   }
808   /// Sets the icon to be used as the 'open' icon.
809   /// This overrides the built in default '[+]' icon.
810   ///
811   /// \param[in] val -- The new image, or zero to use the default [+] icon.
812   ///
openicon(Fl_Image * val)813   void openicon(Fl_Image *val) {
814     _prefs.openicon(val);
815     redraw();
816   }
817   /// Returns the icon to be used as the 'close' icon.
818   /// If none was set, the internal default is returned,
819   /// a simple '[-]' icon.
820   ///
closeicon()821   Fl_Image *closeicon() const {
822     return(_prefs.closeicon());
823   }
824   /// Sets the icon to be used as the 'close' icon.
825   /// This overrides the built in default '[-]' icon.
826   ///
827   /// \param[in] val -- The new image, or zero to use the default [-] icon.
828   ///
closeicon(Fl_Image * val)829   void closeicon(Fl_Image *val) {
830     _prefs.closeicon(val);
831     redraw();
832   }
833   /// Returns 1 if the collapse icon is enabled, 0 if not.
showcollapse()834   int showcollapse() const {
835     return(_prefs.showcollapse());
836   }
837   /// Set if we should show the collapse icon or not.
838   /// If collapse icons are disabled, the user will not be able
839   /// to interactively collapse items in the tree, unless the application
840   /// provides some other means via open() and close().
841   ///
842   /// \param[in] val 1: shows collapse icons (default),\n
843   ///                0: hides collapse icons.
844   ///
showcollapse(int val)845   void showcollapse(int val) {
846     _prefs.showcollapse(val);
847     redraw();
848   }
849   /// Returns 1 if the root item is to be shown, or 0 if not.
showroot()850   int showroot() const {
851     return(_prefs.showroot());
852   }
853   /// Set if the root item should be shown or not.
854   /// \param[in] val 1 -- show the root item (default)\n
855   ///                0 -- hide the root item.
856   ///
showroot(int val)857   void showroot(int val) {
858     _prefs.showroot(val);
859     redraw();
860   }
861   /// Returns the line drawing style for inter-connecting items.
connectorstyle()862   Fl_Tree_Connector connectorstyle() const {
863     return(_prefs.connectorstyle());
864   }
865   /// Sets the line drawing style for inter-connecting items.
connectorstyle(Fl_Tree_Connector val)866   void connectorstyle(Fl_Tree_Connector val) {
867     _prefs.connectorstyle(val);
868     redraw();
869   }
870   /// Set the default sort order used when items are added to the tree.
871   ///     See Fl_Tree_Sort for possible values.
872   ///
sortorder()873   Fl_Tree_Sort sortorder() const {
874     return(_prefs.sortorder());
875   }
876   /// Gets the sort order used to add items to the tree.
sortorder(Fl_Tree_Sort val)877   void sortorder(Fl_Tree_Sort val) {
878     _prefs.sortorder(val);
879     // no redraw().. only affects new add()itions
880   }
881   /// Sets the style of box used to draw selected items.
882   /// This is an fltk Fl_Boxtype.
883   /// The default is influenced by FLTK's current Fl::scheme()
884   ///
selectbox()885   Fl_Boxtype selectbox() const {
886     return(_prefs.selectbox());
887   }
888   /// Gets the style of box used to draw selected items.
889   /// This is an fltk Fl_Boxtype.
890   /// The default is influenced by FLTK's current Fl::scheme()
891   ///
selectbox(Fl_Boxtype val)892   void selectbox(Fl_Boxtype val) {
893     _prefs.selectbox(val);
894     redraw();
895   }
896   /// Gets the tree's current selection mode.
selectmode()897   Fl_Tree_Select selectmode() const {
898     return(_prefs.selectmode());
899   }
900   /// Sets the tree's selection mode.
selectmode(Fl_Tree_Select val)901   void selectmode(Fl_Tree_Select val) {
902     _prefs.selectmode(val);
903   }
904   int displayed(Fl_Tree_Item *item);
905   void show_item(Fl_Tree_Item *item, int yoff);
906   void show_item(Fl_Tree_Item *item);
907   void show_item_bottom(Fl_Tree_Item *item);
908   void show_item_middle(Fl_Tree_Item *item);
909   void show_item_top(Fl_Tree_Item *item);
910   void display(Fl_Tree_Item *item);
911   int  vposition() const;
912   void vposition(int ypos);
913 
914   /// See if widget \p w is one of the Fl_Tree widget's scrollbars.
915   /// Use this to skip over the scrollbars when walking the child() array. Example:
916   /// \code
917   /// for ( int i=0; i<tree->children(); i++ ) {    // walk children
918   ///     Fl_Widget *w= tree->child(i);
919   ///     if ( brow->is_scrollbar(w) ) continue;    // skip scrollbars
920   ///     ..do work here..
921   /// }
922   /// \endcode
923   /// \param[in] w Widget to test
924   /// \returns 1 if \p w is a scrollbar, 0 if not.
925   ///
is_scrollbar(Fl_Widget * w)926   int is_scrollbar(Fl_Widget *w) {
927       return( ( w == _vscroll ) ? 1 : 0 );
928   }
929   /// Gets the current size of the scrollbars' troughs, in pixels.
930   ///
931   /// If this value is zero (default), this widget will use the global
932   /// Fl::scrollbar_size() value as the scrollbar's width.
933   ///
934   /// \returns Scrollbar size in pixels, or 0 if the global Fl::scrollsize() is being used.
935   /// \see Fl::scrollbar_size(int)
936   ///
scrollbar_size()937   int scrollbar_size() const {
938       return(_scrollbar_size);
939   }
940   /// Sets the pixel size of the scrollbars' troughs to the \p size, in pixels.
941   ///
942   /// Normally you should not need this method, and should use the global
943   /// Fl::scrollbar_size(int) instead to manage the size of ALL
944   /// your widgets' scrollbars. This ensures your application
945   /// has a consistent UI, is the default behavior, and is normally
946   /// what you want.
947   ///
948   /// Only use THIS method if you really need to override the global
949   /// scrollbar size. The need for this should be rare.
950   ///
951   /// Setting \p size to the special value of 0 causes the widget to
952   /// track the global Fl::scrollbar_size(), which is the default.
953   ///
954   /// \param[in] size Sets the scrollbar size in pixels.\n
955   ///                 If 0 (default), scrollbar size tracks the global Fl::scrollbar_size()
956   /// \see Fl::scrollbar_size()
957   ///
scrollbar_size(int size)958   void scrollbar_size(int size) {
959       _scrollbar_size = size;
960       int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size();
961       if ( _vscroll->w() != scrollsize ) {
962         _vscroll->resize(x()+w()-scrollsize, h(), scrollsize, _vscroll->h());
963       }
964   }
965 
966   ///////////////////////
967   // callback related
968   ///////////////////////
969 
970   /// Sets the item that was changed for this callback.
971   ///    Used internally to pass the item that invoked the callback.
972   ///
callback_item(Fl_Tree_Item * item)973   void callback_item(Fl_Tree_Item* item) {
974     _callback_item = item;
975   }
976   /// Gets the item that caused the callback.
977   /// The callback() can use this value to see which item changed.
978   ///
callback_item()979   Fl_Tree_Item* callback_item() {
980     return(_callback_item);
981   }
982   /// Sets the reason for this callback.
983   ///    Used internally to pass the reason the callback was invoked.
984   ///
callback_reason(Fl_Tree_Reason reason)985   void callback_reason(Fl_Tree_Reason reason) {
986     _callback_reason = reason;
987   }
988   /// Gets the reason for this callback.
989   ///
990   /// The callback() can use this value to see why it was called. Example:
991   /// \code
992   ///     void MyTreeCallback(Fl_Widget *w, void *userdata) {
993   ///         Fl_Tree *tree = (Fl_Tree*)w;
994   ///         Fl_Tree_Item *item = tree->callback_item();    // the item changed (can be NULL if more than one item was changed!)
995   ///         switch ( tree->callback_reason() ) {           // reason callback was invoked
996   ///             case     FL_TREE_REASON_OPENED: ..item was opened..
997   ///             case     FL_TREE_REASON_CLOSED: ..item was closed..
998   ///             case   FL_TREE_REASON_SELECTED: ..item was selected..
999   ///             case FL_TREE_REASON_DESELECTED: ..item was deselected..
1000   ///         }
1001   ///     }
1002   /// \endcode
1003   ///
callback_reason()1004   Fl_Tree_Reason callback_reason() const {
1005     return(_callback_reason);
1006   }
1007 
1008   /// Load FLTK preferences
1009   void load(class Fl_Preferences&);
1010 };
1011 
1012 #endif /*FL_TREE_H*/
1013 
1014 //
1015 // End of "$Id: Fl_Tree.H 8632 2011-05-04 02:59:50Z greg.ercolano $".
1016 //
1017