Flu_Tree_Browser.H 51 KB

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