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