1 // $Id: Flu_Tree_Browser.h,v 1.91 2004/11/05 17:03:20 jbryan Exp $ 2 3 /*************************************************************** 4 * FLU - FLTK Utility Widgets 5 * Copyright (C) 2002 Ohio Supercomputer Center, Ohio State University 6 * 7 * This file and its content is protected by a software license. 8 * You should have received a copy of this license with this file. 9 * If not, please contact the Ohio Supercomputer Center immediately: 10 * Attn: Jason Bryan Re: FLU 1224 Kinnear Rd, Columbus, Ohio 43212 11 * 12 ***************************************************************/ 13 14 15 16 #ifndef _FLU_TREE_BROWSER_H 17 #define _FLU_TREE_BROWSER_H 18 19 #include <stdio.h> 20 #include <string.h> 21 #include <stdlib.h> 22 23 //#define USE_FLU_DND 24 25 /* fltk includes */ 26 #include <FL/Fl.H> 27 #include <FL/Fl_Box.H> 28 #include <FL/Fl_Pixmap.H> 29 #include <FL/Fl_Image.H> 30 #include <FL/Fl_Scrollbar.H> 31 #include <FL/Fl_Group.H> 32 #include <FL/Fl_Menu_Button.H> 33 34 /* flu includes */ 35 #include "Flu_Enumerations.h" 36 #include "FluSimpleString.h" 37 #ifdef USE_FLU_DND 38 #include "Flu_DND.h" 39 #else 40 typedef struct { bool dummy; } Flu_DND_Event; // for compatibilty when not compiling DND support 41 #endif 42 43 //! This class provides a browser for hierarchical data representation (i.e. a "tree") 44 #ifdef USE_FLU_DND 45 class FLU_EXPORT Flu_Tree_Browser : public Fl_Group, public Flu_DND 46 #else 47 class FLU_EXPORT Flu_Tree_Browser : public Fl_Group 48 #endif 49 { 50 51 static bool USE_FLU_WIDGET_CALLBACK; 52 53 public: 54 55 class Node; 56 friend class Node; 57 58 //! Normal FLTK widget constructor 59 Flu_Tree_Browser( int x, int y, int w, int h, const char *label = 0 ); 60 61 //! Default destructor 62 virtual ~Flu_Tree_Browser(); 63 64 //! Add the entry specified by \b fullpath to the tree. If \b w is not \c NULL then that widget is the entry and its label is visible depending on the value of \b showLabel. Note that the widget is destroyed by the tree/node on clear() or the destructor 65 /*! If \b fullpath ends in a slash ("/"), then the entry is added as a branch, else it is added as a leaf 66 \return a pointer to the Node of the added entry or NULL if the add failed */ 67 Node* add( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ); 68 69 //! Convenience function that is the same as add() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 70 Node* add( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 71 72 //! Add entry \b name to node \b n. If \b w is not \c NULL then that widget is the entry and its label is visible depending on the value of \b showLabel. Note that the widget is destroyed by the tree/node on clear() or the destructor 73 /*! If \b name ends in a slash ("/"), then the entry is added as a branch, else it is added as a leaf 74 \return a pointer to the Node of the added entry or NULL if the add failed */ 75 inline Node* add( Node* n, const char* name, Fl_Widget *w = 0, bool showLabel = true ) 76 { return n->add( name, w, showLabel ); } 77 78 //! Convenience function that is the same as add() except it appends a '/' to \b fullpath if one does not exist 79 Node* add_branch( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ); 80 81 //! Convenience function that is the same as add() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 82 Node* add_branch( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 83 84 //! Convenience function that is the same as add() except it appends a '/' to \b name if one does not exist 85 inline Node* add_branch( Node* n, const char* name, Fl_Widget *w = 0, bool showLabel = true ) 86 { return n->add_branch( name, w, showLabel ); } 87 88 //! Convenience function that is the same as add() except it removes any '/' at the end of \b fullpath 89 Node* add_leaf( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ); 90 91 //! Convenience function that is the same as add() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 92 Node* add_leaf( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 93 94 //! Convenience function that is the same as add() except it removes any '/' at the end of \b fullpath 95 inline Node* add_leaf( Node* n, const char* name, Fl_Widget *w = 0, bool showLabel = true ) 96 { return n->add_leaf( name, w, showLabel ); } 97 98 //! Set whether all branches are always open. Default value is \c false all_branches_always_open(bool b)99 inline void all_branches_always_open( bool b ) 100 { rdata.allBranchesAlwaysOpen = b; } 101 102 //! Get whether all branches are always open. Default value is \c false all_branches_always_open()103 inline bool all_branches_always_open() 104 { return rdata.allBranchesAlwaysOpen; } 105 106 //! Set whether multiple leaves with the same path are allowed. Default value is \c true allow_leaf_duplication(bool b)107 inline void allow_leaf_duplication( bool b ) 108 { rdata.allowDuplication = b; } 109 110 //! Get whether multiple leaves with the same path are allowed. allow_leaf_duplication()111 inline bool allow_leaf_duplication() 112 { return rdata.allowDuplication; } 113 114 //! \return \c true if drag and drop support has been compiled in, \c false otherwise have_dnd()115 inline bool have_dnd() 116 { 117 #ifdef USE_FLU_DND 118 return true; 119 #else 120 return false; 121 #endif 122 } 123 124 //! Set whether drag and drop processing is enabled for the browser. Default is \c false 125 /*! If DND is enabled, either text or instances of Flu_Tree_Browser::DND_Object from outside the tree can be dragged and dropped 126 onto the tree to create a new node. Nodes within the tree can be dragged and dropped (only within the same tree) according to 127 the value of selection_drag_mode(). */ allow_dnd(bool b)128 inline void allow_dnd( bool b ) 129 { rdata.dnd = b; } 130 131 //! Get whether drag and drop processing is enabled for the browser. allow_dnd()132 inline bool allow_dnd() 133 { return rdata.dnd; } 134 135 //! Set whether the root node is always open. Shortcut for \c get_root()->always_open(b). Default is \c false always_open(bool b)136 inline void always_open( bool b ) 137 { root.always_open( b ); } 138 139 //! Get whether the root node is always open always_open()140 inline bool always_open() 141 { return root.always_open(); } 142 143 //! Set whether animations of opening/closing branches are enabled. Default is \c false animate(bool b)144 inline void animate( bool b ) 145 { rdata.animate = b; } 146 147 //! Get whether animations of opening/closing branches are enabled animate()148 inline bool animate() 149 { return rdata.animate; } 150 151 //! Set whether the tree automatically determines whether a node is a branch or a leaf based on whether it has any children. Default is \c false 152 void auto_branches( bool b ); 153 154 //! Get whether the tree automatically determines whether a node is a branch or a leaf based on whether it has any children auto_branches()155 inline bool auto_branches() const 156 { return rdata.autoBranches; } 157 158 //! Get the default branch text color branch_color()159 inline Fl_Color branch_color() const 160 { return rdata.defBranchColor; } 161 162 //! Get the default branch text font branch_font()163 inline Fl_Font branch_font() const 164 { return rdata.defBranchFont; } 165 166 //! Get the default branch text size branch_size()167 inline int branch_size() const 168 { return rdata.defBranchSize; } 169 170 //! Set the default color, font and size to use for the text of all subsequent branches added to the tree branch_text(Fl_Color color,Fl_Font font,int size)171 inline void branch_text( Fl_Color color, Fl_Font font, int size ) 172 { rdata.defBranchColor = color; rdata.defBranchFont = font; rdata.defBranchSize = size; } 173 174 //! Set the default branch icons to use for all subsequent branches added to the tree 175 /*! Passing in \c NULL for either icon will disable that icon for the branch */ 176 void branch_icons( Fl_Image *closed, Fl_Image *open ); 177 178 //! Get the type of box to draw the browser in box()179 inline Fl_Boxtype box() const 180 { return _box->box(); } 181 182 //! Set the type of box to draw the browser in. Default is FL_FLAT_BOX box(Fl_Boxtype b)183 inline void box( Fl_Boxtype b ) 184 { _box->box( b ); } 185 186 //! Override of Fl_Widget::callback 187 //inline void callback( Fl_Callback *c, void *user_data = 0 ) 188 //{ rdata.cb = c; rdata.cbd = user_data; } 189 190 //! Get the reason why the last callback happened. This can be one of FLU_UNHILIGHTED, FLU_HILIGHTED, FLU_SELECTED, FLU_UNSELECTED, FLU_OPENED, FLU_CLOSED, FLU_DOUBLE_CLICK, FLU_WIDGET_CALLBACK, FLU_MOVED_CALLBACK, FLU_NEW_NODE_CALLBACK callback_reason()191 inline int callback_reason() const 192 { return rdata.cbReason; } 193 194 //! Get the node on which the last callback happened. 195 /*! \note this node is only guaranteed to be in the tree \b during the callback. If the callback adds/removes nodes, then this node may have changed */ callback_node()196 inline Node* callback_node() const 197 { return rdata.cbNode; } 198 199 //! Clear all entries from the tree 200 void clear(); 201 202 //! Set the default collapse icons to use for all subsequent branches added to the tree 203 void collapse_icons( Fl_Image *closed, Fl_Image *open ); 204 205 //! Get the amount of time to take when animating an open/close. Use in conjunction with frame_rate() collapse_time()206 inline float collapse_time() const 207 { return rdata.collapseTime; } 208 209 //! Set the amount of time to take when animating an open/close. Use in conjunction with frame_rate(). Default is 0.1 seconds collapse_time(float t)210 inline void collapse_time( float t ) 211 { rdata.collapseTime = t; } 212 213 //! Get the background color of the browser color()214 inline Fl_Color color() const 215 { return _box->color(); } 216 217 //! Set the background color of the browser. Default is FL_WHITE color(Fl_Color c)218 inline void color( Fl_Color c ) 219 { _box->color( c ); } 220 221 //! Set the color, style, and width of the connector lines. Default is FL_DARK2, FL_DOT, 1 222 inline void connector_style( Fl_Color color, int style, int width = 1 ) 223 { rdata.defLineColor = color; rdata.lineStyle = style; rdata.lineWidth = width; } 224 225 //! Get the color of the connector lines connector_color()226 inline Fl_Color connector_color() const 227 { return rdata.defLineColor; } 228 229 //! Get the style of the connector lines connector_style()230 inline int connector_style() const 231 { return rdata.lineStyle; } 232 233 //! Get the width of the connector lines connector_width()234 inline int connector_width() const 235 { return rdata.lineWidth; } 236 237 //! Set whether double-clicking a branch opens/closes it double_click_opens(bool b)238 inline void double_click_opens( bool b ) 239 { rdata.doubleClickToOpen = b; } 240 241 //! Get whether double-clicking a branch opens/closes it double_click_opens()242 inline bool double_click_opens() 243 { return rdata.doubleClickToOpen; } 244 245 //! Get the color to use for shading even entries even_shaded_entry_color()246 inline Fl_Color even_shaded_entry_color() const 247 { return rdata.shadedColors[0]; } 248 249 //! Find the entry identified by \b fullpath 250 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ find(const char * fullpath)251 inline Node* find( const char *fullpath ) 252 { return find_next( fullpath ); } 253 254 //! Find entry \b name in path \b path 255 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 256 Node* find( const char *path, const char *name ); 257 258 //! Find the entry identified by unique id \b id 259 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 260 Node* find( unsigned int id ); 261 262 //! Search for Node \b n in the tree 263 /*! \return a pointer to \b n if it is found, or NULL if it is not in the tree */ find(Node * n)264 inline Node* find( Node *n ) 265 { if( !n ) return NULL; else return find( n->id() ); } 266 267 //! Find the entry containing the widget \b w 268 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 269 Node* find( Fl_Widget *w ); 270 271 //! Find the next entry identified by \b fullpath after \b startNode 272 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 273 Node* find_next( const char *fullpath, Node* startNode = NULL ); 274 275 //! Find the next entry \b name in path \b path after \b startNode 276 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 277 Node* find_next( const char *path, const char *name ); 278 279 //! \return the number of discovered nodes matching path \b fullpath 280 int find_number( const char *fullpath ); 281 282 //! \return the number of discovered nodes with name \b name in path \b path 283 int find_number( const char *path, const char *name ); 284 285 //! \return the full path of the entry identified by unique id \b id, or the empty string if no matching entry was found 286 /*! \note the returned value is only valid until the next time find_path() is called */ 287 const char* find_path( unsigned int id ); 288 289 //! \return the full path of the entry containing the widget \b w, or the empty string if no matching entry was found 290 /*! \note the returned value is only valid until the next time find_path() is called */ 291 const char* find_path( Fl_Widget *w ); 292 293 //! \return the full path of Node \b n, or the empty string if \b n is not in the tree 294 /*! \note the returned value is only valid until the next time find_path() is called */ find_path(Node * n)295 inline const char* find_path( Node *n ) 296 { if( !n ) return ""; else return find_path( n->id() ); } 297 298 //! \return the first node in the tree (i.e. the root) first()299 inline Node* first() { return root.first(); } 300 301 //! \return the first branch encountered in a depth-first traversal of the tree. NULL means there are no branches first_branch()302 inline Node* first_branch() { return root.first_branch(); } 303 304 //! \return the first leaf encountered in a depth-first traversal of the tree. NULL means there are no leaves first_leaf()305 inline Node* first_leaf() { return root.first_leaf(); } 306 307 //! Get the frame rate to use during the open/close animation. Use in conjunction with collapse_time() frame_rate()308 inline float frame_rate() const 309 { return rdata.fps; } 310 311 //! Set the frame rate to use during the open/close animation. Use in conjunction with collapse_time(). Default is 100 frames per second frame_rate(float f)312 inline void frame_rate( float f ) 313 { if( f <= 0.0f ) rdata.fps = 0.001f; else rdata.fps = f; } 314 315 //! \return the currently highlighted node get_hilighted()316 inline Node* get_hilighted() 317 { return rdata.hilighted; } 318 319 //! \return a pointer to the root node of the tree get_root()320 inline Node *get_root() { return &root; } 321 322 //! \return the selected Node that is at \b index among all selected nodes, or \c NULL if no Node is selected 323 /*! For example, \c get_selected(1) will return the first selected node. */ 324 Node* get_selected( int index ); 325 326 //! Override of Fl_Widget::handle 327 int handle( int event ); 328 329 //! Set the horizontal icon gap for each entry. Default is 2 horizontal_gap(int g)330 inline void horizontal_gap( int g ) 331 { rdata.hGap = g; rdata.forceResize = true; } 332 333 //! Get the horizontal icon gap for each entry horizontal_gap()334 inline int horizontal_gap() const 335 { return rdata.hGap; } 336 337 //! Set how entries are inserted into the tree. This can be one of FLU_INSERT_FRONT, FLU_INSERT_BACK, FLU_INSERT_SORTED, FLU_INSERT_SORTED_REVERSE. Default is FLU_INSERT_SORTED 338 void insertion_mode( int m ); 339 340 //! Get how entries are inserted into the tree. insertion_mode()341 inline int insertion_mode() 342 { return rdata.insertionMode; } 343 344 //! \return whether the point \c (x,y) is inside the entry area (not on the scrollbars) 345 bool inside_entry_area( int x, int y ); 346 347 //! Set the title of the Tree (also the label for the root entry) label(const char * l)348 inline void label( const char *l ) 349 { root.text = l; } 350 351 //! Get the title of the Tree (also the label for the root entry) label()352 inline const char* label() const 353 { return root.text.c_str(); } 354 355 //! \return the last node in the tree last()356 inline Node* last() { return root.last(); } 357 358 //! \return the last branch encountered in a depth-first traversal of the tree. NULL means there are no branches last_branch()359 inline Node* last_branch() { return root.last_branch(); } 360 361 //! \return the last leaf encountered in a depth-first traversal of the tree. NULL means there are no leaves last_leaf()362 inline Node* last_leaf() { return root.last_leaf(); } 363 364 //! Get the default leaf text color leaf_color()365 inline Fl_Color leaf_color() const 366 { return rdata.defLeafColor; } 367 368 //! Get the default leaf text font leaf_font()369 inline Fl_Font leaf_font() const 370 { return rdata.defLeafFont; } 371 372 //! Get the default leaf text size leaf_size()373 inline int leaf_size() const 374 { return rdata.defLeafSize; } 375 376 //! Set the default leaf icon to use for all subsequent leaves added to the tree 377 void leaf_icon( Fl_Image *icon ); 378 379 //! Set the default color, font and size to use for the text of all subsequent leaves added to the tree, Default is FL_BLACK, FL_HELVETICA, 12 leaf_text(Fl_Color color,Fl_Font font,int size)380 inline void leaf_text( Fl_Color color, Fl_Font font, int size ) 381 { rdata.defLeafColor = color; rdata.defLeafFont = font; rdata.defLeafSize = size; } 382 383 //! Set whether items can be moved only within their group ( \c true ) or can be moved anywhere in the tree ( \c false ). Default is \c false. Used only when selection_drag_mode() is FLU_DRAG_TO_MOVE. move_only_same_group(bool b)384 inline void move_only_same_group( bool b ) 385 { rdata.moveOnlySameGroup = b; } 386 387 //! Get whether items can be moved only within their group ( \c true ) or can be moved anywhere in the tree ( \c false ). Used only when selection_drag_mode() is FLU_DRAG_TO_MOVE. move_only_same_group()388 inline bool move_only_same_group() 389 { return rdata.moveOnlySameGroup; } 390 391 //! \return the number of selected entries 392 int num_selected(); 393 394 //! Get the color to use for shading odd entries odd_shaded_entry_color()395 inline Fl_Color odd_shaded_entry_color() const 396 { return rdata.shadedColors[1]; } 397 398 //! Set whether only a single branch (except the root branch) is allowed open at a time. Default is \c false only_one_open_branch(bool b)399 inline void only_one_open_branch( bool b ) 400 { rdata.singleBranchOpen = b; } 401 402 //! Get whether only a single branch (except the root branch) is allowed open at a time only_one_open_branch()403 inline bool only_one_open_branch() 404 { return rdata.singleBranchOpen; } 405 406 //! Open or close the root node open(bool b)407 inline void open( bool b ) 408 { root.open( b ); } 409 410 //! Is the root node open or closed? open()411 inline bool open() const 412 { return root.open(); } 413 414 //! Set whether you can open/close a branch even if it has no children. Default is \c false open_without_children(bool b)415 inline void open_without_children( bool b ) 416 { rdata.openWOChildren = b; } 417 418 //! Get whether you can open/close a branch even if it has no children. open_without_children()419 inline bool open_without_children() const 420 { return rdata.openWOChildren; } 421 422 //! Set whether selecting a branch also opens it. Default is \c false open_on_select(bool b)423 inline void open_on_select( bool b ) 424 { rdata.openOnSelect = b; } 425 426 //! Get whether selecting a branch also opens it open_on_select()427 inline bool open_on_select() const 428 { return rdata.openOnSelect; } 429 430 //! Print the tree to stdout 431 void print(); 432 433 //! Remove the entry identified by path \b fullpath from the tree 434 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 435 unsigned long remove( const char *fullpath ); 436 437 //! Remove entry \b name in path \b path from the tree 438 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 439 unsigned long remove( const char *path, const char *name ); 440 441 //! Remove the entry identified by unique id \b id from the tree 442 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 443 unsigned long remove( unsigned int id ); 444 445 //! Remove the entry containing the widget \b w from the tree. Note that the widget is automatically destroyed 446 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 447 unsigned long remove( Fl_Widget *w ); 448 449 //! Remove Node \b n from the tree 450 /*! \return the id of \b n on successful removal, or \c 0 if \b n is not in the tree */ remove(Node * n)451 inline unsigned long remove( Node* n ) 452 { if( !n ) return 0; else return remove( n->id() ); } 453 454 //! Override of Fl_Widget::resize 455 void resize( int X, int Y, int W, int H ); 456 457 //! Convenience routine to set the root label color. See Flu_Tree_Browser::Node::label_color() root_color(Fl_Color c)458 inline void root_color( Fl_Color c ) 459 { get_root()->label_color( c ); } 460 461 //! Convenience routine to set the root label color. See Flu_Tree_Browser::Node::label_color() root_color()462 inline Fl_Color root_color() 463 { return get_root()->label_color(); } 464 465 //! Convenience routine to set the root label font. See Flu_Tree_Browser::Node::label_font() root_font(Fl_Font f)466 inline void root_font( Fl_Font f ) 467 { get_root()->label_font( f ); } 468 469 //! Convenience routine to set the root label font. See Flu_Tree_Browser::Node::label_font() root_font()470 inline Fl_Font root_font() 471 { return get_root()->label_font(); } 472 473 //! Convenience routine to set the root label size. See Flu_Tree_Browser::Node::label_size() root_size(unsigned char s)474 inline void root_size( unsigned char s ) 475 { get_root()->label_size( s ); } 476 477 //! Convenience routine to set the root label size. See Flu_Tree_Browser::Node::label_size() root_size()478 inline unsigned char root_size() 479 { return get_root()->label_size(); } 480 481 //! Select all entries in the tree select_all()482 inline void select_all() 483 { root.select_all(); } 484 485 //! Get the color to use when hilighting selected entries selection_color()486 inline Fl_Color selection_color() const 487 { return rdata.defSelectionColor; } 488 489 //! Set the color to use when hilighting selected entries. Default is FL_SELECTION_COLOR selection_color(Fl_Color c)490 inline void selection_color( Fl_Color c ) 491 { rdata.defSelectionColor = c; } 492 493 //! Set how selection is affected when the mouse is dragged. This can be one of FLU_DRAG_IGNORE, FLU_DRAG_TO_SELECT, FLU_DRAG_TO_MOVE. Default is FLU_DRAG_TO_SELECT. selection_drag_mode(int m)494 inline void selection_drag_mode( int m ) 495 { rdata.selectionDragMode = m; } 496 497 //! Get how selection is affected when the mouse is dragged selection_drag_mode()498 inline int selection_drag_mode() const 499 { return rdata.selectionDragMode; } 500 501 //! Set whether the hilighted node is always selected. Default is \c false selection_follows_hilight(bool b)502 inline void selection_follows_hilight( bool b ) 503 { rdata.selectionFollowsHilight = b; if( b && rdata.hilighted ) rdata.hilighted->select(true); } 504 505 //! Get whether the hilighted node is always selected selection_follows_hilight()506 inline bool selection_follows_hilight() 507 { return rdata.selectionFollowsHilight; } 508 509 //! Set how individual entries are selected using the mouse. This can be one of FLU_NO_SELECT, FLU_SINGLE_SELECT, FLU_MULTI_SELECT. Default is FLU_MULTI_SELECT selection_mode(int m)510 inline void selection_mode( int m ) 511 { rdata.selectionMode = m; root.unselect_all(); } 512 513 //! Get how individual entries are selected using the mouse selection_mode()514 inline int selection_mode() const 515 { return rdata.selectionMode; } 516 517 //! If selection_mode() is \c FLU_SINGLE_SELECT, then whichever node is under the mouse will always be selected, with all others unselected. Default is \c false select_under_mouse(bool b)518 inline void select_under_mouse( bool b ) 519 { rdata.selectUnderMouse = b; } 520 521 //! If selection_mode() is \c FLU_SINGLE_SELECT, then whichever node is under the mouse will always be selected, with all others unselected. Default is \c false select_under_mouse()522 inline bool select_under_mouse() const 523 { return rdata.selectUnderMouse; } 524 525 //! Calling this will cause any newly added branches to use the default branch icon 526 void set_default_branch_icons(); 527 528 //! Set which node is hilighted and ready to be selected or unselected. This also scrolls the browser so \b n is visible. 529 void set_hilighted( Node* n ); 530 531 //! Set the title of the root of the tree to \b label. If \b w is not \c NULL then that widget is the entry and its label is visible depending on the value of \b showLabel. Note that the widget is destroyed by the tree/node on clear() or the destructor 532 /*! The root icons, color, font and size are set to the current branch icons and text color, font and size */ 533 Node* set_root( const char *label, Fl_Widget *w = 0, bool showLabel = true ); 534 535 //! Set the colors to use for shading every other entry. Default is FL_WHITE, FL_WHITE shaded_entry_colors(Fl_Color even,Fl_Color odd)536 inline void shaded_entry_colors( Fl_Color even, Fl_Color odd ) 537 { rdata.shadedColors[0] = even; rdata.shadedColors[1] = odd; } 538 539 //! Set whether branch entries are visible. Default is \c true show_branches(bool b)540 inline void show_branches( bool b ) 541 { rdata.showBranches = b; rdata.forceResize = true; } 542 543 //! Get whether branch entries are visible show_branches()544 inline bool show_branches() const 545 { return rdata.showBranches; } 546 547 //! Set whether the connectors between entries are visible. Default is \c true show_connectors(bool b)548 inline void show_connectors( bool b ) 549 { rdata.showConnectors = b; } 550 551 //! Get whether the connectors between entries are visible show_connectors()552 inline bool show_connectors() const 553 { return rdata.showConnectors; } 554 555 //! Set whether the root branch (i.e. the name of the tree) is visible. Default is \c true show_root(bool b)556 inline void show_root( bool b ) 557 { rdata.showRoot = b; rdata.forceResize = true; } 558 559 //! Get whether the root branch (i.e. the name of the tree) is visible show_root()560 inline bool show_root() const 561 { return rdata.showRoot; } 562 563 //! Set whether leaf entries are visible. Default is \c true show_leaves(bool b)564 inline void show_leaves( bool b ) 565 { rdata.showLeaves = b; rdata.forceResize = true; } 566 567 //! Get whether leaf entries are visible show_leaves()568 inline bool show_leaves() const 569 { return rdata.showLeaves; } 570 571 //! Sort the tree according to insertion_mode() sort()572 inline void sort() 573 { root.sort(); } 574 575 //! Unselect all entries in the tree unselect_all()576 inline void unselect_all() 577 { root.unselect_all(); } 578 use_FLU_WIDGET_CALLBACK(bool b)579 inline static void use_FLU_WIDGET_CALLBACK( bool b ) 580 { USE_FLU_WIDGET_CALLBACK = b; } 581 582 //! Set the vertical gap between tree entries. Default is 0 vertical_gap(int g)583 inline void vertical_gap( int g ) 584 { rdata.vGap = g; rdata.forceResize = true; } 585 586 //! Get the vertical gap between tree entries vertical_gap()587 inline int vertical_gap() const 588 { return rdata.vGap; } 589 590 //! Override of Fl_Widget::when. Currently only FL_WHEN_NEVER, FL_WHEN_CHANGED, and FL_WHEN_NOT_CHANGED are supported. Default value is FL_WHEN_CHANGED 591 /*! When the callback occurs, you can use callback_reason() to determine exactly what cause the callback and callback_node() 592 to get the node that was affected. */ 593 //inline void when( unsigned int w ) 594 //{ rdata.when = w; } 595 596 //! Override of Fl_Widget::when 597 //inline unsigned int when() const 598 //{ return rdata.when; } 599 600 //! Set the gap between the widget and the icon that precedes it. Default is 2 widget_gap(int g)601 inline void widget_gap( int g ) 602 { rdata.wGap = g; rdata.forceResize = true; } 603 604 //! Get the gap between the widget and the icon that precedes it widget_gap()605 inline int widget_gap() const 606 { return rdata.wGap; } 607 608 protected: 609 610 class RData; 611 612 //! Internal class holding an (alphabetically) ordered list of nodes 613 class FLU_EXPORT NodeList 614 { 615 public: 616 NodeList(); 617 ~NodeList(); 618 void add( Node* n, int position = -1 ); child(int n)619 inline Node* child( int n ) const { return _nodes[n]; } 620 int erase( Node* n ); 621 int erase( const char* n ); 622 void erase( int n ); 623 void clear(); 624 int findNum( const char *n ); // find the number of nodes in the list with name n 625 Node* find( const char* n, int which = 1 ); // find the which'th node in the list with name n size()626 inline int size() const { return _nNodes; }; 627 void sort(); 628 static bool move( Node* n1, int where, Node* n2 ); 629 private: 630 friend class Node; 631 static int compareNodes( const void *arg1, const void* arg2 ); 632 static int reverseCompareNodes( const void *arg1, const void* arg2 ); 633 bool search( Node *n, int &index ); 634 bool search( const char *n, int &index ); 635 bool linSearch( Node *n, int &index ); 636 bool linSearch( const char *n, int &index ); 637 bool binSearch( Node *n, int &index ); 638 bool binSearch( const char *n, int &index ); 639 Node **_nodes; 640 int _nNodes, _size; 641 }; 642 643 //! Internal class holding a stack of integers 644 class FLU_EXPORT IntStack 645 { 646 public: 647 IntStack(); 648 IntStack( const IntStack& s ); 649 ~IntStack(); 650 void push( int i ); 651 int pop(); 652 void clear(); 653 inline int operator [](int i) { return _list[i]; } size()654 inline int size() { return _size; } 655 IntStack& operator =( const IntStack& s ); 656 private: 657 int *_list; 658 int _size, _bufferSize; 659 }; 660 661 public: 662 enum { MOVE_BEFORE, MOVE_INSIDE, MOVE_AFTER }; // where to move a dragged node? 663 protected: 664 665 //! Recursive data structure passed down through the node tree 666 class FLU_EXPORT RData { 667 public: 668 // volatile objects (from the perspective of each node during a recursive descent) 669 int x, y, totalW, totalH; 670 bool first, last, dragging, shiftSelect, shiftSelectAll, visibilityChanged, selectionFollowsHilight; 671 Node *hilighted, /**lastHilighted, */ *previous, *grabbed, *dragNode, *animatedNode; 672 int delta, shadedIndex, counter, searchIndex, branchIconW, dragPos, dragWhere; 673 Fl_Color lineColor, bgColor, selectionColor; 674 bool forceResize; // force the browser to resize on the next draw (which forces a recalculation of the tree layout) 675 unsigned int nextId; // monotonically increasing id of each entry 676 FluSimpleString path; // used to construct the full path during a findPath() operation 677 IntStack branchConnectors; 678 679 // static objects (from the perspective of each node during a recursive descent) 680 int insertionMode; 681 Fl_Image *defaultCollapseIcons[2], *defaultBranchIcons[2]; 682 Fl_Image *collapseIcons[2], *branchIcons[2], *leafIcon; 683 int hGap, vGap, wGap; 684 int lineStyle, lineWidth, selectionMode, selectionDragMode; 685 bool showRoot, showConnectors, showLeaves, showBranches, openOnSelect, 686 allowDuplication, animate, animating, singleBranchOpen, moveOnlySameGroup, justOpenedClosed, 687 isMoveValid, doubleClickToOpen, dnd, allBranchesAlwaysOpen, autoBranches, openWOChildren, 688 selectUnderMouse; 689 float collapseTime, fps, animationDelta, animationOffset; 690 Fl_Color defLineColor, defSelectionColor, shadedColors[2]; 691 Fl_Color defLeafColor, defBranchColor; 692 Fl_Font defLeafFont, defBranchFont; 693 int defLeafSize, defBranchSize; 694 int browserX, browserY, browserW, browserH; 695 Node *root; 696 Flu_Tree_Browser *tree; 697 unsigned int cbReason; 698 Node *cbNode, *lastOpenBranch; 699 }; 700 701 public: 702 703 #ifdef USE_FLU_DND 704 //! This class can be subclassed to make an object which can be dropped on a tree to make a new node 705 /*! When the object is dropped, the tree will name the object according to what the function 706 \b name() returns */ 707 class FLU_EXPORT DND_Object : public Flu_DND 708 { 709 public: 710 711 //! Default constructor 712 DND_Object(); 713 714 //! The descendent should call this when the user grabs the object to start dragging it (e.g. on the FL_PUSH event) grab()715 inline void grab() 716 { dnd_grab( this, "DND_Object" ); } 717 718 //! Descendents MUST implement this function to return the name of the dropped object 719 virtual const char* name() = 0; 720 721 }; 722 #endif 723 724 //! This class holds a single entry in the tree 725 class FLU_EXPORT Node 726 { 727 728 protected: 729 730 enum { ADD, REMOVE, FIND, FIND_NUMBER, GET_SELECTED }; // parameters for modify() 731 enum { DRAW, MEASURE, MEASURE_THIS_OPEN, HANDLE, COUNT_SELECTED }; // parameters for recurse() 732 733 // flags 734 enum { SELECTED = 0x0001, COLLAPSED = 0x0002, LEAF = 0x0004, SHOW_LABEL = 0x0008, 735 ACTIVE = 0x0010, EXPAND_TO_WIDTH = 0x0020, ALWAYS_OPEN = 0x0040, 736 SOME_VISIBLE_CHILDREN = 0x0080, MOVABLE = 0x0100, DROPPABLE = 0x0200, 737 AUTO_LABEL_COLOR = 0x0400, AUTO_COLOR = 0x0800, AUTO_LABEL = 0x1000, 738 SWAP_LABEL_AND_WIDGET = 0x2000, ICON_AT_END = 0x4000 }; 739 740 // flag manipulator functions CHECK(unsigned short flag)741 inline bool CHECK( unsigned short flag ) const { return flags & flag; } SET(unsigned short flag)742 inline void SET( unsigned short flag ) { flags |= flag; } SET(unsigned short flag,bool b)743 inline void SET( unsigned short flag, bool b ) { if(b) SET(flag); else CLEAR(flag); } CLEAR(unsigned short flag)744 inline void CLEAR( unsigned short flag ) { flags &= ~flag; } 745 746 public: 747 748 //! Is this node currently active? active()749 inline bool active() const 750 { return CHECK(ACTIVE); } 751 752 //! Activate or deactivate this node 753 void active( bool b ); 754 755 //! Activate this node activate()756 inline void activate() 757 { active(true); } 758 759 //! Add the entry specified by \b fullpath to this node. If \b w is not \c NULL then that widget is the entry and the label (as specified in \b fullPath) is visible depending on the value of \b showLabel. Note that the widget is destroyed by the tree/node on clear() or the destructor 760 /*! \return a pointer to the Node of the added entry or NULL if the add failed */ 761 inline Node* add( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ) 762 { return( modify( fullpath, ADD, tree->rdata, w, showLabel ) ); } 763 764 //! Convenience function that is the same as add() except it appends a '/' to \b fullpath if one does not exist 765 Node* add_branch( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ); 766 767 //! Convenience function that is the same as add() except it removes any '/' at the end of \b fullpath 768 Node* add_leaf( const char* fullpath, Fl_Widget *w = 0, bool showLabel = true ); 769 770 //! Convenience function that is the same as add() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 771 Node* add( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 772 773 //! Convenience function that is the same as add_branch() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 774 Node* add_branch( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 775 776 //! Convenience function that is the same as add_leaf() except \b path and \b name are concatenated (with a '/' added if necessary) to create the full path 777 Node* add_leaf( const char* path, const char* name, Fl_Widget *w = 0, bool showLabel = true ); 778 779 //! Set whether a branch node is always open (only for branch nodes). Default is \c false always_open(bool b)780 inline void always_open( bool b ) 781 { if( b ) open(true); SET(ALWAYS_OPEN,b); tree->rdata.forceResize = true; } 782 783 //! Get whether this branch node is always open (only for branches) always_open()784 inline bool always_open() const 785 { return CHECK(ALWAYS_OPEN); } 786 787 //! Set whether the color of the widget in this node tracks the color of the node itself. This is useful for changing the color of the widget when the node is selected. Default is \c false auto_color(bool b)788 inline void auto_color( bool b ) 789 { SET(AUTO_COLOR,b); } 790 791 //! Get whether the color of the widget in this node tracks the color of the node itself auto_color()792 inline bool auto_color() 793 { return CHECK(AUTO_COLOR); } 794 795 //! Set whether the label of the widget in this node tracks the label of the node itself. This is useful for when the label of the node changes and you want the widget to reflect the change auto_label(bool b)796 inline void auto_label( bool b ) 797 { SET(AUTO_LABEL,b); } 798 799 //! Set whether the label of the widget in this node tracks the label of the node itself. auto_label()800 inline bool auto_label() 801 { return CHECK(AUTO_LABEL); } 802 803 //! Set whether the label color of the widget in this node tracks the label color of the node itself. This is useful for changing the label color of the widget when the node is selected. Default is \c false auto_label_color(bool b)804 inline void auto_label_color( bool b ) 805 { SET(AUTO_LABEL_COLOR,b); } 806 807 //! Get whether the label color of the widget in this node tracks the label color of the node itself auto_label_color()808 inline bool auto_label_color() 809 { return CHECK(AUTO_LABEL_COLOR); } 810 811 //! Set the branch icons to use for this node (only for branch nodes) 812 void branch_icons( Fl_Image *closed, Fl_Image *open ); 813 814 //! Convenience routine to set both branch icons at once branch_icon(Fl_Image * icon)815 inline void branch_icon( Fl_Image *icon ) 816 { branch_icons( icon, icon ); } 817 818 //! \return child \b i of this node (base 0). Bounds checking is performed and NULL is returned if the child cannot be found 819 Node* child( int i ) const; 820 821 //! \return the number of child nodes beneath this node children()822 inline int children() const 823 { return _children.size(); } 824 825 //! Clear all child entries from this node (does not change the entry of this node) 826 void clear(); 827 828 //! Close this node (only for branches) close()829 inline void close() 830 { open( false ); } 831 832 //! Is this node closed? (only for branches) closed()833 inline bool closed() 834 { return !open(); } 835 836 //! Set the collapse icons to use for this node (only for branch nodes) 837 /*! \note if a NULL icon is passed, the default plus/minus icons are chosen */ 838 void collapse_icons( Fl_Image *closed, Fl_Image *open ); 839 840 //! Deactivate this node deactivate()841 inline void deactivate() 842 { active(false); } 843 844 //! Get the depth of this node in the tree 845 unsigned short depth() const; 846 847 //! Do the tree browser callback. \b reason should be one of FLU_HILIGHTED, FLU_UNHILIGHTED, FLU_SELECTED, FLU_UNSELECTED, FLU_OPENED, FLU_CLOSED, FLU_DOUBLE_CLICK, FLU_WIDGET_CALLBACK 848 void do_callback( int reason ); 849 850 //! Set whether this node can receive new nodes as a result of dragging-and-dropping (only for branch nodes). Default is \c true droppable(bool b)851 inline void droppable( bool b ) 852 { SET(DROPPABLE,b); } 853 854 //! Get whether this node can receive new nodes as a result of dragging-and-dropping (only for branch nodes). droppable()855 inline bool droppable() 856 { return CHECK(DROPPABLE); } 857 858 //! Set whether to force the size of the embedded widget to expand to fill the visible width of the browser. Default is \c false expand_to_width(bool b)859 inline void expand_to_width( bool b ) 860 { SET(EXPAND_TO_WIDTH,b); tree->rdata.forceResize = true; } 861 862 //! Get whether to force the size of the embedded widget to expand to fill the visible width of the browser expand_to_width()863 inline bool expand_to_width() const 864 { return CHECK(EXPAND_TO_WIDTH); } 865 866 //! Find the entry identified by \b fullpath 867 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ find(const char * fullpath)868 inline Node* find( const char *fullpath ) 869 { return( modify( fullpath, FIND, tree->rdata ) ); } 870 871 //! Find the entry identified by unique id \b id 872 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 873 Node* find( unsigned int id ); 874 875 //! Find the entry containing the widget \b w 876 /*! \return a pointer to the Node of the found entry, or NULL if no matching entry was found */ 877 Node* find( Fl_Widget *w ); 878 879 //! Search for Node \b n 880 /*! \return a pointer to \b n if it is found, or NULL if it is not present */ find(Node * n)881 inline Node* find( Node *n ) 882 { if( !n ) return NULL; else return find( n->id() ); } 883 884 //! \return the full path of this node 885 /*! \note the returned value is only valid until the next time find_path() is called */ find_path()886 inline const char* find_path() 887 { return tree->find_path( this ); } 888 889 //! \return the first node in this hierarchy (i.e. this node) 890 Node* first(); 891 892 //! \return the first branch encountered in a depth-first traversal (or this node if it is a branch). NULL means there are no branches 893 Node* first_branch(); 894 895 //! \return the first leaf encountered in a depth-first traversal (or this node if it is a leaf). NULL means there are no leaves 896 Node* first_leaf(); 897 898 //! Set whether this node draws the label to the left of the widget (\c false, default) or to the right of the widget (\c true) swap_label_and_widget(bool b)899 inline void swap_label_and_widget( bool b ) 900 { SET(SWAP_LABEL_AND_WIDGET,b); } 901 902 //! Get whether this node draws the label to the left of the widget (\c false, default) or to the right of the widget (\c true) swap_label_and_widget()903 inline bool swap_label_and_widget() 904 { return CHECK(SWAP_LABEL_AND_WIDGET); } 905 906 //! \return the selected Node that is at \b index among all selected nodes, or \c NULL if no Node is selected 907 /*! For example, \c get_selected(1) will return the first selected node. */ 908 Node* get_selected( int index ); 909 910 //! Set whether the icon for this node is drawn after the label and widget (\c true) or before (\c false, default) (only for leaf nodes) icon_at_end(bool b)911 inline void icon_at_end( bool b ) 912 { SET(ICON_AT_END,b); } 913 914 //! Get whether the icon for this node is drawn after the label and widget (\c true) or before (\c false, default) (only for leaf nodes) icon_at_end()915 inline bool icon_at_end() 916 { return CHECK(ICON_AT_END); } 917 918 //! Get the unique ID of this node id()919 inline unsigned int id() const 920 { return _id; } 921 922 //! Get the index this node is (as a child) in its parent's list 923 /*! \return -1 if this node has no parent, else its index in its parent's list of children */ 924 int index() const; 925 926 //! Insert a new node at position \b pos 927 Node* insert( const char* fullpath, int pos ); 928 929 //! Insert a new branch at position \b pos 930 Node* insert_branch( const char* fullpath, int pos ); 931 932 //! Insert a new leaf at position \b pos 933 Node* insert_leaf( const char* fullpath, int pos ); 934 935 //! Is node \b n an ancestor of this node? 936 bool is_ancestor( Node* n ); 937 938 //! Is this node a branch node? 939 bool is_branch() const; 940 941 //! Is node \b n a descendent of this node? 942 bool is_descendent( Node* n ); 943 944 //! Is this node a leaf node? 945 bool is_leaf() const; 946 947 //! Is this node the root node? is_root()948 inline bool is_root() const 949 { return( _parent == 0 ); } 950 951 //! Set the label for this node. Note that setting the label may invalidate a sorted tree. Fix by calling Flu_Tree_Browser::sort() label(const char * l)952 inline void label( const char *l ) 953 { text = l; tree->redraw(); } 954 955 //! Get the label for this node label()956 inline const char* label() const 957 { return text.c_str(); } 958 959 //! Set the label color for this node label_color(Fl_Color c)960 inline void label_color( Fl_Color c ) 961 { textColor = c; } 962 963 //! Get the label color for this node label_color()964 inline Fl_Color label_color() const 965 { return textColor; } 966 967 //! Set the label font for this node label_font(Fl_Font f)968 inline void label_font( Fl_Font f ) 969 { textFont = f; tree->rdata.forceResize = true; } 970 971 //! Get the label font for this node label_font()972 inline Fl_Font label_font() const 973 { return textFont; } 974 975 //! Set the label size for this node label_size(unsigned char s)976 inline void label_size( unsigned char s ) 977 { textSize = s; tree->rdata.forceResize = true; } 978 979 //! Get the label size for this node label_size()980 inline unsigned char label_size() const 981 { return textSize; } 982 983 //! Is the label for this node visible? label_visible()984 inline bool label_visible() const 985 { return CHECK(SHOW_LABEL); } 986 987 //! Set whether the label for this node is visible label_visible(bool b)988 inline void label_visible( bool b ) 989 { SET(SHOW_LABEL,b); tree->rdata.forceResize = true; } 990 991 //! \return the last node in this hierarchy 992 Node* last(); 993 994 //! \return the last branch encountered in a depth-first traversal (or this node if it is a branch and has no children). NULL means there are no branches 995 Node* last_branch(); 996 997 //! \return the last leaf encountered in a depth-first traversal (or this node if it is a leaf). NULL means there are no leaves 998 Node* last_leaf(); 999 1000 //! Set the leaf icon to use for this node (only for leaf nodes) 1001 void leaf_icon( Fl_Image *icon ); 1002 1003 //! Set whether this node can be moved (either via move() or by dragging with the mouse). Default is \c true movable(bool b)1004 inline void movable( bool b ) 1005 { SET(MOVABLE,b); } 1006 1007 //! Get whether this node can be moved (either via move() or by dragging with the mouse) movable()1008 inline bool movable() 1009 { return CHECK(MOVABLE); } 1010 1011 //! Move this node to absolute position \b pos within its parent 1012 /*! \return \c true if the move was successful, or \c false if the move is not allowed 1013 */ 1014 bool move( int pos ); 1015 1016 //! Move this node to a position before, after, or inside node \b n 1017 /*! \param where can be one of MOVE_BEFORE, MOVE_AFTER, or MOVE_INSIDE 1018 \return \c true if the move was successful, or \c false if the move is not allowed 1019 */ move(int where,Node * n)1020 inline bool move( int where, Node* n ) 1021 { return( move( this, where, n ) ); } 1022 1023 //! Move node \b n1 to a position before, after, or inside node \b n2 1024 /*! \param where can be one of MOVE_BEFORE, MOVE_AFTER, or MOVE_INSIDE 1025 \return \c true if the move was successful, or \c false if the move is not allowed 1026 */ 1027 static bool move( Node* n1, int where, Node* n2 ); 1028 1029 //! \return the next node (after this node) in this hierarchy (depth-first traversal) 1030 Node* next(); 1031 1032 //! \return the next branch (after this node) encountered in a depth-first traversal. NULL means there are no more branches 1033 Node* next_branch(); 1034 1035 //! \return the next leaf (after this node) encountered in a depth-first traversal. NULL means there are no more leaves 1036 Node* next_leaf(); 1037 1038 //! \return the next sibling (after this node) encountered in a depth-first traversal. NULL means this node is the last child w.r.t. its parent 1039 Node* next_sibling(); 1040 1041 //! \return the number of selected entries 1042 int num_selected(); 1043 1044 //! Is this node currently open? (only for branch nodes) open()1045 inline bool open() const 1046 { return( !CHECK(COLLAPSED) || tree->rdata.allBranchesAlwaysOpen ); } 1047 1048 //! Open or close this node (only for branch nodes) 1049 void open( bool b ); 1050 1051 //! Get the node that is the parent of this node, or NULL if there is no parent parent()1052 inline Node* parent() const 1053 { return _parent; } 1054 1055 //! \return the previous node (before this node) in this hierarchy (depth-first traversal) 1056 Node* previous(); 1057 1058 //! \return the previous branch (before this node) encountered in a depth-first traversal. NULL means there are no more branches 1059 Node* previous_branch(); 1060 1061 //! \return the previous leaf (before this node) encountered in a depth-first traversal. NULL means there are no more leaves 1062 Node* previous_leaf(); 1063 1064 //! \return the previous sibling (before this node) encountered in a depth-first traversal. NULL means this node is the first child w.r.t. its parent 1065 Node* previous_sibling(); 1066 1067 //! Print this node and its children to stdout 1068 void print( int spaces = 0 ); 1069 1070 //! Remove the entry identified by path \b fullpath from this node 1071 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ remove(const char * fullpath)1072 inline unsigned long remove( const char *fullpath ) 1073 { return( (unsigned long)modify( fullpath, REMOVE, tree->rdata ) ); } 1074 1075 //! Remove the entry identified by unique id \b id from this node 1076 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 1077 unsigned long remove( unsigned int id ); 1078 1079 //! Remove the node containing the widget \b w from this node. Note that the widget is automatically destroyed 1080 /*! \return the unique id of the removed entry, or \c 0 if no matching entry was found */ 1081 unsigned long remove( Fl_Widget *w ); 1082 1083 //! Remove Node \b n 1084 /*! \return the id of \b n on successful removal, or \c 0 if \b n is present */ remove(Node * n)1085 inline unsigned long remove( Node* n ) 1086 { if( !n ) return 0; else return remove( n->id() ); } 1087 1088 //! Select this entry and all child entries 1089 void select_all(); 1090 1091 //! Is this node currently selected? selected()1092 inline bool selected() const 1093 { return CHECK(SELECTED); } 1094 1095 //! Select or unselect this node 1096 void select( bool b ); 1097 1098 //! Select only this node select_only()1099 inline void select_only() 1100 { tree->unselect_all(); select(true); } 1101 1102 //! Sort this node's children according to Flu_Tree_Browser::insertion_mode() sort_children()1103 inline void sort_children() 1104 { sort(); } 1105 1106 //! Swap this node and node \b n in their respective trees 1107 /*! \return \c true if the swap was successful, else \c false */ swap(Node * n)1108 inline bool swap( Node* n ) 1109 { return swap( this, n ); } 1110 1111 //! Swap nodes \b n1 and \b n2 in their respective trees 1112 /*! \return \c true if the swap was successful, else \c false */ 1113 static bool swap( Node* n1, Node* n2 ); 1114 1115 //! Unselect this entry and all child entries (except for Node \b except ) 1116 void unselect_all( Node* except = NULL ); 1117 1118 //! Get the user-specific data stored in this node user_data()1119 inline void* user_data() 1120 { return userData; } 1121 1122 //! Set the user-specific data stored in this node user_data(void * d)1123 inline void user_data( void *d ) 1124 { userData = d; } 1125 1126 //! Get the widget in this node, or NULL if there is no widget. Note that the widget is destroyed by the tree/node on clear() or the destructor widget()1127 inline Fl_Widget* widget() const 1128 { return( _widget ? _widget->w : NULL ); } 1129 1130 //! Set the widget in this node. Note that the widget is destroyed by the tree/node on clear() or the destructor 1131 void widget( Fl_Widget *w ); 1132 1133 protected: 1134 1135 friend class Flu_Tree_Browser; 1136 friend class NodeList; 1137 1138 // Root node constructor 1139 Node( const char *lbl = 0 ); 1140 1141 // Non-root constructor 1142 Node( bool l, const char* n, Node *p, RData &rdata, Fl_Widget *w, bool showLabel ); 1143 1144 ~Node(); 1145 1146 // add/remove/find/get 1147 Node* modify( const char* path, int what, RData &rdata, Fl_Widget *w = 0, bool showLabel = true ); 1148 1149 void initType(); 1150 1151 void sort(); 1152 1153 void determineVisibility( bool parentVisible = true ); 1154 1155 static bool isMoveValid( Node* &n1, int &where, Node* &n2 ); 1156 1157 // handle/draw/measure/count 1158 int recurse( RData &rdata, int type, int event = 0 ); 1159 1160 void draw( RData &rdata, bool measure ); 1161 1162 // recursively finding the full path of the node identified by id 1163 bool findPath( unsigned int id, RData &rdata ); 1164 1165 // recursively finding the full path of the node containing w 1166 bool findPath( Fl_Widget *w, RData &rdata ); 1167 1168 class FLU_EXPORT WidgetInfo 1169 { 1170 public: 1171 Fl_Widget *w; 1172 int defaultW; // the initial width of the widget 1173 void (*CB)(Fl_Widget*,void*); 1174 void *CBData; 1175 }; 1176 1177 unsigned int _id; // the unique id of this node 1178 unsigned short flags; 1179 NodeList _children; 1180 Node *_parent; 1181 Flu_Tree_Browser *tree; 1182 FluSimpleString text; 1183 WidgetInfo *_widget; // memory overhead deferred to WidgetInfo. present only if widget is 1184 Fl_Group *_group; 1185 void *userData; 1186 int totalChildH; // needed for animation 1187 Fl_Image *cIcon[2], *bIcon[2], *lIcon; 1188 Fl_Color textColor; 1189 Fl_Font textFont; 1190 unsigned char textSize; // the font size of the entry label text 1191 unsigned short textW, textH; // how big the entry label actually is (stored within the node for performance reasons) 1192 int currentY; // needed for animation 1193 unsigned short currentH; 1194 _widgetCB(Fl_Widget *,void * arg)1195 inline static void _widgetCB( Fl_Widget* /*w*/, void* arg ) 1196 { ((Node*)arg)->widgetCB(); } 1197 void widgetCB(); 1198 }; 1199 1200 protected: 1201 _scrollCB(Fl_Widget *,void * arg)1202 inline static void _scrollCB( Fl_Widget* /*w*/, void* arg ) 1203 { ((Flu_Tree_Browser*)arg)->redraw(); } 1204 _timerRedrawCB(void * arg)1205 inline static void _timerRedrawCB( void *arg ) 1206 { ((Flu_Tree_Browser*)arg)->timerRedrawCB(); } 1207 void timerRedrawCB(); 1208 _timerScrollCB(void * arg)1209 inline static void _timerScrollCB( void *arg ) 1210 { ((Flu_Tree_Browser*)arg)->timerScrollCB(); } 1211 void timerScrollCB(); 1212 1213 void on_dnd_leave(); 1214 1215 void on_dnd_release(); 1216 1217 bool on_dnd_drag( int X, int Y ); 1218 1219 void on_dnd_drop( const Flu_DND_Event *e ); 1220 1221 /* override of Fl_Double_Window::draw() */ 1222 void draw(); 1223 1224 Fl_Group *scrollBox; 1225 Fl_Scrollbar *scrollH, *scrollV; 1226 Fl_Group *_box; 1227 Node root; 1228 RData rdata; 1229 //int lastEvent; 1230 float autoScrollX, autoScrollY; 1231 bool scrolledTimerOn; 1232 1233 }; 1234 1235 #endif 1236