Flu_Tree_Browser.H 51 KB

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