Flu_Tree_Browser.h 50 KB

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