summaryrefslogtreecommitdiff
path: root/FL/Fl_Tree.H
blob: 3768ab8e2871c9111e306b09d83f6cd9533af69b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
//
// "$Id$"
//

#ifndef FL_TREE_H
#define FL_TREE_H

#include <FL/Fl.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Scrollbar.H>
#include <FL/fl_draw.H>

#include <FL/Fl_Tree_Item.H>
#include <FL/Fl_Tree_Prefs.H>

//////////////////////
// FL/Fl_Tree.H
//////////////////////
//
// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
// Copyright (C) 2009 by Greg Ercolano.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//

///
/// \file
/// \brief This file contains the definitions of the Fl_Tree class
///

/// \class Fl_Tree
///
/// \brief Tree widget.
///
/// \code
///     Fl_Tree                                         // Top level widget
///        |--- Fl_Tree_Item                            // Items in the tree
///        |--- Fl_Tree_Prefs                           // Preferences for the tree
///                  |--- Fl_Tree_Connector (enum)      // Connection modes
///                  |--- Fl_Tree_Select (enum)         // Selection modes
///                  |--- Fl_Tree_Sort (enum)           // Sort behavior
/// \endcode
///
///     An expandable tree widget.
///
///     Similar to Fl_Browser, Fl_Tree is browser of Fl_Tree_Item's, which can be
///     in a parented hierarchy. Subtrees can be expanded or closed. Items can be
///     added, deleted, inserted, sorted and re-ordered.
///
///     The tree items may also contain other FLTK widgets, like buttons, input fields,
///     or even "custom" widgets.
///
///     The simple way to define a tree:
/// \code
///    #include <FL/Fl_Tree.H>
///    [..]
///    Fl_Tree tree(X,Y,W,H);
///    tree.begin();
///      tree.add("Flintstones/Fred");
///      tree.add("Flintstones/Wilma");
///      tree.add("Flintstones/Pebbles");
///      tree.add("Simpsons/Homer");
///      tree.add("Simpsons/Marge");
///      tree.add("Simpsons/Bart");
///      tree.add("Simpsons/Lisa");
///    tree.end();
/// \endcode
///     
///     Items can be added with Fl_Tree::add(),
///     removed with Fl_Tree::remove(),
///     inserted with Fl_Tree::insert_above(),
///     selected/deselected with Fl_Tree::select() and Fl_Tree::deselect().
///     Items can be swapped with Fl_Tree_Item::swap_children(), sorting control via
///     Fl_Tree::sortorder().
///
///     The tree can have different selection behaviors controlled by Fl_Tree::selectmode().
///
///     FLTK and custom FLTK widgets can be assigned to tree items via Fl_Tree_Item::widget().
///
///     Parent nodes can be open/closed with open() and close(), icons can be assigned
///     or redefined with some or all items via 
///     Fl_Tree_Item::openicon(), 
///     Fl_Tree_Item::closeicon(),
///     Fl_Tree_Item::usericon().
///
///     Various default preferences can be manipulated via Fl_Tree_Prefs, including
///     colors, margins, connection lines. 
///
///     \image html tree-elements.png
///

class Fl_Tree : public Fl_Group {
  Fl_Tree_Item  *_root;					// can be null!
  Fl_Tree_Item  *_item_clicked;
  Fl_Tree_Prefs  _prefs;				// all the tree's settings
  Fl_Scrollbar  *_vscroll;
  
public:
  /// Find the item that was clicked.
  /// You probably want to use item_clicked() instead, which is fast.
  ///
  /// This method walks the entire tree looking for the first item that is
  /// under the mouse (ie. at Fl::event_x()/Fl:event_y().
  ///
  /// Use this method /only/ if you've subclassed Fl_Tree, and are receiving
  /// events before Fl_Tree has been able to process and update item_clicked().
  /// 
  /// \returns the item clicked, or 0 if no item was under the current event.
  ///
  const Fl_Tree_Item *find_clicked() const {
    if ( ! _root ) return(0);
    return(_root->find_clicked(_prefs));
  }
protected:
  /// Set the item that was last clicked.
  /// Should only be used by subclasses needing to change this value.
  /// Normally Fl_Tree manages this value.
  ///
  void item_clicked(Fl_Tree_Item* val) {
    _item_clicked = val;
  }
  
public:
  Fl_Tree(int X, int Y, int W, int H, const char *L=0);
  ~Fl_Tree();
  int handle(int e);
  void draw();
  
  ///////////////////////
  // root methods
  ///////////////////////
  
  /// Set the label for the root item. 
  ///
  /// Makes an internally managed copy of 'new_label'.
  ///
  void root_label(const char *new_label) {
    if ( ! _root ) return;
    _root->label(new_label);
  }
  /// Returns the root item.
  Fl_Tree_Item* root() {
    return(_root);
  }
  
  ////////////////////////////////
  // Item creation/removal methods
  ////////////////////////////////
  Fl_Tree_Item *add(const char *path);
  Fl_Tree_Item* add(Fl_Tree_Item *item, const char *name);
  Fl_Tree_Item *insert_above(Fl_Tree_Item *above, const char *name);
  Fl_Tree_Item* insert(Fl_Tree_Item *item, const char *name, int pos);
  
  /// Remove the specified 'item' from the tree.
  /// If it has children, all those are removed too.
  /// \returns 0 if done, -1 if 'item' not found.
  ///
  int remove(Fl_Tree_Item *item) {
    if ( !item ) return(0);
    if ( item == _root ) {
      clear();
    } else {
      Fl_Tree_Item *parent = item->parent();		// find item's parent
      if ( ! parent ) return(-1);
      parent->remove_child(item);			// remove child + children
    }
    return(0);
  } 
  /// Clear all children from the tree.
  /// The tree will be left completely empty.
  ///
  void clear() {
    if ( ! _root ) return;
    _root->clear_children();
    delete _root; _root = 0;
  } 
  /// Clear all the children of a particular node in the tree.
  void clear_children(Fl_Tree_Item *item) {
    if ( item->has_children() ) {
      item->clear_children();
      redraw();						// redraw only if there were children to clear
    }
  } 
  
  ////////////////////////
  // Item lookup methods
  ////////////////////////
  Fl_Tree_Item *find_item(const char *path);
  const Fl_Tree_Item *find_item(const char *path) const;
  
  /// Return the parent for specified 'item'.
  ///
  /// \returns item's parent, or 0 if none (root).
  ///
  Fl_Tree_Item *parent(Fl_Tree_Item *item) {
    return(item->parent());
  }
  /// Return the item that was last clicked.
  ///
  /// Valid only from within an Fl_Tree::callback().
  ///
  /// \returns the item clicked, or 0 if none.
  ///
  Fl_Tree_Item *item_clicked() {
    return(_item_clicked);
  }
  /// Returns the first item in the tree.
  ///
  /// Use this to walk the tree in the forward direction, eg:
  /// \code
  /// for ( Fl_Tree_Item *item = tree->first(); item; item = item->next() ) {
  ///     printf("Item: %s\n", item->label());
  /// }
  /// \endcode
  ///
  /// \returns first item in tree, or 0 if none (tree empty).
  ///
  Fl_Tree_Item *first() {
    return(_root);					// first item always root
  }
  /// Returns the last item in the tree.
  ///
  /// Use this to walk the tree in reverse, eg:
  ///
  /// \code
  /// for ( Fl_Tree_Item *item = tree->last(); item; item = item->prev() ) {
  ///     printf("Item: %s\n", item->label());
  /// }
  /// \endcode
  ///
  /// \returns last item in the tree, or 0 if none (tree empty).
  ///
  Fl_Tree_Item *last() {
    if ( ! _root ) return(0);
    Fl_Tree_Item *item = _root;
    while ( item->has_children() ) {
      item = item->child(item->children()-1);
    }
    return(item);
  }
  
  //////////////////////////
  // Item open/close methods
  //////////////////////////
  
  /// Open the specified 'item'.
  /// This causes the item's children (if any) to be shown.
  /// Handles redrawing if anything was actually changed.
  ///
  void open(Fl_Tree_Item *item) {
    if ( ! item->is_open() ) {
      item->open();
      redraw();
    }
  }
  /// Opens the item specified by a 'menu item' style pathname (eg: "Parent/child/item").
  /// This causes the item's children (if any) to be shown.
  /// Handles redrawing if anything was actually changed.
  ///
  /// \returns
  ///     -   0 : OK
  ///     -  -1 : item was not found
  ///         
  int open(const char *path) {
    Fl_Tree_Item *item = find_item(path);
    if ( item ) {
      open(item);
      return(0);
    }
    return(-1);
  }
  /// Closes the 'item'.
  /// Handles redrawing if anything was actually changed.
  ///
  void close(Fl_Tree_Item *item) {
    if ( ! item->is_close() ) {
      item->close();
      redraw();
    }
  }
  /// Closes the item specified by 'path', eg: "Parent/child/item".
  ///
  /// Handles redrawing if anything was actually changed.
  ///
  /// \returns
  ///     -   0 -- OK
  ///     -  -1 -- item was not found
  ///         
  int close(const char *path) {
    Fl_Tree_Item *item = find_item(path);
    if ( item ) {
      close(item);
      return(0);
    }
    return(-1);
  }
  /// See if item is open.
  ///
  /// Items that are 'open' are themselves not necessarily visible;
  /// one of the item's parents might be closed.
  ///
  /// \returns
  ///     -  1 : item is open
  ///     -  0 : item is closed
  ///
  int is_open(Fl_Tree_Item *item) const {
    return(item->is_open()?1:0);
  }
  /// See if item specified by 'path' (eg: "Parent/child/item") is open.
  ///
  /// Items that are 'open' are themselves not necessarily visible;
  /// one of the item's parents might be closed.
  ///
  /// \returns
  ///     -    1 : item is open
  ///     -    0 : item is closed
  ///     -   -1 : item was not found
  ///
  int is_open(const char *path) const {
    const Fl_Tree_Item *item = find_item(path);
    if ( item ) return(item->is_open()?1:0);
    return(-1);
  }
  /// See if item is closed.
  /// \returns
  ///     -   1 : item is open
  ///     -   0 : item is closed
  ///
  int is_close(Fl_Tree_Item *item) const {
    return(item->is_close());
  }
  /// See if item specified by 'path' (eg: "Parent/child/item") is closed.
  ///
  /// \returns
  ///     -   1 : item is closed
  ///     -   0 : item is open
  ///     -  -1 : item was not found
  ///
  int is_close(const char *path) const {
    const Fl_Tree_Item *item = find_item(path);
    if ( item ) return(item->is_close()?1:0);
    return(-1);
  }
  
  /////////////////////////
  // Item selection methods
  /////////////////////////
  
  /// Select the specified item. Use 'deselect()' to de-select it.
  /// Handles redrawing if anything was actually changed.
  ///
  void select(Fl_Tree_Item *item) {
    if ( ! item->is_selected() ) {
      item->select();
      redraw();
    }
  }
  /// Select an item specified by 'path' (eg: "Parent/child/item").
  /// Handles redrawing if anything was actually changed.
  ///
  /// \returns
  ///     -   0 : OK
  ///     -  -1 : item was not found
  ///
  int select(const char *path) {
    Fl_Tree_Item *item = find_item(path);
    if ( item ) {
      select(item);
      return(0);
    }
    return(-1);
  }
  /// Toggle item's select state.
  /// Handles redrawing.
  ///
  void select_toggle(Fl_Tree_Item *item) {
    item->select_toggle();
    redraw();
  }
  /// De-select the specified item.
  /// Handles redrawing if anything was actually changed.
  ///
  void deselect(Fl_Tree_Item *item) {
    if ( item->is_selected() ) {
      item->deselect();
      redraw();
    }
  }
  /// De-select an item specified by 'path' (eg: "Parent/child/item").
  /// Handles redrawing if anything was actually changed.
  ///
  ///  \returns
  ///     -   0 : OK
  ///     -  -1 : item was not found
  ///
  int deselect(const char *path) {
    Fl_Tree_Item *item = find_item(path);
    if ( item ) {
      deselect(item);
      return(0);
    }
    return(-1);
  }
  
  int deselect_all(Fl_Tree_Item *item=0);
  int select_only(Fl_Tree_Item *selitem);
    int select_all(Fl_Tree_Item *item=0);
  
  /// See if the specified item is selected.
  /// \return
  ///     -   1 : item selected
  ///     -   0 : item deselected
  ///
  int is_selected(Fl_Tree_Item *item) const {
    return(item->is_selected()?1:0);
  }
  /// See if item specified by 'path' (eg: "Parent/child/item") is selected.
  ///
  /// \returns
  ///     -   1 : item selected
  ///     -   0 : item deselected
  ///     -  -1 : item was not found
  ///
  int is_selected(const char *path) {
    Fl_Tree_Item *item = find_item(path);
    if ( item ) return(is_selected(item));
    return(-1);
  }
  /// Print the tree as 'ascii art' to stdout.
  /// Used mainly for debugging.
  ///
  void show_self() {
    if ( ! _root ) return;
    _root->show_self();
  }
  
  /////////////////////////////////
  // Item attribute related methods
  /////////////////////////////////
  
  /// Get the default label fontsize used for creating new items.
  int labelsize() const {
    return(_prefs.labelsize());
  }
  /// Set the default label font size used for creating new items.
  /// To change the font size on a per-item basis, use Fl_Tree_Item::labelsize(int)
  ///
  void labelsize(int val) {
    _prefs.labelsize(val);
  }
  
  /// Get the default font face used for item's labels when new items are created.
  ///
  /// Don't use this if you want to change an existing label() size; use
  /// item->labelfont() instead.
  ///
  int labelfont() const {
    return(_prefs.labelfont());
  }
  /// Set the default font face used for item's labels when new items are created.
  ///
  /// Don't use this if you want to change an existing label() size; use
  /// item->labelfont(int) instead.
  ///
  void labelfont(int val) {
    _prefs.labelfont(val);
  }
  /// Get the amount of white space (in pixels) that should appear
  /// between the widget's left border and the tree's contents.
  ///
  int  marginleft() const {
    return(_prefs.marginleft());
  }
  /// Set the amount of white space (in pixels) that should appear
  /// between the widget's left border and the left side of the tree's contents.
  ///
  void marginleft(int val) {
    _prefs.marginleft(val);
    redraw();
  }
  /// Get the amount of white space (in pixels) that should appear
  /// between the widget's top border and the top of the tree's contents.
  ///
  int  margintop() const {
    return(_prefs.margintop());
  }
  /// Sets the amount of white space (in pixels) that should appear
  /// between the widget's top border and the top of the tree's contents.
  ///
  void margintop(int val) {
    _prefs.margintop(val);
    redraw();
  }
  /// Get the amount of white space (in pixels) that should appear
  /// below an open child tree's contents.
  ///
  int  openchild_marginbottom() const {
    return(_prefs.openchild_marginbottom());
  }
  /// Set the amount of white space (in pixels) that should appear
  /// below an open child tree's contents.
  ///
  void openchild_marginbottom(int val) {
    _prefs.openchild_marginbottom(val);
    redraw();
  }
  /// Gets the width of the horizontal connection lines (in pixels) 
  /// that appear to the left of each tree item's label.
  ///
  int  connectorwidth() const {
    return(_prefs.connectorwidth());
  }
  /// Sets the width of the horizontal connection lines (in pixels) 
  /// that appear to the left of each tree item's label.
  ///
  void connectorwidth(int val) {
    _prefs.connectorwidth(val);
    redraw();
  }
  /// Returns the Fl_Image being used as the default user icon for newly created items.
  /// Returns zero if no icon has been set, which is the default.
  ///
  Fl_Image *usericon() const {
    return(_prefs.usericon());
  }
  /// Sets the Fl_Image to be used as the default user icon for all
  /// newly created items.
  ///
  /// If you want to specify user icons on a per-item basis,
  /// use Fl_Tree_Item::usericon() instead.
  ///
  /// \param[in] val -- The new image to be used, or
  ///                   zero to disable user icons.
  ///
  void usericon(Fl_Image *val) {
    _prefs.usericon(val);
    redraw();
  }
  /// Returns the icon to be used as the 'open' icon.
  /// If none was set, the internal default is returned,
  /// a simple '[+]' icon.
  ///
  Fl_Image *openicon() const {
    return(_prefs.openicon());
  }
  /// Sets the icon to be used as the 'open' icon.
  /// This overrides the built in default '[+]' icon.
  ///
  /// \param[in] val -- The new image, or zero to use the default [+] icon.
  ///
  void openicon(Fl_Image *val) {
    _prefs.openicon(val);
    redraw();
  }
  /// Returns the icon to be used as the 'close' icon.
  /// If none was set, the internal default is returned,
  /// a simple '[-]' icon.
  ///
  Fl_Image *closeicon() const {
    return(_prefs.closeicon());
  }
  /// Sets the icon to be used as the 'close' icon.
  /// This overrides the built in default '[-]' icon.
  ///
  /// \param[in] val -- The new image, or zero to use the default [-] icon.
  ///
  void closeicon(Fl_Image *val) {
    _prefs.closeicon(val);
    redraw();
  }
  /// Returns 1 if the collapse icon is enabled, 0 if not.
  int showcollapse() const {
    return(_prefs.showcollapse());
  }
  /// Set if we should show the collapse icon or not.
  /// If collapse icons are disabled, the user will not be able
  /// to interactively collapse items in the tree, unless the application
  /// provides some other means via open() and close().
  ///
  /// \param[in] val 1: shows collapse icons (default),\n
  ///                0: hides collapse icons.
  ///
  void showcollapse(int val) {
    _prefs.showcollapse(val);
    redraw();
  }
  /// Returns 1 if the root item is to be shown, or 0 if not.
  int showroot() const {
    return(_prefs.showroot());
  }
  /// Set if the root item should be shown or not.
  /// \param[in] val 1 -- show the root item (default)\n
  ///                0 -- hide the root item.
  ///
  void showroot(int val) {
    _prefs.showroot(val);
    redraw();
  }
  /// Returns the line drawing style for inter-connecting items.
  Fl_Tree_Connector connectorstyle() const {
    return(_prefs.connectorstyle());
  }
  /// Sets the line drawing style for inter-connecting items.
  void connectorstyle(Fl_Tree_Connector val) {
    _prefs.connectorstyle(val);
    redraw();
  }
  /// Set the default sort order used when items are added to the tree.
  ///     See Fl_Tree_Sort for possible values.
  ///
  Fl_Tree_Sort sortorder() const {
    return(_prefs.sortorder());
  }
  /// Gets the sort order used to add items to the tree.
  void sortorder(Fl_Tree_Sort val) {
    _prefs.sortorder(val);
    // no redraw().. only affects new add()itions
  }
  /// Sets the style of box used to draw selected items.
  /// This is an fltk Fl_Boxtype.
  /// The default is influenced by FLTK's current Fl::scheme()
  ///
  Fl_Boxtype selectbox() const {
    return(_prefs.selectbox());
  }
  /// Gets the style of box used to draw selected items.
  /// This is an fltk Fl_Boxtype.
  /// The default is influenced by FLTK's current Fl::scheme()
  ///
  void selectbox(Fl_Boxtype val) {
    _prefs.selectbox(val);
    redraw();
  }
  /// Gets the tree's current selection mode.
  Fl_Tree_Select selectmode() const {
    return(_prefs.selectmode());
  }
  /// Sets the tree's selection mode.
  void selectmode(Fl_Tree_Select val) {
    _prefs.selectmode(val);
  }
};

#endif /*FL_TREE_H*/

//
// End of "$Id$".
//